mirror of
https://github.com/Calamytryx/MineLauncher.git
synced 2026-05-19 13:54:48 -04:00
Refactor configuration and UI components for improved structure and functionality; add launcher icon configuration and enhance grid layouts.
This commit is contained in:
17
contents/config/config.qml
Normal file
17
contents/config/config.qml
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
import org.kde.plasma.configuration 2.0
|
||||
|
||||
ConfigModel {
|
||||
ConfigCategory {
|
||||
name: i18n("General")
|
||||
icon: "preferences-desktop-plasma"
|
||||
source: "ConfigGeneral.qml"
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@
|
||||
<kcfgfile name=""/>
|
||||
|
||||
<group name="General">
|
||||
<entry name="favoriteApps" type="String">
|
||||
<default></default>
|
||||
<entry name="launcherIcon" type="String">
|
||||
<default>applications-all</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
|
||||
@@ -12,24 +12,13 @@ Rectangle {
|
||||
|
||||
signal clicked()
|
||||
|
||||
color: isActive ? "#8B8B8B" : "#5B5B5B"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
color: isActive ? "#C6C6C6" : "#8B8B8B"
|
||||
z: isActive ? 9999999 : 0
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 100 }
|
||||
}
|
||||
|
||||
// Inner highlight
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.devicePixelRatio
|
||||
color: "transparent"
|
||||
border.color: isActive ? "#FFFFFF" : "#7B7B7B"
|
||||
border.width: Kirigami.Units.devicePixelRatio
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
// Icon
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
@@ -37,7 +26,7 @@ Rectangle {
|
||||
height: Kirigami.Units.iconSizes.medium
|
||||
source: categoryIcon
|
||||
smooth: true
|
||||
color: "#FFFFFF"
|
||||
color: "#000"
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
@@ -78,19 +67,6 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onEntered: {
|
||||
hovered = true
|
||||
if (!isActive) {
|
||||
tab.color = Qt.lighter(tab.color, 1.2)
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
hovered = false
|
||||
if (!isActive) {
|
||||
tab.color = "#5B5B5B"
|
||||
}
|
||||
}
|
||||
onClicked: tab.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
55
contents/ui/ConfigGeneral.qml
Normal file
55
contents/ui/ConfigGeneral.qml
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.kcmutils as KCM
|
||||
import org.kde.iconthemes as KIconThemes
|
||||
|
||||
KCM.SimpleKCM {
|
||||
id: configGeneral
|
||||
|
||||
property string cfg_launcherIcon: Plasmoid.configuration.launcherIcon || "applications-all"
|
||||
|
||||
Kirigami.FormLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Button {
|
||||
id: iconButton
|
||||
|
||||
Kirigami.FormData.label: i18n("Launcher Icon:")
|
||||
|
||||
implicitWidth: Kirigami.Units.iconSizes.large + Kirigami.Units.smallSpacing * 2
|
||||
implicitHeight: Kirigami.Units.iconSizes.large + Kirigami.Units.smallSpacing * 2
|
||||
|
||||
onPressed: iconDialog.open()
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.iconSizes.large
|
||||
height: width
|
||||
source: configGeneral.cfg_launcherIcon || "applications-all"
|
||||
}
|
||||
|
||||
KIconThemes.IconDialog {
|
||||
id: iconDialog
|
||||
onIconNameChanged: configGeneral.cfg_launcherIcon = iconName || "applications-all"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: i18n("Choose an icon for the compact launcher representation.")
|
||||
font.italic: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ Item {
|
||||
property string appExec: ""
|
||||
property bool hovered: false
|
||||
property bool isFavorite: false
|
||||
property bool isFavoriteRow: false
|
||||
|
||||
signal clicked()
|
||||
signal rightClicked()
|
||||
@@ -22,39 +23,19 @@ Item {
|
||||
Rectangle {
|
||||
id: slotBg
|
||||
anchors.fill: parent
|
||||
color: hovered ? "#A0A0A0" : "#8B8B8B"
|
||||
border.color: "#C6C6C6"
|
||||
border.width: 3
|
||||
antialiasing: false // Disable antialiasing for crisp edges
|
||||
color: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 100 }
|
||||
}
|
||||
|
||||
// Inner rectangle with only top and left borders
|
||||
// Inner rectangle
|
||||
Rectangle {
|
||||
id: innerBorders
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1 // Small margin to avoid overlap with parent border
|
||||
color: "transparent"
|
||||
color: "#8B8B8B"
|
||||
|
||||
// Top border
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
|
||||
// Left border
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
}
|
||||
// App icon
|
||||
Kirigami.Icon {
|
||||
@@ -65,9 +46,9 @@ Item {
|
||||
smooth: true
|
||||
}
|
||||
|
||||
// Favorite star indicator
|
||||
// Favorite star indicator (only show if not in favorite row)
|
||||
Text {
|
||||
visible: isFavorite
|
||||
visible: isFavorite && !isFavoriteRow
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Kirigami.Units.smallSpacing / 2
|
||||
@@ -81,7 +62,7 @@ Item {
|
||||
id: tooltip
|
||||
visible: hovered && appName !== ""
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Kirigami.Units.smallSpacing
|
||||
width: tooltipText.width + Kirigami.Units.largeSpacing
|
||||
height: tooltipText.height + Kirigami.Units.smallSpacing
|
||||
@@ -89,7 +70,7 @@ Item {
|
||||
border.color: "#2A2A2A"
|
||||
border.width: Kirigami.Units.devicePixelRatio
|
||||
radius: Kirigami.Units.smallSpacing / 2
|
||||
z: 1000
|
||||
z: 999999
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
69
contents/ui/StaticFavoriteGrid.qml
Normal file
69
contents/ui/StaticFavoriteGrid.qml
Normal file
@@ -0,0 +1,69 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Grid {
|
||||
id: staticFavoriteGrid
|
||||
property int cellWidth: Kirigami.Units.gridUnit * 3.5
|
||||
property int cellHeight: Kirigami.Units.gridUnit * 3.5
|
||||
|
||||
readonly property int numCols: 10 // Force 10 columns
|
||||
readonly property int numRows: 1 // Force 1 row
|
||||
readonly property int totalCells: numCols * numRows
|
||||
|
||||
columns: numCols
|
||||
z: 9999999
|
||||
|
||||
Repeater {
|
||||
model: staticFavoriteGrid.totalCells
|
||||
|
||||
Item {
|
||||
width: staticFavoriteGrid.cellWidth
|
||||
height: staticFavoriteGrid.cellHeight
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "#C6C6C6"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
contents/ui/StaticGrid.qml
Normal file
69
contents/ui/StaticGrid.qml
Normal file
@@ -0,0 +1,69 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Grid {
|
||||
id: staticGrid
|
||||
property int cellWidth: Kirigami.Units.gridUnit * 3.5
|
||||
property int cellHeight: Kirigami.Units.gridUnit * 3.5
|
||||
|
||||
readonly property int numCols: 10 // Force 10 columns
|
||||
readonly property int numRows: 5 // Force 5 rows
|
||||
readonly property int totalCells: numCols * numRows
|
||||
|
||||
columns: numCols
|
||||
z: 9999999
|
||||
|
||||
Repeater {
|
||||
model: staticGrid.totalCells
|
||||
|
||||
Item {
|
||||
width: staticGrid.cellWidth
|
||||
height: staticGrid.cellHeight
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,581 @@ import org.kde.plasma.plasma5support as Plasma5Support
|
||||
import org.kde.ksvg as KSvg
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.plasma.private.kicker 0.1 as Kicker
|
||||
import org.kde.plasma.plasma5support 2.0 as P5Support
|
||||
|
||||
PlasmoidItem {
|
||||
id: root
|
||||
|
||||
width: Kirigami.Units.gridUnit * 40
|
||||
height: Kirigami.Units.gridUnit * 35
|
||||
|
||||
Plasmoid.backgroundHints: PlasmaCore.Types.DefaultBackground
|
||||
Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground
|
||||
|
||||
preferredRepresentation: fullRepresentation
|
||||
preferredRepresentation: compactRepresentation
|
||||
|
||||
compactRepresentation: MouseArea {
|
||||
width: Kirigami.Units.gridUnit * 1.5
|
||||
height: Kirigami.Units.gridUnit * 1.5
|
||||
|
||||
Kirigami.Icon {
|
||||
anchors.centerIn: parent
|
||||
width: plasmoid.configuration.launcherIconSize || Kirigami.Units.iconSizes.large
|
||||
height: plasmoid.configuration.launcherIconSize || Kirigami.Units.iconSizes.large
|
||||
source: plasmoid.configuration.launcherIcon || "~/.local/share/plasma/plasmoids/mc_inventory/grass_block.png"
|
||||
}
|
||||
|
||||
onClicked: root.expanded = !root.expanded
|
||||
}
|
||||
|
||||
fullRepresentation: Item {
|
||||
x: plasmoid.screenGeometry.x + (plasmoid.screenGeometry.width - width) / 2
|
||||
y: plasmoid.screenGeometry.y + (plasmoid.screenGeometry.height - height) / 2
|
||||
|
||||
|
||||
Layout.preferredWidth: (backgroundRect.width)
|
||||
Layout.preferredHeight: (topCategoriesRow.height + bottomCategoriesRow.height + backgroundRect.height) // Dynamic height based on content
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 30
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 19 // Adjusted minimum accordingly
|
||||
|
||||
// Top categories outside the main container
|
||||
RowLayout {
|
||||
id: topCategoriesRow
|
||||
anchors.top: parent.top
|
||||
anchors.bottomMargin: -2 // Negative margin to overlap the border
|
||||
anchors.left: parent.left
|
||||
|
||||
height: Kirigami.Units.gridUnit * 3
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
z: 999999999
|
||||
|
||||
// Top categories
|
||||
Repeater {
|
||||
model: topCategories
|
||||
|
||||
CategoryTab {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
categoryId: modelData.id
|
||||
categoryName: modelData.name
|
||||
categoryIcon: modelData.icon
|
||||
isActive: currentCategory === modelData.id
|
||||
onClicked: currentCategory = modelData.id
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#c6c6c6"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Minecraft-style background (now smaller, containing only search, inventory, close)
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.top: topCategoriesRow.bottom
|
||||
anchors.bottom: bottomCategoriesRow.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: "#C6C6C6"
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing * 2
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Search row inside the container
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
// Search button/field
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 9
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
color: "#8B8B8B"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
|
||||
TextField {
|
||||
id: searchField
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
placeholderText: "🔍 Search"
|
||||
background: Rectangle {
|
||||
color: "#000000"
|
||||
opacity: 0.4
|
||||
}
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: searchField.height * 0.4
|
||||
horizontalAlignment: Text.AlignHLeft
|
||||
onTextChanged: searchText = text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inventory grid with custom scrollbar
|
||||
Rectangle {
|
||||
id: inventoryContainer
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: "#c6c6c6"
|
||||
|
||||
readonly property int scrollbarWidth: Kirigami.Units.gridUnit * 3.5 * 0.75
|
||||
readonly property int separatorWidth: Kirigami.Units.gridUnit * 3.5 * 0.25
|
||||
readonly property int gridAreaWidth: width - scrollbarWidth - separatorWidth
|
||||
readonly property int favoriteBarHeight: Kirigami.Units.gridUnit * 3.5
|
||||
readonly property int mainGridHeight: Kirigami.Units.gridUnit * 3.5 * 5
|
||||
|
||||
StaticGrid {
|
||||
id: staticGridDisplay
|
||||
width: inventoryContainer.gridAreaWidth
|
||||
height: inventoryContainer.mainGridHeight
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: gridView
|
||||
width: inventoryContainer.gridAreaWidth
|
||||
height: inventoryContainer.mainGridHeight
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
clip: true
|
||||
|
||||
model: getFilteredApps()
|
||||
|
||||
cellWidth: Kirigami.Units.gridUnit * 3.5
|
||||
cellHeight: Kirigami.Units.gridUnit * 3.5
|
||||
|
||||
// Force 10 columns
|
||||
property int columns: 10
|
||||
|
||||
interactive: false // Disable user interaction on the grid itself
|
||||
|
||||
// Make any change to contentY instantaneous
|
||||
Behavior on contentY { NumberAnimation { duration: 0 } }
|
||||
|
||||
delegate: InventorySlot {
|
||||
appName: modelData.name
|
||||
appIcon: modelData.icon
|
||||
appExec: modelData.desktop
|
||||
isFavorite: root.isFavorite(modelData.desktop)
|
||||
isFavoriteRow: false
|
||||
onClicked: launchApp(appExec)
|
||||
onRightClicked: root.toggleFavorite(appExec)
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: gridView.width
|
||||
height: gridView.height
|
||||
anchors.left: gridView.left
|
||||
anchors.top: gridView.top
|
||||
acceptedButtons: Qt.NoButton // Only interested in wheel events
|
||||
onWheel: {
|
||||
let newY = gridView.contentY
|
||||
if (wheel.angleDelta.y < 0) { // Scroll down
|
||||
newY += gridView.cellHeight
|
||||
} else if (wheel.angleDelta.y > 0) { // Scroll up
|
||||
newY -= gridView.cellHeight
|
||||
}
|
||||
// Clamp the position to prevent overscrolling
|
||||
gridView.contentY = Math.max(0, Math.min(newY, gridView.contentHeight - gridView.height))
|
||||
}
|
||||
}
|
||||
|
||||
// Static favorite grid background
|
||||
StaticFavoriteGrid {
|
||||
width: inventoryContainer.gridAreaWidth
|
||||
height: inventoryContainer.favoriteBarHeight
|
||||
anchors.left: gridView.left
|
||||
anchors.top: gridView.bottom
|
||||
anchors.topMargin: ((gridView.height / 5) / 4 )
|
||||
}
|
||||
|
||||
// Favorite app bar
|
||||
Grid {
|
||||
id: favoriteBar
|
||||
width: inventoryContainer.gridAreaWidth
|
||||
height: inventoryContainer.favoriteBarHeight
|
||||
anchors.left: gridView.left
|
||||
anchors.top: gridView.bottom
|
||||
anchors.topMargin: ((gridView.height / 5) / 4 )
|
||||
columns: 10
|
||||
|
||||
Repeater {
|
||||
model: 10
|
||||
|
||||
InventorySlot {
|
||||
property var favoriteApp: index < favoriteApps.length ? getFavoriteAppData(favoriteApps[index]) : null
|
||||
|
||||
appName: favoriteApp ? favoriteApp.name : ""
|
||||
appIcon: favoriteApp ? favoriteApp.icon : ""
|
||||
appExec: favoriteApp ? favoriteApp.desktop : ""
|
||||
isFavorite: true
|
||||
isFavoriteRow: true
|
||||
onClicked: {
|
||||
if (appExec) launchApp(appExec)
|
||||
}
|
||||
onRightClicked: {
|
||||
if (appExec) root.toggleFavorite(appExec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator wall
|
||||
Rectangle {
|
||||
id: separatorWall
|
||||
width: ((gridView.height / 5) / 4 )
|
||||
height: parent.height
|
||||
anchors.right: scrollbarArea.left
|
||||
anchors.left: gridView.right
|
||||
color: "#C6C6C6"
|
||||
}
|
||||
|
||||
// Custom Scrollbar
|
||||
Rectangle {
|
||||
id: scrollbarArea
|
||||
width: inventoryContainer.scrollbarWidth
|
||||
height: parent.height - 8
|
||||
y: 4
|
||||
anchors.right: parent.right
|
||||
color: "#8b8b8b"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: scrollbarHandle
|
||||
width: parent.width * 0.9
|
||||
height: Kirigami.Units.gridUnit * 3.5
|
||||
color: "#5B5B5B"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
|
||||
// Calculate Y position based on GridView's scroll
|
||||
y: {
|
||||
let scrollableHeight = gridView.contentHeight - gridView.height
|
||||
let handleScrollableHeight = scrollbarArea.height - height
|
||||
if (scrollableHeight <= 0) return 0
|
||||
return (gridView.contentY / scrollableHeight) * handleScrollableHeight
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
drag.target: parent
|
||||
drag.axis: Drag.YAxis
|
||||
drag.minimumY: 0
|
||||
drag.maximumY: scrollbarArea.height - parent.height
|
||||
|
||||
onPositionChanged: {
|
||||
let scrollableHeight = gridView.contentHeight - gridView.height
|
||||
let handleScrollableHeight = scrollbarArea.height - parent.height
|
||||
if (handleScrollableHeight <= 0) return
|
||||
|
||||
// Calculate the scroll ratio from the handle's drag position
|
||||
let scrollRatio = parent.y / handleScrollableHeight
|
||||
|
||||
// Calculate the ideal, continuous content position
|
||||
let continuousContentY = scrollRatio * scrollableHeight
|
||||
|
||||
// Snap the content position to the nearest cell row
|
||||
let snappedContentY = Math.round(continuousContentY / gridView.cellHeight) * gridView.cellHeight
|
||||
|
||||
// Apply the snapped position to the GridView
|
||||
gridView.contentY = snappedContentY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom categories outside the main container
|
||||
RowLayout {
|
||||
id: bottomCategoriesRow
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: Kirigami.Units.gridUnit * 3
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Bottom categories
|
||||
Repeater {
|
||||
model: bottomCategories
|
||||
|
||||
CategoryTab {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
categoryId: modelData.id
|
||||
categoryName: modelData.name
|
||||
categoryIcon: modelData.icon
|
||||
isActive: currentCategory === modelData.id
|
||||
onClicked: currentCategory = modelData.id
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#c6c6c6"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
// Close button
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
color: "#8B8B8B"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
border.width: 3
|
||||
antialiasing: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#2a2a2a"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: "#f7f7f7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: Kirigami.Units.gridUnit
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.expanded = false
|
||||
onEntered: parent.color = "#A0A0A0"
|
||||
onExited: parent.color = "#8B8B8B"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Data source for applications
|
||||
Plasma5Support.DataSource {
|
||||
@@ -76,6 +642,22 @@ PlasmoidItem {
|
||||
return favoriteApps.indexOf(exec) !== -1
|
||||
}
|
||||
|
||||
function getFavoriteAppData(desktopFile) {
|
||||
if (!desktopFile) return null
|
||||
|
||||
for (let source in appsSource.data) {
|
||||
let appData = appsSource.data[source]
|
||||
if ((appData.storageId || source) === desktopFile) {
|
||||
return {
|
||||
name: appData.name || appData.genericName || source,
|
||||
icon: appData.iconName || "application-x-executable",
|
||||
desktop: desktopFile
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function getFilteredApps() {
|
||||
let apps = []
|
||||
let seenDesktopFiles = {}
|
||||
@@ -135,6 +717,15 @@ PlasmoidItem {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always ensure we have exactly 50 items (5 rows × 10 columns)
|
||||
while (apps.length < 50) {
|
||||
apps.push({
|
||||
name: "",
|
||||
icon: "",
|
||||
desktop: ""
|
||||
})
|
||||
}
|
||||
|
||||
return apps
|
||||
}
|
||||
|
||||
@@ -150,174 +741,4 @@ PlasmoidItem {
|
||||
disconnectSource(sourceName)
|
||||
}
|
||||
}
|
||||
|
||||
fullRepresentation: Item {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 40
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 35
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 30
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 25
|
||||
|
||||
// Minecraft-style background
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#C6C6C6"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
|
||||
// Inner shadow effect
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.devicePixelRatio * 2
|
||||
color: "transparent"
|
||||
border.color: "#FFFFFF"
|
||||
border.width: Kirigami.Units.devicePixelRatio
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing * 2
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Top row: categories + search
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Top categories
|
||||
Repeater {
|
||||
model: topCategories
|
||||
|
||||
CategoryTab {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
categoryId: modelData.id
|
||||
categoryName: modelData.name
|
||||
categoryIcon: modelData.icon
|
||||
isActive: currentCategory === modelData.id
|
||||
onClicked: currentCategory = modelData.id
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
// Search button/field
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 9
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
color: "#8B8B8B"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
|
||||
TextField {
|
||||
id: searchField
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
placeholderText: "🔍 Search"
|
||||
background: Rectangle {
|
||||
color: "#000000"
|
||||
opacity: 0.4
|
||||
}
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: Kirigami.Theme.defaultFont.pixelSize
|
||||
horizontalAlignment: Text.AlignHLeft
|
||||
onTextChanged: searchText = text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inventory grid
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: "#8B8B8B"
|
||||
border.color: "#373737"
|
||||
border.width: 2
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
clip: true
|
||||
|
||||
Flow {
|
||||
width: scrollView.availableWidth
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: getFilteredApps()
|
||||
|
||||
InventorySlot {
|
||||
appName: modelData.name
|
||||
appIcon: modelData.icon
|
||||
appExec: modelData.desktop
|
||||
isFavorite: root.isFavorite(modelData.desktop)
|
||||
onClicked: launchApp(appExec)
|
||||
onRightClicked: root.toggleFavorite(appExec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom row: other categories + close
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Bottom categories
|
||||
Repeater {
|
||||
model: bottomCategories
|
||||
|
||||
CategoryTab {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
categoryId: modelData.id
|
||||
categoryName: modelData.name
|
||||
categoryIcon: modelData.icon
|
||||
isActive: currentCategory === modelData.id
|
||||
onClicked: currentCategory = modelData.id
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
// Close button
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
color: "#8B8B8B"
|
||||
border.color: "#373737"
|
||||
border.width: Kirigami.Units.devicePixelRatio * 2
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.devicePixelRatio
|
||||
color: "transparent"
|
||||
border.color: "#7B7B7B"
|
||||
border.width: Kirigami.Units.devicePixelRatio
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: Kirigami.Units.gridUnit
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.expanded = false
|
||||
onEntered: parent.color = "#A0A0A0"
|
||||
onExited: parent.color = "#8B8B8B"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user