MetaBox/Scripts/Animation/epic_pose_wrangler/view/log_widget.py
2025-01-14 03:07:03 +08:00

140 lines
5.6 KiB
Python

# Copyright Epic Games, Inc. All Rights Reserved.
import logging
from PySide2 import QtWidgets, QtCore, QtGui
class LogWidget(logging.Handler):
"""
Custom Log Handler with embedded QtWidgets.QDockWidget
"""
def __init__(self):
super(LogWidget, self).__init__()
# Set default formatting
self.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s', '%Y-%m-%d %H:%M:%S'))
# Create dock
self._log_dock = QtWidgets.QDockWidget()
# Only allow it to be parented to the bottom
self._log_dock.setAllowedAreas(QtCore.Qt.BottomDockWidgetArea)
central_widget = QtWidgets.QWidget()
central_widget.setContentsMargins(0, 0, 0, 0)
self._log_dock.setWidget(central_widget)
main_layout = QtWidgets.QVBoxLayout()
main_layout.setContentsMargins(0, 0, 0, 0)
central_widget.setLayout(main_layout)
toolbar_layout = QtWidgets.QHBoxLayout()
toolbar_layout.setContentsMargins(0, 0, 0, 0)
main_layout.addLayout(toolbar_layout)
self._output_log = QtWidgets.QListWidget()
self._output_log.setProperty("Log", True)
self._output_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self._output_log.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self._output_log.customContextMenuRequested.connect(self._show_context_menu)
main_layout.addWidget(self._output_log)
icon_size_px = 25
icon_size = QtCore.QSize(icon_size_px, icon_size_px)
btn_size_px = 30
btn_size = QtCore.QSize(btn_size_px, btn_size_px)
self._debug_btn = QtWidgets.QPushButton()
self._debug_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:debug.png")))
self._debug_btn.setIconSize(icon_size)
self._debug_btn.setProperty("LogButton", True)
self._debug_btn.setCheckable(True)
self._debug_btn.setChecked(False)
self._debug_btn.setFixedSize(btn_size)
self._debug_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._debug_btn)
self._info_btn = QtWidgets.QPushButton()
self._info_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:info.png")))
self._info_btn.setIconSize(icon_size)
self._info_btn.setProperty("LogButton", True)
self._info_btn.setCheckable(True)
self._info_btn.setChecked(True)
self._info_btn.setFixedSize(btn_size)
self._info_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._info_btn)
self._warning_btn = QtWidgets.QPushButton()
self._warning_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:warning.png")))
self._warning_btn.setIconSize(icon_size)
self._warning_btn.setProperty("LogButton", True)
self._warning_btn.setCheckable(True)
self._warning_btn.setChecked(True)
self._warning_btn.setFixedSize(btn_size)
self._warning_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._warning_btn)
self._error_btn = QtWidgets.QPushButton()
self._error_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:error.png")))
self._error_btn.setIconSize(icon_size)
self._error_btn.setProperty("LogButton", True)
self._error_btn.setCheckable(True)
self._error_btn.setChecked(True)
self._error_btn.setFixedSize(btn_size)
self._error_btn.clicked.connect(self._refresh_log)
toolbar_layout.addWidget(self._error_btn)
toolbar_layout.addStretch(0)
self._clear_log_btn = QtWidgets.QPushButton()
self._clear_log_btn.setIcon(QtGui.QIcon(QtGui.QPixmap("PoseWrangler:clear.png")))
self._clear_log_btn.setIconSize(icon_size)
self._clear_log_btn.setProperty("LogButton", True)
self._clear_log_btn.setFixedSize(btn_size)
self._clear_log_btn.clicked.connect(self._output_log.clear)
toolbar_layout.addWidget(self._clear_log_btn)
@property
def log_dock(self):
return self._log_dock
def emit(self, record):
level_colour_map = {
logging.DEBUG: QtGui.QColor(91, 192, 222),
logging.INFO: QtGui.QColor(247, 247, 247),
logging.WARNING: QtGui.QColor(240, 173, 78),
logging.ERROR: QtGui.QColor(217, 83, 79)
}
msg = self.format(record)
item = QtWidgets.QListWidgetItem(msg)
item.setData(QtCore.Qt.UserRole, record.levelno)
item.setForeground(QtGui.QBrush(level_colour_map[record.levelno]))
self._output_log.addItem(item)
self._refresh_log()
def _refresh_log(self):
level_btn_map = {
logging.DEBUG: self._debug_btn,
logging.INFO: self._info_btn,
logging.WARNING: self._warning_btn,
logging.ERROR: self._error_btn
}
for i in range(0, self._output_log.count()):
item = self._output_log.item(i)
data = item.data(QtCore.Qt.UserRole)
item.setHidden(not level_btn_map[data].isChecked())
def _copy_to_clipboard(self):
clipboard_text = ""
for item in self._output_log.selectedItems():
text = item.text()
clipboard_text += text
if text:
clipboard_text += "\n"
clipboard = QtWidgets.QApplication.clipboard()
clipboard.setText(clipboard_text)
def _show_context_menu(self, pos):
if not self._output_log.selectedItems():
return
menu = QtWidgets.QMenu(parent=self._output_log)
copy_action = menu.addAction("Copy")
copy_action.triggered.connect(self._copy_to_clipboard)
menu.exec_(QtGui.QCursor.pos())