Skip to content

Implement monitors #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 18, 2024
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ qputenv("QSG_RENDER_LOOP", "basic");
- [ ] Touching sprite block
- [ ] Touching color blocks
- [ ] Pen blocks
- [ ] Monitors
- [x] Monitors
- [ ] Graphics effects (maybe using shaders)
- [ ] Speech and thought bubbles
- [ ] Question text box ("ask and wait" block)
Expand Down
12 changes: 12 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ qt_add_qml_module(scratchcpp-render
OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ScratchCPP/Render
QML_FILES
ProjectPlayer.qml
RESOURCES
internal/ValueMonitor.qml
internal/MonitorSlider.qml
internal/ListMonitor.qml
SOURCES
global.h
projectloader.cpp
Expand All @@ -18,6 +22,14 @@ qt_add_qml_module(scratchcpp-render
stagemodel.h
spritemodel.cpp
spritemodel.h
monitormodel.cpp
monitormodel.h
valuemonitormodel.cpp
valuemonitormodel.h
listmonitormodel.cpp
listmonitormodel.h
listmonitorlistmodel.cpp
listmonitorlistmodel.h
irenderedtarget.h
renderedtarget.cpp
renderedtarget.h
Expand Down
78 changes: 68 additions & 10 deletions src/ProjectPlayer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import QtQuick.Layouts
import QtQuick.Controls
import ScratchCPP.Render

import "internal"

ProjectScene {
property string fileName
property int stageWidth: 480
Expand Down Expand Up @@ -64,6 +66,21 @@ ProjectScene {
else
clones.model.remove(i);
}

onMonitorAdded: (monitorModel)=> monitors.model.append({"monitorModel": monitorModel})

onMonitorRemoved: (monitorModel)=> {
// TODO: Removing the monitor from C++ would probably be faster
let i;

for(i = 0; i < monitors.model.count; i++) {
if(monitors.model.get(i).monitorModel === monitorModel)
break;
}

if(i !== monitors.model.count)
monitors.model.remove(i);
}
}

function start() {
Expand Down Expand Up @@ -120,6 +137,57 @@ ProjectScene {
delegate: renderedSprite
}

SceneMouseArea {
id: sceneMouseArea
anchors.fill: parent
stage: stageTarget
projectLoader: loader
onMouseMoved: (x, y)=> root.handleMouseMove(x, y)
onMousePressed: root.handleMousePress()
onMouseReleased: root.handleMouseRelease()
}

Component {
id: renderedValueMonitor

ValueMonitor {
model: parent.model
scale: root.stageScale
transformOrigin: Item.TopLeft
x: model.x * scale
y: model.y * scale
}
}

Component {
id: renderedListMonitor

ListMonitor {
model: parent.model
scale: root.stageScale
transformOrigin: Item.TopLeft
x: model.x * scale
y: model.y * scale
}
}

Component {
id: renderedMonitor

Loader {
readonly property MonitorModel model: monitorModel
sourceComponent: monitorModel ? (monitorModel.type === MonitorModel.Value ? renderedValueMonitor : renderedListMonitor) : null
active: sourceComponent != null
z: loader.sprites.length + loader.clones.length + 1 // above all sprites
}
}

Repeater {
id: monitors
model: ListModel {}
delegate: renderedMonitor
}

Loader {
anchors.fill: parent
active: showLoadingProgress && loading
Expand Down Expand Up @@ -159,15 +227,5 @@ ProjectScene {
Item { Layout.fillHeight: true }
}
}

SceneMouseArea {
id: sceneMouseArea
anchors.fill: parent
stage: stageTarget
projectLoader: loader
onMouseMoved: (x, y)=> root.handleMouseMove(x, y)
onMousePressed: root.handleMousePress()
onMouseReleased: root.handleMouseRelease()
}
}
}
201 changes: 201 additions & 0 deletions src/internal/ListMonitor.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// SPDX-License-Identifier: LGPL-3.0-or-later

import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import ScratchCPP.Render

// NOTE: All the values here make list monitors look
// like on Scratch, so be careful when doing any changes.
Rectangle {
id: root
property ListMonitorModel model: null

width: model ? (model.width > 0 ? model.width : priv.defaultWidth) : priv.defaultWidth
height: model ? (model.height > 0 ? model.height : priv.defaultHeight) : priv.defaultHeight
color: Qt.rgba(0.9, 0.94, 1, 1)
border.color: Qt.rgba(0.765, 0.8, 0.85, 1)
radius: 5
visible: model ? model.visible : true

QtObject {
id: priv
readonly property int defaultWidth: 102
readonly property int defaultHeight: 203
readonly property color textColor: Qt.rgba(0.34, 0.37, 0.46, 1)
}

Text {
id: header
anchors.left: parent.left
anchors.top: parent.top
width: parent.width
color: priv.textColor
text: model ? model.name : ""
textFormat: Text.PlainText
font.pointSize: 9
font.bold: true
font.family: "Helvetica"
horizontalAlignment: Qt.AlignHCenter
wrapMode: Text.WordWrap
clip: true
padding: 3

Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.leftMargin: 1
anchors.topMargin: 1
anchors.rightMargin: 1
height: root.height
color: "white"
radius: root.radius
z: -1
}
}

Text {
id: emptyText
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
visible: listView.count <= 0
color: priv.textColor
text: qsTr("(empty)")
textFormat: Text.PlainText
font.pointSize: 9
font.family: "Helvetica"
horizontalAlignment: Qt.AlignHCenter
wrapMode: Text.WordWrap
clip: true
padding: 3
}

ListView {
property real oldContentY
readonly property int scrollBarWidth: 15

id: listView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
anchors.bottom: footer.top
anchors.topMargin: 1
clip: true
model: root.model ? root.model.listModel : null
boundsBehavior: Flickable.StopAtBounds

ScrollBar.vertical: ScrollBar {
id: scrollBar
anchors.right: listView.right
anchors.rightMargin: 2
width: 13
visible: scrollBar.size < 1
policy: ScrollBar.AlwaysOn

contentItem: Rectangle {
color: scrollBar.pressed ? Qt.rgba(0.47, 0.47, 0.47, 1) : (hoverHandler.hovered ? Qt.rgba(0.66, 0.66, 0.66, 1) : Qt.rgba(0.76, 0.76, 0.76, 1))

HoverHandler {
id: hoverHandler
}
}

background: null // background is a separate component because contentItem width can't be changed
}

Rectangle {
// Scroll bar background
id: scrollBarBg
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: 1
visible: scrollBar.visible
width: listView.scrollBarWidth
color: Qt.rgba(0.95, 0.95, 0.95, 1)
}

delegate: RowLayout {
width: scrollBar.visible ? listView.width - listView.scrollBarWidth - 6 : listView.width - 6
height: implicitHeight + 2
spacing: 6

Text {
color: priv.textColor
text: index + 1
font.pointSize: 9
font.bold: true
font.family: "Helvetica"
Layout.leftMargin: 6
}

Item {
height: 22
Layout.fillWidth: true

TextEdit {
// TextEdit instead of Text for mouse selection
id: itemText
anchors.left: parent.left
anchors.leftMargin: 3
color: "white"
text: value
textFormat: TextEdit.PlainText
font.pointSize: 9
font.family: "Helvetica"
selectByMouse: true
padding: 2
Layout.rightMargin: 6
}

Rectangle {
anchors.fill: parent
color: root.model ? root.model.color : "green"
border.color: color.darker(1.2)
radius: root.radius
z: -1
}
}
}
}

Text {
id: footer
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
color: priv.textColor
text: qsTr("length %1").arg(listView.count)
textFormat: Text.PlainText
font.pointSize: 9
font.bold: true
font.family: "Helvetica"
horizontalAlignment: Qt.AlignHCenter
wrapMode: Text.WordWrap
clip: true
padding: 3

Rectangle {
anchors.fill: parent
anchors.leftMargin: 1
anchors.bottomMargin: 1
anchors.rightMargin: 1
anchors.topMargin: -5
color: "white"
radius: root.radius
z: -1
}
}

Rectangle {
// for header and footer borders
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
anchors.bottom: footer.top
color: "transparent"
border.color: root.border.color
}
}
Loading