diff --git a/.github/workflows/windows-mingw.yml b/.github/workflows/windows-mingw.yml index 1efbead..506837f 100644 --- a/.github/workflows/windows-mingw.yml +++ b/.github/workflows/windows-mingw.yml @@ -66,7 +66,7 @@ jobs: - name: package id: package env: - archiveName: ${{ env.fileName }}-${{ matrix.qt_ver }}-${{ matrix.qt_arch }} + archiveName: ${{ env.fileName }}-${{ matrix.qt_arch }}-${{ matrix.qt_ver }} shell: pwsh run: | & scripts\windows-mingw-publish.ps1 ${env:archiveName} ${env:targetName} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9f12c29..43ce294 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -67,7 +67,7 @@ jobs: - name: package id: package env: - archiveName: ${{ env.fileName }}-${{ matrix.qt_ver }}-${{ matrix.qt_arch }} + archiveName: ${{ env.fileName }}-${{ matrix.qt_arch }}-${{ matrix.qt_ver }} msvcArch: ${{ matrix.msvc_arch }} shell: pwsh run: | diff --git a/example/T_MediaPlayer.qml b/example/T_MediaPlayer.qml index bb2391c..a44196b 100644 --- a/example/T_MediaPlayer.qml +++ b/example/T_MediaPlayer.qml @@ -30,8 +30,8 @@ FluScrollablePage{ FluMediaPlayer{ id:player - source:"http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4" -// source:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" +// source:"http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4" + source:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" // source:"http://video.chinanews.com/flv/2019/04/23/400/111773_web.mp4" } diff --git a/example/T_TabView.qml b/example/T_TabView.qml new file mode 100644 index 0000000..242fe37 --- /dev/null +++ b/example/T_TabView.qml @@ -0,0 +1,27 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Window 2.15 +import FluentUI 1.0 + +FluScrollablePage{ + + title:"TabView" + + + FluArea{ + width: parent.width + Layout.topMargin: 20 + height: 400 + paddings: 10 + + + FluTabView{ + + } + + + } + + +} diff --git a/example/T_Theme.qml b/example/T_Theme.qml index aff8713..b19046c 100644 --- a/example/T_Theme.qml +++ b/example/T_Theme.qml @@ -13,10 +13,10 @@ FluScrollablePage{ Layout.topMargin: 20 Repeater{ model: [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green] - delegate: Rectangle{ + delegate: FluRectangle{ width: 42 height: 42 - radius: 4 + radius: [4,4,4,4] color: mouse_item.containsMouse ? Qt.lighter(modelData.normal,1.1) : modelData.normal FluIcon { anchors.centerIn: parent diff --git a/example/page/MainPage.qml b/example/page/MainPage.qml index ef249fc..f3beb0f 100644 --- a/example/page/MainPage.qml +++ b/example/page/MainPage.qml @@ -161,6 +161,13 @@ FluWindow { title:"Navigation" } + FluPaneItem{ + title:"TabView" + onTap:{ + nav_view.push("qrc:/T_TabView.qml") + } + } + FluPaneItem{ title:"TreeView" onTap:{ diff --git a/example/qml.qrc b/example/qml.qrc index 2f04bfc..a014aa2 100644 --- a/example/qml.qrc +++ b/example/qml.qrc @@ -45,5 +45,6 @@ T_ColorPicker.qml T_Carousel.qml T_MediaPlayer.qml + T_TabView.qml diff --git a/src/Fluent.cpp b/src/Fluent.cpp index 97a366f..7d99eae 100644 --- a/src/Fluent.cpp +++ b/src/Fluent.cpp @@ -32,6 +32,7 @@ void Fluent::registerTypes(const char *uri){ qmlRegisterType(uri,major,minor,"WindowHelper"); qmlRegisterType(uri,major,minor,"FluColorSet"); + qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTabView.qml"),uri,major,minor,"FluTabView"); qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluArea.qml"),uri,major,minor,"FluArea"); qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluBadge.qml"),uri,major,minor,"FluBadge"); qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMediaPlayer.qml"),uri,major,minor,"FluMediaPlayer"); diff --git a/src/controls/FluAppBar.qml b/src/controls/FluAppBar.qml index 749e04d..7bc39ef 100644 --- a/src/controls/FluAppBar.qml +++ b/src/controls/FluAppBar.qml @@ -1,13 +1,25 @@ import QtQuick 2.15 +import QtQuick.Controls 2.15 import QtQuick.Window 2.15 import QtQuick.Layouts 1.15 import FluentUI 1.0 Rectangle{ - id:root - + property string title: "标题" + property color textColor: FluTheme.isDark ? "#000000" : "#FFFFFF" + property bool showDark: false + property bool showFps: false + property var window: Window.window property color borerlessColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + property bool resizable: { + if(window == null){ + return false + } + return !(window.minimumHeight === window.maximumHeight && window.maximumWidth === window.minimumWidth) + } + + id:root color: { if(Window.window == null) return borerlessColor @@ -15,7 +27,6 @@ Rectangle{ } visible: FluTheme.isFrameless height: visible ? 34 : 0 - width: { if(parent==null) return 200 @@ -23,19 +34,7 @@ Rectangle{ } z: 65535 clip: true - property string title: "标题" - property color textColor: FluTheme.isDark ? "#000000" : "#FFFFFF" - property bool showDark: false - property bool showFps: false - property var window: Window.window - - property bool resizable: { - if(window == null){ - return false - } - return !(window.minimumHeight === window.maximumHeight && window.maximumWidth === window.minimumWidth) - } TapHandler { onTapped: if (tapCount === 2) toggleMaximized() @@ -48,16 +47,6 @@ Rectangle{ onActiveChanged: if (active) { window.startSystemMove(); } } - function toggleMaximized() { - if(!resizable) - return - if (window.visibility === Window.Maximized) { - window.showNormal(); - } else { - window.showMaximized(); - } - } - FluText { text: title anchors{ @@ -149,4 +138,14 @@ Rectangle{ anchors.bottom: parent.bottom; } + function toggleMaximized() { + if(!resizable) + return + if (window.visibility === Window.Maximized) { + window.showNormal(); + } else { + window.showMaximized(); + } + } + } diff --git a/src/controls/FluArea.qml b/src/controls/FluArea.qml index 4b4a066..91daddd 100644 --- a/src/controls/FluArea.qml +++ b/src/controls/FluArea.qml @@ -2,12 +2,6 @@ import FluentUI 1.0 Rectangle { - radius: 4 - color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1) - border.color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1) - border.width: 1 - implicitHeight: height - implicitWidth: width default property alias content: container.data property int paddings : 0 @@ -16,6 +10,13 @@ Rectangle { property int topPadding : 0 property int bottomPadding : 0 + radius: 4 + color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1) + border.color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1) + border.width: 1 + implicitHeight: height + implicitWidth: width + Item { id: container anchors.fill: parent diff --git a/src/controls/FluBadge.qml b/src/controls/FluBadge.qml index c2581b3..cfc47b1 100644 --- a/src/controls/FluBadge.qml +++ b/src/controls/FluBadge.qml @@ -6,7 +6,6 @@ Rectangle{ property bool showZero: true property int count: 0 - id:control color:Qt.rgba(255/255,77/255,79/255,1) width: { diff --git a/src/controls/FluCalendarPicker.qml b/src/controls/FluCalendarPicker.qml index dd1d03a..86aff99 100644 --- a/src/controls/FluCalendarPicker.qml +++ b/src/controls/FluCalendarPicker.qml @@ -6,13 +6,12 @@ import FluentUI 1.0 Rectangle { - id:root - property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1) property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1) property var window : Window.window + id:root color: { if(mouse_area.containsMouse){ return hoverColor diff --git a/src/controls/FluCalendarView.qml b/src/controls/FluCalendarView.qml index d7b5129..a2694b6 100644 --- a/src/controls/FluCalendarView.qml +++ b/src/controls/FluCalendarView.qml @@ -4,111 +4,26 @@ import FluentUI 1.0 Item { - id:control - property int displayMode: FluCalendarView.Month - - property var date: new Date() - - property var currentDate : new Date() - - property var toDay: new Date() - - signal dateClicked(var date) - - width: 280 - height: 325 - enum DisplayMode { Month, Year, Decade } + property int displayMode: FluCalendarView.Month + property var date: new Date() + property var currentDate : new Date() + property var toDay: new Date() + signal dateClicked(var date) + + id:control + width: 280 + height: 325 + Component.onCompleted: { updateMouth(date) } - function createItemWeek(name){ - return {type:0,date:new Date(),name:name,isDecade:false} - } - - function createItemDay(date){ - return {type:1,date:date,name:"",isDecade:false} - } - - function createItemMonth(date){ - return {type:2,date:date,name:"",isDecade:false} - } - - function createItemYear(date,isDecade){ - return {type:3,date:date,name:"",isDecade:isDecade} - } - - function updateDecade(date){ - list_model.clear() - var year = date.getFullYear() - const decadeStart = Math.floor(year / 10) * 10; - for(var i = decadeStart ; i< decadeStart+10 ; i++){ - list_model.append(createItemYear(new Date(i,0,1),true)); - } - for(var j = decadeStart+10 ; j< decadeStart+16 ; j++){ - list_model.append(createItemYear(new Date(j,0,1),false)); - } - title.text = decadeStart+"-"+(decadeStart+10) - } - - function updateYear(date){ - list_model.clear() - var year = date.getFullYear() - for(var i = 0 ; i< 12 ; i++){ - list_model.append(createItemMonth(new Date(year,i))); - } - for(var j = 0 ; j< 4 ; j++){ - list_model.append(createItemMonth(new Date(year+1,j))); - } - title.text = year+"年" - } - - function updateMouth(date){ - list_model.clear() - list_model.append([createItemWeek("一"),createItemWeek("二"),createItemWeek("三"),createItemWeek("四"),createItemWeek("五"),createItemWeek("六"),createItemWeek("日")]) - var year = date.getFullYear() - var month = date.getMonth() - var day = date.getDate() - var firstDayOfMonth = new Date(year, month, 1) - var dayOfWeek = firstDayOfMonth.getDay() - var headerSize = (dayOfWeek===0?7:dayOfWeek)-1 - if(headerSize!==0){ - var lastMonthYear = year; - var lastMonthMonth = month - 1 - if (month === 0) { - lastMonthYear = year - 1 - lastMonthMonth = 11 - } - var lastMonthDays = new Date(lastMonthYear, lastMonthMonth+1, 0).getDate() - for (var i = headerSize-1; i >= 0; i--) { - list_model.append(createItemDay(new Date(lastMonthYear, lastMonthMonth,lastMonthDays-i))) - } - } - const lastDayOfMonth = new Date(year, month+1, 0).getDate() - for (let day = 1; day <= lastDayOfMonth; day++) { - list_model.append(createItemDay(new Date(year, month,day))) - } - var footerSize = 49-list_model.count - var nextMonthYear = year - var nextMonth = month + 1 - if (month === 11) { - nextMonthYear = year + 1 - nextMonth = 0 - } - const nextDayOfMonth = new Date(nextMonthYear, nextMonth+1, 0).getDate() - for (let j = 1; j <= footerSize; j++) { - list_model.append(createItemDay(new Date(nextMonthYear, nextMonth,j))) - } - title.text = year+"年"+(month+1)+"月" - } - - Component{ id:com_week Item{ @@ -473,4 +388,86 @@ Item { } } } + + function createItemWeek(name){ + return {type:0,date:new Date(),name:name,isDecade:false} + } + + function createItemDay(date){ + return {type:1,date:date,name:"",isDecade:false} + } + + function createItemMonth(date){ + return {type:2,date:date,name:"",isDecade:false} + } + + function createItemYear(date,isDecade){ + return {type:3,date:date,name:"",isDecade:isDecade} + } + + function updateDecade(date){ + list_model.clear() + var year = date.getFullYear() + const decadeStart = Math.floor(year / 10) * 10; + for(var i = decadeStart ; i< decadeStart+10 ; i++){ + list_model.append(createItemYear(new Date(i,0,1),true)); + } + for(var j = decadeStart+10 ; j< decadeStart+16 ; j++){ + list_model.append(createItemYear(new Date(j,0,1),false)); + } + title.text = decadeStart+"-"+(decadeStart+10) + } + + function updateYear(date){ + list_model.clear() + var year = date.getFullYear() + for(var i = 0 ; i< 12 ; i++){ + list_model.append(createItemMonth(new Date(year,i))); + } + for(var j = 0 ; j< 4 ; j++){ + list_model.append(createItemMonth(new Date(year+1,j))); + } + title.text = year+"年" + } + + function updateMouth(date){ + list_model.clear() + list_model.append([createItemWeek("一"),createItemWeek("二"),createItemWeek("三"),createItemWeek("四"),createItemWeek("五"),createItemWeek("六"),createItemWeek("日")]) + var year = date.getFullYear() + var month = date.getMonth() + var day = date.getDate() + var firstDayOfMonth = new Date(year, month, 1) + var dayOfWeek = firstDayOfMonth.getDay() + var headerSize = (dayOfWeek===0?7:dayOfWeek)-1 + if(headerSize!==0){ + var lastMonthYear = year; + var lastMonthMonth = month - 1 + if (month === 0) { + lastMonthYear = year - 1 + lastMonthMonth = 11 + } + var lastMonthDays = new Date(lastMonthYear, lastMonthMonth+1, 0).getDate() + for (var i = headerSize-1; i >= 0; i--) { + list_model.append(createItemDay(new Date(lastMonthYear, lastMonthMonth,lastMonthDays-i))) + } + } + const lastDayOfMonth = new Date(year, month+1, 0).getDate() + for (let day = 1; day <= lastDayOfMonth; day++) { + list_model.append(createItemDay(new Date(year, month,day))) + } + var footerSize = 49-list_model.count + var nextMonthYear = year + var nextMonth = month + 1 + if (month === 11) { + nextMonthYear = year + 1 + nextMonth = 0 + } + const nextDayOfMonth = new Date(nextMonthYear, nextMonth+1, 0).getDate() + for (let j = 1; j <= footerSize; j++) { + list_model.append(createItemDay(new Date(nextMonthYear, nextMonth,j))) + } + title.text = year+"年"+(month+1)+"月" + } + + } diff --git a/src/controls/FluColorView.qml b/src/controls/FluColorView.qml index d74059c..00b69e4 100644 --- a/src/controls/FluColorView.qml +++ b/src/controls/FluColorView.qml @@ -3,11 +3,11 @@ import "../colorpicker" Item { + property alias colorValue: color_picker.colorValue + width: color_picker.width+10 height: color_picker.height - property alias colorValue: color_picker.colorValue - FluArea{ anchors.fill: parent radius: 5 diff --git a/src/controls/FluContentDialog.qml b/src/controls/FluContentDialog.qml index dfbda0f..8cfbbe1 100644 --- a/src/controls/FluContentDialog.qml +++ b/src/controls/FluContentDialog.qml @@ -12,7 +12,6 @@ Popup { property string positiveText: "Positive" signal negativeClicked signal positiveClicked - property var minWidth: { if(Window.window==null) return 400 @@ -111,7 +110,6 @@ Popup { positiveClicked() } } - } } } diff --git a/src/controls/FluContentPage.qml b/src/controls/FluContentPage.qml index aa6051f..980efb8 100644 --- a/src/controls/FluContentPage.qml +++ b/src/controls/FluContentPage.qml @@ -6,11 +6,11 @@ import FluentUI 1.0 Item { - id:root - property alias title: text_title.text default property alias content: container.data + id:root + FluText{ id:text_title fontStyle: FluText.TitleLarge diff --git a/src/controls/FluDatePicker.qml b/src/controls/FluDatePicker.qml index 81d20a7..2876216 100644 --- a/src/controls/FluDatePicker.qml +++ b/src/controls/FluDatePicker.qml @@ -6,15 +6,16 @@ import FluentUI 1.0 Rectangle { - id:root - property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1) property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1) property var window : Window.window - property bool showYear: true + property bool changeFlag: true + readonly property var rowData: ["","",""] + + id:root color: { if(mouse_area.containsMouse){ return hoverColor @@ -367,9 +368,6 @@ Rectangle { } } - property bool changeFlag: true - readonly property var rowData: ["","",""] - function generateYearArray(startYear, endYear) { const yearArray = []; for (let year = startYear; year <= endYear; year++) { diff --git a/src/controls/FluDropDownButton.qml b/src/controls/FluDropDownButton.qml index 29d24b0..c1bea65 100644 --- a/src/controls/FluDropDownButton.qml +++ b/src/controls/FluDropDownButton.qml @@ -9,6 +9,8 @@ Button { property color normalColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1) property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) property color disableColor: FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1) + property var window : Window.window + property alias items: menu.content id: control topPadding:5 @@ -17,9 +19,6 @@ Button { rightPadding:35 enabled: !disabled focusPolicy:Qt.TabFocus - property var window : Window.window - - property alias items: menu.content Keys.onSpacePressed: control.visualFocus&&clicked() diff --git a/src/controls/FluExpander.qml b/src/controls/FluExpander.qml index 18f60d8..0dde665 100644 --- a/src/controls/FluExpander.qml +++ b/src/controls/FluExpander.qml @@ -1,11 +1,13 @@ import QtQuick 2.15 +import QtQuick.Controls 2.15 import FluentUI 1.0 Item { - property string headerText: "Titlte" property bool expand: false + property int contentHeight : 300 + default property alias content: container.data id:root height: layout_header.height + container.height @@ -13,10 +15,6 @@ Item { implicitWidth: width implicitHeight: height - property int contentHeight : 300 - - default property alias content: container.data - Rectangle{ id:layout_header width: parent.width diff --git a/src/controls/FluFilledButton.qml b/src/controls/FluFilledButton.qml index 0c4f617..a959ddd 100644 --- a/src/controls/FluFilledButton.qml +++ b/src/controls/FluFilledButton.qml @@ -3,13 +3,13 @@ import QtQuick.Controls 2.15 import FluentUI 1.0 Button { - id: control property bool disabled: false property color normalColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark property color hoverColor: FluTheme.isDark ? Qt.darker(normalColor,1.1) : Qt.lighter(normalColor,1.1) property color disableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1) + id: control enabled: !disabled topPadding:5 bottomPadding:5 diff --git a/src/controls/FluFocusRectangle.qml b/src/controls/FluFocusRectangle.qml index 1a4d9cd..3faa0f6 100644 --- a/src/controls/FluFocusRectangle.qml +++ b/src/controls/FluFocusRectangle.qml @@ -2,12 +2,13 @@ import FluentUI 1.0 Item { + + property int radius: 4 + id:root anchors.fill: parent anchors.margins: -3 - property var radius: 4 - Rectangle{ width: root.width height: root.height diff --git a/src/controls/FluInfoBar.qml b/src/controls/FluInfoBar.qml index edb8660..cb24167 100644 --- a/src/controls/FluInfoBar.qml +++ b/src/controls/FluInfoBar.qml @@ -7,26 +7,6 @@ FluObject { property var root; property int layoutY: 75; - function showSuccess(text,duration,moremsg){ - mcontrol.create(mcontrol.const_success,text,duration,moremsg ? moremsg : ""); - } - - function showInfo(text,duration,moremsg){ - mcontrol.create(mcontrol.const_info,text,duration,moremsg ? moremsg : ""); - } - - function showWarning(text,duration,moremsg){ - mcontrol.create(mcontrol.const_warning,text,duration,moremsg ? moremsg : ""); - } - - function showError(text,duration,moremsg){ - mcontrol.create(mcontrol.const_error,text,duration,moremsg ? moremsg : ""); - } - - function showCustom(itemcomponent,duration){ - mcontrol.createCustom(itemcomponent,duration); - } - FluObject{ id:mcontrol @@ -34,9 +14,7 @@ FluObject { property string const_info: "info"; property string const_warning: "warning"; property string const_error: "error"; - property int maxWidth: 300; - property var screenLayout: null; function create(type,text,duration,moremsg){ @@ -230,4 +208,25 @@ FluObject { } } + function showSuccess(text,duration,moremsg){ + mcontrol.create(mcontrol.const_success,text,duration,moremsg ? moremsg : ""); + } + + function showInfo(text,duration,moremsg){ + mcontrol.create(mcontrol.const_info,text,duration,moremsg ? moremsg : ""); + } + + function showWarning(text,duration,moremsg){ + mcontrol.create(mcontrol.const_warning,text,duration,moremsg ? moremsg : ""); + } + + function showError(text,duration,moremsg){ + mcontrol.create(mcontrol.const_error,text,duration,moremsg ? moremsg : ""); + } + + function showCustom(itemcomponent,duration){ + mcontrol.createCustom(itemcomponent,duration); + } + + } diff --git a/src/controls/FluItem.qml b/src/controls/FluItem.qml new file mode 100644 index 0000000..cb309d8 --- /dev/null +++ b/src/controls/FluItem.qml @@ -0,0 +1,53 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtGraphicalEffects 1.15 + +Item{ + id:control + property var radius:[0,0,0,0] + default property alias contentItem: container.data + + Item{ + id:container + width: control.width + height: control.height + opacity: 0 + } + + Canvas { + id: canvas + anchors.fill: parent + visible: false + onPaint: { + var ctx = getContext("2d"); + var x = 0; + var y = 0; + var w = control.width; + var h = control.height; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x + radius[0], y); + ctx.lineTo(x + w - radius[1], y); + ctx.arcTo(x + w, y, x + w, y + radius[1], radius[1]); + ctx.lineTo(x + w, y + h - radius[2]); + ctx.arcTo(x + w, y + h, x + w - radius[2], y + h, radius[2]); + ctx.lineTo(x + radius[3], y + h); + ctx.arcTo(x, y + h, x, y + h - radius[3], radius[3]); + ctx.lineTo(x, y + radius[0]); + ctx.arcTo(x, y, x + radius[0], y, radius[0]); + ctx.closePath(); + ctx.fillStyle = control.color; + ctx.fill(); + ctx.restore(); + } + } + + OpacityMask { + anchors.fill: container + source: container + maskSource: canvas + } + +} diff --git a/src/controls/FluMediaPlayer.qml b/src/controls/FluMediaPlayer.qml index 78d328b..2dd0bd6 100644 --- a/src/controls/FluMediaPlayer.qml +++ b/src/controls/FluMediaPlayer.qml @@ -6,14 +6,15 @@ import FluentUI 1.0 Rectangle { property url source + property bool showControl: false + property real volume: 30 + id:control width: 480 height: 270 color: FluColors.Black clip: true - property bool showControl: true - MouseArea{ anchors.fill: parent onClicked: { @@ -37,6 +38,7 @@ Rectangle { onStatusChanged: { if(status===6){ slider.maxValue = mediaplayer.duration + showControl = true } } } @@ -85,6 +87,7 @@ Rectangle { mediaplayer.autoSeek = false mediaplayer.pause() } + value:0 onReleased: { mediaplayer.autoSeek = true mediaplayer.play() @@ -122,24 +125,44 @@ Rectangle { text: formatDuration(mediaplayer.duration) } - FluIconButton{ - iconSize: 15 - iconSource: mediaplayer.playbackState === Audio.PlayingState ? FluentIcons.Pause : FluentIcons.Play + + Row{ + spacing: 10 anchors{ horizontalCenter: parent.horizontalCenter bottom: parent.bottom bottomMargin: 10 } - onClicked: { - if(mediaplayer.playbackState === Audio.PlayingState){ - mediaplayer.pause() - }else{ - mediaplayer.play() + FluIconButton{ + iconSize: 17 + iconSource: FluentIcons.SkipBack10 + onClicked: { + mediaplayer.seek(Math.max(mediaplayer.position-10*1000,0)) + } + } + FluIconButton{ + iconSize: 15 + iconSource: mediaplayer.playbackState === Audio.PlayingState ? FluentIcons.Pause : FluentIcons.Play + onClicked: { + if(mediaplayer.playbackState === Audio.PlayingState){ + mediaplayer.pause() + }else{ + mediaplayer.play() + } + } + } + FluIconButton{ + iconSize: 17 + iconSource: FluentIcons.SkipForward30 + onClicked: { + mediaplayer.seek(Math.min(mediaplayer.position+30*1000,mediaplayer.duration)) } } } + FluIconButton{ + id:btn_volume iconSize: 17 iconSource: mediaplayer.volume ? FluentIcons.Volume : FluentIcons.Mute anchors{ @@ -149,11 +172,24 @@ Rectangle { bottomMargin: 10 } onClicked: { - // FluentIcons.SkipBack10 FluentIcons.SkipForward30 mediaplayer.volume = !mediaplayer.volume } } + FluSlider{ + id:slider_volume + size: 80 + dotSize: 20 + value:30 + anchors{ + left:btn_volume.right + verticalCenter: btn_volume.verticalCenter + leftMargin: 10 + } + onValueChanged:{ + mediaplayer.volume = value/100 + } + } } diff --git a/src/controls/FluMenu.qml b/src/controls/FluMenu.qml index 5a54e57..0242b54 100644 --- a/src/controls/FluMenu.qml +++ b/src/controls/FluMenu.qml @@ -3,9 +3,10 @@ import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 Menu { - id: popup + default property alias content: container.data + id: popup width: 140 height: container.height diff --git a/src/controls/FluMenuItem.qml b/src/controls/FluMenuItem.qml index d165452..2cadb6b 100644 --- a/src/controls/FluMenuItem.qml +++ b/src/controls/FluMenuItem.qml @@ -3,6 +3,9 @@ import QtQuick.Controls 2.15 Item { + property string text: "MenuItem" + signal clicked + id:root width: { if(root.parent){ @@ -12,8 +15,6 @@ Item { } height: 32 - property string text: "MenuItem" - signal clicked Rectangle{ anchors.centerIn: parent diff --git a/src/controls/FluNavigationView.qml b/src/controls/FluNavigationView.qml index 7c50356..b8c483c 100644 --- a/src/controls/FluNavigationView.qml +++ b/src/controls/FluNavigationView.qml @@ -7,17 +7,14 @@ import FluentUI 1.0 Item { - id:root - property FluObject items property FluObject footerItems - property int displayMode: width<=700 ? FluNavigationView.Minimal : FluNavigationView.Open - property bool displaMinimalNav : false - property alias actions: layout_actions.data + id:root + onDisplayModeChanged: { if(displayMode === FluNavigationView.Minimal){ anim_navi.enabled = false diff --git a/src/controls/FluProgressBar.qml b/src/controls/FluProgressBar.qml index 20bb624..3e8cc0b 100644 --- a/src/controls/FluProgressBar.qml +++ b/src/controls/FluProgressBar.qml @@ -2,15 +2,16 @@ import QtQuick.Controls 2.12 FluRectangle { - id: control + property real progress: 0.5 + property bool indeterminate: true + + id: control width: 150 height: 5 radius: [3,3,3,3] clip: true color: FluTheme.isDark ? Qt.rgba(41/255,41/255,41/255,1) : Qt.rgba(214/255,214/255,214/255,1) - property real progress: 0.5 - property bool indeterminate: true Component.onCompleted: { if(indeterminate){ diff --git a/src/controls/FluProgressRing.qml b/src/controls/FluProgressRing.qml index f6bf84f..110d0b0 100644 --- a/src/controls/FluProgressRing.qml +++ b/src/controls/FluProgressRing.qml @@ -2,19 +2,20 @@ import QtQuick.Controls 2.12 Rectangle { - id: control + property real linWidth : 5 + property real progress: 0.25 + property bool indeterminate: true + readonly property real radius2 : radius - linWidth/2 + property color primaryColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + + id: control width: 44 height: 44 radius: 22 border.width: linWidth color: "#00000000" border.color: FluTheme.isDark ? Qt.rgba(41/255,41/255,41/255,1) : Qt.rgba(214/255,214/255,214/255,1) - property real linWidth : 5 - property real progress: 0.25 - property bool indeterminate: true - readonly property real radius2 : radius - linWidth/2 - property color primaryColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark onProgressChanged: { canvas.requestPaint() diff --git a/src/controls/FluRectangle.qml b/src/controls/FluRectangle.qml index 76cb41a..38bab89 100644 --- a/src/controls/FluRectangle.qml +++ b/src/controls/FluRectangle.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 2.15 import QtGraphicalEffects 1.15 Item{ - id:root + id:control property var radius:[0,0,0,0] property color color : "#FFFFFF" property bool shadow: true @@ -11,17 +11,17 @@ Item{ Rectangle{ id:container - width: root.width - height: root.height + width: control.width + height: control.height opacity: 0 - color:root.color + color:control.color } FluShadow{ anchors.fill: container - radius: root.radius[0] + radius: control.radius[0] visible: { - if(root.radius[0] === root.radius[1] && root.radius[0] === root.radius[2] && root.radius[0] === root.radius[3] && root.shadow){ + if(control.radius[0] === control.radius[1] && control.radius[0] === control.radius[2] && control.radius[0] === control.radius[3] && control.shadow){ return true } return false @@ -36,8 +36,8 @@ Item{ var ctx = getContext("2d"); var x = 0; var y = 0; - var w = root.width; - var h = root.height; + var w = control.width; + var h = control.height; ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); @@ -52,7 +52,7 @@ Item{ ctx.lineTo(x, y + radius[0]); ctx.arcTo(x, y, x + radius[0], y, radius[0]); ctx.closePath(); - ctx.fillStyle = root.color; + ctx.fillStyle = control.color; ctx.fill(); ctx.restore(); } diff --git a/src/controls/FluScrollablePage.qml b/src/controls/FluScrollablePage.qml index e0cd536..8fe97a9 100644 --- a/src/controls/FluScrollablePage.qml +++ b/src/controls/FluScrollablePage.qml @@ -6,12 +6,12 @@ import FluentUI 1.0 Item { - id:root - property alias title: text_title.text default property alias content: container.data property int spacing : 5 + id:root + FluText{ id:text_title fontStyle: FluText.TitleLarge diff --git a/src/controls/FluShadow.qml b/src/controls/FluShadow.qml index 490718a..a4c244c 100644 --- a/src/controls/FluShadow.qml +++ b/src/controls/FluShadow.qml @@ -1,12 +1,13 @@ import QtQuick 2.15 Item { + + property color color: FluTheme.isDark ? "#FFFFFF" : "#999999" + property int radius: 4 + id:root anchors.fill: parent anchors.margins: -4 - property color color: FluTheme.isDark ? "#FFFFFF" : "#999999" - - property int radius: 4 Rectangle{ width: root.width diff --git a/src/controls/FluSlider.qml b/src/controls/FluSlider.qml index d7e8c71..df56b2b 100644 --- a/src/controls/FluSlider.qml +++ b/src/controls/FluSlider.qml @@ -23,8 +23,9 @@ Item{ height: control.height width: control.width rotation: isHorizontal ? 0 : 180 + Component.onCompleted: { - seek(0) + seek(value) } MouseArea{ diff --git a/src/controls/FluTabView.qml b/src/controls/FluTabView.qml new file mode 100644 index 0000000..bc621b7 --- /dev/null +++ b/src/controls/FluTabView.qml @@ -0,0 +1,185 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import FluentUI 1.0 + +Item { + + id:control + anchors.fill: { + if(parent) + return parent + return undefined + } + + implicitHeight: height + implicitWidth: width + + enum TabWidthBehavior { + Equal, + SizeToContent, + Compact + } + + enum CloseButtonVisibility{ + Nerver, + Always, + OnHover + } + + property int tabWidthBehavior : FluTabView.Equal + property int closeButtonVisibility : FluTabView.Always + + QtObject { + id: d + property int dragIndex: -1 + property bool dragBehavior: false + } + + + ListModel{ + id:tab_model + ListElement{ + icon:"" + text:"Document0" + } + ListElement{ + icon:"" + text:"Document1" + } + ListElement{ + icon:"" + text:"Document2" + } + } + + ListView{ + id:tab_nav + height: 34 + orientation: ListView.Horizontal + width: parent.width + model: tab_model + move: Transition { + NumberAnimation { properties: "x"; duration: 100; easing.type: Easing.OutCubic } + NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic } + } + moveDisplaced: Transition { + NumberAnimation { properties: "x"; duration: 300; easing.type: Easing.OutCubic} + NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic } + } + clip: true + delegate: Item{ + + width: item_container.width + height: item_container.height + z: item_mouse_drag.pressed ? 1000 : 1 + + Item{ + id:item_layout + width: item_container.width + height: item_container.height + + FluItem{ + id:item_container + + property real timestamp: new Date().getTime() + + height: tab_nav.height + width: item_text.width+30 + radius: [5,5,0,0] + Behavior on x { enabled: d.dragBehavior; NumberAnimation { duration: 200 } } + Behavior on y { enabled: d.dragBehavior; NumberAnimation { duration: 200 } } + + MouseArea{ + id:item_mouse_hove + anchors.fill: parent + hoverEnabled: true + } + + MouseArea{ + id:item_mouse_drag + anchors.fill: parent + drag.target: item_container + drag.axis: Drag.XAxis + + onPressed: { + item_container.timestamp = new Date().getTime(); + d.dragBehavior = false; + var pos = tab_nav.mapFromItem(item_container, 0, 0) + d.dragIndex = model.index + item_container.parent = tab_nav + item_container.x = pos.x + item_container.y = pos.y + } + + onReleased: { + var timeDiff = new Date().getTime() - item_container.timestamp + console.debug(timeDiff) + if (timeDiff < 150) { + tab_nav.currentIndex = index + } + d.dragIndex = -1; + var pos = tab_nav.mapToItem(item_layout, item_container.x, item_container.y) + item_container.parent = item_layout; + item_container.x = pos.x; + item_container.y = pos.y; + d.dragBehavior = true; + item_container.x = 0; + item_container.y = 0; + } + + onPositionChanged: { + var pos = tab_nav.mapFromItem(item_container, 0, 0); + var idx = tab_nav.indexAt(pos.x, pos.y); + if (idx > -1 && idx < tab_nav.count) { + tab_model.move(d.dragIndex, idx, 1) + d.dragIndex = idx; + } + } + } + + Rectangle{ + anchors.fill: parent + color: { + if(FluTheme.isDark){ + if(item_mouse_hove.containsMouse){ + return Qt.rgba(1,1,1,0.03) + } + if(tab_nav.currentIndex === index){ + return Qt.rgba(1,1,1,0.06) + } + return Qt.rgba(0,0,0,0) + }else{ + if(item_mouse_hove.containsMouse){ + return Qt.rgba(0,0,0,0.03) + } + if(tab_nav.currentIndex === index){ + return Qt.rgba(0,0,0,0.06) + } + return Qt.rgba(0,0,0,0) + } + } + } + + FluText{ + id:item_text + anchors.centerIn: parent + text: model.text + rightPadding: 24 + } + + FluIconButton{ + iconSource: FluentIcons.ChromeClose + iconSize: 10 + width: 24 + height: 24 + anchors{ + right: parent.right + rightMargin: 5 + verticalCenter: parent.verticalCenter + } + } + } + } + } + } +} diff --git a/src/controls/FluTextButton.qml b/src/controls/FluTextButton.qml index 5b4b034..f2c91f6 100644 --- a/src/controls/FluTextButton.qml +++ b/src/controls/FluTextButton.qml @@ -5,7 +5,6 @@ import FluentUI 1.0 Button { property bool disabled: false - property color normalColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark property color hoverColor: FluTheme.isDark ? Qt.darker(normalColor,1.3) : Qt.lighter(normalColor,1.3) property color disableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1) diff --git a/src/controls/FluTimePicker.qml b/src/controls/FluTimePicker.qml index e9f0e77..50063ec 100644 --- a/src/controls/FluTimePicker.qml +++ b/src/controls/FluTimePicker.qml @@ -6,22 +6,18 @@ import FluentUI 1.0 Rectangle { - id:root - - property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1) - property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) - property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1) - property var window : Window.window - - property int hourFormat: FluTimePicker.H - - property int isH: hourFormat === FluTimePicker.H - enum HourFormat { H, HH } + property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1) + property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) + property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1) + property var window : Window.window + property int hourFormat: FluTimePicker.H + property int isH: hourFormat === FluTimePicker.H + id:root color: { if(mouse_area.containsMouse){ return hoverColor diff --git a/src/controls/FluTreeView.qml b/src/controls/FluTreeView.qml index 0179445..1edc768 100644 --- a/src/controls/FluTreeView.qml +++ b/src/controls/FluTreeView.qml @@ -6,20 +6,19 @@ import FluentUI 1.0 import QtGraphicalEffects 1.15 Item { - id:root - - property int selectionMode: FluTreeView.None - property var currentElement - property var currentParentElement - property var rootModel: tree_model.get(0).items - signal itemClicked(var item) enum TreeViewSelectionMode { None, Single, Multiple } + property int selectionMode: FluTreeView.None + property var currentElement + property var currentParentElement + property var rootModel: tree_model.get(0).items + signal itemClicked(var item) + id:root ListModel{ id:tree_model ListElement{ diff --git a/src/controls/FluWindow.qml b/src/controls/FluWindow.qml index cef9ccd..b6fb225 100644 --- a/src/controls/FluWindow.qml +++ b/src/controls/FluWindow.qml @@ -6,14 +6,26 @@ import QtGraphicalEffects 1.15 Item { - id:root - + property string title: "FluentUI" + property int minimumWidth + property int maximumWidth + property int minimumHeight + property int maximumHeight + property int modality:0 + signal initArgument(var argument) + property var pageRegister + default property alias content: container.data property var window : { if(Window.window == null) return null return Window.window } - + property int borderless:{ + if(!FluTheme.isFrameless){ + return 0 + } + return (window && (window.visibility === Window.Maximized)) ? 0 : 4 + } property color color: { if(window && window.active){ return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1) @@ -21,25 +33,9 @@ Item { return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1) } - property string title: "FluentUI" - property int minimumWidth - property int maximumWidth - property int minimumHeight - property int maximumHeight - property int modality:0 + id:root - signal initArgument(var argument) - property var pageRegister - - property int borderless:{ - if(!FluTheme.isFrameless){ - return 0 - } - return (window && (window.visibility === Window.Maximized)) ? 0 : 4 - } - - default property alias content: container.data FluWindowResize{ border:borderless diff --git a/src/controls/TFpsMonitor.qml b/src/controls/TFpsMonitor.qml index 53abc4d..671d96e 100644 --- a/src/controls/TFpsMonitor.qml +++ b/src/controls/TFpsMonitor.qml @@ -1,23 +1,23 @@ import QtQuick 2.15 import FluentUI 1.0 - -/*! TODO */ Item { - id: toou2d_fps - width: contentItemLoader.width + 5; - height: contentItemLoader.height + 5; readonly property alias fps: _private.fps; readonly property alias fpsAvg: _private.fpsAvg; - property color color: "#C0C0C0" property Component contentItem: contentComponent; + id: control + width: contentItemLoader.width + 5; + height: contentItemLoader.height + 5; + + + Component{ id:contentComponent FluText{ - color:toou2d_fps.color + color:control.color text: " Avg " + fpsAvg + " | " + fps + " Fps"; } } diff --git a/src/res.qrc b/src/res.qrc index b1b89fc..1a9b6bb 100644 --- a/src/res.qrc +++ b/src/res.qrc @@ -58,5 +58,7 @@ colorpicker/content/PanelBorder.qml colorpicker/content/SBPicker.qml controls/FluMediaPlayer.qml + controls/FluTabView.qml + controls/FluItem.qml