Bug 1308268 - Add a Grid Outline to layout panel. r?gl draft
authorMicah Tigley <tigleym@gmail.com>
Wed, 22 Feb 2017 22:58:56 -0700
changeset 489756 7e36b6a4db408f03094bfef10ac743026c6fca85
parent 488302 32dcdde1fc64fc39a9065dc4218265dbc727673f
child 547063 0026c415c00a3a0dc29334f4c4eb79c203a2121f
push id46887
push userbmo:tigleym@gmail.com
push dateSat, 25 Feb 2017 20:53:50 +0000
reviewersgl
bugs1308268
milestone54.0a1
Bug 1308268 - Add a Grid Outline to layout panel. r?gl MozReview-Commit-ID: 5BjnFGO5PmD
devtools/client/inspector/layout/components/App.js
devtools/client/inspector/layout/components/Grid.js
devtools/client/inspector/layout/components/GridOutline.js
devtools/client/inspector/layout/components/moz.build
devtools/client/inspector/layout/layout.js
devtools/client/preferences/devtools.js
devtools/client/themes/layout.css
--- 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;
 }