Added frontend support for new features
This commit is contained in:
@@ -5,6 +5,10 @@
|
|||||||
<kcfgfile name=""/>
|
<kcfgfile name=""/>
|
||||||
|
|
||||||
<group name="General">
|
<group name="General">
|
||||||
|
<entry name="shader_updated" type="Bool">
|
||||||
|
<label>shaderUpdated</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
<entry name="selectedShaderPath" type="String">
|
<entry name="selectedShaderPath" type="String">
|
||||||
<label>SelectedShader</label>
|
<label>SelectedShader</label>
|
||||||
<default>Shaders6/Ps3menu.frag.qsb</default>
|
<default>Shaders6/Ps3menu.frag.qsb</default>
|
||||||
|
|||||||
@@ -58,14 +58,6 @@ Rectangle
|
|||||||
|
|
||||||
property var pack: wallpaper.configuration.shader_package
|
property var pack: wallpaper.configuration.shader_package
|
||||||
|
|
||||||
// onPackChanged: () =>
|
|
||||||
// {
|
|
||||||
// if(mainItem.ready)
|
|
||||||
// {
|
|
||||||
// shaderPackModel.loadJson(pack)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
id: mainItem
|
id: mainItem
|
||||||
color: "black"
|
color: "black"
|
||||||
|
|
||||||
@@ -108,11 +100,7 @@ Rectangle
|
|||||||
property var bufferB
|
property var bufferB
|
||||||
property var bufferC
|
property var bufferC
|
||||||
property var bufferD
|
property var bufferD
|
||||||
|
|
||||||
// ShaderChannel { id: bufferA; visible: false; anchors.fill: parent }
|
|
||||||
// ShaderChannel { id: bufferB; visible: false; anchors.fill: parent }
|
|
||||||
// ShaderChannel { id: bufferC; visible: false; anchors.fill: parent }
|
|
||||||
// ShaderChannel { id: bufferD; visible: false; anchors.fill: parent }
|
|
||||||
iTime: mainItem.iTime
|
iTime: mainItem.iTime
|
||||||
iMouse: mainItem.iMouse
|
iMouse: mainItem.iMouse
|
||||||
iResolution: mainItem.iResolution
|
iResolution: mainItem.iResolution
|
||||||
@@ -230,35 +218,7 @@ Rectangle
|
|||||||
// Recursive helper function to parse channels
|
// Recursive helper function to parse channels
|
||||||
function parseChannel(channel, json, typeDefault = 2, autodestroy = true)
|
function parseChannel(channel, json, typeDefault = 2, autodestroy = true)
|
||||||
{
|
{
|
||||||
var source = getFilePath(json.source)
|
var component = Qt.createComponent("./ShaderChannel.qml")
|
||||||
|
|
||||||
channel.frameBufferChannel = json.frame_buffer_channel !== undefined ? json.frame_buffer_channel : -1
|
|
||||||
channel.type = json.type !== undefined ? json.type : typeDefault
|
|
||||||
channel.visible = false
|
|
||||||
channel.iMouse = Qt.binding(() => { return mainItem.iMouse; })
|
|
||||||
channel.iTime = Qt.binding(() => { return mainItem.iTime; })
|
|
||||||
channel.iResolutionScale = json.resolution_scale ? json.resolution_scale : 1.0
|
|
||||||
channel.iResolution = Qt.binding(() => { return json.resolution_x ? Qt.vector3d(json.resolution_x, json.resolution_y, 1.0) : Qt.vector3d(mainItem.iResolution.x,mainItem.iResolution.y,1.0); })
|
|
||||||
channel.mouseBias = json.mouse_scale ? json.mouse_scale : 1.0
|
|
||||||
channel.iTimeScale = json.time_scale ? json.time_scale : 1.0
|
|
||||||
channel.iTimeDelta = Qt.binding(() => { return mainItem.iTimeDelta; })
|
|
||||||
channel.width = Qt.binding(() => channel.iResolution.x)
|
|
||||||
channel.height = Qt.binding(() => channel.iResolution.y)
|
|
||||||
|
|
||||||
channel.iChannelTime = Qt.binding(() => {
|
|
||||||
return [
|
|
||||||
mainItem.iTime * channel.iTimeScale,
|
|
||||||
mainItem.iTime * channel.iTimeScale,
|
|
||||||
mainItem.iTime * channel.iTimeScale,
|
|
||||||
mainItem.iTime * channel.iTimeScale
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
channel.iFrameRate = Qt.binding(() => { return mainItem.iFrameRate; })
|
|
||||||
channel.iFrame = mainItem.iFrame
|
|
||||||
channel.invert = json.invert ? json.invert : false
|
|
||||||
|
|
||||||
channel.source = source
|
|
||||||
|
|
||||||
if (json.channel0)
|
if (json.channel0)
|
||||||
{
|
{
|
||||||
@@ -271,9 +231,8 @@ Rectangle
|
|||||||
}
|
}
|
||||||
else if(typeof json.channel0 === "object")
|
else if(typeof json.channel0 === "object")
|
||||||
{
|
{
|
||||||
var component = Qt.createComponent("./ShaderChannel.qml")
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
if (component.status === Component.Ready) {
|
|
||||||
channel.iChannel0 = component.createObject(mainItem, { })
|
channel.iChannel0 = component.createObject(mainItem, { })
|
||||||
parseChannel(channel.iChannel0, json.channel0)
|
parseChannel(channel.iChannel0, json.channel0)
|
||||||
}
|
}
|
||||||
@@ -293,9 +252,8 @@ Rectangle
|
|||||||
}
|
}
|
||||||
else if(typeof json.channel1 === "object")
|
else if(typeof json.channel1 === "object")
|
||||||
{
|
{
|
||||||
var component = Qt.createComponent("./ShaderChannel.qml")
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
if (component.status === Component.Ready) {
|
|
||||||
channel.iChannel1 = component.createObject(mainItem, { })
|
channel.iChannel1 = component.createObject(mainItem, { })
|
||||||
parseChannel(channel.iChannel1, json.channel1)
|
parseChannel(channel.iChannel1, json.channel1)
|
||||||
}
|
}
|
||||||
@@ -315,9 +273,8 @@ Rectangle
|
|||||||
}
|
}
|
||||||
else if(typeof json.channel2 === "object")
|
else if(typeof json.channel2 === "object")
|
||||||
{
|
{
|
||||||
var component = Qt.createComponent("./ShaderChannel.qml")
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
if (component.status === Component.Ready) {
|
|
||||||
channel.iChannel2 = component.createObject(mainItem, { })
|
channel.iChannel2 = component.createObject(mainItem, { })
|
||||||
parseChannel(channel.iChannel2, json.channel2)
|
parseChannel(channel.iChannel2, json.channel2)
|
||||||
}
|
}
|
||||||
@@ -337,9 +294,8 @@ Rectangle
|
|||||||
}
|
}
|
||||||
else if(typeof json.channel3 === "object")
|
else if(typeof json.channel3 === "object")
|
||||||
{
|
{
|
||||||
var component = Qt.createComponent("./ShaderChannel.qml")
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
if (component.status === Component.Ready) {
|
|
||||||
channel.iChannel3 = component.createObject(mainItem, { })
|
channel.iChannel3 = component.createObject(mainItem, { })
|
||||||
parseChannel(channel.iChannel3, json.channel3)
|
parseChannel(channel.iChannel3, json.channel3)
|
||||||
}
|
}
|
||||||
@@ -348,6 +304,37 @@ Rectangle
|
|||||||
console.log('Uknown channel type 3 ' + typeof json.channel3)
|
console.log('Uknown channel type 3 ' + typeof json.channel3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.frameBufferChannel = json.frame_buffer_channel !== undefined ? json.frame_buffer_channel : -1
|
||||||
|
channel.type = json.type !== undefined ? json.type : typeDefault
|
||||||
|
channel.visible = false
|
||||||
|
channel.iMouse = Qt.binding(() => { return mainItem.iMouse; })
|
||||||
|
channel.iTime = Qt.binding(() => { return mainItem.iTime; })
|
||||||
|
channel.iResolutionScale = json.resolution_scale ? json.resolution_scale : 1.0
|
||||||
|
channel.iResolution = Qt.binding(() => { return json.resolution_x ? Qt.vector3d(json.resolution_x, json.resolution_y, 1.0) : Qt.vector3d(mainItem.iResolution.x,mainItem.iResolution.y,1.0); })
|
||||||
|
channel.mouseBias = json.mouse_scale ? json.mouse_scale : 1.0
|
||||||
|
channel.iTimeScale = json.time_scale ? json.time_scale : 1.0
|
||||||
|
channel.iTimeDelta = Qt.binding(() => { return mainItem.iTimeDelta; })
|
||||||
|
channel.width = Qt.binding(() => channel.iResolution.x)
|
||||||
|
channel.height = Qt.binding(() => channel.iResolution.y)
|
||||||
|
channel.materialTexture = json.materialTexture !== undefined ? getFilePath(json.materialTexture) : ""
|
||||||
|
channel.materialShader = json.materialShader !== undefined ? getFilePath(json.materialShader) : ""
|
||||||
|
|
||||||
|
channel.iChannelTime = Qt.binding(() => {
|
||||||
|
return [
|
||||||
|
mainItem.iTime * channel.iTimeScale,
|
||||||
|
mainItem.iTime * channel.iTimeScale,
|
||||||
|
mainItem.iTime * channel.iTimeScale,
|
||||||
|
mainItem.iTime * channel.iTimeScale
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
channel.iFrameRate = Qt.binding(() => { return mainItem.iFrameRate; })
|
||||||
|
channel.iFrame = mainItem.iFrame
|
||||||
|
channel.invert = json.invert ? json.invert : false
|
||||||
|
|
||||||
|
var source = getFilePath(json.source)
|
||||||
|
channel.source = source
|
||||||
|
|
||||||
if(autodestroy)
|
if(autodestroy)
|
||||||
data.channels.push(channel)
|
data.channels.push(channel)
|
||||||
}
|
}
|
||||||
@@ -364,11 +351,13 @@ Rectangle
|
|||||||
|
|
||||||
var component = Qt.createComponent("./ShaderChannel.qml")
|
var component = Qt.createComponent("./ShaderChannel.qml")
|
||||||
|
|
||||||
if (component.status === Component.Ready) {
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
channelOutput.bufferA = component.createObject(channelOutput, { visible: false })
|
channelOutput.bufferA = component.createObject(channelOutput, { visible: false })
|
||||||
channelOutput.bufferB = component.createObject(channelOutput, { visible: false })
|
channelOutput.bufferB = component.createObject(channelOutput, { visible: false })
|
||||||
channelOutput.bufferC = component.createObject(channelOutput, { visible: false })
|
channelOutput.bufferC = component.createObject(channelOutput, { visible: false })
|
||||||
channelOutput.bufferD = component.createObject(channelOutput, { visible: false })
|
channelOutput.bufferD = component.createObject(channelOutput, { visible: false })
|
||||||
|
|
||||||
data.buffers.set("{bufferA}", channelOutput.bufferA)
|
data.buffers.set("{bufferA}", channelOutput.bufferA)
|
||||||
data.buffers.set("{bufferB}", channelOutput.bufferB)
|
data.buffers.set("{bufferB}", channelOutput.bufferB)
|
||||||
data.buffers.set("{bufferC}", channelOutput.bufferC)
|
data.buffers.set("{bufferC}", channelOutput.bufferC)
|
||||||
@@ -401,11 +390,11 @@ Rectangle
|
|||||||
// Generate a new ShaderEffectSource for the requested buffer
|
// Generate a new ShaderEffectSource for the requested buffer
|
||||||
function createBufferAssociation(buffer)
|
function createBufferAssociation(buffer)
|
||||||
{
|
{
|
||||||
|
|
||||||
var component = Qt.createComponent('./ShaderBuffer.qml')
|
var component = Qt.createComponent('./ShaderBuffer.qml')
|
||||||
var result
|
var result
|
||||||
|
|
||||||
if (component.status === Component.Ready) {
|
if (component.status === Component.Ready)
|
||||||
|
{
|
||||||
result = component.createObject(mainItem, {
|
result = component.createObject(mainItem, {
|
||||||
x:0,
|
x:0,
|
||||||
y:0,
|
y:0,
|
||||||
|
|||||||
434
package/contents/ui/PexelsImageHub.qml
Normal file
434
package/contents/ui/PexelsImageHub.qml
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import Komplex.Pexels.Image as Pexels
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: mainItem
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Pexels.SearchModel
|
||||||
|
{
|
||||||
|
id: searchModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillHeight: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
TextField
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: searchField
|
||||||
|
placeholderText: "Search"
|
||||||
|
onEditingFinished: mainItem.updateSearch()
|
||||||
|
Keys.onPressed: (event) =>
|
||||||
|
{
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
|
||||||
|
{
|
||||||
|
searchField.focus = false; // Unfocus the TextField
|
||||||
|
event.accepted = true; // Prevent further propagation of the key event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
|
||||||
|
icon.name: "search-symbolic"
|
||||||
|
|
||||||
|
onClicked: mainItem.updateSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: highlight
|
||||||
|
Rectangle {
|
||||||
|
width: view.cellWidth; height: view.cellHeight
|
||||||
|
color: palette.highlight; radius: 5
|
||||||
|
x: view.currentItem.x
|
||||||
|
y: view.currentItem.y
|
||||||
|
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: palette.base
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
GridView
|
||||||
|
{
|
||||||
|
// The standard size
|
||||||
|
property int idealCellHeight: 300
|
||||||
|
property int idealCellWidth: 300
|
||||||
|
cellWidth: width / Math.floor(width / idealCellWidth)
|
||||||
|
cellHeight: idealCellHeight
|
||||||
|
|
||||||
|
id: view
|
||||||
|
|
||||||
|
model: searchModel
|
||||||
|
highlight: highlight
|
||||||
|
highlightFollowsCurrentItem: false
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
delegate: Column
|
||||||
|
{
|
||||||
|
property int itemIndex: index
|
||||||
|
property int originalHeight: imageHeight
|
||||||
|
property int originalWidth: imageWidth
|
||||||
|
property int imageId: id
|
||||||
|
property string author: photographer
|
||||||
|
property string authorUrl: photographerUrl
|
||||||
|
property string imageUrl: original
|
||||||
|
property string thumbnailUrl: thumbnail
|
||||||
|
property string altText: alt
|
||||||
|
property string largeThumbnail: large
|
||||||
|
|
||||||
|
id: entry
|
||||||
|
|
||||||
|
leftPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
topPadding: 10
|
||||||
|
rightPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
bottomPadding: 10
|
||||||
|
width: view.cellWidth
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
width: 280
|
||||||
|
height: 200
|
||||||
|
id: thumbnailImage
|
||||||
|
source: thumbnail
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
view.currentIndex = parent.parent.itemIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: thumbnailImage.status === Image.Loading
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 64
|
||||||
|
Layout.preferredWidth: 64
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
property string externalLink: photographerUrl
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 2
|
||||||
|
text: "<h3>" + photographer + "</h3>"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 280
|
||||||
|
color: palette.link
|
||||||
|
font.bold: true
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
Qt.openUrlExternally(parent.externalLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
leftPadding: 8
|
||||||
|
rightPadding: 8
|
||||||
|
text: qsTr(alt)
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: 280
|
||||||
|
color: palette.text
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
maximumLineCount: 2
|
||||||
|
font.italic: true
|
||||||
|
}
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
visible: parent.itemIndex === view.currentIndex
|
||||||
|
width: 280
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.topMargin: 4
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
icon.name: "emblem-downloads"
|
||||||
|
onClicked: {
|
||||||
|
downloadDialog.imageHeight = entry.originalHeight
|
||||||
|
downloadDialog.imageWidth = entry.originalWidth
|
||||||
|
downloadDialog.photographer = entry.author
|
||||||
|
downloadDialog.photographerUrl = entry.authorUrl
|
||||||
|
downloadDialog.alt = entry.altText
|
||||||
|
downloadDialog.thumbnail = entry.largeThumbnail
|
||||||
|
downloadDialog.imageUrl = entry.imageUrl
|
||||||
|
downloadDialog.id = entry.imageId
|
||||||
|
downloadDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
populate: Transition
|
||||||
|
{
|
||||||
|
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Previous"
|
||||||
|
enabled: searchModel.previousPage !== ""
|
||||||
|
onClicked: searchModel.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
visible: searchModel.totalResults > 0
|
||||||
|
color: palette.text
|
||||||
|
text: ((searchModel.resultsPerPage * searchModel.currentPage) - searchModel.resultsPerPage + 1) + "-" + (searchModel.resultsPerPage * searchModel.currentPage) + " of " + searchModel.totalResults
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Page " + searchModel.currentPage + " of " + Math.ceil(searchModel.totalResults / searchModel.resultsPerPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.link
|
||||||
|
text: "<a href=\"https://www.pexels.com\">Photos provided by Pexels</a>"
|
||||||
|
font.bold: true
|
||||||
|
|
||||||
|
onLinkActivated: (link) => Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Next"
|
||||||
|
enabled: searchModel.nextPage !== ""
|
||||||
|
onClicked: searchModel.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: searchModel.status === Pexels.SearchModel.Searching
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 128
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
property string photographer
|
||||||
|
property string photographerUrl
|
||||||
|
property string imageUrl
|
||||||
|
property string thumbnail
|
||||||
|
property string alt
|
||||||
|
property int imageHeight
|
||||||
|
property int imageWidth
|
||||||
|
property int id
|
||||||
|
|
||||||
|
id: downloadDialog
|
||||||
|
modal: Qt.WindowModal
|
||||||
|
width: 600
|
||||||
|
height: 420
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
property string externalLink: downloadDialog.photographerUrl
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 2
|
||||||
|
text: "<h3>" + downloadDialog.photographer + "</h3>"
|
||||||
|
width: 280
|
||||||
|
color: palette.link
|
||||||
|
font.bold: true
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
Qt.openUrlExternally(parent.externalLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
source: downloadDialog.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
leftPadding: 8
|
||||||
|
rightPadding: 8
|
||||||
|
text: qsTr(downloadDialog.alt)
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: 280
|
||||||
|
color: palette.text
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
maximumLineCount: 4
|
||||||
|
font.italic: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Download (" + downloadDialog.imageWidth + "x" + downloadDialog.imageHeight + ")"
|
||||||
|
icon.name: "image-symbolic"
|
||||||
|
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
downloadDialog.close();
|
||||||
|
progressDialog.thumbnail = downloadDialog.thumbnail
|
||||||
|
progressDialog.photographer = downloadDialog.photographer
|
||||||
|
progressDialog.open()
|
||||||
|
searchModel.download(downloadDialog.imageUrl, downloadDialog.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
property string photographer
|
||||||
|
property string thumbnail
|
||||||
|
|
||||||
|
modal: Qt.WindowModal
|
||||||
|
width: 600
|
||||||
|
height: 420
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
id: progressDialog
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
source: downloadDialog.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: "Downloading Photo..."
|
||||||
|
color: palette.text
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
value: searchModel.downloadProgress
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: searchModel
|
||||||
|
function onDownloadFinished()
|
||||||
|
{
|
||||||
|
progressDialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSearch()
|
||||||
|
{
|
||||||
|
console.log(searchField.text)
|
||||||
|
searchModel.query = searchField.text
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
587
package/contents/ui/PexelsVideoHub.qml
Normal file
587
package/contents/ui/PexelsVideoHub.qml
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtMultimedia
|
||||||
|
|
||||||
|
import Komplex.Pexels.Video as Pexels
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
property alias selectedFile: searchModel.lastSavedFile
|
||||||
|
|
||||||
|
id: mainItem
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Pexels.SearchModel
|
||||||
|
{
|
||||||
|
id: searchModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillHeight: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
TextField
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: searchField
|
||||||
|
placeholderText: "Search"
|
||||||
|
onEditingFinished: mainItem.updateSearch()
|
||||||
|
Keys.onPressed: (event) =>
|
||||||
|
{
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
|
||||||
|
{
|
||||||
|
searchField.focus = false; // Unfocus the TextField
|
||||||
|
event.accepted = true; // Prevent further propagation of the key event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
|
||||||
|
icon.name: "search-symbolic"
|
||||||
|
|
||||||
|
onClicked: mainItem.updateSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: highlight
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
width: view.cellWidth; height: view.cellHeight
|
||||||
|
color: palette.highlight; radius: 5
|
||||||
|
x: view.currentItem.x
|
||||||
|
y: view.currentItem.y
|
||||||
|
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: palette.base
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
GridView
|
||||||
|
{
|
||||||
|
// The standard size
|
||||||
|
property int idealCellHeight: 220
|
||||||
|
property int idealCellWidth: 250
|
||||||
|
cellWidth: width / Math.floor(width / idealCellWidth)
|
||||||
|
cellHeight: idealCellHeight
|
||||||
|
|
||||||
|
id: view
|
||||||
|
|
||||||
|
model: searchModel
|
||||||
|
highlight: highlight
|
||||||
|
highlightFollowsCurrentItem: false
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
delegate: Column
|
||||||
|
{
|
||||||
|
property int itemIndex: index
|
||||||
|
property int originalHeight: videoHeight
|
||||||
|
property int originalWidth: videoWidth
|
||||||
|
property int videoId: id
|
||||||
|
property string author: user
|
||||||
|
property string authorUrl: userUrl
|
||||||
|
property string videoUrl: videoUrl
|
||||||
|
property string thumbnailUrl: thumbnail
|
||||||
|
|
||||||
|
id: entry
|
||||||
|
|
||||||
|
leftPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
topPadding: 10
|
||||||
|
rightPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
bottomPadding: 10
|
||||||
|
width: view.cellWidth
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
width: 250
|
||||||
|
height: 140
|
||||||
|
id: thumbnailImage
|
||||||
|
source: thumbnail
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: thumbnailImage.status === Image.Loading
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 64
|
||||||
|
Layout.preferredWidth: 64
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) =>
|
||||||
|
{
|
||||||
|
view.currentIndex = parent.parent.itemIndex
|
||||||
|
searchModel.currentIndex = view.currentIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
property string externalLink: authorUrl
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 2
|
||||||
|
text: "<h3>" + author + "</h3>"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 280
|
||||||
|
color: palette.link
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) =>
|
||||||
|
{
|
||||||
|
Qt.openUrlExternally(parent.externalLink)
|
||||||
|
}
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
visible: parent.itemIndex === view.currentIndex
|
||||||
|
width: thumbnailImage.width
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.topMargin: 4
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.fillWidth: true
|
||||||
|
icon.name: "emblem-downloads"
|
||||||
|
text: qsTr("Preview & Download")
|
||||||
|
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
downloadDialog.user = entry.author
|
||||||
|
downloadDialog.userUrl = entry.authorUrl
|
||||||
|
downloadDialog.thumbnail = entry.thumbnailUrl
|
||||||
|
downloadDialog.id = entry.videoId
|
||||||
|
downloadDialog.open()
|
||||||
|
searchModel.videoModel.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
populate: Transition
|
||||||
|
{
|
||||||
|
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Previous"
|
||||||
|
enabled: searchModel.previousPage !== ""
|
||||||
|
onClicked: searchModel.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
visible: searchModel.totalResults > 0
|
||||||
|
color: palette.text
|
||||||
|
text: ((searchModel.resultsPerPage * searchModel.currentPage) - searchModel.resultsPerPage + 1) + "-" + (searchModel.resultsPerPage * searchModel.currentPage) + " of " + searchModel.totalResults
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Page " + searchModel.currentPage + " of " + Math.ceil(searchModel.totalResults / searchModel.resultsPerPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
text: "Videos provided by Pexels"
|
||||||
|
font.bold: true
|
||||||
|
|
||||||
|
onLinkActivated: (link) => Qt.openUrlExternally(link)
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) =>
|
||||||
|
{
|
||||||
|
Qt.openUrlExternally("https://www.pexels.com")
|
||||||
|
}
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Next"
|
||||||
|
enabled: searchModel.nextPage !== ""
|
||||||
|
onClicked: searchModel.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: searchModel.status === Pexels.SearchModel.Searching
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 128
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
property string user
|
||||||
|
property string userUrl
|
||||||
|
property string thumbnail
|
||||||
|
property string preview
|
||||||
|
property int id
|
||||||
|
|
||||||
|
id: downloadDialog
|
||||||
|
modal: Qt.WindowModal
|
||||||
|
width: 600
|
||||||
|
height: 440
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
property string externalLink: downloadDialog.userUrl
|
||||||
|
|
||||||
|
elide: Text.ElideRight
|
||||||
|
text: "<h3>" + downloadDialog.user + "</h3>"
|
||||||
|
width: 280
|
||||||
|
color: palette.link
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) =>
|
||||||
|
{
|
||||||
|
Qt.openUrlExternally(parent.externalLink)
|
||||||
|
}
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 300
|
||||||
|
color: "black"
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
VideoOutput
|
||||||
|
{
|
||||||
|
property alias duration: mediaPlayer.duration
|
||||||
|
property alias mediaSource: mediaPlayer.source
|
||||||
|
property alias metaData: mediaPlayer.metaData
|
||||||
|
property alias playbackRate: mediaPlayer.playbackRate
|
||||||
|
property alias position: mediaPlayer.position
|
||||||
|
property alias seekable: mediaPlayer.seekable
|
||||||
|
property alias volume: audioOutput.volume
|
||||||
|
|
||||||
|
signal sizeChanged
|
||||||
|
signal fatalError
|
||||||
|
|
||||||
|
id: videoOutput
|
||||||
|
|
||||||
|
visible: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.preferredHeight: 281
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
fillMode: VideoOutput.PreserveAspectCrop
|
||||||
|
smooth: true
|
||||||
|
|
||||||
|
onHeightChanged: this.sizeChanged()
|
||||||
|
|
||||||
|
MediaPlayer
|
||||||
|
{
|
||||||
|
id: mediaPlayer
|
||||||
|
videoOutput: videoOutput
|
||||||
|
source: Qt.resolvedUrl(downloadSelector.currentValue ? downloadSelector.currentValue : "")
|
||||||
|
|
||||||
|
audioOutput: AudioOutput
|
||||||
|
{
|
||||||
|
id: audioOutput
|
||||||
|
volume: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
onErrorOccurred: function(error, errorString)
|
||||||
|
{
|
||||||
|
if (MediaPlayer.NoError !== error)
|
||||||
|
{
|
||||||
|
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||||
|
videoOutput.fatalError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSourceChanged:
|
||||||
|
{
|
||||||
|
if(mediaPlayer.source !== "")
|
||||||
|
mediaPlayer.play()
|
||||||
|
else
|
||||||
|
mediaPlayer.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() { mediaPlayer.play() }
|
||||||
|
function stop() { mediaPlayer.stop() }
|
||||||
|
function seek(position) { mediaPlayer.setPosition(position); }
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
visible: !mediaPlayer.playing
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
fillMode: Image.PreserveAspectFill
|
||||||
|
source: downloadDialog.thumbnail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 18
|
||||||
|
color: palette.alternateBase
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
from: 0
|
||||||
|
to: mediaPlayer.duration
|
||||||
|
value: mediaPlayer.position
|
||||||
|
}
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 18
|
||||||
|
Layout.preferredWidth: 18
|
||||||
|
icon.name: mediaPlayer.playing ? "stop-symbolic" : "play-symbolic"
|
||||||
|
icon.height: 16
|
||||||
|
icon.width: 16
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
if(mediaPlayer.playing)
|
||||||
|
mediaPlayer.stop()
|
||||||
|
else
|
||||||
|
mediaPlayer.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: qsTr("Download Options")
|
||||||
|
color: palette.text
|
||||||
|
font.bold: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
verticalAlignment: Text.AlignBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: downloadSelector.height
|
||||||
|
ComboBox
|
||||||
|
{
|
||||||
|
id: downloadSelector
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: searchModel.videoModel
|
||||||
|
textRole: "text"
|
||||||
|
valueRole: "url"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
enabled: downloadSelector.currentIndex >= 0
|
||||||
|
Layout.preferredHeight: downloadSelector.height
|
||||||
|
Layout.preferredWidth: downloadSelector.height
|
||||||
|
icon.name: "image-symbolic"
|
||||||
|
|
||||||
|
id: downloadButton
|
||||||
|
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
downloadDialog.close();
|
||||||
|
progressDialog.thumbnail = downloadDialog.thumbnail
|
||||||
|
progressDialog.author = downloadDialog.user
|
||||||
|
progressDialog.open()
|
||||||
|
searchModel.videoModel.download(downloadSelector.currentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: searchModel.videoModel
|
||||||
|
function onStatusChanged()
|
||||||
|
{
|
||||||
|
if(searchModel.videoModel.status === 0)
|
||||||
|
downloadSelector.currentIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: () =>
|
||||||
|
{
|
||||||
|
mediaPlayer.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: searchModel.videoModel.status === 1
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 128
|
||||||
|
Layout.preferredWidth: 128
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
property string author
|
||||||
|
property string thumbnail
|
||||||
|
|
||||||
|
modal: Qt.WindowModal
|
||||||
|
width: 600
|
||||||
|
height: 420
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
id: progressDialog
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
source: downloadDialog.thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
text: "Downloading Video..."
|
||||||
|
color: palette.text
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
value: searchModel.videoModel.downloadProgress
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: searchModel.videoModel
|
||||||
|
function onDownloadFinished()
|
||||||
|
{
|
||||||
|
progressDialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSearch()
|
||||||
|
{
|
||||||
|
console.log(searchField.text)
|
||||||
|
searchModel.query = searchField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,8 @@ Item
|
|||||||
VideoChannel,
|
VideoChannel,
|
||||||
ShaderChannel,
|
ShaderChannel,
|
||||||
CubeMapChannel,
|
CubeMapChannel,
|
||||||
AudioChannel
|
AudioChannel,
|
||||||
|
SceneChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
property int type: ShaderChannel.Type.ImageChannel
|
property int type: ShaderChannel.Type.ImageChannel
|
||||||
@@ -70,6 +71,9 @@ Item
|
|||||||
property real iTimeScale: 1 // This is used to scale the time for the shader, allowing for slow motion or fast forward effects per channel
|
property real iTimeScale: 1 // This is used to scale the time for the shader, allowing for slow motion or fast forward effects per channel
|
||||||
property int frameBufferChannel: -1
|
property int frameBufferChannel: -1
|
||||||
property bool blending: false
|
property bool blending: false
|
||||||
|
property string materialTexture:""
|
||||||
|
property string materialShader:""
|
||||||
|
property var windowModel
|
||||||
|
|
||||||
// bind to ShaderEffectSource.live to prevent data being updated causing a refresh between intended frames. I think this may be why
|
// bind to ShaderEffectSource.live to prevent data being updated causing a refresh between intended frames. I think this may be why
|
||||||
// the shaders are using so many resources. This is likely to cause issues of its own since we have no way of knowing the progress
|
// the shaders are using so many resources. This is likely to cause issues of its own since we have no way of knowing the progress
|
||||||
@@ -80,8 +84,20 @@ Item
|
|||||||
// but god damn does it feel hacky. Try to find a better way to actually limit framerate
|
// but god damn does it feel hacky. Try to find a better way to actually limit framerate
|
||||||
onIFrameChanged: () =>
|
onIFrameChanged: () =>
|
||||||
{
|
{
|
||||||
active = true;
|
// this method of frame limiting breaks video playback
|
||||||
active = false;
|
// even when the video is the source of an item being limited
|
||||||
|
// in this way
|
||||||
|
|
||||||
|
// if(type === ShaderChannel.ShaderChannel)
|
||||||
|
// {
|
||||||
|
// active = true;
|
||||||
|
// active = false;
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if(active === false)
|
||||||
|
// active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool invert
|
property bool invert
|
||||||
@@ -162,10 +178,14 @@ Item
|
|||||||
PropertyChanges
|
PropertyChanges
|
||||||
{
|
{
|
||||||
loader.sourceComponent: channelAudio
|
loader.sourceComponent: channelAudio
|
||||||
|
}
|
||||||
// loader.width: 512
|
},
|
||||||
// loader.height: 2
|
State
|
||||||
// loader.and
|
{
|
||||||
|
when: channel.type === ShaderChannel.Type.SceneChannel
|
||||||
|
PropertyChanges
|
||||||
|
{
|
||||||
|
loader.sourceComponent: Qt.createComponent(channel.source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -206,35 +226,42 @@ Item
|
|||||||
Component
|
Component
|
||||||
{
|
{
|
||||||
id: channelVideo
|
id: channelVideo
|
||||||
|
Rectangle
|
||||||
VideoOutput
|
|
||||||
{
|
{
|
||||||
property alias duration: mediaPlayer.duration
|
|
||||||
property alias mediaSource: mediaPlayer.source
|
|
||||||
property alias metaData: mediaPlayer.metaData
|
|
||||||
property alias playbackRate: mediaPlayer.playbackRate
|
|
||||||
property alias position: mediaPlayer.position
|
|
||||||
property alias seekable: mediaPlayer.seekable
|
|
||||||
property alias volume: audioOutput.volume
|
|
||||||
|
|
||||||
signal sizeChanged
|
|
||||||
signal fatalError
|
|
||||||
|
|
||||||
id: videoOutput
|
|
||||||
|
|
||||||
visible: true
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
fillMode: VideoOutput.PreserveAspectCrop
|
color: "black"
|
||||||
smooth: true
|
|
||||||
|
|
||||||
onHeightChanged: this.sizeChanged()
|
VideoOutput
|
||||||
|
{
|
||||||
|
property alias duration: mediaPlayer.duration
|
||||||
|
property alias mediaSource: mediaPlayer.source
|
||||||
|
property alias metaData: mediaPlayer.metaData
|
||||||
|
property alias playbackRate: mediaPlayer.playbackRate
|
||||||
|
property alias position: mediaPlayer.position
|
||||||
|
property alias seekable: mediaPlayer.seekable
|
||||||
|
property alias volume: audioOutput.volume
|
||||||
|
property bool loaded: false
|
||||||
|
|
||||||
MediaPlayer
|
signal sizeChanged
|
||||||
|
signal fatalError
|
||||||
|
|
||||||
|
id: videoComponent
|
||||||
|
|
||||||
|
visible: true
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: VideoOutput.PreserveAspectCrop
|
||||||
|
smooth: true
|
||||||
|
|
||||||
|
onHeightChanged: this.sizeChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPlayer
|
||||||
{
|
{
|
||||||
id: mediaPlayer
|
id: mediaPlayer
|
||||||
videoOutput: videoOutput
|
videoOutput: videoComponent
|
||||||
loops: MediaPlayer.Infinite
|
loops: MediaPlayer.Infinite
|
||||||
source: Qt.resolvedUrl(channel.source)
|
source: Qt.resolvedUrl(channel.source)
|
||||||
|
playbackRate: channel.iTimeScale >= 0.01 ? channel.iTimeScale : 0.01
|
||||||
|
|
||||||
audioOutput: AudioOutput
|
audioOutput: AudioOutput
|
||||||
{
|
{
|
||||||
@@ -242,22 +269,96 @@ Item
|
|||||||
volume: 0
|
volume: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
onErrorOccurred: function(error, errorString)
|
onErrorOccurred: (error, errorString) =>
|
||||||
{
|
{
|
||||||
if (MediaPlayer.NoError !== error)
|
if (MediaPlayer.NoError !== error)
|
||||||
{
|
{
|
||||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||||
videoOutput.fatalError()
|
videoComponent.fatalError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSourceChanged:
|
onSourceChanged:
|
||||||
{
|
{
|
||||||
if(mediaPlayer.source != "")
|
if(!videoComponent.loaded)
|
||||||
mediaPlayer.play()
|
return;
|
||||||
else
|
delayedStartTimer.start()
|
||||||
mediaPlayer.stop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMediaStatusChanged:
|
||||||
|
{
|
||||||
|
switch(mediaStatus)
|
||||||
|
{
|
||||||
|
case MediaPlayer.NoMedia:
|
||||||
|
console.log("No media loaded")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.LoadingMedia:
|
||||||
|
console.log("Video loading")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.LoadedMedia:
|
||||||
|
console.log("Video Loaded")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.BufferingMedia:
|
||||||
|
console.log("Video buffering")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.StalledMedia:
|
||||||
|
console.log("Video stalled")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.BufferedMedia:
|
||||||
|
console.log("Video buffered")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.EndOfMedia:
|
||||||
|
console.log("Video EOF")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.InvalidMedia:
|
||||||
|
console.log("Video invalid")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlaybackStateChanged:
|
||||||
|
{
|
||||||
|
switch(playbackState)
|
||||||
|
{
|
||||||
|
case MediaPlayer.PlayingState:
|
||||||
|
console.log("Video playback started")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.PausedState:
|
||||||
|
console.log("Video playback paused")
|
||||||
|
break;
|
||||||
|
case MediaPlayer.StoppedState:
|
||||||
|
console.log("Video playback stopped")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted:
|
||||||
|
{
|
||||||
|
videoComponent.loaded = true
|
||||||
|
delayedStartTimer.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoStart()
|
||||||
|
{
|
||||||
|
if(mediaPlayer.source !== "" && mediaPlayer.source !== undefined)
|
||||||
|
{
|
||||||
|
console.log("Starting playback of " + mediaPlayer.source)
|
||||||
|
mediaPlayer.play()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log("Stopping playback")
|
||||||
|
mediaPlayer.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer
|
||||||
|
{
|
||||||
|
id: delayedStartTimer
|
||||||
|
interval: 500
|
||||||
|
repeat: false
|
||||||
|
onTriggered: mediaPlayer.autoStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() { mediaPlayer.play() }
|
function start() { mediaPlayer.play() }
|
||||||
@@ -395,14 +496,6 @@ Item
|
|||||||
|
|
||||||
blending: channel.blending
|
blending: channel.blending
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShaderEffectSource
|
|
||||||
// {
|
|
||||||
// anchors.fill: parent
|
|
||||||
// sourceItem: channelShaderOutput
|
|
||||||
// hideSource: true
|
|
||||||
// visible: true
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,4 +623,129 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Scene is directly loaded, no comp needed
|
||||||
|
|
||||||
|
// 3D Model
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: modelComponent
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
id: channelModelContent
|
||||||
|
|
||||||
|
// recursive frame buffer
|
||||||
|
ShaderEffectSource
|
||||||
|
{
|
||||||
|
id: frameBufferSource
|
||||||
|
sourceItem: channel.frameBufferChannel === -1 ? null : channelModelContent
|
||||||
|
sourceRect: Qt.rect(0,0, channelModelContent.width, channelModelContent.height)
|
||||||
|
wrapMode: ShaderEffectSource.ClampToEdge
|
||||||
|
live: channel.active
|
||||||
|
mipmap: true
|
||||||
|
recursive: true
|
||||||
|
textureSize: Qt.size(channelModelContent.width, channelModelContent.height)
|
||||||
|
visible: false
|
||||||
|
textureMirroring: ShaderEffectSource.NoMirroring
|
||||||
|
width: channel.iResolution.x
|
||||||
|
height: channel.iResolution.y
|
||||||
|
}
|
||||||
|
|
||||||
|
View3D
|
||||||
|
{
|
||||||
|
id: view3d
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
property real lastX: 0
|
||||||
|
property real lastY: 0
|
||||||
|
property bool mousePressed: false
|
||||||
|
property real yaw: 0
|
||||||
|
property real pitch: 0
|
||||||
|
|
||||||
|
environment: SceneEnvironment
|
||||||
|
{
|
||||||
|
backgroundMode: SceneEnvironment.SkyBoxCubeMap
|
||||||
|
skyBoxCubeMap: CubeMapTexture
|
||||||
|
{
|
||||||
|
source: channel.source !== "" ? Qt.resolvedUrl(channel.source) + "/%p.jpg" : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
camera: PerspectiveCamera
|
||||||
|
{
|
||||||
|
id: camera
|
||||||
|
position: Qt.vector3d(0, 0, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCamera()
|
||||||
|
{
|
||||||
|
yaw -= (data.iMouse.x - lastX) * 0.5
|
||||||
|
pitch -= (data.iMouse.y - lastY) * -0.5
|
||||||
|
pitch = Math.max(-89, Math.min(89, pitch))
|
||||||
|
lastX = data.iMouse.x
|
||||||
|
lastY = data.iMouse.y
|
||||||
|
|
||||||
|
var radYaw = yaw * Math.PI / 180
|
||||||
|
var radPitch = pitch * Math.PI / 180
|
||||||
|
var x = Math.cos(radPitch) * Math.sin(radYaw)
|
||||||
|
var y = Math.sin(radPitch)
|
||||||
|
var z = Math.cos(radPitch) * Math.cos(radYaw)
|
||||||
|
|
||||||
|
camera.eulerRotation = Qt.vector3d((radPitch * 180 / Math.PI), (radYaw * 180 / Math.PI), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: channel
|
||||||
|
function onIMouseChanged()
|
||||||
|
{
|
||||||
|
view3d.updateCamera()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Model
|
||||||
|
{
|
||||||
|
source: Qt.resolvedUrl(channel.source)
|
||||||
|
scale: Qt.vector3d(channel.scale)
|
||||||
|
geometry: Komplex.GeometryProvider
|
||||||
|
{
|
||||||
|
source: Qt.resolvedUrl(channel.source)
|
||||||
|
}
|
||||||
|
materials:
|
||||||
|
[
|
||||||
|
CustomMaterial
|
||||||
|
{
|
||||||
|
property var iChannel0: channel.frameBufferChannel === 0 ? frameBufferSource : channelSource0
|
||||||
|
property var iChannel1: channel.frameBufferChannel === 1 ? frameBufferSource : channelSource1
|
||||||
|
property var iChannel2: channel.frameBufferChannel === 2 ? frameBufferSource : channelSource2
|
||||||
|
property var iChannel3: channel.frameBufferChannel === 3 ? frameBufferSource : channelSource3
|
||||||
|
|
||||||
|
property var iResolution: channel.iResolution
|
||||||
|
property var iTime: data.iTime
|
||||||
|
property var iTimeDelta: channel.iTimeDelta
|
||||||
|
property var iChannelTime: channel.iChannelTime
|
||||||
|
property var iSampleRate: channel.iSampleRate
|
||||||
|
property var iFrame: channel.iFrame
|
||||||
|
property var iFrameRate: channel.iFrameRate
|
||||||
|
property var iMouse: data.iMouse
|
||||||
|
property var iDate: channel.iDate
|
||||||
|
|
||||||
|
property var iChannelResolution: channel.iResolution
|
||||||
|
|
||||||
|
Texture
|
||||||
|
{
|
||||||
|
id: baseColorMap
|
||||||
|
source: Qt.resolvedUrl(channel.materialTexture)
|
||||||
|
}
|
||||||
|
|
||||||
|
cullMode: PrincipledMaterial.NoCulling
|
||||||
|
fragmentShader: Qt.resolvedUrl(channel.materialShader)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ Item
|
|||||||
property int resolution_y
|
property int resolution_y
|
||||||
property bool enabled
|
property bool enabled
|
||||||
property bool invert
|
property bool invert
|
||||||
|
property bool changed
|
||||||
|
|
||||||
id: window
|
id: window
|
||||||
|
|
||||||
@@ -116,6 +117,16 @@ Item
|
|||||||
type: ShaderChannel.Type.ImageChannel
|
type: ShaderChannel.Type.ImageChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListElement
|
||||||
|
{
|
||||||
|
file: true
|
||||||
|
name: "Scene"
|
||||||
|
icon: "./icons/image.svg"
|
||||||
|
title: "Select a scene file"
|
||||||
|
filter: "Image Files (*.qml)"
|
||||||
|
type: ShaderChannel.Type.SceneChannel
|
||||||
|
}
|
||||||
|
|
||||||
ListElement
|
ListElement
|
||||||
{
|
{
|
||||||
file: true
|
file: true
|
||||||
@@ -574,8 +585,8 @@ Item
|
|||||||
function accept()
|
function accept()
|
||||||
{
|
{
|
||||||
// copy over temp values
|
// copy over temp values
|
||||||
source = tmp_source
|
|
||||||
type = tmp_type
|
type = tmp_type
|
||||||
|
source = tmp_source
|
||||||
timeScale = tmp_timeScale
|
timeScale = tmp_timeScale
|
||||||
resolution_scale = tmp_resolution_scale
|
resolution_scale = tmp_resolution_scale
|
||||||
resolution_x = tmp_resolution_x
|
resolution_x = tmp_resolution_x
|
||||||
@@ -629,6 +640,12 @@ Item
|
|||||||
// Function to reset the selection to default values
|
// Function to reset the selection to default values
|
||||||
function resetSelection()
|
function resetSelection()
|
||||||
{
|
{
|
||||||
|
if((tmp_source !== source) || (tmp_enabled !== enabled) ||
|
||||||
|
(tmp_invert !== invert) || (tmp_resolution_scale !== resolution_scale) ||
|
||||||
|
(tmp_resolution_x !== resolution_x) || (tmp_resolution_y !== resolution_y) ||
|
||||||
|
(tmp_timeScale !== timeScale) || (tmp_type !== type))
|
||||||
|
changed = true;
|
||||||
|
|
||||||
tmp_source = source
|
tmp_source = source
|
||||||
tmp_timeScale = timeScale
|
tmp_timeScale = timeScale
|
||||||
tmp_resolution_scale = resolution_scale
|
tmp_resolution_scale = resolution_scale
|
||||||
|
|||||||
577
package/contents/ui/ShaderToyHub.qml
Normal file
577
package/contents/ui/ShaderToyHub.qml
Normal file
@@ -0,0 +1,577 @@
|
|||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Dialogs
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtMultimedia
|
||||||
|
import QtWebView
|
||||||
|
|
||||||
|
import Komplex.ShaderToy as ShaderToy
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: mainItem
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ShaderToy.SearchModel
|
||||||
|
{
|
||||||
|
id: searchModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.fillHeight: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
TextField
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
id: searchField
|
||||||
|
placeholderText: "Search"
|
||||||
|
onEditingFinished: mainItem.updateSearch()
|
||||||
|
Keys.onPressed: (event) =>
|
||||||
|
{
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
|
||||||
|
{
|
||||||
|
searchField.focus = false; // Unfocus the TextField
|
||||||
|
event.accepted = true; // Prevent further propagation of the key event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
|
||||||
|
icon.name: "search-symbolic"
|
||||||
|
|
||||||
|
onClicked: mainItem.updateSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component
|
||||||
|
{
|
||||||
|
id: highlight
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
width: view.cellWidth; height: view.cellHeight
|
||||||
|
color: palette.highlight; radius: 5
|
||||||
|
x: view.currentItem.x
|
||||||
|
y: view.currentItem.y
|
||||||
|
Behavior on x { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
Behavior on y { SpringAnimation { spring: 3; damping: 0.2 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: palette.base
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
GridView
|
||||||
|
{
|
||||||
|
// The standard size
|
||||||
|
property int idealCellHeight: 200
|
||||||
|
property int idealCellWidth: 250
|
||||||
|
cellWidth: width / Math.floor(width / idealCellWidth)
|
||||||
|
cellHeight: idealCellHeight
|
||||||
|
|
||||||
|
id: view
|
||||||
|
|
||||||
|
model: searchModel
|
||||||
|
highlight: highlight
|
||||||
|
highlightFollowsCurrentItem: false
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
|
||||||
|
delegate: Column
|
||||||
|
{
|
||||||
|
property int itemIndex: index
|
||||||
|
property string shaderThumbnail: thumbnail
|
||||||
|
property string shaderEmbed: embedUrl
|
||||||
|
property string shaderId: id
|
||||||
|
property string author: username
|
||||||
|
property string shaderDescription: model.description
|
||||||
|
|
||||||
|
id: entry
|
||||||
|
|
||||||
|
leftPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
topPadding: 10
|
||||||
|
rightPadding: Math.floor((width - thumbnailImage.width) / 2)
|
||||||
|
bottomPadding: 10
|
||||||
|
width: view.cellWidth
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
width: 250
|
||||||
|
height: 140
|
||||||
|
id: thumbnailImage
|
||||||
|
source: thumbnail
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: thumbnailImage.status === Image.Loading
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: 64
|
||||||
|
Layout.preferredWidth: 64
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.dark
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: thumbnailImage.status === Image.Error
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Error Loading Image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked:
|
||||||
|
(mouse) => {
|
||||||
|
view.currentIndex = parent.parent.itemIndex
|
||||||
|
//searchModel.currentIndex = view.currentIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
visible: parent.itemIndex === view.currentIndex
|
||||||
|
width: thumbnailImage.width
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.topMargin: 4
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.preferredHeight: 32
|
||||||
|
Layout.fillWidth: true
|
||||||
|
icon.name: "emblem-downloads"
|
||||||
|
text: qsTr("Preview & Download")
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
downloadDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
id: downloadDialog
|
||||||
|
modal: Qt.WindowModal
|
||||||
|
width: 600
|
||||||
|
height: 440
|
||||||
|
|
||||||
|
parent: mainItem
|
||||||
|
anchors.centerIn: mainItem
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
WebView
|
||||||
|
{
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
id: shaderPreview
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.preferredHeight: 281
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
url: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 64
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
id: shaderDescription
|
||||||
|
text: model.description
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
maximumLineCount: 3
|
||||||
|
color: palette.text
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
icon.name: "image-symbolic"
|
||||||
|
|
||||||
|
id: downloadButton
|
||||||
|
text: qsTr("Convert to Komplex Pack")
|
||||||
|
|
||||||
|
onClicked: () =>
|
||||||
|
{
|
||||||
|
workingThumbnail.source = model.thumbnail
|
||||||
|
searchModel.convert(model.index);
|
||||||
|
downloadDialog.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: () =>
|
||||||
|
{
|
||||||
|
shaderPreview.loadHtml(`<html><head></head><body></body></html>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: () =>
|
||||||
|
{
|
||||||
|
shaderDescription.text = model.description
|
||||||
|
shaderPreview.loadHtml(`<html><head></head><body style="background-color:${palette.base.toString(16)};"><center><iframe src="${model.embedUrl}?gui=true&t=10&paused=false&muted=true" width="500" height="281" frameborder="0" allowfullscreen="allowfullscreen" /></center></body></html>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
populate: Transition
|
||||||
|
{
|
||||||
|
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Previous"
|
||||||
|
enabled: searchModel.currentPage > 1
|
||||||
|
onClicked: searchModel.previous()
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
visible: searchModel.totalResults > 0
|
||||||
|
color: palette.text
|
||||||
|
text: ((searchModel.resultsPerPage * searchModel.currentPage) - searchModel.resultsPerPage + 1) + "-" + (searchModel.resultsPerPage * searchModel.currentPage) + " of " + searchModel.totalResults
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Page " + searchModel.currentPage + " of " + Math.ceil(searchModel.totalResults / searchModel.resultsPerPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
color: palette.text
|
||||||
|
text: "Shaders provided by ShaderToy"
|
||||||
|
font.bold: true
|
||||||
|
|
||||||
|
onLinkActivated: (link) => Qt.openUrlExternally(link)
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: (mouse) => Qt.openUrlExternally("https://www.shadertoy.com")
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
text: "Next"
|
||||||
|
enabled: searchModel.currentPage <= searchModel.totalPages
|
||||||
|
onClicked: searchModel.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: palette.base
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: searchModel.status === ShaderToy.SearchModel.Searching || searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Image
|
||||||
|
{
|
||||||
|
visible: searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
id: workingThumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: stateText
|
||||||
|
text: searchModel.statusMessage
|
||||||
|
color: palette.text
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
id: totalProgress
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 6
|
||||||
|
visible: searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
id: downloadText
|
||||||
|
text: qsTr(searchModel.downloadText)
|
||||||
|
color: palette.text
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: searchModel.totalDownloads > 0 && searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar
|
||||||
|
{
|
||||||
|
id: downloadProgress
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 6
|
||||||
|
from: 0
|
||||||
|
to: searchModel.totalDownloads
|
||||||
|
value: searchModel.completedDownloads
|
||||||
|
visible: searchModel.totalDownloads > 0 && searchModel.status === ShaderToy.SearchModel.Compiling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator
|
||||||
|
{
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
width: 128
|
||||||
|
height: 128
|
||||||
|
visible: running
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
property int totalVideos: searchModel.videoSelections.length
|
||||||
|
property int selectedVideos: 0
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.base
|
||||||
|
visible: searchModel.status === ShaderToy.SearchModel.Compiled
|
||||||
|
enabled: visible
|
||||||
|
|
||||||
|
id: mediaSelectionItem
|
||||||
|
|
||||||
|
signal accepted
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 50
|
||||||
|
color: palette.text
|
||||||
|
text: "<h2>Select Media</h2>";
|
||||||
|
}
|
||||||
|
|
||||||
|
Text
|
||||||
|
{
|
||||||
|
Layout.margins: 6
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: palette.text
|
||||||
|
text: qsTr("The shader you selected contains one or more video references. However, the videos available on ShaderToy are not likely to be desired.\n\nPlease select a new video source from your local drive or from Pexels.")
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 6
|
||||||
|
model: searchModel.videoSelections
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
width: parent.width
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
RowLayout
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
TextField
|
||||||
|
{
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 35
|
||||||
|
id: mediaSelectionField
|
||||||
|
placeholderText: "Select Media Source"
|
||||||
|
color: palette.text
|
||||||
|
onEditingFinished:
|
||||||
|
{
|
||||||
|
if(text.length > 0)
|
||||||
|
mediaSelectionItem.selectedVideos += 1
|
||||||
|
else if(mediaItem.selectedVideos > 0)
|
||||||
|
mediaSelectionItem.selectedVideos -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
icon.name: "folder-symbolic"
|
||||||
|
onClicked: fileDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
icon.name: "network-symbolic"
|
||||||
|
onClicked: pexelsDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileDialog
|
||||||
|
{
|
||||||
|
id: fileDialog
|
||||||
|
currentFolder: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||||
|
onAccepted:
|
||||||
|
{
|
||||||
|
mediaSelectionField.text = selectedFile
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog
|
||||||
|
{
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
id: pexelsDialog
|
||||||
|
|
||||||
|
parent: mainItem
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
PexelsVideoHub
|
||||||
|
{
|
||||||
|
onSelectedFileChanged:
|
||||||
|
{
|
||||||
|
mediaSelectionField.text = selectedFile
|
||||||
|
mediaSelectionField.editingFinished()
|
||||||
|
pexelsDialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: mediaSelectionItem
|
||||||
|
function onAccepted()
|
||||||
|
{
|
||||||
|
searchModel.replaceSource(view.currentIndex, modelData, mediaSelectionField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
color: "transparent"
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
Layout.preferredHeight: 35
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||||
|
text: qsTr("Accept")
|
||||||
|
enabled: mediaSelectionItem.totalVideos === mediaSelectionItem.selectedVideos
|
||||||
|
|
||||||
|
onClicked: mediaSelectionItem.accepted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog
|
||||||
|
{
|
||||||
|
buttons: MessageDialog.Ok
|
||||||
|
id: warningDialog
|
||||||
|
text: searchModel.statusMessage
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: searchModel
|
||||||
|
function onStatusChanged()
|
||||||
|
{
|
||||||
|
console.log("Search Model Status " + searchModel.status)
|
||||||
|
|
||||||
|
if(searchModel.status === ShaderToy.SearchModel.Error)
|
||||||
|
{
|
||||||
|
warningDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog
|
||||||
|
{
|
||||||
|
buttons: MessageDialog.Ok
|
||||||
|
id: messageDialog
|
||||||
|
text: searchModel.statusMessage
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: searchModel
|
||||||
|
function onShaderInstalled()
|
||||||
|
{
|
||||||
|
messageDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSearch()
|
||||||
|
{
|
||||||
|
console.log(searchField.text)
|
||||||
|
searchModel.currentPage = 1
|
||||||
|
searchModel.query = searchField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
* This software uses some of the QML code from JaredTao/jared2020@163.com's ToyShader for Android.
|
* This software uses some of the QML code from JaredTao/jared2020@163.com's ToyShader for Android.
|
||||||
* See: https://github.com/jaredtao/TaoShaderToy/
|
* See: https://github.com/jaredtao/TaoShaderToy/
|
||||||
*/
|
*/
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -94,7 +93,7 @@ Item
|
|||||||
source: wallpaper.configuration.iChannel0_flag ? Qt.resolvedUrl(wallpaper.configuration.iChannel0) : ""
|
source: wallpaper.configuration.iChannel0_flag ? Qt.resolvedUrl(wallpaper.configuration.iChannel0) : ""
|
||||||
|
|
||||||
// ShaderToy seems to start at bottom left for 0,0
|
// ShaderToy seems to start at bottom left for 0,0
|
||||||
invert: wallpaper.configuration.iChannel0_inverted
|
invert: wallpaper.configuration.iChannel0_inverted !== undefined ? wallpaper.configuration.iChannel0_inverted : true
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderChannel
|
ShaderChannel
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ Kirigami.FormLayout
|
|||||||
property alias cfg_resolution_y: resolutionYField.value
|
property alias cfg_resolution_y: resolutionYField.value
|
||||||
|
|
||||||
property alias cfg_framerate_limit: frameRateField.value
|
property alias cfg_framerate_limit: frameRateField.value
|
||||||
|
property bool cfg_shader_updated
|
||||||
|
|
||||||
Palette
|
Palette
|
||||||
{
|
{
|
||||||
@@ -366,7 +367,13 @@ Kirigami.FormLayout
|
|||||||
id: shaderChannelConfig0
|
id: shaderChannelConfig0
|
||||||
palette: palette
|
palette: palette
|
||||||
height: 350
|
height: 350
|
||||||
onAccepted: shaderChannelOverlay0.close(); // Close the overlay after configuration
|
onAccepted: () =>
|
||||||
|
{
|
||||||
|
if(shaderChannelConfig0.changed)
|
||||||
|
root.cfg_shader_updated = true
|
||||||
|
|
||||||
|
shaderChannelOverlay0.close(); // Close the overlay after configuration
|
||||||
|
}
|
||||||
onRejected: shaderChannelOverlay0.close();
|
onRejected: shaderChannelOverlay0.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,7 +418,13 @@ Kirigami.FormLayout
|
|||||||
{
|
{
|
||||||
id: shaderChannelConfig1
|
id: shaderChannelConfig1
|
||||||
height: 350
|
height: 350
|
||||||
onAccepted: shaderChannelOverlay1.close(); // Close the overlay after configuration
|
onAccepted: () =>
|
||||||
|
{
|
||||||
|
if(shaderChannelConfig1.changed)
|
||||||
|
root.cfg_shader_updated = true
|
||||||
|
|
||||||
|
shaderChannelOverlay1.close(); // Close the overlay after configuration
|
||||||
|
}
|
||||||
onRejected: shaderChannelOverlay1.close();
|
onRejected: shaderChannelOverlay1.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -456,7 +469,13 @@ Kirigami.FormLayout
|
|||||||
{
|
{
|
||||||
id: shaderChannelConfig2
|
id: shaderChannelConfig2
|
||||||
height: 350
|
height: 350
|
||||||
onAccepted: shaderChannelOverlay2.close(); // Close the overlay after configuration
|
onAccepted: () =>
|
||||||
|
{
|
||||||
|
if(shaderChannelConfig2.changed)
|
||||||
|
root.cfg_shader_updated = true
|
||||||
|
|
||||||
|
shaderChannelOverlay2.close(); // Close the overlay after configuration
|
||||||
|
}
|
||||||
onRejected: shaderChannelOverlay2.close();
|
onRejected: shaderChannelOverlay2.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,7 +519,13 @@ Kirigami.FormLayout
|
|||||||
{
|
{
|
||||||
id: shaderChannelConfig3
|
id: shaderChannelConfig3
|
||||||
height: 350
|
height: 350
|
||||||
onAccepted: shaderChannelOverlay3.close(); // Close the overlay after configuration
|
onAccepted: () =>
|
||||||
|
{
|
||||||
|
if(shaderChannelConfig3.changed)
|
||||||
|
root.cfg_shader_updated = true
|
||||||
|
|
||||||
|
shaderChannelOverlay3.close(); // Close the overlay after configuration
|
||||||
|
}
|
||||||
onRejected: shaderChannelOverlay3.close();
|
onRejected: shaderChannelOverlay3.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ WallpaperItem
|
|||||||
property string shaderPack: wallpaper.configuration.shader_package
|
property string shaderPack: wallpaper.configuration.shader_package
|
||||||
property bool changing: false
|
property bool changing: false
|
||||||
|
|
||||||
|
property bool updated: wallpaper.configuration.shader_updated
|
||||||
|
|
||||||
|
property bool iChannel0_inverted: wallpaper.configuration.iChannel0_inverted
|
||||||
|
property bool iChannel1_inverted: wallpaper.configuration.iChannel1_inverted
|
||||||
|
property bool iChannel2_inverted: wallpaper.configuration.iChannel2_inverted
|
||||||
|
property bool iChannel3_inverted: wallpaper.configuration.iChannel3_inverted
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Loader
|
Loader
|
||||||
@@ -78,6 +85,7 @@ WallpaperItem
|
|||||||
|
|
||||||
ShaderToyModel
|
ShaderToyModel
|
||||||
{
|
{
|
||||||
|
//wallpaper: wallpaper
|
||||||
screenGeometry: wallpaperItem.parent.screenGeometry
|
screenGeometry: wallpaperItem.parent.screenGeometry
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
@@ -95,41 +103,18 @@ WallpaperItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// band-aid section
|
// band-aid section
|
||||||
onResolution_xChanged: () =>
|
onResolution_xChanged: () => reload();
|
||||||
|
onResolution_yChanged: () => reload();
|
||||||
|
onShaderPackChanged: () => reload();
|
||||||
|
onIChannel0_invertedChanged: () => reload();
|
||||||
|
|
||||||
|
onUpdatedChanged: () =>
|
||||||
{
|
{
|
||||||
if(changing)
|
if(updated)
|
||||||
return;
|
reload();
|
||||||
|
|
||||||
changing = true
|
|
||||||
|
|
||||||
pageLoader.sourceComponent = null
|
|
||||||
|
|
||||||
if(wallpaper.configuration.komplex_mode === 0)
|
|
||||||
pageLoader.sourceComponent = shaderToyContent
|
|
||||||
else
|
|
||||||
pageLoader.sourceComponent = packContent
|
|
||||||
|
|
||||||
changing = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onResolution_yChanged: () =>
|
function reload()
|
||||||
{
|
|
||||||
if(changing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
changing = true
|
|
||||||
|
|
||||||
pageLoader.sourceComponent = null
|
|
||||||
|
|
||||||
if(wallpaper.configuration.komplex_mode === 0)
|
|
||||||
pageLoader.sourceComponent = shaderToyContent
|
|
||||||
else
|
|
||||||
pageLoader.sourceComponent = packContent
|
|
||||||
|
|
||||||
changing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
onShaderPackChanged: () =>
|
|
||||||
{
|
{
|
||||||
if(changing)
|
if(changing)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user