Compare commits

...

1 Commits

Author SHA1 Message Date
LittFlower a8fee9025c Fix: Update the TiledLayout logic
Log: Rewritten and improved Tinywl's tiled layout logic, added 4 types of tiled logic and workspace management functions, renamed some variables to make it more compliant with code standards, removed useless comments to streamline the code, and maintained some features to improve user experience .
2024-10-29 19:12:13 +08:00
12 changed files with 1373 additions and 255 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
.vscode/
.cache/
.gdb_history
build*/
*.user

View File

@ -17,7 +17,7 @@ include(GNUInstallDirs)
# Macros
include(FeatureSummary)
option(WITH_SUBMODULE_WAYLIB "Use the waylib from git submodule" OFF)
option(WITH_SUBMODULE_WAYLIB "Use the waylib from git submodule" ON)
add_feature_info(submodule_waylib WITH_SUBMODULE_WAYLIB "Use waylib from submodule")
option(ADDRESS_SANITIZER "Enable address sanitize" OFF)

View File

@ -31,6 +31,12 @@ qt_add_qml_module(treeland-qml
EQHGrid.qml
ToplevelContainer.qml
NewAnimation.qml
SlideLayout.qml
TallLayout.qml
HorizontalLayout.qml
VerticalLayout.qml
WorkspaceManager.qml
RESOURCE_PREFIX
/qt/qml
OUTPUT_DIRECTORY

View File

@ -0,0 +1,262 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Waylib.Server
import TreeLand
import TreeLand.Protocols
import TreeLand.Utils
Item {
id: horizontalLayout
property int spacing: 0 // Distance between this pane and that pane, temporarily set to 0.
property Item selectSurfaceItem1: null
property Item selectSurfaceItem2: null
property Item currentSurfaceItem: null
LoggingCategory {
id: hCategory
name: "treeland.tiledlayout.horizontal"
defaultLogLevel: LoggingCategory.Info
}
function addPane(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (wsPanes.length === 0) {
surfaceItem.x = 0
surfaceItem.y = 0
surfaceItem.width = root.width
surfaceItem.height = root.height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
} else {
let scale = wsPanes.length / (wsPanes.length + 1)
wsPanes[0].x = 0
wsPanes[0].width *= scale
wsPanes[0].visible = true
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
wsPanes[i].y = wsPanes[0].y
wsPanes[i].width *= scale
wsPanes[i].height = wsPanes[0].height
wsPanes[i].visible = true
}
surfaceItem.x = wsPanes[wsPanes.length - 1].x + wsPanes[wsPanes.length - 1].width
surfaceItem.y = wsPanes[0].y
surfaceItem.width = root.width * (1.0 - scale)
surfaceItem.height = wsPanes[0].height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
}
workspaceManager.syncWsPanes("addPane")
}
// TODO: Update the ui of choosing logic.
function choosePane(id) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
currentSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
if (id === 1) {
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem1 = wsPanes[0]
} else {
selectSurfaceItem1 = wsPanes[index+1]
}
console.info(hCategory, "The first selected pane is index", wsPanes.indexOf(selectSurfaceItem1))
Helper.activatedSurface = selectSurfaceItem1.shellSurface
} else if (id === 2) {
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem2 = wsPanes[0]
} else {
selectSurfaceItem2 = wsPanes[index+1]
}
console.info(hCategory, "The second selected pane is index", wsPanes.indexOf(selectSurfaceItem2))
Helper.activatedSurface = selectSurfaceItem2.shellSurface
}
}
function removePane(removeSurfaceIf) {
let surfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(surfaceItem)
if (wsPanes.length === 1) {
wsPanes.splice(index, 1)
// It is no necessory to modify the height or y when removing a pane.
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if(removeSurfaceIf === 0) surfaceItem.visible = false
} else {
let scale = wsPanes.length / (wsPanes.length - 1)
wsPanes.splice(index, 1)
wsPanes[0].x = 0
wsPanes[0].width *= scale // Magnification factor.
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
wsPanes[i].y = wsPanes[0].y
wsPanes[i].width *= scale
wsPanes[i].height = wsPanes[0].height
}
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if(removeSurfaceIf === 0) surfaceItem.visible = false
}
workspaceManager.syncWsPanes("removePane")
}
// Direction: 1 = Left, 2 = Right, 3 = Up, 4 = Down.
function resizePane(size, direction) {
let activeSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(activeSurfaceItem)
if (wsPanes.length === 1) {
console.info(hCategory, "Only one pane, cannot call resizePane() function.")
return
}
if (index === 0) {
let delta = size / (wsPanes.length - 1)
if (direction === 1) {
console.info(hCategory, "You cannot left anymore!")
return
} else if (direction === 2) {
activeSurfaceItem.width += size
for (let i = 1; i < wsPanes.length; ++i) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
wsPanes[i].width -= delta
}
}
} else {
let delta = size / index
let last = wsPanes.length - 1
if (index === last) {
if (direction === 1) {
wsPanes[last].width -= size
wsPanes[last].x += size
for (let i = last - 1; i >= 0; --i) {
wsPanes[i].width += delta
wsPanes[i].x = wsPanes[i+1].x - wsPanes[i].width
}
wsPanes[0].x = 0
} else if (direction === 2) {
console.info(hCategory, "You cannot left anymore!")
return
}
} else if (direction === 1) {
wsPanes[0].x = 0
wsPanes[0].width += delta
for (let i = 1; i < index; ++i) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
wsPanes[i].width += delta
}
activeSurfaceItem.x += size
activeSurfaceItem.width -= size
} else if (direction === 2) {
wsPanes[last].x += delta
wsPanes[last].width -= delta
for (let i = last - 1; i > index; i--) {
wsPanes[i].width -= delta
wsPanes[i].x = wsPanes[i+1].x - wsPanes[i].width
}
activeSurfaceItem.x = activeSurfaceItem.x // x donnot change.
activeSurfaceItem.width += size
}
}
workspaceManager.syncWsPanes("resizePane")
}
function swapPane() {
if (selectSurfaceItem1 === null || selectSurfaceItem2 === null) {
console.info(hCategory, "You should choose two pane before swap them.")
return
}
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let activeSurfaceItem = selectSurfaceItem1
let targetSurfaceItem = selectSurfaceItem2
let index1 = wsPanes.indexOf(activeSurfaceItem)
let index2 = wsPanes.indexOf(targetSurfaceItem)
if (index1 === index2) {
console.info(hCategory, "You should choose two different panes to swap.")
return
}
let tempIndex1 = null
let tempIndex2 = null
for (let i = 0; i < root.panes.length; ++i) {
if (wsPanes[index1] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex1 = i
}
if (wsPanes[index2] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex2 = i
}
}
let delta = activeSurfaceItem.width - targetSurfaceItem.width
if (index1 < index2) {
if (index2 - index1 === 1) {
targetSurfaceItem.x = activeSurfaceItem.x
activeSurfaceItem.x = targetSurfaceItem.x + targetSurfaceItem.width
} else {
let tempPane = targetSurfaceItem
tempPane.x = activeSurfaceItem.x
wsPanes[index1+1].x = tempPane.x + tempPane.width
for (let i = index1 + 2; i < index2; ++i) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
}
targetSurfaceItem = tempPane
activeSurfaceItem.x = wsPanes[index2-1].x + wsPanes[index2-1].width
}
} else if (index1 > index2) {
if (index1 - index2 === 1) {
activeSurfaceItem.x = targetSurfaceItem.x
targetSurfaceItem.x = activeSurfaceItem.x + activeSurfaceItem.width
} else {
let tempPane = activeSurfaceItem
tempPane.x = targetSurfaceItem.x
wsPanes[index2+1].x = tempPane.x + tempPane.width
for (let i = index2 + 2; i < index1; ++i) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
}
activeSurfaceItem = tempPane
targetSurfaceItem.x = wsPanes[index1-1].x + wsPanes[index1-1].width
}
}
let temp1 = root.panes[tempIndex1]
root.panes[tempIndex1] = root.panes[tempIndex2]
root.panes[tempIndex2] = temp1
let temp2 = wsPanes[index1];
wsPanes[index1] = wsPanes[index2];
wsPanes[index2] = temp2;
workspaceManager.syncWsPanes("swapPane")
}
function reLayout(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(surfaceItem)
if (wsPanes.length === 1) {
wsPanes.splice(index, 1)
} else {
let scale = wsPanes.length / (wsPanes.length - 1)
wsPanes.splice(index, 1)
wsPanes[0].x = 0
wsPanes[0].width *= scale
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[i-1].x + wsPanes[i-1].width
wsPanes[i].y = wsPanes[0].y
wsPanes[i].width *= scale
wsPanes[i].height = wsPanes[0].height
}
}
workspaceManager.syncWsPanes("reLayout", surfaceItem)
}
}

View File

@ -120,6 +120,7 @@ Item {
id: stackLayout
anchors.fill: parent
focus: true
active: true
sourceComponent: StackWorkspace {
focus: stackLayout.active
activeOutputDelegate: renderWindow.activeOutputDelegate
@ -129,6 +130,7 @@ Item {
Loader {
active: !stackLayout.active
anchors.fill: parent
focus: true
sourceComponent: TiledWorkspace { }
}
}

78
src/qml/SlideLayout.qml Normal file
View File

@ -0,0 +1,78 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Waylib.Server
import TreeLand
import TreeLand.Protocols
import TreeLand.Utils
Item {
id: slideLayout
property int spacing: 0 // Distance between this pane and that pane, temporarily set to 0.
LoggingCategory {
id: sCategory
name: "com.qt.category"
defaultLogLevel: LoggingCategory.Info
}
function addPane(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
surfaceItem.x = 0
surfaceItem.y = 0
surfaceItem.width = root.width
surfaceItem.height = root.height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
workspaceManager.syncWsPanes("addPane")
}
function swapPane() {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let currentSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
if (wsPanes.length === 1) {
console.info(sCategory, "You have only one pane.")
return
}
let index = wsPanes.indexOf(currentSurfaceItem)
index += 1
if (index === wsPanes.length) {
index = 0
}
for (let i = 0; i < wsPanes.length; ++i) {
if (i === index) wsPanes[i].visible = true
else wsPanes[i].visible = false
}
Helper.activatedSurface = wsPanes[index].shellSurface
workspaceManager.syncWsPanes("swapPane")
}
function removePane(removeSurfaceIf) {
// bug: If there is only one window left under slideLayout,
// deleting it will result in error 116: ReferenceError: xwaylandComponent is not defined.
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let surfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let index = wsPanes.indexOf(surfaceItem)
wsPanes.splice(index, 1)
if (removeSurfaceIf) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if(!removeSurfaceIf) surfaceItem.visible = false
if (wsPanes.length) {
let vis = -1
for (let i = 0; i < wsPanes.length; ++i) {
if (wsPanes[i].visible === true) { vis = 1; break}
}
if (vis === -1) wsPanes[0].visible = true
}
workspaceManager.syncWsPanes("removePane")
}
function reLayout(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(surfaceItem)
wsPanes.splice(index, 1)
workspaceManager.syncWsPanes("reLayout", surfaceItem)
}
}

364
src/qml/TallLayout.qml Normal file
View File

@ -0,0 +1,364 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Waylib.Server
import TreeLand
import TreeLand.Protocols
import TreeLand.Utils
Item {
id: tallLayout
property int spacing: 0 // Distance between this pane and that pane, temporarily set to 0.
property Item selectSurfaceItem1: null
property Item selectSurfaceItem2: null
property Item currentSurfaceItem: null
LoggingCategory {
id: tCategory
name: "treeland.tiledlayout.tall"
defaultLogLevel: LoggingCategory.Info
}
function addPane(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (wsPanes.length === 0) {
surfaceItem.x = 0
surfaceItem.y = 0
surfaceItem.width = root.width
surfaceItem.height = root.height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
} else if (wsPanes.length === 1) {
wsPanes[0].width = root.width / 2
wsPanes[0].height = root.height
wsPanes[0].visible = true
surfaceItem.x = wsPanes[0].x + wsPanes[0].width
surfaceItem.y = wsPanes[0].y
surfaceItem.width = root.width / 2
surfaceItem.height = wsPanes[0].height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
} else {
// There are two or more panes, split vertically on the right side,
// and processed according to the VerticalLayout.
let scale = (wsPanes.length - 1) / (wsPanes.length)
wsPanes[0].visible = true
wsPanes[1].y = 0
wsPanes[1].height *= scale
wsPanes[1].visible = true
for (let i = 2; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[i-1].x
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].width = wsPanes[i-1].width
wsPanes[i].height *= scale
wsPanes[i].visible = true
}
surfaceItem.x = wsPanes[wsPanes.length - 1].x
surfaceItem.y = wsPanes[wsPanes.length - 1].y + wsPanes[wsPanes.length - 1].height
surfaceItem.height = root.height - surfaceItem.y
surfaceItem.width = wsPanes[wsPanes.length - 1].width
surfaceItem.visible = true
wsPanes.push(surfaceItem)
}
workspaceManager.syncWsPanes("addPane")
}
function choosePane(id) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
currentSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
if (id === 1) { // selected for selectPane1
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem1 = wsPanes[0]
} else {
selectSurfaceItem1 = wsPanes[index+1]
}
console.info(tCategory, "The first selected pane is index", wsPanes.indexOf(selectSurfaceItem1))
Helper.activatedSurface = selectSurfaceItem1.shellSurface
} else if (id === 2) { // selectd for selectPane2
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem2 = wsPanes[0]
} else {
selectSurfaceItem2 = wsPanes[index+1]
}
console.info(tCategory, "The second selected pane is index", wsPanes.indexOf(selectSurfaceItem2))
Helper.activatedSurface = selectSurfaceItem2.shellSurface
}
}
// Direction: 1 = Left, 2 = Right, 3 = Up, 4 = Down.
function resizePane(size, direction) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let activeSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let index = wsPanes.indexOf(activeSurfaceItem)
if (wsPanes.length === 1) {
console.info(tCategory, "Only one pane, cannot call resizePane() function.")
return
}
if (index === 0) { // The first pane is on the left.
if (direction === 1) {
console.info(tCategory, "You cannot resize the first pane on left!")
return
} else if (direction === 2) {
activeSurfaceItem.width += size
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x += size
wsPanes[i].width -= size
}
}
} else { // The rest panes are in the right pane.
if (direction === 3 || direction === 4) {
let last = wsPanes.length - 1
if (index === 1) { // The first pane on the right.
if (direction === 3) { // Move the upper line to adjust the size.
console.info(tCategory, "You cannot resize the first pane by the upper line!")
return
} else if (direction === 4) { // Adjust the size with the lower edge line.
let delta = size / (wsPanes.length - index - 1)
wsPanes[1].height += size
for (let i = 2; i < wsPanes.length; i++) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height -= delta
}
}
} else if (index === last) { // The last pane on the right.
if (direction === 4) {
console.info(tCategory, "You cannot resize the last pane by the lower line!")
return
} else if (direction === 3) { // Adjust the size with the upper line.
let delta = size / (index - 1)
wsPanes[last].height -= size
wsPanes[last].y += size
for (let i = last - 1; i >= 1; i--) {
wsPanes[i].height += delta
wsPanes[i].y = wsPanes[i+1].y - wsPanes[i].height
}
wsPanes[1].y = 0
}
} else if (index > 1 && index < last) { // In the middle pane on the right.
if (direction === 3) { // Adjust the size with the upper line.
let delta = size / (index - 1)
wsPanes[1].y = 0
wsPanes[1].height += delta
for (let i = 2; i < index; i++) {
wsPanes[i].height += delta
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
activeSurfaceItem.y += size
activeSurfaceItem.height -= size
} else if (direction === 4) { // Adjust the size with the lower edge line.
let delta = size / (wsPanes.length - index - 1)
wsPanes[last].height -= delta
wsPanes[last].y += delta
for (let i = last - 1; i > index; i--) {
wsPanes[i].height -= delta
wsPanes[i].y = wsPanes[i+1].y - wsPanes[i].height
}
activeSurfaceItem.height += size
}
}
} else if (direction === 1) {
wsPanes[0].width += size
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x += size
wsPanes[i].width -= size
}
} else if (direction === 2) {
console.info(tCategory, "You cannot resize the pane by the right line!")
return
}
}
workspaceManager.syncWsPanes("resizePane")
}
function removePane(removeSurfaceIf) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item === null) {
console.info(tCategory, "You should choose a pane firstly.")
return
}
let surfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let index = wsPanes.indexOf(surfaceItem)
if (wsPanes.length === 1) {
wsPanes.splice(index, 1)
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
} else if (wsPanes.length === 2) {
wsPanes.splice(index, 1)
wsPanes[0].x = 0
wsPanes[0].y = 0
wsPanes[0].width = root.width
wsPanes[0].height = root.height
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
} else if (index === 0) {
let scale = (wsPanes.length - 1) / (wsPanes.length - 2)
wsPanes[2].x = wsPanes[1].x
wsPanes[2].y = wsPanes[1].y
wsPanes[2].width = wsPanes[1].width
wsPanes[2].height *= scale
wsPanes[1].x = wsPanes[0].x
wsPanes[1].y = wsPanes[0].y
wsPanes[1].width = wsPanes[0].width
wsPanes[1].height = wsPanes[0].height
for (let i = 3; i < wsPanes.length; ++i) {
wsPanes[i].height *= scale
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
wsPanes.splice(index, 1)
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
} else {
let scale = (wsPanes.length - 1) / (wsPanes.length - 2)
wsPanes.splice(index, 1)
wsPanes[1].y = 0
wsPanes[1].height *= scale
for (let i = 2; i < wsPanes.length; i++) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height *= scale
}
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
}
workspaceManager.syncWsPanes("removePane")
}
function swapPane() {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (selectSurfaceItem1 === null || selectSurfaceItem2 === null) {
console.info(tCategory, "You should choose two pane before swap them.")
return
}
let activeSurfaceItem = selectSurfaceItem1
let targetSurfaceItem = selectSurfaceItem2
let index1 = wsPanes.indexOf(activeSurfaceItem)
let index2 = wsPanes.indexOf(targetSurfaceItem)
if (index1 === index2) {
console.info(tCategory, "You should choose two different panes to swap.")
return
}
let tempIndex1 = null
let tempIndex2 = null
for (let i = 0; i < root.panes.length; ++i) {
if (wsPanes[index1] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex1 = i
}
if (wsPanes[index2] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex2 = i
}
}
if (index1 === 0 || index2 === 0) {
let tempXPos = activeSurfaceItem.x
let tempYPos = activeSurfaceItem.y
let tempWidth = activeSurfaceItem.width
let tempHeight = activeSurfaceItem.height
activeSurfaceItem.x = targetSurfaceItem.x
activeSurfaceItem.y = targetSurfaceItem.y
activeSurfaceItem.width = targetSurfaceItem.width
activeSurfaceItem.height = targetSurfaceItem.height
targetSurfaceItem.x = tempXPos
targetSurfaceItem.y = tempYPos
targetSurfaceItem.width = tempWidth
targetSurfaceItem.height = tempHeight
} else {
let delta = activeSurfaceItem.height - targetSurfaceItem.height
if (index1 < index2) {
if (index2 - index1 === 1) {
targetSurfaceItem.y = activeSurfaceItem.y
activeSurfaceItem.y = targetSurfaceItem.y + targetSurfaceItem.height
} else {
let tempPane = targetSurfaceItem
tempPane.y = activeSurfaceItem.y
wsPanes[index1+1].y = tempPane.y + tempPane.height
for (let i = index1 + 2; i < index2; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
targetSurfaceItem = tempPane
activeSurfaceItem.y = wsPanes[index2-1].y + wsPanes[index2-1].height
}
} else if (index1 > index2) {
if (index1 - index2 === 1) {
activeSurfaceItem.y = targetSurfaceItem.y
targetSurfaceItem.y = activeSurfaceItem.y + activeSurfaceItem.height
} else {
let tempPane = activeSurfaceItem
tempPane.y = targetSurfaceItem.y
wsPanes[index2+1].y = tempPane.y + tempPane.height
for (let i = index2 + 2; i < index1; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
activeSurfaceItem = tempPane
targetSurfaceItem.y = wsPanes[index1-1].y + wsPanes[index1-1].height
}
}
let temp1 = root.panes[tempIndex1]
root.panes[tempIndex1] = root.panes[tempIndex2]
root.panes[tempIndex2] = temp1
let temp2 = wsPanes[index1];
wsPanes[index1] = wsPanes[index2];
wsPanes[index2] = temp2;
workspaceManager.syncWsPanes("swapPane")
}
}
function reLayout(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(surfaceItem)
if (wsPanes.length === 1) {
wsPanes.splice(index, 1)
} else if (wsPanes.length === 2) {
wsPanes.splice(index, 1)
wsPanes[0].x = 0
wsPanes[0].y = 0
wsPanes[0].width = root.width
wsPanes[0].height = root.height
} else if (index === 0) {
let scale = (wsPanes.length - 1) / (wsPanes.length - 2)
wsPanes[2].x = wsPanes[1].x
wsPanes[2].y = wsPanes[1].y
wsPanes[2].width = wsPanes[1].width
wsPanes[2].height *= scale
wsPanes[1].x = wsPanes[0].x
wsPanes[1].y = wsPanes[0].y
wsPanes[1].width = wsPanes[0].width
wsPanes[1].height = wsPanes[0].height
for (let i = 3; i < wsPanes.length; ++i) {
wsPanes[i].height *= scale
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
wsPanes.splice(index, 1)
} else {
let scale = (wsPanes.length - 1) / (wsPanes.length - 2)
wsPanes.splice(index, 1)
wsPanes[1].y = 0
wsPanes[1].height *= scale
for (let i = 2; i < wsPanes.length; i++) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height *= scale
}
}
workspaceManager.syncWsPanes("reLayout", surfaceItem)
}
}

View File

@ -11,7 +11,6 @@ import TreeLand.Utils
Item {
id: root
function getSurfaceItemFromWaylandSurface(surface) {
let finder = function(props) {
if (!props.waylandSurface)
@ -25,7 +24,7 @@ Item {
if (toplevel) {
return {
shell: toplevel,
item: toplevel.asXdg,
item: toplevel,
type: "toplevel"
}
}
@ -48,219 +47,173 @@ Item {
}
}
let xwayland = Helper.xwaylandCreator.getIf(xwaylandComponent, finder)
if (xwayland) {
return {
shell: xwayland,
item: xwayland.asXwayland,
type: "xwayland"
}
}
// let xwayland = Helper.xwaylandCreator.getIf(xwaylandComponent, finder)
// if (xwayland) {
// return {
// shell: xwayland,
// item: xwayland,
// type: "xwayland"
// }
// }
return null
}
GridLayout {
LoggingCategory {
id: category
name: "treeland.tiledlayout"
defaultLogLevel: LoggingCategory.Info
}
WorkspaceManager {
id: workspaceManager
anchors.fill: parent
columns: Math.floor(root.width / 1920 * 4)
}
DynamicCreatorComponent {
id: toplevelComponent
creator: Helper.xdgShellCreator
chooserRole: "type"
chooserRoleValue: "toplevel"
autoDestroy: false
onObjectRemoved: function (obj) {
obj.doDestroy()
SlideLayout {
id: slideLayout
// objectName: "slideLayout"
anchors.fill: parent
}
HorizontalLayout {
id: horizontalLayout
anchors.fill: parent
}
VerticalLayout {
id: verticalLayout
anchors.fill: parent
}
TallLayout {
id : tallLayout
anchors.fill: parent
}
function getPanes(wsId) {
return workspaceManager.wsPanesById.get(wsId)
}
property list <XdgSurfaceItem> panes: [] // Manage all panels.
property list <int> paneByWs: [] // Which WS does the i-th pane belong to.
property Item currentLayout: verticalLayout // Initialize default layout.
property int currentWsId: -1 // currentWorkSpace id.
property list <int> deleteFlag: [] // This flag is used to indicate whether this pane has been removed by removePane() function.
property list <Item> layouts: [slideLayout, verticalLayout, horizontalLayout, tallLayout]
Connections {
target: Helper
function onResizePane(size, direction) {
console.info(category, "the move size is", size, ", and the move direction is", direction)
if (currentLayout === slideLayout) {
console.log(category, "This Layout don't have resizePane() function!")
return
}
XdgSurfaceItem {
id: toplevelSurfaceItem
property var doDestroy: helper.doDestroy
shellSurface: waylandSurface
resizeMode: SurfaceItem.SizeToSurface
z: (waylandSurface && waylandSurface.isActivated) ? 1 : 0
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumWidth: Math.max(toplevelSurfaceItem.minimumSize.width, 100)
Layout.minimumHeight: Math.max(toplevelSurfaceItem.minimumSize.height, 50)
Layout.maximumWidth: toplevelSurfaceItem.maximumSize.width
Layout.maximumHeight: toplevelSurfaceItem.maximumSize.height
Layout.horizontalStretchFactor: 1
Layout.verticalStretchFactor: 1
OutputLayoutItem {
anchors.fill: parent
layout: Helper.outputLayout
onEnterOutput: function(output) {
if (waylandSurface.surface) {
waylandSurface.surface.enterOutput(output)
}
Helper.onSurfaceEnterOutput(waylandSurface, toplevelSurfaceItem, output)
}
onLeaveOutput: function(output) {
waylandSurface.surface.leaveOutput(output)
Helper.onSurfaceLeaveOutput(waylandSurface, toplevelSurfaceItem, output)
}
}
TiledToplevelHelper {
id: helper
surface: toplevelSurfaceItem
waylandSurface: toplevelSurfaceItem.waylandSurface
creator: toplevelComponent
}
if (currentLayout === verticalLayout && (direction === 1 || direction === 2)) {
console.log(category, "This Layout cannot left or right anymore!")
return
}
if (currentLayout === horizontalLayout && (direction === 3 || direction === 4)) {
console.log(category, "This Layout cannot up or down anymore!")
return
}
currentLayout.resizePane(size, direction)
}
function onSwapPane() { currentLayout.swapPane() }
function onRemovePane(removeSurfaceIf) { currentLayout.removePane(removeSurfaceIf) }
function onChoosePane(id) { currentLayout.choosePane(id) }
function onSwitchLayout() { switchLayout() }
function onCreateWs() { workspaceManager.createWs() }
function onDestoryWs() { workspaceManager.destoryWs() }
function onSwitchNextWs() { workspaceManager.switchNextWs() }
function onMoveWs(wsId) { --wsId; workspaceManager.moveWs(currentWsId, wsId) }
}
function switchLayout() {
console.info(category, "switchLayout")
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = layouts.indexOf(currentLayout)
let len = wsPanes.length
index += 1
if (index === layouts.length) {
index = 0
}
let oldLayout = currentLayout
let tempPanes = []
for (let i = 0; i < len; ++i) {
tempPanes.push(wsPanes[i])
}
currentLayout = layouts[index]
for (let i = 0; i < len; ++i) {
Helper.activatedSurface = wsPanes[0].shellSurface
oldLayout.removePane(0)
}
for (let i = 0; i < tempPanes.length; ++i) {
currentLayout.addPane(tempPanes[i])
}
workspaceManager.wsLayoutById.set(currentWsId, currentLayout)
}
DynamicCreatorComponent {
id: toplevelComponent
creator: Helper.xdgShellCreator
chooserRole: "type"
chooserRoleValue: "toplevel"
autoDestroy: false
onObjectRemoved: function (obj) {
obj.doDestroy()
}
DynamicCreatorComponent {
id: popupComponent
creator: Helper.xdgShellCreator
chooserRole: "type"
chooserRoleValue: "popup"
XdgSurfaceItem {
id: toplevelVerticalSurfaceItem
resizeMode: SurfaceItem.SizeToSurface
property var doDestroy: helper.doDestroy
Popup {
id: popup
required property WaylandXdgSurface waylandSurface
property string type
shellSurface: waylandSurface
required property WaylandXdgSurface waylandSurface
property string type
property alias xdgSurface: popupSurfaceItem
property var parentItem: root.getSurfaceItemFromWaylandSurface(waylandSurface.parentSurface)
parent: parentItem ? parentItem.item : root
visible: parentItem && parentItem.item.effectiveVisible
&& waylandSurface.surface.mapped && waylandSurface.WaylandSocket.rootSocket.enabled
x: {
let retX = 0 // X coordinate relative to parent
let minX = 0
let maxX = root.width - xdgSurface.width
if (!parentItem) {
retX = popupSurfaceItem.implicitPosition.x
if (retX > maxX)
retX = maxX
if (retX < minX)
retX = minX
} else {
retX = popupSurfaceItem.implicitPosition.x / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.x
let parentX = parent.mapToItem(root, 0, 0).x
if (retX + parentX > maxX) {
if (parentItem.type === "popup")
retX = retX - xdgSurface.width - parent.width
else
retX = maxX - parentX
}
if (retX + parentX < minX)
retX = minX - parentX
}
return retX
Component.onCompleted: {
if (currentWsId === -1) {
workspaceManager.createWs(currentLayout)
}
y: {
let retY = 0 // Y coordinate relative to parent
let minY = 0
let maxY = root.height - xdgSurface.height
if (!parentItem) {
retY = popupSurfaceItem.implicitPosition.y
if (retY > maxY)
retY = maxY
if (retY < minY)
retY = minY
} else {
retY = popupSurfaceItem.implicitPosition.y / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.y
let parentY = parent.mapToItem(root, 0, 0).y
if (retY + parentY > maxY)
retY = maxY - parentY
if (retY + parentY < minY)
retY = minY - parentY
}
return retY
}
padding: 0
background: null
closePolicy: Popup.NoAutoClose
XdgSurfaceItem {
id: popupSurfaceItem
shellSurface: popup.waylandSurface
OutputLayoutItem {
anchors.fill: parent
layout: Helper.outputLayout
onEnterOutput: function(output) {
if (waylandSurface.surface) {
waylandSurface.surface.enterOutput(output)
}
Helper.onSurfaceEnterOutput(waylandSurface, popupSurfaceItem, output)
}
onLeaveOutput: function(output) {
waylandSurface.surface.leaveOutput(output)
Helper.onSurfaceLeaveOutput(waylandSurface, popupSurfaceItem, output)
}
}
}
}
}
DynamicCreatorComponent {
id: xwaylandComponent
creator: Helper.xwaylandCreator
autoDestroy: false
onObjectRemoved: function (obj) {
obj.doDestroy()
// paneByWs.push(currentWsId)
currentLayout.addPane(toplevelVerticalSurfaceItem)
}
XWaylandSurfaceItem {
id: xwaylandSurfaceItem
required property XWaylandSurface waylandSurface
property var doDestroy: helper.doDestroy
surface: waylandSurface
resizeMode: SurfaceItem.SizeToSurface
// TODO: Support popup/menu
positionMode: xwaylandSurfaceItem.effectiveVisible ? XWaylandSurfaceItem.PositionToSurface : XWaylandSurfaceItem.ManualPosition
z: (waylandSurface && waylandSurface.isActivated) ? 1 : 0
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumWidth: Math.max(xwaylandSurfaceItem.minimumSize.width, 100)
Layout.minimumHeight: Math.max(xwaylandSurfaceItem.minimumSize.height, 50)
Layout.maximumWidth: xwaylandSurfaceItem.maximumSize.width
Layout.maximumHeight: xwaylandSurfaceItem.maximumSize.height
Layout.horizontalStretchFactor: 1
Layout.verticalStretchFactor: 1
OutputLayoutItem {
anchors.fill: parent
layout: Helper.outputLayout
onEnterOutput: function(output) {
if (xwaylandSurfaceItem.waylandSurface.surface)
xwaylandSurfaceItem.waylandSurface.surface.enterOutput(output);
Helper.onSurfaceEnterOutput(waylandSurface, xwaylandSurfaceItem, output)
}
onLeaveOutput: function(output) {
if (xwaylandSurfaceItem.waylandSurface.surface)
xwaylandSurfaceItem.waylandSurface.surface.leaveOutput(output);
Helper.onSurfaceLeaveOutput(waylandSurface, xwaylandSurfaceItem, output)
}
Component.onDestruction: {
if (deleteFlag.indexOf(1) != -1) {
deleteFlag.splice(0, 1)
return
}
currentLayout.reLayout(toplevelVerticalSurfaceItem)
}
TiledToplevelHelper {
id: helper
OutputLayoutItem {
anchors.fill: parent
layout: Helper.outputLayout
surface: xwaylandSurfaceItem
waylandSurface: surface.waylandSurface
creator: xwaylandComponent
onEnterOutput: function(output) {
waylandSurface.surface.enterOutput(output)
Helper.onSurfaceEnterOutput(waylandSurface, toplevelVerticalSurfaceItem, output)
}
onLeaveOutput: function(output) {
waylandSurface.surface.leaveOutput(output)
Helper.onSurfaceLeaveOutput(waylandSurface, toplevelVerticalSurfaceItem, output)
}
}
TiledToplevelHelper {
id: helper
surface: toplevelVerticalSurfaceItem
waylandSurface: toplevelVerticalSurfaceItem.waylandSurface
creator: toplevelComponent
}
}
}
@ -289,7 +242,7 @@ Item {
parent: getSurfaceItemFromWaylandSurface(popupSurface.parentSurface)
id: inputPopupSurface
surface: popupSurface
shellSurface: popupSurface
}
}
}

259
src/qml/VerticalLayout.qml Normal file
View File

@ -0,0 +1,259 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Waylib.Server
import TreeLand
import TreeLand.Protocols
import TreeLand.Utils
Item {
id: verticalLayout
property int spacing: 0 // Distance between this pane and that pane, temporarily set to 0.
property Item selectSurfaceItem1: null
property Item selectSurfaceItem2: null
property Item currentSurfaceItem: null
LoggingCategory {
id: vCategory
name: "treeland.tiledlayout.vertical"
defaultLogLevel: LoggingCategory.Info
}
function addPane(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (wsPanes.length === 0) {
surfaceItem.x = 0
surfaceItem.y = 0
surfaceItem.width = root.width
surfaceItem.height = root.height
surfaceItem.visible = true
wsPanes.push(surfaceItem)
} else {
let scale = wsPanes.length / (wsPanes.length + 1)
wsPanes[0].y = 0
wsPanes[0].height *= scale
wsPanes[0].visible = true
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[0].x
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height *= scale
wsPanes[i].width = wsPanes[0].width
wsPanes[i].visible = true
}
surfaceItem.x = wsPanes[0].x
surfaceItem.y = wsPanes[wsPanes.length - 1].y + wsPanes[wsPanes.length - 1].height
surfaceItem.height = root.height * (1.0 - scale)
surfaceItem.width = wsPanes[0].width
surfaceItem.visible = true
wsPanes.push(surfaceItem)
}
workspaceManager.syncWsPanes("addPane")
}
// TODO: Update the ui of choosing logic.
function choosePane(id) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
currentSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
if (id === 1) { // selected for selectPane1.
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem1 = wsPanes[0]
} else {
selectSurfaceItem1 = wsPanes[index+1]
}
console.info(vCategory, "The first selected pane is index", wsPanes.indexOf(selectSurfaceItem1))
Helper.activatedSurface = selectSurfaceItem1.shellSurface
} else if (id === 2) { // selectd for selectPane2.
let index = wsPanes.indexOf(currentSurfaceItem)
if (index === wsPanes.length - 1) {
selectSurfaceItem2 = wsPanes[0]
} else {
selectSurfaceItem2 = wsPanes[index+1]
}
console.info(vCategory, "The second selected pane is index", wsPanes.indexOf(selectSurfaceItem2))
Helper.activatedSurface = selectSurfaceItem2.shellSurface
}
}
function removePane(removeSurfaceIf) {
console.info(vCategory, "vertical layout remove pane.")
let surfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(surfaceItem)
if (wsPanes.length === 1) {
wsPanes.splice(index, 1)
// It is no necessory to modify the height or y when removing a pane.
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
} else {
let scale = wsPanes.length / (wsPanes.length - 1) // Magnification factor.
wsPanes.splice(index, 1)
wsPanes[0].y = 0
wsPanes[0].height *= scale
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].x = wsPanes[0].x
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height *= scale
wsPanes[i].width = wsPanes[0].width
}
if (removeSurfaceIf === 1) {
Helper.closeSurface(surfaceItem.shellSurface.surface)
deleteFlag.push(1)
} else if (removeSurfaceIf === 0) surfaceItem.visible = false
}
workspaceManager.syncWsPanes("removePane")
}
// Direction: 1 = Left, 2 = Right, 3 = Up, 4 = Down.
function resizePane(size, direction) {
console.info(vCategory, "vertical layout resize pane.")
let activeSurfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let index = wsPanes.indexOf(activeSurfaceItem)
if (wsPanes.length === 1) {
console.info(vCategory, "Only one pane, cannot call resizePane().")
return
}
if (index === 0) {
let delta = size / (wsPanes.length - 1)
if (direction === 3) {
console.info(vCategory, "You cannot up anymore!")
return
} else if (direction === 4) {
activeSurfaceItem.height += size
for (let i = 1; i < wsPanes.length; i++) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height;
wsPanes[i].height -= delta
}
}
} else {
let delta = size / index
let last = wsPanes.length - 1
if (index === last) {
if (direction === 3) {
wsPanes[last].height -= size
wsPanes[last].y += size
for (let i = last - 1; i >= 0; --i) {
wsPanes[i].height += delta
wsPanes[i].y = wsPanes[i+1].y - wsPanes[i].height
}
wsPanes[0].y = 0
} else if (direction === 4) {
console.info(vCategory, "You cannot down anymore!")
return
}
} else if (direction === 3) {
wsPanes[0].y = 0
wsPanes[0].height += delta
// the middle of panes
for (let i = 1; i < index; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height += delta
}
// current pane
activeSurfaceItem.y += size
activeSurfaceItem.height -= size
} else if (direction === 4) {
// the last of pane
wsPanes[last].y += delta
wsPanes[last].height -= delta
for (let i = last - 1; i > index; i--) {
wsPanes[i].height -= delta
wsPanes[i].y = wsPanes[i+1].y - wsPanes[i].height
}
activeSurfaceItem.y = activeSurfaceItem.y // y is not change
activeSurfaceItem.height += size
}
}
workspaceManager.syncWsPanes("resizePane")
}
function swapPane() {
console.info(vCategory, "vertical layout swap pane")
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
if (selectSurfaceItem1 === null || selectSurfaceItem2 === null) {
console.info(vCategory, "You should choose two panes before swap them.")
return
}
let activeSurfaceItem = selectSurfaceItem1
let targetSurfaceItem = selectSurfaceItem2
let index1 = wsPanes.indexOf(activeSurfaceItem)
let index2 = wsPanes.indexOf(targetSurfaceItem)
if (index1 === index2) {
console.info(vCategory, "You should choose two different panes to swap.")
return
}
let tempIndex1 = null
let tempIndex2 = null
for (let i = 0; i < root.panes.length; ++i) {
if (wsPanes[index1] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex1 = i
}
if (wsPanes[index2] === root.panes[i] && root.paneByWs[i] === currentWsId) {
tempIndex2 = i
}
}
if (index1 < index2) {
if (index2 - index1 === 1) {
targetSurfaceItem.y = activeSurfaceItem.y
activeSurfaceItem.y = targetSurfaceItem.y + targetSurfaceItem.height
} else {
let tempPane = targetSurfaceItem
tempPane.y = activeSurfaceItem.y
wsPanes[index1+1].y = tempPane.y + tempPane.height
for (let i = index1 + 2; i < index2; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
targetSurfaceItem = tempPane
activeSurfaceItem.y = wsPanes[index2-1].y + wsPanes[index2-1].height
}
} else if (index1 > index2) {
if (index1 - index2 === 1) {
activeSurfaceItem.y = targetSurfaceItem.y
targetSurfaceItem.y = activeSurfaceItem.y + activeSurfaceItem.height
} else {
let tempPane = activeSurfaceItem
tempPane.y = targetSurfaceItem.y
wsPanes[index2+1].y = tempPane.y + tempPane.height
for (let i = index2 + 2; i < index1; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
}
activeSurfaceItem = tempPane
targetSurfaceItem.y = wsPanes[index1-1].y + wsPanes[index1-1].height
}
}
let temp1 = root.panes[tempIndex1]
root.panes[tempIndex1] = root.panes[tempIndex2]
root.panes[tempIndex2] = temp1
let temp2 = wsPanes[index1];
wsPanes[index1] = wsPanes[index2];
wsPanes[index2] = temp2;
workspaceManager.syncWsPanes("swapPane")
}
function reLayout(surfaceItem) {
let wsPanes = workspaceManager.wsPanesById.get(currentWsId)
let scale = wsPanes.length / (wsPanes.length - 1)
let index = wsPanes.indexOf(surfaceItem)
wsPanes.splice(index, 1)
wsPanes[0].y = 0
wsPanes[0].height *= scale
for (let i = 1; i < wsPanes.length; ++i) {
wsPanes[i].y = wsPanes[i-1].y + wsPanes[i-1].height
wsPanes[i].height *= scale
}
workspaceManager.syncWsPanes("reLayout", surfaceItem)
}
}

View File

@ -0,0 +1,175 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Waylib.Server
import TreeLand
import TreeLand.Protocols
import TreeLand.Utils
Item {
id: workspaceManager
property var wsPanesById: new Map() // The {id : panes[...]} means a 'id' manages a workspace's panes.
property var wsLayoutById: new Map()
property list <int> wsList: []
LoggingCategory {
id: wmCategory
name: "com.qt.category"
defaultLogLevel: LoggingCategory.Info
}
function createWs() {
console.info(wmCategory, "Creating workspace.")
if (wsList.length === 0) {
currentWsId = 0
wsPanesById.set(0, [])
wsLayoutById.set(0, currentLayout)
wsList.push(currentWsId)
} else {
let size = wsList.length
wsPanesById.set(wsList[size-1] + 1, [])
wsLayoutById.set(wsList[size-1] + 1, currentLayout)
wsList.push(wsList[size-1] + 1)
}
}
function syncWsPanes(opClass, surfaceItem) {
if (opClass === "addPane") {
console.info(wmCategory, "Sync the addPane() function.")
panes.push(wsPanesById.get(currentWsId)[wsPanesById.get(currentWsId).length - 1])
paneByWs.push(currentWsId)
} else if (opClass === "removePane") {
console.info(wmCategory, "Sync the removePane() function.")
let cnt = 0
let index = -1
for (let i = 0; i < paneByWs.length; ++i) {
if (paneByWs[i] === currentWsId && wsPanesById.get(currentWsId).indexOf(panes[i]) === -1) {
// Find the window that was deleted in wsPanes but not deleted in pane
index = i
break // only delete one pane once.
}
}
panes.splice(index, 1)
paneByWs.splice(index, 1)
for (let i = 0; i < paneByWs.length; ++i) {
if (paneByWs[i] === currentWsId) { // Update the size of the workspace pane in the pane.
panes[i].x = wsPanesById.get(currentWsId)[cnt].x
panes[i].y = wsPanesById.get(currentWsId)[cnt].y
panes[i].height = wsPanesById.get(currentWsId)[cnt].height
panes[i].width = wsPanesById.get(currentWsId)[cnt].width
++cnt;
}
}
} else if (opClass === "resizePane" ) {
console.info(wmCategory, "Sync the resizePane() function.")
let cnt = 0
for (let i = 0; i < paneByWs.length; ++i) {
if (paneByWs[i] === currentWsId) {
panes[i].x = wsPanesById.get(currentWsId)[cnt].x
panes[i].y = wsPanesById.get(currentWsId)[cnt].y
panes[i].height = wsPanesById.get(currentWsId)[cnt].height
panes[i].width = wsPanesById.get(currentWsId)[cnt].width
++cnt
}
}
} else if (opClass === "swapPane") {
console.info(wmCategory, "Sync the swapPane() function.")
let cnt = 0
for (let i = 0; i < paneByWs.length; ++i) {
if (paneByWs[i] === currentWsId) {
panes[i].x = wsPanesById.get(currentWsId)[cnt].x
panes[i].y = wsPanesById.get(currentWsId)[cnt].y
panes[i].height = wsPanesById.get(currentWsId)[cnt].height
panes[i].width = wsPanesById.get(currentWsId)[cnt].width
++cnt
}
}
cnt = 0
for (let i = 0; i < root.panes.length; ++i) {
if (paneByWs[i] === currentWsId) {
root.panes[i].visible = wsPanesById.get(currentWsId)[cnt].visible
++cnt
}
}
} else if (opClass === "reLayout") {
console.info(wmCategory, "Sync the reLayout() function.")
let cnt = 0
for (let i = 0; i < paneByWs.length; ++i) {
if (panes[i] === surfaceItem) {
paneByWs.splice(i, 1)
panes.splice(i, 1)
break
}
}
for (let i = 0; i < paneByWs.length; ++i) {
if (paneByWs[i] === currentWsId) {
panes[i].x = wsPanesById.get(currentWsId)[cnt].x
panes[i].y = wsPanesById.get(currentWsId)[cnt].y
panes[i].height = wsPanesById.get(currentWsId)[cnt].height
panes[i].width = wsPanesById.get(currentWsId)[cnt].width
++cnt
}
}
}
}
function switchNextWs() {
console.info(wmCategory, "Switching to the next workspace.")
let index = wsList.indexOf(currentWsId)
let toId = 0
if (index === wsList.length - 1) toId = wsList[0];
else toId = wsList[index+1]
let fromId = currentWsId
console.info(wmCategory, "From the workspace", fromId, "to the workspace", toId, ".")
let fromPanes = wsPanesById.get(fromId)
for (let i = 0; i < fromPanes.length; ++i) {
fromPanes[i].visible = false
}
let toPanes = wsPanesById.get(toId)
for (let i = 0; i < toPanes.length; ++i) {
toPanes[i].visible = true
}
currentWsId = toId
currentLayout = wsLayoutById.get(currentWsId)
console.info(wmCategory, "currentLayout is", currentLayout)
}
function destoryWs() {
console.info(wmCategory, "Destorying the workspace", currentWsId)
if (wsPanesById.size === 1) {
console.info(wmCategory, "You have only one workspace so you cannot destory it.")
return
}
let wsPanes = wsPanesById.get(currentWsId)
let len = wsPanes.length
let cnt = 0
for (let pos = paneByWs.indexOf(currentWsId); pos != -1; pos = paneByWs.indexOf(currentWsId)) {
Helper.closeSurface(panes[pos].shellSurface.surface)
deleteFlag.push(1)
panes.splice(pos, 1)
paneByWs.splice(pos, 1)
}
wsPanes.splice(0, len)
wsPanesById.delete(currentWsId)
wsLayoutById.delete(currentWsId)
let index = wsList.indexOf(currentWsId)
if (index === wsList.length - 1) {
wsList.splice(index, 1)
currentWsId = wsList[0]
} else {
currentWsId = wsList[index+1]
wsList.splice(index, 1)
}
for (let i = 0; i < wsPanesById.get(currentWsId).length; ++i) {
wsPanesById.get(currentWsId)[i].visible = true
}
}
// TODO: fulfil the moveWs() function.
function moveWs(currentWsId, toWsId) {
let surfaceItem = root.getSurfaceItemFromWaylandSurface(Helper.activatedSurface).item
}
}

View File

@ -731,70 +731,75 @@ void Helper::enableOutput(WOutput *output)
bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event)
{
if (event->type() == QEvent::KeyRelease) {
if (!m_actions.empty() && !m_currentUser.isEmpty()) {
auto e = static_cast<QKeyEvent *>(event);
QKeySequence sequence(e->modifiers() | e->key());
bool isFind = false;
for (QAction *action : m_actions[m_currentUser]) {
if (action->shortcut() == sequence) {
isFind = true;
action->activate(QAction::Trigger);
}
if (event->type() == QEvent::KeyPress) {
auto kevent = static_cast<QKeyEvent*>(event);
auto modifiers = kevent->modifiers();
auto key = kevent->key();
// printf("modifiers: %d, key: %d\n", modifiers, key);
if (modifiers.testFlag(Qt::MetaModifier)) {
switch (key) {
case Qt::Key_Q:
qApp->quit();
return true;
case Qt::Key_Space:
Q_EMIT switchLayout();
return true;
case Qt::Key_H:
Q_EMIT resizePane(10, 1); // 左
return true;
case Qt::Key_J:
Q_EMIT resizePane(10, 4); // 下
return true;
case Qt::Key_K:
Q_EMIT resizePane(10, 3); // 上
return true;
case Qt::Key_L:
Q_EMIT resizePane(10, 2); // 右
return true;
case Qt::Key_T: // This is because the <Meta + S> has been used by stack layout.
Q_EMIT swapPane();
return true;
case Qt::Key_1:
Q_EMIT choosePane(1);
return true;
case Qt::Key_2:
Q_EMIT choosePane(2);
return true;
case Qt::Key_D:
Q_EMIT removePane(1);
return true;
case Qt::Key_M:
return true;
case Qt::Key_Tab:
Q_EMIT swapPane();
return true;
default:
// printf("undefined modifiers: %d, key: %d\n", modifiers, key);
return false;
}
}
if (isFind) {
if (modifiers.testFlag(Qt::AltModifier)) {
switch (key) {
case Qt::Key_C:
Q_EMIT createWs();
return true;
case Qt::Key_D:
Q_EMIT destoryWs();
return true;
case Qt::Key_M:
return true;
case Qt::Key_S:
Q_EMIT switchNextWs();
return true;
}
}
}
// Alt+Tab switcher
// TODO: move to mid handle
auto e = static_cast<QKeyEvent *>(event);
switch (e->key()) {
case Qt::Key_Alt: {
if (m_switcherOn && event->type() == QKeyEvent::KeyRelease) {
m_switcherOn = false;
Q_EMIT switcherOnChanged(false);
return false;
}
} break;
case Qt::Key_Tab:
case Qt::Key_Backtab: {
if (event->type() == QEvent::KeyPress) {
// switcher would be exclusively disabled when multitask etc is on
if (e->modifiers().testFlag(Qt::AltModifier) && m_switcherEnabled) {
if (e->modifiers() == Qt::AltModifier) {
Q_EMIT switcherChanged(Switcher::Next);
return true;
} else if (e->modifiers() == (Qt::AltModifier | Qt::ShiftModifier)) {
Q_EMIT switcherChanged(Switcher::Previous);
return true;
}
}
}
} break;
case Qt::Key_BracketLeft:
case Qt::Key_Delete: {
if (e->modifiers() == Qt::MetaModifier) {
Q_EMIT backToNormal();
Q_EMIT reboot();
return true;
}
} break;
default: {
} break;
}
if (event->type() == QEvent::KeyPress) {
auto kevent = static_cast<QKeyEvent *>(event);
if (QKeySequence(kevent->keyCombination()) == QKeySequence::Quit) {
// NOTE: 133 exitcode is reset DDM restart limit.
qApp->exit(133);
return true;
}
if (event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress) {
seat->cursor()->setVisible(true);
} else if (event->type() == QEvent::TouchBegin) {
seat->cursor()->setVisible(false);
}
if (watched) {

View File

@ -173,6 +173,19 @@ Q_SIGNALS:
void currentWorkspaceIdChanged();
void currentUserChanged(const QString &user);
// 键盘信号
void resizePane(int size, int direction);
void choosePane(int id);
void swapPane();
void removePane(int flag);
void switchLayout();
void createWs();
void destoryWs();
void switchNextWs();
// void switchBackWs();
void moveWs(int wsId);
protected:
bool beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event) override;
bool afterHandleEvent(WSeat *seat,