feat(StatusPopupMenu): add support for letter identicons, identicons and images

This extends the popup menu to accept image or icon configurations a la `StatusIconSettings`
and `StatusImageSettings` in menu items, as well as nested menus.

Usage:

```qml
StatusPopupMenu {

    StatusMenuItem {
        text: "Custom Image icon"
        image.source: // image source
    }

    StatusMenuItem {
        text: "Custom identicon icon"
        image.source: // identicon source
        image.isIdenticon: true
    }

    StatusMenuItem {
        text: "Custom letter identicon"
        iconSettings.isLetterIdenticon: true
        iconSettings.background.color: "red"
    }
}
```

Few things to note:

- Because `StatusMenuItem` is an `Action` type, we can't extend its `icon` property,
  so we have to introduce our own (`iconSettings`) which can be of type `StatusIconSettings`
- Where possible, `StatusPopupMenu` will prefer `iconSettings.[...]` over `icon.[...]`,
  which means, both would work: `icon.name` and `iconSettings.name`.
  This is for consistency's sake. Consumers can switch completely to `iconSettings` if desired.
- When `isLetterIdenticon` is true, `iconSettings.background.color` must be set, similar
  to how it work in any other StatusQ component that makes use of this configuration type.

Closes #263
This commit is contained in:
Pascal Precht 2021-07-21 15:09:11 +02:00 committed by Michał Cieślak
parent f95e0c9499
commit c6c9bc6a32
3 changed files with 169 additions and 14 deletions

View File

@ -22,6 +22,13 @@ GridLayout {
onClicked: complexMenu.popup()
}
StatusButton {
text: "Menu with custom images and icons"
onClicked: customMenu.popup()
}
StatusPopupMenu {
id: simpleMenu
StatusMenuItem {
@ -40,32 +47,103 @@ GridLayout {
StatusPopupMenu {
id: complexMenu
subMenuItemIcons: ['info']
StatusMenuItem {
text: "One"
icon.name: "info"
iconSettings.name: "info"
}
StatusMenuSeparator {}
StatusMenuItem {
text: "Two"
icon.name: "info"
iconSettings.name: "info"
}
StatusMenuItem {
text: "Three"
icon.name: "info"
iconSettings.name: "info"
}
StatusPopupMenu {
title: "Four"
StatusMenuItem {
text: "One"
icon.name: "info"
iconSettings.name: "info"
}
StatusMenuItem {
text: "Three"
icon.name: "info"
iconSettings.name: "info"
}
}
}
StatusPopupMenu {
id: customMenu
subMenuItemIcons: [
"chat",
{
source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
},
{
isLetterIdenticon: true,
color: "red"
}
]
StatusMenuItem {
text: "Anywhere"
}
StatusMenuSeparator {}
StatusPopupMenu {
title: "Chat"
StatusMenuItem {
text: "vitalik.eth"
image.source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0Bh
CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
image.isIdenticon: true
}
StatusMenuItem {
text: "Pascal"
image.source: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
}
}
StatusPopupMenu {
title: "Cryptokitties"
StatusMenuItem {
text: "welcome"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
}
StatusMenuItem {
text: "support"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
}
StatusMenuHeadline { text: "Public" }
StatusMenuItem {
text: "news"
iconSettings.name: "channel"
iconSettings.color: Theme.palette.directColor1
}
}
StatusPopupMenu {
title: "Another community"
StatusMenuItem {
text: "welcome"
iconSettings.isLetterIdenticon: true
iconSettings.background.color: "red"
}
}
}

View File

@ -9,7 +9,17 @@ Action {
Normal,
Danger
}
icon.color: "transparent"
property int type: StatusMenuItem.Type.Normal
property real iconRotation: 0
property StatusImageSettings image: StatusImageSettings {
height: 16
width: 16
isIdenticon: false
}
property StatusIconSettings iconSettings: StatusIconSettings {
isLetterIdenticon: false
background: StatusIconBackgroundSettings {}
color: "transparent"
}
}

View File

@ -4,6 +4,7 @@ import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
@ -54,13 +55,27 @@ Menu {
implicitHeight: 24
StatusIcon {
anchors.centerIn: parent
width: !!statusPopupMenuItem.action.icon.width ?
statusPopupMenuItem.action.icon.width : 18
width: {
let width = statusPopupMenuItem.action.icon.width ||
statusPopupMenuItem.action.iconSettings.width
return !!width ? width : 18
}
rotation: statusPopupMenuItem.action.iconRotation
icon: statusPopupMenuItem.subMenu ?
statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex] :
statusPopupMenuItem.action.icon.name
icon: {
if (statusPopupMenuItem.subMenu) {
return statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex]
}
return statusPopupMenuItem.action.icon.name ||
statusPopupMenuItem.action.iconSettings.name
}
color: {
let c = statusPopupMenuItem.action.iconSettings.color ||
statusPopupMenuItem.action.icon.color
if (!Qt.colorEqual(c, "transparent")) {
return c
}
switch (statusPopupMenuItem.action.type) {
case StatusMenuItem.Type.Danger:
return Theme.palette.dangerColor1
@ -73,13 +88,66 @@ Menu {
}
}
Component {
id: statusLetterIdenticonCmp
Item {
implicitWidth: 24
implicitHeight: 24
StatusLetterIdenticon {
anchors.centerIn: parent
width: 16
height: 16
color: {
let subMenuItemIcon = statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex]
return subMenuItemIcon && subMenuItemIcon.color ? subMenuItemIcon.color : statusPopupMenuItem.action.iconSettings.background.color
}
name: statusPopupMenuItem.text
letterSize: 11
}
}
}
Component {
id: statusRoundImageCmp
Item {
implicitWidth: 24
implicitHeight: 24
StatusRoundedImage {
anchors.centerIn: parent
width: statusPopupMenuItem.action.image.width
height: statusPopupMenuItem.action.image.height
image.source: statusPopupMenuItem.subMenu ?
statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].source :
statusPopupMenuItem.action.image.source
border.width: (statusPopupMenuItem.subMenu && statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex].isIdenticon) ||
statusPopupMenuItem.action.image.isIdenticon ? 1 : 0
border.color: Theme.palette.directColor7
}
}
}
indicator: Loader {
sourceComponent: indicatorComponent
sourceComponent: {
let subMenuItemIcon = statusPopupMenu.subMenuItemIcons[parent.subMenuIndex]
if ((parent.subMenu && subMenuItemIcon && subMenuItemIcon.source) || !!statusPopupMenuItem.action.image.source.toString()) {
return statusRoundImageCmp
}
return (parent.subMenu && subMenuItemIcon && subMenuItemIcon.isLetterIdenticon) ||
statusPopupMenuItem.action.iconSettings.isLetterIdenticon ?
statusLetterIdenticonCmp : indicatorComponent
}
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
active: (parent.subMenu && !!statusPopupMenu.subMenuItemIcons[parent.subMenuIndex] ||
!!statusPopupMenuItem.action.icon.name) &&
(!!statusPopupMenuItem.action.icon.name ||
!!statusPopupMenuItem.action.iconSettings.name) ||
!!statusPopupMenuItem.action.iconSettings.isLetterIdenticon ||
!!statusPopupMenuItem.action.image.source.toString()) &&
statusPopupMenuItem.action.enabled
}
@ -163,5 +231,4 @@ Menu {
}
}
}
}