完成全屏应用界面
This commit is contained in:
parent
12cae14527
commit
5754abb725
|
@ -0,0 +1,296 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml.Models 2.12
|
||||
|
||||
import org.ukui.menu.core 1.0
|
||||
import AppControls2 1.0 as AppControls2
|
||||
|
||||
RowLayout {
|
||||
clip: true
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 90
|
||||
Layout.fillHeight: true
|
||||
|
||||
ListView {
|
||||
id: labelListView
|
||||
signal labelClicked(string labelId)
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: contentHeight > parent.height ? parent.height : contentHeight
|
||||
interactive: contentHeight > parent.height
|
||||
spacing: 5
|
||||
model: DelegateModel {
|
||||
groups: DelegateModelGroup {
|
||||
name: "disabledItem"
|
||||
includeByDefault: false
|
||||
}
|
||||
|
||||
items.onChanged: {
|
||||
for (let i = 0; i < items.count;) {
|
||||
let item = items.get(i);
|
||||
if (item.model.isDisable) {
|
||||
items.setGroups(i, 1, "disabledItem");
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
model: modelManager.getLabelModel()
|
||||
delegate: MouseArea {
|
||||
width: ListView.view.width
|
||||
height: 30
|
||||
hoverEnabled: true
|
||||
AppControls2.StyleBackground {
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
paletteRole: Palette.Base
|
||||
alpha: parent.containsPress ? 0.36 : parent.containsMouse ? 0.18 : 0
|
||||
useStyleTransparent: false
|
||||
|
||||
AppControls2.StyleText {
|
||||
anchors.fill: parent
|
||||
paletteRole: Palette.Text
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: model.displayName
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
labelListView.labelClicked(model.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentViewBase
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
property int maxColumns: 8
|
||||
property int columns: {
|
||||
let c = Math.floor(width / cellWidth);
|
||||
return c > maxColumns ? maxColumns : c;
|
||||
}
|
||||
property int cellWidth: 220
|
||||
// property int cellWidth: Math.min(Math.floor(width / columns), 220)
|
||||
property int cellHeight: cellWidth
|
||||
property int headerHeight: 30
|
||||
|
||||
Component.onCompleted: {
|
||||
changeView(modelManager.getLabelGroupModel().containLabel);
|
||||
modelManager.getLabelGroupModel().containLabelChanged.connect(changeView);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
modelManager.getLabelGroupModel().containLabelChanged.disconnect(changeView);
|
||||
contentViewLoader.sourceComponent = undefined;
|
||||
}
|
||||
|
||||
function changeView(toLabelView) {
|
||||
contentViewLoader.sourceComponent = toLabelView ? labelViewComponent : appViewComponent;
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentViewLoader
|
||||
height: parent.height
|
||||
width: contentViewBase.cellWidth * contentViewBase.columns + 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
// view id: 1
|
||||
Component {
|
||||
id: appViewComponent
|
||||
GridView {
|
||||
ScrollBar.vertical: fullScreenScrollBar
|
||||
cellWidth: contentViewBase.cellWidth
|
||||
cellHeight: contentViewBase.cellHeight
|
||||
model: modelManager.getAppModel()
|
||||
delegate: Loader {
|
||||
width: GridView.view.cellWidth
|
||||
height: width
|
||||
property int index: model.index
|
||||
property int type: model.type
|
||||
property string name: model.name
|
||||
property string icon: model.icon
|
||||
sourceComponent: {
|
||||
if (type === DataType.Normal) {
|
||||
return appComponent;
|
||||
}
|
||||
if (type === DataType.Folder) {
|
||||
return folderComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: appComponent
|
||||
MouseArea {
|
||||
anchors.centerIn: parent
|
||||
width: 100
|
||||
height: 140
|
||||
AppControls2.IconLabel {
|
||||
anchors.fill: parent
|
||||
iconWidth: 96
|
||||
iconHeight: 96
|
||||
appName: name
|
||||
appIcon: icon
|
||||
}
|
||||
onClicked: {
|
||||
parent.GridView.view.model.appClicked(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: folderComponent
|
||||
Item {
|
||||
MouseArea {
|
||||
anchors.centerIn: parent
|
||||
width: 100; height: 140
|
||||
AppControls2.IconLabel {
|
||||
anchors.fill: parent
|
||||
iconWidth: 96
|
||||
iconHeight: 96
|
||||
appName: name
|
||||
appIcon: icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// view id: 2
|
||||
Component {
|
||||
id: labelViewComponent
|
||||
Flickable {
|
||||
id: labelViewFlickable
|
||||
ScrollBar.vertical: fullScreenScrollBar
|
||||
contentHeight: labelColumn.height
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
interactive: !contentYAnimation.running
|
||||
|
||||
Column {
|
||||
id: labelColumn
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
Repeater {
|
||||
id: labelRepeater
|
||||
model: modelManager.getLabelGroupModel()
|
||||
delegate: GridView {
|
||||
id: labelAppsGridView
|
||||
width: parent.width
|
||||
height: contentHeight
|
||||
|
||||
property int labelIndex: index
|
||||
|
||||
interactive: false
|
||||
cacheBuffer: 50
|
||||
cellWidth: contentViewBase.cellWidth
|
||||
cellHeight: contentViewBase.cellHeight
|
||||
|
||||
header: Row {
|
||||
width: labelAppsGridView.width
|
||||
height: contentViewBase.headerHeight
|
||||
spacing: 15
|
||||
Text {
|
||||
id: labelName
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: contentWidth
|
||||
text: name
|
||||
}
|
||||
|
||||
AppControls2.StyleBackground {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
paletteRole: Palette.Light
|
||||
height: 1
|
||||
width: parent.width - labelName.width - parent.spacing
|
||||
}
|
||||
}
|
||||
|
||||
model: extraData
|
||||
delegate: Item {
|
||||
width: GridView.view.cellWidth
|
||||
height: GridView.view.cellHeight
|
||||
|
||||
MouseArea {
|
||||
anchors.centerIn: parent
|
||||
width: 100; height: 140
|
||||
AppControls2.IconLabel {
|
||||
anchors.fill: parent
|
||||
iconWidth: 96
|
||||
iconHeight: 96
|
||||
appName: modelData.name
|
||||
appIcon: modelData.icon
|
||||
}
|
||||
onClicked: {
|
||||
//console.log("clicked", Object.keys(model))
|
||||
labelRepeater.model.openApp(labelAppsGridView.labelIndex, model.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: contentYAnimation
|
||||
target: labelViewFlickable
|
||||
property: "contentY"
|
||||
duration: 300
|
||||
onFinished: {
|
||||
labelViewFlickable.returnToBounds();
|
||||
}
|
||||
}
|
||||
|
||||
function scrollerView(labelId) {
|
||||
let labelindex = labelRepeater.model.getLabelIndex(labelId);
|
||||
if (labelindex < 0 || labelindex >= labelRepeater.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nextY = labelRepeater.itemAt(labelindex).y;
|
||||
let sh = labelColumn.height - nextY;
|
||||
if (sh < height) {
|
||||
nextY -= (height - sh);
|
||||
}
|
||||
|
||||
contentYAnimation.running = false;
|
||||
if (nextY === contentY) {
|
||||
return;
|
||||
}
|
||||
|
||||
contentYAnimation.from = contentY;
|
||||
contentYAnimation.to = nextY;
|
||||
contentYAnimation.running = true;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
labelListView.labelClicked.connect(scrollerView);
|
||||
}
|
||||
Component.onDestruction: {
|
||||
labelListView.labelClicked.disconnect(scrollerView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 90
|
||||
Layout.fillHeight: true
|
||||
|
||||
AppControls2.ScrollBar {
|
||||
id: fullScreenScrollBar
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: parent.height
|
||||
width: 20
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
text: qsTr("FullScreenFooter.qml")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import AppControls2 1.0 as AppControls2
|
||||
import org.ukui.menu.core 1.0
|
||||
|
||||
Item {
|
||||
clip: true
|
||||
|
||||
PluginSelectMenu {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 72 // 48+24
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 80
|
||||
height: 48
|
||||
spacing: 8
|
||||
}
|
||||
|
||||
AppControls2.RoundButton {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 48
|
||||
height: 48
|
||||
buttonIcon: "image://appicon/view-restore-symbolic"
|
||||
onClicked: {
|
||||
mainWindow.isFullScreen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +1,28 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
import QtQuick.Layouts 1.12
|
||||
Item {
|
||||
Rectangle {
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
color: "yellow"
|
||||
anchors.leftMargin: 35
|
||||
anchors.rightMargin: 35
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onClicked: {
|
||||
mainWindow.isFullScreen = !mainWindow.isFullScreen;
|
||||
}
|
||||
FullScreenHeader {
|
||||
// full screen header
|
||||
Layout.preferredHeight: 130
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: 130
|
||||
}
|
||||
|
||||
FullScreenContent {
|
||||
// full screen content
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
FullScreenFooter {
|
||||
// full screen footer
|
||||
Layout.preferredHeight: 90
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ Item {
|
|||
id: extensionListView
|
||||
width: parent.width - 34
|
||||
height: parent.height
|
||||
clip: true
|
||||
orientation: ListView.Horizontal
|
||||
model: extensionManager.extensionModel()
|
||||
delegate: headerDelegate
|
||||
|
@ -60,6 +61,19 @@ Item {
|
|||
Item {
|
||||
width: 34
|
||||
height: 34
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: height / 2
|
||||
color: "lightblue"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
// 全屏
|
||||
console.log("==开始全屏==")
|
||||
mainWindow.isFullScreen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,6 @@ FullScreenUI 1.0 FullScreenUI.qml
|
|||
AppPageHeader 1.0 AppPageHeader.qml
|
||||
SearchInputBar 1.0 SearchInputBar.qml
|
||||
PluginSelectMenu 1.0 PluginSelectMenu.qml
|
||||
FullScreenHeader 1.0 FullScreenHeader.qml
|
||||
FullScreenContent 1.0 FullScreenContent.qml
|
||||
FullScreenFooter 1.0 FullScreenFooter.qml
|
||||
|
|
93
qml/main.qml
93
qml/main.qml
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -17,11 +17,98 @@
|
|||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQml 2.12
|
||||
|
||||
import AppUI 1.0 as AppUI
|
||||
import AppControls2 1.0 as AppControls2
|
||||
import org.ukui.menu.core 1.0
|
||||
|
||||
Item {
|
||||
AppUI.NormalUI {
|
||||
anchors.fill: parent
|
||||
id: root
|
||||
clip: true
|
||||
property int animationDuration: 150
|
||||
|
||||
Component.onCompleted: {
|
||||
loader.reloadUI();
|
||||
mainWindow.beforeFullScreenChanged.connect(beforeFullScreenSlot);
|
||||
mainWindow.fullScreenChanged.connect(fullScreenChangedSlot);
|
||||
}
|
||||
|
||||
function fullScreenChangedSlot() {
|
||||
loader.opacity = 0;
|
||||
fullScreenAnimation.start();
|
||||
}
|
||||
|
||||
function beforeFullScreenSlot(status) {
|
||||
if (!status) {
|
||||
loader.sourceComponent = undefined;
|
||||
}
|
||||
backgroundMask.alpha = status ? 0.5 : 0
|
||||
backgroundMask.enableSizeChange = false;
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: fullScreenAnimation
|
||||
NumberAnimation { target: backgroundMask; property: "width"; to: root.width; duration: root.animationDuration }
|
||||
NumberAnimation { target: backgroundMask; property: "height"; to: root.height; duration: root.animationDuration }
|
||||
|
||||
onFinished: {
|
||||
backgroundMask.enableSizeChange = true;
|
||||
loader.reloadUI();
|
||||
}
|
||||
}
|
||||
|
||||
AppControls2.StyleBackground {
|
||||
id: backgroundMask
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
alpha: 0
|
||||
useStyleTransparent: false
|
||||
paletteRole: Palette.Dark
|
||||
|
||||
property bool enableSizeChange: true
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "disableSizeChange"
|
||||
when: !backgroundMask.enableSizeChange
|
||||
AnchorChanges {
|
||||
target: backgroundMask
|
||||
anchors.top: undefined
|
||||
anchors.right: undefined
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "enableSizeChange"
|
||||
when: backgroundMask.enableSizeChange
|
||||
AnchorChanges {
|
||||
target: backgroundMask
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: root.animationDuration }
|
||||
}
|
||||
function reloadUI() {
|
||||
loader.sourceComponent = mainWindow.isFullScreen ? fullSceenComponent : normalComponent;
|
||||
loader.opacity = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fullSceenComponent
|
||||
AppUI.FullScreenUI {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: normalComponent
|
||||
AppUI.NormalUI {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<file>AppUI/AppPage.qml</file>
|
||||
<file>AppUI/Sidebar.qml</file>
|
||||
<file>AppUI/AppList.qml</file>
|
||||
<file>AppUI/FullScreenHeader.qml</file>
|
||||
<file>AppUI/FullScreenContent.qml</file>
|
||||
<file>AppUI/FullScreenFooter.qml</file>
|
||||
<file>AppUI/AppPageHeader.qml</file>
|
||||
<file>AppUI/SearchInputBar.qml</file>
|
||||
<file>AppControls2/qmldir</file>
|
||||
|
|
|
@ -395,6 +395,8 @@ void MenuWindow::init()
|
|||
QEvent event(QEvent::Move);
|
||||
QCoreApplication::sendEvent(this, &event);
|
||||
});
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MenuWindow::updateGeometry()
|
||||
|
@ -412,13 +414,24 @@ bool MenuWindow::isFullScreen() const
|
|||
return m_isFullScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* beforeFullScreenChanged -> (qml)onWidthChanged -> fullScreenChanged
|
||||
* @param isFullScreen
|
||||
*/
|
||||
void MenuWindow::setFullScreen(bool isFullScreen)
|
||||
{
|
||||
if (m_isFullScreen == isFullScreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT beforeFullScreenChanged(isFullScreen);
|
||||
|
||||
m_isFullScreen = isFullScreen;
|
||||
WindowHelper::windowBlur(this, !m_isFullScreen);
|
||||
|
||||
updateGeometry();
|
||||
|
||||
// 更新contentItem尺寸
|
||||
QEvent event(QEvent::Resize);
|
||||
QCoreApplication::sendEvent(this, &event);
|
||||
|
||||
|
@ -427,24 +440,17 @@ void MenuWindow::setFullScreen(bool isFullScreen)
|
|||
|
||||
void MenuWindow::exposeEvent(QExposeEvent *event)
|
||||
{
|
||||
if (isExposed()) {
|
||||
requestActivate();
|
||||
}
|
||||
QQuickWindow::exposeEvent(event);
|
||||
}
|
||||
|
||||
void MenuWindow::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
updateGeometry();
|
||||
QQuickView::resizeEvent(event);
|
||||
}
|
||||
|
||||
void MenuWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
QQuickWindow::showEvent(event);
|
||||
}
|
||||
|
||||
void MenuWindow::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
//setVisible(false);
|
||||
// void QQuickWindow::focusOutEvent(QFocusEvent *ev) { Q_D(QQuickWindow); if (d->contentItem) d->contentItem->setFocus(false, ev->reason()); }
|
||||
QQuickWindow::focusOutEvent(event);
|
||||
// setVisible(false);
|
||||
}
|
||||
|
||||
bool MenuWindow::event(QEvent *event)
|
||||
|
|
|
@ -115,14 +115,13 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void fullScreenChanged();
|
||||
void beforeFullScreenChanged(bool isToFullScreen);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onActiveFocusItemChanged();
|
||||
|
||||
protected:
|
||||
void exposeEvent(QExposeEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void focusOutEvent(QFocusEvent *event) override;
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
|
|
Loading…
Reference in New Issue