From 1c3848d29bb82d65c82fc0824bff4bea566ad8e8 Mon Sep 17 00:00:00 2001 From: Mike Hendricks Date: Thu, 11 Dec 2025 16:46:15 -0800 Subject: [PATCH] The OutputConsole now use the same stylesheet used by preditor Updating the style of the controller will automatically apply that style to the OutputWindow. This is not enabled by default for ConsoleBase or ConsolePrEdit. --- examples/output_console.py | 54 ++++++++++++++++++++++++++-------- examples/output_console.ui | 49 +++++++++++++++++++++++++++--- preditor/gui/console_base.py | 42 ++++++++++++++++++++++++++ preditor/gui/output_console.py | 6 ++++ 4 files changed, 134 insertions(+), 17 deletions(-) diff --git a/examples/output_console.py b/examples/output_console.py index 6cdba005..16896376 100644 --- a/examples/output_console.py +++ b/examples/output_console.py @@ -6,6 +6,7 @@ import logging import sys +from argparse import ArgumentParser import Qt from Qt.QtCore import QDateTime @@ -26,7 +27,7 @@ class ExampleApp(QMainWindow): - def __init__(self, parent=None): + def __init__(self, parent=None, init_preditor=True): super().__init__(parent=parent) # Use a .ui file to simplify the example code setup. Qt.QtCompat.loadUi(__file__.replace(".py", ".ui"), self) @@ -40,6 +41,8 @@ def __init__(self, parent=None): self.uiAllLoggingChangeHandlersBTN.released.connect( self.all_logging_change_handlers ) + self.uiUsePrEditorStyleCHK.toggled.connect(self.set_stdout_style) + self.uiRemovePrEditorStyleBTN.released.connect(self.clear_stdout_style) self.uiLoggingCriticalBTN.released.connect(self.level_critical) self.uiLoggingErrorBTN.released.connect(self.level_error) self.uiLoggingWarningBTN.released.connect(self.level_warning) @@ -51,12 +54,15 @@ def __init__(self, parent=None): self.uiSendLoggingBTN.released.connect(self.send_logging) # 1. Create the preditor instance and connect to the console's controllers - plog = preditor.instance(parent=self, create=True) - preditor.connect_preditor(self) - self.uiAllLog.controller = plog - self.uiSelectLog.controller = plog - self.uiStdout.controller = plog - self.uiStderr.controller = plog + if init_preditor: + plog = preditor.instance(parent=self, create=True) + preditor.connect_preditor(self) + self.uiAllLog.controller = plog + self.uiSelectLog.controller = plog + self.uiStdout.controller = plog + self.uiStderr.controller = plog + else: + self.setWindowTitle(f"{self.windowTitle()} - No PrEditor") # 2. Configure the various OutputConsole widgets. # Note: this can be done in the .ui file, but for this example we will @@ -149,6 +155,11 @@ def clear_all(self): self.uiStdout.clear() self.uiStderr.clear() + def clear_stdout_style(self): + """Reset uiStdout's style to not use PrEditor's style.""" + self.uiUsePrEditorStyleCHK.setChecked(False) + self.uiStdout.setStyleSheet(None) + def level_critical(self): logging.root.setLevel(logging.CRITICAL) @@ -176,6 +187,14 @@ def print_time_stderr(self): def raise_exception(self): raise RuntimeError(self.message_time()) + def set_stdout_style(self, state): + """Enable/disable uiStdout using PrEditor's style. + + Note: Disabling it doesn't clear the style, just prevent it from being + automatically updated when changed in PrEditor. + """ + self.uiStdout.use_console_stylesheet = state + def send_logging(self): logger_a.critical("A critical msg for logger_a") logger_a.error("A error msg for logger_a") @@ -198,18 +217,27 @@ def send_logging(self): if __name__ == '__main__': + parser = ArgumentParser("Example of using OutputConsole features.") + parser.add_argument( + "--no-preditor", + action="store_true", + help="Don't init and install the PrEditor console.", + ) + args = parser.parse_args() + # Configure PrEditor for this application, start capturing all text output # from stderr/stdout so once PrEditor is launched, it can show this text. # This does not initialize any QtGui/QtWidgets. - preditor.configure( - # This is the name used to store PrEditor preferences and workboxes - # specific to this application. - 'output_console', - ) + if not args.no_preditor: + preditor.configure( + # This is the name used to store PrEditor preferences and workboxes + # specific to this application. + 'output_console', + ) # Create a Gui Application allowing the user to show PrEditor app = QApplication(sys.argv) - main_gui = ExampleApp() + main_gui = ExampleApp(init_preditor=not args.no_preditor) main_gui.show() app.exec_() diff --git a/examples/output_console.ui b/examples/output_console.ui index c479cbd1..94ff0391 100644 --- a/examples/output_console.ui +++ b/examples/output_console.ui @@ -26,7 +26,11 @@ - + + + true + + @@ -126,9 +130,46 @@ Stdout - - - + + + + + <html><head/><body><p>Reset stylesheet to empty and disable Use PrEditor Style Sheet.</p></body></html> + + + Remove Style Sheet + + + + + + + <html><head/><body><p>Enable using the stylesheet from the PrEditor instances Options -&gt; Style menu. This OutputConsole doesn't have it enabled by default so it doesn't have the stylesheet applied. Checking this will load the style sheet. If you then uncheck it, the style sheet won't be cleared but it will no longer respect the PrEditor Options -&gt; Style changes.</p></body></html> + + + Use PrEditor Style Sheet + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + diff --git a/preditor/gui/console_base.py b/preditor/gui/console_base.py index bcf68efd..8f15cfb5 100644 --- a/preditor/gui/console_base.py +++ b/preditor/gui/console_base.py @@ -39,7 +39,10 @@ class ConsoleBase(QTextEdit): def __init__(self, parent: QWidget, controller: Optional[LoggerWindow] = None): super().__init__(parent) + self._controller = None + self._stylesheet_changed_meta = None self.controller = controller + self._first_show = True # The last time a repaint call was made when writing. Used to limit the # number of refreshes to once per X.X seconds. @@ -156,7 +159,14 @@ def controller(self) -> Optional[LoggerWindow]: @controller.setter def controller(self, value: LoggerWindow): + if self._stylesheet_changed_meta and self.controller: + # Remove the existing signals if connected + self.controller.styleSheetChanged.disconnect(self._stylesheet_changed_meta) + self._stylesheet_changed_meta = None + self._controller = value + # Ensure the stylesheet is up to date and stays up to date. + self.init_stylesheet() def codeHighlighter(self): """Get the code highlighter for the console @@ -343,6 +353,22 @@ def init_excepthook(self, attrName=None, value=None): if self.write_error in PreditorExceptHook.callbacks: PreditorExceptHook.callbacks.remove(self.write_error) + def init_stylesheet(self, attrName=None, value=None): + if not self.controller: + return + + signal = self.controller.styleSheetChanged + if self.use_console_stylesheet: + # Apply the stylesheet and ensure that future updates are respected + self._stylesheet_changed_meta = signal.connect(self.update_stylesheet) + self.update_stylesheet() + + elif self._stylesheet_changed_meta: + # if disabling use_console_stylesheet, then remove the existing + # connection if it was previously connected. + signal.disconnect(self._stylesheet_changed_meta) + self._stylesheet_changed_meta = None + def maybeRepaint(self, force=False): """Forces the console to repaint if enough time has elapsed from the last repaint. @@ -579,6 +605,12 @@ def update_streams(self, attrName=None, value=None): else: self.stream_manager.remove_callback(self.write) + def update_stylesheet(self): + sheet = None + if self.controller: + sheet = self.controller.styleSheet() + self.setStyleSheet(sheet) + def get_logging_info(self, name): # Look for a specific rule to handle this logging message parts = name.split(".") @@ -864,6 +896,16 @@ def logging_formatter_str(self, value): stream_echo_stderr is disabled or you likely will get duplicate output. """ + use_console_stylesheet = QtPropertyInit( + "_use_console_stylesheet", False, callback=init_stylesheet + ) + """Set this widgets stylesheet to the PrEditor instance's style sheet. + + This ensures that the style of random OutputConsoles match even when not + parented to PrEditor. Enabling this will update the widgets style sheet, but + disabling it will not update the style sheet. + """ + # Build and add the class properties for regex patterns so subclasses can use them. ConsoleBase._ConsoleBase__defineRegexPatterns() diff --git a/preditor/gui/output_console.py b/preditor/gui/output_console.py index 30eea7e1..8f37b510 100644 --- a/preditor/gui/output_console.py +++ b/preditor/gui/output_console.py @@ -1,5 +1,11 @@ +from ..utils.cute import QtPropertyInit from .console_base import ConsoleBase class OutputConsole(ConsoleBase): """A text widget used to show stdout/stderr writes.""" + + # Enable these settings by default + use_console_stylesheet = QtPropertyInit( + "_use_console_stylesheet", True, callback=ConsoleBase.init_stylesheet + )