Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: samplecode/SampleBevel.cpp

Issue 2259183003: Added a small widget framework to the interactive bevel SampleApp (Closed) Base URL: https://skia.googlesource.com/skia@bevel-interactive
Patch Set: Correct call for integer string append Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SampleCode.h" 8 #include "SampleCode.h"
9 #include "SkCanvas.h" 9 #include "SkCanvas.h"
10 #include "SkLightingShader.h" 10 #include "SkLightingShader.h"
11 #include "SkNormalSource.h" 11 #include "SkNormalSource.h"
12 #include "sk_tool_utils.h" 12 #include "sk_tool_utils.h"
13 13
14 class ParentControl;
15
16 // Abstract base class for all components that a control panel must have
17 class Control : public SkRefCnt {
18 public:
19 Control(SkString name)
20 : fName(name)
21 , fParent(nullptr)
22 , fRelativePos(SkPoint::Make(0.0f, 0.0f)) {}
23
24 // Use this to propagate a click's position down to a control. Gets modulate d by the component's
25 // relative position
26 bool click(const SkPoint& clickPos) {
27 SkPoint relativeClickPos = SkPoint::Make(clickPos.fX - fRelativePos.fX,
28 clickPos.fY - fRelativePos.fY);
29 return this->onClick(relativeClickPos);
30 }
31
32 // Use this to draw the control and its appropriate children. Gets modulated by the component's
33 // relative position.
34 void drawContent(SkCanvas *canvas) {
35 canvas->save();
36 canvas->translate(fRelativePos.fX, fRelativePos.fY);
37 this->onDrawContent(canvas);
38 canvas->restore();
39 }
40
41 /* Returns true when click position argumend lands over a control region in this control. Click
42 * position gets modulated by the component's relative position.
43 *
44 * @param click The position of the click in the coordinate space relative t o the parent
45 */
46 bool isInCtrlRegion(const SkPoint& click) {
47 SkPoint relativeClickPos = SkPoint::Make(click.fX - fRelativePos.fX,
48 click.fY - fRelativePos.fY);
49 return this->onIsInCtrlRegion(relativeClickPos);
50 }
51
52 // Returns height of content drawn
53 virtual SkScalar height() const = 0;
54
55 // Sets the parent of this component. May only be used once. Height must rem ain constant after
56 // parent is set.
57 void setParent(ParentControl *parent, const SkPoint& relativePos) {
58 SkASSERT(parent);
59 SkASSERT(!fParent); // No chidren transfer since relativeY would get inv alid for younger kid
60
61 fParent = parent;
62 fRelativePos = relativePos;
63 this->onSetParent();
64 }
65
66 // Overriden by sub-classes that need to recompute fields after parent is se t. Called after
67 // setting fParent.
68 virtual void onSetParent() {}
69
70 // Overriden by sub-classes that need to know when a click is released.
71 virtual void onClickRelease() {}
72
73 protected:
74
75 // Draws a label for the component, using its name and a passed value. Does NOT modulate by
76 // relative height, expects CTM to have been adjusted in advance.
77 void drawLabel(SkCanvas *canvas, const SkString& valueStr) const {
78 // TODO Cache this
79 sk_sp<SkTypeface> fLabelTypeface =
80 sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyl e());
81
82 SkString label;
83 label.append(fName);
84 label.append(": ");
85 label.append(valueStr);
86
87 SkPaint labelPaint;
88 labelPaint.setTypeface(fLabelTypeface);
89 labelPaint.setAntiAlias(true);
90 labelPaint.setColor(0xFFFFFFFF);
91 labelPaint.setTextSize(12.0f);
92
93 canvas->drawText(label.c_str(), label.size(), 0, kLabelHeight - 6.0f, la belPaint);
94 }
95
96 SkString fName;
97 ParentControl* fParent;
98
99 static constexpr SkScalar kLabelHeight = 20.0f;
100
101 private:
102 // Overriden by sub-class to draw component. Do not call directly, drawConte nt() modulates by
103 // relative position.
104 virtual void onDrawContent(SkCanvas *canvas) = 0;
105
106 // Overriden by sub-class to handle clicks. Do not call directly, click() mo dulates by relative
107 // position. Return true if holding mouse capture
108 virtual bool onClick(const SkPoint& clickPos) { return false; };
109
110 // Overriden by sub-classes with controls. Should return true if clickPos la nds inside a control
111 // region, to enable mouse caputre.
112 virtual bool onIsInCtrlRegion(const SkPoint& clickPos) const { return false; };
113
114 // The position of the control relative to it's parent
115 SkPoint fRelativePos;
116 };
117
118 class ParentControl : public Control { // Interface for all controls that have c hildren
119 public:
120 ParentControl(const SkString& name) : INHERITED(name) {}
121
122 // Adds a child
123 virtual void add(sk_sp<Control> control) = 0;
124
125 // Returns the control's width. Used to propagate width down to components t hat don't specify it
126 virtual SkScalar width() const = 0;
127
128 private:
129 typedef Control INHERITED;
130 };
131
132 class ControlPanel : public ParentControl {
133 public:
134
135 ControlPanel(SkScalar width)
136 : ParentControl(SkString("ControlPanel"))
137 , fWidth(width)
138 , fHeight(0.0f)
139 , fSelectedControl(-1) {}
140
141 // Width unspecified, expectation is inheritance from parent
142 ControlPanel() : ControlPanel(-1.0f) {}
143
144 // Use this for introducing clicks on a ControlPanel from outside of the fra mework. It
145 // propagates click release or position down the chain. Returns false when c lick capture is
146 // being released.
147 bool inClick(SkView::Click *inClick) {
148 if (SkView::Click::State::kUp_State == inClick->fState) {
149 this->onClickRelease();
150 return false;
151 }
152 return this->click(inClick->fCurr);
153 }
154
155 // Add children
156 void add(sk_sp<Control> control) override {
157 SkASSERT(!fParent); // Validity of parent's relativeY and fHeight depend s on immutability
158 fControls.push_back(control);
159 control->setParent(this, SkPoint::Make(0.0f, fHeight));
160 fHeight += control->height();
161 }
162
163 SkScalar width() const override {
164 return fParent ? fParent->width() : fWidth; // Width inherited from pare nt if there is one
165 }
166
167 SkScalar height() const override {
168 return fHeight;
169 }
170
171 // Propagate click release to selected control, deselect control
172 void onClickRelease() override {
173 if (fSelectedControl >= 0) {
174 fControls[fSelectedControl]->onClickRelease();
175 }
176 fSelectedControl = -1;
177 }
178
179 // Propagate onSetParent() down to children, some might need fParent->width( ) refresh
180 void onSetParent() override {
181 for (int i = 0; i < fControls.count(); i++) {
182 fControls[i]->onSetParent();
183 }
184 }
185
186 // Holds a vertical shelf of controls. Can't be hierarchy root if not given a width value.
187 static sk_sp<ParentControl> Make() {
188 return sk_sp<ParentControl>(new ControlPanel());
189 }
190
191 // Holds a vertical shelf of controls. Only control that can be hooked from outside the
192 // framework.
193 static sk_sp<ParentControl> Make(SkScalar width) {
194 return sk_sp<ParentControl>(new ControlPanel(width));
195 }
196
197 protected:
198 // Returns true if control panel has mouse captured, false when it is ready to release
199 // capture
200 bool onClick(const SkPoint& click) override {
201
202 if (fSelectedControl == -1) { // If no child control selected, check eve ry child
203 for (int i = 0; i < fControls.count(); i++) {
204 if (fControls[i]->isInCtrlRegion(click)) {
205 fSelectedControl = i;
206 break;
207 }
208 }
209 }
210
211 if (fSelectedControl >= 0) { // If child control selected, propagate cli ck
212 bool keepSelection = fControls[fSelectedControl]->click(click);
213 if (!keepSelection) {
214 fSelectedControl = -1;
215 }
216 return keepSelection;
217 }
218
219 return false;
220 }
221
222 // Draw all children
223 void onDrawContent(SkCanvas* canvas) override {
224 canvas->save();
225 for (int i = 0; i < fControls.count(); i++) {
226 fControls[i]->drawContent(canvas);
227 }
228 canvas->restore();
229 }
230
231 // Check all children's control regions
232 bool onIsInCtrlRegion(const SkPoint& clickPos) const override {
233 for (int i = 0; i < fControls.count(); i++) {
234 if (fControls[i]->isInCtrlRegion(clickPos)) {
235 return true;
236 }
237 }
238
239 return false;
240 }
241
242 private:
243 SkScalar fWidth;
244 SkScalar fHeight;
245
246 SkTArray<sk_sp<Control>> fControls;
247 int fSelectedControl;
248 };
249
250 class DiscreteSliderControl : public Control {
251 public:
252 SkScalar height() const override {
253 return 2.0f * kLabelHeight;
254 }
255
256 // Set width-dependant variables when new parent is set
257 void onSetParent() override {
258 fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, fParent->width(), kSl iderHeight);
259 fSliderRange = fParent->width() - kSliderWidth;
260 }
261
262 /* Make a slider for an integer value. Snaps to discrete positions.
263 *
264 * @params name The name of the control, displayed in the label
265 * @params output Pointer to the integer that will be set by the slider
266 * @params min Min value for output.
267 * @params max Max value for output.
268 */
269 static sk_sp<Control> Make(SkString name, int* output, int min, int max) {
270 return sk_sp<Control>(new DiscreteSliderControl(name, output, min, max)) ;
271 }
272
273 protected:
274 void onDrawContent(SkCanvas* canvas) override {
275 SkASSERT(fParent);
276 int numChoices = fMax - fMin + 1;
277 fSlider.offsetTo(fSliderRange * ( (*fOutput)/SkIntToScalar(numChoices)
278 + 1.0f/(2.0f * numChoices) ),
279 fSlider.fTop);
280
281 SkString valueStr;
282 valueStr.appendS32(*fOutput);
283 this->drawLabel(canvas, valueStr);
284
285 SkPaint sliderPaint;
286 sliderPaint.setColor(0xFFF3F3F3);
287 canvas->drawRect(fSlider, sliderPaint);
288
289 SkPaint ctrlRegionPaint;
290 ctrlRegionPaint.setColor(0xFFFFFFFF);
291 ctrlRegionPaint.setStyle(SkPaint::kStroke_Style);
292 ctrlRegionPaint.setStrokeWidth(2.0f);
293 canvas->drawRect(fCtrlRegion, ctrlRegionPaint);
294 }
295
296 bool onClick(const SkPoint& clickPos) override {
297 SkASSERT(fParent);
298 SkScalar x = SkScalarPin(clickPos.fX, 0.0f, fSliderRange);
299 int numChoices = fMax - fMin + 1;
300 *fOutput = SkTMin(SkScalarFloorToInt(numChoices * x / fSliderRange) + fM in, fMax);
301
302 return true;
303 }
304
305 bool onIsInCtrlRegion(const SkPoint& clickPos) const override {
306 SkASSERT(fParent);
307 return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, 1 , 1));
308 }
309
310 private:
311 DiscreteSliderControl(SkString name, int* output, int min, int max)
312 : INHERITED(name)
313 , fOutput(output)
314 , fMin(min)
315 , fMax(max) {
316 fSlider = SkRect::MakeXYWH(0, kLabelHeight, kSliderWidth, kSliderHeight) ;
317 }
318
319 int* fOutput;
320 int fMin;
321 int fMax;
322 SkRect fSlider; // The rectangle that slides
323 // The region in which the rectangle slides. Also the region in which mouse is caputred
324 SkRect fCtrlRegion;
325 SkScalar fSliderRange; // The width in pixels over which the slider can slid e
326
327 static constexpr SkScalar kSliderHeight = 20.0f;
328 static constexpr SkScalar kSliderWidth = 10.0f;
329
330 typedef Control INHERITED;
331 };
332
333 class ControlSwitcher : public ParentControl {
334 public:
335 // Add children
336 void add(sk_sp<Control> control) override {
337 SkASSERT(!fParent); // Validity of parent's relativeY and fHeight depend s on immutability
338 fControls.push_back(control);
339 control->setParent(this, SkPoint::Make(0.0f, kSelectorHeight));
340 fHeight = SkMaxScalar(fHeight, control->height()); // Setting height to max child height.
341 }
342
343 SkScalar width() const override { return fParent ? (fParent->width()) : 0; }
344
345 SkScalar height() const override {
346 return fHeight;
347 }
348
349 // Propagate onClickRelease to control that currently captures mouse
350 void onClickRelease() override {
351 if (fCtrlOnClick) {
352 fCtrlOnClick->onClickRelease();
353 }
354 fCtrlOnClick = nullptr;
355 }
356
357 void onSetParent() override {
358 for (int i = 0; i < fControls.count(); i++) {
359 fControls[i]->onSetParent(); // Propagate to children
360 }
361
362 // Finalize control selector
363 // TODO can be moved to constructor if list-initialized
364 if (!finalizedChildren) {
365 fControlSelector = DiscreteSliderControl::Make(
366 SkString(fName), &fSelectedControl, 0, fControls.count()-1);
367 fControlSelector->setParent(this, SkPoint::Make(0.0f, 0.0f));
368 fHeight += kSelectorHeight;
369
370 SkASSERT(fControlSelector->height() <= kSelectorHeight);
371 }
372 }
373
374 /* A set of a selector and a list of controls. Displays the control from the list of controls
375 * with the index set by the aforementioned selector.
376 *
377 * @param name The name of the switcher. Will be displayed in the selector's label.
378 */
379 static sk_sp<ParentControl> Make(const SkString& name) {
380 return sk_sp<ParentControl>(new ControlSwitcher(name));
381 }
382
383 protected:
384 // Draw selector and currently selected control
385 void onDrawContent(SkCanvas* canvas) override {
386 fControlSelector->drawContent(canvas);
387 fControls[fSelectedControl]->drawContent(canvas);
388 }
389
390 // Returns true if control panel has mouse captured, false when it is ready to release
391 // capture
392 bool onClick(const SkPoint& click) override {
393 if (!fCtrlOnClick) {
394 if (fControlSelector->isInCtrlRegion(click)) {
395 fCtrlOnClick = fControlSelector.get();
396 } else if (fControls[fSelectedControl]->isInCtrlRegion(click)) {
397 fCtrlOnClick = fControls[fSelectedControl].get();
398 }
399 }
400 if (fCtrlOnClick) {
401 return fCtrlOnClick->click(click);
402 }
403
404 return false;
405 }
406
407 // Is in control region of selector or currently selected control
408 bool onIsInCtrlRegion(const SkPoint& clickPos) const override {
409 if (fControlSelector->isInCtrlRegion(clickPos)) {
410 return true;
411 }
412 if (fControls[fSelectedControl]->isInCtrlRegion(clickPos)) {
413 return true;
414 }
415
416 return false;
417 }
418
419 private:
420 ControlSwitcher(const SkString& name)
421 : INHERITED(name)
422 , fHeight(0.0)
423 , fSelectedControl(0)
424 , fCtrlOnClick(nullptr){}
425
426 bool finalizedChildren = false;
427
428 sk_sp<Control> fControlSelector;
429 SkScalar fHeight;
430 SkTArray<sk_sp<Control>> fControls;
431 int fSelectedControl;
432
433 Control* fCtrlOnClick;
434
435 static constexpr SkScalar kSelectorHeight = 40.0f;
436
437 typedef ParentControl INHERITED;
438 };
439
440 class ContinuousSliderControl : public Control {
441 public:
442 SkScalar height() const override {
443 return 2.0f * kLabelHeight;
444 }
445
446 void onSetParent() override {
447 fSlider = SkRect::MakeXYWH(0, kLabelHeight, kSliderWidth, kSliderHeight) ;
448 fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, fParent->width(), kSl iderHeight);
449 fSliderRange = fParent->width() - kSliderWidth;
450 }
451
452 /* Make a slider for an SkScalar.
453 *
454 * @params name The name of the control, displayed in the label
455 * @params output Pointer to the SkScalar that will be set by the slider
456 * @params min Min value for output
457 * @params max Max value for output
458 */
459 static sk_sp<Control> Make(const SkString& name, SkScalar* output, SkScalar min, SkScalar max) {
460 return sk_sp<Control>(new ContinuousSliderControl(name, output, min, max) );
461 }
462
463 protected:
464 void onDrawContent(SkCanvas* canvas) override {
465 SkASSERT(fParent);
466 SkScalar x = fSliderRange * (*fOutput - fMin) / (fMax - fMin);
467 fSlider.offsetTo(SkScalarPin(x, 0.0f, fSliderRange), fSlider.fTop);
468
469 SkString valueStr;
470 valueStr.appendScalar(*fOutput);
471 this->drawLabel(canvas, valueStr);
472
473 SkPaint sliderPaint;
474 sliderPaint.setColor(0xFFF3F3F3);
475 canvas->drawRect(fSlider, sliderPaint);
476
477 SkPaint ctrlRegionPaint;
478 ctrlRegionPaint.setColor(0xFFFFFFFF);
479 ctrlRegionPaint.setStyle(SkPaint::kStroke_Style);
480 ctrlRegionPaint.setStrokeWidth(2.0f);
481 canvas->drawRect(fCtrlRegion, ctrlRegionPaint);
482 }
483
484 bool onClick(const SkPoint& clickPos) override {
485 SkASSERT(fParent);
486 SkScalar x = SkScalarPin(clickPos.fX, 0.0f, fSliderRange);
487 *fOutput = (x/fSliderRange) * (fMax - fMin) + fMin;
488 return true;
489 }
490
491 bool onIsInCtrlRegion(const SkPoint& clickPos) const override {
492 SkASSERT(fParent);
493 return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, 1 , 1));
494 }
495
496 private:
497 ContinuousSliderControl(const SkString& name, SkScalar* output, SkScalar min , SkScalar max)
498 : INHERITED(name)
499 , fOutput(output)
500 , fMin(min)
501 , fMax(max) {}
502
503 SkScalar* fOutput;
504 SkScalar fMin;
505 SkScalar fMax;
506 SkRect fSlider;
507 SkRect fCtrlRegion;
508 SkScalar fSliderRange;
509
510 static constexpr SkScalar kSliderHeight = 20.0f;
511 static constexpr SkScalar kSliderWidth = 10.0f;
512
513 typedef Control INHERITED;
514 };
515
516 class RadialDirectionControl : public Control {
517 public:
518 SkScalar height() const override {
519 return kLabelHeight + 2.0f * kRegionRadius;
520 }
521
522 /* Make a direction selector.
523 *
524 * @params name The name of the control, displayed in the label
525 * @params output Pointer to the SkVector that will be set by the slider
526 */
527 static sk_sp<Control> Make(const SkString& name, SkVector* output) {
528 return sk_sp<Control>(new RadialDirectionControl(name, output));
529 }
530
531 protected:
532 void onDrawContent(SkCanvas* canvas) override {
533 SkASSERT(fParent);
534
535 SkString valueStr;
536 valueStr.appendf("%.2f, %.2f", fOutput->fX, fOutput->fY);
537 this->drawLabel(canvas, valueStr);
538
539 SkPoint lineEnd = SkPoint::Make(fCtrlRegion.centerX(), fCtrlRegion.cente rY())
540 + (*fOutput * (kRegionRadius - kCapRadius));
541 SkPaint linePaint;
542 linePaint.setColor(0xFFF3F3F3);
543 linePaint.setStrokeWidth(kStrokeWidth);
544 linePaint.setAntiAlias(true);
545 linePaint.setStrokeCap(SkPaint::kRound_Cap);
546 canvas->drawLine(fCtrlRegion.centerX(), fCtrlRegion.centerY(),
547 lineEnd.fX, lineEnd.fY, linePaint);
548
549 SkPaint ctrlRegionPaint;
550 ctrlRegionPaint.setColor(0xFFFFFFFF);
551 ctrlRegionPaint.setStyle(SkPaint::kStroke_Style);
552 ctrlRegionPaint.setStrokeWidth(2.0f);
553 ctrlRegionPaint.setAntiAlias(true);
554 canvas->drawCircle(fCtrlRegion.centerX(), fCtrlRegion.centerY(), kRegion Radius,
555 ctrlRegionPaint);
556 }
557
558 bool onClick(const SkPoint& clickPos) override {
559 SkASSERT(fParent);
560 fOutput->fX = clickPos.fX - fCtrlRegion.centerX();
561 fOutput->fY = clickPos.fY - fCtrlRegion.centerY();
562 fOutput->normalize();
563
564 return true;
565 }
566
567 bool onIsInCtrlRegion(const SkPoint& clickPos) const override {
568 SkASSERT(fParent);
569 return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY,
570 1, 1));
571 }
572
573 private:
574 RadialDirectionControl(const SkString& name, SkVector* output)
575 : INHERITED(name)
576 , fOutput(output) {
577 fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight,
578 kRegionRadius * 2.0f, kRegionRadius * 2.0 f);
579 }
580
581 SkVector* fOutput;
582 SkRect fCtrlRegion;
583
584 static constexpr SkScalar kRegionRadius = 50.0f;
585 static constexpr SkScalar kStrokeWidth = 6.0f;
586 static constexpr SkScalar kCapRadius = kStrokeWidth / 2.0f;
587
588 typedef Control INHERITED;
589 };
590
591 class ColorDisplay: public Control {
592 public:
593 SkScalar height() const override {
594 return kHeight;
595 }
596
597 void onSetParent() override {
598 fDisplayRect = SkRect::MakeXYWH(0.0f, kPadding, fParent->width(), kHeigh t - kPadding);
599 }
600
601 /* Make a display that shows an SkColor3f.
602 *
603 * @params output Pointer to the SkColor3f that will be displayed
604 */
605 static sk_sp<Control> Make(SkColor3f* input) {
606 return sk_sp<Control>(new ColorDisplay(SkString("ColorDisplay"), input)) ;
607 }
608
609 protected:
610 void onDrawContent(SkCanvas* canvas) override {
611 SkASSERT(fParent);
612
613 SkPaint displayPaint;
614 displayPaint.setColor(SkColor4f::FromColor3f(*fInput, 1.0f).toSkColor()) ;
615 canvas->drawRect(fDisplayRect, displayPaint);
616 }
617
618 private:
619 ColorDisplay(const SkString& name, SkColor3f* input)
620 : INHERITED(name)
621 , fInput(input) {}
622
623 SkColor3f* fInput;
624 SkRect fDisplayRect;
625
626 static constexpr SkScalar kHeight = 24.0f;
627 static constexpr SkScalar kPadding = 4.0f;
628
629 typedef Control INHERITED;
630 };
14 631
15 class BevelView : public SampleView { 632 class BevelView : public SampleView {
16 public: 633 public:
17 BevelView() 634 BevelView()
18 : fShapeBounds(SkRect::MakeWH(kShapeBoundsSize, kShapeBoundsSize)) 635 : fShapeBounds(SkRect::MakeWH(kShapeBoundsSize, kShapeBoundsSize))
19 , fRedLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.6f, 0.45f , 0.3f), 636 , fControlPanel(kCtrlRange) {
20 SkVector3::Make(0.0f, -5.0f , 1.0f)))
21 , fBlueLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.3f, 0.45 f, 0.6f),
22 SkVector3::Make(0.0f, 5.0f , 1.0f))) {
23 this->setBGColor(0xFF666868); // Slightly colorized gray for contrast 637 this->setBGColor(0xFF666868); // Slightly colorized gray for contrast
24 638
25 // Lights
26 SkLights::Builder builder;
27 builder.add(fRedLight);
28 builder.add(fBlueLight);
29 builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4 f)));
30 fLights = builder.finish();
31
32 // Controls 639 // Controls
33 640 fBevelWidth = 25.0f;
34 SkScalar currY = kSliderHeight; 641 fBevelHeight = 25.0f;
35 642 fBevelType = 0;
36 const SkScalar kWidthCtrlInitialPos = 0.2f; 643
37 fCtrlRangeRects[0] = SkRect::MakeXYWH(0.0f, currY, 644 int currLight = 0;
38 kCtrlRange + kSliderWidth, 645 fLightDefs[currLight++] =
39 kSliderHeight); 646 {SkVector::Make(0.0f, 1.0f), 1.0f, SkColor3f::Make(0.6f, 0.45f, 0.3f)};
40 fWidthCtrlRect = SkRect::MakeXYWH(kWidthCtrlInitialPos * kCtrlRange, cur rY, 647 fLightDefs[currLight++] =
41 kSliderWidth, kSliderHeight); 648 {SkVector::Make(0.0f, -1.0f), 1.0f, SkColor3f::Make(0.3f, 0.45f, 0.6f)};
42 fBevelWidth = kBevelWidthMax * kWidthCtrlInitialPos; 649 fLightDefs[currLight++] =
43 currY += 2 * kSliderHeight; 650 {SkVector::Make(1.0f, 0.0f), 1.0f, SkColor3f::Make(0.0f, 0.0f, 0 .0f)};
44 651 // Making sure we initialized all lights
45 const SkScalar kHeightCtrlInitialPos = 0.75f; 652 SkASSERT(currLight == kNumLights);
46 fCtrlRangeRects[1] = SkRect::MakeXYWH(0.0f, currY, 653
47 kCtrlRange + kSliderWidth, 654 fControlPanel.add(ContinuousSliderControl::Make(SkString("BevelWidth"), &fBevelWidth,
48 kSliderHeight); 655 1.0f, kShapeBoundsSize)) ;
49 fHeightCtrlRect = SkRect::MakeXYWH(kHeightCtrlInitialPos * kCtrlRange, c urrY, 656 fControlPanel.add(ContinuousSliderControl::Make(SkString("BevelHeight"), &fBevelHeight,
50 kSliderWidth, kSliderHeight); 657 -50.0f, 50.0f));
51 // Mapping from (0, 1) to (-1, 1) 658 fControlPanel.add(DiscreteSliderControl::Make(SkString("BevelType"), &fB evelType,
52 fBevelHeight = kBevelHeightMax * (kHeightCtrlInitialPos * 2.0f - 1.0f); 659 0, 2));
53 currY += 2 * kSliderHeight; 660 sk_sp<ParentControl> lightCtrlSelector = ControlSwitcher::Make(SkString( "SelectedLight"));
54 661 for (int i = 0; i < kNumLights; i++) {
55 const SkScalar kTypeCtrlInitialPos = 1.0f / (2.0f * kBevelTypeCount); 662 SkString name("Light");
56 fCtrlRangeRects[2] = SkRect::MakeXYWH(0.0f, currY, 663 name.appendS32(i);
57 kCtrlRange + kSliderWidth, 664 sk_sp<ParentControl> currLightPanel = ControlPanel::Make();
58 kSliderHeight); 665 SkString dirName(name);
59 fTypeCtrlRect = SkRect::MakeXYWH(kTypeCtrlInitialPos * kCtrlRange, currY , 666 dirName.append("Dir");
60 kSliderWidth, kSliderHeight); 667 currLightPanel->add(RadialDirectionControl::Make(dirName, &(fLightDe fs[i].fDirXY)));
61 fBevelType = (SkNormalSource::BevelType) SkScalarFloorToInt(kTypeCtrlIni tialPos); 668 SkString heightName(name);
62 currY += 2 * kSliderHeight; 669 heightName.append("Height");
63 670 currLightPanel->add(ContinuousSliderControl::Make(heightName, &(fLig htDefs[i].fDirZ),
64 fSelectedCtrlRect = nullptr; 671 0.0f, 2.0f));
672 SkString redName(name);
673 redName.append("Red");
674 currLightPanel->add(ContinuousSliderControl::Make(redName, &(fLightD efs[i].fColor.fX),
675 0.0f, 1.0f));
676 SkString greenName(name);
677 greenName.append("Green");
678 currLightPanel->add(ContinuousSliderControl::Make(greenName, &(fLigh tDefs[i].fColor.fY),
679 0.0f, 1.0f));
680 SkString blueName(name);
681 blueName.append("Blue");
682 currLightPanel->add(ContinuousSliderControl::Make(blueName, &(fLight Defs[i].fColor.fZ),
683 0.0f, 1.0f));
684 currLightPanel->add(ColorDisplay::Make(&(fLightDefs[i].fColor)));
685 lightCtrlSelector->add(currLightPanel);
686 }
687 fControlPanel.add(lightCtrlSelector);
688
689 fControlPanelSelected = false;
65 fDirtyNormalSource = true; 690 fDirtyNormalSource = true;
66 691
67 fLabelTypeface = sk_tool_utils::create_portable_typeface("sans-serif", S kFontStyle()); 692 fLabelTypeface = sk_tool_utils::create_portable_typeface("sans-serif", S kFontStyle());
68 } 693 }
69 694
70 protected: 695 protected:
71 bool onQuery(SkEvent *evt) override { 696 bool onQuery(SkEvent *evt) override {
72 if (SampleCode::TitleQ(*evt)) { 697 if (SampleCode::TitleQ(*evt)) {
73 SampleCode::TitleR(evt, "Bevel"); 698 SampleCode::TitleR(evt, "Bevel");
74 return true; 699 return true;
75 } 700 }
76 701
77 return this->INHERITED::onQuery(evt); 702 return this->INHERITED::onQuery(evt);
78 } 703 }
79 704
80 enum Shape { 705 enum Shape {
81 kCircle_Shape, 706 kCircle_Shape,
82 kRect_Shape, 707 kRect_Shape,
83 }; 708 };
84 void drawShape(enum Shape shape, SkCanvas* canvas) { 709 void drawShape(enum Shape shape, SkCanvas* canvas) {
85 canvas->save(); 710 canvas->save();
86 711
87 SkPaint paint; 712 SkPaint paint;
88 713
89 if (fDirtyNormalSource) { 714 if (fDirtyNormalSource) {
90 fNormalSource = SkNormalSource::MakeBevel(fBevelType, fBevelWidth, f BevelHeight); 715 fNormalSource = SkNormalSource::MakeBevel((SkNormalSource::BevelType )fBevelType,
716 fBevelWidth, fBevelHeight) ;
91 fDirtyNormalSource = false; 717 fDirtyNormalSource = false;
92 } 718 }
93 719
94 paint.setShader(SkLightingShader::Make(nullptr, fNormalSource, fLights)) ; 720 paint.setShader(SkLightingShader::Make(nullptr, fNormalSource, fLights)) ;
95 paint.setAntiAlias(true); 721 paint.setAntiAlias(true);
96 paint.setColor(0xFFDDDDDD); 722 paint.setColor(0xFFDDDDDD);
97 switch (shape) { 723 switch (shape) {
98 case kCircle_Shape: 724 case kCircle_Shape:
99 canvas->drawCircle(fShapeBounds.centerX(), fShapeBounds.centerY( ), 725 canvas->drawCircle(fShapeBounds.centerX(), fShapeBounds.centerY( ),
100 fShapeBounds.width()/2.0f, paint); 726 fShapeBounds.width()/2.0f, paint);
101 break; 727 break;
102 case kRect_Shape: 728 case kRect_Shape:
103 canvas->drawRect(fShapeBounds, paint); 729 canvas->drawRect(fShapeBounds, paint);
104 break; 730 break;
105 default: 731 default:
106 SkDEBUGFAIL("Invalid shape enum for drawShape"); 732 SkDEBUGFAIL("Invalid shape enum for drawShape");
107 } 733 }
108 734
109 canvas->restore(); 735 canvas->restore();
110 } 736 }
111 737
112 void onDrawContent(SkCanvas *canvas) override { 738 void onDrawContent(SkCanvas *canvas) override {
113 739
114 canvas->save(); 740 canvas->save();
115 canvas->resetMatrix(); // Force static controls and labels 741 canvas->resetMatrix(); // Force static control panel position
742 fControlPanel.drawContent(canvas);
743 canvas->restore();
116 744
117 // Draw controls 745 SkLights::Builder builder;
118 746 for (int i = 0; i < kNumLights; i++) {
119 SkPaint ctrlRectPaint; 747 builder.add(SkLights::Light::MakeDirectional(fLightDefs[i].fColor,
120 ctrlRectPaint.setColor(0xFFF3F3F3); 748 SkPoint3::Make(fLightDe fs[i].fDirXY.fX,
121 canvas->drawRect(fWidthCtrlRect, ctrlRectPaint); 749 fLightDe fs[i].fDirXY.fY,
122 canvas->drawRect(fHeightCtrlRect, ctrlRectPaint); 750 fLightDe fs[i].fDirZ)));
123 canvas->drawRect(fTypeCtrlRect, ctrlRectPaint);
124
125 SkPaint ctrlRectRangePaint;
126 ctrlRectRangePaint.setColor(0xFFFFFFFF);
127 ctrlRectRangePaint.setStyle(SkPaint::kStroke_Style);
128 ctrlRectRangePaint.setStrokeWidth(2.0f);
129
130 for (size_t i = 0; i < kNumControls; i++) {
131 canvas->drawRect(fCtrlRangeRects[i], ctrlRectRangePaint);
132 } 751 }
133 752 builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4 f)));
134 // Draw labels 753 fLights = builder.finish();
135 constexpr SkScalar kTextSize = 12.0f;
136 SkString widthLabel, heightLabel, typeLabel;
137 SkPaint labelPaint;
138 labelPaint.setTypeface(fLabelTypeface);
139 labelPaint.setAntiAlias(true);
140 labelPaint.setColor(0xFFFFFFFF);
141 labelPaint.setTextSize(kTextSize);
142
143 widthLabel.appendf("BevelWidth: %f", fBevelWidth);
144 heightLabel.appendf("BevelHeight: %f", fBevelHeight);
145 typeLabel.append("BevelType: ");
146
147 switch (fBevelType) {
148 case SkNormalSource::BevelType::kLinear:
149 typeLabel.append("Linear");
150 break;
151 case SkNormalSource::BevelType::kRoundedIn:
152 typeLabel.append("RoundedIn");
153 break;
154 case SkNormalSource::BevelType::kRoundedOut:
155 typeLabel.append("RoundedOut");
156 break;
157 }
158
159 canvas->drawText(widthLabel.c_str(), widthLabel.size(), 0,
160 fWidthCtrlRect.fTop - kTextSize/2.0f, labelPaint);
161 canvas->drawText(heightLabel.c_str(), heightLabel.size(), 0,
162 fHeightCtrlRect.fTop - kTextSize/2.0f, labelPaint);
163 canvas->drawText(typeLabel.c_str(), typeLabel.size(), 0,
164 fTypeCtrlRect.fTop - kTextSize/2.0f, labelPaint);
165
166 canvas->restore(); // Return to modified matrix when drawing shapes
167 754
168 // Draw shapes 755 // Draw shapes
169 SkScalar xPos = kCtrlRange + 25.0f; 756 SkScalar xPos = kCtrlRange + 25.0f;
170 SkScalar yPos = fShapeBounds.height(); 757 SkScalar yPos = fShapeBounds.height();
171 for (Shape shape : { kCircle_Shape, kRect_Shape }) { 758 for (Shape shape : { kCircle_Shape, kRect_Shape }) {
172 canvas->save(); 759 canvas->save();
173 canvas->translate(xPos, yPos); 760 canvas->translate(xPos, yPos);
174 this->drawShape(shape, canvas); 761 this->drawShape(shape, canvas);
175 canvas->restore(); 762 canvas->restore();
176 763
177 xPos += 1.2f * fShapeBounds.width(); 764 xPos += 1.2f * fShapeBounds.width();
178 } 765 }
179 } 766 }
180 767
181 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove rride { 768 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove rride {
182 return new SkView::Click(this); 769 return new SkView::Click(this);
183 } 770 }
184 771
185 bool onClick(Click *click) override { 772 bool onClick(Click *click) override {
186 SkScalar x = click->fCurr.fX; 773 // Control panel mouse handling
187 SkScalar y = click->fCurr.fY; 774 fControlPanelSelected = fControlPanel.inClick(click);
188 775
189 SkScalar dx = x - click->fPrev.fX; 776 if (fControlPanelSelected) { // Control modification
190 SkScalar dy = y - click->fPrev.fY;
191
192 // Control deselection
193 if (Click::State::kUp_State == click->fState) {
194 fSelectedCtrlRect = nullptr;
195 return true;
196 }
197
198 // Control selection
199 if (nullptr == fSelectedCtrlRect && Click::State::kDown_State == click-> fState) {
200 if (fWidthCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
201 fSelectedCtrlRect = &fWidthCtrlRect;
202 } else if (fHeightCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
203 fSelectedCtrlRect = &fHeightCtrlRect;
204 } else if (fTypeCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
205 fSelectedCtrlRect = &fTypeCtrlRect;
206 }
207 }
208
209 if (nullptr != fSelectedCtrlRect) { // Control modification
210 fSelectedCtrlRect->offsetTo(SkScalarPin(x, 0.0f, kCtrlRange), fSelec tedCtrlRect->fTop);
211
212 fBevelHeight = (fHeightCtrlRect.fLeft / kCtrlRange) * kBevelHeightMa x * 2.0f
213 - kBevelHeightMax;
214 fBevelWidth = (fWidthCtrlRect.fLeft / kCtrlRange) * kBevelWidthMax;
215 fBevelType = (SkNormalSource::BevelType)SkTMin(
216 SkScalarFloorToInt(kBevelTypeCount * fTypeCtrlRect.fLeft / k CtrlRange),
217 kBevelTypeCount - 1);
218
219 // Snap type controls to 3 positions
220 fTypeCtrlRect.offsetTo(kCtrlRange * ( ((int)fBevelType)/SkIntToScala r(kBevelTypeCount)
221 + 1.0f/(2.0f * kBevelTypeCount ) ),
222 fTypeCtrlRect.fTop);
223
224 // Ensuring width is non-zero
225 fBevelWidth = SkMaxScalar(1.0f, fBevelWidth);
226
227 fDirtyNormalSource = true; 777 fDirtyNormalSource = true;
228 778
229 this->inval(nullptr); 779 this->inval(nullptr);
230 return true; 780 return true;
231 } else { // Moving light
232 if (dx != 0 || dy != 0) {
233 float recipX = 1.0f / kAppWidth;
234 float recipY = 1.0f / kAppHeight;
235
236 if (0 == click->fModifierKeys) { // No modifier
237 fBlueLight = SkLights::Light::MakeDirectional(fBlueLight.col or(),
238 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0 f,
239 (kAppHeight/2.0f - y) * recipY * -3. 0f,
240 1.0f));
241 } else if (1 == click->fModifierKeys) { // Shift key
242 fRedLight = SkLights::Light::MakeDirectional(fRedLight.color (),
243 SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0 f,
244 (kAppHeight/2.0f - y) * recipY * -3. 0f,
245 1.0f));
246 }
247
248 SkLights::Builder builder;
249 builder.add(fRedLight);
250 builder.add(fBlueLight);
251 builder.add(SkLights::Light::MakeAmbient(
252 SkColor3f::Make(0.4f, 0.4f, 0.4f)));
253 fLights = builder.finish();
254
255 this->inval(nullptr);
256 }
257 return true;
258 } 781 }
259 782
783 // TODO move shapes
784 this->inval(nullptr);
260 return true; 785 return true;
261 } 786 }
262 787
263 private: 788 private:
264 static constexpr int kNumTestRects = 3; 789 static constexpr int kNumTestRects = 3;
265 790
266 static constexpr SkScalar kAppWidth = 400.0f;
267 static constexpr SkScalar kAppHeight = 400.0f;
268 static constexpr SkScalar kShapeBoundsSize = 120.0f; 791 static constexpr SkScalar kShapeBoundsSize = 120.0f;
269 792
270 static constexpr SkScalar kCtrlRange = 150.0f; 793 static constexpr SkScalar kCtrlRange = 150.0f;
271 static constexpr SkScalar kBevelWidthMax = kShapeBoundsSize;
272 static constexpr SkScalar kBevelHeightMax = 50.0f;
273 static constexpr int kBevelTypeCount = 3;
274 794
275 static constexpr SkScalar kSliderHeight = 20.0f; 795 static constexpr int kNumLights = 3;
276 static constexpr SkScalar kSliderWidth = 10.0f;
277 796
278 const SkRect fShapeBounds; 797 const SkRect fShapeBounds;
279 798
280 static constexpr int kNumControls = 3;
281 SkRect fCtrlRangeRects[kNumControls];
282 SkRect* fSelectedCtrlRect;
283 SkRect fWidthCtrlRect;
284 SkRect fHeightCtrlRect;
285 SkRect fTypeCtrlRect;
286
287 SkScalar fBevelWidth; 799 SkScalar fBevelWidth;
288 SkScalar fBevelHeight; 800 SkScalar fBevelHeight;
289 SkNormalSource::BevelType fBevelType; 801 int fBevelType;
802
290 sk_sp<SkNormalSource> fNormalSource; 803 sk_sp<SkNormalSource> fNormalSource;
291 bool fDirtyNormalSource; 804 bool fDirtyNormalSource;
292 805
293 sk_sp<SkLights> fLights; 806 sk_sp<SkLights> fLights;
294 SkLights::Light fRedLight; 807
295 SkLights::Light fBlueLight; 808 struct LightDef {
809 SkVector fDirXY;
810 SkScalar fDirZ;
811 SkColor3f fColor;
812
813 LightDef() {}
814 LightDef(SkVector dirXY, SkScalar dirZ, SkColor3f color)
815 : fDirXY(dirXY)
816 , fDirZ(dirZ)
817 , fColor(color) {}
818 };
819 LightDef fLightDefs[kNumLights];
820
821 ControlPanel fControlPanel;
822 bool fControlPanelSelected;
296 823
297 sk_sp<SkTypeface> fLabelTypeface; 824 sk_sp<SkTypeface> fLabelTypeface;
298 825
299 typedef SampleView INHERITED; 826 typedef SampleView INHERITED;
300 }; 827 };
301 828
302 ////////////////////////////////////////////////////////////////////////////// 829 //////////////////////////////////////////////////////////////////////////////
303 830
304 static SkView* MyFactory() { return new BevelView; } 831 static SkView* MyFactory() { return new BevelView; }
305 static SkViewRegister reg(MyFactory); 832 static SkViewRegister reg(MyFactory);
306 833
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698