utilities/record: select mode
This commit is contained in:
parent
9a92ad2d62
commit
4f54763e02
11 changed files with 392 additions and 18 deletions
|
|
@ -8,6 +8,7 @@ MouseArea {
|
||||||
property bool disabled
|
property bool disabled
|
||||||
property color color: Colours.palette.m3onSurface
|
property color color: Colours.palette.m3onSurface
|
||||||
property real radius: parent?.radius ?? 0
|
property real radius: parent?.radius ?? 0
|
||||||
|
property alias rect: hoverLayer
|
||||||
|
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
86
components/controls/IconTextButton.qml
Normal file
86
components/controls/IconTextButton.qml
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import ".."
|
||||||
|
import qs.services
|
||||||
|
import qs.config
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
Filled,
|
||||||
|
Tonal,
|
||||||
|
Text
|
||||||
|
}
|
||||||
|
|
||||||
|
property alias icon: iconLabel.text
|
||||||
|
property alias text: label.text
|
||||||
|
property bool checked
|
||||||
|
property bool toggle
|
||||||
|
property real horizontalPadding: Appearance.padding.normal
|
||||||
|
property real verticalPadding: Appearance.padding.smaller
|
||||||
|
property alias font: label.font
|
||||||
|
property int type: IconTextButton.Filled
|
||||||
|
|
||||||
|
property alias stateLayer: stateLayer
|
||||||
|
property alias iconLabel: iconLabel
|
||||||
|
property alias label: label
|
||||||
|
|
||||||
|
property bool internalChecked
|
||||||
|
property color activeColour: type == IconTextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
|
||||||
|
property color inactiveColour: type == IconTextButton.Filled ? Colours.palette.m3surfaceContainer : Colours.palette.m3secondaryContainer
|
||||||
|
property color activeOnColour: type == IconTextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary
|
||||||
|
property color inactiveOnColour: type == IconTextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
onCheckedChanged: internalChecked = checked
|
||||||
|
|
||||||
|
radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2
|
||||||
|
color: type == IconTextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour
|
||||||
|
|
||||||
|
implicitWidth: row.implicitWidth + horizontalPadding * 2
|
||||||
|
implicitHeight: row.implicitHeight + verticalPadding * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
if (root.toggle)
|
||||||
|
root.internalChecked = !root.internalChecked;
|
||||||
|
root.onClicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: iconLabel
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
|
||||||
|
fill: root.internalChecked ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on fill {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on radius {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
components/controls/Menu.qml
Normal file
111
components/controls/Menu.qml
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import ".."
|
||||||
|
import "../effects"
|
||||||
|
import qs.services
|
||||||
|
import qs.config
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Elevation {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property list<MenuItem> items
|
||||||
|
property MenuItem active: items[0] ?? null
|
||||||
|
property bool expanded
|
||||||
|
|
||||||
|
signal itemSelected(item: MenuItem)
|
||||||
|
|
||||||
|
radius: Appearance.rounding.small / 2
|
||||||
|
level: 2
|
||||||
|
|
||||||
|
implicitWidth: column.implicitWidth
|
||||||
|
implicitHeight: root.expanded ? column.implicitHeight : 0
|
||||||
|
opacity: root.expanded ? 1 : 0
|
||||||
|
|
||||||
|
StyledClippingRect {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: parent.radius
|
||||||
|
color: Colours.palette.m3surfaceContainer
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.items
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: item
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property MenuItem modelData
|
||||||
|
readonly property bool active: modelData === root.active
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.normal * 2
|
||||||
|
implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.normal * 2
|
||||||
|
|
||||||
|
color: Qt.alpha(Colours.palette.m3secondaryContainer, active ? 1 : 0)
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
|
||||||
|
disabled: !root.expanded
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
root.itemSelected(item.modelData);
|
||||||
|
root.active = item.modelData;
|
||||||
|
root.expanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: menuOptionRow
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.normal
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text: item.modelData.icon
|
||||||
|
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurfaceVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: item.modelData.text
|
||||||
|
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
active: item.modelData.trailingIcon.length > 0
|
||||||
|
visible: active
|
||||||
|
|
||||||
|
sourceComponent: MaterialIcon {
|
||||||
|
text: item.modelData.trailingIcon
|
||||||
|
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
components/controls/MenuItem.qml
Normal file
11
components/controls/MenuItem.qml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
required property string text
|
||||||
|
property string icon
|
||||||
|
property string trailingIcon
|
||||||
|
property string activeIcon: icon
|
||||||
|
property string activeText: text
|
||||||
|
|
||||||
|
signal clicked
|
||||||
|
}
|
||||||
141
components/controls/SplitButton.qml
Normal file
141
components/controls/SplitButton.qml
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
import ".."
|
||||||
|
import qs.services
|
||||||
|
import qs.config
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
Filled,
|
||||||
|
Tonal
|
||||||
|
}
|
||||||
|
|
||||||
|
property real horizontalPadding: Appearance.padding.normal
|
||||||
|
property real verticalPadding: Appearance.padding.smaller
|
||||||
|
property int type: SplitButton.Filled
|
||||||
|
property alias menuItems: menu.items
|
||||||
|
property alias active: menu.active
|
||||||
|
property alias expanded: menu.expanded
|
||||||
|
property alias menu: menu
|
||||||
|
|
||||||
|
property color colour: type == SplitButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondaryContainer
|
||||||
|
property color textColour: type == SplitButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondaryContainer
|
||||||
|
|
||||||
|
spacing: Math.floor(Appearance.spacing.small / 2)
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
radius: implicitHeight / 2
|
||||||
|
topRightRadius: Appearance.rounding.small / 2
|
||||||
|
bottomRightRadius: Appearance.rounding.small / 2
|
||||||
|
color: root.colour
|
||||||
|
|
||||||
|
implicitWidth: textRow.implicitWidth + root.horizontalPadding * 2
|
||||||
|
implicitHeight: expandBtn.implicitHeight
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
rect.topRightRadius: parent.topRightRadius
|
||||||
|
rect.bottomRightRadius: parent.bottomRightRadius
|
||||||
|
color: root.textColour
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
root.active?.clicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: textRow
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4)
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: iconLabel
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
animate: true
|
||||||
|
text: root.active?.activeIcon ?? ""
|
||||||
|
color: root.textColour
|
||||||
|
fill: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.preferredWidth: implicitWidth
|
||||||
|
animate: true
|
||||||
|
text: root.active?.activeText ?? ""
|
||||||
|
color: root.textColour
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Behavior on Layout.preferredWidth {
|
||||||
|
Anim {
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: expandBtn
|
||||||
|
|
||||||
|
property real rad: root.expanded ? implicitHeight / 2 : Appearance.rounding.small / 2
|
||||||
|
|
||||||
|
radius: implicitHeight / 2
|
||||||
|
topLeftRadius: rad
|
||||||
|
bottomLeftRadius: rad
|
||||||
|
color: root.colour
|
||||||
|
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: expandStateLayer
|
||||||
|
|
||||||
|
rect.topRightRadius: parent.topRightRadius
|
||||||
|
rect.bottomRightRadius: parent.bottomRightRadius
|
||||||
|
color: root.textColour
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
root.expanded = !root.expanded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: expandIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: root.expanded ? 0 : -Math.floor(root.verticalPadding / 4)
|
||||||
|
|
||||||
|
text: "expand_more"
|
||||||
|
color: root.textColour
|
||||||
|
rotation: root.expanded ? 180 : 0
|
||||||
|
|
||||||
|
Behavior on anchors.horizontalCenterOffset {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on rotation {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on rad {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
|
||||||
|
anchors.top: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: Appearance.spacing.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,16 +18,16 @@ StyledRect {
|
||||||
property real horizontalPadding: Appearance.padding.normal
|
property real horizontalPadding: Appearance.padding.normal
|
||||||
property real verticalPadding: Appearance.padding.smaller
|
property real verticalPadding: Appearance.padding.smaller
|
||||||
property alias font: label.font
|
property alias font: label.font
|
||||||
property int type: IconButton.Filled
|
property int type: TextButton.Filled
|
||||||
|
|
||||||
property alias stateLayer: stateLayer
|
property alias stateLayer: stateLayer
|
||||||
property alias label: label
|
property alias label: label
|
||||||
|
|
||||||
property bool internalChecked
|
property bool internalChecked
|
||||||
property color activeColour: type == IconButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
|
property color activeColour: type == TextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary
|
||||||
property color inactiveColour: type == IconButton.Filled ? Colours.palette.m3surfaceContainer : Colours.palette.m3secondaryContainer
|
property color inactiveColour: type == TextButton.Filled ? Colours.palette.m3surfaceContainer : Colours.palette.m3secondaryContainer
|
||||||
property color activeOnColour: type == IconButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary
|
property color activeOnColour: type == TextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary
|
||||||
property color inactiveOnColour: type == IconButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer
|
property color inactiveOnColour: type == TextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer
|
||||||
|
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ StyledRect {
|
||||||
onCheckedChanged: internalChecked = checked
|
onCheckedChanged: internalChecked = checked
|
||||||
|
|
||||||
radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2
|
radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2
|
||||||
color: type == IconButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour
|
color: type == TextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour
|
||||||
|
|
||||||
implicitWidth: label.implicitWidth + horizontalPadding * 2
|
implicitWidth: label.implicitWidth + horizontalPadding * 2
|
||||||
implicitHeight: label.implicitHeight + verticalPadding * 2
|
implicitHeight: label.implicitHeight + verticalPadding * 2
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@ JsonObject {
|
||||||
property Sizes sizes: Sizes {}
|
property Sizes sizes: Sizes {}
|
||||||
|
|
||||||
component Sizes: JsonObject {
|
component Sizes: JsonObject {
|
||||||
property int width: 400
|
property int width: 430
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ Item {
|
||||||
Record {
|
Record {
|
||||||
props: root.props
|
props: root.props
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
|
z: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggles {
|
Toggles {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Item {
|
||||||
readonly property PersistentProperties props: PersistentProperties {
|
readonly property PersistentProperties props: PersistentProperties {
|
||||||
property bool recordingListExpanded: false
|
property bool recordingListExpanded: false
|
||||||
property string recordingConfirmDelete
|
property string recordingConfirmDelete
|
||||||
|
property string recordingMode
|
||||||
|
|
||||||
reloadableId: "utilities"
|
reloadableId: "utilities"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ StyledRect {
|
||||||
|
|
||||||
required property var props
|
required property var props
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
property bool modePickerExpanded
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
|
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
|
||||||
|
|
@ -34,6 +35,7 @@ StyledRect {
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: Appearance.spacing.normal
|
spacing: Appearance.spacing.normal
|
||||||
|
z: 1
|
||||||
|
|
||||||
StyledRect {
|
StyledRect {
|
||||||
implicitWidth: implicitHeight
|
implicitWidth: implicitHeight
|
||||||
|
|
@ -77,16 +79,36 @@ StyledRect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
SplitButton {
|
||||||
icon: "not_started"
|
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
|
||||||
checked: Recorder.running
|
menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text
|
||||||
type: IconButton.Filled
|
|
||||||
inactiveColour: Colours.palette.m3surfaceContainerHighest
|
|
||||||
toggle: true
|
|
||||||
|
|
||||||
function onClicked(): void {
|
menuItems: [
|
||||||
Recorder.toggle();
|
MenuItem {
|
||||||
}
|
icon: "fullscreen"
|
||||||
|
text: qsTr("Record fullscreen")
|
||||||
|
activeText: qsTr("Fullscreen")
|
||||||
|
onClicked: Recorder.toggle()
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
icon: "screenshot_region"
|
||||||
|
text: qsTr("Record region")
|
||||||
|
activeText: qsTr("Region")
|
||||||
|
onClicked: Recorder.toggle(["-r"])
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
icon: "select_to_speak"
|
||||||
|
text: qsTr("Record fullscreen with sound")
|
||||||
|
activeText: qsTr("Fullscreen")
|
||||||
|
onClicked: Recorder.toggle(["-s"])
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
icon: "volume_up"
|
||||||
|
text: qsTr("Record region with sound")
|
||||||
|
activeText: qsTr("Region")
|
||||||
|
onClicked: Recorder.toggle(["-sr"])
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ Singleton {
|
||||||
readonly property alias running: props.running
|
readonly property alias running: props.running
|
||||||
readonly property alias paused: props.paused
|
readonly property alias paused: props.paused
|
||||||
|
|
||||||
function toggle(): void {
|
function toggle(extraArgs: list<string>): void {
|
||||||
Quickshell.execDetached(["caelestia", "record"]);
|
Quickshell.execDetached(["caelestia", "record", ...extraArgs]);
|
||||||
props.running = !props.running;
|
props.running = !props.running;
|
||||||
if (!props.running)
|
if (!props.running)
|
||||||
props.paused = false;
|
props.paused = false;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue