Bug 1308268 - Add a Grid Outline to layout panel. r?gl
MozReview-Commit-ID: 5BjnFGO5PmD
--- a/devtools/client/inspector/layout/components/App.js
+++ b/devtools/client/inspector/layout/components/App.js
@@ -25,16 +25,17 @@ const App = createClass({
displayName: "App",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
+ showGridOutline: PropTypes.bool.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
onShowBoxModelHighlighter: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
onToggleShowGridLineNumbers: PropTypes.func.isRequired,
onToggleShowInfiniteLines: PropTypes.func.isRequired,
},
--- a/devtools/client/inspector/layout/components/Grid.js
+++ b/devtools/client/inspector/layout/components/Grid.js
@@ -4,64 +4,77 @@
"use strict";
const { addons, createClass, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const GridDisplaySettings = createFactory(require("./GridDisplaySettings"));
const GridList = createFactory(require("./GridList"));
+const GridOutline = createFactory(require("./GridOutline"));
const Types = require("../types");
const { getStr } = require("../utils/l10n");
module.exports = createClass({
displayName: "Grid",
propTypes: {
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
+ showGridOutline: PropTypes.bool.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
onToggleShowGridLineNumbers: PropTypes.func.isRequired,
onToggleShowInfiniteLines: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
render() {
let {
getSwatchColorPickerTooltip,
grids,
highlighterSettings,
+ showGridOutline,
onSetGridOverlayColor,
onToggleGridHighlighter,
onToggleShowGridLineNumbers,
onToggleShowInfiniteLines,
} = this.props;
return grids.length ?
dom.div(
{
id: "layout-grid-container",
},
- GridList({
- getSwatchColorPickerTooltip,
- grids,
- onSetGridOverlayColor,
- onToggleGridHighlighter,
- }),
- GridDisplaySettings({
- highlighterSettings,
- onToggleShowGridLineNumbers,
- onToggleShowInfiniteLines,
- })
- )
+ showGridOutline ?
+ GridOutline({
+ grids,
+ })
+ :
+ null,
+ dom.div(
+ {
+ className: "grid-content",
+ },
+ GridList({
+ getSwatchColorPickerTooltip,
+ grids,
+ onSetGridOverlayColor,
+ onToggleGridHighlighter,
+ }),
+ GridDisplaySettings({
+ highlighterSettings,
+ onToggleShowGridLineNumbers,
+ onToggleShowInfiniteLines,
+ })
+ ))
:
dom.div(
{
className: "layout-no-grids",
},
getStr("layout.noGrids")
);
},
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/layout/components/GridOutline.js
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { addons, createClass, DOM: dom, PropTypes } =
+ require("devtools/client/shared/vendor/react");
+
+const Types = require("../types");
+
+// Move SVG grid to the right 100 units, so that it is not flushed against the edge of
+// layout border
+const TRANSLATE_X = -100;
+const TRANSLATE_Y = 0;
+
+const VIEWPORT_HEIGHT = 100;
+const VIEWPORT_WIDTH = 450;
+
+module.exports = createClass({
+
+ displayName: "GridOutline",
+
+ propTypes: {
+ grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
+ },
+
+ mixins: [ addons.PureRenderMixin ],
+
+ getInitialState() {
+ return {
+ selectedGrids: [],
+ };
+ },
+
+ componentWillReceiveProps({ grids }) {
+ this.setState({
+ selectedGrids: grids.filter(grid => grid.highlighted),
+ });
+ },
+
+ renderGridCell(columnNumber, rowNumber, color) {
+ return dom.rect(
+ {
+ className: "grid-outline-cell",
+ x: columnNumber,
+ y: rowNumber,
+ width: 10,
+ height: 10,
+ stroke: color,
+ }
+ );
+ },
+
+ renderGridFragment({ color, gridFragments }) {
+ // TODO: We are drawing the first fragment since only one is currently being stored.
+ // In future we will need to iterate over all fragments of a grid.
+ const { rows, cols } = gridFragments[0];
+ const numOfColLines = cols.lines.length - 1;
+ const numOfRowLines = rows.lines.length - 1;
+ const rectangles = [];
+
+ // Draw a rectangle that acts as a border for the grid outline
+ const border = this.renderGridOutlineBorder(numOfRowLines, numOfColLines, color);
+ rectangles.push(border);
+
+ let x = 1;
+ let y = 1;
+ const width = 10;
+ const height = 10;
+
+ // Draw the cells within the grid outline border
+ for (let row = 0; row < numOfRowLines; row++) {
+ for (let col = 0; col < numOfColLines; col++) {
+ rectangles.push(this.renderGridCell(x, y, color));
+ x += width;
+ }
+
+ x = 1;
+ y += height;
+ }
+
+ return rectangles;
+ },
+
+ renderGridOutline(gridFragments) {
+ return dom.g(
+ {
+ className: "grid-cell-group",
+ },
+ gridFragments.map(gridFragment => this.renderGridFragment(gridFragment))
+ );
+ },
+
+ renderGridOutlineBorder(numberOfRows, numberOfCols, color) {
+ return dom.rect(
+ {
+ className: "grid-outline-border",
+ x: 1,
+ y: 1,
+ width: numberOfCols * 10,
+ height: numberOfRows * 10,
+ stroke: color,
+ }
+ );
+ },
+
+ render() {
+ return this.state.selectedGrids.length ?
+ dom.svg(
+ {
+ className: "grid-outline",
+ width: "100%",
+ height: 100,
+ viewBox: `${TRANSLATE_X} ${TRANSLATE_Y} ${VIEWPORT_WIDTH} ${VIEWPORT_HEIGHT}`,
+ },
+ this.renderGridOutline(this.state.selectedGrids)
+ )
+ :
+ null;
+ },
+
+});
--- a/devtools/client/inspector/layout/components/moz.build
+++ b/devtools/client/inspector/layout/components/moz.build
@@ -13,9 +13,10 @@ DevToolsModules(
'BoxModelInfo.js',
'BoxModelMain.js',
'BoxModelProperties.js',
'ComputedProperty.js',
'Grid.js',
'GridDisplaySettings.js',
'GridItem.js',
'GridList.js',
+ 'GridOutline.js',
)
--- a/devtools/client/inspector/layout/layout.js
+++ b/devtools/client/inspector/layout/layout.js
@@ -33,16 +33,17 @@ const App = createFactory(require("./com
const EditingSession = require("./utils/editing-session");
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
new LocalizationHelper("devtools/client/locales/inspector.properties");
const NUMERIC = /^-?[\d\.]+$/;
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
+const SHOW_GRID_OUTLINE_PREF = "devtools.gridinspector.showGridOutline";
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
// Default grid colors.
const GRID_COLORS = [
"#05E4EE",
"#BB9DFF",
"#FFB53B",
"#71F362",
@@ -108,16 +109,22 @@ LayoutView.prototype = {
/**
* Shows the box model properties under the box model if true, otherwise, hidden by
* default.
*/
showBoxModelProperties: true,
/**
+ * Shows the grid outline if user preferences are set to true, otherwise, hidden by
+ * default.
+ */
+ showGridOutline: Services.prefs.getBoolPref(SHOW_GRID_OUTLINE_PREF),
+
+ /**
* Hides the box-model highlighter on the currently selected element.
*/
onHideBoxModelHighlighter: () => {
let toolbox = this.inspector.toolbox;
toolbox.highlighterUtils.unhighlight();
},
/**
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -69,16 +69,17 @@ pref("devtools.inspector.colorWidget.ena
// Enable the Font Inspector
pref("devtools.fontinspector.enabled", true);
// Enable the Layout View
pref("devtools.layoutview.enabled", false);
// Grid highlighter preferences
pref("devtools.gridinspector.showGridLineNumbers", false);
+pref("devtools.gridinspector.showGridOutline", false);
pref("devtools.gridinspector.showInfiniteLines", false);
// By how many times eyedropper will magnify pixels
pref("devtools.eyedropper.zoom", 6);
// Enable to collapse attributes that are too long.
pref("devtools.markup.collapseAttributes", true);
--- a/devtools/client/themes/layout.css
+++ b/devtools/client/themes/layout.css
@@ -35,20 +35,49 @@
}
/**
* Grid Container
*/
#layout-grid-container {
display: flex;
+ flex-direction: column;
margin: 5px;
}
/**
+ * Grid Content
+ */
+
+.grid-content {
+ display: flex;
+ flex: 1;
+}
+
+/**
+ * Grid Outline
+ */
+
+#grid-outline {
+ margin: 5px auto;
+}
+
+.grid-outline-border {
+ stroke-width: 0.75;
+ fill: none;
+}
+
+.grid-outline-cell {
+ fill: none;
+ pointer-events: all;
+ stroke-dasharray: 0.5, 2;
+}
+
+/**
* Container when no grids are present
*/
.layout-no-grids {
font-style: italic;
text-align: center;
padding: 0.5em;
}