mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
* Normalize and correct linphone color * Add border when user focus using keyboard navigation * Correct some keyboard navigation * Add accessibility screen reading to interactive elements except chat and meeting
199 lines
7.2 KiB
QML
199 lines
7.2 KiB
QML
import QtQuick
|
|
import QtQuick.Controls.Basic as Control
|
|
import QtQuick.Effects
|
|
import Linphone
|
|
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
|
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
|
|
|
Button {
|
|
id: mainItem
|
|
property alias popup: popup
|
|
property bool shadowEnabled: mainItem.activeFocus && !keyboardFocus || hovered
|
|
property alias popupBackgroundColor: popupBackground.color
|
|
property color backgroundColor: checked ? pressedColor : hovered || mainItem.activeFocus ? hoveredColor : color
|
|
property string popUpTitle: ""
|
|
Accessible.name: popup.visible ?
|
|
//: "Close %1 popup"
|
|
qsTr("close_popup_panel_accessible_name").arg(popUpTitle) :
|
|
//: "Open %1" popup
|
|
qsTr("open_popup_panel_accessible_name").arg(popUpTitle)
|
|
style: ButtonStyle.popupButton
|
|
checked: popup.visible
|
|
leftPadding: 0
|
|
rightPadding: 0
|
|
topPadding: 0
|
|
bottomPadding: 0
|
|
icon.source: AppIcons.verticalDots
|
|
icon.width: Utils.getSizeWithScreenRatio(24)
|
|
icon.height: Utils.getSizeWithScreenRatio(24)
|
|
implicitWidth: Utils.getSizeWithScreenRatio(30)
|
|
implicitHeight: Utils.getSizeWithScreenRatio(30)
|
|
function close() {
|
|
popup.close();
|
|
}
|
|
function open() {
|
|
popup.open();
|
|
}
|
|
|
|
function isFocusable(item) {
|
|
return item.activeFocusOnTab;
|
|
}
|
|
|
|
/**
|
|
* Check if an element has at least one child that is focusable
|
|
*/
|
|
function hasFocusableChild(content) {
|
|
return content.children.some(child => isFocusable(child));
|
|
}
|
|
|
|
function getPreviousItem(index) {
|
|
return _getPreviousItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index);
|
|
}
|
|
|
|
function getNextItem(index) {
|
|
return _getNextItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index);
|
|
}
|
|
|
|
function _getPreviousItem(content, index) {
|
|
if (content.visibleChildren.length == 0 || !hasFocusableChild(content))
|
|
return null;
|
|
--index;
|
|
while (index >= 0) {
|
|
if (isFocusable(content.children[index]) && content.children[index].visible)
|
|
return content.children[index];
|
|
--index;
|
|
}
|
|
return _getPreviousItem(content, content.visibleChildren.length);
|
|
}
|
|
|
|
function _getNextItem(content, index) {
|
|
if (content.visibleChildren.length == 0 || !hasFocusableChild(content))
|
|
return null;
|
|
++index;
|
|
while (index < content.children.length) {
|
|
if (isFocusable(content.children[index]) && content.children[index].visible)
|
|
return content.children[index];
|
|
++index;
|
|
}
|
|
return _getNextItem(content, -1);
|
|
}
|
|
|
|
Keys.onPressed: event => {
|
|
if (mainItem.checked) {
|
|
if (event.key == Qt.Key_Escape || event.key == Qt.Key_Left || event.key == Qt.Key_Space) {
|
|
mainItem.close();
|
|
mainItem.forceActiveFocus(Qt.TabFocusReason);
|
|
event.accepted = true;
|
|
} else if (event.key == Qt.Key_Up) {
|
|
getPreviousItem(0).forceActiveFocus(Qt.TabFocusReason);
|
|
event.accepted = true;
|
|
} else if (event.key == Qt.Key_Tab || event.key == Qt.Key_Down) {
|
|
getNextItem(-1).forceActiveFocus(Qt.BacktabFocusReason);
|
|
event.accepted = true;
|
|
}
|
|
} else if (event.key == Qt.Key_Space) {
|
|
mainItem.open();
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
|
|
background: Item {
|
|
anchors.fill: mainItem
|
|
Rectangle {
|
|
id: buttonBackground
|
|
anchors.fill: parent
|
|
color: mainItem.backgroundColor
|
|
radius: Utils.getSizeWithScreenRatio(40)
|
|
border.color: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderColor : mainItem.borderColor
|
|
border.width: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderWidth : mainItem.borderWidth
|
|
}
|
|
MultiEffect {
|
|
enabled: mainItem.shadowEnabled
|
|
anchors.fill: buttonBackground
|
|
source: buttonBackground
|
|
visible: mainItem.shadowEnabled
|
|
// Crash : https://bugreports.qt.io/browse/QTBUG-124730
|
|
shadowEnabled: true //mainItem.shadowEnabled
|
|
shadowColor: DefaultStyle.grey_1000
|
|
shadowBlur: 0.1
|
|
shadowOpacity: mainItem.shadowEnabled ? 0.5 : 0.0
|
|
}
|
|
}
|
|
contentItem: EffectImage {
|
|
imageSource: mainItem.icon.source
|
|
imageWidth: mainItem.icon.width
|
|
imageHeight: mainItem.icon.height
|
|
colorizationColor: mainItem.contentImageColor
|
|
}
|
|
onPressed: {
|
|
if (popup.visible)
|
|
popup.close();
|
|
else
|
|
popup.open();
|
|
}
|
|
Control.Popup {
|
|
id: popup
|
|
x: 0
|
|
y: mainItem.height
|
|
visible: false
|
|
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
|
padding: Utils.getSizeWithScreenRatio(10)
|
|
parent: mainItem // Explicit define for coordinates references.
|
|
function updatePosition() {
|
|
if (!visible)
|
|
return;
|
|
var popupHeight = popup.height + popup.padding;
|
|
var popupWidth = popup.width + popup.padding;
|
|
var winPosition = mainItem.Window.contentItem ? mainItem.Window.contentItem.mapToItem(mainItem, 0, 0) : {
|
|
"x": 0,
|
|
"y": 0
|
|
};
|
|
// Stay inside main window
|
|
y = Math.max(Math.min(winPosition.y + mainItem.Window.height - popupHeight, mainItem.height), winPosition.y);
|
|
x = Math.max(Math.min(winPosition.x + mainItem.Window.width - popupWidth, 0), winPosition.x);
|
|
// Avoid overlapping with popup button by going to the right (todo: check if left is better?)
|
|
if (y < mainItem.height && y + popupHeight > 0) {
|
|
x += mainItem.width;
|
|
}
|
|
var globalPos = mapToItem(mainItem.Window.contentItem, x, y);
|
|
if (globalPos.x + popupWidth >= mainItem.Window.width) {
|
|
x = -popupWidth;
|
|
}
|
|
}
|
|
|
|
onHeightChanged: Qt.callLater(updatePosition)
|
|
onWidthChanged: Qt.callLater(updatePosition)
|
|
onVisibleChanged: Qt.callLater(updatePosition)
|
|
|
|
Connections {
|
|
target: mainItem.Window
|
|
function onHeightChanged() {
|
|
Qt.callLater(popup.updatePosition);
|
|
}
|
|
function onWidthChanged() {
|
|
Qt.callLater(popup.updatePosition);
|
|
}
|
|
}
|
|
|
|
background: Item {
|
|
anchors.fill: parent
|
|
Rectangle {
|
|
id: popupBackground
|
|
anchors.fill: parent
|
|
color: DefaultStyle.grey_0
|
|
radius: Utils.getSizeWithScreenRatio(16)
|
|
}
|
|
MultiEffect {
|
|
source: popupBackground
|
|
anchors.fill: popupBackground
|
|
shadowEnabled: true
|
|
shadowBlur: 0.1
|
|
shadowColor: DefaultStyle.grey_1000
|
|
shadowOpacity: 0.4
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
}
|
|
}
|
|
}
|
|
}
|