3535 TitleBarFormat ,
3636)
3737from .palettes import BLACK , WHITE
38+ from .utils import pack_close_to_square
3839
3940logger = logging .getLogger ("epicsdb2bob" )
4041
@@ -151,26 +152,31 @@ def add_widget_for_record(
151152
152153
153154def add_title_bar (
154- name : str , config : EPICSDB2BOBConfig , title_bar_width : int
155+ name : str ,
156+ config : EPICSDB2BOBConfig ,
157+ title_bar_width : int ,
158+ top_level_titlebar : bool = False ,
155159) -> Label | None :
156- if config .title_bar_format == TitleBarFormat .NONE :
160+ title_bar_format = (
161+ config .title_bar_format if not top_level_titlebar else TitleBarFormat .FULL
162+ )
163+
164+ if title_bar_format == TitleBarFormat .NONE :
157165 return None
158166
159167 title_bar = Label (
160- short_uuid () ,
168+ "TitleBar" ,
161169 name ,
162- config .widget_offset
163- if config .title_bar_format == TitleBarFormat .MINIMAL
164- else 0 ,
170+ config .widget_offset if title_bar_format == TitleBarFormat .MINIMAL else 0 ,
165171 0 ,
166172 title_bar_width ,
167- config .title_bar_heights [config . title_bar_format ],
173+ config .title_bar_heights [title_bar_format ],
168174 )
169175 title_bar .foreground_color (* WHITE )
170- if config . title_bar_format == TitleBarFormat .FULL :
176+ if title_bar_format == TitleBarFormat .FULL :
171177 title_bar .font_size (config .font_size * 2 )
172178 title_bar .horizontal_alignment_center ()
173- elif config . title_bar_format == TitleBarFormat .MINIMAL :
179+ elif title_bar_format == TitleBarFormat .MINIMAL :
174180 title_bar .auto_size ()
175181 title_bar .font_size (config .font_size + 2 )
176182 title_bar .border_width (2 )
@@ -328,7 +334,11 @@ def generate_bobfile_for_db(
328334 else :
329335 screen_height = current_y_pos + config .widget_offset
330336
331- title_bar = add_title_bar (name , config , screen_width - config .widget_offset )
337+ title_bar = add_title_bar (
338+ name .replace ("_" , " " ).replace ("-" , " " ),
339+ config ,
340+ screen_width - config .widget_offset ,
341+ )
332342 if title_bar :
333343 widget_counters [Label ] = widget_counters .get (Label , 0 ) + 1
334344 title_bar .name (f"Label_{ widget_counters [Label ]} " )
@@ -340,7 +350,7 @@ def generate_bobfile_for_db(
340350 screen_height - int (config .title_bar_heights [config .title_bar_format ] / 2 )
341351 )
342352
343- screen .background_color (* config .background_color )
353+ screen .background_color (* config .palette . screen_bg )
344354
345355 screen .height (screen_height )
346356 screen .width (screen_width )
@@ -372,22 +382,17 @@ def generate_bobfile_for_substitution(
372382 """
373383 Generate a BOB file for a substitution.
374384 """
385+ substitution_name .replace ("_" , " " ).replace ("-" , " " ).title ()
375386 screen = Screen (substitution_name )
376387 screen .background_color (* config .background_color )
377388
378- screen_width = 0
379- max_col_width = 0
380- hit_max_y_pos = False
381-
382- current_x_pos = config .widget_offset
383- current_y_pos = (
384- config .widget_offset + config .title_bar_heights [config .title_bar_format ]
385- )
386389 launcher_buttons : dict [str , ActionButton ] = {}
387390
388391 logger .info (f"Generating screen for substitution: { substitution_name } " )
389392 logger .debug (f"Found bobfiles: { found_bobfiles } " )
390393
394+ embed_rects : dict [Widget , tuple [int , int ]] = {}
395+
391396 for template in substitution :
392397 template_instances = substitution [template ]
393398 logger .info (f"Processing template: { template } " )
@@ -402,33 +407,20 @@ def generate_bobfile_for_substitution(
402407 )
403408 embed_height = embed_raw_height + config .widget_offset
404409 embed_width = embed_raw_width + config .widget_offset
405- if (
406- current_y_pos + embed_height
407- > config .max_screen_height
408- + config .title_bar_heights [TitleBarFormat .FULL ]
409- ):
410- current_y_pos = (
411- config .widget_offset
412- + config .title_bar_heights [TitleBarFormat .FULL ]
413- )
414- current_x_pos += max_col_width + config .widget_offset
415- max_col_width = 0
416410
417411 embedded_display = EmbeddedDisplay (
418412 short_uuid (),
419413 template_to_bob (template ),
420- current_x_pos ,
421- current_y_pos ,
414+ 0 ,
415+ 0 ,
422416 embed_width ,
423417 embed_height ,
424418 )
425- current_y_pos += embed_height + config .widget_offset
426419
427- if embed_width > max_col_width :
428- max_col_width = embed_width
420+ embed_rects [ embedded_display ] = ( embed_width , embed_height )
421+
429422 for macro in instance :
430423 embedded_display .macro (macro , instance [macro ])
431- screen .add_widget (embedded_display )
432424
433425 elif template in launcher_buttons :
434426 launcher_buttons [template ].action_open_display (
@@ -439,49 +431,59 @@ def generate_bobfile_for_substitution(
439431 )
440432 else :
441433 logger .info (f"Creating launcher button for template: { template } " )
434+
442435 launcher_buttons [template ] = ActionButton (
443436 short_uuid (),
444437 os .path .splitext (template )[0 ],
445438 "" ,
446- current_x_pos ,
447- current_y_pos ,
439+ 0 ,
440+ 0 ,
448441 config .default_widget_width ,
449442 config .default_widget_height ,
450443 )
444+
451445 launcher_buttons [template ].action_open_display (
452446 template_to_bob (template ),
453447 "tab" ,
454448 f"{ os .path .splitext (template )[0 ]} { i + 1 } " ,
455449 instance ,
456450 )
457- screen .add_widget (launcher_buttons [template ])
458- current_y_pos += config .default_widget_height + config .widget_offset
459-
460- if config .default_widget_width > max_col_width :
461- max_col_width = config .default_widget_width
462-
463- if (
464- current_y_pos
465- > config .max_screen_height
466- + config .title_bar_heights [TitleBarFormat .FULL ]
467- ):
468- hit_max_y_pos = True
469- current_y_pos = (
470- config .widget_offset
471- + config .title_bar_heights [TitleBarFormat .FULL ]
472- )
473- current_x_pos += max_col_width + config .widget_offset
474- max_col_width = 0
451+ embed_rects [launcher_buttons [template ]] = (
452+ config .default_widget_width + config .widget_offset ,
453+ config .default_widget_height + config .widget_offset ,
454+ )
475455
476- screen_height = current_y_pos + config .widget_offset
477- if hit_max_y_pos :
478- screen_height = config .max_screen_height + config .widget_offset
479- screen_width = current_x_pos + max_col_width + config .widget_offset
456+ packed_x_y_embeds = pack_close_to_square (
457+ list (embed_rects .values ()),
458+ config .max_screen_height ,
459+ padding = config .widget_offset ,
460+ )
461+
462+ embed_stop_positions = [
463+ (pos [0 ] + size [0 ], pos [1 ] + size [1 ])
464+ for pos , size in zip (packed_x_y_embeds , embed_rects .values (), strict = False )
465+ ]
466+ screen_width = max ([pos [0 ] for pos in embed_stop_positions ], default = 0 )
467+ screen_height = max ([pos [1 ] for pos in embed_stop_positions ], default = 0 )
468+ screen_height = screen_height + 5 * config .widget_offset
469+
470+ for i , (xy_position , embed ) in enumerate (
471+ zip (packed_x_y_embeds , embed_rects .keys (), strict = False )
472+ ):
473+ embed .x (xy_position [0 ])
474+ embed .y (
475+ xy_position [1 ]
476+ + config .title_bar_heights [config .title_bar_format ]
477+ + 3 * config .widget_offset
478+ )
479+ embed .name (f"{ embed .__class__ .__name__ } _{ i + 1 } " )
480+ screen .add_widget (embed )
480481
481482 title_bar = add_title_bar (
482483 substitution_name ,
483484 config ,
484485 screen_width - config .widget_offset ,
486+ top_level_titlebar = True ,
485487 )
486488 if title_bar :
487489 screen .add_widget (title_bar )
0 commit comments