diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,11 +31,13 @@ set(KF5_VERSION "5.22.0") -find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick) +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Gui Widgets) find_package(PkgConfig) ######################################################################### +add_subdirectory(plugin) + install(DIRECTORY org.kde.desktop DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/Controls.2) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/org.kde.desktop/Button.qml b/org.kde.desktop/Button.qml --- a/org.kde.desktop/Button.qml +++ b/org.kde.desktop/Button.qml @@ -21,27 +21,26 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Button { - id: control + id: controlRoot implicitWidth: background.implicitWidth implicitHeight: background.implicitHeight hoverEnabled: true //Qt.styleHints.useHoverEffects TODO: how to make this work in 5.7? contentItem: Item {} - background: StyleItem { + background: StylePrivate.StyleItem { id: styleitem + control: controlRoot elementType: "button" - sunken: control.pressed || (control.checkable && control.checked) - raised: !(control.pressed || (control.checkable && control.checked)) - hover: control.hovered - text: control.text - hasFocus: control.activeFocus - activeControl: control.isDefault ? "default" : "f" + sunken: controlRoot.pressed || (controlRoot.checkable && controlRoot.checked) + raised: !(controlRoot.pressed || (controlRoot.checkable && controlRoot.checked)) + hover: controlRoot.hovered + text: controlRoot.text + hasFocus: controlRoot.activeFocus + activeControl: controlRoot.isDefault ? "default" : "f" } } diff --git a/org.kde.desktop/CheckBox.qml b/org.kde.desktop/CheckBox.qml --- a/org.kde.desktop/CheckBox.qml +++ b/org.kde.desktop/CheckBox.qml @@ -23,12 +23,10 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T import QtQuick.Controls 2.0 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.CheckBox { - id: control + id: controlRoot implicitWidth: Math.max(background ? background.implicitWidth : 0, contentItem.implicitWidth + leftPadding + rightPadding) @@ -38,29 +36,29 @@ baselineOffset: contentItem.y + contentItem.baselineOffset padding: 1 - spacing: Math.round(TextSingleton.height / 8) + spacing: Math.round(StylePrivate.TextSingleton.height / 8) hoverEnabled: true indicator: CheckIndicator { - LayoutMirroring.enabled: control.mirrored + LayoutMirroring.enabled: controlRoot.mirrored LayoutMirroring.childrenInherit: true anchors { left: parent.left verticalCenter: parent.verticalCenter } - control: control + control: controlRoot } contentItem: Label { - leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0 - rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0 - opacity: control.enabled ? 1 : 0.6 - text: control.text - font: control.font - color: SystemPaletteSingleton.text(control.enabled) + leftPadding: controlRoot.indicator && !controlRoot.mirrored ? controlRoot.indicator.width + controlRoot.spacing : 0 + rightPadding: controlRoot.indicator && controlRoot.mirrored ? controlRoot.indicator.width + controlRoot.spacing : 0 + opacity: controlRoot.enabled ? 1 : 0.6 + text: controlRoot.text + font: controlRoot.font + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } diff --git a/org.kde.desktop/CheckDelegate.qml b/org.kde.desktop/CheckDelegate.qml --- a/org.kde.desktop/CheckDelegate.qml +++ b/org.kde.desktop/CheckDelegate.qml @@ -21,12 +21,12 @@ import QtQuick 2.5 -import QtQuick.Controls.Private 1.0 import QtQuick.Templates 2.0 as T +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import "private" T.CheckDelegate { - id: control + id: controlRoot implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitHeight: Math.max(contentItem.implicitHeight, @@ -38,23 +38,23 @@ rightPadding: 20 contentItem: Label { - leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 - rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 + leftPadding: controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 + rightPadding: !controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 - text: control.text - font: control.font - color: (control.pressed && !control.checked && !control.sectionDelegate) ? SystemPaletteSingleton.highlightedText(control.enabled) : SystemPaletteSingleton.text(control.enabled) + text: controlRoot.text + font: controlRoot.font + color: (controlRoot.pressed && !controlRoot.checked && !controlRoot.sectionDelegate) ? StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } indicator: CheckIndicator { - x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding - y: control.topPadding + (control.availableHeight - height) / 2 + x: controlRoot.mirrored ? controlRoot.leftPadding : controlRoot.width - width - controlRoot.rightPadding + y: controlRoot.topPadding + (controlRoot.availableHeight - height) / 2 - control: control + control: controlRoot } background: DefaultListItemBackground {} diff --git a/org.kde.desktop/CheckIndicator.qml b/org.kde.desktop/CheckIndicator.qml --- a/org.kde.desktop/CheckIndicator.qml +++ b/org.kde.desktop/CheckIndicator.qml @@ -21,13 +21,10 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate -StyleItem { +StylePrivate.StyleItem { id: styleitem - property Item control elementType: "checkbox" sunken: control.pressed on: control.checked || control.pressed diff --git a/org.kde.desktop/ComboBox.qml b/org.kde.desktop/ComboBox.qml --- a/org.kde.desktop/ComboBox.qml +++ b/org.kde.desktop/ComboBox.qml @@ -24,13 +24,11 @@ import QtQuick.Window 2.2 import QtQuick.Templates 2.0 as T import QtQuick.Controls 2.0 as Controls -//those for Settings -import QtQuick.Controls 1.0 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtGraphicalEffects 1.0 T.ComboBox { - id: control + id: controlRoot implicitWidth: background.implicitWidth + leftPadding + rightPadding implicitHeight: background.implicitHeight @@ -42,39 +40,49 @@ rightPadding: padding + 5 delegate: ItemDelegate { - width: control.popup.width - text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData - highlighted: control.highlightedIndex == index + width: controlRoot.popup.width + text: controlRoot.textRole ? (Array.isArray(controlRoot.model) ? modelData[controlRoot.textRole] : model[controlRoot.textRole]) : modelData + highlighted: controlRoot.highlightedIndex == index property bool separatorVisible: false } indicator: Item {} - contentItem: Item {} + contentItem: MouseArea { + onPressed: mouse.accepted = false; + onWheel: { + if (wheel.pixelDelta.y < 0 || wheel.angleDelta.y < 0) { + controlRoot.currentIndex = (controlRoot.currentIndex + 1) % delegateModel.count + } else { + controlRoot.currentIndex = (controlRoot.currentIndex - 1 + delegateModel.count) % delegateModel.count + } + } + } - background: StyleItem { + background: StylePrivate.StyleItem { id: styleitem + control: controlRoot elementType: "combobox" anchors.fill: parent - hover: control.hovered - hasFocus: control.activeFocus - enabled: control.enabled - text: control.displayText + hover: controlRoot.hovered + hasFocus: controlRoot.activeFocus + enabled: controlRoot.enabled + text: controlRoot.displayText } popup: T.Popup { - y: control.height - width: Math.max(control.width, 150) + y: controlRoot.height + width: Math.max(controlRoot.width, 150) implicitHeight: contentItem.implicitHeight topMargin: 6 bottomMargin: 6 contentItem: ListView { id: listview clip: true implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null - currentIndex: control.highlightedIndex + model: controlRoot.popup.visible ? controlRoot.delegateModel : null + currentIndex: controlRoot.highlightedIndex highlightRangeMode: ListView.ApplyRange highlightMoveDuration: 0 T.ScrollBar.vertical: Controls.ScrollBar { } @@ -85,8 +93,8 @@ margins: -1 } radius: 2 - color: SystemPaletteSingleton.base(control.enabled) - property color borderColor: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.base(controlRoot.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) layer.enabled: true diff --git a/org.kde.desktop/Dial.qml b/org.kde.desktop/Dial.qml --- a/org.kde.desktop/Dial.qml +++ b/org.kde.desktop/Dial.qml @@ -24,8 +24,7 @@ import QtQuick.Controls 2.0 import QtQuick.Controls.impl 2.0 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Dial { id: control @@ -36,7 +35,7 @@ background: DialRing { width: control.availableWidth height: control.availableHeight - color: control.visualFocus ? SystemPaletteSingleton.highlight(control.enabled) : SystemPaletteSingleton.text(control.enabled) + color: control.visualFocus ? StylePrivate.SystemPaletteSingleton.highlight(control.enabled) : StylePrivate.SystemPaletteSingleton.text(control.enabled) progress: control.position opacity: control.enabled ? 0.5 : 0.3 } @@ -47,6 +46,6 @@ width: 18 height: width radius: 8 - color: control.visualFocus ? SystemPaletteSingleton.highlight(control.enabled) : SystemPaletteSingleton.text(control.enabled) + color: control.visualFocus ? StylePrivate.SystemPaletteSingleton.highlight(control.enabled) : StylePrivate.SystemPaletteSingleton.text(control.enabled) } } diff --git a/org.kde.desktop/Dialog.qml b/org.kde.desktop/Dialog.qml --- a/org.kde.desktop/Dialog.qml +++ b/org.kde.desktop/Dialog.qml @@ -23,8 +23,7 @@ import QtQuick 2.6 import QtGraphicalEffects 1.0 import QtQuick.Templates 2.1 as T -import QtQuick.Controls 1.0 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Dialog { id: control @@ -63,8 +62,8 @@ background: Rectangle { radius: 2 - color: SystemPaletteSingleton.window(control.enabled) - property color borderColor: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) layer.enabled: true diff --git a/org.kde.desktop/Drawer.qml b/org.kde.desktop/Drawer.qml --- a/org.kde.desktop/Drawer.qml +++ b/org.kde.desktop/Drawer.qml @@ -23,8 +23,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.0 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Drawer { id: control @@ -43,16 +42,16 @@ bottomPadding: control.edge === Qt.TopEdge ? 1 : 0 background: Rectangle { - color: SystemPaletteSingleton.window(control.enabled) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) Rectangle { readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge anchors { left: control.edge !== Qt.LeftEdge ? parent.left : undefined right: control.edge !== Qt.RightEdge ? parent.right : undefined top: control.edge !== Qt.TopEdge ? parent.top : undefined bottom: control.edge !== Qt.BottomEdge ? parent.bottom : undefined } - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(control.enabled) opacity: 0.3 width: 1 height: 1 diff --git a/org.kde.desktop/Frame.qml b/org.kde.desktop/Frame.qml --- a/org.kde.desktop/Frame.qml +++ b/org.kde.desktop/Frame.qml @@ -37,7 +37,7 @@ background: Rectangle { color: "transparent" - property color borderColor: SystemPaletteSingleton.text(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) } } diff --git a/org.kde.desktop/GroupBox.qml b/org.kde.desktop/GroupBox.qml --- a/org.kde.desktop/GroupBox.qml +++ b/org.kde.desktop/GroupBox.qml @@ -23,6 +23,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.0 import QtQuick.Templates 2.0 as T +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.GroupBox { id: control @@ -42,15 +43,15 @@ text: control.title font: control.font - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(control.enabled) elide: Text.ElideRight horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } background: Rectangle { color: "transparent" - property color borderColor: SystemPaletteSingleton.text(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) } } diff --git a/org.kde.desktop/ItemDelegate.qml b/org.kde.desktop/ItemDelegate.qml --- a/org.kde.desktop/ItemDelegate.qml +++ b/org.kde.desktop/ItemDelegate.qml @@ -21,12 +21,12 @@ import QtQuick 2.5 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T import "private" T.ItemDelegate { - id: control + id: controlRoot implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitHeight: Math.max(contentItem.implicitHeight, @@ -38,14 +38,14 @@ rightPadding: 20 contentItem: Label { - leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 - rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 + leftPadding: controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 + rightPadding: !controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 - text: control.text - font: control.font - color: control.highlighted || control.checked || (control.pressed && !control.checked && !control.sectionDelegate) ? SystemPaletteSingleton.highlightedText(control.enabled) : SystemPaletteSingleton.text(control.enabled) + text: controlRoot.text + font: controlRoot.font + color: controlRoot.highlighted || controlRoot.checked || (controlRoot.pressed && !controlRoot.checked && !controlRoot.sectionDelegate) ? StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } diff --git a/org.kde.desktop/Label.qml b/org.kde.desktop/Label.qml --- a/org.kde.desktop/Label.qml +++ b/org.kde.desktop/Label.qml @@ -22,22 +22,20 @@ import QtQuick 2.1 import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Label { id: control - height: Math.round(Math.max(paintedHeight, TextSingleton.height * 1.6)) + height: Math.round(Math.max(paintedHeight, StylePrivate.TextSingleton.height * 1.6)) verticalAlignment: lineCount > 1 ? Text.AlignTop : Text.AlignVCenter activeFocusOnTab: false renderType: Text.NativeRendering //font data is the system one by default - color: SystemPaletteSingleton.text(control.enabled) - //SystemPaletteSingleton doesn't have a link color + color: StylePrivate.SystemPaletteSingleton.text(control.enabled) + //StylePrivate.SystemPaletteSingleton doesn't have a link color linkColor: "#2196F3" opacity: enabled? 1 : 0.6 diff --git a/org.kde.desktop/Menu.qml b/org.kde.desktop/Menu.qml --- a/org.kde.desktop/Menu.qml +++ b/org.kde.desktop/Menu.qml @@ -24,9 +24,7 @@ import QtGraphicalEffects 1.0 import QtQuick.Controls 2.0 import QtQuick.Templates 2.0 as T -//for systempalettesingleton -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Menu { id: control @@ -72,8 +70,8 @@ radius: 2 implicitWidth: 150 implicitHeight: 40 - color: SystemPaletteSingleton.window(control.enabled) - property color borderColor: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) layer.enabled: true diff --git a/org.kde.desktop/MenuItem.qml b/org.kde.desktop/MenuItem.qml --- a/org.kde.desktop/MenuItem.qml +++ b/org.kde.desktop/MenuItem.qml @@ -22,11 +22,10 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.MenuItem { - id: control + id: controlRoot implicitWidth: Math.max(background ? background.implicitWidth : 0, contentItem.implicitWidth + leftPadding + rightPadding) @@ -39,33 +38,34 @@ hoverEnabled: true contentItem: Label { - leftPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 - rightPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 + leftPadding: !controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 + rightPadding: controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 - text: control.text - font: control.font - color: control.hovered && !control.pressed ? SystemPaletteSingleton.highlightedText(control.enabled) : SystemPaletteSingleton.text(control.enabled) + text: controlRoot.text + font: controlRoot.font + color: controlRoot.hovered && !controlRoot.pressed ? StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } indicator: CheckIndicator { - x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding - y: control.topPadding + (control.availableHeight - height) / 2 + x: controlRoot.mirrored ? controlRoot.width - width - controlRoot.rightPadding : controlRoot.leftPadding + y: controlRoot.topPadding + (controlRoot.availableHeight - height) / 2 - visible: control.checkable - on: control.checked + visible: controlRoot.checkable + on: controlRoot.checked + control: controlRoot } background: Item { implicitWidth: 150 Rectangle { anchors.fill: parent - color: SystemPaletteSingleton.highlight(control.enabled) - opacity: control.hovered && !control.pressed ? 1 : 0 + color: StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) + opacity: controlRoot.hovered && !controlRoot.pressed ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 150 } } } } diff --git a/org.kde.desktop/Popup.qml b/org.kde.desktop/Popup.qml --- a/org.kde.desktop/Popup.qml +++ b/org.kde.desktop/Popup.qml @@ -23,8 +23,7 @@ import QtQuick 2.6 import QtGraphicalEffects 1.0 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.Popup { id: control @@ -63,8 +62,8 @@ background: Rectangle { radius: 2 - color: SystemPaletteSingleton.window(control.enabled) - property color borderColor: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) layer.enabled: true diff --git a/org.kde.desktop/ProgressBar.qml b/org.kde.desktop/ProgressBar.qml --- a/org.kde.desktop/ProgressBar.qml +++ b/org.kde.desktop/ProgressBar.qml @@ -21,32 +21,31 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T T.ProgressBar { - id: control + id: controlRoot implicitWidth: 250 implicitHeight: 22 hoverEnabled: true contentItem: Item {} - background: StyleItem { + background: StylePrivate.StyleItem { elementType: "progressbar" - maximum: indeterminate ? 0 : control.to*100 - minimum: indeterminate ? 0 : control.from*100 - value: indeterminate ? 0 : ((!control.inverted ? control.visualPosition : 1 - control.visualPosition)*control.to*100) + control: controlRoot + maximum: indeterminate ? 0 : controlRoot.to*100 + minimum: indeterminate ? 0 : controlRoot.from*100 + value: indeterminate ? 0 : ((!controlRoot.inverted ? controlRoot.visualPosition : 1 - controlRoot.visualPosition)*controlRoot.to*100) horizontal: true - enabled: control.enabled + enabled: controlRoot.enabled Timer { interval: 50 - running: control.indeterminate + running: controlRoot.indeterminate repeat: true onTriggered: parent.updateItem(); } diff --git a/org.kde.desktop/RadioButton.qml b/org.kde.desktop/RadioButton.qml --- a/org.kde.desktop/RadioButton.qml +++ b/org.kde.desktop/RadioButton.qml @@ -23,9 +23,7 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T import QtQuick.Controls 2.0 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.CheckBox { id: control @@ -38,7 +36,7 @@ baselineOffset: contentItem.y + contentItem.baselineOffset padding: 1 - spacing: Math.round(TextSingleton.height / 8) + spacing: Math.round(StylePrivate.TextSingleton.height / 8) hoverEnabled: true @@ -58,7 +56,7 @@ opacity: control.enabled ? 1 : 0.6 text: control.text font: control.font - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(control.enabled) elide: Text.ElideRight visible: control.text horizontalAlignment: Text.AlignLeft diff --git a/org.kde.desktop/RadioDelegate.qml b/org.kde.desktop/RadioDelegate.qml --- a/org.kde.desktop/RadioDelegate.qml +++ b/org.kde.desktop/RadioDelegate.qml @@ -21,12 +21,12 @@ import QtQuick 2.5 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T import "private" T.RadioDelegate { - id: control + id: controlRoot implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitHeight: Math.max(contentItem.implicitHeight, @@ -38,23 +38,23 @@ rightPadding: 20 contentItem: Label { - leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 - rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 + leftPadding: controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 + rightPadding: !controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 - text: control.text - font: control.font - color: (control.pressed && !control.checked && !control.sectionDelegate) ? SystemPaletteSingleton.highlightedText(control.enabled) : SystemPaletteSingleton.text(control.enabled) + text: controlRoot.text + font: controlRoot.font + color: (controlRoot.pressed && !controlRoot.checked && !controlRoot.sectionDelegate) ? StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } indicator: RadioIndicator { - x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding - y: control.topPadding + (control.availableHeight - height) / 2 + x: controlRoot.mirrored ? controlRoot.leftPadding : controlRoot.width - width - controlRoot.rightPadding + y: controlRoot.topPadding + (controlRoot.availableHeight - height) / 2 - control: control + control: controlRoot } background: DefaultListItemBackground {} diff --git a/org.kde.desktop/RadioIndicator.qml b/org.kde.desktop/RadioIndicator.qml --- a/org.kde.desktop/RadioIndicator.qml +++ b/org.kde.desktop/RadioIndicator.qml @@ -21,13 +21,10 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate -StyleItem { +StylePrivate.StyleItem { id: styleitem - property Item control elementType: "radiobutton" sunken: control.pressed on: control.checked || control.pressed diff --git a/org.kde.desktop/RangeSlider.qml b/org.kde.desktop/RangeSlider.qml --- a/org.kde.desktop/RangeSlider.qml +++ b/org.kde.desktop/RangeSlider.qml @@ -23,9 +23,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.0 import QtQuick.Templates 2.0 as T -//for systempalettesingleton -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.RangeSlider { id: control @@ -46,9 +44,9 @@ implicitWidth: 18 implicitHeight: 18 radius: width / 2 - property color borderColor: SystemPaletteSingleton.text(control.enabled) - border.color: control.activeFocus ? SystemPaletteSingleton.highlight(control.enabled) : Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) - color: SystemPaletteSingleton.window(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) + border.color: control.activeFocus ? StylePrivate.SystemPaletteSingleton.highlight(control.enabled) : Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) Rectangle { z: -1 x: 1 @@ -67,9 +65,9 @@ implicitWidth: 18 implicitHeight: 18 radius: width / 2 - property color borderColor: SystemPaletteSingleton.text(control.enabled) - border.color: control.activeFocus ? SystemPaletteSingleton.highlight(control.enabled) : Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) - color: SystemPaletteSingleton.window(control.enabled) + property color borderColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) + border.color: control.activeFocus ? StylePrivate.SystemPaletteSingleton.highlight(control.enabled) : Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3) + color: StylePrivate.SystemPaletteSingleton.window(control.enabled) Rectangle { z: -1 x: 1 @@ -88,16 +86,16 @@ width: horizontal ? control.availableWidth : implicitWidth height: horizontal ? implicitHeight : control.availableHeight radius: Math.round(Math.min(width/2, height/2)) - property color bgColor: SystemPaletteSingleton.text(control.enabled) + property color bgColor: StylePrivate.SystemPaletteSingleton.text(control.enabled) color: Qt.rgba(bgColor.r, bgColor.g, bgColor.b, 0.3) anchors.centerIn: parent Rectangle { x: parent.horizontal ? control.first.position * parent.width : 0 y: parent.horizontal ? 0 : control.second.visualPosition * parent.height + 6 width: parent.horizontal ? control.second.position * parent.width - control.first.position * parent.width - 6 : 6 height: parent.horizontal ? 6 : control.second.position * parent.height - control.first.position * parent.height - 6 - color: SystemPaletteSingleton.highlight(control.enabled) + color: StylePrivate.SystemPaletteSingleton.highlight(control.enabled) } } } diff --git a/org.kde.desktop/ScrollBar.qml b/org.kde.desktop/ScrollBar.qml --- a/org.kde.desktop/ScrollBar.qml +++ b/org.kde.desktop/ScrollBar.qml @@ -21,25 +21,23 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T T.ScrollBar { - id: control + id: controlRoot implicitWidth: background.implicitWidth implicitHeight: background.implicitHeight hoverEnabled: true - visible: control.size < 1.0 + visible: controlRoot.size < 1.0 background: MouseArea { id: mouseArea anchors.fill: parent - visible: control.size < 1.0 + visible: controlRoot.size < 1.0 hoverEnabled: true onPositionChanged: style.activeControl = style.hitTest(mouse.x, mouse.y) onExited: style.activeControl = "groove"; @@ -65,20 +63,21 @@ implicitWidth: style.horizontal ? 200 : style.pixelMetric("scrollbarExtent") implicitHeight: style.horizontal ? style.pixelMetric("scrollbarExtent") : 200 - StyleItem { + StylePrivate.StyleItem { id: style + control: controlRoot anchors.fill: parent elementType: "scrollbar" hover: activeControl != "none" activeControl: "none" - sunken: control.pressed + sunken: controlRoot.pressed minimum: 0 - maximum: (control.height/control.size - control.height) - value: control.position * (control.height/control.size) - horizontal: control.orientation == Qt.Horizontal - enabled: control.enabled + maximum: (controlRoot.height/controlRoot.size - controlRoot.height) + value: controlRoot.position * (controlRoot.height/controlRoot.size) + horizontal: controlRoot.orientation == Qt.Horizontal + enabled: controlRoot.enabled - visible: control.size < 1.0 + visible: controlRoot.size < 1.0 opacity: mouseArea.containsMouse ? 1 : 0 Behavior on opacity { OpacityAnimator { @@ -92,22 +91,23 @@ repeat: true interval: 150 onTriggered: { - control.position += increment; + controlRoot.position += increment; } } } - StyleItem { + StylePrivate.StyleItem { anchors.fill: parent + control: controlRoot elementType: "scrollbar" activeControl: "none" sunken: false minimum: 0 maximum: style.maximum value: style.value horizontal: style.horizontal - enabled: control.enabled + enabled: controlRoot.enabled - visible: control.size < 1.0 + visible: controlRoot.size < 1.0 opacity: !mouseArea.containsMouse ? 1 : 0 Behavior on opacity { OpacityAnimator { diff --git a/org.kde.desktop/Slider.qml b/org.kde.desktop/Slider.qml --- a/org.kde.desktop/Slider.qml +++ b/org.kde.desktop/Slider.qml @@ -21,13 +21,11 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T T.Slider { - id: control + id: controlRoot implicitWidth: background.implicitWidth implicitHeight: background.implicitHeight @@ -38,21 +36,22 @@ snapMode: T.Slider.SnapOnRelease - background: StyleItem { + background: StylePrivate.StyleItem { + control: controlRoot elementType: "slider" - sunken: control.pressed + sunken: controlRoot.pressed implicitWidth: 200 contentHeight: horizontal ? 22 : implicitWidth contentWidth: horizontal ? implicitWidth : 22 - maximum: control.to*100 - minimum: control.from*100 - step: control.stepSize*100 - value: (horizontal ? control.visualPosition : 1 - control.visualPosition)*control.to*100 - horizontal: control.orientation === Qt.Horizontal - enabled: control.enabled - hasFocus: control.activeFocus - hover: control.hovered - activeControl: control.stepSize > 0 ? "ticks" : "" + maximum: controlRoot.to*100 + minimum: controlRoot.from*100 + step: controlRoot.stepSize*100 + value: (horizontal ? controlRoot.visualPosition : 1 - controlRoot.visualPosition)*controlRoot.to*100 + horizontal: controlRoot.orientation === Qt.Horizontal + enabled: controlRoot.enabled + hasFocus: controlRoot.activeFocus + hover: controlRoot.hovered + activeControl: controlRoot.stepSize > 0 ? "ticks" : "" } } diff --git a/org.kde.desktop/SpinBox.qml b/org.kde.desktop/SpinBox.qml --- a/org.kde.desktop/SpinBox.qml +++ b/org.kde.desktop/SpinBox.qml @@ -22,66 +22,85 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 -import QtQuick.Controls 2.0 as Controls -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.SpinBox { - id: control + id: controlRoot implicitWidth: Math.max(48, contentItem.implicitWidth + 2 * padding + up.indicator.implicitWidth) implicitHeight: contentItem.implicitHeight + topPadding + bottomPadding padding: 6 - leftPadding: padding + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : 0) - rightPadding: padding + (control.mirrored ? 0 : (up.indicator ? up.indicator.width : 0)) + leftPadding: padding + (controlRoot.mirrored ? (up.indicator ? up.indicator.width : 0) : 0) + rightPadding: padding + (controlRoot.mirrored ? 0 : (up.indicator ? up.indicator.width : 0)) + hoverEnabled: true + validator: IntValidator { - locale: control.locale.name - bottom: Math.min(control.from, control.to) - top: Math.max(control.from, control.to) + locale: controlRoot.locale.name + bottom: Math.min(controlRoot.from, controlRoot.to) + top: Math.max(controlRoot.from, controlRoot.to) } contentItem: TextInput { z: 2 - text: control.textFromValue(control.value, control.locale) - opacity: control.enabled ? 1 : 0.3 + text: controlRoot.textFromValue(controlRoot.value, controlRoot.locale) + opacity: controlRoot.enabled ? 1 : 0.3 - font: control.font - color: SystemPaletteSingleton.text(control.enabled) - selectionColor: SystemPaletteSingleton.highlight(control.enabled) - selectedTextColor: SystemPaletteSingleton.highlightedText(control.enabled) + font: controlRoot.font + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) + selectionColor: StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) + selectedTextColor: StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter - readOnly: !control.editable - validator: control.validator + readOnly: !controlRoot.editable + validator: controlRoot.validator inputMethodHints: Qt.ImhFormattedNumbersOnly + + MouseArea { + anchors.fill: parent + onPressed: mouse.accepted = false; + onWheel: { + if (wheel.pixelDelta.y < 0 || wheel.angleDelta.y < 0) { + controlRoot.decrease(); + } else { + controlRoot.increase(); + } + } + } } up.indicator: Item { implicitWidth: parent.height/2 implicitHeight: implicitWidth - x: control.mirrored ? 0 : parent.width - width + x: controlRoot.mirrored ? 0 : parent.width - width } down.indicator: Item { implicitWidth: parent.height/2 implicitHeight: implicitWidth - x: control.mirrored ? 0 : parent.width - width + x: controlRoot.mirrored ? 0 : parent.width - width y: parent.height - height } - background: StyleItem { + background: StylePrivate.StyleItem { id: styleitem + control: controlRoot elementType: "spinbox" anchors.fill: parent - hover: control.hovered - hasFocus: control.activeFocus - enabled: control.enabled - value: control.textFromValue(control.value, control.locale) + hover: controlRoot.hovered + hasFocus: controlRoot.activeFocus + enabled: controlRoot.enabled + + value: (controlRoot.up.pressed ? 1 : 0) | + (controlRoot.down.pressed ? 1<<1 : 0) | + ( controlRoot.value != controlRoot.to ? (1<<2) : 0) | + (controlRoot.value != controlRoot.from ? (1<<3) : 0) | + (controlRoot.up.hovered ? 0x1 : 0) | + (controlRoot.down.hovered ? (1<<1) : 0) border { top: 6 bottom: 6 diff --git a/org.kde.desktop/Switch.qml b/org.kde.desktop/Switch.qml --- a/org.kde.desktop/Switch.qml +++ b/org.kde.desktop/Switch.qml @@ -22,10 +22,7 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.CheckBox { id: control @@ -36,7 +33,7 @@ baselineOffset: contentItem.y + contentItem.baselineOffset padding: 1 - spacing: Math.round(TextSingleton.height / 8) + spacing: Math.round(StylePrivate.TextSingleton.height / 8) hoverEnabled: true @@ -57,7 +54,7 @@ opacity: control.enabled ? 1 : 0.6 text: control.text font: control.font - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(control.enabled) elide: Text.ElideRight visible: control.text horizontalAlignment: Text.AlignLeft diff --git a/org.kde.desktop/SwitchDelegate.qml b/org.kde.desktop/SwitchDelegate.qml --- a/org.kde.desktop/SwitchDelegate.qml +++ b/org.kde.desktop/SwitchDelegate.qml @@ -21,12 +21,12 @@ import QtQuick 2.5 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T import "private" T.SwitchDelegate { - id: control + id: controlRoot implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitHeight: Math.max(contentItem.implicitHeight, @@ -38,23 +38,23 @@ rightPadding: 20 contentItem: Label { - leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 - rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 + leftPadding: controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 + rightPadding: !controlRoot.mirrored ? (controlRoot.indicator ? controlRoot.indicator.width : 0) + controlRoot.spacing : 0 - text: control.text - font: control.font - color: (control.pressed && !control.checked && !control.sectionDelegate) ? SystemPaletteSingleton.highlightedText(control.enabled) : SystemPaletteSingleton.text(control.enabled) + text: controlRoot.text + font: controlRoot.font + color: (controlRoot.pressed && !controlRoot.checked && !controlRoot.sectionDelegate) ? StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) elide: Text.ElideRight - visible: control.text + visible: controlRoot.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } indicator: SwitchIndicator { - x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding - y: control.topPadding + (control.availableHeight - height) / 2 + x: controlRoot.mirrored ? controlRoot.leftPadding : controlRoot.width - width - controlRoot.rightPadding + y: controlRoot.topPadding + (controlRoot.availableHeight - height) / 2 - control: control + control: controlRoot } background: DefaultListItemBackground {} diff --git a/org.kde.desktop/SwitchIndicator.qml b/org.kde.desktop/SwitchIndicator.qml --- a/org.kde.desktop/SwitchIndicator.qml +++ b/org.kde.desktop/SwitchIndicator.qml @@ -21,16 +21,15 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate Item { - property Item control + property alias control: slider.control implicitWidth: 32 implicitHeight : 22 - StyleItem { + StylePrivate.StyleItem { + id: slider anchors.fill: parent elementType: "slider" sunken: control.pressed diff --git a/org.kde.desktop/TabBar.qml b/org.kde.desktop/TabBar.qml --- a/org.kde.desktop/TabBar.qml +++ b/org.kde.desktop/TabBar.qml @@ -21,25 +21,23 @@ import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T T.TabBar { - id: control + id: controlRoot implicitWidth: contentItem.implicitWidth implicitHeight: contentItem.implicitHeight spacing: 0 contentItem: ListView { - implicitWidth: control.contentModel.get(0).implicitWidth * count - implicitHeight: control.contentModel.get(0).height + implicitWidth: controlRoot.contentModel.get(0).implicitWidth * count + implicitHeight: controlRoot.contentModel.get(0).height - model: control.contentModel - currentIndex: control.currentIndex + model: controlRoot.contentModel + currentIndex: controlRoot.currentIndex spacing: -styleItem.pixelMetric("tabOverlap")-1 orientation: ListView.Horizontal @@ -53,25 +51,26 @@ preferredHighlightEnd: width - 40 } - StyleItem { + StylePrivate.StyleItem { id: styleItem + control: controlRoot visible: false elementType: "tabframe" properties: { - "orientation" : control.position == T.TabBar.Header ? "Top" : "Bottom" + "orientation" : controlRoot.position == T.TabBar.Header ? "Top" : "Bottom" } } background: Item { Rectangle { anchors { left: parent.left right: parent.right - bottom : control.position == T.TabBar.Header ? parent.bottom : undefined - top : control.position == T.TabBar.Header ? undefined : parent.top + bottom : controlRoot.position == T.TabBar.Header ? parent.bottom : undefined + top : controlRoot.position == T.TabBar.Header ? undefined : parent.top } height: 1 - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) opacity: 0.4 } } diff --git a/org.kde.desktop/TabButton.qml b/org.kde.desktop/TabButton.qml --- a/org.kde.desktop/TabButton.qml +++ b/org.kde.desktop/TabButton.qml @@ -21,15 +21,14 @@ import QtQuick 2.6 -import QtQuick.Controls 2.1 import QtQml.Models 2.1 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +//for TabBar.* +import QtQuick.Controls 2.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate import QtQuick.Templates 2.0 as T T.TabButton { - id: control + id: controlRoot implicitWidth: styleitem.implicitWidth implicitHeight: styleitem.implicitHeight @@ -41,30 +40,31 @@ contentItem: Item {} - background: StyleItem { + background: StylePrivate.StyleItem { id: styleitem + control: controlRoot anchors.fill: parent elementType: "tab" paintMargins: 0 - property Item tabBar: control.parent.parent.parent + property Item tabBar: controlRoot.parent.parent.parent property string orientation: tabBar.position == TabBar.Header ? "Top" : "Bottom" - property string selectedpos: tabBar.currentIndex == control.ObjectModel.index + 1 ? "next" : - tabBar.currentIndex == control.ObjectModel.index - 1 ? "previous" : "" - property string tabpos: tabBar.count === 1 ? "only" : control.ObjectModel.index === 0 ? "beginning" : control.ObjectModel.index === tabBar.count - 1 ? "end" : "middle" + property string selectedpos: tabBar.currentIndex == controlRoot.ObjectModel.index + 1 ? "next" : + tabBar.currentIndex == controlRoot.ObjectModel.index - 1 ? "previous" : "" + property string tabpos: tabBar.count === 1 ? "only" : controlRoot.ObjectModel.index === 0 ? "beginning" : controlRoot.ObjectModel.index === tabBar.count - 1 ? "end" : "middle" properties: { "hasFrame" : true, "orientation": orientation, "tabpos": tabpos, "selectedpos": selectedpos } - enabled: control.enabled - selected: control.checked - text: control.text - hover: control.hovered - hasFocus: control.activeFocus + enabled: controlRoot.enabled + selected: controlRoot.checked + text: controlRoot.text + hover: controlRoot.hovered + hasFocus: controlRoot.activeFocus } } diff --git a/org.kde.desktop/TextArea.qml b/org.kde.desktop/TextArea.qml --- a/org.kde.desktop/TextArea.qml +++ b/org.kde.desktop/TextArea.qml @@ -22,12 +22,10 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.TextArea { - id: control + id: controlRoot implicitWidth: Math.max(contentWidth + leftPadding + rightPadding, background ? background.implicitWidth : 0, @@ -38,39 +36,40 @@ padding: 6 - color: SystemPaletteSingleton.text(control.enabled) - selectionColor: SystemPaletteSingleton.highlight(control.enabled) - selectedTextColor: SystemPaletteSingleton.highlightedText(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) + selectionColor: StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) + selectedTextColor: StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) wrapMode: Text.WordWrap verticalAlignment: TextEdit.AlignTop renderType: Text.NativeRendering Label { id: placeholder - x: control.leftPadding - y: control.topPadding - width: control.width - (control.leftPadding + control.rightPadding) - height: control.height - (control.topPadding + control.bottomPadding) + x: controlRoot.leftPadding + y: controlRoot.topPadding + width: controlRoot.width - (controlRoot.leftPadding + controlRoot.rightPadding) + height: controlRoot.height - (controlRoot.topPadding + controlRoot.bottomPadding) - text: control.placeholderText - font: control.font - color: SystemPaletteSingleton.text(false) - horizontalAlignment: control.horizontalAlignment - verticalAlignment: control.verticalAlignment - visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) + text: controlRoot.placeholderText + font: controlRoot.font + color: StylePrivate.SystemPaletteSingleton.text(false) + horizontalAlignment: controlRoot.horizontalAlignment + verticalAlignment: controlRoot.verticalAlignment + visible: !controlRoot.length && !controlRoot.preeditText && (!controlRoot.activeFocus || controlRoot.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight } - background: StyleItem { + background: StylePrivate.StyleItem { id: style - visible: control.backgroundVisible + control: controlRoot + visible: controlRoot.backgroundVisible elementType: "edit" implicitWidth: 200 implicitHeight: 22 sunken: true - hasFocus: control.activeFocus - hover: control.hovered + hasFocus: controlRoot.activeFocus + hover: controlRoot.hovered } } diff --git a/org.kde.desktop/TextField.qml b/org.kde.desktop/TextField.qml --- a/org.kde.desktop/TextField.qml +++ b/org.kde.desktop/TextField.qml @@ -21,13 +21,12 @@ import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.TextField { - id: control + id: controlRoot implicitWidth: Math.max(200, placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) @@ -38,33 +37,35 @@ padding: 6 - color: SystemPaletteSingleton.text(control.enabled) - selectionColor: SystemPaletteSingleton.highlight(control.enabled) - selectedTextColor: SystemPaletteSingleton.highlightedText(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) + selectionColor: StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) + selectedTextColor: StylePrivate.SystemPaletteSingleton.highlightedText(controlRoot.enabled) verticalAlignment: TextInput.AlignVCenter - Label { + Controls.Label { id: placeholder - x: control.leftPadding - y: control.topPadding - width: control.width - (control.leftPadding + control.rightPadding) - height: control.height - (control.topPadding + control.bottomPadding) + x: controlRoot.leftPadding + y: controlRoot.topPadding + width: controlRoot.width - (controlRoot.leftPadding + controlRoot.rightPadding) + height: controlRoot.height - (controlRoot.topPadding + controlRoot.bottomPadding) - text: control.placeholderText - font: control.font - color: SystemPaletteSingleton.text(false) - horizontalAlignment: control.horizontalAlignment - verticalAlignment: control.verticalAlignment - visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) + text: controlRoot.placeholderText + font: controlRoot.font + color: StylePrivate.SystemPaletteSingleton.text(false) + horizontalAlignment: controlRoot.horizontalAlignment + verticalAlignment: controlRoot.verticalAlignment + visible: !controlRoot.length && !controlRoot.preeditText && (!controlRoot.activeFocus || controlRoot.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight } - background: StyleItem { + background: StylePrivate.StyleItem { id: style + + control: controlRoot elementType: "edit" sunken: true - hasFocus: control.activeFocus - hover: control.hovered + hasFocus: controlRoot.activeFocus + hover: controlRoot.hovered } } diff --git a/org.kde.desktop/ToolBar.qml b/org.kde.desktop/ToolBar.qml --- a/org.kde.desktop/ToolBar.qml +++ b/org.kde.desktop/ToolBar.qml @@ -22,11 +22,10 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.ToolBar { - id: control + id: controlRoot implicitWidth: Math.max(background ? background.implicitWidth : 0, contentWidth + leftPadding + rightPadding) implicitHeight: Math.max(background ? background.implicitHeight : 0, contentHeight + topPadding + bottomPadding) @@ -38,15 +37,15 @@ background: Rectangle { implicitHeight: 40 - color: SystemPaletteSingleton.window(control.enabled) + color: StylePrivate.SystemPaletteSingleton.window(controlRoot.enabled) Rectangle { anchors { left: parent.left right: parent.right bottom: parent.bottom } height: 1 - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) opacity: 0.3 } } diff --git a/org.kde.desktop/ToolButton.qml b/org.kde.desktop/ToolButton.qml --- a/org.kde.desktop/ToolButton.qml +++ b/org.kde.desktop/ToolButton.qml @@ -22,28 +22,27 @@ import QtQuick 2.6 import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.ToolButton { - id: control + id: controlRoot implicitWidth: background.implicitWidth implicitHeight: background.implicitHeight hoverEnabled: true //Qt.styleHints.useHoverEffects TODO: how to make this work in 5.7? flat: true contentItem: Item {} - background: StyleItem { + background: StylePrivate.StyleItem { id: styleitem - elementType: control.flat ? "toolbutton" : "button" - sunken: control.pressed || (control.checkable && control.checked) - raised: !(control.pressed || (control.checkable && control.checked)) - hover: control.hovered - text: control.text + control: controlRoot + elementType: controlRoot.flat ? "toolbutton" : "button" + sunken: controlRoot.pressed || (controlRoot.checkable && controlRoot.checked) + raised: !(controlRoot.pressed || (controlRoot.checkable && controlRoot.checked)) + hover: controlRoot.hovered + text: controlRoot.text hasFocus: false - activeControl: control.isDefault ? "default" : "f" + activeControl: controlRoot.isDefault ? "default" : "f" } } diff --git a/org.kde.desktop/ToolTip.qml b/org.kde.desktop/ToolTip.qml --- a/org.kde.desktop/ToolTip.qml +++ b/org.kde.desktop/ToolTip.qml @@ -22,14 +22,12 @@ import QtQuick 2.6 import QtGraphicalEffects 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.0 as Controls import QtQuick.Templates 2.0 as T -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate T.ToolTip { - id: control + id: controlRoot x: parent ? (parent.width - implicitWidth) / 2 : 0 y: -implicitHeight - 3 @@ -42,17 +40,17 @@ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent - contentItem: Label { - text: control.text - font: control.font - color: SystemPaletteSingleton.base(control.enabled) + contentItem: Controls.Label { + text: controlRoot.text + font: controlRoot.font + color: StylePrivate.StylePrivate.SystemPaletteSingleton.base(controlRoot.enabled) } background: Rectangle { radius: 3 opacity: 0.95 - color: SystemPaletteSingleton.text(control.enabled) + color: StylePrivate.StylePrivate.SystemPaletteSingleton.text(controlRoot.enabled) layer.enabled: true layer.effect: DropShadow { transparentBorder: true diff --git a/org.kde.desktop/private/DefaultListItemBackground.qml b/org.kde.desktop/private/DefaultListItemBackground.qml --- a/org.kde.desktop/private/DefaultListItemBackground.qml +++ b/org.kde.desktop/private/DefaultListItemBackground.qml @@ -21,19 +21,17 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 as Controls -import QtQuick.Controls.Private 1.0 +import org.kde.qqc2desktopstyle.private 1.0 as StylePrivate Rectangle { id: background - color: highlighted || (control.pressed && !control.checked && !control.sectionDelegate) ? SystemPaletteSingleton.highlight(control.enabled) : SystemPaletteSingleton.base(control.enabled) + color: highlighted || (controlRoot.pressed && !controlRoot.checked && !controlRoot.sectionDelegate) ? StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) : StylePrivate.SystemPaletteSingleton.base(controlRoot.enabled) - visible: control.ListView.view ? control.ListView.view.highlight === null : true + visible: controlRoot.ListView.view ? controlRoot.ListView.view.highlight === null : true Rectangle { anchors.fill: parent - visible: !Settings.isMobile - color: SystemPaletteSingleton.highlight(control.enabled) - opacity: control.hovered && !control.pressed ? 0.2 : 0 + color: StylePrivate.SystemPaletteSingleton.highlight(controlRoot.enabled) + opacity: controlRoot.hovered && !controlRoot.pressed ? 0.2 : 0 Behavior on opacity { NumberAnimation { duration: 150 } } } Behavior on color { diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugin/CMakeLists.txt @@ -0,0 +1,23 @@ +project(qqc2desktopstyle) + +set(qqc2desktopstyle_SRCS + qqc2desktopstyleplugin.cpp + kquickstyleitem.cpp + ) + +if(Qt5_VERSION VERSION_LESS "5.8.0") +set(qqc2desktopstyle_SRCS + ${qqc2desktopstyle_SRCS} + #FIXME: remove when we can depend from Qt 5.8+ + qsgninepatchnode.cpp + qsgdefaultninepatchnode.cpp + ) +endif() + +add_library(qqc2desktopstyleplugin SHARED ${qqc2desktopstyle_SRCS}) +target_link_libraries(qqc2desktopstyleplugin Qt5::Core Qt5::Qml Qt5::Quick Qt5::Gui Qt5::Widgets) + +install(TARGETS qqc2desktopstyleplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/qqc2desktopstyle/private) +install(FILES SystemPaletteSingleton.qml DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/qqc2desktopstyle/private) +install(FILES TextSingleton.qml DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/qqc2desktopstyle/private) +install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/qqc2desktopstyle/private) diff --git a/plugin/SystemPaletteSingleton.qml b/plugin/SystemPaletteSingleton.qml new file mode 100644 --- /dev/null +++ b/plugin/SystemPaletteSingleton.qml @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Marco Martin + * Copyright 2017 The Qt Company Ltd. + * + * GNU Lesser General Public License Usage + * Alternatively, this file may be used under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software + * Foundation and appearing in the file LICENSE.LGPLv3 included in the + * packaging of this file. Please review the following information to + * ensure the GNU Lesser General Public License version 3 requirements + * will be met: https://www.gnu.org/licenses/lgpl.html. + * + * GNU General Public License Usage + * Alternatively, this file may be used under the terms of the GNU + * General Public License version 2.0 or later as published by the Free + * Software Foundation and appearing in the file LICENSE.GPL included in + * the packaging of this file. Please review the following information to + * ensure the GNU General Public License version 2.0 requirements will be + * met: http://www.gnu.org/licenses/gpl-2.0.html. + */ + +pragma Singleton +import QtQuick 2.2 + +QtObject { + property SystemPalette active: SystemPalette { colorGroup: SystemPalette.Active } + property SystemPalette disabled: SystemPalette { colorGroup: SystemPalette.Disabled } + + function alternateBase(enabled) { return enabled ? active.alternateBase : disabled.alternateBase } + function base(enabled) { return enabled ? active.base : disabled.base } + function button(enabled) { return enabled ? active.button : disabled.button } + function buttonText(enabled) { return enabled ? active.buttonText : disabled.buttonText } + function dark(enabled) { return enabled ? active.dark : disabled.dark } + function highlight(enabled) { return enabled ? active.highlight : disabled.highlight } + function highlightedText(enabled) { return enabled ? active.highlightedText : disabled.highlightedText } + function light(enabled) { return enabled ? active.light : disabled.light } + function mid(enabled) { return enabled ? active.mid : disabled.mid } + function midlight(enabled) { return enabled ? active.midlight : disabled.midlight } + function shadow(enabled) { return enabled ? active.shadow : disabled.shadow } + function text(enabled) { return enabled ? active.text : disabled.text } + function window(enabled) { return enabled ? active.window : disabled.window } + function windowText(enabled) { return enabled ? active.windowText : disabled.windowText } +} diff --git a/org.kde.desktop/RadioIndicator.qml b/plugin/TextSingleton.qml copy from org.kde.desktop/RadioIndicator.qml copy to plugin/TextSingleton.qml --- a/org.kde.desktop/RadioIndicator.qml +++ b/plugin/TextSingleton.qml @@ -19,21 +19,7 @@ * met: http://www.gnu.org/licenses/gpl-2.0.html. */ - -import QtQuick 2.6 -//QQC1 is needed for StyleItem to fully work -import QtQuick.Controls 1.0 as QQC1 -import QtQuick.Controls.Private 1.0 - -StyleItem { - id: styleitem - property Item control - elementType: "radiobutton" - sunken: control.pressed - on: control.checked || control.pressed - hover: control.hovered - enabled: control.enabled - implicitWidth: pixelMetric("indicatorwidth") + 4 - implicitHeight : implicitWidth +pragma Singleton +import QtQuick 2.2 +Text { } - diff --git a/plugin/kquickpadding_p.h b/plugin/kquickpadding_p.h new file mode 100644 --- /dev/null +++ b/plugin/kquickpadding_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright 2017 by Marco Martin +** Copyright 2017 by David Edmundson +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef KQUICKPADDING_H +#define KQUICKPADDING_H + +#include + +class KQuickPadding : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int left READ left WRITE setLeft NOTIFY leftChanged) + Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged) + Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightChanged) + Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + + int m_left; + int m_top; + int m_right; + int m_bottom; + +public: + KQuickPadding(QObject *parent = 0) : + QObject(parent), + m_left(0), + m_top(0), + m_right(0), + m_bottom(0) {} + + int left() const { return m_left; } + int top() const { return m_top; } + int right() const { return m_right; } + int bottom() const { return m_bottom; } + +public slots: + void setLeft(int arg) { if (m_left != arg) {m_left = arg; emit leftChanged();}} + void setTop(int arg) { if (m_top != arg) {m_top = arg; emit topChanged();}} + void setRight(int arg) { if (m_right != arg) {m_right = arg; emit rightChanged();}} + void setBottom(int arg) {if (m_bottom != arg) {m_bottom = arg; emit bottomChanged();}} + +signals: + void leftChanged(); + void topChanged(); + void rightChanged(); + void bottomChanged(); +}; + + +#endif // QQUICKPADDING_H diff --git a/plugin/kquickstyleitem.cpp b/plugin/kquickstyleitem.cpp new file mode 100644 --- /dev/null +++ b/plugin/kquickstyleitem.cpp @@ -0,0 +1,1647 @@ +/**************************************************************************** +** +** Copyright 2017 by Marco Martin +** Copyright 2017 by David Edmundson +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "kquickstyleitem_p.h" + +#include +#include +#include +#include +#include +#include +#include +#if QT_VERSION >= QT_VERSION_CHECK(5,8,0) +#include +#else +#include "qsgdefaultninepatchnode_p.h" +#endif + + +KQuickStyleItem::KQuickStyleItem(QQuickItem *parent) + : QQuickItem(parent), + m_styleoption(0), + m_itemType(Undefined), + m_sunken(false), + m_raised(false), + m_active(true), + m_selected(false), + m_focus(false), + m_hover(false), + m_on(false), + m_horizontal(true), + m_transient(false), + m_sharedWidget(false), + m_minimum(0), + m_maximum(100), + m_value(0), + m_step(0), + m_paintMargins(0), + m_contentWidth(0), + m_contentHeight(0), + m_textureWidth(0), + m_textureHeight(0), + m_lastFocusReason(Qt::NoFocusReason) +{ + m_font = qApp->font(); + setFlag(QQuickItem::ItemHasContents, true); + setSmooth(false); + qmlRegisterType(); + + connect(this, SIGNAL(visibleChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(widthChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(heightChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(enabledChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(infoChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(onChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(selectedChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(textChanged()), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(textChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(raisedChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(sunkenChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(hoverChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(maximumChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(minimumChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(valueChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(horizontalChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(transientChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(hasFocusChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(hintChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(propertiesChanged()), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(propertiesChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(elementTypeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(contentWidthChanged(int)), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(contentHeightChanged(int)), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(widthChanged()), this, SLOT(updateRect())); + connect(this, SIGNAL(heightChanged()), this, SLOT(updateRect())); + + connect(this, SIGNAL(heightChanged()), this, SLOT(updateBaselineOffset())); + connect(this, SIGNAL(contentHeightChanged(int)), this, SLOT(updateBaselineOffset())); +} + +KQuickStyleItem::~KQuickStyleItem() +{ + if (const QStyleOptionButton *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionViewItem *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionHeader *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionToolButton *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionToolBar *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionTab *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionFrame *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionFocusRect *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionTabWidgetFrame *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionMenuItem *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionComboBox *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionSpinBox *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionSlider *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionProgressBar *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else if (const QStyleOptionGroupBox *aux = qstyleoption_cast(m_styleoption)) + delete aux; + else + delete m_styleoption; + + m_styleoption = 0; +} + +void KQuickStyleItem::initStyleOption() +{ + if (m_styleoption) + m_styleoption->state = 0; + + QString sizeHint = m_hints.value(QStringLiteral("size")).toString(); + + bool needsResolvePalette = true; + + switch (m_itemType) { + case Button: { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->icon = m_properties[QStringLiteral("icon")].value(); + int e = qApp->style()->pixelMetric(QStyle::PM_ButtonIconSize, m_styleoption, 0); + opt->iconSize = QSize(e, e); + opt->features = activeControl() == QLatin1String("default") ? + QStyleOptionButton::DefaultButton : + QStyleOptionButton::None; + const QFont font = qApp->font("QPushButton"); + opt->fontMetrics = QFontMetrics(font); + QObject * menu = m_properties[QStringLiteral("menu")].value(); + if (menu) { + opt->features |= QStyleOptionButton::HasMenu; + } + } + break; + case ItemRow: { + if (!m_styleoption) + m_styleoption = new QStyleOptionViewItem(); + + QStyleOptionViewItem *opt = qstyleoption_cast(m_styleoption); + opt->features = 0; + if (activeControl() == QLatin1String("alternate")) + opt->features |= QStyleOptionViewItem::Alternate; + } + break; + + case Splitter: { + if (!m_styleoption) { + m_styleoption = new QStyleOption; + } + } + break; + + case Item: { + if (!m_styleoption) { + m_styleoption = new QStyleOptionViewItem(); + } + QStyleOptionViewItem *opt = qstyleoption_cast(m_styleoption); + opt->features = QStyleOptionViewItem::HasDisplay; + opt->text = text(); + opt->textElideMode = Qt::ElideRight; + opt->displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; + opt->decorationAlignment = Qt::AlignCenter; + resolvePalette(); + needsResolvePalette = false; + QPalette pal = m_styleoption->palette; + pal.setBrush(QPalette::Base, Qt::NoBrush); + m_styleoption->palette = pal; + const QFont font = qApp->font("QAbstractItemView"); + opt->font = font; + opt->fontMetrics = QFontMetrics(font); + break; + } + case ItemBranchIndicator: { + if (!m_styleoption) + m_styleoption = new QStyleOption; + + m_styleoption->state = QStyle::State_Item; // We don't want to fully support Win 95 + if (m_properties.value(QStringLiteral("hasChildren")).toBool()) + m_styleoption->state |= QStyle::State_Children; + if (m_properties.value(QStringLiteral("hasSibling")).toBool()) // Even this one could go away + m_styleoption->state |= QStyle::State_Sibling; + if (m_on) + m_styleoption->state |= QStyle::State_Open; + } + break; + case Header: { + if (!m_styleoption) + m_styleoption = new QStyleOptionHeader(); + + QStyleOptionHeader *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->textAlignment = static_cast(m_properties.value(QStringLiteral("textalignment")).toInt()); + opt->sortIndicator = activeControl() == QLatin1String("down") ? + QStyleOptionHeader::SortDown + : activeControl() == QLatin1String("up") ? + QStyleOptionHeader::SortUp : QStyleOptionHeader::None; + QString headerpos = m_properties.value(QStringLiteral("headerpos")).toString(); + if (headerpos == QLatin1String("beginning")) + opt->position = QStyleOptionHeader::Beginning; + else if (headerpos == QLatin1String("end")) + opt->position = QStyleOptionHeader::End; + else if (headerpos == QLatin1String("only")) + opt->position = QStyleOptionHeader::OnlyOneSection; + else + opt->position = QStyleOptionHeader::Middle; + + const QFont font = qApp->font("QHeaderView"); + opt->fontMetrics = QFontMetrics(font); + } + break; + case ToolButton: { + if (!m_styleoption) + m_styleoption = new QStyleOptionToolButton(); + + QStyleOptionToolButton *opt = + qstyleoption_cast(m_styleoption); + opt->subControls = QStyle::SC_ToolButton; + opt->state |= QStyle::State_AutoRaise; + opt->activeSubControls = QStyle::SC_ToolButton; + opt->text = text(); + opt->icon = m_properties[QStringLiteral("icon")].value(); + + if (m_properties.value(QStringLiteral("menu")).toBool()) { + opt->subControls |= QStyle::SC_ToolButtonMenu; + opt->features = QStyleOptionToolButton::HasMenu; + } + + // For now icon only is displayed by default. + opt->toolButtonStyle = Qt::ToolButtonIconOnly; + if (opt->icon.isNull() && !opt->text.isEmpty()) + opt->toolButtonStyle = Qt::ToolButtonTextOnly; + + int e = qApp->style()->pixelMetric(QStyle::PM_ToolBarIconSize, m_styleoption, 0); + opt->iconSize = QSize(e, e); + + const QFont font = qApp->font("QToolButton"); + opt->font = font; + opt->fontMetrics = QFontMetrics(font); + } + break; + case ToolBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionToolBar(); + } + break; + case Tab: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTab(); + + QStyleOptionTab *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + + if (m_properties.value(QStringLiteral("hasFrame")).toBool()) + opt->features |= QStyleOptionTab::HasFrame; + + QString orientation = m_properties.value(QStringLiteral("orientation")).toString(); + QString position = m_properties.value(QStringLiteral("tabpos")).toString(); + QString selectedPosition = m_properties.value(QStringLiteral("selectedpos")).toString(); + + opt->shape = orientation == QLatin1String("Bottom") ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; + if (position == QLatin1String("beginning")) + opt->position = QStyleOptionTab::Beginning; + else if (position == QLatin1String("end")) + opt->position = QStyleOptionTab::End; + else if (position == QLatin1String("only")) + opt->position = QStyleOptionTab::OnlyOneTab; + else + opt->position = QStyleOptionTab::Middle; + + if (selectedPosition == QLatin1String("next")) + opt->selectedPosition = QStyleOptionTab::NextIsSelected; + else if (selectedPosition == QLatin1String("previous")) + opt->selectedPosition = QStyleOptionTab::PreviousIsSelected; + else + opt->selectedPosition = QStyleOptionTab::NotAdjacent; + + + } break; + + case Frame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrame(); + + QStyleOptionFrame *opt = qstyleoption_cast(m_styleoption); + opt->frameShape = QFrame::StyledPanel; + opt->lineWidth = 1; + opt->midLineWidth = 1; + } + break; + case FocusRect: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFocusRect(); + // Needed on windows + m_styleoption->state |= QStyle::State_KeyboardFocusChange; + } + break; + case TabFrame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTabWidgetFrame(); + QStyleOptionTabWidgetFrame *opt = qstyleoption_cast(m_styleoption); + + opt->selectedTabRect = m_properties[QStringLiteral("selectedTabRect")].toRect(); + opt->shape = m_properties[QStringLiteral("orientation")] == Qt::BottomEdge ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; + if (minimum()) + opt->selectedTabRect = QRect(value(), 0, minimum(), height()); + opt->tabBarSize = QSize(minimum() , height()); + // oxygen style needs this hack + opt->leftCornerWidgetSize = QSize(value(), 0); + } + break; + case MenuBar: + if (!m_styleoption) { + QStyleOptionMenuItem *menuOpt = new QStyleOptionMenuItem(); + menuOpt->menuItemType = QStyleOptionMenuItem::EmptyArea; + m_styleoption = menuOpt; + } + + break; + case MenuBarItem: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + + QStyleOptionMenuItem *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->menuItemType = QStyleOptionMenuItem::Normal; + setProperty("_q_showUnderlined", m_hints[QStringLiteral("showUnderlined")].toBool()); + + const QFont font = qApp->font("QMenuBar"); + opt->font = font; + opt->fontMetrics = QFontMetrics(font); + m_font = opt->font; + } + break; + case Menu: { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + } + break; + case MenuItem: + case ComboBoxItem: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + + QStyleOptionMenuItem *opt = qstyleoption_cast(m_styleoption); + // For GTK style. See below, in setElementType() + setProperty("_q_isComboBoxPopupItem", m_itemType == ComboBoxItem); + + KQuickStyleItem::MenuItemType type = + static_cast(m_properties[QStringLiteral("type")].toInt()); + if (type == KQuickStyleItem::ScrollIndicatorType) { + int scrollerDirection = m_properties[QStringLiteral("scrollerDirection")].toInt(); + opt->menuItemType = QStyleOptionMenuItem::Scroller; + opt->state |= scrollerDirection == Qt::UpArrow ? + QStyle::State_UpArrow : QStyle::State_DownArrow; + } else if (type == KQuickStyleItem::SeparatorType) { + opt->menuItemType = QStyleOptionMenuItem::Separator; + } else { + opt->text = text(); + + if (type == KQuickStyleItem::MenuType) { + opt->menuItemType = QStyleOptionMenuItem::SubMenu; + } else { + opt->menuItemType = QStyleOptionMenuItem::Normal; + + QString shortcut = m_properties[QStringLiteral("shortcut")].toString(); + if (!shortcut.isEmpty()) { + opt->text += QLatin1Char('\t') + shortcut; + opt->tabWidth = qMax(opt->tabWidth, qRound(textWidth(shortcut))); + } + + if (m_properties[QStringLiteral("checkable")].toBool()) { + opt->checked = on(); + QVariant exclusive = m_properties[QStringLiteral("exclusive")]; + opt->checkType = exclusive.toBool() ? QStyleOptionMenuItem::Exclusive : + QStyleOptionMenuItem::NonExclusive; + } + } + if (m_properties[QStringLiteral("icon")].canConvert()) + opt->icon = m_properties[QStringLiteral("icon")].value(); + setProperty("_q_showUnderlined", m_hints["showUnderlined"].toBool()); + + const QFont font = qApp->font(m_itemType == ComboBoxItem ?"QComboMenuItem" : "QMenu"); + opt->font = font; + opt->fontMetrics = QFontMetrics(font); + m_font = opt->font; + } + } + break; + case CheckBox: + case RadioButton: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast(m_styleoption); + if (!on()) + opt->state |= QStyle::State_Off; + if (m_properties.value(QStringLiteral("partiallyChecked")).toBool()) + opt->state |= QStyle::State_NoChange; + opt->text = text(); + } + break; + case Edit: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrame(); + + QStyleOptionFrame *opt = qstyleoption_cast(m_styleoption); + opt->lineWidth = 1; // this must be non-zero + } + break; + case ComboBox :{ + if (!m_styleoption) + m_styleoption = new QStyleOptionComboBox(); + + QStyleOptionComboBox *opt = qstyleoption_cast(m_styleoption); + + const QFont font = qApp->font("QPushButton"); //DAVE - QQC1 code does this, but if you look at QComboBox this doesn't make sense + opt->fontMetrics = QFontMetrics(font); + opt->currentText = text(); + opt->editable = m_properties[QStringLiteral("editable")].toBool(); + } + break; + case SpinBox: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSpinBox(); + + QStyleOptionSpinBox *opt = qstyleoption_cast(m_styleoption); + opt->frame = true; + opt->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField; + if (value() & 0x1) + opt->activeSubControls = QStyle::SC_SpinBoxUp; + else if (value() & (1<<1)) + opt->activeSubControls = QStyle::SC_SpinBoxDown; + opt->subControls = QStyle::SC_All; + opt->stepEnabled = 0; + if (value() & (1<<2)) + opt->stepEnabled |= QAbstractSpinBox::StepUpEnabled; + if (value() & (1<<3)) + opt->stepEnabled |= QAbstractSpinBox::StepDownEnabled; + } + break; + case Slider: + case Dial: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionSlider(); + + QStyleOptionSlider *opt = qstyleoption_cast(m_styleoption); + opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; + opt->upsideDown = !horizontal(); + opt->minimum = minimum(); + opt->maximum = maximum(); + opt->sliderPosition = value(); + opt->singleStep = step(); + + if (opt->singleStep) { + qreal numOfSteps = (opt->maximum - opt->minimum) / opt->singleStep; + // at least 5 pixels between tick marks + qreal extent = horizontal() ? width() : height(); + if (numOfSteps && (extent / numOfSteps < 5)) + opt->tickInterval = qRound((5 * numOfSteps / extent) + 0.5) * step(); + else + opt->tickInterval = opt->singleStep; + + } else // default Qt-components implementation + opt->tickInterval = opt->maximum != opt->minimum ? 1200 / (opt->maximum - opt->minimum) : 0; + + opt->sliderValue = value(); + opt->subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle; + opt->tickPosition = activeControl() == QLatin1String("ticks") ? + QSlider::TicksBelow : QSlider::NoTicks; + if (opt->tickPosition != QSlider::NoTicks) + opt->subControls |= QStyle::SC_SliderTickmarks; + + opt->activeSubControls = QStyle::SC_SliderHandle; + } + break; + case ProgressBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionProgressBar(); + + QStyleOptionProgressBar *opt = qstyleoption_cast(m_styleoption); + opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; + opt->minimum = minimum(); + opt->maximum = maximum(); + opt->progress = value(); + } + break; + case GroupBox: { + if (!m_styleoption) + m_styleoption = new QStyleOptionGroupBox(); + + QStyleOptionGroupBox *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->lineWidth = 1; + opt->subControls = QStyle::SC_GroupBoxLabel; + opt->features = 0; + if (m_properties[QStringLiteral("sunken")].toBool()) { // Qt draws an ugly line here so I ignore it + opt->subControls |= QStyle::SC_GroupBoxFrame; + } else { + opt->features |= QStyleOptionFrame::Flat; + } + if (m_properties[QStringLiteral("checkable")].toBool()) + opt->subControls |= QStyle::SC_GroupBoxCheckBox; + + } + break; + case ScrollBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSlider(); + + QStyleOptionSlider *opt = qstyleoption_cast(m_styleoption); + opt->minimum = minimum(); + opt->maximum = maximum(); + opt->pageStep = qMax(0, int(horizontal() ? width() : height())); + opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; + opt->sliderPosition = value(); + opt->sliderValue = value(); + opt->activeSubControls = (activeControl() == QLatin1String("up")) + ? QStyle::SC_ScrollBarSubLine : (activeControl() == QLatin1String("down")) ? + QStyle::SC_ScrollBarAddLine : + (activeControl() == QLatin1String("handle")) ? + QStyle::SC_ScrollBarSlider : hover() ? QStyle::SC_ScrollBarGroove : QStyle::SC_None; + if (raised()) + opt->state |= QStyle::State_On; + + opt->sliderValue = value(); + opt->subControls = QStyle::SC_All; + + setTransient(qApp->style()->styleHint(QStyle::SH_ScrollBar_Transient, m_styleoption)); + break; + } + default: + break; + } + + if (!m_styleoption) + m_styleoption = new QStyleOption(); + + if (needsResolvePalette) + resolvePalette(); + + m_styleoption->styleObject = this; + m_styleoption->direction = qApp->layoutDirection(); + + int w = m_textureWidth > 0 ? m_textureWidth : width(); + int h = m_textureHeight > 0 ? m_textureHeight : height(); + + m_styleoption->rect = QRect(m_paintMargins, 0, w - 2* m_paintMargins, h); + + if (isEnabled()) { + m_styleoption->state |= QStyle::State_Enabled; + m_styleoption->palette.setCurrentColorGroup(QPalette::Active); + } else { + m_styleoption->palette.setCurrentColorGroup(QPalette::Disabled); + } + if (m_active) + m_styleoption->state |= QStyle::State_Active; + else + m_styleoption->palette.setCurrentColorGroup(QPalette::Inactive); + if (m_sunken) + m_styleoption->state |= QStyle::State_Sunken; + if (m_raised) + m_styleoption->state |= QStyle::State_Raised; + if (m_selected) + m_styleoption->state |= QStyle::State_Selected; + if (m_focus) + m_styleoption->state |= QStyle::State_HasFocus; + if (m_on) + m_styleoption->state |= QStyle::State_On; + if (m_hover) + m_styleoption->state |= QStyle::State_MouseOver; + if (m_horizontal) + m_styleoption->state |= QStyle::State_Horizontal; + + // some styles don't draw a focus rectangle if + // QStyle::State_KeyboardFocusChange is not set + if (window()) { + if (m_lastFocusReason == Qt::TabFocusReason || m_lastFocusReason == Qt::BacktabFocusReason) { + m_styleoption->state |= QStyle::State_KeyboardFocusChange; + } + } + + if (sizeHint == QLatin1String("mini")) { + m_styleoption->state |= QStyle::State_Mini; + } else if (sizeHint == QLatin1String("small")) { + m_styleoption->state |= QStyle::State_Small; + } + +} + +const char* KQuickStyleItem::classNameForItem() const +{ + switch(m_itemType) { + case Button: + return "QPushButton"; + case RadioButton: + return "QRadioButton"; + case CheckBox: + return "QCheckBox"; + case ComboBox: + return "QComboBox"; + case ComboBoxItem: + return "QComboMenuItem"; + case ToolBar: + return ""; + case ToolButton: + return "QToolButton"; + case Tab: + return "QTabButton"; + case TabFrame: + return "QTabBar"; + case Edit: + return "QTextEdit"; + case GroupBox: + return "QGroupBox"; + case Header: + return "QHeaderView"; + case Item: + case ItemRow: + return "QAbstractItemView"; + case Menu: + case MenuItem: + return "QMenu"; + case MenuBar: + case MenuBarItem: + return "QMenuBar"; + default: + return ""; + } + Q_UNREACHABLE(); +} + +void KQuickStyleItem::resolvePalette() +{ + if (QCoreApplication::testAttribute(Qt::AA_SetPalette)) + return; + + m_styleoption->palette = QApplication::palette(classNameForItem()); +} + +/* + * Property style + * + * Returns a simplified style name. + * + * QMacStyle = "mac" + * QWindowsXPStyle = "windowsxp" + * QFusionStyle = "fusion" + */ + +QString KQuickStyleItem::style() const +{ + QString style = qApp->style()->metaObject()->className(); + style = style.toLower(); + if (style.startsWith(QLatin1Char('q'))) + style = style.right(style.length() - 1); + if (style.endsWith(QLatin1String("style"))) + style = style.left(style.length() - 5); + return style; +} + +QString KQuickStyleItem::hitTest(int px, int py) +{ + QStyle::SubControl subcontrol = QStyle::SC_All; + switch (m_itemType) { + case SpinBox :{ + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_SpinBox, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SpinBoxUp) + return QStringLiteral("up"); + else if (subcontrol == QStyle::SC_SpinBoxDown) + return QStringLiteral("down"); + } + break; + + case Slider: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_Slider, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SliderHandle) + return QStringLiteral("handle"); + } + break; + + case ScrollBar: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_ScrollBar, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + switch (subcontrol) { + case QStyle::SC_ScrollBarSlider: + return QStringLiteral("handle"); + + case QStyle::SC_ScrollBarSubLine: + return QStringLiteral("up"); + + case QStyle::SC_ScrollBarSubPage: + return QStringLiteral("upPage"); + + case QStyle::SC_ScrollBarAddLine: + return QStringLiteral("down"); + + case QStyle::SC_ScrollBarAddPage: + return QStringLiteral("downPage"); + + default: + break; + } + } + break; + + default: + break; + } + return QStringLiteral("none"); +} + +QSize KQuickStyleItem::sizeFromContents(int width, int height) +{ + initStyleOption(); + + QSize size; + switch (m_itemType) { + case RadioButton: + size = qApp->style()->sizeFromContents(QStyle::CT_RadioButton, m_styleoption, QSize(width,height)); + break; + case CheckBox: + size = qApp->style()->sizeFromContents(QStyle::CT_CheckBox, m_styleoption, QSize(width,height)); + break; + case ToolBar: + size = QSize(200, style().contains(QLatin1String("windows")) ? 30 : 42); + break; + case ToolButton: { + QStyleOptionToolButton *btn = qstyleoption_cast(m_styleoption); + int w = 0; + int h = 0; + if (btn->toolButtonStyle != Qt::ToolButtonTextOnly) { + QSize icon = btn->iconSize; + w = icon.width(); + h = icon.height(); + } + if (btn->toolButtonStyle != Qt::ToolButtonIconOnly) { + QSize textSize = btn->fontMetrics.size(Qt::TextShowMnemonic, btn->text); + textSize.setWidth(textSize.width() + btn->fontMetrics.width(QLatin1Char(' '))*2); + if (btn->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { + h += 4 + textSize.height(); + if (textSize.width() > w) + w = textSize.width(); + } else if (btn->toolButtonStyle == Qt::ToolButtonTextBesideIcon) { + w += 4 + textSize.width(); + if (textSize.height() > h) + h = textSize.height(); + } else { // TextOnly + w = textSize.width(); + h = textSize.height(); + } + } + btn->rect.setSize(QSize(w, h)); + size = qApp->style()->sizeFromContents(QStyle::CT_ToolButton, m_styleoption, QSize(w, h)); } + break; + case Button: { + QStyleOptionButton *btn = qstyleoption_cast(m_styleoption); + + int contentWidth = btn->fontMetrics.width(btn->text); + int contentHeight = btn->fontMetrics.height(); + if (!btn->icon.isNull()) { + //+4 matches a hardcoded value in QStyle and acts as a margin between the icon and the text. + contentWidth += btn->iconSize.width() + 4; + contentHeight = qMax(btn->fontMetrics.height(), btn->iconSize.height()); + } + int newWidth = qMax(width, contentWidth); + int newHeight = qMax(height, contentHeight); + size = qApp->style()->sizeFromContents(QStyle::CT_PushButton, m_styleoption, QSize(newWidth, newHeight)); } + break; + case ComboBox: { + QStyleOptionComboBox *btn = qstyleoption_cast(m_styleoption); + int newWidth = qMax(width, btn->fontMetrics.width(btn->currentText)); + int newHeight = qMax(height, btn->fontMetrics.height()); + size = qApp->style()->sizeFromContents(QStyle::CT_ComboBox, m_styleoption, QSize(newWidth, newHeight)); } + break; + case Tab: + size = qApp->style()->sizeFromContents(QStyle::CT_TabBarTab, m_styleoption, QSize(width,height)); + break; + case Slider: + size = qApp->style()->sizeFromContents(QStyle::CT_Slider, m_styleoption, QSize(width,height)); + break; + case ProgressBar: + size = qApp->style()->sizeFromContents(QStyle::CT_ProgressBar, m_styleoption, QSize(width,height)); + break; + case SpinBox: + case Edit: + { + // We have to create a new style option since we might be calling with a QStyleOptionSpinBox + QStyleOptionFrame frame; + frame.state = m_styleoption->state; + frame.lineWidth = qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, 0); + frame.rect = m_styleoption->rect; + frame.styleObject = this; + size = qApp->style()->sizeFromContents(QStyle::CT_LineEdit, &frame, QSize(width, height)); + if (m_itemType == SpinBox) + size.setWidth(qApp->style()->sizeFromContents(QStyle::CT_SpinBox, + m_styleoption, QSize(width + 2, height)).width()); + } + break; + case GroupBox: { + QStyleOptionGroupBox *box = qstyleoption_cast(m_styleoption); + QFontMetrics metrics(box->fontMetrics); + int baseWidth = metrics.width(box->text) + metrics.width(QLatin1Char(' ')); + int baseHeight = metrics.height() + m_contentHeight; + if (box->subControls & QStyle::SC_GroupBoxCheckBox) { + baseWidth += qApp->style()->pixelMetric(QStyle::PM_IndicatorWidth); + baseWidth += qApp->style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing); + baseHeight = qMax(baseHeight, qApp->style()->pixelMetric(QStyle::PM_IndicatorHeight)); + } + size = qApp->style()->sizeFromContents(QStyle::CT_GroupBox, m_styleoption, QSize(qMax(baseWidth, m_contentWidth), baseHeight)); + } + break; + case Header: + size = qApp->style()->sizeFromContents(QStyle::CT_HeaderSection, m_styleoption, QSize(width,height)); + break; + case ItemRow: + case Item: //fall through + size = qApp->style()->sizeFromContents(QStyle::CT_ItemViewItem, m_styleoption, QSize(width,height)); + break; + case MenuBarItem: + size = qApp->style()->sizeFromContents(QStyle::CT_MenuBarItem, m_styleoption, QSize(width,height)); + break; + case MenuBar: + size = qApp->style()->sizeFromContents(QStyle::CT_MenuBar, m_styleoption, QSize(width,height)); + break; + case Menu: + size = qApp->style()->sizeFromContents(QStyle::CT_Menu, m_styleoption, QSize(width,height)); + break; + case MenuItem: + case ComboBoxItem: + if (static_cast(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller) { + size.setHeight(qMax(QApplication::globalStrut().height(), + qApp->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, 0))); + } else { + size = qApp->style()->sizeFromContents(QStyle::CT_MenuItem, m_styleoption, QSize(width,height)); + } + break; + default: + break; + } return size; +} + +qreal KQuickStyleItem::baselineOffset() +{ + QRect r; + bool ceilResult = true; // By default baseline offset rounding is done upwards + switch (m_itemType) { + case RadioButton: + r = qApp->style()->subElementRect(QStyle::SE_RadioButtonContents, m_styleoption); + break; + case Button: + r = qApp->style()->subElementRect(QStyle::SE_PushButtonContents, m_styleoption); + break; + case CheckBox: + r = qApp->style()->subElementRect(QStyle::SE_CheckBoxContents, m_styleoption); + break; + case Edit: + r = qApp->style()->subElementRect(QStyle::SE_LineEditContents, m_styleoption); + break; + case ComboBox: + if (const QStyleOptionComboBox *combo = qstyleoption_cast(m_styleoption)) { + r = qApp->style()->subControlRect(QStyle::CC_ComboBox, combo, QStyle::SC_ComboBoxEditField); + if (style() != QLatin1String("mac")) + r.adjust(0,0,0,1); + } + break; + case SpinBox: + if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast(m_styleoption)) { + r = qApp->style()->subControlRect(QStyle::CC_SpinBox, spinbox, QStyle::SC_SpinBoxEditField); + ceilResult = false; + } + break; + default: + break; + } + if (r.height() > 0) { + const QFontMetrics &fm = m_styleoption->fontMetrics; + int surplus = r.height() - fm.height(); + if ((surplus & 1) && ceilResult) + surplus++; + int result = r.top() + surplus/2 + fm.ascent(); + return result; + } + + return 0.; +} + +void KQuickStyleItem::updateBaselineOffset() +{ + const qreal baseline = baselineOffset(); + if (baseline > 0) + setBaselineOffset(baseline); +} + +void KQuickStyleItem::setContentWidth(int arg) +{ + if (m_contentWidth != arg) { + m_contentWidth = arg; + emit contentWidthChanged(arg); + } +} + +void KQuickStyleItem::setContentHeight(int arg) +{ + if (m_contentHeight != arg) { + m_contentHeight = arg; + emit contentHeightChanged(arg); + } +} + +void KQuickStyleItem::updateSizeHint() +{ + QSize implicitSize = sizeFromContents(m_contentWidth, m_contentHeight); + setImplicitSize(implicitSize.width(), implicitSize.height()); +} + +void KQuickStyleItem::updateRect() +{ + initStyleOption(); + m_styleoption->rect.setWidth(width()); + m_styleoption->rect.setHeight(height()); +} + +int KQuickStyleItem::pixelMetric(const QString &metric) +{ + + if (metric == QLatin1String("scrollbarExtent")) + return qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0 ); + else if (metric == QLatin1String("defaultframewidth")) + return qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption); + else if (metric == QLatin1String("taboverlap")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ); + else if (metric == QLatin1String("tabbaseoverlap")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, m_styleoption ); + else if (metric == QLatin1String("tabhspace")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabHSpace, 0 ); + else if (metric == QLatin1String("indicatorwidth")) + return qApp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, 0 ); + else if (metric == QLatin1String("tabvspace")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabVSpace, 0 ); + else if (metric == QLatin1String("tabbaseheight")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0 ); + else if (metric == QLatin1String("tabvshift")) + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, 0 ); + else if (metric == QLatin1String("menubarhmargin")) + return qApp->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0 ); + else if (metric == QLatin1String("menubarvmargin")) + return qApp->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0 ); + else if (metric == QLatin1String("menubarpanelwidth")) + return qApp->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0 ); + else if (metric == QLatin1String("menubaritemspacing")) + return qApp->style()->pixelMetric(QStyle::PM_MenuBarItemSpacing, 0 ); + else if (metric == QLatin1String("spacebelowmenubar")) + return qApp->style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, m_styleoption); + else if (metric == QLatin1String("menuhmargin")) + return qApp->style()->pixelMetric(QStyle::PM_MenuHMargin, 0 ); + else if (metric == QLatin1String("menuvmargin")) + return qApp->style()->pixelMetric(QStyle::PM_MenuVMargin, 0 ); + else if (metric == QLatin1String("menupanelwidth")) + return qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0 ); + else if (metric == QLatin1String("submenuoverlap")) + return qApp->style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0 ); + else if (metric == QLatin1String("splitterwidth")) + return qApp->style()->pixelMetric(QStyle::PM_SplitterWidth, 0 ); + else if (metric == QLatin1String("scrollbarspacing")) + return abs(qApp->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, 0 )); + else if (metric == QLatin1String("treeviewindentation")) + return qApp->style()->pixelMetric(QStyle::PM_TreeViewIndentation, 0 ); + return 0; +} + +QVariant KQuickStyleItem::styleHint(const QString &metric) +{ + initStyleOption(); + if (metric == QLatin1String("comboboxpopup")) { + return qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, m_styleoption); + } else if (metric == QLatin1String("highlightedTextColor")) { + return m_styleoption->palette.highlightedText().color().name(); + } else if (metric == QLatin1String("textColor")) { + QPalette pal = m_styleoption->palette; + pal.setCurrentColorGroup(active()? QPalette::Active : QPalette::Inactive); + return pal.text().color().name(); + } else if (metric == QLatin1String("focuswidget")) { + return qApp->style()->styleHint(QStyle::SH_FocusFrame_AboveWidget); + } else if (metric == QLatin1String("tabbaralignment")) { + int result = qApp->style()->styleHint(QStyle::SH_TabBar_Alignment); + if (result == Qt::AlignCenter) + return QStringLiteral("center"); + return QStringLiteral("left"); + } else if (metric == QLatin1String("externalScrollBars")) { + return qApp->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents); + } else if (metric == QLatin1String("scrollToClickPosition")) + return qApp->style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition); + else if (metric == QLatin1String("activateItemOnSingleClick")) + return qApp->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick); + else if (metric == QLatin1String("submenupopupdelay")) + return qApp->style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, m_styleoption); + else if (metric == QLatin1String("wheelScrollLines")) + return qApp->wheelScrollLines(); + return 0; + + // Add SH_Menu_SpaceActivatesItem +} + +void KQuickStyleItem::setHints(const QVariantMap &str) +{ + if (m_hints != str) { + m_hints = str; + initStyleOption(); + updateSizeHint(); + if (m_styleoption->state & QStyle::State_Mini) { + m_font.setPointSize(9.); + emit fontChanged(); + } else if (m_styleoption->state & QStyle::State_Small) { + m_font.setPointSize(11.); + emit fontChanged(); + } else { + emit hintChanged(); + } + } +} + +void KQuickStyleItem::resetHints() +{ + m_hints.clear(); +} + + +void KQuickStyleItem::setElementType(const QString &str) +{ + if (m_type == str) + return; + + m_type = str; + + emit elementTypeChanged(); + if (m_styleoption) { + delete m_styleoption; + m_styleoption = 0; + } + + // Only enable visible if the widget can animate + if (str == QLatin1String("menu")) { + m_itemType = Menu; + } else if (str == QLatin1String("menuitem")) { + m_itemType = MenuItem; + } else if (str == QLatin1String("item") || str == QLatin1String("itemrow") || str == QLatin1String("header")) { + if (str == QLatin1String("header")) { + m_itemType = Header; + } else { + m_itemType = str == QLatin1String("item") ? Item : ItemRow; + } + } else if (str == QLatin1String("itembranchindicator")) { + m_itemType = ItemBranchIndicator; + } else if (str == QLatin1String("groupbox")) { + m_itemType = GroupBox; + } else if (str == QLatin1String("tab")) { + m_itemType = Tab; + } else if (str == QLatin1String("tabframe")) { + m_itemType = TabFrame; + } else if (str == QLatin1String("comboboxitem")) { + // Gtk uses qobject cast, hence we need to separate this from menuitem + // On mac, we temporarily use the menu item because it has more accurate + // palette. + m_itemType = ComboBoxItem; + } else if (str == QLatin1String("toolbar")) { + m_itemType = ToolBar; + } else if (str == QLatin1String("toolbutton")) { + m_itemType = ToolButton; + } else if (str == QLatin1String("slider")) { + m_itemType = Slider; + } else if (str == QLatin1String("frame")) { + m_itemType = Frame; + } else if (str == QLatin1String("combobox")) { + m_itemType = ComboBox; + } else if (str == QLatin1String("splitter")) { + m_itemType = Splitter; + } else if (str == QLatin1String("progressbar")) { + m_itemType = ProgressBar; + } else if (str == QLatin1String("button")) { + m_itemType = Button; + } else if (str == QLatin1String("checkbox")) { + m_itemType = CheckBox; + } else if (str == QLatin1String("radiobutton")) { + m_itemType = RadioButton; + } else if (str == QLatin1String("edit")) { + m_itemType = Edit; + } else if (str == QLatin1String("spinbox")) { + m_itemType = SpinBox; + } else if (str == QLatin1String("scrollbar")) { + m_itemType = ScrollBar; + } else if (str == QLatin1String("widget")) { + m_itemType = Widget; + } else if (str == QLatin1String("focusframe")) { + m_itemType = FocusFrame; + } else if (str == QLatin1String("focusrect")) { + m_itemType = FocusRect; + } else if (str == QLatin1String("dial")) { + m_itemType = Dial; + } else if (str == QLatin1String("statusbar")) { + m_itemType = StatusBar; + } else if (str == QLatin1String("machelpbutton")) { + m_itemType = MacHelpButton; + } else if (str == QLatin1String("scrollareacorner")) { + m_itemType = ScrollAreaCorner; + } else if (str == QLatin1String("menubar")) { + m_itemType = MenuBar; + } else if (str == QLatin1String("menubaritem")) { + m_itemType = MenuBarItem; + } else { + m_itemType = Undefined; + } + updateSizeHint(); +} + +QRectF KQuickStyleItem::subControlRect(const QString &subcontrolString) +{ + QStyle::SubControl subcontrol = QStyle::SC_None; + initStyleOption(); + switch (m_itemType) { + case SpinBox: + { + QStyle::ComplexControl control = QStyle::CC_SpinBox; + if (subcontrolString == QLatin1String("down")) + subcontrol = QStyle::SC_SpinBoxDown; + else if (subcontrolString == QLatin1String("up")) + subcontrol = QStyle::SC_SpinBoxUp; + else if (subcontrolString == QLatin1String("edit")){ + subcontrol = QStyle::SC_SpinBoxEditField; + } + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol); + + } + break; + case Slider: + { + QStyle::ComplexControl control = QStyle::CC_Slider; + if (subcontrolString == QLatin1String("handle")) + subcontrol = QStyle::SC_SliderHandle; + else if (subcontrolString == QLatin1String("groove")) + subcontrol = QStyle::SC_SliderGroove; + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol); + + } + break; + case ScrollBar: + { + QStyle::ComplexControl control = QStyle::CC_ScrollBar; + if (subcontrolString == QLatin1String("slider")) + subcontrol = QStyle::SC_ScrollBarSlider; + if (subcontrolString == QLatin1String("groove")) + subcontrol = QStyle::SC_ScrollBarGroove; + else if (subcontrolString == QLatin1String("handle")) + subcontrol = QStyle::SC_ScrollBarSlider; + else if (subcontrolString == QLatin1String("add")) + subcontrol = QStyle::SC_ScrollBarAddPage; + else if (subcontrolString == QLatin1String("sub")) + subcontrol = QStyle::SC_ScrollBarSubPage; + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol); + } + break; + case ItemBranchIndicator: { + QStyleOption opt; + opt.rect = QRect(0, 0, implicitWidth(), implicitHeight()); + return qApp->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, 0); + } + default: + break; + } + return QRectF(); +} + +namespace { +class QHighDpiPixmapsEnabler1 { +public: + QHighDpiPixmapsEnabler1() + :wasEnabled(false) + { + if (!qApp->testAttribute(Qt::AA_UseHighDpiPixmaps)) { + qApp->setAttribute(Qt::AA_UseHighDpiPixmaps); + wasEnabled = true; + } + } + + ~QHighDpiPixmapsEnabler1() + { + if (wasEnabled) + qApp->setAttribute(Qt::AA_UseHighDpiPixmaps, false); + } +private: + bool wasEnabled; +}; +} + +void KQuickStyleItem::paint(QPainter *painter) +{ + initStyleOption(); + if (QStyleOptionMenuItem *opt = qstyleoption_cast(m_styleoption)) + painter->setFont(opt->font); + else { + QFont font; + if (m_styleoption->state & QStyle::State_Mini) { + font = qApp->font("QMiniFont"); + } else if (m_styleoption->state & QStyle::State_Small) { + font = qApp->font("QSmallFont"); + } + painter->setFont(font); + } + + // Set AA_UseHighDpiPixmaps when calling style code to make QIcon return + // "retina" pixmaps. The flag is controlled by the application so we can't + // set it unconditinally. + QHighDpiPixmapsEnabler1 enabler; + + switch (m_itemType) { + case Button: + qApp->style()->drawControl(QStyle::CE_PushButton, m_styleoption, painter); + break; + case ItemRow :{ + QPixmap pixmap; + // Only draw through style once + const QString pmKey = QLatin1Literal("itemrow") % QString::number(m_styleoption->state,16) % activeControl(); + if (!QPixmapCache::find(pmKey, pixmap) || pixmap.width() < width() || height() != pixmap.height()) { + int newSize = width(); + pixmap = QPixmap(newSize, height()); + pixmap.fill(Qt::transparent); + QPainter pixpainter(&pixmap); + qApp->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, m_styleoption, &pixpainter); + if ((style() == QLatin1String("mac") || !qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected)) && selected()) { + QPalette pal = QApplication::palette("QAbstractItemView"); + pal.setCurrentColorGroup(m_styleoption->palette.currentColorGroup()); + pixpainter.fillRect(m_styleoption->rect, pal.highlight()); + } + QPixmapCache::insert(pmKey, pixmap); + } + painter->drawPixmap(0, 0, pixmap); + } + break; + case Item: + qApp->style()->drawControl(QStyle::CE_ItemViewItem, m_styleoption, painter); + break; + case ItemBranchIndicator: + qApp->style()->drawPrimitive(QStyle::PE_IndicatorBranch, m_styleoption, painter); + break; + case Header: + qApp->style()->drawControl(QStyle::CE_Header, m_styleoption, painter); + break; + case ToolButton: + qApp->style()->drawComplexControl(QStyle::CC_ToolButton, qstyleoption_cast(m_styleoption), painter); + break; + case Tab: + { + if (m_lastFocusReason != Qt::TabFocusReason && m_lastFocusReason != Qt::BacktabFocusReason) { + m_styleoption->state &= ~QStyle::State_HasFocus; + } + qApp->style()->drawControl(QStyle::CE_TabBarTab, m_styleoption, painter); + } + break; + case Frame: + qApp->style()->drawControl(QStyle::CE_ShapedFrame, m_styleoption, painter); + break; + case FocusFrame: + qApp->style()->drawControl(QStyle::CE_FocusFrame, m_styleoption, painter); + break; + case FocusRect: + qApp->style()->drawPrimitive(QStyle::PE_FrameFocusRect, m_styleoption, painter); + break; + case TabFrame: + qApp->style()->drawPrimitive(QStyle::PE_FrameTabWidget, m_styleoption, painter); + break; + case MenuBar: + qApp->style()->drawControl(QStyle::CE_MenuBarEmptyArea, m_styleoption, painter); + break; + case MenuBarItem: + qApp->style()->drawControl(QStyle::CE_MenuBarItem, m_styleoption, painter); + break; + case MenuItem: + case ComboBoxItem: { // fall through + QStyle::ControlElement menuElement = + static_cast(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller ? + QStyle::CE_MenuScroller : QStyle::CE_MenuItem; + qApp->style()->drawControl(menuElement, m_styleoption, painter); + } + break; + case CheckBox: + qApp->style()->drawControl(QStyle::CE_CheckBox, m_styleoption, painter); + break; + case RadioButton: + qApp->style()->drawControl(QStyle::CE_RadioButton, m_styleoption, painter); + break; + case Edit: { + qApp->style()->drawPrimitive(QStyle::PE_PanelLineEdit, m_styleoption, painter); + } + break; + case MacHelpButton: + //Not managed as mac is not supported + break; + case Widget: + qApp->style()->drawPrimitive(QStyle::PE_Widget, m_styleoption, painter); + break; + case ScrollAreaCorner: + qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, m_styleoption, painter); + break; + case Splitter: + if (m_styleoption->rect.width() == 1) + painter->fillRect(0, 0, width(), height(), m_styleoption->palette.dark().color()); + else + qApp->style()->drawControl(QStyle::CE_Splitter, m_styleoption, painter); + break; + case ComboBox: + { + qApp->style()->drawComplexControl(QStyle::CC_ComboBox, + qstyleoption_cast(m_styleoption), + painter); + // This is needed on mac as it will use the painter color and ignore the palette + QPen pen = painter->pen(); + painter->setPen(m_styleoption->palette.text().color()); + qApp->style()->drawControl(QStyle::CE_ComboBoxLabel, m_styleoption, painter); + painter->setPen(pen); + } break; + case SpinBox: +#ifdef Q_OS_MAC + // macstyle depends on the embedded qlineedit to fill the editfield background + if (style() == QLatin1String("mac")) { + QRect editRect = qApp->style()->subControlRect(QStyle::CC_SpinBox, + qstyleoption_cast(m_styleoption), + QStyle::SC_SpinBoxEditField); + painter->fillRect(editRect.adjusted(-1, -1, 1, 1), m_styleoption->palette.base()); + } +#endif + qApp->style()->drawComplexControl(QStyle::CC_SpinBox, + qstyleoption_cast(m_styleoption), + painter); + break; + case Slider: + qApp->style()->drawComplexControl(QStyle::CC_Slider, + qstyleoption_cast(m_styleoption), + painter); + break; + case Dial: + qApp->style()->drawComplexControl(QStyle::CC_Dial, + qstyleoption_cast(m_styleoption), + painter); + break; + case ProgressBar: + qApp->style()->drawControl(QStyle::CE_ProgressBar, m_styleoption, painter); + break; + case ToolBar: + painter->fillRect(m_styleoption->rect, m_styleoption->palette.window().color()); + qApp->style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter); + painter->save(); + painter->setPen(style() != QLatin1String("fusion") ? m_styleoption->palette.dark().color().darker(120) : + m_styleoption->palette.window().color().lighter(107)); + painter->drawLine(m_styleoption->rect.bottomLeft(), m_styleoption->rect.bottomRight()); + painter->restore(); + break; + case StatusBar: + { + painter->fillRect(m_styleoption->rect, m_styleoption->palette.window().color()); + painter->setPen(m_styleoption->palette.dark().color().darker(120)); + painter->drawLine(m_styleoption->rect.topLeft(), m_styleoption->rect.topRight()); + qApp->style()->drawPrimitive(QStyle::PE_PanelStatusBar, m_styleoption, painter); + } + break; + case GroupBox: + qApp->style()->drawComplexControl(QStyle::CC_GroupBox, qstyleoption_cast(m_styleoption), painter); + break; + case ScrollBar: + qApp->style()->drawComplexControl(QStyle::CC_ScrollBar, qstyleoption_cast(m_styleoption), painter); + break; + case Menu: { + QStyleHintReturnMask val; + qApp->style()->styleHint(QStyle::SH_Menu_Mask, m_styleoption, 0, &val); + painter->save(); + painter->setClipRegion(val.region); + painter->fillRect(m_styleoption->rect, m_styleoption->palette.window()); + painter->restore(); + qApp->style()->drawPrimitive(QStyle::PE_PanelMenu, m_styleoption, painter); + + if (int fw = qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth)) { + QStyleOptionFrame frame; + frame.state = QStyle::State_None; + frame.lineWidth = fw; + frame.midLineWidth = 0; + frame.rect = m_styleoption->rect; + frame.styleObject = this; + frame.palette = m_styleoption->palette; + qApp->style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, painter); + } + } + break; + default: + break; + } +} + +qreal KQuickStyleItem::textWidth(const QString &text) +{ + QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics); + return fm.boundingRect(text).width(); +} + +qreal KQuickStyleItem::textHeight(const QString &text) +{ + QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics); + return text.isEmpty() ? fm.height() : + fm.boundingRect(text).height(); +} + +QString KQuickStyleItem::elidedText(const QString &text, int elideMode, int width) +{ + return m_styleoption->fontMetrics.elidedText(text, Qt::TextElideMode(elideMode), width); +} + +bool KQuickStyleItem::hasThemeIcon(const QString &icon) const +{ + return QIcon::hasThemeIcon(icon); +} + +bool KQuickStyleItem::event(QEvent *ev) +{ + if (ev->type() == QEvent::StyleAnimationUpdate) { + if (isVisible()) { + ev->accept(); + polish(); + } + return true; + } else if (ev->type() == QEvent::StyleChange) { + if (m_itemType == ScrollBar) + initStyleOption(); + } + return QQuickItem::event(ev); +} + +void KQuickStyleItem::setTextureWidth(int w) +{ + if (m_textureWidth == w) + return; + m_textureWidth = w; + emit textureWidthChanged(m_textureWidth); + update(); +} + +void KQuickStyleItem::setTextureHeight(int h) +{ + if (m_textureHeight == h) + return; + m_textureHeight = h; + emit textureHeightChanged(m_textureHeight); + update(); +} + +QQuickItem *KQuickStyleItem::control() const +{ + return m_control; +} + +void KQuickStyleItem::setControl(QQuickItem *control) +{ + if (control == m_control) { + return; + } + + if (m_control) { + m_control->removeEventFilter(this); + } + + m_control = control; + m_control->installEventFilter(this); + + emit controlChanged(); +} + +QSGNode *KQuickStyleItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + if (m_image.isNull()) { + delete node; + return 0; + } + + QSGNinePatchNode *styleNode = static_cast(node); + if (!styleNode) +#if QT_VERSION >= QT_VERSION_CHECK(5,8,0) + styleNode = window()->createNinePatchNode(); +#else + styleNode = new QSGDefaultNinePatchNode; +#endif + +#ifdef QSG_RUNTIME_DESCRIPTION + qsgnode_set_description(styleNode, + QString::fromLatin1("%1:%2, '%3'") + .arg(style()) + .arg(elementType()) + .arg(text())); +#endif + + styleNode->setTexture(window()->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas)); + styleNode->setBounds(boundingRect()); + styleNode->setDevicePixelRatio(window()->devicePixelRatio()); + styleNode->setPadding(m_border.left(), m_border.top(), m_border.right(), m_border.bottom()); + styleNode->update(); + + return styleNode; +} + +void KQuickStyleItem::updatePolish() +{ + if (width() >= 1 && height() >= 1) { // Note these are reals so 1 pixel is minimum + float devicePixelRatio = window() ? window()->devicePixelRatio() : qApp->devicePixelRatio(); + int w = m_textureWidth > 0 ? m_textureWidth : width(); + int h = m_textureHeight > 0 ? m_textureHeight : height(); + m_image = QImage(w * devicePixelRatio, h * devicePixelRatio, QImage::Format_ARGB32_Premultiplied); + m_image.setDevicePixelRatio(devicePixelRatio); + m_image.fill(Qt::transparent); + QPainter painter(&m_image); + painter.setLayoutDirection(qApp->layoutDirection()); + paint(&painter); + QQuickItem::update(); + } else if (!m_image.isNull()) { + m_image = QImage(); + QQuickItem::update(); + } +} + +bool KQuickStyleItem::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) { + QFocusEvent *fe = static_cast(event); + m_lastFocusReason = fe->reason(); + } + + return QQuickItem::eventFilter(watched, event); +} + +QPixmap QQuickTableRowImageProvider1::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + Q_UNUSED (requestedSize); + int width = 16; + int height = 16; + if (size) + *size = QSize(width, height); + + QPixmap pixmap(width, height); + + QStyleOptionViewItem opt; + opt.state |= QStyle::State_Enabled; + opt.rect = QRect(0, 0, width, height); + QString style = qApp->style()->metaObject()->className(); + opt.features = 0; + + if (id.contains(QLatin1String("selected"))) + opt.state |= QStyle::State_Selected; + + if (id.contains(QLatin1String("active"))) { + opt.state |= QStyle::State_Active; + opt.palette.setCurrentColorGroup(QPalette::Active); + } else + opt.palette.setCurrentColorGroup(QPalette::Inactive); + + if (id.contains(QLatin1String("alternate"))) + opt.features |= QStyleOptionViewItem::Alternate; + + QPalette pal = QApplication::palette("QAbstractItemView"); + if (opt.state & QStyle::State_Selected && (style.contains(QLatin1String("Mac")) || + !qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected))) { + pal.setCurrentColorGroup(opt.palette.currentColorGroup()); + pixmap.fill(pal.highlight().color()); + } else { + pixmap.fill(pal.base().color()); + QPainter pixpainter(&pixmap); + qApp->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, &pixpainter); + } + return pixmap; +} + +#include "moc_kquickstyleitem_p.cpp" +#include "moc_kquickpadding_p.cpp" diff --git a/plugin/kquickstyleitem_p.h b/plugin/kquickstyleitem_p.h new file mode 100644 --- /dev/null +++ b/plugin/kquickstyleitem_p.h @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** Copyright 2017 by Marco Martin +** Copyright 2017 by David Edmundson +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef KQUICKSTYLEITEM_P_H +#define KQUICKSTYLEITEM_P_H + +#include +#include +#include +#include "kquickpadding_p.h" +#include + +class QWidget; +class QStyleOption; + +class QQuickTableRowImageProvider1 : public QQuickImageProvider +{ +public: + QQuickTableRowImageProvider1() + : QQuickImageProvider(QQuickImageProvider::Pixmap) {} + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); +}; + +class KQuickStyleItem: public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(KQuickPadding* border READ border CONSTANT) + + Q_PROPERTY( bool sunken READ sunken WRITE setSunken NOTIFY sunkenChanged) + Q_PROPERTY( bool raised READ raised WRITE setRaised NOTIFY raisedChanged) + Q_PROPERTY( bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY( bool selected READ selected WRITE setSelected NOTIFY selectedChanged) + Q_PROPERTY( bool hasFocus READ hasFocus WRITE sethasFocus NOTIFY hasFocusChanged) + Q_PROPERTY( bool on READ on WRITE setOn NOTIFY onChanged) + Q_PROPERTY( bool hover READ hover WRITE setHover NOTIFY hoverChanged) + Q_PROPERTY( bool horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged) + Q_PROPERTY( bool isTransient READ isTransient WRITE setTransient NOTIFY transientChanged) + + Q_PROPERTY( QString elementType READ elementType WRITE setElementType NOTIFY elementTypeChanged) + Q_PROPERTY( QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY( QString activeControl READ activeControl WRITE setActiveControl NOTIFY activeControlChanged) + Q_PROPERTY( QString style READ style NOTIFY styleChanged) + Q_PROPERTY( QVariantMap hints READ hints WRITE setHints NOTIFY hintChanged RESET resetHints) + Q_PROPERTY( QVariantMap properties READ properties WRITE setProperties NOTIFY propertiesChanged) + Q_PROPERTY( QFont font READ font NOTIFY fontChanged) + + // For range controls + Q_PROPERTY( int minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY( int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY( int value READ value WRITE setValue NOTIFY valueChanged) + Q_PROPERTY( int step READ step WRITE setStep NOTIFY stepChanged) + Q_PROPERTY( int paintMargins READ paintMargins WRITE setPaintMargins NOTIFY paintMarginsChanged) + + Q_PROPERTY( int contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged) + Q_PROPERTY( int contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged) + + Q_PROPERTY( int textureWidth READ textureWidth WRITE setTextureWidth NOTIFY textureWidthChanged) + Q_PROPERTY( int textureHeight READ textureHeight WRITE setTextureHeight NOTIFY textureHeightChanged) + + Q_PROPERTY( QQuickItem *control READ control WRITE setControl NOTIFY controlChanged) + + KQuickPadding* border() { return &m_border; } + +public: + KQuickStyleItem(QQuickItem *parent = 0); + ~KQuickStyleItem(); + + enum MenuItemType { + SeparatorType = 0, + ItemType, + MenuType, + ScrollIndicatorType + }; + + enum Type { + Undefined, + Button, + RadioButton, + CheckBox, + ComboBox, + ComboBoxItem, + Dial, + ToolBar, + ToolButton, + Tab, + TabFrame, + Frame, + FocusFrame, + FocusRect, + SpinBox, + Slider, + ScrollBar, + ProgressBar, + Edit, + GroupBox, + Header, + Item, + ItemRow, + ItemBranchIndicator, + Splitter, + Menu, + MenuItem, + Widget, + StatusBar, + ScrollAreaCorner, + MacHelpButton, + MenuBar, + MenuBarItem + }; + + void paint(QPainter *); + + bool sunken() const { return m_sunken; } + bool raised() const { return m_raised; } + bool active() const { return m_active; } + bool selected() const { return m_selected; } + bool hasFocus() const { return m_focus; } + bool on() const { return m_on; } + bool hover() const { return m_hover; } + bool horizontal() const { return m_horizontal; } + bool isTransient() const { return m_transient; } + + int minimum() const { return m_minimum; } + int maximum() const { return m_maximum; } + int step() const { return m_step; } + int value() const { return m_value; } + int paintMargins() const { return m_paintMargins; } + + QString elementType() const { return m_type; } + QString text() const { return m_text; } + QString activeControl() const { return m_activeControl; } + QVariantMap hints() const { return m_hints; } + QVariantMap properties() const { return m_properties; } + QFont font() const { return m_font;} + QString style() const; + + void setSunken(bool sunken) { if (m_sunken != sunken) {m_sunken = sunken; emit sunkenChanged();}} + void setRaised(bool raised) { if (m_raised!= raised) {m_raised = raised; emit raisedChanged();}} + void setActive(bool active) { if (m_active!= active) {m_active = active; emit activeChanged();}} + void setSelected(bool selected) { if (m_selected!= selected) {m_selected = selected; emit selectedChanged();}} + void sethasFocus(bool focus) { if (m_focus != focus) {m_focus = focus; emit hasFocusChanged();}} + void setOn(bool on) { if (m_on != on) {m_on = on ; emit onChanged();}} + void setHover(bool hover) { if (m_hover != hover) {m_hover = hover ; emit hoverChanged();}} + void setHorizontal(bool horizontal) { if (m_horizontal != horizontal) {m_horizontal = horizontal; emit horizontalChanged();}} + void setTransient(bool transient) { if (m_transient != transient) {m_transient = transient; emit transientChanged();}} + void setMinimum(int minimum) { if (m_minimum!= minimum) {m_minimum = minimum; emit minimumChanged();}} + void setMaximum(int maximum) { if (m_maximum != maximum) {m_maximum = maximum; emit maximumChanged();}} + void setValue(int value) { if (m_value!= value) {m_value = value; emit valueChanged();}} + void setStep(int step) { if (m_step != step) { m_step = step; emit stepChanged(); }} + void setPaintMargins(int value) { if (m_paintMargins!= value) {m_paintMargins = value; emit paintMarginsChanged(); } } + void setElementType(const QString &str); + void setText(const QString &str) { if (m_text != str) {m_text = str; emit textChanged();}} + void setActiveControl(const QString &str) { if (m_activeControl != str) {m_activeControl = str; emit activeControlChanged();}} + void setHints(const QVariantMap &str); + void setProperties(const QVariantMap &props) { if (m_properties != props) { m_properties = props; emit propertiesChanged(); } } + void resetHints(); + + int contentWidth() const { return m_contentWidth; } + void setContentWidth(int arg); + + int contentHeight() const { return m_contentHeight; } + void setContentHeight(int arg); + + virtual void initStyleOption (); + void resolvePalette(); + + Q_INVOKABLE qreal textWidth(const QString &); + Q_INVOKABLE qreal textHeight(const QString &); + + int textureWidth() const { return m_textureWidth; } + void setTextureWidth(int w); + + int textureHeight() const { return m_textureHeight; } + void setTextureHeight(int h); + + QQuickItem *control() const; + void setControl(QQuickItem *control); + +public Q_SLOTS: + int pixelMetric(const QString&); + QVariant styleHint(const QString&); + void updateSizeHint(); + void updateRect(); + void updateBaselineOffset(); + void updateItem(){polish();} + QString hitTest(int x, int y); + QRectF subControlRect(const QString &subcontrolString); + QString elidedText(const QString &text, int elideMode, int width); + bool hasThemeIcon(const QString &) const; + +Q_SIGNALS: + void elementTypeChanged(); + void textChanged(); + void sunkenChanged(); + void raisedChanged(); + void activeChanged(); + void selectedChanged(); + void hasFocusChanged(); + void onChanged(); + void hoverChanged(); + void horizontalChanged(); + void transientChanged(); + void minimumChanged(); + void maximumChanged(); + void stepChanged(); + void valueChanged(); + void activeControlChanged(); + void infoChanged(); + void styleChanged(); + void paintMarginsChanged(); + void hintChanged(); + void propertiesChanged(); + void fontChanged(); + void controlChanged(); + + void contentWidthChanged(int arg); + void contentHeightChanged(int arg); + + void textureWidthChanged(int w); + void textureHeightChanged(int h); + +protected: + virtual bool event(QEvent *); + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + virtual void updatePolish(); + bool eventFilter(QObject *watched, QEvent *event) override; + +private: + const char* classNameForItem() const; + QSize sizeFromContents(int width, int height); + qreal baselineOffset(); + +protected: + QStyleOption *m_styleoption; + QPointer m_control; + Type m_itemType; + + QString m_type; + QString m_text; + QString m_activeControl; + QVariantMap m_hints; + QVariantMap m_properties; + QFont m_font; + + bool m_sunken; + bool m_raised; + bool m_active; + bool m_selected; + bool m_focus; + bool m_hover; + bool m_on; + bool m_horizontal; + bool m_transient; + bool m_sharedWidget; + + int m_minimum; + int m_maximum; + int m_value; + int m_step; + int m_paintMargins; + + int m_contentWidth; + int m_contentHeight; + + int m_textureWidth; + int m_textureHeight; + + Qt::FocusReason m_lastFocusReason; + + QImage m_image; + KQuickPadding m_border; +}; + + +#endif // QQUICKSTYLEITEM_P_H diff --git a/plugin/qmldir b/plugin/qmldir new file mode 100644 --- /dev/null +++ b/plugin/qmldir @@ -0,0 +1,5 @@ +module org.kde.qqc2desktopstyle.private +plugin qqc2desktopstyleplugin + +singleton SystemPaletteSingleton 1.0 SystemPaletteSingleton.qml +singleton TextSingleton 1.0 TextSingleton.qml diff --git a/plugin/qqc2desktopstyleplugin.h b/plugin/qqc2desktopstyleplugin.h new file mode 100644 --- /dev/null +++ b/plugin/qqc2desktopstyleplugin.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 by Marco Martin + * Copyright 2017 by David Edmundson + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details + * + * You should have received a copy of the GNU Library 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. + */ + +#ifndef QQC2DESKTOPSTYLEPLUGIN_H +#define QQC2DESKTOPSTYLEPLUGIN_H + +#include + + +class QQc2DesktopStylePlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri); +}; + +#endif + diff --git a/plugin/qqc2desktopstyleplugin.cpp b/plugin/qqc2desktopstyleplugin.cpp new file mode 100644 --- /dev/null +++ b/plugin/qqc2desktopstyleplugin.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2017 by Marco Martin + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details + * + * You should have received a copy of the GNU Library 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. + */ + +#include "qqc2desktopstyleplugin.h" +#include "kquickstyleitem_p.h" + +#include +#include +#include + + +void QQc2DesktopStylePlugin::registerTypes(const char *uri) +{ + Q_ASSERT(uri == QLatin1String("org.kde.qqc2desktopstyle.private")); + + qmlRegisterType(uri, 1, 0, "StyleItem"); + + qmlProtectModule(uri, 2); +} + +#include "moc_qqc2desktopstyleplugin.cpp" + diff --git a/plugin/qsgdefaultninepatchnode.cpp b/plugin/qsgdefaultninepatchnode.cpp new file mode 100644 --- /dev/null +++ b/plugin/qsgdefaultninepatchnode.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultninepatchnode_p.h" + +QT_BEGIN_NAMESPACE + +QSGDefaultNinePatchNode::QSGDefaultNinePatchNode() + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) +{ + setGeometry(&m_geometry); + setMaterial(&m_material); +} + +QSGDefaultNinePatchNode::~QSGDefaultNinePatchNode() +{ + delete m_material.texture(); +} + +void QSGDefaultNinePatchNode::setTexture(QSGTexture *texture) +{ + delete m_material.texture(); + m_material.setTexture(texture); +} + +void QSGDefaultNinePatchNode::setBounds(const QRectF &bounds) +{ + m_bounds = bounds; +} + +void QSGDefaultNinePatchNode::setDevicePixelRatio(qreal ratio) +{ + m_devicePixelRatio = ratio; +} + +void QSGDefaultNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom) +{ + m_padding = QVector4D(left, top, right, bottom); +} + +void QSGDefaultNinePatchNode::update() +{ + rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio); + markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); +} + +QT_END_NAMESPACE + diff --git a/plugin/qsgdefaultninepatchnode_p.h b/plugin/qsgdefaultninepatchnode_p.h new file mode 100644 --- /dev/null +++ b/plugin/qsgdefaultninepatchnode_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTNINEPATCHNODE_P_H +#define QSGDEFAULTNINEPATCHNODE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +//#include +#include "qsgninepatchnode.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QSGDefaultNinePatchNode : public QSGNinePatchNode +{ +public: + QSGDefaultNinePatchNode(); + ~QSGDefaultNinePatchNode(); + + void setTexture(QSGTexture *texture) override; + void setBounds(const QRectF &bounds) override; + void setDevicePixelRatio(qreal ratio) override; + void setPadding(qreal left, qreal top, qreal right, qreal bottom) override; + void update() override; + +private: + QRectF m_bounds; + qreal m_devicePixelRatio; + QVector4D m_padding; + QSGGeometry m_geometry; + QSGTextureMaterial m_material; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTNINEPATCHNODE_P_H diff --git a/plugin/qsgninepatchnode.h b/plugin/qsgninepatchnode.h new file mode 100644 --- /dev/null +++ b/plugin/qsgninepatchnode.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGNINEPATCHNODE_H +#define QSGNINEPATCHNODE_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGNinePatchNode : public QSGGeometryNode +{ +public: + virtual ~QSGNinePatchNode() { } + + virtual void setTexture(QSGTexture *texture) = 0; + virtual void setBounds(const QRectF &bounds) = 0; + virtual void setDevicePixelRatio(qreal ratio) = 0; + virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0; + virtual void update() = 0; + + static void rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, + const QVector4D &padding, + const QRectF &bounds, qreal dpr); +}; + +QT_END_NAMESPACE + +#endif // QSGNINEPATCHNODE_H diff --git a/plugin/qsgninepatchnode.cpp b/plugin/qsgninepatchnode.cpp new file mode 100644 --- /dev/null +++ b/plugin/qsgninepatchnode.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgninepatchnode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGNinePatchNode + \inmodule QtQuick + \since 5.8 + \internal + */ + +/*! + \fn void QSGNinePatchNode::setTexture(QSGTexture *texture) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setBounds(const QRectF &bounds) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setDevicePixelRatio(qreal ratio) + \internal + */ + +/*! + \fn void QSGNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom) + \internal + */ + + +/*! + \fn void QSGNinePatchNode::update() + \internal + */ + +void QSGNinePatchNode::rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, + const QRectF &bounds, qreal dpr) +{ + if (padding.x() <= 0 && padding.y() <= 0 && padding.z() <= 0 && padding.w() <= 0) { + geometry->allocate(4, 0); + QSGGeometry::updateTexturedRectGeometry(geometry, bounds, texture->normalizedTextureSubRect()); + return; + } + + QRectF tc = texture->normalizedTextureSubRect(); + QSize ts = texture->textureSize(); + ts.setHeight(ts.height() / dpr); + ts.setWidth(ts.width() / dpr); + + qreal invtw = tc.width() / ts.width(); + qreal invth = tc.height() / ts.height(); + + struct Coord { qreal p; qreal t; }; + Coord cx[4] = { { bounds.left(), tc.left() }, + { bounds.left() + padding.x(), tc.left() + padding.x() * invtw }, + { bounds.right() - padding.z(), tc.right() - padding.z() * invtw }, + { bounds.right(), tc.right() } + }; + Coord cy[4] = { { bounds.top(), tc.top() }, + { bounds.top() + padding.y(), tc.top() + padding.y() * invth }, + { bounds.bottom() - padding.w(), tc.bottom() - padding.w() * invth }, + { bounds.bottom(), tc.bottom() } + }; + + geometry->allocate(16, 28); + QSGGeometry::TexturedPoint2D *v = geometry->vertexDataAsTexturedPoint2D(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + v->set(cx[x].p, cy[y].p, cx[x].t, cy[y].t); + ++v; + } + } + + quint16 *i = geometry->indexDataAsUShort(); + for (int r = 0; r < 3; ++r) { + if (r > 0) + *i++ = 4 * r; + for (int c = 0; c < 4; ++c) { + i[0] = 4 * r + c; + i[1] = 4 * r + c + 4; + i += 2; + } + if (r < 2) + *i++ = 4 * r + 3 + 4; + } +} + +QT_END_NAMESPACE