Initial commit
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick3D
|
||||
import QtQuick3D.Helpers
|
||||
|
||||
import QtQuick3D.lightmapviewer
|
||||
import LightmapFile 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
width: 1024
|
||||
height: 768
|
||||
visible: true
|
||||
title: qsTr("Lightmap Viewer")
|
||||
|
||||
id: window
|
||||
|
||||
property var selectedEntry: listView.model.length ? listView.model[0] : null
|
||||
property real imageZoom: 1
|
||||
property real imageCenterX: 0
|
||||
property real imageCenterY: 0
|
||||
|
||||
function isImage(entry) {
|
||||
return entry && entry.kind === "image"
|
||||
}
|
||||
function isMesh(entry) {
|
||||
return entry && entry.kind === "mesh"
|
||||
}
|
||||
|
||||
Dialog {
|
||||
id: sceneMetadataDialog
|
||||
modal: true
|
||||
standardButtons: Dialog.NoButton
|
||||
x: Math.round((window.width - width) / 2)
|
||||
y: Math.round((window.height - height) / 2)
|
||||
visible: false
|
||||
width: 220
|
||||
height: 360
|
||||
|
||||
contentItem: SceneMetadataView {}
|
||||
}
|
||||
|
||||
header: ToolBar {
|
||||
RowLayout {
|
||||
Button {
|
||||
text: qsTr("Open Lightmap...")
|
||||
onClicked: fileDialog.open()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
color: "darkgray"
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Scene Metadata...")
|
||||
onClicked: sceneMetadataDialog.open()
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Zoom: " + window.imageZoom.toFixed(1)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
color: "darkgray"
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: alphaSwitch
|
||||
padding: 0
|
||||
checked: true
|
||||
text: "Alpha"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
color: "darkgray"
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Path: " + LightmapFile.source
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
onAccepted: {
|
||||
LightmapFile.source = selectedFile
|
||||
LightmapFile.loadData()
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequences: [StandardKey.Open]
|
||||
onActivated: {
|
||||
fileDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
SplitView {
|
||||
anchors.fill: parent
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
focus: true
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Up) {
|
||||
listView.currentIndex = Math.max(
|
||||
0, listView.currentIndex - 1)
|
||||
selectedEntry = listView.model[listView.currentIndex]
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
listView.currentIndex = Math.min(
|
||||
listView.model.length - 1,
|
||||
listView.currentIndex + 1)
|
||||
selectedEntry = listView.model[listView.currentIndex]
|
||||
}
|
||||
}
|
||||
|
||||
SplitView {
|
||||
id: leftSplit
|
||||
SplitView.preferredWidth: 220
|
||||
SplitView.minimumWidth: 120
|
||||
orientation: Qt.Vertical
|
||||
|
||||
Item {
|
||||
id: metaArea
|
||||
SplitView.preferredHeight: 120
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 4
|
||||
|
||||
Pane {
|
||||
id: metaPane
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: metadataColumn
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
model: LightmapFile.metadataFor(selectedEntry)
|
||||
delegate: RowLayout {
|
||||
width: metadataColumn.width
|
||||
spacing: 8
|
||||
|
||||
Label {
|
||||
text: (modelData.key ?? "—") + ":"
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
text: modelData.value
|
||||
!== undefined ? String(
|
||||
modelData.value) : "—"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
clip: true
|
||||
spacing: 2
|
||||
highlightMoveVelocity: -1
|
||||
highlightMoveDuration: 1
|
||||
model: LightmapFile.dataList
|
||||
property var sectionExpanded: ({})
|
||||
|
||||
section.property: "owner"
|
||||
section.criteria: ViewSection.FullString
|
||||
section.delegate: Rectangle {
|
||||
width: listView.width
|
||||
height: 26
|
||||
color: Qt.rgba(0, 0, 0, 0.05)
|
||||
radius: 4
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
spacing: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Text {
|
||||
text: (listView.sectionExpanded[section] === false) ? "▸" : "▾"
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Text {
|
||||
text: section
|
||||
font.bold: true
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
listView.sectionExpanded[section]
|
||||
= !(listView.sectionExpanded[section] !== false)
|
||||
listView.sectionExpanded = Object.assign(
|
||||
{}, listView.sectionExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: listView.width
|
||||
|
||||
property bool isExpanded: listView.sectionExpanded[modelData.owner] !== false
|
||||
|
||||
height: isExpanded ? Math.max(
|
||||
24, rowText.implicitHeight + 6) : 0
|
||||
opacity: isExpanded ? 1 : 0
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Text {
|
||||
id: rowText
|
||||
text: modelData.display
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: isExpanded
|
||||
onClicked: {
|
||||
listView.currentIndex = index
|
||||
selectedEntry = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highlight: Rectangle {
|
||||
color: Qt.rgba(76 / 255, 134 / 255, 191 / 255, 0.25)
|
||||
radius: 6
|
||||
anchors.margins: 2
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: rightSplit
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
// These are toggled based on what is currently selected
|
||||
Loader {
|
||||
id: imageLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: ImageViewer {}
|
||||
active: true
|
||||
visible: isImage(selectedEntry)
|
||||
enabled: visible
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: meshLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: MeshViewer {}
|
||||
active: true
|
||||
visible: isMesh(selectedEntry)
|
||||
enabled: visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropArea {
|
||||
id: dropArea
|
||||
anchors.fill: parent
|
||||
onEntered: drag => {
|
||||
drag.accept(Qt.LinkAction)
|
||||
}
|
||||
// Just take first url if several
|
||||
onDropped: drop => {
|
||||
if (drop.hasUrls) {
|
||||
LightmapFile.source = drop.urls[0]
|
||||
LightmapFile.loadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user