Bug 766054 - [debugger] experiment with collapsed panels, r=rcampbell
authorVictor Porof <vporof@mozilla.com>
Fri, 20 Jul 2012 11:56:46 +0300
changeset 105436 350499bc1b85b32fbf55da7b78b611664bca21aa
parent 105435 11a0db7262a04c8481f672122d1bded2636c5451
child 105437 9ea94325f9f5d62832f5880557e28e07d3188ef7
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersrcampbell
bugs766054
milestone17.0a1
Bug 766054 - [debugger] experiment with collapsed panels, r=rcampbell
browser/app/profile/firefox.js
browser/devtools/debugger/DebuggerUI.jsm
browser/devtools/debugger/debugger-controller.js
browser/devtools/debugger/debugger-view.js
browser/devtools/debugger/debugger.xul
browser/devtools/debugger/test/Makefile.in
browser/devtools/debugger/test/browser_dbg_pane-collapse.js
browser/themes/gnomestripe/devtools/debugger-collapse.png
browser/themes/gnomestripe/devtools/debugger-expand.png
browser/themes/gnomestripe/devtools/debugger.css
browser/themes/gnomestripe/jar.mn
browser/themes/pinstripe/devtools/debugger-collapse.png
browser/themes/pinstripe/devtools/debugger-expand.png
browser/themes/pinstripe/devtools/debugger.css
browser/themes/pinstripe/jar.mn
browser/themes/winstripe/devtools/debugger-collapse.png
browser/themes/winstripe/devtools/debugger-expand.png
browser/themes/winstripe/devtools/debugger.css
browser/themes/winstripe/jar.mn
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1025,17 +1025,19 @@ pref("devtools.debugger.remote-autoconne
 pref("devtools.debugger.remote-connection-retries", 3);
 pref("devtools.debugger.remote-timeout", 3000);
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.height", 250);
 pref("devtools.debugger.ui.remote-win.width", 900);
 pref("devtools.debugger.ui.remote-win.height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
+pref("devtools.debugger.ui.stackframes-pane-visible", true);
 pref("devtools.debugger.ui.variables-width", 300);
+pref("devtools.debugger.ui.variables-pane-visible", true);
 
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -28,16 +28,17 @@ let EXPORTED_SYMBOLS = ["DebuggerUI"];
  *        The chrome window for which the DebuggerUI instance is created.
  */
 function DebuggerUI(aWindow) {
   this.chromeWindow = aWindow;
   this.listenToTabs();
 }
 
 DebuggerUI.prototype = {
+
   /**
    * Update the status of tool's menuitems and buttons when
    * the user switch tabs.
    */
   listenToTabs: function DUI_listenToTabs() {
     let win = this.chromeWindow;
     let tabs = win.gBrowser.tabContainer;
 
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -45,16 +45,17 @@ let DebuggerController = {
    */
   _startupDebugger: function DC__startupDebugger() {
     if (this._isInitialized) {
       return;
     }
     this._isInitialized = true;
     window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
 
+    DebuggerView.cacheView();
     DebuggerView.initializePanes();
     DebuggerView.initializeEditor(function() {
       DebuggerView.GlobalSearch.initialize();
       DebuggerView.Scripts.initialize();
       DebuggerView.StackFrames.initialize();
       DebuggerView.Breakpoints.initialize();
       DebuggerView.Properties.initialize();
       DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
@@ -1688,113 +1689,164 @@ let L10N = {
     return this.stringBundle.formatStringFromName(aName, aArray, aArray.length);
   }
 };
 
 XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
   return Services.strings.createBundle(DBG_STRINGS_URI);
 });
 
+const STACKFRAMES_WIDTH = "devtools.debugger.ui.stackframes-width";
+const STACKFRAMES_VISIBLE = "devtools.debugger.ui.stackframes-pane-visible";
+const VARIABLES_WIDTH = "devtools.debugger.ui.variables-width";
+const VARIABLES_PANE_VISIBLE = "devtools.debugger.ui.variables-pane-visible";
+const REMOTE_AUTO_CONNECT = "devtools.debugger.remote-autoconnect";
+const REMOTE_HOST = "devtools.debugger.remote-host";
+const REMOTE_PORT = "devtools.debugger.remote-port";
+const REMOTE_CONNECTION_RETRIES = "devtools.debugger.remote-connection-retries";
+const REMOTE_TIMEOUT = "devtools.debugger.remote-timeout";
+
 /**
  * Shortcuts for accessing various debugger preferences.
  */
 let Prefs = {
 
   /**
    * Gets the preferred stackframes pane width.
    * @return number
    */
   get stackframesWidth() {
-    if (this._sfrmWidth === undefined) {
-      this._sfrmWidth = Services.prefs.getIntPref("devtools.debugger.ui.stackframes-width");
+    if (this._stackframesWidth === undefined) {
+      this._stackframesWidth = Services.prefs.getIntPref(STACKFRAMES_WIDTH);
     }
-    return this._sfrmWidth;
+    return this._stackframesWidth;
   },
 
   /**
    * Sets the preferred stackframes pane width.
-   * @return number
+   * @param number value
    */
   set stackframesWidth(value) {
-    Services.prefs.setIntPref("devtools.debugger.ui.stackframes-width", value);
-    this._sfrmWidth = value;
+    Services.prefs.setIntPref(STACKFRAMES_WIDTH, value);
+    this._stackframesWidth = value;
+  },
+
+  /**
+   * Gets the preferred stackframes pane visibility state.
+   * @return boolean
+   */
+  get stackframesPaneVisible() {
+    if (this._stackframesVisible === undefined) {
+      this._stackframesVisible = Services.prefs.getBoolPref(STACKFRAMES_VISIBLE);
+    }
+    return this._stackframesVisible;
+  },
+
+  /**
+   * Sets the preferred stackframes pane visibility state.
+   * @param boolean value
+   */
+  set stackframesPaneVisible(value) {
+    Services.prefs.setBoolPref(STACKFRAMES_VISIBLE, value);
+    this._stackframesVisible = value;
   },
 
   /**
    * Gets the preferred variables pane width.
    * @return number
    */
   get variablesWidth() {
-    if (this._varsWidth === undefined) {
-      this._varsWidth = Services.prefs.getIntPref("devtools.debugger.ui.variables-width");
+    if (this._variablesWidth === undefined) {
+      this._variablesWidth = Services.prefs.getIntPref(VARIABLES_WIDTH);
     }
-    return this._varsWidth;
+    return this._variablesWidth;
   },
 
   /**
    * Sets the preferred variables pane width.
-   * @return number
+   * @param number value
    */
   set variablesWidth(value) {
-    Services.prefs.setIntPref("devtools.debugger.ui.variables-width", value);
-    this._varsWidth = value;
+    Services.prefs.setIntPref(VARIABLES_WIDTH, value);
+    this._variablesWidth = value;
+  },
+
+  /**
+   * Gets the preferred variables pane visibility state.
+   * @return boolean
+   */
+  get variablesPaneVisible() {
+    if (this._variablesVisible === undefined) {
+      this._variablesVisible = Services.prefs.getBoolPref(VARIABLES_PANE_VISIBLE);
+    }
+    return this._variablesVisible;
+  },
+
+  /**
+   * Sets the preferred variables pane visibility state.
+   * @param boolean value
+   */
+  set variablesPaneVisible(value) {
+    Services.prefs.setBoolPref(VARIABLES_PANE_VISIBLE, value);
+    this._variablesVisible = value;
   },
 
   /**
    * Gets a flag specifying if the the debugger should automatically connect to
    * the default host and port number.
    * @return boolean
    */
   get remoteAutoConnect() {
-    if (this._autoConn === undefined) {
-      this._autoConn = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
+    if (this._autoConnect === undefined) {
+      this._autoConnect = Services.prefs.getBoolPref(REMOTE_AUTO_CONNECT);
     }
-    return this._autoConn;
+    return this._autoConnect;
   },
 
   /**
-   * Sets a flag specifying if the the debugger should automatically connect.
+   * Sets a flag specifying if the the debugger should automatically connect to
+   * the default host and port number.
    * @param boolean value
    */
   set remoteAutoConnect(value) {
-    Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", value);
-    this._autoConn = value;
+    Services.prefs.setBoolPref(REMOTE_AUTO_CONNECT, value);
+    this._autoConnect = value;
   }
 };
 
 /**
  * Gets the preferred default remote debugging host.
  * @return string
  */
 XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() {
-  return Services.prefs.getCharPref("devtools.debugger.remote-host");
+  return Services.prefs.getCharPref(REMOTE_HOST);
 });
 
 /**
  * Gets the preferred default remote debugging port.
  * @return number
  */
 XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() {
-  return Services.prefs.getIntPref("devtools.debugger.remote-port");
+  return Services.prefs.getIntPref(REMOTE_PORT);
 });
 
 /**
  * Gets the max number of attempts to reconnect to a remote server.
  * @return number
  */
 XPCOMUtils.defineLazyGetter(Prefs, "remoteConnectionRetries", function() {
-  return Services.prefs.getIntPref("devtools.debugger.remote-connection-retries");
+  return Services.prefs.getIntPref(REMOTE_CONNECTION_RETRIES);
 });
 
 /**
  * Gets the remote debugging connection timeout (in milliseconds).
  * @return number
  */
 XPCOMUtils.defineLazyGetter(Prefs, "remoteTimeout", function() {
-  return Services.prefs.getIntPref("devtools.debugger.remote-timeout");
+  return Services.prefs.getIntPref(REMOTE_TIMEOUT);
 });
 
 /**
  * Preliminary setup for the DebuggerController object.
  */
 DebuggerController.init();
 DebuggerController.ThreadState = new ThreadState();
 DebuggerController.StackFrames = new StackFrames();
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -23,24 +23,40 @@ const SEARCH_TOKEN_FLAG = "#";
 let DebuggerView = {
 
   /**
    * An instance of SourceEditor.
    */
   editor: null,
 
   /**
+   * Caches frequently used global view elements.
+   */
+  cacheView: function DV_cacheView() {
+    this._onTogglePanesButtonPressed = this._onTogglePanesButtonPressed.bind(this);
+
+    this._togglePanesButton = document.getElementById("toggle-panes");
+    this._stackframesAndBreakpoints = document.getElementById("stackframes+breakpoints");
+    this._stackframes = document.getElementById("stackframes");
+    this._breakpoints = document.getElementById("breakpoints");
+    this._variables = document.getElementById("variables");
+    this._globalSearch = document.getElementById("globalsearch");
+  },
+
+  /**
    * Initializes UI properties for all the displayed panes.
    */
   initializePanes: function DV_initializePanes() {
-    let stackframes = document.getElementById("stackframes+breakpoints");
-    stackframes.setAttribute("width", Prefs.stackframesWidth);
-
-    let variables = document.getElementById("variables");
-    variables.setAttribute("width", Prefs.variablesWidth);
+    this._togglePanesButton.addEventListener("click", this._onTogglePanesButtonPressed);
+
+    this._stackframesAndBreakpoints.setAttribute("width", Prefs.stackframesWidth);
+    this._variables.setAttribute("width", Prefs.variablesWidth);
+
+    this.showStackframesAndBreakpointsPane(Prefs.stackframesPaneVisible);
+    this.showVariablesPane(Prefs.variablesPaneVisible);
   },
 
   /**
    * Initializes the SourceEditor instance.
    *
    * @param function aCallback
    *        Called after the editor finishes initializing.
    */
@@ -61,32 +77,26 @@ let DebuggerView = {
       aCallback();
     }.bind(this));
   },
 
   /**
    * Removes the displayed panes and saves any necessary state.
    */
   destroyPanes: function DV_destroyPanes() {
-    let stackframes = document.getElementById("stackframes+breakpoints");
-    Prefs.stackframesWidth = stackframes.getAttribute("width");
-
-    let variables = document.getElementById("variables");
-    Prefs.variablesWidth = variables.getAttribute("width");
-
-    let bkps = document.getElementById("breakpoints");
-    let frames = document.getElementById("stackframes");
-    bkps.parentNode.removeChild(bkps);
-    frames.parentNode.removeChild(frames);
-
-    stackframes.parentNode.removeChild(stackframes);
-    variables.parentNode.removeChild(variables);
-
-    let search = document.getElementById("globalsearch");
-    search.parentNode.removeChild(search);
+    this._togglePanesButton.removeEventListener("click", this._onTogglePanesButtonPressed);
+
+    Prefs.stackframesWidth = this._stackframesAndBreakpoints.getAttribute("width");
+    Prefs.variablesWidth = this._variables.getAttribute("width");
+
+    this._breakpoints.parentNode.removeChild(this._breakpoints);
+    this._stackframes.parentNode.removeChild(this._stackframes);
+    this._stackframesAndBreakpoints.parentNode.removeChild(this._stackframesAndBreakpoints);
+    this._variables.parentNode.removeChild(this._variables);
+    this._globalSearch.parentNode.removeChild(this._globalSearch);
   },
 
   /**
    * Removes the SourceEditor instance and added breakpoints.
    */
   destroyEditor: function DV_destroyEditor() {
     DebuggerController.Breakpoints.destroy();
     this.editor = null;
@@ -97,22 +107,89 @@ let DebuggerView = {
    * editor initialization.
    */
   _onEditorLoad: function DV__onEditorLoad() {
     DebuggerController.Breakpoints.initialize();
     this.editor.focus();
   },
 
   /**
+   * Called when the panes toggle button is clicked.
+   */
+  _onTogglePanesButtonPressed: function DV__onTogglePanesButtonPressed() {
+    this.showStackframesAndBreakpointsPane(
+      this._togglePanesButton.getAttribute("stackframesAndBreakpointsHidden"), true);
+
+    this.showVariablesPane(
+      this._togglePanesButton.getAttribute("variablesHidden"), true);
+  },
+
+  /**
    * Sets the close button hidden or visible. It's hidden by default.
    * @param boolean aVisibleFlag
    */
   showCloseButton: function DV_showCloseButton(aVisibleFlag) {
     document.getElementById("close").setAttribute("hidden", !aVisibleFlag);
-  }
+  },
+
+  /**
+   * Sets the stackframes and breakpoints pane hidden or visible.
+   * @param boolean aVisibleFlag
+   * @param boolean aAnimatedFlag
+   */
+  showStackframesAndBreakpointsPane:
+  function DV_showStackframesAndBreakpointsPane(aVisibleFlag, aAnimatedFlag) {
+    if (aAnimatedFlag) {
+      this._stackframesAndBreakpoints.setAttribute("animated", "");
+    } else {
+      this._stackframesAndBreakpoints.removeAttribute("animated");
+    }
+    if (aVisibleFlag) {
+      this._stackframesAndBreakpoints.style.marginLeft = "0";
+      this._togglePanesButton.removeAttribute("stackframesAndBreakpointsHidden");
+    } else {
+      let margin = parseInt(this._stackframesAndBreakpoints.getAttribute("width")) + 1;
+      this._stackframesAndBreakpoints.style.marginLeft = -margin + "px";
+      this._togglePanesButton.setAttribute("stackframesAndBreakpointsHidden", "true");
+    }
+    Prefs.stackframesPaneVisible = aVisibleFlag;
+  },
+
+  /**
+   * Sets the variable spane hidden or visible.
+   * @param boolean aVisibleFlag
+   * @param boolean aAnimatedFlag
+   */
+  showVariablesPane:
+  function DV_showVariablesPane(aVisibleFlag, aAnimatedFlag) {
+    if (aAnimatedFlag) {
+      this._variables.setAttribute("animated", "");
+    } else {
+      this._variables.removeAttribute("animated");
+    }
+    if (aVisibleFlag) {
+      this._variables.style.marginRight = "0";
+      this._togglePanesButton.removeAttribute("variablesHidden");
+    } else {
+      let margin = parseInt(this._variables.getAttribute("width")) + 1;
+      this._variables.style.marginRight = -margin + "px";
+      this._togglePanesButton.setAttribute("variablesHidden", "true");
+    }
+    Prefs.variablesPaneVisible = aVisibleFlag;
+  },
+
+  /**
+   * The cached global view elements.
+   */
+  _togglePanesButton: null,
+  _stackframesAndBreakpoints: null,
+  _stackframes: null,
+  _breakpoints: null,
+  _variables: null,
+  _globalSearch: null
 };
 
 /**
  * A simple way of displaying a "Connect to..." prompt.
  */
 function RemoteDebuggerPrompt() {
 
   /**
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -59,16 +59,19 @@
 
   <vbox id="body" flex="1">
     <toolbar id="dbg-toolbar" class="devtools-toolbar">
 #ifdef XP_MACOSX
       <toolbarbutton id="close"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"
                      class="devtools-closebutton"/>
 #endif
+      <toolbarbutton id="toggle-panes"
+                     class="devtools-toolbarbutton"
+                     tabindex="0"/>
       <hbox id="debugger-controls">
         <toolbarbutton id="resume"
                        class="devtools-toolbarbutton"
                        type="checkbox"
                        tabindex="0"/>
         <toolbarbutton id="step-over"
                        class="devtools-toolbarbutton"
                        tooltiptext="&debuggerUI.stepOverButton.tooltip;"
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -31,16 +31,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_propertyview-05.js \
 	browser_dbg_propertyview-06.js \
 	browser_dbg_propertyview-07.js \
 	browser_dbg_propertyview-08.js \
 	browser_dbg_propertyview-09.js \
 	browser_dbg_propertyview-10.js \
 	browser_dbg_propertyview-edit.js \
 	$(warning browser_dbg_reload-same-script.js temporarily disabled due to oranges, see bug 780198 & bug 782179) \
+	browser_dbg_pane-collapse.js \
 	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_pane-collapse.js
@@ -0,0 +1,139 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the debugger panes collapse properly.
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var gView = null;
+
+function test() {
+  debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gView = gDebugger.DebuggerView;
+
+    testPaneCollapse1();
+    testPaneCollapse2();
+    closeDebuggerAndFinish();
+  });
+}
+
+function testPaneCollapse1() {
+  let stackframesAndBrekpoints =
+    gDebugger.document.getElementById("stackframes+breakpoints");
+  let togglePanesButton =
+    gDebugger.document.getElementById("toggle-panes");
+
+  let width = parseInt(stackframesAndBrekpoints.getAttribute("width"));
+  is(width, gDebugger.Prefs.stackframesWidth,
+    "The stackframes and breakpoints pane has an incorrect width.");
+  is(stackframesAndBrekpoints.style.marginLeft, "0px",
+    "The stackframes and breakpoints pane has an incorrect initial left margin.");
+  ok(!stackframesAndBrekpoints.hasAttribute("animated"),
+    "The stackframes and breakpoints pane has an incorrect initial animated attribute.");
+  ok(!togglePanesButton.getAttribute("stackframesAndBreakpointsHidden"),
+    "The stackframes and breakpoints pane should initially be visible.");
+
+  is(gDebugger.Prefs.stackframesPaneVisible, true,
+    "The stackframes and breakpoints pane should initially be visible.");
+
+  gView.showStackframesAndBreakpointsPane(false, true);
+
+  is(gDebugger.Prefs.stackframesPaneVisible, false,
+    "The stackframes and breakpoints pane should be hidden after collapsing.");
+
+  let margin = -(width + 1) + "px";
+  is(width, gDebugger.Prefs.stackframesWidth,
+    "The stackframes and breakpoints pane has an incorrect width after collapsing.");
+  is(stackframesAndBrekpoints.style.marginLeft, margin,
+    "The stackframes and breakpoints pane has an incorrect left margin after collapsing.");
+  ok(stackframesAndBrekpoints.hasAttribute("animated"),
+    "The stackframes and breakpoints pane has an incorrect attribute after an animated collapsing.");
+  ok(togglePanesButton.hasAttribute("stackframesAndBreakpointsHidden"),
+    "The stackframes and breakpoints pane should not be visible after collapsing.");
+
+  is(gDebugger.Prefs.stackframesPaneVisible, false,
+    "The stackframes and breakpoints pane should be hidden before uncollapsing.");
+
+  gView.showStackframesAndBreakpointsPane(true, false);
+
+  is(gDebugger.Prefs.stackframesPaneVisible, true,
+    "The stackframes and breakpoints pane should be visible after uncollapsing.");
+
+  is(width, gDebugger.Prefs.stackframesWidth,
+    "The stackframes and breakpoints pane has an incorrect width after uncollapsing.");
+  is(stackframesAndBrekpoints.style.marginLeft, "0px",
+    "The stackframes and breakpoints pane has an incorrect left margin after uncollapsing.");
+  ok(!stackframesAndBrekpoints.hasAttribute("animated"),
+    "The stackframes and breakpoints pane has an incorrect attribute after an unanimated uncollapsing.");
+  ok(!togglePanesButton.getAttribute("stackframesAndBreakpointsHidden"),
+    "The stackframes and breakpoints pane should be visible again after uncollapsing.");
+}
+
+function testPaneCollapse2() {
+  let variables =
+    gDebugger.document.getElementById("variables");
+  let togglePanesButton =
+    gDebugger.document.getElementById("toggle-panes");
+
+  let width = parseInt(variables.getAttribute("width"));
+  is(width, gDebugger.Prefs.variablesWidth,
+    "The variables pane has an incorrect width.");
+  is(variables.style.marginRight, "0px",
+    "The variables pane has an incorrect initial right margin.");
+  ok(!variables.hasAttribute("animated"),
+    "The variables pane has an incorrect initial animated attribute.");
+  ok(!togglePanesButton.getAttribute("variablesHidden"),
+    "The variables pane should initially be visible.");
+
+  is(gDebugger.Prefs.variablesPaneVisible, true,
+    "The variables pane should initially be visible.");
+
+  gView.showVariablesPane(false, true);
+
+  is(gDebugger.Prefs.variablesPaneVisible, false,
+    "The variables pane should be hidden after collapsing.");
+
+  let margin = -(width + 1) + "px";
+  is(width, gDebugger.Prefs.variablesWidth,
+    "The variables pane has an incorrect width after collapsing.");
+  is(variables.style.marginRight, margin,
+    "The variables pane has an incorrect right margin after collapsing.");
+  ok(variables.hasAttribute("animated"),
+    "The variables pane has an incorrect attribute after an animated collapsing.");
+  ok(togglePanesButton.hasAttribute("variablesHidden"),
+    "The variables pane should not be visible after collapsing.");
+
+  is(gDebugger.Prefs.variablesPaneVisible, false,
+    "The variables pane should be hidden before uncollapsing.");
+
+  gView.showVariablesPane(true, false);
+
+  is(gDebugger.Prefs.variablesPaneVisible, true,
+    "The variables pane should be visible after uncollapsing.");
+
+  is(width, gDebugger.Prefs.variablesWidth,
+    "The variables pane has an incorrect width after uncollapsing.");
+  is(variables.style.marginRight, "0px",
+    "The variables pane has an incorrect right margin after uncollapsing.");
+  ok(!variables.hasAttribute("animated"),
+    "The variables pane has an incorrect attribute after an unanimated uncollapsing.");
+  ok(!togglePanesButton.getAttribute("variablesHidden"),
+    "The variables pane should be visible again after uncollapsing.");
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+  gView = null;
+});
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cde5299b75dfd553cce438496c95afc6be7a59c5
GIT binary patch
literal 693
zc$@*X0!safP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0007fNkl<Zc-qC4
zT}abW7{&!}B1oeyf(W`z>7u&G$tv(BWPKPc7<3h}A|&Xp527}h*%r;lmTO-+n@&f6
zkhyHFwiMF~i>0>Aj|#eLM2fJyU(W;Qz~K+ZMi;yI?RnqxJnz}N@gJ)zm&-M!_6zLT
zy>}bf2b#gb3Tftym~8-uKsz{HA?;$OfeY-<7nb9{Ha4@>z!}bhBOZTb=w)^)Q4O5o
zY#m>U>!nm-<wxS@S}BSC3OEDKQ`MRtGt6>^v!DYP4oBnK2o=2_TnBfky4tVHc5nd$
zF4Y#6zK>ARn}G4d{9;gk<)Svy(`607^5XU6vq&s4NJW2*XODZsT;v21wS}H8YvBT|
zxNLa-%eNR6y>)taE>v9qlR$l#u;v*(UA7fi#$LVc3r6DuRP<4Y%hNCFvxGIz=&4zC
zfq}WjuYJ_XnfF1w;UH^%Lc*G7^wg|eAeqhu0{uf_s=fPBgi7d1UwUd*T_E)F^J;*a
z&b{+d2|ejcPtD2&M#taydc(1&)VmH>h)U>5UwUd*UBH(wta_>FZ>BO6Zc!g4ta(OH
z&B_I|v5earh<d5$wOjY@`$cUgta(OH&8iEy^Mw^RRXpvc?9{9cdVq-9L{H7i1)e9<
zPW-IgRPnT1@pV6d8i}Z_^wg|epaqvX^PiTTRP+}>n|OeZ5mC3%(`8$LIWaok)$=6$
zkcz%Xyx9$Kk%-z#PnR`wfu?kB+Fo2Mb>ULS?~P5*zhH*h%*2eHvt01Dt=kpXQnqT~
z3}%mWfnC4=&IwH5<QABeoI%X)5$9JyC%6nQZ2`Sbkv+v(E>I7)gGR8kLK?+P{r}F_
b{NL~|?E%iu<(6&$00000NkvXXu0mjfrC3y8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ee8012ff315b41ac1a5ddb3fc73b050f6f8560e7
GIT binary patch
literal 669
zc$@*90%HA%P)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0007HNkl<Zc-qC4
z-Aj{k6vszFL{yFjKA?%<-E2q+)rNT?f{n0wv2wI73YUTOdQs3tO=&3#8H<e;(yV3X
zXd$}H%vB~qFBf@J7ySiEFEX&*ukRPm1BWqaql;a9Jm>eE^ZD&NwxK1T&sUVn2iRt-
z*$j4qM&KxsMmpkd2fKkAbe4#l4qXPQ|NQ0KqaWE^rX1+d1<ki(;}4%_mXqZ`hpvTx
zR@c_k-eV{F(fh$+&`}JT`MFDnF6hFAkN38;O`#8g3!tYMG7E8+4qXOte*e9mLhb#u
z@^uWg1sK3ufWevU^orvIzGp9&5~$Hz(XklMpst8t$C>Oz#qlwK3zsoX-|E_*<hze6
zd;vSy1S~{)J7?VCt~f5>n|<**j(VRpG!h<1-ww7YpM5)LdRGT{fO?J<FEEjqddiQ(
zrY^AY8E1Oe3@|hQ>MrUeD+%;n4D<V;{CYm)Oz-LdeAnk$Ni06W0EW82;4{wjt{Gr@
zZZX13S;@)MXBnVD`3-!=ncmd_csRqFUU)N#z7=exOr&q+Oz)ZjQnL$m60BE(gLlw(
z1FQ1ccXOt9bpRd$i*Mf#pdJF%U;||$eKlvY6QE-Tcrr6Tj2amjy2*M9)E4n;Ig_0T
z9W%gwTsGWw^!R1;UeE@bfTMsWnRz`&{Fms^<vBS$cf--_x`#d}0X(3y0FTUqyY@Ka
zbm%gGJ+u7b+Rtom^j9_)E(Pww3DN}zu3jG*oJ^(r%K^?1KUN0V0rmkmI0!oa0e9SV
z#5LsH0|HWuqIbkG7+|CPPOE^mM5^e}{a?T0{|)~FW<oAC=n-Xv00000NkvXXu0mjf
DVTm_e
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -102,17 +102,30 @@
 }
 
 .dbg-results-container .line-contents > .string[match=true][focused] {
   transition-duration: 0.1s;
   transform: scale(1.75, 1.75);
 }
 
 /**
- * Stack frames
+ * Stack frames and breakpoints panel
+ */
+
+#stackframes\+breakpoints {
+  background-color: white;
+  min-width: 50px;
+}
+
+#stackframes\+breakpoints[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
+}
+
+/**
+ * Stack frames view
  */
 
 #stackframes {
   background-color: white;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
@@ -141,16 +154,21 @@
 }
 
 /**
  * Properties view
  */
 
 #variables {
   background-color: white;
+  min-width: 50px;
+}
+
+#variables[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
@@ -341,16 +359,32 @@
     transform: scaleY(1);
   }
 }
 
 /**
  * Toolbar Controls
  */
 
+#toggle-panes {
+  background: none;
+  border: none;
+  box-shadow: none;
+  list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+#toggle-panes:not([stackframesAndBreakpointsHidden]):not([variablesHidden]) {
+  list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
+}
+
+#toggle-panes:active {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
+}
+
 #resume {
   list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #resume[checked=true] {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -149,16 +149,18 @@ browser.jar:
   skin/classic/browser/devtools/itemArrow-ltr.png     (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/inspect-button.png    (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png        (devtools/dropmarker.png)
   skin/classic/browser/devtools/treepanel-button.png  (devtools/treepanel-button.png)
   skin/classic/browser/devtools/layout-background.png (devtools/layout-background.png)
   skin/classic/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
   skin/classic/browser/devtools/layoutview.css        (devtools/layoutview.css)
   skin/classic/browser/devtools/layout-buttons.png    (devtools/layout-buttons.png)
+  skin/classic/browser/devtools/debugger-collapse.png  (devtools/debugger-collapse.png)
+  skin/classic/browser/devtools/debugger-expand.png    (devtools/debugger-expand.png)
   skin/classic/browser/devtools/debugger-pause.png     (devtools/debugger-pause.png)
   skin/classic/browser/devtools/debugger-play.png      (devtools/debugger-play.png)
   skin/classic/browser/devtools/debugger-step-in.png   (devtools/debugger-step-in.png)
   skin/classic/browser/devtools/debugger-step-out.png  (devtools/debugger-step-out.png)
   skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
   skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
   skin/classic/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
   skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cde5299b75dfd553cce438496c95afc6be7a59c5
GIT binary patch
literal 693
zc$@*X0!safP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0007fNkl<Zc-qC4
zT}abW7{&!}B1oeyf(W`z>7u&G$tv(BWPKPc7<3h}A|&Xp527}h*%r;lmTO-+n@&f6
zkhyHFwiMF~i>0>Aj|#eLM2fJyU(W;Qz~K+ZMi;yI?RnqxJnz}N@gJ)zm&-M!_6zLT
zy>}bf2b#gb3Tftym~8-uKsz{HA?;$OfeY-<7nb9{Ha4@>z!}bhBOZTb=w)^)Q4O5o
zY#m>U>!nm-<wxS@S}BSC3OEDKQ`MRtGt6>^v!DYP4oBnK2o=2_TnBfky4tVHc5nd$
zF4Y#6zK>ARn}G4d{9;gk<)Svy(`607^5XU6vq&s4NJW2*XODZsT;v21wS}H8YvBT|
zxNLa-%eNR6y>)taE>v9qlR$l#u;v*(UA7fi#$LVc3r6DuRP<4Y%hNCFvxGIz=&4zC
zfq}WjuYJ_XnfF1w;UH^%Lc*G7^wg|eAeqhu0{uf_s=fPBgi7d1UwUd*T_E)F^J;*a
z&b{+d2|ejcPtD2&M#taydc(1&)VmH>h)U>5UwUd*UBH(wta_>FZ>BO6Zc!g4ta(OH
z&B_I|v5earh<d5$wOjY@`$cUgta(OH&8iEy^Mw^RRXpvc?9{9cdVq-9L{H7i1)e9<
zPW-IgRPnT1@pV6d8i}Z_^wg|epaqvX^PiTTRP+}>n|OeZ5mC3%(`8$LIWaok)$=6$
zkcz%Xyx9$Kk%-z#PnR`wfu?kB+Fo2Mb>ULS?~P5*zhH*h%*2eHvt01Dt=kpXQnqT~
z3}%mWfnC4=&IwH5<QABeoI%X)5$9JyC%6nQZ2`Sbkv+v(E>I7)gGR8kLK?+P{r}F_
b{NL~|?E%iu<(6&$00000NkvXXu0mjfrC3y8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ee8012ff315b41ac1a5ddb3fc73b050f6f8560e7
GIT binary patch
literal 669
zc$@*90%HA%P)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0007HNkl<Zc-qC4
z-Aj{k6vszFL{yFjKA?%<-E2q+)rNT?f{n0wv2wI73YUTOdQs3tO=&3#8H<e;(yV3X
zXd$}H%vB~qFBf@J7ySiEFEX&*ukRPm1BWqaql;a9Jm>eE^ZD&NwxK1T&sUVn2iRt-
z*$j4qM&KxsMmpkd2fKkAbe4#l4qXPQ|NQ0KqaWE^rX1+d1<ki(;}4%_mXqZ`hpvTx
zR@c_k-eV{F(fh$+&`}JT`MFDnF6hFAkN38;O`#8g3!tYMG7E8+4qXOte*e9mLhb#u
z@^uWg1sK3ufWevU^orvIzGp9&5~$Hz(XklMpst8t$C>Oz#qlwK3zsoX-|E_*<hze6
zd;vSy1S~{)J7?VCt~f5>n|<**j(VRpG!h<1-ww7YpM5)LdRGT{fO?J<FEEjqddiQ(
zrY^AY8E1Oe3@|hQ>MrUeD+%;n4D<V;{CYm)Oz-LdeAnk$Ni06W0EW82;4{wjt{Gr@
zZZX13S;@)MXBnVD`3-!=ncmd_csRqFUU)N#z7=exOr&q+Oz)ZjQnL$m60BE(gLlw(
z1FQ1ccXOt9bpRd$i*Mf#pdJF%U;||$eKlvY6QE-Tcrr6Tj2amjy2*M9)E4n;Ig_0T
z9W%gwTsGWw^!R1;UeE@bfTMsWnRz`&{Fms^<vBS$cf--_x`#d}0X(3y0FTUqyY@Ka
zbm%gGJ+u7b+Rtom^j9_)E(Pww3DN}zu3jG*oJ^(r%K^?1KUN0V0rmkmI0!oa0e9SV
z#5LsH0|HWuqIbkG7+|CPPOE^mM5^e}{a?T0{|)~FW<oAC=n-Xv00000NkvXXu0mjf
DVTm_e
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -104,17 +104,30 @@
 }
 
 .dbg-results-container .line-contents > .string[match=true][focused] {
   transition-duration: 0.1s;
   transform: scale(1.75, 1.75);
 }
 
 /**
- * Stack frames
+ * Stack frames and breakpoints panel
+ */
+
+#stackframes\+breakpoints {
+  background-color: white;
+  min-width: 50px;
+}
+
+#stackframes\+breakpoints[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
+}
+
+/**
+ * Stack frames view
  */
 
 #stackframes {
   background-color: white;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
@@ -143,16 +156,21 @@
 }
 
 /**
  * Properties view
  */
 
 #variables {
   background-color: white;
+  min-width: 50px;
+}
+
+#variables[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
@@ -341,16 +359,32 @@
     transform: scaleY(1);
   }
 }
 
 /**
  * Toolbar Controls
  */
 
+#toggle-panes {
+  background: none;
+  border: none;
+  box-shadow: none;
+  list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+#toggle-panes:not([stackframesAndBreakpointsHidden]):not([variablesHidden]) {
+  list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
+}
+
+#toggle-panes:active {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
+}
+
 #resume {
   list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #resume[checked=true] {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -190,16 +190,18 @@ browser.jar:
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
   skin/classic/browser/devtools/inspect-button.png          (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png              (devtools/dropmarker.png)
   skin/classic/browser/devtools/treepanel-button.png        (devtools/treepanel-button.png)
   skin/classic/browser/devtools/layout-background.png       (devtools/layout-background.png)
   skin/classic/browser/devtools/layout-background-grid.png  (devtools/layout-background-grid.png)
   skin/classic/browser/devtools/layoutview.css              (devtools/layoutview.css)
   skin/classic/browser/devtools/layout-buttons.png          (devtools/layout-buttons.png)
+  skin/classic/browser/devtools/debugger-collapse.png       (devtools/debugger-collapse.png)
+  skin/classic/browser/devtools/debugger-expand.png         (devtools/debugger-expand.png)
   skin/classic/browser/devtools/debugger-pause.png          (devtools/debugger-pause.png)
   skin/classic/browser/devtools/debugger-play.png           (devtools/debugger-play.png)
   skin/classic/browser/devtools/debugger-step-in.png        (devtools/debugger-step-in.png)
   skin/classic/browser/devtools/debugger-step-out.png       (devtools/debugger-step-out.png)
   skin/classic/browser/devtools/debugger-step-over.png      (devtools/debugger-step-over.png)
   skin/classic/browser/devtools/inspector-option-icon.png   (devtools/inspector-option-icon.png)
   skin/classic/browser/devtools/responsive-se-resizer.png   (devtools/responsive-se-resizer.png)
   skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..242e19c560d6817a484d0087c14028fc997ae6ff
GIT binary patch
literal 970
zc$@*s12z1KP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000A#Nkl<Zc-qyL
zZ%CDA7{-NtiP$O%8jL|-`}d(nOC^h<Xri`ajx`EuL`6i<w`xTxoYpitO|;Cv*(~eO
zfiNqxX^L5>XGcAnOY5wxR#{}(&M~b|?)t&=@}Bd8qMwEzeqQ%;U)QbA{c_HWF~h^d
z6Pk&?z-KeQm?XXwbH)5ILY5h3KNYh@f>=IA$TGw16tO@gij*;u$PBYAFw5W3RracX
zpn5zo!>pLs-r3z1djH|y@xTnT;;XFOqI1`(>pkOv8D?Yn(fcM;(b3)GdC?at*Lk~G
zBfdu?YdkV!nPFC}>JJb01$+K^{5CZBT4$HoB6gvU+C_#eGt7#$y3qNOGVcXc=UlN{
z96%j)t|Pma1>$rmZ{XhF7f_v(#1dayXTEekP}9S6WaC7#F7-0_=xGnC^JbBvC)_NJ
z1!{VDj%>16f8|Eq??t7avnb2b`|V^Qi!1|bdU%fPdKQS+WzM(#6)Z({-rCUATG0C@
z>`}cCsOjN3vhiF@mwBd31yP+dn*D*+{_xOq)hmIT9-bqc!X++Wzge7LQg#N_xx|&3
zb=uV50yRCn=&ZfKnbyt+#c18_=6qfFEHzIUsOjNFW~~MEad;ej^rRbY^tH6T8yI>@
z%@YP{dU%mpYk~60n!LQz=L*sEBgcwRz_WbYv$K&46tvvEpNCe~+{!@#&+={0&e{tM
z1@%-r(fT_+9}0MuZ+mvuTHw;vKXOhMmYzZnx-tt;z_WbYv$K&4<oG-8XG>}Bt*EMX
zn|d)&)5CLQtp&OsJbV&B`J&Y}G&Y+08=$6#7nL;&crRDEv-3)_QJuZ}4*imA>Qtbn
zhZmi-7jXMKy4|RG+ay)jH>F8u12sK7N7h>4t}fMrnzzk{CV%@4=^~(}hZmJK3tTL(
z%+PDmjheU3R()K4l`a8ldU#P;vp}pali_dg%0SH@T4BCG2|!H`&ykH4iMmWcm-3-H
z?-xIa?czJ2ribUqCW=(grK^XJpC~+v>U`W>c8~Z8sOjN3vZ*XEr?RFYy|*uPSeJ6W
z?jOh+4Kie_YHz1AE55$tYpr`19^$F`!-F61jRqOAjeiE}%ttig=d>f4W!{Rk@xY8`
zm$JZg5hvCelEmr}z_W79FgsJM6r0S`+9-Y;0X#BfSDD$*&F|eIc8YCc%Lw3+A)CxB
s3w$Cbi>YGT7$G~E+5dZf!v8n=A5o_J7R^pT4*&oF07*qoM6N<$f+DZy5&!@I
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..af453e3168a64900baecaadedbbfde25c21fe031
GIT binary patch
literal 936
zc$@*K16TZsP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000ATNkl<Zc-qyL
zOGuP)6vaObLZnm@9MU9cl@Fo>OHn~HY)I3E`5J>vGmxHOL5ot$6a_6q$&l2{e4r(2
zX1>a#FclSRB%?MFl|8g6$JADKPTZmYVvunaE`Hwo-Fwc=|9pNkjJCA2w5nPC0oJ>?
z*@I2M3;5WG7d_%#2eyJB5Mm=i^oZ9HYzKM}X(M{^I5NQIQRC}7Urcj7D}f$*fwyt;
z&BW}l#h)vI9(sZAwX(|F4|@6=RsucrYWy=bGusxEcqj|K0qh6i){vcnT6*XOdrao}
z>G*>w_2@G|3P`Yq>@ujOhh7kk1J(HjhSHw{PEltK+2v4654{ZF|7m)*2{mnKY@!@B
z5a@ujip&B<lO`U25b=F>{xj;uapUB${EOYK_}#gqhFbANfcX1eebuO?S4zvvcnv(P
z_&vB2O{sX|86W_MVVd-*8FRza!7(1t6RZUqk=~O#YN!=Y0Eon4KA;wu%nKifM#jfv
zZjVPrBkVcjjv8v|k+AWt4<A*aR<Y(36j!1T0}enV(uZ-UYSjR@P*1SpfHl?iclkKE
z&`j8K#+|CQ1i<6)4)rSQkGX~Sb&bvUaP4NEU(^VD&bU*xmH;gsy*E&6SxIX8>0<eO
zX@osz+^JeM0Pp%qR#H|`!vH#(1s!MHsoH-57T)qutfacOkpVo+^S?F1o-^)LttCKn
zdv^&B#Y&Qo9%q0pKqKrq<4)D80eEqYwXO4U5&B@Tj%Ff#Fn6j}2{4IT$lCX8a6k^`
zs0482j5}3p3DDHq$@i>gJ(rn#9etcU_ZpEtjyqMW2H-_%_mhEa)P2Ae*wIX+cjZnr
zsq`oTjHuazBQLt-n`|RJN&q{V8AOv!k0n53OGiFxNp@Z#>k;5?<^A2c6HN&{mH@kO
znEdG2q_gN_Kq%M-d{kr>N=?)O!x?($1$rE2JTB?*-_M5Jz1<*0MP_l-#2S*T=%E+H
zG&Hwg_VEq4i9S;TL`gW6DA{Ft@9?jnhh7Ho?CF1g;j3w`=$mP-*cPaTCzD>_H#GXP
z7vDA$xZAI6f!g6QV=ufrLD2b21-Z3NZCNV;o;*I*46s37NDuac@Z}JVo*wbK${kJs
ziLA?@YC^@Ulh;cDsjSN)8u92DU=45pPQckloamwVfBRScuhBp5q!31-;(ML|0000<
KMNUMnLSTZ><-Uyo
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -110,17 +110,30 @@
 }
 
 .dbg-results-container .line-contents > .string[match=true][focused] {
   transition-duration: 0.1s;
   transform: scale(1.75, 1.75);
 }
 
 /**
- * Stack frames
+ * Stack frames and breakpoints panel
+ */
+
+#stackframes\+breakpoints {
+  background-color: white;
+  min-width: 50px;
+}
+
+#stackframes\+breakpoints[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
+}
+
+/**
+ * Stack frames view
  */
 
 #stackframes {
   background-color: white;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
@@ -149,16 +162,21 @@
 }
 
 /**
  * Properties view
  */
 
 #variables {
   background-color: white;
+  min-width: 50px;
+}
+
+#variables[animated] {
+  -moz-transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
@@ -352,16 +370,36 @@
     transform: scaleY(1);
   }
 }
 
 /**
  * Toolbar Controls
  */
 
+#toggle-panes {
+  background: none;
+  border: none;
+  box-shadow: none;
+  list-style-image: url("chrome://browser/skin/devtools/debugger-expand.png");
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+#toggle-panes:not([stackframesAndBreakpointsHidden]):not([variablesHidden]) {
+  list-style-image: url("chrome://browser/skin/devtools/debugger-collapse.png");
+}
+
+#toggle-panes:hover {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
+}
+
+#toggle-panes:hover:active {
+  -moz-image-region: rect(0px, 48px, 16px, 32px);
+}
+
 #resume {
   list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #resume[checked=true] {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -177,16 +177,18 @@ browser.jar:
         skin/classic/browser/devtools/itemArrow-ltr.png             (devtools/itemArrow-ltr.png)
         skin/classic/browser/devtools/inspect-button.png            (devtools/inspect-button.png)
         skin/classic/browser/devtools/dropmarker.png                (devtools/dropmarker.png)
         skin/classic/browser/devtools/treepanel-button.png          (devtools/treepanel-button.png)
         skin/classic/browser/devtools/layout-background.png         (devtools/layout-background.png)
         skin/classic/browser/devtools/layout-background-grid.png    (devtools/layout-background-grid.png)
         skin/classic/browser/devtools/layoutview.css                (devtools/layoutview.css)
         skin/classic/browser/devtools/layout-buttons.png            (devtools/layout-buttons.png)
+        skin/classic/browser/devtools/debugger-collapse.png         (devtools/debugger-collapse.png)
+        skin/classic/browser/devtools/debugger-expand.png           (devtools/debugger-expand.png)
         skin/classic/browser/devtools/debugger-pause.png            (devtools/debugger-pause.png)
         skin/classic/browser/devtools/debugger-play.png             (devtools/debugger-play.png)
         skin/classic/browser/devtools/debugger-step-in.png          (devtools/debugger-step-in.png)
         skin/classic/browser/devtools/debugger-step-out.png         (devtools/debugger-step-out.png)
         skin/classic/browser/devtools/debugger-step-over.png        (devtools/debugger-step-over.png)
         skin/classic/browser/devtools/inspector-option-icon.png     (devtools/inspector-option-icon.png)
         skin/classic/browser/devtools/responsive-se-resizer.png     (devtools/responsive-se-resizer.png)
         skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
@@ -380,16 +382,18 @@ browser.jar:
         skin/classic/aero/browser/devtools/itemArrow-ltr.png         (devtools/itemArrow-ltr.png)
         skin/classic/aero/browser/devtools/inspect-button.png        (devtools/inspect-button.png)
         skin/classic/aero/browser/devtools/dropmarker.png            (devtools/dropmarker.png)
         skin/classic/aero/browser/devtools/treepanel-button.png      (devtools/treepanel-button.png)
         skin/classic/aero/browser/devtools/layout-background.png     (devtools/layout-background.png)
         skin/classic/aero/browser/devtools/layout-background-grid.png (devtools/layout-background-grid.png)
         skin/classic/aero/browser/devtools/layoutview.css            (devtools/layoutview.css)
         skin/classic/aero/browser/devtools/layout-buttons.png        (devtools/layout-buttons.png)
+        skin/classic/aero/browser/devtools/debugger-collapse.png     (devtools/debugger-collapse.png)
+        skin/classic/aero/browser/devtools/debugger-expand.png       (devtools/debugger-expand.png)
         skin/classic/aero/browser/devtools/debugger-pause.png        (devtools/debugger-pause.png)
         skin/classic/aero/browser/devtools/debugger-play.png         (devtools/debugger-play.png)
         skin/classic/aero/browser/devtools/debugger-step-in.png      (devtools/debugger-step-in.png)
         skin/classic/aero/browser/devtools/debugger-step-out.png     (devtools/debugger-step-out.png)
         skin/classic/aero/browser/devtools/debugger-step-over.png    (devtools/debugger-step-over.png)
         skin/classic/aero/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
         skin/classic/aero/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
         skin/classic/aero/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)