@@ -99,6 +99,13 @@ const SIDE_PORTAIT_MODE_WIDTH_THRESHOLD = 1000;
9999const THREE_PANE_ENABLED_PREF = "devtools.inspector.three-pane-enabled" ;
100100const THREE_PANE_CHROME_ENABLED_PREF =
101101 "devtools.inspector.chrome.three-pane-enabled" ;
102+ const SPLIT_ORIENTATION_PREF = "devtools.inspector.split-orientation" ;
103+ // Possible values for SPLIT_ORIENTATION_PREF; AUTO keeps the width-threshold behavior.
104+ const SPLIT_ORIENTATIONS = {
105+ AUTO : "auto" ,
106+ SIDE : "side" ,
107+ STACKED : "stacked" ,
108+ } ;
102109const DEFAULT_COLOR_UNIT_PREF = "devtools.defaultColorUnit" ;
103110
104111/**
@@ -168,6 +175,14 @@ class Inspector extends EventEmitter {
168175 DEFAULT_COLOR_UNIT_PREF ,
169176 this . #handleDefaultColorUnitPrefChange
170177 ) ;
178+ this . prefObserver . on (
179+ SPLIT_ORIENTATION_PREF ,
180+ this . #onSplitOrientationPrefChange
181+ ) ;
182+ this . #splitOrientationPrefValue = Services . prefs . getCharPref (
183+ SPLIT_ORIENTATION_PREF ,
184+ SPLIT_ORIENTATIONS . AUTO
185+ ) ;
171186 this . defaultColorUnit = Services . prefs . getStringPref (
172187 DEFAULT_COLOR_UNIT_PREF
173188 ) ;
@@ -197,6 +212,11 @@ class Inspector extends EventEmitter {
197212 #InspectorTabPanel;
198213 #InspectorSplitBox;
199214 #TabBar;
215+ #MenuButton;
216+ #MenuItem;
217+ #MenuList;
218+ #splitOrientationL10nStrings;
219+ #splitOrientationPrefValue;
200220 #updateProgress;
201221
202222 /**
@@ -236,6 +256,7 @@ class Inspector extends EventEmitter {
236256 // parent of the iframe in the DOM tree which would reset the state of the
237257 // iframe if it had already been initialized.
238258 this . #setupSplitter( ) ;
259+ this . #setupSplitOrientationMenu( ) ;
239260
240261 // Optional NodeFront/ElementIdentifier set on inspector startup, to be selected once the first root
241262 // node is available.
@@ -942,16 +963,50 @@ class Inspector extends EventEmitter {
942963 return this . #TabBar;
943964 }
944965
966+ get MenuButton ( ) {
967+ if ( ! this . #MenuButton) {
968+ this . #MenuButton = this . React . createFactory (
969+ this . browserRequire ( "devtools/client/shared/components/menu/MenuButton" )
970+ ) ;
971+ }
972+ return this . #MenuButton;
973+ }
974+
975+ get MenuItem ( ) {
976+ if ( ! this . #MenuItem) {
977+ this . #MenuItem = this . React . createFactory (
978+ this . browserRequire ( "devtools/client/shared/components/menu/MenuItem" )
979+ ) ;
980+ }
981+ return this . #MenuItem;
982+ }
983+
984+ get MenuList ( ) {
985+ if ( ! this . #MenuList) {
986+ this . #MenuList = this . React . createFactory (
987+ this . browserRequire ( "devtools/client/shared/components/menu/MenuList" )
988+ ) ;
989+ }
990+ return this . #MenuList;
991+ }
992+
945993 /**
946- * Check if the inspector should use the landscape mode .
994+ * Check if the Inspector panels should be laid out side by side .
947995 *
948- * @return {boolean } true if the inspector should be in landscape mode .
996+ * @return {boolean } true if the inspector should use the side-by-side layout .
949997 */
950- #useLandscapeMode ( ) {
998+ #useSideBySideLayout ( ) {
951999 if ( ! this . panelDoc ) {
9521000 return true ;
9531001 }
9541002
1003+ if ( this . #splitOrientationPrefValue === SPLIT_ORIENTATIONS . SIDE ) {
1004+ return true ;
1005+ }
1006+ if ( this . #splitOrientationPrefValue === SPLIT_ORIENTATIONS . STACKED ) {
1007+ return false ;
1008+ }
1009+
9551010 const splitterBox = this . panelDoc . getElementById ( "inspector-splitter-box" ) ;
9561011 const width = splitterBox . clientWidth ;
9571012
@@ -996,7 +1051,7 @@ class Inspector extends EventEmitter {
9961051 } ) ,
9971052 ref : this . sidebarSplitBoxRef ,
9981053 } ) ,
999- vert : this . #useLandscapeMode ( ) ,
1054+ vert : this . #useSideBySideLayout ( ) ,
10001055 onControlledPanelResized : this . onSidebarResized ,
10011056 } ) ;
10021057
@@ -1019,13 +1074,119 @@ class Inspector extends EventEmitter {
10191074 return ;
10201075 }
10211076
1022- this . splitBox . setState ( { vert : this . #useLandscapeMode ( ) } ) ;
1077+ this . splitBox . setState ( { vert : this . #useSideBySideLayout ( ) } ) ;
10231078 this . emit ( "inspector-resize" ) ;
10241079 } ,
10251080 LAZY_RESIZE_INTERVAL_MS ,
10261081 this
10271082 ) ;
10281083
1084+ /**
1085+ * Build the toolbar button opening the menu that controls the orientation of
1086+ * the splitter between the Inspector panels.
1087+ */
1088+ async #setupSplitOrientationMenu( ) {
1089+ const [ buttonTitle , auto , sideBySide , stacked ] =
1090+ await this . panelDoc . l10n . formatValues ( [
1091+ { id : "inspector-split-orientation-button-title" } ,
1092+ { id : "inspector-split-orientation-auto" } ,
1093+ { id : "inspector-split-orientation-side-by-side" } ,
1094+ { id : "inspector-split-orientation-stacked" } ,
1095+ ] ) ;
1096+
1097+ // The inspector could have been destroyed while waiting for the strings.
1098+ if ( ! this . panelDoc ) {
1099+ return ;
1100+ }
1101+
1102+ this . #splitOrientationL10nStrings = {
1103+ buttonTitle,
1104+ auto,
1105+ sideBySide,
1106+ stacked,
1107+ } ;
1108+ this . #renderSplitOrientationMenu( ) ;
1109+ }
1110+
1111+ #renderSplitOrientationMenu( ) {
1112+ const strings = this . #splitOrientationL10nStrings;
1113+ const container = this . panelDoc ?. getElementById (
1114+ "inspector-split-orientation-menu"
1115+ ) ;
1116+ if ( ! strings || ! container ) {
1117+ return ;
1118+ }
1119+
1120+ const orientation = this . #splitOrientationPrefValue;
1121+ const items = [
1122+ this . MenuItem ( {
1123+ key : SPLIT_ORIENTATIONS . AUTO ,
1124+ id : "inspector-split-orientation-auto" ,
1125+ role : "menuitemradio" ,
1126+ checked : orientation === SPLIT_ORIENTATIONS . AUTO ,
1127+ label : strings . auto ,
1128+ icon : "chrome://devtools/skin/images/dock-auto.svg" ,
1129+ onClick : ( ) =>
1130+ Services . prefs . setCharPref (
1131+ SPLIT_ORIENTATION_PREF ,
1132+ SPLIT_ORIENTATIONS . AUTO
1133+ ) ,
1134+ } ) ,
1135+ this . MenuItem ( {
1136+ key : SPLIT_ORIENTATIONS . SIDE ,
1137+ id : "inspector-split-orientation-side" ,
1138+ role : "menuitemradio" ,
1139+ checked : orientation === SPLIT_ORIENTATIONS . SIDE ,
1140+ label : strings . sideBySide ,
1141+ icon : "chrome://devtools/skin/images/dock-side-right.svg" ,
1142+ onClick : ( ) =>
1143+ Services . prefs . setCharPref (
1144+ SPLIT_ORIENTATION_PREF ,
1145+ SPLIT_ORIENTATIONS . SIDE
1146+ ) ,
1147+ } ) ,
1148+ this . MenuItem ( {
1149+ key : SPLIT_ORIENTATIONS . STACKED ,
1150+ id : "inspector-split-orientation-stacked" ,
1151+ role : "menuitemradio" ,
1152+ checked : orientation === SPLIT_ORIENTATIONS . STACKED ,
1153+ label : strings . stacked ,
1154+ icon : "chrome://devtools/skin/images/dock-bottom.svg" ,
1155+ onClick : ( ) =>
1156+ Services . prefs . setCharPref (
1157+ SPLIT_ORIENTATION_PREF ,
1158+ SPLIT_ORIENTATIONS . STACKED
1159+ ) ,
1160+ } ) ,
1161+ ] ;
1162+
1163+ this . ReactDOM . render (
1164+ this . MenuButton (
1165+ {
1166+ id : "inspector-split-orientation-button" ,
1167+ menuId : "inspector-split-orientation-menu-panel" ,
1168+ toolboxDoc : this . #toolbox. doc ,
1169+ className : "devtools-button" ,
1170+ title : strings . buttonTitle ,
1171+ } ,
1172+ ( ) => this . MenuList ( { } , items )
1173+ ) ,
1174+ container
1175+ ) ;
1176+ }
1177+
1178+ #onSplitOrientationPrefChange = ( ) => {
1179+ this . #splitOrientationPrefValue = Services . prefs . getCharPref (
1180+ SPLIT_ORIENTATION_PREF ,
1181+ SPLIT_ORIENTATIONS . AUTO
1182+ ) ;
1183+ if ( this . #destroyed || ! this . splitBox ) {
1184+ return ;
1185+ }
1186+ this . splitBox . setState ( { vert : this . #useSideBySideLayout( ) } ) ;
1187+ this . #renderSplitOrientationMenu( ) ;
1188+ } ;
1189+
10291190 getSidebarSize ( ) {
10301191 let width ;
10311192 let height ;
@@ -1139,7 +1300,7 @@ class Inspector extends EventEmitter {
11391300 // bottom-right panel in vertical mode width in 3 pane mode.
11401301 let sidebarSplitboxWidth ;
11411302
1142- if ( this . #useLandscapeMode ( ) ) {
1303+ if ( this . #useSideBySideLayout ( ) ) {
11431304 // Whether or not doubling the inspector sidebar's (right panel in horizontal mode
11441305 // or bottom panel in vertical mode) width will be bigger than half of the
11451306 // toolbox's width.
@@ -1224,7 +1385,7 @@ class Inspector extends EventEmitter {
12241385 "inspector-splitter-box"
12251386 ) ;
12261387 this . splitBox . setState ( {
1227- width : this . #useLandscapeMode ( )
1388+ width : this . #useSideBySideLayout ( )
12281389 ? this . sidebarSplitBoxRef . current . state . width
12291390 : splitterBox . clientWidth ,
12301391 } ) ;
0 commit comments