Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion meshroom/ui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from meshroom.ui.components.scene3D import Scene3DHelper, Transformations3DHelper
from meshroom.ui.components.scriptEditor import ScriptEditorManager
from meshroom.ui.components.thumbnail import ThumbnailCache
from meshroom.ui.components.statusBar import MessageController
from meshroom.ui.components.messaging import MessageController
from meshroom.ui.palette import PaletteManager
from meshroom.ui.reconstruction import Reconstruction
from meshroom.ui.utils import QmlInstantEngine
Expand Down
77 changes: 77 additions & 0 deletions meshroom/ui/components/messaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import json
from PySide6.QtCore import QObject
from datetime import datetime
from meshroom.common import Signal, Slot, Property


class Message:
def __init__(self, msg, status=None):
self.msg = msg
self.status = status or "info"
self.date = datetime.now()

def dateStr(self, fullDate=False):
dateFormat = "%H:%M:%S"
if fullDate:
dateFormat = "%Y-%m-%d %H:%M:%S.%f"
return self.date.strftime(dateFormat)


class MessageController(QObject):
"""
Handles messages sent from the Python side to the StatusBar component
"""

message = Signal(str, str, int)
messagesChanged = Signal() # Signal to notify when messages list changes

def __init__(self, parent):
super().__init__(parent)
self._messages = []

def sendMessage(self, msg, status, duration):
""" Sends a message that will be displayed on the status bar """
self.message.emit(msg, status, duration)

@Slot(str, str)
def storeMessage(self, msg, status):
""" Adds a new message in the stack """
self._messages.append(Message(msg, status or "info"))
self.messagesChanged.emit() # Notify QML that messages have changed

def _getMessagesDict(self, fullDate=False):
""" Get a dict with all stored messages """
messages = []
for msg in self._messages:
messages.append({
"status": msg.status,
"date": msg.dateStr(fullDate),
"text": msg.msg,
})
return messages

def getMessages(self):
""" Get the messages with simple date infos.
Reverse the list to make sure we see the most recent item on top
"""
return self._getMessagesDict()[::-1]

@Slot(result=str)
def getMessagesAsString(self):
""" Return messages for clipboard copy
.. note::
Could also do `json.dumps(self._getMessagesDict(fullDate=True), indent=4)`
"""
messages = []
for msg in self._messages:
messages.append(f"{msg.dateStr(True)} [{msg.status.upper():<7}] {msg.msg}")
return "\n".join(messages)

@Slot()
def clearMessages(self):
""" Clear all stored messages """
self._messages.clear()
self.messagesChanged.emit()

# Property to expose messages to QML
messages = Property("QVariantList", getMessages, notify=messagesChanged)
16 changes: 0 additions & 16 deletions meshroom/ui/components/statusBar.py

This file was deleted.

13 changes: 8 additions & 5 deletions meshroom/ui/qml/Controls/StatusBar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ RowLayout {
font.pointSize: 8
text: defaultIcon
ToolTip.text: "Open Messages UI"
// TODO : Open messages UI
// onClicked: statusBar.showMessage("NotImplementedError : Cannot open interface", "error", 2000)
enabled: false // TODO: to remove when implemented
ToolTip.visible: false // TODO: to remove when implemented
onClicked: {
var component = Qt.createComponent("StatusMessages.qml")
var window = component.createObject(root)
window.show()
}
Component.onCompleted: {
statusBarButton.contentItem.color = defaultColor
}
Expand Down Expand Up @@ -99,12 +100,14 @@ RowLayout {

function showMessage(msg, status=undefined, duration=root.interval) {
statusBar.showMessage(msg, status, duration)
// Add message to the message list
_messageController.storeMessage(msg, status)
}

Connections {
target: _messageController
function onMessage(message, color, duration) {
showMessage(message, color, duration)
root.showMessage(message, color, duration)
}
}
}
168 changes: 168 additions & 0 deletions meshroom/ui/qml/Controls/StatusMessages.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

import MaterialIcons 2.2
import Utils 1.0

ApplicationWindow {
id: root
title: "Messages"
width: 500
height: 400
minimumWidth: 350
minimumHeight: 250

SystemPalette { id: systemPalette }

function getColor(status) {
switch (status) {
case "ok": return Colors.green
case "warning": return Colors.orange
case "error": return Colors.red
default: return systemPalette.text
}
}

function getBackgroundColor(status) {
var color = getColor(status)
var alphaValue = status == "info" ? 0.05 : 0.1
return Qt.rgba(color.r, color.g, color.b, alphaValue)
}

function getBorderColor(status) {
var color = getColor(status)
var alphaValue = status == "info" ? 0.2 : 0.3
return Qt.rgba(color.r, color.g, color.b, alphaValue)
}

function getStatusIcon(status) {
switch (status) {
case "ok": return MaterialIcons.check_circle
case "warning": return MaterialIcons.warning
case "error": return MaterialIcons.error
default: return MaterialIcons.info
}
}

header: ToolBar {

background: Rectangle {
implicitWidth: root.width
implicitHeight: 50
color: Qt.darker(systemPalette.base, 1.2)
}

RowLayout {
anchors.fill: parent

Text {
Layout.fillWidth: true
text: "Messages (" + messageListView.count + ")"
font.bold: true
color: Qt.darker(systemPalette.text, 1.2)
}

MaterialToolButton {
ToolTip.text: "Clear the message list"
text: MaterialIcons.clear_all
font.pointSize: 16
palette.base: systemPalette.base
// Text color
Component.onCompleted: {
contentItem.color = Qt.darker(systemPalette.text, 1.2)
}
onClicked: _messageController.clearMessages()
}

MaterialToolButton {
ToolTip.text: "Copy the messages"
text: MaterialIcons.content_copy
font.pointSize: 16
palette.base: systemPalette.base
// Text color
Component.onCompleted: {
contentItem.color = Qt.darker(systemPalette.text, 1.2)
}
onClicked: {
var msgDict = _messageController.getMessagesAsString()
if (msgDict !== '') {
Clipboard.clear()
Clipboard.setText(msgDict)
}
}
}
}
}

Rectangle {
anchors.fill: parent
color: systemPalette.base

ScrollView {
anchors.fill: parent
anchors.margins: 10

ListView {
id: messageListView
model: _messageController.messages
verticalLayoutDirection: ListView.TopToBottom
spacing: 5

delegate: Rectangle {
width: messageListView.width
height: messageLayout.implicitHeight + 16
color: root.getBackgroundColor(modelData.status)
border.color: root.getBorderColor(modelData.status)
border.width: 1
radius: 4

RowLayout {
id: messageLayout
anchors.fill: parent
anchors.margins: 8
spacing: 12

// Icon
Text {
text: root.getStatusIcon(modelData.status)
font.pointSize: 14
color: root.getColor(modelData.status)
Layout.alignment: Qt.AlignVCenter
}

// Text
RowLayout {
Layout.fillWidth: true
spacing: 8

Text {
text: modelData.date
font.pointSize: 8
color: Qt.darker(systemPalette.windowText, 1.5)
Layout.alignment: Qt.AlignLeft
}

Text {
text: modelData.text
wrapMode: Text.WordWrap
Layout.fillWidth: true
color: systemPalette.windowText
font.pointSize: 10
}
}
}
}

// Empty state
Text {
anchors.centerIn: parent
text: "No message to display"
color: Qt.darker(systemPalette.windowText, 1.5)
font.pointSize: 12
visible: messageListView.count === 0
}
}
}
}
}