More UI work in QML

This commit is contained in:
Oscar Cerna-Mandujano 2018-09-03 06:05:55 -07:00
parent b1149a1a82
commit a4a15b15cf
14 changed files with 867 additions and 74 deletions

View File

@ -2,7 +2,16 @@
CasterPlayerController::CasterPlayerController(QObject *parent) : QObject(parent)
{
mItems.append({ false });
// Add initial player
mItems.append({
false, // IsInPlayerMode
false, // IsLooped
1.0, // Volume
false, // IsPlayRegionEnabled
0, // PlayRegionBegin
0, // PlayRegionEnd
0 // Trigger Style
});
}
QVector<CasterPlayerItem> CasterPlayerController::items() const
@ -23,10 +32,16 @@ bool CasterPlayerController::setItemAt(int index, const CasterPlayerItem &item)
void CasterPlayerController::appendItem()
{
// Adds player
// Adds player with default settings
emit preItemAppend();
CasterPlayerItem item;
item.isInPlayerMode = false;
item.isLooped = false;
item.volume = 1.0;
item.isPlayRegionEnabled = false;
item.playRegionBegin = 0;
item.playRegionEnd = 0;
item.triggerStyle = 0;
mItems.append(item);
emit postItemAppend();
}

View File

@ -7,6 +7,12 @@
struct CasterPlayerItem {
bool isInPlayerMode;
bool isLooped;
double volume;
bool isPlayRegionEnabled;
int playRegionBegin;
int playRegionEnd;
int triggerStyle;
};

View File

@ -27,6 +27,18 @@ QVariant CasterPlayerModel::data(const QModelIndex &index, int role) const
switch (role) {
case IsInPlayerModeRole:
return QVariant(item.isInPlayerMode);
case IsLoopedRole:
return QVariant(item.isLooped);
case VolumeRole:
return QVariant(item.volume);
case IsPlayingRegionEnabledRole:
return QVariant(item.isPlayRegionEnabled);
case PlayRegionBeginRole:
return QVariant(item.playRegionBegin);
case PlayRegionEndRole:
return QVariant(item.playRegionEnd);
case TriggerStyleRole:
return QVariant(item.triggerStyle);
}
return QVariant();
@ -42,6 +54,23 @@ bool CasterPlayerModel::setData(const QModelIndex &index, const QVariant &value,
case IsInPlayerModeRole:
item.isInPlayerMode = value.toBool();
break;
case IsLoopedRole:
item.isLooped = value.toBool();
break;
case VolumeRole:
item.volume = value.toDouble();
break;
case IsPlayingRegionEnabledRole:
item.isPlayRegionEnabled = value.toBool();
break;
case PlayRegionBeginRole:
item.playRegionBegin = value.toInt();
break;
case PlayRegionEndRole:
item.playRegionEnd = value.toInt();
break;
case TriggerStyleRole:
item.triggerStyle = value.toInt();
}
if (mList->setItemAt(index.row(), item)) {
@ -65,8 +94,15 @@ Qt::ItemFlags CasterPlayerModel::flags(const QModelIndex &index) const
*/
QHash<int, QByteArray> CasterPlayerModel::roleNames() const
{
// Set QML property names
QHash<int, QByteArray> names;
names[IsInPlayerModeRole] = "isInPlayerMode";
names[IsLoopedRole] = "isLooped";
names[VolumeRole] = "volume";
names[IsPlayingRegionEnabledRole] = "isPlayRegionEnabled";
names[PlayRegionBeginRole] = "playRegionBegin";
names[PlayRegionEndRole] = "playRegionEnd";
names[TriggerStyleRole] = "triggerStyle";
return names;
}

View File

@ -13,9 +13,22 @@ class CasterPlayerModel : public QAbstractListModel
public:
explicit CasterPlayerModel(QObject *parent = nullptr);
enum {
IsInPlayerModeRole = Qt::UserRole
enum ModelRoles {
IsInPlayerModeRole = Qt::UserRole,
IsLoopedRole,
VolumeRole,
IsPlayingRegionEnabledRole,
PlayRegionBeginRole,
PlayRegionEndRole,
TriggerStyleRole
};
Q_ENUM(ModelRoles)
enum TriggerStyle {
PlayPauseTriggerStyle = 0,
PlayStopTriggerStyle,
PlayAgainTriggerStyle
};
Q_ENUM(TriggerStyle)
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;

View File

@ -46,5 +46,8 @@
<file>qml/img/player_outline.png</file>
<file>qml/views/components/caster_player_settings_drawer/Component.qml</file>
<file>qml/views/components/caster_player_settings_drawer/subcomponents/BootstrapButton.qml</file>
<file>qml/views/components/caster_player_settings_drawer/subcomponents/FlatSwitch.qml</file>
<file>qml/views/components/caster_player_settings_drawer/subcomponents/StateSelector.qml</file>
<file>qml/views/components/caster_player_settings_drawer/subcomponents/TimeRangeSelector.qml</file>
</qresource>
</RCC>

View File

@ -8,31 +8,34 @@ import MVC_CasterPlayer 1.0
import "../caster_player" as CasterPlayer
Flickable {
id: soundboardFlickable
property int defaultPlayerSize: 210
id: root
//Component Properties & Events
anchors.fill: parent
anchors.margins: 8
contentHeight: soundboardGrid.height
//contentWidth: soundboardGrid.width
clip: true
flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar {
id: soundboardScrollbar
width: 30
active: true
onActiveChanged: {
if (!active)
active = true;//Keep scrollbar always visible
}
}
id: soundboardScrollbar
width: 30
active: true
onActiveChanged: {
if (!active)
active = true;//Keep scrollbar always visible
}
}
onWidthChanged: soundboardGrid.columns = soundboardGrid.computeNeededColumns(root.defaultPlayerSize, root.width, soundboardGrid.spacing, soundboardScrollbar.width)
onDefaultPlayerSizeChanged: soundboardGrid.columns = soundboardGrid.computeNeededColumns(root.defaultPlayerSize, root.width, soundboardGrid.spacing, soundboardScrollbar.width)
onWidthChanged: soundboardGrid.columns = soundboardGrid.computeNeededColumns(soundboardFlickable.defaultPlayerSize, soundboardFlickable.width, soundboardGrid.spacing, soundboardScrollbar.width)
//Player Properties
property int defaultPlayerSize: 210
property alias soundboardPlayers: playerRepeater
Grid {
id: soundboardGrid
//Properties & Functions
spacing: 8
columns: soundboardGrid.computeNeededColumns(soundboardFlickable.defaultPlayerSize, parent.width, soundboardGrid.spacing, soundboardScrollbar.width)
columns: soundboardGrid.computeNeededColumns(root.defaultPlayerSize, parent.width, soundboardGrid.spacing, soundboardScrollbar.width)
function computeNeededColumns(playerWidth, containerWidth, gridSpacing, scrollbarWidth){
var neededColumnsWithoutSpacing = Math.floor(containerWidth / playerWidth);
var adjustedGridWidth = containerWidth - ((neededColumnsWithoutSpacing - 1) * gridSpacing) - (gridSpacing + scrollbarWidth);
@ -41,11 +44,25 @@ Flickable {
return neededColumns;
}
//Generate Players
Repeater {
id: playerRepeater
model: CasterPlayerModel { list: casterPlayerController }
delegate: CasterPlayer.Component {
size: soundboardFlickable.defaultPlayerSize
size: root.defaultPlayerSize
isInPlayerMode: model.isInPlayerMode
isLooped: model.isLooped
onIsLoopedChanged: model.isLooped = isLooped
volume: model.volume
onVolumeChanged: model.volume = volume
isPlayRegionEnabled: model.isPlayRegionEnabled
onIsPlayRegionEnabledChanged: model.isPlayRegionEnabled = isPlayRegionEnabled
playRegionBegin: model.playRegionBegin
onPlayRegionBeginChanged: model.playRegionBegin = playRegionBegin
playRegionEnd: model.playRegionEnd
onPlayRegionEndChanged: model.playRegionEnd = playRegionEnd
triggerStyle: model.triggerStyle
onTriggerStyleChanged: model.triggerStyle = triggerStyle
}
}
}

View File

@ -4,18 +4,39 @@ import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import QtMultimedia 5.9
import MVC_CasterPlayer 1.0
import "./subcomponents" as Subcomponent
Rectangle {
id: root
//Component properties
property int size: 210
width: root.size; height: root.size
color: "transparent"
property bool shouldKeepPlayingLoop: false
property int duration: player.duration
//Player properties, functions & events
property bool isInPlayerMode: true
property bool isLooped: false
property double volume: 1.0
property bool isPlayRegionEnabled: false
property int playRegionBegin: 0
property int playRegionEnd: 0
onPlayRegionEndChanged: progressBar.playRegionEnd = root.playRegionEnd
property int triggerStyle: 0
property alias trackTile: trackTitle.trackTitleString
property alias trackVolume: volumeBar.value
property alias isLooped: progressBar.isLooped
onIsLoopedChanged: {
if(root.isLooped == false)
root.shouldKeepPlayingLoop = false;
else if (root.isLooped == true && player.playbackState == MediaPlayer.PlayingState){
root.shouldKeepPlayingLoop = true;
}
}
function baseName(url)
{
@ -23,6 +44,8 @@ Rectangle {
return filename;
}
//Player Subcomponents
MediaPlayer {
id: player
volume: volumeBar.value
@ -30,14 +53,27 @@ Rectangle {
onPlaybackStateChanged: {
switch (playbackState) {
case MediaPlayer.StoppedState:
playerStateOverlay.source = '/qml/icons/playState_stopped.png'
// Enforce Looping
if(root.shouldKeepPlayingLoop){
// Loop behavior
player.play();
} else {
// Normal behavior
playerStateOverlay.source = '/qml/icons/playState_stopped.png'
progressBar.state = "stopped";
}
break;
case MediaPlayer.PausedState:
playerStateOverlay.source = '/qml/icons/playState_paused.png'
progressBar.state = "paused";
break;
case MediaPlayer.PlayingState:
default:
playerStateOverlay.source = '/qml/icons/playState_playing.png'
progressBar.state = "playing";
// Enforce Looping
if(root.isLooped)
root.shouldKeepPlayingLoop = true;
break;
}
}
@ -54,10 +90,26 @@ Rectangle {
onDurationChanged: {
progressBar.duration = player.duration;
root.playRegionBegin = 0;
root.playRegionEnd = player.duration;
}
onPositionChanged: {
//Update ProgressBar
progressBar.elapsedTime = player.position;
//Enforce play region and looping
if(root.isPlayRegionEnabled)
if(0 < root.playRegionEnd && root.playRegionEnd <= player.position){
if(root.isLooped)
player.seek(root.playRegionBegin);
else {
player.stop();
player.seek(root.playRegionBegin);
}
} else if (player.position < root.playRegionBegin && 0 < root.playRegionBegin && root.playRegionBegin < root.playRegionEnd) {
player.seek(root.playRegionBegin);
}
}
}
@ -121,14 +173,58 @@ Rectangle {
onClicked: {
switch (player.playbackState) {
case MediaPlayer.StoppedState:
player.play();
switch(root.triggerStyle){
default:
case CasterPlayerModel.PlayPauseTriggerStyle:
player.play();
break;
case CasterPlayerModel.PlayStopTriggerStyle:
player.play();
break;
case CasterPlayerModel.PlayAgainTriggerStyle:
if(root.isPlayRegionEnabled)
player.seek(root.playRegionBegin);
else
player.seek(0);
player.play();
break;
}
break;
case MediaPlayer.PausedState:
player.play();
switch(root.triggerStyle){
default:
case CasterPlayerModel.PlayPauseTriggerStyle:
player.play();
break;
case CasterPlayerModel.PlayStopTriggerStyle:
player.play();
break;
case CasterPlayerModel.PlayAgainTriggerStyle:
if(root.isPlayRegionEnabled)
player.seek(root.playRegionBegin);
else
player.seek(0);
player.play();
break;
}
break;
case MediaPlayer.PlayingState:
default:
player.pause();
case MediaPlayer.PlayingState:
switch(root.triggerStyle){
default:
case CasterPlayerModel.PlayPauseTriggerStyle:
player.pause();
break;
case CasterPlayerModel.PlayStopTriggerStyle:
player.stop();
break;
case CasterPlayerModel.PlayAgainTriggerStyle:
if(root.isPlayRegionEnabled)
player.seek(root.playRegionBegin);
else
player.seek(0);
break;
}
break;
}
}
@ -156,6 +252,10 @@ Rectangle {
id: progressBar
visible: root.isInPlayerMode
enabled: root.isInPlayerMode
isLooped: root.isLooped
isPlayRegionEnabled: root.isPlayRegionEnabled
playRegionBegin: root.playRegionBegin
playRegionEnd: root.playRegionEnd
x: 5 ; y: root.height - this.height - 12;
onMoved: {
player.seek(progressBar.value);
@ -166,9 +266,11 @@ Rectangle {
id: volumeBar
visible: root.isInPlayerMode
enabled: root.isInPlayerMode
x: root.size - 45; y: 10;
x: root.size - this.width - 5; y: 10;
value: root.volume
onMoved: {
player.volume = volumeBar.value;
player.volume = volumeBar.value;//Change volume
root.volume = volumeBar.value;//Update model since we are changing volume internally
}
}

View File

@ -3,24 +3,126 @@ import QtGraphicalEffects 1.0
import QtQuick.Controls 2.4
Slider {
id: control
id: root
// Component properties
implicitWidth: 200
implicitHeight: 25
implicitHeight: 40
from: 0
to: 0
stepSize: 1
state: "stopped"
// Volume bar properties, functions & events
property bool isLooped: false
property bool isPlayRegionEnabled: false
property int playRegionBegin: 0
property int playRegionEnd: 0
property int elapsedTime: 0
property int duration: 0
states: [
State {
name: "stopped"
PropertyChanges { target: sliderHandle; color: "#6AFF0000" }
PropertyChanges { target: repeatIcon; color: "#000000" }
PropertyChanges { target: foregroundBar; color: "red" }
PropertyChanges {
target: trackTimeElapsed
color: (sliderHandle.x >= sliderHandle.width + 8 ? "white" : "black")
}
PropertyChanges {
target: trackTimeRemaining
color: (sliderHandle.x + sliderHandle.width >= parent.width - this.width - 5 ? "white" : "black")
}
},
State {
name: "paused"
PropertyChanges { target: sliderHandle; color: "#80FFFF00" }
PropertyChanges { target: repeatIcon; color: "#000000" }
PropertyChanges { target: foregroundBar; color: "yellow" }
PropertyChanges { target: trackTimeElapsed; color: "black" }
PropertyChanges { target: trackTimeRemaining; color: "black" }
},
State {
name: "playing"
PropertyChanges { target: sliderHandle; color: "#6A00FF00" }
PropertyChanges { target: repeatIcon; color: "#000000" }
PropertyChanges { target: foregroundBar; color: "green" }
PropertyChanges {
target: trackTimeElapsed
color: (sliderHandle.x >= sliderHandle.width + 8 ? "white" : "black")
}
PropertyChanges {
target: trackTimeRemaining
color: (sliderHandle.x + sliderHandle.width >= parent.width - this.width - 5 ? "white" : "black")
}
}
]
transitions: [
Transition {
from: "stopped"; to: "playing"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#6AFF0000"; to: "#6A00FF00"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "red"; to: "green"; duration: 150
}
},
Transition {
from: "stopped"; to: "paused"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#6AFF0000"; to: "#80FFFF00"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "red"; to: "yellow"; duration: 150
}
},
Transition {
from: "playing"; to: "paused"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#6A00FF00"; to: "#80FFFF00"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "green"; to: "yellow"; duration: 150
}
},
Transition {
from: "playing"; to: "stopped"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#6A00FF00"; to: "#6AFF0000"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "green"; to: "red"; duration: 150
}
},
Transition {
from: "paused"; to: "playing"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#80FFFF00"; to: "#6A00FF00"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "yellow"; to: "green"; duration: 150
}
},
Transition {
from: "paused"; to: "stopped"
ColorAnimation { target: sliderHandle; properties: "color"
from: "#80FFFF00"; to: "#6AFF0000"; duration: 150
}
ColorAnimation { target: foregroundBar; properties: "color"
from: "yellow"; to: "red"; duration: 150
}
}
]
onElapsedTimeChanged: {
control.value = control.elapsedTime;
root.value = root.elapsedTime;
}
onDurationChanged: {
control.to = control.duration;
root.to = root.duration;
}
@ -49,56 +151,81 @@ Slider {
return "-" + ("00" + mins).slice(-2) + ':' + ("00" + secs).slice(-2);
}
// Component UI
handle: Rectangle {
id: sliderHandle
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
x: root.visualPosition * (root.width - width)
y: (root.height - height) / 2
width: 45
height: 40
color: control.pressed ? "#f0f0f0" : "#f6f6f6"
height: root.height
border.color: "white"
border.width: 2
opacity: 0.87
//color: "#414345"
/*
gradient: Gradient {
GradientStop { position: 0.0; color: "#414345" }
GradientStop { position: 1.0; color: "#232526" }
}
}*/
Image {
id: loopStateImage
width: Math.floor(0.90 * control.width); height: Math.floor(0.90 * control.height)
width: Math.floor(0.6 * sliderHandle.width); height: Math.floor(0.6 * sliderHandle.height)
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
source: '/qml/icons/loop.png'
visible: control.isLooped
visible: root.isLooped
}
ColorOverlay {
anchors.fill: loopStateImage; source: loopStateImage
color: "#ffffff"
visible: control.isLooped
id: repeatIcon
anchors.fill: loopStateImage; source: loopStateImage
visible: root.isLooped
}
}
background: Rectangle {
y: (control.height - height) / 2
height: 20
border.color: "white"
border.width: 2
gradient: Gradient {
GradientStop { position: 0.0; color: "#cfcfcf" }
GradientStop { position: 1.0; color: "#9e9e9e" }
background: Item {
id: background
y: (root.height - height) / 2
width: root.width; height: 20
Rectangle {
id: playRegion
x: (root.playRegionBegin <= 0 || root.duration <= 0) ? 0 : root.width * root.playRegionBegin / root.duration
y: -20
width: (root.playRegionEnd <= 0 || root.duration <= 0) ? 0 : root.width * (root.playRegionEnd - root.playRegionBegin) / root.duration
height: root.height + 20
opacity: 0.8
color: "blue"
visible: root.isPlayRegionEnabled
}
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
id: backgroundBar
width: root.width; height: 20
border.color: "white"
border.width: 2
gradient: Gradient {
GradientStop { position: 0.0; color: "#cfcfcf" }
GradientStop { position: 1.0; color: "#9e9e9e" }
}
}
Rectangle {
id: foregroundBar
width: root.visualPosition * parent.width
height: 20
border.color: "white"
border.width: 2
gradient: Gradient {
GradientStop { position: 0.0; color: "#414345" }
GradientStop { position: 1.0; color: "#232526" }
}
}
Rectangle {
id: playRegionPosition
x: root.visualPosition * (root.width - width/2); y: -20
width: 5; height: root.height + 20
opacity: 0.9
color: "yellow"
visible: root.isPlayRegionEnabled
}
Text {
@ -109,7 +236,7 @@ Slider {
font.family: "Helvetica"
font.bold: true
font.pointSize: 14
text: timeElapsed(control.elapsedTime)
text: timeElapsed(root.elapsedTime)
}
@ -121,7 +248,7 @@ Slider {
font.family: "Helvetica"
font.bold: true
font.pointSize: 14
text: timeRemaining(control.elapsedTime, control.duration)
text: timeRemaining(root.elapsedTime, root.duration)
}
}
}

View File

@ -2,16 +2,15 @@ import QtQuick 2.7
import QtQuick.Controls 2.4
Slider {
id: control
id: root
orientation: Qt.Vertical
implicitWidth: 25
implicitWidth: 50
implicitHeight: 145
handle: Rectangle {
x: (control.width - width) / 2
y: control.visualPosition * (control.height - height)
width: 50
y: root.visualPosition * (root.height - height)
width: root.width
height: 60
border.color: "white"
border.width: 2
@ -34,14 +33,14 @@ Slider {
anchors.centerIn: parent
color: "white"
font.family: "Helvetica"; font.pointSize: 18; font.bold: true
text: Math.floor(control.value * 100) + "%"
text: Math.floor(root.value * 100) + "%"
}
}
background: Rectangle {
x: (control.width - width) / 2; y: 25
x: (root.width - width) / 2; y: 25
width: 20
height: control.height - 50
height: root.height - 50
border.color: "white"
border.width: 2
gradient: Gradient {

View File

@ -4,21 +4,54 @@ import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import QtMultimedia 5.9
import MVC_CasterPlayer 1.0
import "./subcomponents" as Subcomponent
Drawer {
id: root
//Component properties
edge: Qt.RightEdge
interactive: false
width: parent.width * 0.66; height: parent.height
background: Rectangle { anchors.fill: parent; color: "#00000000" }
//Settings properties & functions
property int playerIndex: 0
function openSettings(player_index){
root.playerIndex = player_index
//Set active player
root.playerIndex = player_index;
//Update setting components
settingLoopSwitch.checked = soundboard1.soundboardPlayers.itemAt(playerIndex).isLooped;
settingPlayRegionEnabledSwitch.checked = soundboard1.soundboardPlayers.itemAt(playerIndex).isPlayRegionEnabled;
settingPlayRegionRange.regionBegin = soundboard1.soundboardPlayers.itemAt(playerIndex).playRegionBegin;
settingPlayRegionRange.regionEnd = soundboard1.soundboardPlayers.itemAt(playerIndex).playRegionEnd;
settingPlayRegionRange.duration = soundboard1.soundboardPlayers.itemAt(playerIndex).duration;
//open settings drawer
root.open();
}
signal settingChanged (var role, var settingValue)
onSettingChanged: {
switch (role) {
case CasterPlayerModel.IsLoopedRole:
soundboard1.soundboardPlayers.itemAt(playerIndex).isLooped = settingValue;
break;
case CasterPlayerModel.IsPlayingRegionEnabledRole:
soundboard1.soundboardPlayers.itemAt(playerIndex).isPlayRegionEnabled = settingValue;
break;
case CasterPlayerModel.TriggerStyleRole:
soundboard1.soundboardPlayers.itemAt(playerIndex).triggerStyle = settingValue;
break;
case CasterPlayerModel.PlayRegionBeginRole:
soundboard1.soundboardPlayers.itemAt(playerIndex).playRegionBegin = settingValue;
break;
case CasterPlayerModel.PlayRegionEndRole:
soundboard1.soundboardPlayers.itemAt(playerIndex).playRegionEnd = settingValue;
break;
}
}
// Settings subcomponents
Pane {
id: header
width: parent.width; height: 60
@ -42,6 +75,7 @@ Drawer {
}
Rectangle {
id: settingsArea
anchors.top: header.bottom
width: parent.width; height: parent.height
color: "#DF333333"
@ -55,15 +89,15 @@ Drawer {
Column {
id: columnView
anchors.fill: parent
width: root.width;
spacing: 8
Item {
Item {//Action: Remove Player
width: parent.width; height: 50
Subcomponent.BootstrapButton {
anchors.centerIn: parent
text: 'Delete Player'; type: 'danger'
text: 'Remove Player'; type: 'danger'
onClicked: {
casterPlayerController.removeItemAt(root.playerIndex);
root.close();
@ -71,6 +105,77 @@ Drawer {
}
}
Item {//Setting: isLooped
width: parent.width; height:100
Subcomponent.FlatSwitch {
id: settingLoopSwitch
anchors.centerIn: parent
questionText: "Loop sound?"
checkedText: "YES"
uncheckedText: "NO"
onToggled: {
root.settingChanged(CasterPlayerModel.IsLoopedRole, checked);
}
}
}
Item {//Setting: isPlayRegionEnabled
width: parent.width; height:100
Subcomponent.FlatSwitch {
id: settingPlayRegionEnabledSwitch
anchors.centerIn: parent
questionText: "Play region:"
onToggled: {
root.settingChanged(CasterPlayerModel.IsPlayingRegionEnabledRole, checked);
}
}
}
Item {//Setting: play region time range
width: parent.width; height:100
Subcomponent.TimeRangeSelector {
id: settingPlayRegionRange
anchors.centerIn: parent
onRegionBeginChanged: {
root.settingChanged(CasterPlayerModel.PlayRegionBeginRole, regionBegin);
}
onRegionEndChanged: {
root.settingChanged(CasterPlayerModel.PlayRegionEndRole, regionEnd);
}
}
}
Item {//Setting: Trigger Style
width: parent.width; height: 100
Subcomponent.StateSelector {
id: settingTriggerStyle
anchors.centerIn: parent
label: "Test label"
list: ListModel {
ListElement {
name: "Play/Pause"
}
ListElement {
name: "Play/Stop"
}
ListElement {
name: "Play Again"
}
}
onSelectedIndexChanged: {
root.settingChanged(CasterPlayerModel.TriggerStyleRole, selectedIndex);
}
}
}
}

View File

@ -0,0 +1,135 @@
import QtQuick 2.7
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
Item {
id: root
// Component properties
width: parent.width; height: parent.height
state: "unchecked"
// Switch Properties & events
property bool checked: false
property string questionText: "State:"
property alias questionTextFont: question.font
property string checkedText: "ON"
property string uncheckedText: "OFF"
signal toggled
onToggled: {
switch(root.checked){
case false:
root.checked = true;
break;
case true:
root.checked = false;
break;
}
}
onCheckedChanged: {
switch(root.checked){
case false:
root.state = "unchecked";
break;
case true:
root.state = "checked";
break;
}
}
states: [
State {
name: "unchecked"
PropertyChanges { target: background; color: "#434343" }
},
State {
name: "checked"
PropertyChanges { target: background; color: "#764ba2" }
}
]
transitions: [
Transition {
from: "unchecked"; to: "checked"
NumberAnimation { target: handle; properties: "x"; from: 0; to: switchContainer.width - handle.width; duration: 70 }
ColorAnimation {
target: background
properties: "color"
from: "#434343"
to: "#764ba2"
duration: 150
}
},
Transition {
from: "checked"; to: "unchecked"
NumberAnimation { target: handle; properties: "x"; from: switchContainer.width - handle.width; to: 0; duration: 70 }
ColorAnimation {
target: background
properties: "color"
from: "#764ba2"
to: "#434343"
duration: 150
}
}
]
Column {
id: gridContainer
width: root.width
height: root.height
spacing: 8
Item {
id: questionContainer
x: (parent.width - this.width)/2
width: question.width; height: 0.5 * parent.height
Text {
id: question
y: (questionContainer.height - this.height)/2
color: "white"
font.bold: true
font.pointSize: 24
text: root.questionText
}
}
Item {
id: switchContainer
x: (parent.width - this.width)/2
width: 120; height: 0.5 * parent.height
Rectangle {
id: background
width: parent.width; height: parent.height
radius: parent.height
border.color: "white"
border.width: 2
}
Text {
x: root.checked ? (switchContainer.width - handle.width - this.width) : handle.width; y: (switchContainer.height - this.height)/2
color: "white"
font.bold: true
font.pointSize: 24
text: root.checked ? qsTr(root.checkedText) : qsTr(root.uncheckedText)
}
Rectangle {
id: handle
width: parent.height; height: parent.height
radius: parent.height
border.color: "white"
border.width: 2
color: "#667eea"
}
MouseArea {
width: parent.width; height: parent.height
onClicked: root.toggled()
}
}
}
}

View File

@ -0,0 +1,83 @@
import QtQuick 2.7
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
Item {
id: selector
property alias list: view.model
property alias selectedIndex: view.currentIndex
property alias label: labelText.text
property bool expanded
width: parent.width; height: parent.height
Rectangle {
anchors { left: parent.left; right: parent.right; bottom: parent.bottom; }
height: labelText.implicitHeight + 4 + (expanded ? 20 * view.count : 20)
Behavior on height { NumberAnimation { duration: 300 } }
radius: 2
border.width: 1
border.color: "yellow"
color: "yellow"
MouseArea {
anchors.fill: parent
onClicked: selector.expanded = !selector.expanded
Text {
id: labelText
anchors { left: parent.left; top: parent.top; margins: 2 }
}
Rectangle {
anchors {
left: parent.left; top: labelText.bottom;
right: parent.right; bottom: parent.bottom;
margins: 2
leftMargin: 10
}
radius: 2
color: "white"
ListView {
id: view
anchors.fill: parent
clip: true
delegate: Text {
anchors { left: parent.left; right: parent.right }
height: 20
verticalAlignment: Text.AlignVCenter
text: modelData
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
selector.expanded = !selector.expanded
}
}
}
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
height: 20
radius: 2
color: "yellow"
}
}
}
}
}
}

View File

@ -0,0 +1,152 @@
import QtQuick 2.7
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import "./" as Subcomponent
Item {
id: root
// Component properties
width: parent.width; height: parent.height
// Properties, functions & events
property int regionBegin: 0
onRegionBeginChanged: beginInput.text = root.msToProperTime(root.regionBegin)
property int regionEnd: 0
onRegionEndChanged: endInput.text = root.msToProperTime(root.regionEnd)
property int duration: 0
property string labelText: "Set play region range:"
function msToProperTime(msTime){
var secs = (msTime / 1000 - (msTime % 1000) / 1000) % 60;
var mins = ((msTime / 1000 - (msTime % 1000) / 1000) - secs) / 60;
return ("00" + mins).slice(-2) + ':' + ("00" + secs).slice(-2);
}
function properTimeToMs(properTime){
var ms = 0;
var time = properTime.split(':');
if(time.length === 2){
ms = parseInt(time[0], 10) * 60 * 1000 + parseInt(time[1], 10) * 1000;
}
return ms;
}
// Component UI
Column {
id: columnContainer
width: root.width
height: root.height
spacing: 8
Item {
id: labelContainer
x: (parent.width - this.width)/2
width: label.width; height: 0.33 * parent.height
Text {
id: label
y: (labelContainer.height - this.height)/2
color: "white"
font.bold: true
font.pointSize: 24
text: root.labelText
}
}
Item {
id: rangeContainer
width: parent.width; height: 0.33 * parent.height
Row {
anchors.centerIn: parent
Text {
id: beginLabel
color: "white"
font.bold: true
font.pointSize: 24
text: "BEGIN:"
}
Item {
width: 80; height: parent.height
clip: true
Rectangle {
width: parent.width; height: parent.height
color: "white"
}
TextInput {
id: beginInput
width: parent.width; height: parent.height
font.bold: true
font.pointSize: 20
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: root.msToProperTime(root.regionBegin)
}
}
Text {
id: endLabel
color: "white"
font.bold: true
font.pointSize: 24
text: "END:"
}
Item {
width: 80; height: parent.height
clip: true
Rectangle {
width: parent.width; height: parent.height
color: "white"
}
TextInput {
id: endInput
width: parent.width; height: parent.height
font.bold: true
font.pointSize: 20
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: root.msToProperTime(root.regionEnd)
}
}
}
}
Item {
width: parent.width; height: 0.33 * parent.height
Subcomponent.BootstrapButton {
id: setRangeButton
width: 100; height: parent.height
anchors.centerIn: parent
text: 'Set Range'; type: 'info'
onClicked: {
var beginTemp = root.properTimeToMs(beginInput.text);
var endTemp = root.properTimeToMs(endInput.text);
if(0 <= beginTemp && beginTemp < root.duration && beginTemp < endTemp){
if(0 < endTemp && beginTemp < endTemp && endTemp <= root.duration){
root.regionBegin = beginTemp;
root.regionEnd = endTemp;
}
}
// Update Inputs
beginInput.text = root.msToProperTime(root.regionBegin);
endInput.text = root.msToProperTime(root.regionEnd);
}
}
}
}
}

View File

@ -4,6 +4,8 @@ import QtGraphicalEffects 1.0
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
import MVC_CasterPlayer 1.0
import "./components/caster_board" as CasterBoard
import "./components/caster_player_settings_drawer" as CasterPlayerSettingsDrawer
@ -22,9 +24,7 @@ ApplicationWindow {
height: 600
color: "#4D4D4D"
CasterPlayerSettingsDrawer.Component {
id: casterPlayerSettingsDrawer
}
CasterPlayerSettingsDrawer.Component { id: casterPlayerSettingsDrawer }
Rectangle {
id: mainSideNav
@ -234,7 +234,7 @@ ApplicationWindow {
currentIndex: mainSoundboardsContainer_tabBar.currentIndex
Item {
id: tab1
CasterBoard.Component {}
CasterBoard.Component {id: soundboard1 }
}
Item {
id: tab2