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

Unified Diff: third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js

Issue 2292583002: DevTools: Create 2D slider for shadow-editor offset (Closed)
Patch Set: 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js b/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js
index 74a23375f05e4e34776ea655363b76441b91a928..d40d339f714b88d262cf12141bc3d0528336d64c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/CSSShadowEditor.js
@@ -21,20 +21,27 @@ WebInspector.CSSShadowEditor = function()
this._insetButton.textContent = WebInspector.UIString("Inset");
this._insetButton.addEventListener("click", this._onButtonClick.bind(this), false);
- var inputs;
- inputs = this._createSliderField(WebInspector.UIString("X offset"), true);
- this._xInput = inputs.textInput;
- this._xSlider = inputs.rangeInput;
- inputs = this._createSliderField(WebInspector.UIString("Y offset"), true);
- this._yInput = inputs.textInput;
- this._ySlider = inputs.rangeInput;
- inputs = this._createSliderField(WebInspector.UIString("Blur"), false);
- this._blurInput = inputs.textInput;
- this._blurSlider = inputs.rangeInput;
- inputs = this._createSliderField(WebInspector.UIString("Spread"), false);
- this._spreadInput = inputs.textInput;
- this._spreadSlider = inputs.rangeInput;
- this._spreadField = inputs.field;
+ var xField = this.contentElement.createChild("div", "shadow-editor-field");
+ this._xInput = this._createTextInput(xField, WebInspector.UIString("X offset"));
+ var yField = this.contentElement.createChild("div", "shadow-editor-field");
+ this._yInput = this._createTextInput(yField, WebInspector.UIString("Y offset"));
+ this._xySlider = xField.createChild("canvas", "shadow-editor-2D-slider");
+ this._xySlider.width = WebInspector.CSSShadowEditor.canvasSize;
+ this._xySlider.height = WebInspector.CSSShadowEditor.canvasSize;
+ this._xySlider.tabIndex = -1;
+ this._halfCanvasSize = WebInspector.CSSShadowEditor.canvasSize / 2;
+ this._innerCanvasSize = this._halfCanvasSize - WebInspector.CSSShadowEditor.sliderThumbRadius;
+ WebInspector.installDragHandle(this._xySlider, this._dragStart.bind(this), this._dragMove.bind(this), null, "default");
+ this._xySlider.addEventListener("keydown", this._onCanvasUpDown.bind(this), false);
+ this._xySlider.addEventListener("blur", this._onCanvasBlur.bind(this), false);
+
+ var blurField = this.contentElement.createChild("div", "shadow-editor-blur-field");
+ this._blurInput = this._createTextInput(blurField, WebInspector.UIString("Blur"));
+ this._blurSlider = this._createSlider(blurField);
+
+ this._spreadField = this.contentElement.createChild("div", "shadow-editor-field");
+ this._spreadInput = this._createTextInput(this._spreadField, WebInspector.UIString("Spread"));
+ this._spreadSlider = this._createSlider(this._spreadField);
}
/** @enum {symbol} */
@@ -43,19 +50,22 @@ WebInspector.CSSShadowEditor.Events = {
}
/** @type {number} */
-WebInspector.CSSShadowEditor.maxRange = 40;
+WebInspector.CSSShadowEditor.maxRange = 20;
/** @type {string} */
WebInspector.CSSShadowEditor.defaultUnit = "px";
+/** @type {number} */
+WebInspector.CSSShadowEditor.sliderThumbRadius = 6;
+/** @type {number} */
+WebInspector.CSSShadowEditor.canvasSize = 88;
WebInspector.CSSShadowEditor.prototype = {
/**
+ * @param {!Element} field
* @param {string} propertyName
- * @param {boolean} negativeAllowed
- * @return {{textInput: !Element, rangeInput: !Element, field: !Element}}
+ * @return {!Element}
*/
- _createSliderField: function(propertyName, negativeAllowed)
+ _createTextInput: function(field, propertyName)
{
- var field = this.contentElement.createChild("div", "shadow-editor-field");
var label = field.createChild("label", "shadow-editor-label");
label.textContent = propertyName;
label.setAttribute("for", propertyName);
@@ -66,11 +76,19 @@ WebInspector.CSSShadowEditor.prototype = {
textInput.addEventListener("mousewheel", this._handleValueModification.bind(this), false);
textInput.addEventListener("input", this._onTextInput.bind(this), false);
textInput.addEventListener("blur", this._onTextBlur.bind(this), false);
- var halfRange = WebInspector.CSSShadowEditor.maxRange / 2;
- var slider = negativeAllowed ? createSliderLabel(-halfRange, halfRange) : createSliderLabel(0, WebInspector.CSSShadowEditor.maxRange);
+ return textInput;
+ },
+
+ /**
+ * @param {!Element} field
+ * @return {!Element}
+ */
+ _createSlider: function(field)
+ {
+ var slider = createSliderLabel(0, WebInspector.CSSShadowEditor.maxRange, -1);
slider.addEventListener("input", this._onSliderInput.bind(this), false);
field.appendChild(slider);
- return {field: field, textInput: textInput, rangeInput: slider};
+ return slider;
},
/**
@@ -99,10 +117,9 @@ WebInspector.CSSShadowEditor.prototype = {
this._yInput.value = this._model.offsetY().asCSSText();
this._blurInput.value = this._model.blurRadius().asCSSText();
this._spreadInput.value = this._model.spreadRadius().asCSSText();
- this._xSlider.value = this._model.offsetX().amount;
- this._ySlider.value = this._model.offsetY().amount;
this._blurSlider.value = this._model.blurRadius().amount;
this._spreadSlider.value = this._model.spreadRadius().amount;
+ this._updateCanvas();
},
_updateButtons: function()
@@ -111,6 +128,47 @@ WebInspector.CSSShadowEditor.prototype = {
this._outsetButton.classList.toggle("enabled", !this._model.inset());
},
+ _updateCanvas: function()
+ {
+ var context = this._xySlider.getContext("2d");
+ context.clearRect(0, 0, this._xySlider.width, this._xySlider.height);
+
+ // Draw dashed axes.
+ context.save();
+ context.setLineDash([1, 1]);
+ context.strokeStyle = "rgba(0, 0, 0, 0.2)";
+ context.beginPath();
+ context.moveTo(this._halfCanvasSize, 0);
+ context.lineTo(this._halfCanvasSize, WebInspector.CSSShadowEditor.canvasSize);
+ context.moveTo(0, this._halfCanvasSize);
+ context.lineTo(WebInspector.CSSShadowEditor.canvasSize, this._halfCanvasSize);
+ context.stroke();
+ context.restore();
+
+ var thumbPoint = this._sliderThumbPosition();
+ // Draw 2D slider line.
+ context.save();
+ context.translate(this._halfCanvasSize, this._halfCanvasSize);
+ context.lineWidth = 2;
+ context.strokeStyle = "rgba(0, 0, 0, 0.3)";
+ context.beginPath();
+ context.moveTo(0, 0);
+ context.lineTo(thumbPoint.x, thumbPoint.y);
+ context.stroke();
+ // Draw 2D slider thumb.
+ context.beginPath();
+ if (this._xySlider.hasFocus) {
+ context.fillStyle = "rgba(66, 133, 244, 0.4)";
+ context.arc(thumbPoint.x, thumbPoint.y, WebInspector.CSSShadowEditor.sliderThumbRadius + 2, 0, 2 * Math.PI);
+ context.fill();
+ }
+ context.beginPath()
+ context.fillStyle = "#4285F4";
+ context.arc(thumbPoint.x, thumbPoint.y, WebInspector.CSSShadowEditor.sliderThumbRadius, 0, 2 * Math.PI);
+ context.fill();
+ context.restore();
+ },
+
/**
* @param {!Event} event
*/
@@ -169,10 +227,10 @@ WebInspector.CSSShadowEditor.prototype = {
return;
if (event.currentTarget === this._xInput) {
this._model.setOffsetX(length);
- this._xSlider.value = length.amount;
+ this._updateCanvas();
} else if (event.currentTarget === this._yInput) {
this._model.setOffsetY(length);
- this._ySlider.value = length.amount;
+ this._updateCanvas();
} else if (event.currentTarget === this._blurInput) {
this._model.setBlurRadius(length);
this._blurSlider.value = length.amount;
@@ -187,7 +245,7 @@ WebInspector.CSSShadowEditor.prototype = {
{
if (!this._changedElement)
return;
- var length = !this._changedElement.value ? WebInspector.CSSLength.zero() : WebInspector.CSSLength.parse(this._changedElement.value);
+ var length = !this._changedElement.value.trim() ? WebInspector.CSSLength.zero() : WebInspector.CSSLength.parse(this._changedElement.value);
if (!length)
length = WebInspector.CSSLength.parse(this._changedElement.value + WebInspector.CSSShadowEditor.defaultUnit);
if (!length) {
@@ -198,11 +256,11 @@ WebInspector.CSSShadowEditor.prototype = {
if (this._changedElement === this._xInput) {
this._model.setOffsetX(length);
this._xInput.value = length.asCSSText();
- this._xSlider.value = length.amount;
+ this._updateCanvas();
} else if (this._changedElement === this._yInput) {
this._model.setOffsetY(length);
this._yInput.value = length.asCSSText();
- this._ySlider.value = length.amount;
+ this._updateCanvas();
} else if (this._changedElement === this._blurInput) {
if (length.amount < 0)
length = WebInspector.CSSLength.zero();
@@ -223,15 +281,7 @@ WebInspector.CSSShadowEditor.prototype = {
*/
_onSliderInput: function(event)
{
- if (event.currentTarget === this._xSlider) {
- this._model.setOffsetX(new WebInspector.CSSLength(this._xSlider.value, this._model.offsetX().unit || WebInspector.CSSShadowEditor.defaultUnit));
- this._xInput.value = this._model.offsetX().asCSSText();
- this._xInput.classList.toggle("invalid", false);
- } else if (event.currentTarget === this._ySlider) {
- this._model.setOffsetY(new WebInspector.CSSLength(this._ySlider.value, this._model.offsetY().unit || WebInspector.CSSShadowEditor.defaultUnit));
- this._yInput.value = this._model.offsetY().asCSSText();
- this._yInput.classList.toggle("invalid", false);
- } else if (event.currentTarget === this._blurSlider) {
+ if (event.currentTarget === this._blurSlider) {
this._model.setBlurRadius(new WebInspector.CSSLength(this._blurSlider.value, this._model.blurRadius().unit || WebInspector.CSSShadowEditor.defaultUnit));
this._blurInput.value = this._model.blurRadius().asCSSText();
this._blurInput.classList.toggle("invalid", false);
@@ -243,5 +293,109 @@ WebInspector.CSSShadowEditor.prototype = {
this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
},
+ /**
+ * @param {!Event} event
+ * @return {boolean}
+ */
+ _dragStart: function(event)
+ {
+ if (event.currentTarget === this._xySlider) {
+ this._xySlider.focus();
+ this._xySlider.hasFocus = true;
lushnikov 2016/08/30 19:22:19 let's not add fields to the DOM wrappers - i think
flandy 2016/08/30 22:50:42 Done. I've added Document.prototype.deepActiveElem
+ }
+ this._canvasOrigin = new WebInspector.Geometry.Point(this._xySlider.totalOffsetLeft() + this._halfCanvasSize, this._xySlider.totalOffsetTop() + this._halfCanvasSize);
+ var clickedPoint = new WebInspector.Geometry.Point(event.x - this._canvasOrigin.x, event.y - this._canvasOrigin.y);
+ var thumbPoint = this._sliderThumbPosition();
+ if (clickedPoint.distanceTo(thumbPoint) >= WebInspector.CSSShadowEditor.sliderThumbRadius)
+ this._dragMove(event);
+ return true;
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _dragMove: function(event)
+ {
+ var point = new WebInspector.Geometry.Point(event.x - this._canvasOrigin.x, event.y - this._canvasOrigin.y);
lushnikov 2016/08/30 19:22:19 nit: excessive spaces
flandy 2016/08/30 22:50:42 Done.
+ var constrainedPoint = this._constrainPoint(point, this._innerCanvasSize);
+ var newX = Math.round((constrainedPoint.x / this._innerCanvasSize) * WebInspector.CSSShadowEditor.maxRange);
+ var newY = Math.round((constrainedPoint.y / this._innerCanvasSize) * WebInspector.CSSShadowEditor.maxRange);
+ this._model.setOffsetX(new WebInspector.CSSLength(newX, this._model.offsetX().unit || WebInspector.CSSShadowEditor.defaultUnit));
+ this._model.setOffsetY(new WebInspector.CSSLength(newY, this._model.offsetY().unit || WebInspector.CSSShadowEditor.defaultUnit));
+ this._xInput.value = this._model.offsetX().asCSSText();
+ this._yInput.value = this._model.offsetY().asCSSText();
+ this._xInput.classList.toggle("invalid", false);
lushnikov 2016/08/30 19:22:19 nit: this._xInput.classList.remove("invalid")
flandy 2016/08/30 22:50:42 Done.
+ this._yInput.classList.toggle("invalid", false);
+ this._updateCanvas();
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ _onCanvasBlur: function()
+ {
+ this._xySlider.hasFocus = false;
+ this._updateCanvas();
+ },
+
+ /**
+ * @param {!Event} event
+ */
+ _onCanvasUpDown: function(event)
+ {
+ var upDown = (event.key === "ArrowUp" || event.key === "ArrowDown");
lushnikov 2016/08/30 19:22:19 can we use WI.KeyboardShortcuts for key detection?
flandy 2016/08/30 22:50:41 This seems unnecessary here. Also, keyCode is depr
+ var leftRight = (event.key === "ArrowRight" || event.key === "ArrowLeft")
+ if (!upDown && !leftRight || !this._xySlider.hasFocus)
lushnikov 2016/08/30 19:22:19 how could it be non-focused? doesn't even triggeri
flandy 2016/08/30 22:50:41 Yes good point. Removed.
+ return
lushnikov 2016/08/30 19:22:19 ; missing
flandy 2016/08/30 22:50:41 Done.
+ event.consume(true);
+
+ var newAmount;
+ if (upDown) {
+ var offsetY = this._model.offsetY();
+ newAmount = event.key === "ArrowUp" ? offsetY.amount - 1 : offsetY.amount + 1;
lushnikov 2016/08/30 19:22:19 Let's compare for event.key only only once, in the
flandy 2016/08/30 22:50:41 Done.
+ newAmount = Number.constrain(newAmount, -WebInspector.CSSShadowEditor.maxRange, WebInspector.CSSShadowEditor.maxRange);
+ this._model.setOffsetY(new WebInspector.CSSLength(newAmount, offsetY.unit || WebInspector.CSSShadowEditor.defaultUnit));
+ this._yInput.value = this._model.offsetY().asCSSText();
+ this._yInput.classList.toggle("invalid", false);
+ } else if (leftRight) {
+ var offsetX = this._model.offsetX()
+ newAmount = event.key === "ArrowRight" ? offsetX.amount + 1 : offsetX.amount - 1;
+ newAmount = Number.constrain(newAmount, -WebInspector.CSSShadowEditor.maxRange, WebInspector.CSSShadowEditor.maxRange);
+ this._model.setOffsetX(new WebInspector.CSSLength(newAmount, offsetX.unit || WebInspector.CSSShadowEditor.defaultUnit));
+ this._xInput.value = this._model.offsetX().asCSSText();
+ this._xInput.classList.toggle("invalid", false);
+ }
+ this._updateCanvas();
+ this.dispatchEventToListeners(WebInspector.CSSShadowEditor.Events.ShadowChanged, this._model);
+ },
+
+ /**
+ * @param {!WebInspector.Geometry.Point} point
+ * @param {number} max
+ * @return {!WebInspector.Geometry.Point}
+ */
+ _constrainPoint: function(point, max)
+ {
+ var newPoint = new WebInspector.Geometry.Point(point.x, point.y);
+ if ((Math.abs(point.x) <= max && Math.abs(point.y) <= max) || (point.x === 0 && point.y === 0))
lushnikov 2016/08/30 19:22:19 why special case for zeroes?
flandy 2016/08/30 22:50:42 To avoid divide by zero if max < 0. I never use ma
+ return newPoint;
+ if (Math.abs(point.x) > Math.abs(point.y)) {
lushnikov 2016/08/30 19:22:19 the function could be written simpler: if (Mat
flandy 2016/08/30 22:50:41 Thanks! Done.
+ newPoint.x = point.x < 0 ? -max : max;
+ newPoint.y = newPoint.x * point.y / point.x;
+ } else {
+ newPoint.y = point.y < 0 ? -max : max;
+ newPoint.x = newPoint.y * point.x / point.y;
+ }
+ return newPoint;
+ },
+
+ /**
+ * @return {!WebInspector.Geometry.Point}
+ */
+ _sliderThumbPosition: function()
+ {
+ var x = (this._model.offsetX().amount / WebInspector.CSSShadowEditor.maxRange) * this._innerCanvasSize;
+ var y = (this._model.offsetY().amount / WebInspector.CSSShadowEditor.maxRange) * this._innerCanvasSize;
+ return this._constrainPoint(new WebInspector.Geometry.Point(x, y), this._innerCanvasSize);
+ },
+
__proto__: WebInspector.VBox.prototype
-}
+}
« no previous file with comments | « no previous file | third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698