Commit 0868a5ae authored by Nate Graham's avatar Nate Graham
Browse files

applets/kickoff: add "compact list item style" option and use new tall style by default

Kickoff uses an unusual way of locating list items' descriptions: it
puts them on the same line as the title, aligned to the right.

This saves vertical space but suffers from several issues:

- Because both labels need to inhabit the same line, a long title will
  cause the description to be elided into uselessness
- It's a different style than what we use for other list items with
  fundamentally the same set of data; we don't re-use users' existing
  familiarity with KDE-style list items that typically have the caption,
  subtitle, or description below the label/title
- Saving vertical space is not a win here because we want the applet to
  be touch-friendly, and short list items make that worse, not better

Accordingly, this MR adds an option to switch the list items between two
styles:
- The current style, which is now called "compact list item style"
- A new default style with the subtitle below the main text, wh...
parent c840409f
Pipeline #215529 passed with stage
in 4 minutes and 48 seconds
......@@ -49,5 +49,9 @@
<label>Whether to display captions ("shut down", "log out", etc.) for the footer action buttons</label>
<default>true</default>
</entry>
<entry name="compactMode" type="Bool">
<label>Whether to use a compact display style for list items</label>
<default>false</default>
</entry>
</group>
</kcfg>
......@@ -5,6 +5,7 @@
Copyright (C) 2015-2018 Eike Hein <hein@kde.org>
Copyright (C) 2021 by Mikel Johnson <mikel5764@gmail.com>
Copyright (C) 2021 by Noah Davis <noahadvs@gmail.com>
Copyright (C) 2022 Nate Graham <nate@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -40,7 +41,6 @@ T.ItemDelegate {
required property string description
readonly property Flickable view: ListView.view ?? GridView.view
readonly property bool textUnderIcon: display === PC3.AbstractButton.TextUnderIcon
property bool isCategory: false
readonly property bool hasActionList: model && (model.favoriteId !== null || ("hasActionList" in model && model.hasActionList === true))
property var actionList: null
......@@ -49,6 +49,10 @@ T.ItemDelegate {
property bool dragEnabled: enabled && !isCategory
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
property bool labelTruncated: false
property bool descriptionTruncated: false
property bool descriptionVisible: true
function openActionMenu(x = undefined, y = undefined) {
if (!hasActionList) { return; }
// fill actionList only when needed to prevent slowness when changing app categories rapidly.
......@@ -88,22 +92,11 @@ T.ItemDelegate {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
// We use an increased fixed vertical padding to improve touch usability
leftPadding: KickoffSingleton.listItemMetrics.margins.left
+ (!textUnderIcon && mirrored ? KickoffSingleton.fontMetrics.descent : 0)
rightPadding: KickoffSingleton.listItemMetrics.margins.right
+ (!textUnderIcon && !mirrored ? KickoffSingleton.fontMetrics.descent : 0)
topPadding: PlasmaCore.Units.smallSpacing*2
bottomPadding: PlasmaCore.Units.smallSpacing*2
spacing: KickoffSingleton.fontMetrics.descent
enabled: !model.disabled
hoverEnabled: false
icon.width: PlasmaCore.Units.iconSizes.smallMedium
icon.height: PlasmaCore.Units.iconSizes.smallMedium
text: model.name ?? model.display
Accessible.description: root.description != root.text ? root.description : ""
......@@ -128,55 +121,6 @@ T.ItemDelegate {
}
}
background: null
contentItem: GridLayout {
baselineOffset: label.y + label.baselineOffset
columnSpacing: parent.spacing
rowSpacing: parent.spacing
flow: root.textUnderIcon ? GridLayout.TopToBottom : GridLayout.LeftToRight
PlasmaCore.IconItem {
id: iconItem
Layout.alignment: root.textUnderIcon ? Qt.AlignHCenter | Qt.AlignBottom : Qt.AlignLeft | Qt.AlignVCenter
implicitWidth: root.icon.width
implicitHeight: root.icon.height
animated: false
usesPlasmaTheme: false
source: root.decoration || root.icon.name || root.icon.source
}
PC3.Label {
id: label
Layout.alignment: root.textUnderIcon ? Qt.AlignHCenter | Qt.AlignTop : Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
Layout.preferredHeight: root.textUnderIcon && lineCount === 1 ? implicitHeight * 2 : implicitHeight
text: root.text
elide: Text.ElideRight
horizontalAlignment: root.textUnderIcon ? Text.AlignHCenter : Text.AlignLeft
verticalAlignment: root.textUnderIcon ? Text.AlignTop : Text.AlignVCenter
maximumLineCount: 2
wrapMode: Text.Wrap
textFormat: root.model && root.model.isMultilineText ? Text.StyledText : Text.PlainText
}
}
PC3.Label {
id: descriptionLabel
parent: root
anchors {
left: root.contentItem.left
right: root.contentItem.right
baseline: root.contentItem.baseline
leftMargin: root.textUnderIcon ? 0 : root.implicitContentWidth + root.spacing
baselineOffset: root.textUnderIcon ? implicitHeight : 0
}
visible: !textUnderIcon && text.length > 0
enabled: false
text: root.Accessible.description
elide: Text.ElideRight
horizontalAlignment: root.textUnderIcon ? Text.AlignHCenter : Text.AlignRight
verticalAlignment: root.textUnderIcon ? Text.AlignTop : Text.AlignVCenter
maximumLineCount: 1
}
Drag.active: mouseArea.drag.active
Drag.dragType: Drag.Automatic
Drag.mimeData: { "text/uri-list" : root.url }
......@@ -250,15 +194,15 @@ T.ItemDelegate {
}
PC3.ToolTip.text: {
const showDescription = descriptionLabel.truncated
|| (textUnderIcon && Accessible.description.length > 0)
if (label.truncated && showDescription) {
if (root.labelTruncated && root.descriptionTruncated) {
return `${text} (${description})`
} else if (showDescription) {
} else if (root.descriptionTruncated || !root.descriptionVisible) {
return description
}
return ""
}
PC3.ToolTip.visible: mouseArea.containsMouse && PC3.ToolTip.text.length > 0
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
background: null
}
......@@ -19,7 +19,7 @@ BasePage {
model: plasmoid.rootItem.rootModel
// needed otherwise app displayed at top-level will show a first character as group.
section.property: ""
delegate: KickoffItemDelegate {
delegate: KickoffListDelegate {
width: view.availableWidth
isCategory: model.hasChildren
}
......
/*
SPDX-FileCopyrightText: 2013 David Edmundson <davidedmundson@kde.org>
SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com>
SPDX-FileCopyrightText: 2022 Nate Graham <nate@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -22,6 +23,7 @@ ColumnLayout {
property var cfg_systemFavorites: String(plasmoid.configuration.systemFavorites)
property int cfg_primaryActions: plasmoid.configuration.primaryActions
property alias cfg_showActionButtonCaptions: showActionButtonCaptions.checked
property alias cfg_compactMode: compactModeCheckbox.checked
Kirigami.FormLayout {
Button {
......@@ -80,9 +82,24 @@ ColumnLayout {
CheckBox {
id: alphaSort
Kirigami.FormData.label: i18nc("General options", "General:")
text: i18n("Always sort applications alphabetically")
}
CheckBox {
id: compactModeCheckbox
text: i18n("Use compact list item style")
checked: Kirigami.Settings.tabletMode ? true : plasmoid.configuration.compactMode
enabled: !Kirigami.Settings.tabletMode
}
Label {
visible: Kirigami.Settings.tabletMode
text: i18nc("@info:usagetip under a checkbox when Touch Mode is on", "Automatically disabled when in Touch Mode")
Layout.fillWidth: true
wrapMode: Text.Wrap
font: Kirigami.Theme.smallFont
}
Button {
enabled: KQuickAddons.KCMShell.authorize("kcm_plasmasearch.desktop").length > 0
icon.name: "settings-configure"
......
......@@ -88,7 +88,7 @@ EmptyPage {
// Forces the function be re-run every time runnerModel.count changes.
// This is absolutely necessary to make the search view work reliably.
model: plasmoid.rootItem.runnerModel.count ? plasmoid.rootItem.runnerModel.modelForRow(0) : null
delegate: KickoffItemDelegate {
delegate: KickoffListDelegate {
width: view.availableWidth
isSearchResult: true
}
......
......@@ -14,7 +14,7 @@ DropArea {
property real scrollUpMargin: 0
property real scrollDownMargin: 0
enabled: plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
onPositionChanged: if (drag.source instanceof KickoffItemDelegate) {
onPositionChanged: if (drag.source instanceof KickoffGridDelegate || drag.source instanceof KickoffListDelegate) {
const source = drag.source
const view = drag.source.view
if (source.view === root.targetView && !view.move.running && !view.moveDisplaced.running) {
......
/*
Copyright (C) 2011 Martin *Gräßlin <mgraesslin@kde.org>
Copyright (C) 2012 Gregor Taetzner <gregor@freenet.de>
Copyright 2014 Sebastian Kügler <sebas@kde.org>
Copyright (C) 2015-2018 Eike Hein <hein@kde.org>
Copyright (C) 2021 by Mikel Johnson <mikel5764@gmail.com>
Copyright (C) 2021 by Noah Davis <noahadvs@gmail.com>
Copyright (C) 2022 Nate Graham <nate@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PC3
AbstractKickoffItemDelegate {
id: root
leftPadding: KickoffSingleton.listItemMetrics.margins.left
rightPadding: KickoffSingleton.listItemMetrics.margins.right
topPadding: PlasmaCore.Units.smallSpacing * 2
bottomPadding: PlasmaCore.Units.smallSpacing * 2
icon.width: PlasmaCore.Units.iconSizes.large
icon.height: PlasmaCore.Units.iconSizes.large
labelTruncated: label.truncated
descriptionVisible: false
contentItem: ColumnLayout {
spacing: root.spacing
PlasmaCore.IconItem {
implicitWidth: root.icon.width
implicitHeight: root.icon.height
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
animated: false
usesPlasmaTheme: false
source: root.decoration || root.icon.name || root.icon.source
}
PC3.Label {
id: label
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.fillWidth: true
Layout.preferredHeight: label.lineCount === 1 ? label.implicitHeight * 2 : label.implicitHeight
text: root.text
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
maximumLineCount: 2
wrapMode: Text.Wrap
}
}
}
......@@ -129,11 +129,8 @@ EmptyPage {
prefix: "hover"
}
delegate: KickoffItemDelegate {
delegate: KickoffGridDelegate {
id: itemDelegate
icon.width: PlasmaCore.Units.iconSizes.large
icon.height: PlasmaCore.Units.iconSizes.large
display: PC3.AbstractButton.TextUnderIcon
width: view.cellWidth
Accessible.role: Accessible.Cell
}
......
/*
Copyright (C) 2011 Martin *Gräßlin <mgraesslin@kde.org>
Copyright (C) 2012 Gregor Taetzner <gregor@freenet.de>
Copyright 2014 Sebastian Kügler <sebas@kde.org>
Copyright (C) 2015-2018 Eike Hein <hein@kde.org>
Copyright (C) 2021 by Mikel Johnson <mikel5764@gmail.com>
Copyright (C) 2021 by Noah Davis <noahadvs@gmail.com>
Copyright (C) 2022 Nate Graham <nate@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami 2.16 as Kirigami
AbstractKickoffItemDelegate {
id: root
property bool compact: Kirigami.Settings.tabletMode ? false : plasmoid.configuration.compactMode
leftPadding: KickoffSingleton.listItemMetrics.margins.left
+ (mirrored ? KickoffSingleton.fontMetrics.descent : 0)
rightPadding: KickoffSingleton.listItemMetrics.margins.right
+ (!mirrored ? KickoffSingleton.fontMetrics.descent : 0)
// Otherwise it's *too* compact :)
topPadding: compact ? PlasmaCore.Units.mediumSpacing : PlasmaCore.Units.smallSpacing
bottomPadding: compact ? PlasmaCore.Units.mediumSpacing : PlasmaCore.Units.smallSpacing
icon.width: compact || root.isCategory ? PlasmaCore.Units.iconSizes.smallMedium : PlasmaCore.Units.iconSizes.medium
icon.height: compact || root.isCategory ? PlasmaCore.Units.iconSizes.smallMedium : PlasmaCore.Units.iconSizes.medium
labelTruncated: label.truncated
descriptionTruncated: descriptionLabel.truncated
descriptionVisible: descriptionLabel.visible
contentItem: RowLayout {
id: row
spacing: KickoffSingleton.listItemMetrics.margins.left * 2
PlasmaCore.IconItem {
id: icon
implicitWidth: root.icon.width
implicitHeight: root.icon.height
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
animated: false
usesPlasmaTheme: false
source: root.decoration || root.icon.name || root.icon.source
}
GridLayout {
id: gridLayout
Layout.fillWidth: true
rows: root.compact ? 1 : 2
columns: root.compact ? 2 : 1
rowSpacing: 0
columnSpacing: root.spacing
PC3.Label {
id: label
Layout.fillWidth: !descriptionLabel.visible
Layout.maximumWidth: root.width - root.leftPadding - root.rightPadding - icon.width - row.spacing
Layout.preferredHeight: {
if (root.isCategory) {
return root.compact ? implicitHeight : Math.round(implicitHeight * 1.5);
}
if (!root.compact && !descriptionLabel.visible) {
return implicitHeight * 2;
}
return implicitHeight;
}
text: root.text
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
maximumLineCount: 1
}
PC3.Label {
id: descriptionLabel
Layout.fillWidth: true
visible: text.length > 0 && text !== root.text
enabled: false
text: root.description
font: PlasmaCore.Theme.smallestFont
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: root.compact ? Text.AlignRight : Text.AlignLeft
maximumLineCount: 1
}
}
}
}
......@@ -130,7 +130,7 @@ EmptyPage {
prefix: "hover"
}
delegate: KickoffItemDelegate {
delegate: KickoffListDelegate {
width: view.availableWidth
}
......@@ -139,13 +139,13 @@ EmptyPage {
criteria: ViewSection.FullString
delegate: PC3.AbstractButton {
width: view.availableWidth
height: KickoffSingleton.listDelegateHeight
height: KickoffSingleton.compactListDelegateHeight
PC3.Label {
id: contentLabel
anchors.left: parent.left
width: section.length === 1
? KickoffSingleton.listDelegateContentHeight + leftPadding + rightPadding
? KickoffSingleton.compactListDelegateContentHeight + leftPadding + rightPadding
: parent.width
height: parent.height
leftPadding: view.effectiveLayoutDirection === Qt.LeftToRight
......@@ -156,7 +156,7 @@ EmptyPage {
verticalAlignment: Text.AlignVCenter
maximumLineCount: 1
elide: Text.ElideRight
font.pixelSize: KickoffSingleton.listDelegateContentHeight
font.pixelSize: KickoffSingleton.compactListDelegateContentHeight
enabled: hoverHandler.hovered
text: section.length === 1 ? section.toUpperCase() : section
}
......
......@@ -57,32 +57,43 @@ Item {
readonly property real gridCellSize: gridDelegate.implicitHeight
readonly property real listDelegateHeight: listDelegate.implicitHeight
readonly property real listDelegateContentHeight: listDelegate.implicitContentHeight
readonly property real compactListDelegateHeight: compactListDelegate.implicitHeight
readonly property real compactListDelegateContentHeight: compactListDelegate.implicitContentHeight
//END
//BEGIN Private
KickoffItemDelegate {
KickoffGridDelegate {
id: gridDelegate
visible: false
enabled: false
icon.width: PlasmaCore.Units.iconSizes.large
icon.height: PlasmaCore.Units.iconSizes.large
model: null
index: -1
text: "asdf"
url: ""
decoration: "start-here-kde"
description: "asdf"
display: PC3.AbstractButton.TextUnderIcon
width: implicitHeight
action: null
indicator: null
}
KickoffItemDelegate {
KickoffListDelegate {
id: listDelegate
visible: false
enabled: false
icon.width: PlasmaCore.Units.iconSizes.smallMedium
icon.height: PlasmaCore.Units.iconSizes.smallMedium
model: null
index: -1
text: "asdf"
url: ""
decoration: "start-here-kde"
description: "asdf"
action: null
indicator: null
}
KickoffListDelegate {
id: compactListDelegate
visible: false
enabled: false
compact: true
model: null
index: -1
text: "asdf"
......
......@@ -16,7 +16,7 @@ BasePage {
id: sideBar
focus: true // needed for Loaders
model: placesCategoryModel
delegate: KickoffItemDelegate {
delegate: KickoffListDelegate {
url: ""
description: ""
width: view.availableWidth
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment