2626 QTabWidget ,
2727 QTextEdit ,
2828 QToolButton ,
29+ QStatusBar ,
2930 QWidget ,
3031)
3132
@@ -180,12 +181,19 @@ def _find(cls, name: str):
180181 self .toolButton_more = _find (QToolButton , "toolButton_more" )
181182 self .log = _find (QTextEdit , "log" )
182183 self .progress = _find (QProgressBar , "progress" )
184+ self .statusbar = self .findChild (QStatusBar , "statusbar" )
185+ self .status_hint = None
186+ try :
187+ self .status_hint = self .statusbar .findChild (QLabel , "status_hint" ) if self .statusbar else None
188+ except Exception :
189+ self .status_hint = None
183190 try :
184191 if self .log is not None :
185192 self .log .setReadOnly (True )
186193 self .log .setAcceptRichText (False )
187194 except Exception :
188195 pass
196+ _setup_status_bar (self )
189197
190198
191199def _setup_ide_like_compiler_tabs (self ) -> None :
@@ -207,6 +215,7 @@ def _apply_classic_policies(self) -> None:
207215 from ..UiConnection import (
208216 _apply_button_icons ,
209217 _apply_initial_theme ,
218+ _auto_resize_for_screen ,
210219 _connect_dialogs_to_app ,
211220 _refresh_log_palette ,
212221 )
@@ -215,6 +224,10 @@ def _apply_classic_policies(self) -> None:
215224 _apply_initial_theme (self )
216225 _refresh_log_palette (self )
217226 _apply_button_icons (self )
227+ try :
228+ QTimer .singleShot (0 , lambda : _auto_resize_for_screen (self ))
229+ except Exception :
230+ _auto_resize_for_screen (self )
218231 except Exception :
219232 pass
220233
@@ -406,6 +419,7 @@ def _apply_activity_buttons_theme(self) -> None:
406419 btn .setStyleSheet (style )
407420 except Exception :
408421 pass
422+ _apply_status_bar_theme (self , dark , fg , border )
409423
410424
411425def _connect_ide_like_signals (self ) -> None :
@@ -458,6 +472,7 @@ def _connect_text(widget, handler) -> None:
458472 self .btn_bc_loader .clicked .connect (lambda : open_bc_loader_dialog (self ))
459473 except Exception :
460474 pass
475+ _bind_status_updates (self )
461476
462477def init_ide_like_ui (self ) -> None :
463478 """Initialize the ide-like UI and wire it to existing Core methods."""
@@ -469,6 +484,166 @@ def init_ide_like_ui(self) -> None:
469484 _schedule_ide_like_async_init (self )
470485
471486
487+ def _setup_status_bar (self ) -> None :
488+ if self .statusbar is None :
489+ try :
490+ self .statusbar = QStatusBar (self )
491+ self .statusbar .setObjectName ("statusbar" )
492+ self .setStatusBar (self .statusbar )
493+ except Exception :
494+ return
495+ try :
496+ self .status_hint = QLabel ("Ready" )
497+ self .status_hint .setObjectName ("status_hint" )
498+ self .statusbar .addPermanentWidget (self .status_hint , 1 )
499+ except Exception :
500+ pass
501+
502+
503+ def _apply_status_bar_theme (self , dark : bool , fg : str , border : str ) -> None :
504+ if not getattr (self , "statusbar" , None ):
505+ return
506+ if dark :
507+ bg = "#151A20"
508+ else :
509+ bg = "#F7F7F9"
510+ style = (
511+ "QStatusBar {"
512+ f"background: { bg } ;"
513+ f"color: { fg } ;"
514+ f"border-top: 1px solid { border } ;"
515+ "}"
516+ "QStatusBar::item { border: none; }"
517+ "QLabel#status_hint { padding: 2px 8px; }"
518+ )
519+ try :
520+ self .statusbar .setStyleSheet (style )
521+ except Exception :
522+ pass
523+
524+
525+ def _bind_status_updates (self ) -> None :
526+ """Keep a lightweight status line without touching core logic."""
527+ statusbar = getattr (self , "statusbar" , None )
528+ if statusbar is None :
529+ return
530+
531+ def _queue_update () -> None :
532+ try :
533+ QTimer .singleShot (0 , lambda : _update_status_line (self ))
534+ except Exception :
535+ _update_status_line (self )
536+
537+ _queue_update ()
538+
539+ for attr in (
540+ "btn_select_folder" ,
541+ "btn_select_files" ,
542+ "btn_remove_file" ,
543+ "btn_clear_workspace" ,
544+ "venv_button" ,
545+ "compile_btn" ,
546+ "cancel_btn" ,
547+ ):
548+ btn = getattr (self , attr , None )
549+ if btn is None :
550+ continue
551+ try :
552+ btn .clicked .connect (_queue_update )
553+ except Exception :
554+ pass
555+
556+ file_list = getattr (self , "file_list" , None )
557+ if file_list is not None :
558+ try :
559+ file_list .itemSelectionChanged .connect (_queue_update )
560+ except Exception :
561+ pass
562+ try :
563+ model = file_list .model ()
564+ if model is not None :
565+ model .rowsInserted .connect (lambda * _ : _queue_update ())
566+ model .rowsRemoved .connect (lambda * _ : _queue_update ())
567+ model .modelReset .connect (lambda * _ : _queue_update ())
568+ except Exception :
569+ pass
570+
571+ compiler_tabs = getattr (self , "compiler_tabs" , None )
572+ if compiler_tabs is not None :
573+ try :
574+ compiler_tabs .currentChanged .connect (lambda * _ : _queue_update ())
575+ except Exception :
576+ pass
577+
578+ progress = getattr (self , "progress" , None )
579+ if progress is not None :
580+ try :
581+ progress .valueChanged .connect (lambda * _ : _queue_update ())
582+ except Exception :
583+ pass
584+
585+
586+ def _update_status_line (self ) -> None :
587+ statusbar = getattr (self , "statusbar" , None )
588+ if statusbar is None :
589+ return
590+
591+ def _short_path (path : str | None , max_len : int = 28 ) -> str :
592+ if not path :
593+ return "None"
594+ try :
595+ p = os .path .normpath (path )
596+ except Exception :
597+ p = path
598+ if len (p ) <= max_len :
599+ return p
600+ return f"...{ p [- max_len :]} "
601+
602+ ws = _short_path (getattr (self , "workspace_dir" , None ))
603+ files_total = 0
604+ files_sel = 0
605+ try :
606+ fl = getattr (self , "file_list" , None )
607+ if fl is not None :
608+ files_total = fl .count ()
609+ files_sel = len (fl .selectedItems ())
610+ except Exception :
611+ pass
612+
613+ engine_name = "None"
614+ try :
615+ tabs = getattr (self , "compiler_tabs" , None )
616+ if tabs is not None and tabs .currentIndex () >= 0 :
617+ engine_name = tabs .tabText (tabs .currentIndex ())
618+ except Exception :
619+ pass
620+
621+ prog = ""
622+ try :
623+ pb = getattr (self , "progress" , None )
624+ if pb is not None :
625+ prog = f"{ pb .value ()} %"
626+ except Exception :
627+ pass
628+
629+ parts = [
630+ f"Workspace: { ws } " ,
631+ f"Files: { files_total } " ,
632+ f"Selected: { files_sel } " ,
633+ f"Engine: { engine_name } " ,
634+ ]
635+ if prog :
636+ parts .append (f"Progress: { prog } " )
637+
638+ msg = " | " .join (parts )
639+ try :
640+ if getattr (self , "status_hint" , None ):
641+ self .status_hint .setText (msg )
642+ statusbar .showMessage (msg )
643+ except Exception :
644+ pass
645+
646+
472647def _schedule_ide_like_async_init (self ) -> None :
473648 """Defer heavier IDE setup steps to keep first paint responsive."""
474649 try :
0 commit comments