Laying out main page and adding songlistmodel
This commit is contained in:
parent
f2a10ebfcc
commit
3bd74d1ca6
24 changed files with 816 additions and 454 deletions
|
@ -10,11 +10,18 @@ import "./presenter" as Presenter
|
|||
|
||||
Kirigami.ApplicationWindow {
|
||||
id: root
|
||||
|
||||
property bool libraryOpen: true
|
||||
|
||||
pageStack.initialPage: mainPage
|
||||
header: Presenter.Header {}
|
||||
width: 1280
|
||||
|
||||
Presenter.MainWindow {
|
||||
id: mainPage
|
||||
}
|
||||
|
||||
function toggleLibrary() {
|
||||
libraryOpen = !libraryOpen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
12
src/qml/presenter/Actions.qml
Normal file
12
src/qml/presenter/Actions.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Dialogs 1.0
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtMultimedia 5.15
|
||||
import QtAudioEngine 1.15
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import "./" as Presenter
|
||||
|
||||
QtObject {
|
||||
}
|
54
src/qml/presenter/Header.qml
Normal file
54
src/qml/presenter/Header.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Dialogs 1.0
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
|
||||
Kirigami.ActionToolBar {
|
||||
id: root
|
||||
alignment: Qt.AlignRight
|
||||
|
||||
Kirigami.Heading {
|
||||
text: "Presenter"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
}
|
||||
|
||||
actions: [
|
||||
|
||||
Kirigami.Action {
|
||||
displayComponent: Component {
|
||||
Kirigami.SearchField {
|
||||
id: searchField
|
||||
onAccepted: showPassiveNotification(searchField.text, 3000)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Kirigami.Action {
|
||||
icon.name: "fileopen"
|
||||
text: "VideoBG"
|
||||
onTriggered: {
|
||||
print("Action button in buttons page clicked");
|
||||
fileDialog.open()
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "view-presentation"
|
||||
text: "Go Live"
|
||||
onTriggered: {
|
||||
print("Window is loading")
|
||||
presentLoader.active = true
|
||||
}
|
||||
},
|
||||
|
||||
Kirigami.Action {
|
||||
icon.name: "sidebar-collapse-right"
|
||||
text: "Close Library"
|
||||
onTriggered: toggleLibrary()
|
||||
}
|
||||
|
||||
]
|
||||
}
|
|
@ -7,11 +7,49 @@ import QtMultimedia 5.15
|
|||
import QtAudioEngine 1.15
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
|
||||
ListView {
|
||||
id: serviceItemList
|
||||
model: listModel
|
||||
delegate: itemDelegate
|
||||
/* flickDeceleration: 2000 */
|
||||
ColumnLayout {
|
||||
id: root
|
||||
Layout.fillHeight: true
|
||||
|
||||
Kirigami.Heading {
|
||||
id: serviceTitle
|
||||
text: "Service List"
|
||||
level: 1
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: serviceItemList
|
||||
model: listModel
|
||||
delegate: itemDelegate
|
||||
/* flickDeceleration: 2000 */
|
||||
|
||||
Component {
|
||||
id: itemDelegate
|
||||
Kirigami.BasicListItem {
|
||||
width: serviceItemList.width
|
||||
height:50
|
||||
label: itemName
|
||||
subtitle: type
|
||||
hoverEnabled: true
|
||||
onClicked: serviceItemList.currentIndex = index
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.WheelHandler {
|
||||
id: wheelHandler
|
||||
target: serviceItemList
|
||||
filterMouseEvents: true
|
||||
keyNavigationEnabled: true
|
||||
}
|
||||
|
||||
Controls.ScrollBar.vertical: Controls.ScrollBar {
|
||||
anchors.right: serviceItemList.right
|
||||
anchors.leftMargin: 10
|
||||
active: hovered || pressed
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: listModel
|
||||
|
@ -88,30 +126,4 @@ ListView {
|
|||
type: "video"
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: itemDelegate
|
||||
Kirigami.BasicListItem {
|
||||
width: serviceItemList.width
|
||||
height:50
|
||||
label: itemName
|
||||
subtitle: type
|
||||
hoverEnabled: true
|
||||
onClicked: serviceItemList.currentIndex = index
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.WheelHandler {
|
||||
id: wheelHandler
|
||||
target: serviceItemList
|
||||
filterMouseEvents: true
|
||||
keyNavigationEnabled: true
|
||||
}
|
||||
|
||||
Controls.ScrollBar.vertical: Controls.ScrollBar {
|
||||
anchors.right: serviceItemList.right
|
||||
anchors.leftMargin: 10
|
||||
active: hovered || pressed
|
||||
}
|
||||
}
|
||||
|
|
47
src/qml/presenter/Library.qml
Normal file
47
src/qml/presenter/Library.qml
Normal file
|
@ -0,0 +1,47 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Dialogs 1.0
|
||||
import QtQuick.Controls 2.0 as Controls
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import "./" as Presenter
|
||||
|
||||
Item {
|
||||
id: root
|
||||
Presenter.PanelItem {
|
||||
anchors.fill: parent
|
||||
title: "Songs"
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
id: libraryListView
|
||||
model: _songListModel
|
||||
delegate: itemDelegate
|
||||
|
||||
Component {
|
||||
id: itemDelegate
|
||||
Kirigami.BasicListItem {
|
||||
width: ListView.view.width
|
||||
height:40
|
||||
label: title
|
||||
subtitle: author
|
||||
hoverEnabled: true
|
||||
onClicked: ListView.view.currentIndex = index
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.WheelHandler {
|
||||
id: wheelHandler
|
||||
target: libraryListView
|
||||
filterMouseEvents: true
|
||||
keyNavigationEnabled: true
|
||||
}
|
||||
|
||||
Controls.ScrollBar.vertical: Controls.ScrollBar {
|
||||
anchors.right: libraryListView.right
|
||||
anchors.leftMargin: 10
|
||||
active: hovered || pressed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/qml/presenter/LibraryDelegate.qml
Normal file
11
src/qml/presenter/LibraryDelegate.qml
Normal file
|
@ -0,0 +1,11 @@
|
|||
import QtQuick 2.13
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
|
||||
Kirigami.BasicListItem {
|
||||
width: ListView.view.width
|
||||
height:20
|
||||
label: model.itemName
|
||||
subtitle: model.type
|
||||
hoverEnabled: true
|
||||
onClicked: ListView.view.currentIndex = index
|
||||
}
|
76
src/qml/presenter/LibraryModel.qml
Normal file
76
src/qml/presenter/LibraryModel.qml
Normal file
|
@ -0,0 +1,76 @@
|
|||
import QtQuick 2.13
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
itemName: "10,000 Reason"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Marvelous Light"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10 reason to use church presenter"
|
||||
type: "video"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "killer.jpg"
|
||||
type: "image"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Marvelous Light"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Cool runnings"
|
||||
type: "video"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10,000 Reason"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Slides1.odp"
|
||||
type: "presentation"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "IntroSlide"
|
||||
type: "custom-slide"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10,000 Reason"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Marvelous Light"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "other slide"
|
||||
type: "custom-slide"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10,000 Reason"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Marvelous Light"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10 reason to use church presenter"
|
||||
type: "video"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10,000 Reason"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "Marvelous Light"
|
||||
type: "song"
|
||||
}
|
||||
ListElement {
|
||||
itemName: "10 reason to use church presenter"
|
||||
type: "video"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Dialogs 1.0
|
||||
import QtQuick.Controls 2.0 as Controls
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtMultimedia 5.15
|
||||
|
@ -8,61 +8,54 @@ import QtAudioEngine 1.15
|
|||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import "./" as Presenter
|
||||
|
||||
Kirigami.Page {
|
||||
Controls.Page {
|
||||
id: mainPage
|
||||
title: "Presenter"
|
||||
padding: 0
|
||||
property var video: null
|
||||
|
||||
actions {
|
||||
main: Kirigami.Action {
|
||||
icon.name: "fileopen"
|
||||
text: "VideoBG"
|
||||
onTriggered: {
|
||||
print("Action button in buttons page clicked");
|
||||
fileDialog.open()
|
||||
}
|
||||
}
|
||||
right: Kirigami.Action {
|
||||
icon.name: "view-presentation"
|
||||
text: "Go Live"
|
||||
onTriggered: {
|
||||
print("Window is loading")
|
||||
presentLoader.active = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
anchors.fill: parent
|
||||
height: parent.height
|
||||
|
||||
GridLayout {
|
||||
id: gridLayout
|
||||
Controls.SplitView {
|
||||
id: splitMainView
|
||||
anchors.fill: parent
|
||||
height: parent.height
|
||||
columns: 3
|
||||
rows: 2
|
||||
Presenter.LeftDock {
|
||||
id: leftDock
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 200
|
||||
handle: Item{
|
||||
implicitWidth: 6
|
||||
|
||||
Rectangle {
|
||||
height: parent.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
implicitWidth: 2
|
||||
color: Controls.SplitHandle.hovered ? Kirigami.Theme.hoverColor : Kirigami.Theme.backgroundColor
|
||||
//Controls.SplitHandle.pressed ? Kirigami.Theme.focusColor
|
||||
//: (Controls.Splithandle.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: leftDockBorder
|
||||
color: "lightblue"
|
||||
Layout.fillHeight: true
|
||||
width: 2
|
||||
Presenter.LeftDock {
|
||||
id: leftDock
|
||||
Controls.SplitView.fillHeight: true
|
||||
Controls.SplitView.preferredWidth: 200
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rightMainArea
|
||||
color: "red"
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Controls.SplitView.fillHeight: true
|
||||
Controls.SplitView.fillWidth: true
|
||||
Controls.SplitView.preferredWidth: 700
|
||||
Controls.SplitView.minimumWidth: 500
|
||||
}
|
||||
|
||||
Presenter.Library {
|
||||
id: library
|
||||
Controls.SplitView.fillHeight: true
|
||||
Controls.SplitView.preferredWidth: libraryOpen ? 200 : 0
|
||||
Controls.SplitView.maximumWidth: 350
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
70
src/qml/presenter/PanelItem.qml
Normal file
70
src/qml/presenter/PanelItem.qml
Normal file
|
@ -0,0 +1,70 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0 as Controls
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
|
||||
Item {
|
||||
default property var contentItem: null
|
||||
property string title: "panel"
|
||||
id: root
|
||||
Layout.fillWidth: true
|
||||
height: 30
|
||||
Layout.fillHeight: current
|
||||
property bool current: false
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
Rectangle {
|
||||
id: bar
|
||||
Layout.fillWidth: true
|
||||
height: 30
|
||||
color: root.current ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
|
||||
Controls.Label {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: root.title
|
||||
}
|
||||
Controls.Label {
|
||||
anchors{
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
margins: 10
|
||||
}
|
||||
horizontalAlignment: Text.AlignRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: "^"
|
||||
rotation: root.current ? "180" : 0
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.current = !root.current;
|
||||
if(root.parent.currentItem !== null)
|
||||
root.parent.currentItem.current = false;
|
||||
|
||||
root.parent.currentItem = root;
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: container
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: bar.height / 4
|
||||
implicitHeight: root.height - bar.height
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
clip: true
|
||||
Behavior on implicitHeight {
|
||||
PropertyAnimation { duration: 100 }
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
if(root.contentItem !== null)
|
||||
root.contentItem.parent = container;
|
||||
}
|
||||
}
|
||||
}
|
164
src/qml/presenter/Slide.qml
Normal file
164
src/qml/presenter/Slide.qml
Normal file
|
@ -0,0 +1,164 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtMultimedia 5.15
|
||||
import QtAudioEngine 1.15
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import "./" as Presenter
|
||||
|
||||
Item {
|
||||
/*
|
||||
Slides can only be instantiated as a direct child of a Presentation {} as they rely on
|
||||
several properties there.
|
||||
*/
|
||||
|
||||
id: slide
|
||||
|
||||
property bool isSlide: true;
|
||||
|
||||
property bool delayPoints: false;
|
||||
property int _pointCounter: 0;
|
||||
function _advance() {
|
||||
if (!parent.allowDelay)
|
||||
return false;
|
||||
|
||||
_pointCounter = _pointCounter + 1;
|
||||
if (_pointCounter < content.length)
|
||||
return true;
|
||||
_pointCounter = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
property string title;
|
||||
property variant content: []
|
||||
property string centeredText
|
||||
property string writeInText;
|
||||
property string notes;
|
||||
|
||||
property real fontSize: parent.height * 0.05
|
||||
property real fontScale: 1
|
||||
|
||||
property real baseFontSize: fontSize * fontScale
|
||||
property real titleFontSize: fontSize * 1.2 * fontScale
|
||||
property real bulletSpacing: 1
|
||||
|
||||
property real contentWidth: width
|
||||
|
||||
// Define the slide to be the "content area"
|
||||
x: parent.width * 0.05
|
||||
y: parent.height * 0.2
|
||||
width: parent.width * 0.9
|
||||
height: parent.height * 0.7
|
||||
|
||||
property real masterWidth: parent.width
|
||||
property real masterHeight: parent.height
|
||||
|
||||
property color titleColor: parent.titleColor;
|
||||
property color textColor: parent.textColor;
|
||||
property string fontFamily: parent.fontFamily;
|
||||
property int textFormat: Text.PlainText
|
||||
|
||||
visible: false
|
||||
|
||||
Controls.Label {
|
||||
id: titleText
|
||||
font.pixelSize: titleFontSize
|
||||
text: title;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: parent.fontSize * 1.5
|
||||
font.bold: true;
|
||||
font.family: slide.fontFamily
|
||||
color: slide.titleColor
|
||||
horizontalAlignment: Text.Center
|
||||
z: 1
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: centeredId
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: - parent.y / 3
|
||||
text: centeredText
|
||||
horizontalAlignment: Text.Center
|
||||
font.pixelSize: baseFontSize
|
||||
font.family: slide.fontFamily
|
||||
color: slide.textColor
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: writeInTextId
|
||||
property int length;
|
||||
font.family: slide.fontFamily
|
||||
font.pixelSize: baseFontSize
|
||||
color: slide.textColor
|
||||
|
||||
anchors.fill: parent;
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
text: slide.writeInText.substring(0, length);
|
||||
|
||||
NumberAnimation on length {
|
||||
from: 0;
|
||||
to: slide.writeInText.length;
|
||||
duration: slide.writeInText.length * 30;
|
||||
running: slide.visible && parent.visible && slide.writeInText.length > 0
|
||||
}
|
||||
|
||||
visible: slide.writeInText != undefined;
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
id: contentId
|
||||
anchors.fill: parent
|
||||
|
||||
Repeater {
|
||||
model: content.length
|
||||
|
||||
Row {
|
||||
id: row
|
||||
|
||||
function decideIndentLevel(s) { return s.charAt(0) == " " ? 1 + decideIndentLevel(s.substring(1)) : 0 }
|
||||
property int indentLevel: decideIndentLevel(content[index])
|
||||
property int nextIndentLevel: index < content.length - 1 ? decideIndentLevel(content[index+1]) : 0
|
||||
property real indentFactor: (10 - row.indentLevel * 2) / 10;
|
||||
|
||||
height: text.height + (nextIndentLevel == 0 ? 1 : 0.3) * slide.baseFontSize * slide.bulletSpacing
|
||||
x: slide.baseFontSize * indentLevel
|
||||
visible: (!slide.parent.allowDelay || !delayPoints) || index <= _pointCounter
|
||||
|
||||
Rectangle {
|
||||
id: dot
|
||||
anchors.baseline: text.baseline
|
||||
anchors.baselineOffset: -text.font.pixelSize / 2
|
||||
width: text.font.pixelSize / 3
|
||||
height: text.font.pixelSize / 3
|
||||
color: slide.textColor
|
||||
radius: width / 2
|
||||
opacity: text.text.length == 0 ? 0 : 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: space
|
||||
width: dot.width * 1.5
|
||||
height: 1
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: text
|
||||
width: slide.contentWidth - parent.x - dot.width - space.width
|
||||
font.pixelSize: baseFontSize * row.indentFactor
|
||||
text: content[index]
|
||||
textFormat: slide.textFormat
|
||||
wrapMode: Text.WordWrap
|
||||
color: slide.textColor
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
font.family: slide.fontFamily
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue