88
99from .viewlist import possible_class_views
1010from .layout_presets import get_layout_description
11- from .utils_global import get_size_bottom_row , get_size_top_row
11+ from .utils_global import fill_unnecessary_space , get_present_zones_in_half_of_layout
1212
1313from .utils_qt import qt_style , add_stretch_to_qtoolbar
1414
@@ -200,9 +200,9 @@ def create_main_layout(self):
200200 view_names = [view_name for view_name in view_names if view_name in self .views .keys ()]
201201 widgets_zone [zone ] = view_names
202202
203- self .make_dock (widgets_zone , [ 'zone1' , 'zone2' , 'zone5' , 'zone6' ], "left" , col_shift = 0 )
204- self .make_dock (widgets_zone , [ 'zone3' , 'zone4' , 'zone7' , 'zone8' ], "right" , col_shift = 2 )
205-
203+ self .make_half_layout (widgets_zone , "left" )
204+ self .make_half_layout (widgets_zone , "right" )
205+
206206 # make tabs
207207 for zone , view_names in widgets_zone .items ():
208208 n = len (widgets_zone [zone ])
@@ -217,103 +217,70 @@ def create_main_layout(self):
217217 # make visible the first of each zone
218218 self .docks [view_name0 ].raise_ ()
219219
220- def make_dock (self , widgets_zone , all_zones , side_of_window , col_shift ):
221-
222- all_zones_array = np .transpose (np .reshape (all_zones , (2 ,2 )))
223- is_zone = np .array ([(widgets_zone .get (zone ) is not None ) and (len (widgets_zone .get (zone )) > 0 ) for zone in all_zones ])
224- is_zone_array = np .reshape (is_zone , (2 ,2 ))
225-
226- # If the first non-zero zero (from left to right) is on the bottom, move it up
227- for column_index , zones_in_columns in enumerate (is_zone_array ):
228- if np .any (zones_in_columns ):
229- first_is_top = zones_in_columns [0 ]
230- if not first_is_top :
231- top_zone = f"zone{ column_index + 1 + col_shift } "
232- bottom_zone = f"zone{ column_index + 5 + col_shift } "
233- widgets_zone [top_zone ] = widgets_zone [bottom_zone ]
234- widgets_zone [bottom_zone ] = []
235- continue
236-
237- is_zone = np .array ([(widgets_zone .get (zone ) is not None ) and (len (widgets_zone .get (zone )) > 0 ) for zone in all_zones ])
238- is_zone_array = np .reshape (is_zone , (2 ,2 ))
239- original_zone_array = copy (is_zone_array )
240-
241- # First we split horizontally any columns which are two rows long.
242- # For later, group the zones between these splits
243- all_groups = []
244- group = []
245- for col_index , zones in enumerate (all_zones_array ):
246- col = col_index % 2
247- is_a_zone = original_zone_array [:,col ]
248- num_row_0 , _ = get_size_top_row (0 , col , is_zone_array , original_zone_array )
249- # this function affects is_zone_array so must be run
250- _ , _ = get_size_bottom_row (1 , col , is_zone_array , original_zone_array )
251-
252- if num_row_0 == 2 :
253- if len (group ) > 0 :
254- all_groups .append (group )
255- group = []
256- allowed_zones = zones [is_a_zone ]
257- all_groups .append (allowed_zones )
258- else :
259- for zone in zones [is_a_zone ]:
260- group .append (zone )
261-
262- if len (group ) > 0 :
263- all_groups .append (group )
264-
265- if len (all_groups ) == 0 :
266- return
267-
268- first_zone = all_groups [0 ][0 ]
269- first_dock = widgets_zone [first_zone ][0 ]
270- dock = self .docks [first_dock ]
271- self .addDockWidget (areas [side_of_window ], dock )
272-
273- for group in reversed (all_groups [1 :]):
274- digits = np .array ([int (s [- 1 ]) for s in group ])
275- sorted_indices = np .argsort (digits )
276- sorted_arr = np .array (group )[sorted_indices ]
277- view_name = widgets_zone [sorted_arr [0 ]][0 ]
278- dock = self .docks [view_name ]
279- self .splitDockWidget (self .docks [first_dock ], dock , orientations ['horizontal' ])
280-
281- # Now take each sub-group, and split vertically if appropriate
282- new_all_groups = []
283- for group in all_groups :
284-
285- if len (group ) == 1 :
286- # if only one in group, not need to split
287- continue
288-
289- top_zones = [zone for zone in group if zone in ['zone1' , 'zone2' , 'zone3' , 'zone4' ]]
290- bottom_zones = [zone for zone in group if zone in ['zone5' , 'zone6' , 'zone7' , 'zone8' ]]
291- new_all_groups .append ([top_zones , bottom_zones ])
220+ def make_half_layout (self , widgets_zone , left_or_right ):
221+ """
222+ Function contains the logic for the greedy layout. Given the 2x2 box of zones
292223
293- if len (top_zones ) > 0 and len (bottom_zones ) > 0 :
224+ 1 2 3 4
225+ 5 6 or 7 8
294226
295- top_view_name = widgets_zone [top_zones [0 ]][0 ]
296- top_dock = self .docks [top_view_name ]
227+ Then depending on which zones are non-zero, a different layout is generated using splits.
297228
298- bottom_view_name = widgets_zone [bottom_zones [0 ]][0 ]
299- bottom_dock = self .docks [bottom_view_name ]
229+ The zone indices in the second box (34,78) are equal to the zone indices first box (12,56)
230+ shifted by 2. We take advantage of this fact.
231+ """
300232
301- self . splitDockWidget ( top_dock , bottom_dock , orientations [ 'vertical' ])
233+ shift = 0 if left_or_right == "left" else 2
302234
303- # Finally, split all the sub-sub-groups horizontally
304- for top_bottom_groups in new_all_groups :
305- for group in top_bottom_groups :
306-
307- if len (group ) <= 1 :
308- # if only one in group, no need to split
309- continue
310-
311- first_zone_name = widgets_zone [group [0 ]][0 ]
312- for zone in reversed (group [1 :]):
313- zone_name = widgets_zone [zone ][0 ]
314- self .splitDockWidget (self .docks [first_zone_name ], self .docks [zone_name ], orientations ['horizontal' ])
235+ widgets_zone = fill_unnecessary_space (widgets_zone , shift )
236+ present_zones = get_present_zones_in_half_of_layout (widgets_zone , shift )
315237
238+ if len (present_zones ) == 0 :
239+ return
316240
241+ # The movements from earlier guarantee that the top-left zone is non-zero. Make this the initial zone
242+ view_name = widgets_zone [f"zone{ 1 + shift } " ][0 ]
243+ dock = self .docks [view_name ]
244+ self .addDockWidget (areas [left_or_right ], dock )
245+
246+ # The main logic: apply splittings between different zones and in
247+ # different orders, depending on which zones are present.
248+
249+ # Layouts with two non-zero zones
250+ if present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 2 + shift } ' ]):
251+ self .make_split (1 ,2 ,"horizontal" , widgets_zone , shift )
252+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 5 + shift } ' ]):
253+ self .make_split (1 ,5 ,"vertical" , widgets_zone , shift )
254+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 6 + shift } ' ]):
255+ self .make_split (1 ,6 ,"horizontal" , widgets_zone , shift )
256+
257+ # Layouts with three non-zero zones
258+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 2 + shift } ' , f'zone{ 5 + shift } ' ]):
259+ self .make_split (1 ,2 ,"horizontal" , widgets_zone , shift )
260+ self .make_split (1 ,5 ,"vertical" , widgets_zone , shift )
261+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 2 + shift } ' , f'zone{ 6 + shift } ' ]):
262+ self .make_split (1 ,2 ,"horizontal" , widgets_zone , shift )
263+ self .make_split (2 ,6 ,"vertical" , widgets_zone , shift )
264+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 5 + shift } ' , f'zone{ 6 + shift } ' ]):
265+ self .make_split (1 ,5 ,"vertical" , widgets_zone , shift )
266+ self .make_split (5 ,6 ,"horizontal" , widgets_zone , shift )
267+
268+ # Layout with four non-zero zones
269+ elif present_zones == set ([f'zone{ 1 + shift } ' , f'zone{ 2 + shift } ' , f'zone{ 5 + shift } ' , f'zone{ 6 + shift } ' ]):
270+ self .make_split (1 ,5 ,"vertical" , widgets_zone , shift )
271+ self .make_split (1 ,2 ,"horizontal" , widgets_zone , shift )
272+ self .make_split (5 ,6 ,"horizontal" , widgets_zone , shift )
273+
274+
275+ def make_split (self , zone_index_1 , zone_index_2 , orientation , widgets_zone , shift ):
276+ """
277+ Splits the zone at `zone_{zone_index_1+shift}` into two zones
278+ (`zone_{zone_index_1+shift}` and `zone_{zone_index_2+shift}`)
279+ with an `orientation` split.
280+ """
281+ widget_1 = widgets_zone [f"zone{ zone_index_1 + shift } " ][0 ]
282+ widget_2 = widgets_zone [f"zone{ zone_index_2 + shift } " ][0 ]
283+ self .splitDockWidget (self .docks [widget_1 ], self .docks [widget_2 ], orientations [orientation ])
317284
318285 # used by to tell the launcher this is closed
319286 def closeEvent (self , event ):
0 commit comments