diff options
Diffstat (limited to 'src/qtdesktop')
70 files changed, 10971 insertions, 0 deletions
diff --git a/src/qtdesktop/ApplicationWindow.qml b/src/qtdesktop/ApplicationWindow.qml new file mode 100644 index 00000000..fe35b6c8 --- /dev/null +++ b/src/qtdesktop/ApplicationWindow.qml @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +Window { + id: root + width: 320 + height: 240 + + property MenuBar menuBar + property alias toolBar: toolBarArea.data + property alias statusBar: statusBarArea.data + default property alias data: contentArea.data + property alias backgroundColor: syspal.window + property bool showMenuBar: menuBar ? menuBar.showMenuBar : false + + SystemPalette {id: syspal} + + Rectangle { + anchors.fill: parent + color: backgroundColor + } + + StyleItem { + id: menuBarArea + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + elementType: "menubar" + visible: showMenuBar + contentHeight: showMenuBar ? 20 : 0 + Row { + id: row + anchors.fill: parent + Repeater { + model: showMenuBar ? menuBar.menuList.length : 0 + StyleItem { + id: menuItem + elementType: "menubaritem" + contentWidth: 100 + contentHeight: 20 + width: text.paintedWidth + 12 + height :text.paintedHeight + 4 + sunken: true + selected: mouse.pressed + property var menu: menuBar.menuList[index] + Text { + id: text + text: menu.text + anchors.centerIn: parent + renderType: Text.NativeRendering + } + MouseArea { + id: mouse + anchors.fill:parent + onPressed: menu.showPopup(menuItem.x, menuBarArea.height, 0, root) + } + } + } + } + } + + Row { + id: toolBarArea + anchors.top: menuBarArea.bottom + anchors.left: parent.left + anchors.right: parent.right + } + + Item { + id: contentArea + anchors.top: toolBarArea.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: statusBarArea.top + } + + Row { + id: statusBarArea + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + } +} diff --git a/src/qtdesktop/Button.qml b/src/qtdesktop/Button.qml new file mode 100644 index 00000000..b82e0ebd --- /dev/null +++ b/src/qtdesktop/Button.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "private" +import "Styles/Settings.js" as Settings + +BasicButton { + id: button + + property bool defaultbutton: false + property var styleHintss + property string text + property url iconSource + + Accessible.name: text + + style: Qt.createComponent(Settings.THEME_PATH + "/ButtonStyle.qml") + +// ## TODO: move to style implementation +// label: Item { +// // Used as a fallback since I can't pass the imageURL +// // directly to the style object +// visible: button.iconSource === "" +// Row { +// id: row +// anchors.centerIn: parent +// spacing: 4 +// Image { +// source: iconSource +// anchors.verticalCenter: parent.verticalCenter +// fillMode: Image.Stretch //mm Image should shrink if button is too small, depends on QTBUG-14957 +// } +// Text { +// id:text +// color: textColor +// anchors.verticalCenter: parent.verticalCenter +// text: button.text +// horizontalAlignment: Text.Center +// } +// } +// } +} + diff --git a/src/qtdesktop/ButtonColumn.qml b/src/qtdesktop/ButtonColumn.qml new file mode 100644 index 00000000..50410a32 --- /dev/null +++ b/src/qtdesktop/ButtonColumn.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "private/ButtonGroup.js" as Behavior + +/* + Class: ButtonColumn + A ButtonColumn allows you to group Buttons in a column. It provides a selection-behavior as well. + + Note: This component don't support the enabled property. + If you need to disable it you should disable all the buttons inside it. + + <code> + ButtonColumn { + Button { text: "Top" } + Button { text: "Bottom" } + } + </code> +*/ +Column { + id: root + + /* + * Property: exclusive + * [bool=true] Specifies the grouping behavior. If enabled, the checked property on buttons contained + * in the group will be exclusive. + * + * Note that a button in an exclusive group will allways be checkable + */ + property bool exclusive: true + + /* + * Property: styleHints + * [string] Used to indicate special OS specific button types + */ + property var styleHints:[] + + /* + * Property: checkedButton + * [string] Contains the last checked Button. + */ + property Item checkedButton; + + Component.onCompleted: { + Behavior.create(root, {direction: Qt.Vertical}); + } + + Component.onDestruction: { + Behavior.destroy(); + } + +} diff --git a/src/qtdesktop/ButtonRow.qml b/src/qtdesktop/ButtonRow.qml new file mode 100644 index 00000000..9c3c2c16 --- /dev/null +++ b/src/qtdesktop/ButtonRow.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "private/ButtonGroup.js" as Behavior + +/* + Class: ButtonRow + A ButtonRow allows you to group Buttons in a row. It provides a selection-behavior as well. + + Note: This component don't support the enabled property. + If you need to disable it you should disable all the buttons inside it. + + <code> + ButtonRow { + Button { text: "Left" } + Button { text: "Right" } + } + </code> +*/ +Row { + id: root + + /* + * Property: exclusive + * [bool=false] Specifies the grouping behavior. If enabled, the checked property on buttons contained + * in the group will be exclusive. + * + * Note that a button in an exclusive group will allways be checkable + */ + property bool exclusive: false + + /* + * Property: styleHints + * [string] Used to indicate special OS specific button types + */ + property var styleHints + /* + * Property: checkedButton + * [string] Contains the last checked Button. + */ + property Item checkedButton; + + Component.onCompleted: { + Behavior.create(root, {direction: Qt.Horizontal}); + } + + Component.onDestruction: { + Behavior.destroy(); + } +} diff --git a/src/qtdesktop/CheckBox.qml b/src/qtdesktop/CheckBox.qml new file mode 100644 index 00000000..88f19869 --- /dev/null +++ b/src/qtdesktop/CheckBox.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings +import "private" + + +FocusScope { + id: checkBox + + signal clicked + + property alias pressed: behavior.effectivePressed + property alias checked: behavior.checked + property alias containsMouse: behavior.containsMouse + property bool activeFocusOnPress: false + + property string text + property var styleHints:[] + + // implementation + Accessible.role: Accessible.CheckBox + Accessible.name: text + + implicitWidth: Math.max(120, loader.item ? loader.item.implicitWidth : 0) + implicitHeight: loader.item ? loader.item.implicitHeight : 0 + + property Component style: Qt.createComponent(Settings.THEME_PATH + "/CheckBoxStyle.qml") + + Loader { + id: loader + anchors.fill: parent + property alias control: checkBox + sourceComponent: style + } + + ButtonBehavior { + id: behavior + focus: true + anchors.fill: parent + checkable: true + onClicked: checkBox.clicked(); + onPressed: if (checkBox.activeFocusOnPress) checkBox.forceActiveFocus(); + } + + Keys.onPressed: { + if (event.key == Qt.Key_Space && !event.isAutoRepeat && !behavior.pressed) + behavior.keyPressed = true; + } + + Keys.onReleased: { + if (event.key == Qt.Key_Space && !event.isAutoRepeat && behavior.keyPressed) { + behavior.keyPressed = false; + checked = !checked; + checkBox.clicked(); + } + } +} diff --git a/src/qtdesktop/ComboBox.qml b/src/qtdesktop/ComboBox.qml new file mode 100644 index 00000000..2b50880f --- /dev/null +++ b/src/qtdesktop/ComboBox.qml @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "private" as Private +import "Styles/Settings.js" as Settings + +/* +* +* ComboBox (inherits BasicButton) +* +* The ComboBox component is a combined button and popup list. The popup menu itself is platform +* native, and cannot by styled from QML code. +* Add menu items to the comboBox by either adding MenuItem children inside the popup, or +* assign it a ListModel (or both). +* +* The ComboBox contains the following API (in addition to the BasicButton API): +* +* ListModel model - this model will be used, in addition to MenuItem children, to +* create items inside the popup menu +* bool popupOpen - setting this property to 'true' will open the popup. +* int selectedIndex - the index of the selected item in the popup menu. +* int hoveredIndex - the index of the highlighted item in the popup menu. +* string selectedText - the text of the selected menu item. +* string hoveredText - the text of the highlighted menu item. +* +* Example 1: +* +* ListModel { +* id: menuItems +* ListElement { text: "Banana"; color: "Yellow" } +* ListElement { text: "Apple"; color: "Green" } +* ListElement { text: "Coconut"; color: "Brown" } +* } +* ComboBox { +* model: menuItems +* width: 200 +* onSelectedIndexChanged: console.debug(selectedText + ", " + menuItems.get(selectedIndex).color) +* } +* +* Example 2: +* +* ComboBox { +* width: 200 +* MenuItem { +* text: "Pineapple" +* onSelected: console.debug(text) +* +* } +* MenuItem { +* text: "Grape" +* onSelected: console.debug(text) +* } +* } +* +*/ + +Private.BasicButton { + id: comboBox + + default property alias menuItems: popup.menuItems + property alias model: popup.model + property alias popupOpen: popup.visible + + property alias selectedIndex: popup.selectedIndex + property alias hoveredIndex: popup.hoveredIndex + property alias selectedText: popup.selectedText + property alias hoveredText: popup.hoveredText + property var styleHints:[] + + style: Qt.createComponent(Settings.THEME_PATH + "/ComboBoxStyle.qml") + +// ToDo: adjust margins so that selected popup label +// centers directly above button label when +// popup.centerOnSelectedText === true + + width: implicitWidth + height: implicitHeight + onWidthChanged: popup.setMinimumWidth(width) + checkable: false + onPressedChanged: if (pressed) popup.visible = true + + ContextMenu { + id: popup + property bool center: false + centerSelectedText: center + y: center ? 0 : comboBox.height + } + + // The key bindings below will only be in use when popup is + // not visible. Otherwise, native popup key handling will take place: + Keys.onSpacePressed: { comboBox.popupOpen = !comboBox.popupOpen } + Keys.onUpPressed: { if (selectedIndex < model.count - 1) selectedIndex++ } + Keys.onDownPressed: { if (selectedIndex > 0) selectedIndex-- } +} diff --git a/src/qtdesktop/ContextMenu.qml b/src/qtdesktop/ContextMenu.qml new file mode 100644 index 00000000..0ba2a920 --- /dev/null +++ b/src/qtdesktop/ContextMenu.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +Menu { + id: root + property string selectedText: itemTextAt(selectedIndex) + property string hoveredText: itemTextAt(hoveredIndex) + property string textRole + + // 'centerSelectedText' means that the menu will be positioned + // so that the selected text' top left corner will be at x, y. + property bool centerSelectedText: true + + visible: false + onMenuClosed: visible = false + onModelChanged: if (Component.status === Component.Ready && model !== undefined) rebuildMenu() + + Component.onCompleted: if (model !== undefined) rebuildMenu() + + onHoveredIndexChanged: { + if (hoveredIndex < menuItems.length) + menuItems[hoveredIndex].hovered() + } + + onSelectedIndexChanged: { + if (hoveredIndex < menuItems.length) + menuItems[hoveredIndex].selected() + } + + onVisibleChanged: { + if (visible) { + var globalPos = mapToItem(null, x, y) + showPopup(globalPos.x, globalPos.y, centerSelectedText ? selectedIndex : 0) + } else { + hidePopup() + } + } + + function rebuildMenu() + { + clearMenuItems(); + + for (var i=0; i<menuItems.length; ++i) + addMenuItem(menuItems[i].text) + + var nativeModel = root.hasNativeModel() + + if (model !== undefined) { + var modelCount = nativeModel ? root.modelCount() : model.count; + for (var j = 0 ; j < modelCount; ++j) { + var textValue + if (nativeModel) { + textValue = root.modelTextAt(j); + } else { + if (textRole !== "") + textValue = model.get(j)[textRole] + else if (model.count > 0 && root.model.get && root.model.get(0)) { + // ListModel with one role + var listElement = root.model.get(0) + var oneRole = true + var roleName = "" + var roleCount = 0 + for (var role in listElement) { + if (!roleName || role === "text") + roleName = role + ++roleCount + } + if (roleCount > 1 && roleName !== "text") { + oneRole = false + console.log("Warning: No textRole set for ComboBox.") + break + } + + if (oneRole) { + root.textRole = roleName + textValue = root.model.get(j)[textRole] + } + } + } + addMenuItem(textValue) + } + } + } +} diff --git a/src/qtdesktop/Dial.qml b/src/qtdesktop/Dial.qml new file mode 100644 index 00000000..e235963d --- /dev/null +++ b/src/qtdesktop/Dial.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +// jens: ContainsMouse breaks drag functionality + +Item { + id: dial + + width: 100 + height: 100 + + property alias maximumValue: range.maximumValue + property alias minimumValue: range.minimumValue + property alias containsMouse: mouseArea.containsMouse + property alias value: range.value + property alias stepSize: range.stepSize + + property bool wrapping: false + property bool tickmarksEnabled: false + property bool activeFocusOnPress: false + + Accessible.role: Accessible.Dial + Accessible.name: value + + RangeModel { + id: range + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.0 + value: 0 + } + + MouseArea { + id: mouseArea + anchors.fill:parent + property bool inDrag + hoverEnabled:true + + onPositionChanged: { + if (pressed) { + value = valueFromPoint(mouseX, mouseY) + inDrag = true + } + } + onPressed: { + value = valueFromPoint(mouseX, mouseY) + if (activeFocusOnPress) dial.focus = true + } + + onReleased:inDrag = false; + function bound(val) { return Math.max(minimumValue, Math.min(maximumValue, val)); } + + function valueFromPoint(x, y) + { + var yy = height/2.0 - y; + var xx = x - width/2.0; + var a = (xx || yy) ? Math.atan2(yy, xx) : 0; + + if (a < Math.PI/ -2) + a = a + Math.PI * 2; + + var dist = 0; + var minv = minimumValue*100, maxv = maximumValue*100; + + if (minimumValue < 0) { + dist = -minimumValue; + minv = 0; + maxv = maximumValue + dist; + } + + var r = maxv - minv; + var v; + if (wrapping) + v = (0.5 + minv + r * (Math.PI * 3 / 2 - a) / (2 * Math.PI)); + else + v = (0.5 + minv + r* (Math.PI * 4 / 3 - a) / (Math.PI * 10 / 6)); + + if (dist > 0) + v -= dist; + return maximumValue - bound(v/100) + } + } + StyleItem { + anchors.fill: parent + elementType: "dial" + hasFocus: dial.focus + sunken: mouseArea.pressed + maximum: range.maximumValue * 100 + minimum: range.minimumValue * 100 + value: visualPos * 100 + enabled: dial.enabled + step: range.stepSize * 100 + activeControl: tickmarksEnabled ? "tick" : "" + property double visualPos : range.value + + Behavior on visualPos { + enabled: !mouseArea.inDrag + NumberAnimation { + duration: 300 + easing.type: Easing.OutSine + } + } + } + WheelArea { + id: wheelarea + anchors.fill: parent + horizontalMinimumValue: dial.minimumValue + horizontalMaximumValue: dial.maximumValue + verticalMinimumValue: dial.minimumValue + verticalMaximumValue: dial.maximumValue + property double step: (dial.maximumValue - dial.minimumValue)/100 + + onVerticalWheelMoved: { + value += verticalDelta/4*step + } + + onHorizontalWheelMoved: { + value += horizontalDelta/4*step + } + } +} diff --git a/src/qtdesktop/Dialog.qml b/src/qtdesktop/Dialog.qml new file mode 100644 index 00000000..2cf0e9ad --- /dev/null +++ b/src/qtdesktop/Dialog.qml @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Window 2.0 + +Window { + id: dialog + + width: 400 + height: 200 + + signal closed + signal accepted + signal rejected + signal buttonClicked + + property QtObject clickedButton: null + + property int noRole: 0 + property int acceptRole: 1 + property int rejectRole: 2 + property int helpRole: 3 + + property int ok: 0x00000400 + property int cancel: 0x00400000 + property int close: 0x00200000 + property int help: 0x02000000 + + property int buttons: ok | cancel + + modal: false + + default property alias data: content.data + + Item { + id: content + anchors.topMargin:16 + anchors.margins: 16 + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: buttonrow.top + } + + // Dialogs should center on parent + onVisibleChanged: center() + + Row { + property bool mac: (style.style == "mac") + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: 16 + anchors.topMargin:0 + anchors.bottomMargin: style.isMac ? 12 : 8 + spacing: 6 + + Button { + id: helpbutton + property int role: helpRole + visible: buttons & help + text: "Help" + focus: false + Component.onCompleted: if (style.isMac) width = 22 + delegate: style.isMac ? machelpdelegate : cancelbutton.background + onClicked: { + clickedButton = helpbutton + buttonClicked() + } + Component { + id: machelpdelegate + StyleItem { + anchors.fill: parent + elementType: "machelpbutton" + width: 22 + height: 22 + sunken: helpbutton.pressed + anchors.centerIn: parent + } + } + } + } + Row { + id: buttonrow + spacing: 6 + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 16 + anchors.topMargin: 0 + anchors.bottomMargin: 8 + layoutDirection: style.isMac ? Qt.LeftToRight : Qt.RightToLeft + + Button { + id: cancelbutton + visible: buttons & cancel + property int role: rejectRole + text: "Cancel" + onClicked: { + visible: dialog.visible = false + clickedButton = cancelbutton + rejected() + closed() + buttonClicked(role) + } + } + Button { + id: okbutton + property int role: acceptRole + visible: buttons & ok + text: "OK" + defaultbutton: true + onClicked: { + visible: dialog.visible = false + clickedButton = okbutton + accepted() + closed() + buttonClicked() + } + } + } + StyleItem { + id: style + visible: false + property bool isMac: (style.style == "mac") + + } +} diff --git a/src/qtdesktop/Frame.qml b/src/qtdesktop/Frame.qml new file mode 100644 index 00000000..36627176 --- /dev/null +++ b/src/qtdesktop/Frame.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: frame + default property alias data: content.data + implicitWidth: adjustToContentSize ? content.childrenRect.width + 2 * content.frameWidth : 30 + implicitHeight: adjustToContentSize ? content.childrenRect.height + 2 * content.frameWidth : 30 + + property Component style: Qt.createComponent(Settings.THEME_PATH + "/FrameStyle.qml") + + property bool raised + property bool sunken + property bool adjustToContentSize: false + + Loader { + id: loader + anchors.fill: parent + sourceComponent: delegate + Item { + id: content + anchors.fill: parent + anchors.margins: frameWidth + property int frameWidth + } + onLoaded: item.z = -1 + } + + +} diff --git a/src/qtdesktop/GroupBox.qml b/src/qtdesktop/GroupBox.qml new file mode 100644 index 00000000..dc2e8ccf --- /dev/null +++ b/src/qtdesktop/GroupBox.qml @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: groupbox + implicitWidth: Math.max(200, contentWidth + (loader.item ? loader.item.implicitWidth: 0) ) + implicitHeight: contentHeight + (loader.item ? loader.item.implicitHeight : 0) + 4 + + default property alias data: content.data + + property string title + property bool flat: false + property bool checkable: false + property int contentWidth: content.childrenRect.width + property int contentHeight: content.childrenRect.height + + property Item checkbox: check + property alias checked: check.checked + property bool adjustToContentSize: false // Resizes groupbox to fit contents. + // Note when using this, you cannot anchor children + property Component style: Qt.createComponent(Settings.THEME_PATH + "/GroupBoxStyle.qml") + + Accessible.role: Accessible.Grouping + Accessible.name: title + + Loader { + id: loader + property alias control: groupbox + anchors.fill: parent + property int topMargin: title.length > 0 || checkable ? 22 : 4 + property int bottomMargin: 4 + property int leftMargin: 4 + property int rightMargin: 4 + sourceComponent: style + onLoaded: item.z = -1 + } + + CheckBox { + id: check + checked: true + visible: checkable + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: loader.topMargin + } + + Item { + id:content + z: 1 + focus: true + anchors.topMargin: loader.topMargin + anchors.leftMargin: 8 + anchors.rightMargin: 8 + anchors.bottomMargin: 8 + anchors.fill: parent + enabled: (!checkable || checkbox.checked) + } +} diff --git a/src/qtdesktop/Label.qml b/src/qtdesktop/Label.qml new file mode 100644 index 00000000..99d3ac71 --- /dev/null +++ b/src/qtdesktop/Label.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Text { + id: label + font.pixelSize: 11 + color: pal.text + SystemPalette {id:pal} +} diff --git a/src/qtdesktop/ProgressBar.qml b/src/qtdesktop/ProgressBar.qml new file mode 100644 index 00000000..b9b7fafb --- /dev/null +++ b/src/qtdesktop/ProgressBar.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: progressbar + + property real value: 0 + property real minimumValue: 0 + property real maximumValue: 1 + property bool indeterminate: false + property bool containsMouse: mouseArea.containsMouse + + property int minimumWidth: 0 + property int minimumHeight: 0 + + property int orientation: Qt.Horizontal + property Component style: Qt.createComponent(Settings.THEME_PATH + "/ProgressBarStyle.qml") + property var styleHints:[] + + Accessible.role: Accessible.ProgressBar + Accessible.name: value + + implicitWidth: orientation === Qt.Horizontal ? 200 : (loader.item ? loader.item.implicitHeight : 0) + implicitHeight: orientation === Qt.Horizontal ? (loader.item ? loader.item.implicitHeight : 0) : 200 + + Loader { + id: loader + property alias indeterminate: progressbar.indeterminate + property alias value: progressbar.value + property alias maximumValue: progressbar.maximumValue + property alias minimumValue: progressbar.minimumValue + + property alias control: progressbar + sourceComponent: style + anchors.fill: parent + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } +} + diff --git a/src/qtdesktop/RadioButton.qml b/src/qtdesktop/RadioButton.qml new file mode 100644 index 00000000..f5945535 --- /dev/null +++ b/src/qtdesktop/RadioButton.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +// jb : Size should not depend on background, we should make it consistent + +CheckBox { + id: radiobutton + + Accessible.role: Accessible.RadioButton + + style: Qt.createComponent(Settings.THEME_PATH + "/RadioButtonStyle.qml") +} diff --git a/src/qtdesktop/ScrollArea.qml b/src/qtdesktop/ScrollArea.qml new file mode 100644 index 00000000..9415797a --- /dev/null +++ b/src/qtdesktop/ScrollArea.qml @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "private" as Private + +FocusScope { + id: root + width: 100 + height: 100 + + // Cosmetic propeties + property bool frame: true + property bool frameAroundContents: true + property bool highlightOnFocus: false + property alias color: colorRect.color // background color + property int frameWidth: frame ? styleitem.frameWidth : 0 + + // Item properties + property alias horizontalScrollBar: scroller.horizontalScrollBar + property alias verticalScrollBar: scroller.verticalScrollBar + + // Viewport properties + property int contentX + property int contentY + property int contentHeight : content.childrenRect.height + property int contentWidth: content.childrenRect.width + property int viewportHeight: height - (horizontalScrollBar.visible ? verticalScrollBar.height : 0) - 2 * frameWidth + property int viewportWidth: width - (verticalScrollBar.visible ? verticalScrollBar.width : 0) - 2 * frameWidth + default property alias data: content.data + + Rectangle { + id: colorRect + color: "transparent" + anchors.fill:styleitem + anchors.margins: frameWidth + } + + StyleItem { + id: styleitem + elementType: "frame" + sunken: true + visible: frame + anchors.fill: parent + anchors.rightMargin: frame ? (frameAroundContents ? (verticalScrollBar.visible ? verticalScrollBar.width + 2 * frameMargins : 0) : 0) : 0 + anchors.bottomMargin: frame ? (frameAroundContents ? (horizontalScrollBar.visible ? horizontalScrollBar.height + 2 * frameMargins : 0) : 0) : 0 + anchors.topMargin: frame ? (frameAroundContents ? 0 : 0) : 0 + property int frameWidth + property int scrollbarspacing: styleitem.pixelMetric("scrollbarspacing"); + property int frameMargins : frame ? scrollbarspacing : 0 + Component.onCompleted: { + frameWidth = styleitem.pixelMetric("defaultframewidth"); + frameAroundContents = styleitem.styleHint("framearoundcontents") + } + } + + onContentYChanged: { + scroller.blockUpdates = true + verticalScrollBar.value = contentY + scroller.verticalValue = contentY + scroller.blockUpdates = false + } + + onContentXChanged: { + scroller.blockUpdates = true + horizontalScrollBar.value = contentX + scroller.horizontalValue = contentX + scroller.blockUpdates = false + } + + Item { + id: clipper + anchors.fill: styleitem + anchors.margins: frameWidth + clip: true + Item { + id: content + x: -root.contentX + y: -root.contentY + } + } + + + Private.ScrollAreaHelper { + id: scroller + anchors.fill: parent + } + + StyleItem { + z: 2 + anchors.fill: parent + + anchors.topMargin: -3 + anchors.leftMargin: -3 + anchors.rightMargin: -5 + anchors.bottomMargin: -5 + + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + elementType: "focusframe" + } +} diff --git a/src/qtdesktop/ScrollBar.qml b/src/qtdesktop/ScrollBar.qml new file mode 100644 index 00000000..5e20190c --- /dev/null +++ b/src/qtdesktop/ScrollBar.qml @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: scrollbar + + property int orientation: Qt.Horizontal + property alias minimumValue: slider.minimumValue + property alias maximumValue: slider.maximumValue + property int pageStep: internal.horizontal ? width : height + property int singleStep: 20 + property alias value: slider.value + property bool scrollToClickposition: internal.scrollToClickPosition + + implicitWidth: loader.implicitWidth + implicitHeight: loader.implicitHeight + + onValueChanged: internal.updateHandle() + + property Component style: Qt.createComponent(Settings.THEME_PATH + "/ScrollBarStyle.qml") + + property bool upPressed + property bool downPressed + + property bool pageUpPressed + property bool pageDownPressed + + MouseArea { + id: internal + + property bool horizontal: orientation === Qt.Horizontal + property alias styleItem: loader.item + + anchors.fill: parent + + property bool autoincrement: false + property bool scrollToClickPosition: styleItem ? styleItem.scrollToClickPosition : 0 + property bool handlePressed + + // Update hover item + onEntered: styleItem.activeControl = styleItem.hitTest(mouseX, mouseY) + onExited: styleItem.activeControl = "none" + onMouseXChanged: styleItem.activeControl = styleItem.hitTest(mouseX, mouseY) + hoverEnabled: true + + property variant control + property variant pressedX + property variant pressedY + property int oldPosition + property int grooveSize + + Timer { + running: upPressed || downPressed || pageUpPressed || pageDownPressed + interval: 350 + onTriggered: internal.autoincrement = true + } + + Timer { + running: internal.autoincrement + interval: 60 + repeat: true + onTriggered: upPressed ? internal.decrement() : downPressed ? internal.increment() : + pageUpPressed ? internal.decrementPage() : + internal.incrementPage() + } + + onPositionChanged: { + if (pressed && control === "handle") { + //slider.positionAtMaximum = grooveSize + if (!horizontal) + slider.position = oldPosition + (mouseY - pressedY) + else + slider.position = oldPosition + (mouseX - pressedX) + } + } + + onPressed: { + control = styleItem.hitTest(mouseX, mouseY) + scrollToClickposition = scrollToClickPosition + grooveSize = horizontal ? styleItem.subControlRect("groove").width - + styleItem.subControlRect("handle").width: + styleItem.subControlRect("groove").height - + styleItem.subControlRect("handle").height; + if (control == "handle") { + pressedX = mouseX + pressedY = mouseY + oldPosition = slider.position + } else if (control == "up") { + decrement(); + upPressed = true + } else if (control == "down") { + increment(); + downPressed = true + } else if (!scrollToClickposition){ + if (control == "upPage") { + decrementPage(); + pageUpPressed = true + } else if (control == "downPage") { + incrementPage(); + pageDownPressed = true + } + } else { + slider.position = horizontal ? mouseX - handleRect.width/2 + : mouseY - handleRect.height/2 + } + } + + onReleased: { + autoincrement = false; + upPressed = false; + downPressed = false; + pageUpPressed = false + pageDownPressed = false + control = "" + } + + function incrementPage() { + value += pageStep + if (value > maximumValue) + value = maximumValue + } + + function decrementPage() { + value -= pageStep + if (value < minimumValue) + value = minimumValue + } + + function increment() { + value += singleStep + if (value > maximumValue) + value = maximumValue + } + + function decrement() { + value -= singleStep + if (value < minimumValue) + value = minimumValue + } + + Loader { + id: loader + property Item control: scrollbar + sourceComponent: style + anchors.fill: parent + } + + property rect handleRect: Qt.rect(0,0,0,0) + property rect grooveRect: Qt.rect(0,0,0,0) + function updateHandle() { + internal.handleRect = styleItem.subControlRect("handle") + grooveRect = styleItem.subControlRect("groove"); + } + + RangeModel { + id: slider + minimumValue: 0.0 + maximumValue: 1.0 + value: 0 + stepSize: 0.0 + inverted: false + positionAtMaximum: internal.grooveSize + } + } +} diff --git a/src/qtdesktop/Slider.qml b/src/qtdesktop/Slider.qml new file mode 100644 index 00000000..4e00c156 --- /dev/null +++ b/src/qtdesktop/Slider.qml @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +// jens: ContainsMouse breaks drag functionality + +Item { + id: slider + + // Common API + property int orientation: Qt.Horizontal + property alias minimumValue: range.minimumValue + property alias maximumValue: range.maximumValue + property alias inverted: range.inverted + property bool updateValueWhileDragging: true + property alias pressed: mouseArea.pressed + property alias stepSize: range.stepSize + property alias hoverEnabled: mouseArea.hoverEnabled + property alias value: range.value + + // Destop API + property bool containsMouse: mouseArea.containsMouse + property bool activeFocusOnPress: false + property bool tickmarksEnabled: false + property string tickPosition: "Below" // "Above", "Below", "BothSides" + + Accessible.role: Accessible.Slider + Accessible.name: value + + // Reimplement this function to control how the value is shown in the + // indicator. + function formatValue(v) { + return Math.round(v); + } + + property var styleHints:[] + property Component style: Qt.createComponent(Settings.THEME_PATH + "/SliderStyle.qml") + + Keys.onRightPressed: value += (maximumValue - minimumValue)/10.0 + Keys.onLeftPressed: value -= (maximumValue - minimumValue)/10.0 + + implicitWidth: loader.item ? loader.item.implicitWidth : 0 + implicitHeight: loader.item ? loader.item.implicitHeight : 0 + + RangeModel { + id: range + minimumValue: 0.0 + maximumValue: 1.0 + value: 0 + stepSize: 0.0 + inverted: false + + positionAtMinimum: 0 + positionAtMaximum: slider.width + } + + Loader { + id: loader + sourceComponent: style + anchors.fill: parent + property var control: slider + function positionForValue(value) { return range.positionForValue(value) } + } + + Item { id: fakeHandle } + + MouseArea { + id: mouseArea + + hoverEnabled: true + anchors.centerIn: parent + + width: parent.width + height: parent.height + + drag.target: fakeHandle + drag.axis: Drag.XAxis + drag.minimumX: range.positionAtMinimum + drag.maximumX: range.positionAtMaximum + + onPressed: { + if (activeFocusOnPress) + slider.focus = true; + + // Clamp the value + var newX = Math.max(mouse.x, drag.minimumX); + newX = Math.min(newX, drag.maximumX); + + // Debounce the press: a press event inside the handler will not + // change its position, the user needs to drag it. + + // Note this really messes up things for scrollbar + // if (Math.abs(newX - fakeHandle.x) > handleLoader.width / 2) + range.position = newX; + } + + onReleased: { + // If we don't update while dragging, this is the only + // moment that the range is updated. + if (!slider.updateValueWhileDragging) + range.position = fakeHandle.x; + } + } + + + + // Range position normally follow fakeHandle, except when + // 'updateValueWhileDragging' is false. In this case it will only follow + // if the user is not pressing the handle. + Binding { + when: updateValueWhileDragging || !mouseArea.pressed + target: range + property: "position" + value: fakeHandle.x + } + + // During the drag, we simply ignore position set from the range, this + // means that setting a value while dragging will not "interrupt" the + // dragging activity. + Binding { + when: !mouseArea.drag.active + target: fakeHandle + property: "x" + value: range.position + } + + + WheelArea { + id: wheelarea + anchors.fill: parent + horizontalMinimumValue: slider.minimumValue + horizontalMaximumValue: slider.maximumValue + verticalMinimumValue: slider.minimumValue + verticalMaximumValue: slider.maximumValue + property double step: (slider.maximumValue - slider.minimumValue)/100 + + onVerticalWheelMoved: { + value += verticalDelta/4*step + } + + onHorizontalWheelMoved: { + value += horizontalDelta/4*step + } + } +} diff --git a/src/qtdesktop/SpinBox.qml b/src/qtdesktop/SpinBox.qml new file mode 100644 index 00000000..1ddbc9f6 --- /dev/null +++ b/src/qtdesktop/SpinBox.qml @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +FocusScope { + id: spinbox + + property int minimumWidth: 0 + property int minimumHeight: 0 + + property real value: 0.0 + property real maximumValue: 99 + property real minimumValue: 0 + property real singleStep: 1 + property string postfix + property var styleHints:[] + + property bool upEnabled: value != maximumValue; + property bool downEnabled: value != minimumValue; + property alias upPressed: mouseUp.pressed + property alias downPressed: mouseDown.pressed + property alias upHovered: mouseUp.containsMouse + property alias downHovered: mouseDown.containsMouse + property alias containsMouse: mouseArea.containsMouse + property alias font: input.font + property Component style: Qt.createComponent(Settings.THEME_PATH + "/SpinBoxStyle.qml") + + Accessible.name: input.text + Accessible.role: Accessible.SpinBox + + width: implicitWidth + height: implicitHeight + + implicitWidth: loader.item ? loader.item.implicitWidth : 0 + implicitHeight: loader.item ? loader.item.implicitHeight : 0 + + function increment() { + setValue(input.text) + value += singleStep + if (value > maximumValue) + value = maximumValue + input.text = value + } + + function decrement() { + setValue(input.text) + value -= singleStep + if (value < minimumValue) + value = minimumValue + input.text = value + } + + function setValue(v) { + var newval = parseFloat(v) + if (newval > maximumValue) + newval = maximumValue + else if (v < minimumValue) + newval = minimumValue + value = newval + input.text = value + } + + Component.onCompleted: setValue(value) + + onValueChanged: { + input.valueUpdate = true + input.text = value + input.valueUpdate = false + } + + Loader { + id: loader + property alias control: spinbox + sourceComponent: style + anchors.fill: parent + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } + + // Spinbox input field + + TextInput { + id: input + + property bool valueUpdate: false + property Item styleItem: loader.item + + clip: true + + verticalAlignment: Qt.AlignVCenter + anchors.fill: parent + anchors.leftMargin: styleItem ? styleItem.leftMargin : 0 + anchors.topMargin: styleItem ? styleItem.topMargin : 0 + anchors.rightMargin: styleItem ? styleItem.rightMargin: 0 + anchors.bottomMargin: styleItem ? styleItem.bottomMargin: 0 + selectByMouse: true + + // validator: DoubleValidator { bottom: minimumValue; top: maximumValue; } + onAccepted: {setValue(input.text)} + onActiveFocusChanged: setValue(input.text) + color: loader.item ? loader.item.foregroundColor : "black" + selectionColor: loader.item ? loader.item.selectionColor : "black" + selectedTextColor: loader.item ? loader.item.selectedTextColor : "black" + + opacity: parent.enabled ? 1 : 0.5 + renderType: Text.NativeRendering + Text { + text: postfix + color: loader.item ? loader.item.foregroundColor : "black" + anchors.rightMargin: 4 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + // Spinbox increment button + + MouseArea { + id: mouseUp + + property var upRect: loader.item ? loader.item.upRect : null + + anchors.left: parent.left + anchors.top: parent.top + + anchors.leftMargin: upRect ? upRect.x : 0 + anchors.topMargin: upRect ? upRect.y : 0 + + width: upRect ? upRect.width : 0 + height: upRect ? upRect.height : 0 + + onClicked: increment() + + property bool autoincrement: false; + onReleased: autoincrement = false + Timer { running: mouseUp.pressed; interval: 350 ; onTriggered: mouseUp.autoincrement = true } + Timer { running: mouseUp.autoincrement; interval: 60 ; repeat: true ; onTriggered: increment() } + } + + // Spinbox decrement button + + MouseArea { + id: mouseDown + onClicked: decrement() + property var downRect: loader.item ? loader.item.downRect : null + + anchors.left: parent.left + anchors.top: parent.top + + anchors.leftMargin: downRect ? downRect.x : 0 + anchors.topMargin: downRect ? downRect.y : 0 + + width: downRect ? downRect.width : 0 + height: downRect ? downRect.height : 0 + + property bool autoincrement: false; + onReleased: autoincrement = false + Timer { running: mouseDown.pressed; interval: 350 ; onTriggered: mouseDown.autoincrement = true } + Timer { running: mouseDown.autoincrement; interval: 60 ; repeat: true ; onTriggered: decrement() } + } + + Keys.onUpPressed: increment() + Keys.onDownPressed: decrement() +} diff --git a/src/qtdesktop/SplitterColumn.qml b/src/qtdesktop/SplitterColumn.qml new file mode 100644 index 00000000..1ff35afe --- /dev/null +++ b/src/qtdesktop/SplitterColumn.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "private" as Private +import QtDesktop 1.0 + +/* +* +* SplitterColumn +* +* SplitterColumn is a component that provides a way to layout items horisontally with +* a draggable splitter added in-between each item. +* +* Add items to the SplitterColumn by inserting them as child items. The splitter handle +* is outsourced as a delegate (handleDelegate). To enable the user to drag the handle, +* it will need to contain a mouse area that communicates with the SplitterColumn by binding +* 'drag.target: handle'. The 'handle' property points to the handle item that embeds +* the delegate. To change handle positions, either change 'y; (or 'height') of 'handle', or +* change the height of the child items inside the SplitterColumn. If you set the visibility +* of a child item to false, the corresponding handle will also be hidden, and the +* SplitterColumn will perform a layout update to fill up available space. +* +* There will always be one (and only one) item in the SplitterColumn that is 'expanding'. +* The expanding item is the child that will get all the remaining space in the SplitterColumn +* (down to its own mimimumHeight/Height) when all other items have been layed out. +* This means that that 'height', 'percentageHeight' and 'maximumHeight' will be ignored for this item. +* By default, the last visible child item of the SplitterColumn will be 'expanding'. +* +* A handle can belong to the item on the left side, or the right side, of the handle. Which one depends +* on the expaning item. If the expanding item is to the right of the handle, the +* handle will belong to the item on the left. If it is to the left, it will belong to the item on the +* right. This will again control which item that gets resized when the user drags a handle, and which +* handle that gets hidden when an item is told to hide. +* +* NB: Since SplitterColumn might modify geometry properties like 'height' and 'y; of child items +* to e.g. ensure they stay within minimumHeight/maximumHeight, explicit expression bindings +* to such properties can easily be broken up by the SplitterColumn, and is not recommended. +* +* The SplitterColumn contains the following API: +* +* Component handleDelegate - delegate that will be instanciated between each +* child item. Inside the delegate, the following properties are available: +* int handleIndex - specifies the index of the splitter handle. The handle +* between the first and the second item will get index 0, the next handle index 1 etc. +* Item handle - convenience property that points to the item where the handle background is +* instanciated as a child. Identical to splitterColumn.handles[handleIndex]. The handle +* background iteself can be accessed through handle.item. +* Modify 'handle[d.offset]' to move the handle (or change 'height' of SplitterColumn child items). +* Item splitterItem - convenience property that points to the child item that the handle controls. +* Also refer to information about the expanding item above. +* Item splitterColumn - points to the SplitterColumn that the handle is in. +* List<Item> items - contains the list of child items in the SplitterColumn. Currently read-only. +* List<Item> handles - contains the list of splitter handles in the SplitterColumn. Note that this list will +* be populated after all child items has completed, so accessing it from Component.onCompleted +* inside a SplitterColumn child item will not work. To get to the handle background, access the +* 'background' property of the handle, e.g. handles[0].background. Read-only. +* real preferredHeight/Height - contains the accumulated with of all child items and handles, except +* the expanding item. If the expanding item has a minimum height, the minimum height will +* be included. +* +* The following attached properties can be used for each child item of SplitterColumn: +* +* real Splitter.minimumSize - ensures that the item cannot be resized below the +* given pixelvalue. A value of -1 will disable it. +* real Splitter.maximumSize - ensures that the item cannot be resized above the +* given pixelvalue. A value of -1 will disable it. +* real percentageHeight - This value specifies a percentage (0 - 100) of the height of the +* SplitterColumn height. If the height of the SplitterColumn change, the height of the item will +* change as well. 'percentageHeight' have precedence over 'height', which means that +* SplitterColumn will ignore any assignments to 'height'. A value of -1 disables it. +* bool Splitter.expanding - See explanation of 'expanding' above. If set to true, the current item +* will be the expanding item in the SplitterColumn. If set to false, the SplitterColumn will +* autmatically choose the last visible child of the SplitterColumn as expanding instead. +* int Splitter.itemIndex - will be assigned a read-only value with the item index. Can be used to e.g. look-up +* the handles sourrounding the item (parent.handles[itemIndex]) +* +* Example: +* +* To create a SplitterColumn with three items, and let +* the center item be the one that should be expanding, one +* could do the following: +* +* SplitterColumn { +* anchors.fill: parent +* +* Rectangle { +* Splitter.maximumSize: 400 +* color: "gray" +* height: 200 +* } +* Rectangle { +* Splitter.minimumSize: 50 +* Splitter.expanding: true +* color: "darkgray" +* } +* Rectangle { +* color: "gray" +* height: 200 +* } +* } +*/ + +Private.Splitter { + orientation: Qt.Vertical + handleDelegate: StyleItem { + id: styleitem + elementType: "splitter" + height: handleWidth != -1 ? handleWidth : pixelMetric("splitterwidth") + horizontal: false + property alias pressed: mouseArea.pressed + property bool dragged: mouseArea.drag.active + + MouseArea { + id: mouseArea + anchors.fill: parent + anchors.topMargin: (parent.height <= 1) ? -2 : 0 + anchors.bottomMargin: (parent.height <= 1) ? -2 : 0 + drag.axis: Drag.XandYAxis // Why doesn't X-axis work? + drag.target: handle + cursorShape: Qt.SplitVCursor + } + } +} diff --git a/src/qtdesktop/SplitterRow.qml b/src/qtdesktop/SplitterRow.qml new file mode 100644 index 00000000..14c2ea56 --- /dev/null +++ b/src/qtdesktop/SplitterRow.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import "private" as Private +import QtDesktop 1.0 + +/* +* +* SplitterRow +* +* SplitterRow is a component that provides a way to layout items horisontally with +* a draggable splitter added in-between each item. +* +* Add items to the SplitterRow by inserting them as child items. The splitter handle +* is outsourced as a delegate (handleDelegate). To enable the user to drag the handle, +* it will need to contain a mouse area that communicates with the SplitterRow by binding +* 'drag.target: handle'. The 'handle' property points to the handle item that embeds +* the delegate. To change handle positions, either change 'x' (or 'width') of 'handle', or +* change the width of the child items inside the SplitterRow. If you set the visibility +* of a child item to false, the corresponding handle will also be hidden, and the +* SplitterRow will perform a layout update to fill up available space. +* +* There will always be one (and only one) item in the SplitterRow that is 'expanding'. +* The expanding item is the child that will get all the remaining space in the SplitterRow +* (down to its own mimimumWidth/Height) when all other items have been layed out. +* This means that that 'width', 'percentageWidth' and 'maximumWidth' will be ignored for this item. +* By default, the last visible child item of the SplitterRow will be 'expanding'. +* +* A handle can belong to the item on the left side, or the right side, of the handle. Which one depends +* on the expaning item. If the expanding item is to the right of the handle, the +* handle will belong to the item on the left. If it is to the left, it will belong to the item on the +* right. This will again control which item that gets resized when the user drags a handle, and which +* handle that gets hidden when an item is told to hide. +* +* NB: Since SplitterRow might modify geometry properties like 'width' and 'x' of child items +* to e.g. ensure they stay within minimumWidth/maximumWidth, explicit expression bindings +* to such properties can easily be broken up by the SplitterRow, and is not recommended. +* +* The SplitterRow contains the following API: +* +* Component handleDelegate - delegate that will be instanciated between each +* child item. Inside the delegate, the following properties are available: +* int handleIndex - specifies the index of the splitter handle. The handle +* between the first and the second item will get index 0, the next handle index 1 etc. +* Item handle - convenience property that points to the item where the handle background is +* instanciated as a child. Identical to splitterRow.handles[handleIndex]. The handle +* background iteself can be accessed through handle.item. +* Modify 'handle[d.offset]' to move the handle (or change 'width' of SplitterRow child items). +* Item splitterItem - convenience property that points to the child item that the handle controls. +* Also refer to information about the expanding item above. +* Item splitterRow - points to the SplitterRow that the handle is in. +* List<Item> items - contains the list of child items in the SplitterRow. Currently read-only. +* List<Item> handles - contains the list of splitter handles in the SplitterRow. Note that this list will +* be populated after all child items has completed, so accessing it from Component.onCompleted +* inside a SplitterRow child item will not work. To get to the handle background, access the +* 'background' property of the handle, e.g. handles[0].background. Read-only. +* real preferredWidth/Height - contains the accumulated with of all child items and handles, except +* the expanding item. If the expanding item has a minimum width, the minimum width will +* be included. +* +* The following attached properties can optionally be used for each child item of SplitterRow: +* +* real Splitter.minimumSize - ensures that the item cannot be resized below the +* given pixelvalue. A value of -1 will disable it. +* real Splitter.maximumSixe - ensures that the item cannot be resized above the +* given value. A value of -1 will disable it. +* real Splitter.percentageSize - This value specifies a percentage (0 - 100) of the width of the +* SplitterRow width. If the width of the SplitterRow change, the width of the item will +* change as well. 'percentageWidth' have precedence over 'width', which means that +* SplitterRow will ignore any assignments to 'width'. A value of -1 disables it. +* bool Splitter.expanding - See explanation of 'expanding' above. If set to true, the current item +* will be the expanding item in the SplitterRow. If set to false, the SplitterRow will +* autmatically choose the last visible child of the SplitterRow as expanding instead. +* int Splitter.itemIndex - will be assigned a read-only value with the item index. Can be used to e.g. look-up +* the handles sourrounding the item (parent.handles[itemIndex]) +* +* Example: +* +* To create a SplitterRow with three items, and let +* the center item be the one that should be expanding, one +* could do the following: +* +* SplitterRow { +* anchors.fill: parent +* +* Rectangle { +* Splitter.maximumWidth: 400 +* color: "gray" +* width: 200 +* } +* Rectangle { +* Splitter.minimumWidth: 50 +* Splitter.expanding: true +* color: "darkgray" +* } +* Rectangle { +* color: "gray" +* width: 200 +* } +* } +*/ + + +Private.Splitter { + orientation: Qt.Horizontal + handleDelegate: StyleItem { + id: styleitem + elementType: "splitter" + width: handleWidth != -1 ? handleWidth : pixelMetric("splitterwidth") + property alias pressed: mouseArea.pressed + property bool dragged: mouseArea.drag.active + + MouseArea { + id: mouseArea + anchors.fill: parent + anchors.leftMargin: (parent.width <= 1) ? -2 : 0 + anchors.rightMargin: (parent.width <= 1) ? -2 : 0 + drag.axis: Qt.YAxis + drag.target: handle + cursorShape: Qt.SplitHCursor + } + } +} diff --git a/src/qtdesktop/StatusBar.qml b/src/qtdesktop/StatusBar.qml new file mode 100644 index 00000000..46641411 --- /dev/null +++ b/src/qtdesktop/StatusBar.qml @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +Item { + width: parent ? parent.width : 200 + height: 24 + StyleItem { + anchors.fill: parent + elementType: "statusbar" + } +} diff --git a/src/qtdesktop/Tab.qml b/src/qtdesktop/Tab.qml new file mode 100644 index 00000000..133c3715 --- /dev/null +++ b/src/qtdesktop/Tab.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id:tab + anchors.fill: parent + property string title + property int contentMargin +} diff --git a/src/qtdesktop/TabBar.qml b/src/qtdesktop/TabBar.qml new file mode 100644 index 00000000..0ad47520 --- /dev/null +++ b/src/qtdesktop/TabBar.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: tabbar + property int tabHeight: tabrow.height + property int tabWidth: tabrow.width + + Keys.onRightPressed: { + if (tabFrame && tabFrame.current < tabFrame.count - 1) + tabFrame.current = tabFrame.current + 1 + } + Keys.onLeftPressed: { + if (tabFrame && tabFrame.current > 0) + tabFrame.current = tabFrame.current - 1 + } + + height: tabHeight + + + property Item tabFrame + onTabFrameChanged: parent = tabFrame + visible: tabFrame ? tabFrame.tabsVisible : true + + property int __overlap : loader.item ? loader.item.__overlap : 0 + property string position: tabFrame ? tabFrame.position : "North" + property string tabBarAlignment: loader.item ? loader.item.tabBarAlignment : "Center" + property int tabOverlap: loader.item ? loader.item.tabOverlap : 0 + property int tabBaseOverlap: loader.item ? loader.item.tabBaseOverlap : 0 + property int tabHSpace: loader.item ? loader.item.tabHSpace : 0 + property int tabVSpace: loader.item ? loader.item.tabVSpace : 0 + + function tab(index) { + for (var i = 0; i < tabrow.children.length; ++i) { + if (tabrow.children[i].tabindex == index) { + return tabrow.children[i] + } + } + return null; + } + + property Component style: Qt.createComponent(Settings.THEME_PATH + "/TabBarStyle.qml") + + Loader { + id: loader + sourceComponent: style + property alias control: tabbar + } + + Row { + id: tabrow + Accessible.role: Accessible.PageTabList + states: + State { + when: tabBarAlignment == "center" + name: "centered" + AnchorChanges { + target:tabrow + anchors.horizontalCenter: tabbar.horizontalCenter + } + } + + Repeater { + id: repeater + focus: true + model: tabFrame ? tabFrame.tabs.length : null + delegate: Item { + id: tab + focus: true + + property int tabindex: index + property bool selectedHelper: selected + property bool selected : tabFrame.current == index + property bool hover: mousearea.containsMouse + property bool first: index === 0 + + z: selected ? 1 : -1 + implicitWidth: Math.min(tabloader.implicitWidth, tabbar.width/tabs.length) + 1 + implicitHeight: tabloader.implicitHeight + + Loader { + id: tabloader + sourceComponent: loader.item ? loader.item.tab : null + anchors.fill: parent + // anchors.margins: -2 + property alias control: tab + property int index: tabindex + } + + MouseArea { + id: mousearea + anchors.fill: parent + hoverEnabled: true + onPressed: tabFrame.current = index + } + Accessible.role: Accessible.PageTab + Accessible.name: tabFrame.tabs[index].title + } + } + } +} diff --git a/src/qtdesktop/TabFrame.qml b/src/qtdesktop/TabFrame.qml new file mode 100644 index 00000000..533bdb19 --- /dev/null +++ b/src/qtdesktop/TabFrame.qml @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +Item { + id: tabWidget + width: 100 + height: 100 + property int current: 0 + property int count: stack.children.length + property bool frame: true + property bool tabsVisible: true + property string position: "North" + default property alias tabs : stack.children + property Item tabBar: tabbarItem + property Component delegate: Qt.createComponent(Settings.THEME_PATH + "/TabFrameStyle.qml") + + onCurrentChanged: __setOpacities() + Component.onCompleted: __setOpacities() + + function __setOpacities() { + for (var i = 0; i < stack.children.length; ++i) { + stack.children[i].visible = (i == current ? true : false) + } + } + + Component { + id: tabcomp + Tab {} + } + + function addTab(component, title) { + var tab = tabcomp.createObject(this); + component.createObject(tab) + tab.parent = stack + tab.title = title + __setOpacities() + return tab + } + + function removeTab(id) { + var tab = tabs[id] + tab.destroy() + if (current > 0) + current-=1 + } + + Loader { + id: loader + anchors.fill: parent + anchors.topMargin: tabbarItem && tabsVisible && position == "North" ? Math.max(0, tabbarItem.height - stack.baseOverlap) : 0 + anchors.bottomMargin: tabbarItem && tabsVisible && position == "South" ? Math.max(0, tabbarItem.height - stack.baseOverlap) : 0 + sourceComponent: delegate + Item { + id: stack + anchors.fill: parent + anchors.margins: (frame ? frameWidth : 0) + anchors.topMargin: anchors.margins + (style =="mac" ? 6 : 0) + anchors.bottomMargin: anchors.margins + (style =="mac" ? 6 : 0) + property int frameWidth + property string style + property int baseOverlap + } + onLoaded: item.z = -1 + } + + TabBar { + id: tabbarItem + tabFrame: tabWidget + anchors.top: parent.top + anchors.left: tabWidget.left + anchors.right: tabWidget.right + } + + states: [ + State { + name: "South" + when: position == "South" && tabbarItem != undefined + PropertyChanges { + target: tabbarItem + anchors.topMargin: tabbarItem.height + } + AnchorChanges { + target: tabbarItem + anchors.top: undefined + anchors.bottom: tabWidget.bottom + } + } + ] +} diff --git a/src/qtdesktop/TableColumn.qml b/src/qtdesktop/TableColumn.qml new file mode 100644 index 00000000..53207070 --- /dev/null +++ b/src/qtdesktop/TableColumn.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + property string title + property string role + property int width: 160 + property int x + property bool visible: true + property int elideMode: Text.ElideRight + property int textAlignment: Text.AlignLeft + property Component delegate +} diff --git a/src/qtdesktop/TableView.qml b/src/qtdesktop/TableView.qml new file mode 100644 index 00000000..0e0ed819 --- /dev/null +++ b/src/qtdesktop/TableView.qml @@ -0,0 +1,650 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "private" as Private + +/* +* +* TableView +* +* This component provides an item-view with resizable +* header sections. +* +* You can style the drawn delegate by overriding the itemDelegate +* property. The following properties are supported for custom +* delegates: +* +* Note: Currently only row selection is available for this component +* +* itemheight - default platform size of item +* itemwidth - default platform width of item +* itemselected - if the row is currently selected +* itemvalue - The text for this item +* itemforeground - The default text color for an item +* +* For example: +* itemDelegate: Item { +* Text { +* anchors.verticalCenter: parent.verticalCenter +* color: itemForeground +* elide: Text.ElideRight +* text: itemValue +* } +* } +* +* Data for each row is provided through a model: +* +* ListModel { +* ListElement{ column1: "value 1"; column2: "value 2"} +* ListElement{ column1: "value 3"; column2: "value 4"} +* } +* +* You provide title and size properties on TableColumns +* by setting the default header property : +* +* TableView { +* TableColumn{ role: "column1" ; title: "Column 1" ; width:100} +* TableColumn{ role: "column2" ; title: "Column 2" ; width:200} +* model: datamodel +* } +* +* The header sections are attached to values in the datamodel by defining +* the listmodel property they attach to. Each property in the model, will +* then be shown in each column section. +* +* The view itself does not provide sorting. This has to +* be done on the model itself. However you can provide sorting +* on the model and enable sort indicators on headers. +* +* sortColumn - The index of the currently selected sort header +* sortIndicatorVisible - If sort indicators should be enabled +* sortIndicatorDirection - "up" or "down" depending on state +* +*/ + +FocusScope{ + id: root + + property variant model + + // Framewidth seems to be 1 regardless of style + property int frameWidth: frame ? frameitem.frameWidth : 0; + width: 200 + height: 200 + + // Cosmetic properties + property bool frame: true + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + property bool highlightOnFocus: false + property bool alternateRowColor: true + property bool headerVisible: true + + // Styling properties + property Component itemDelegate: standardDelegate + property Component rowDelegate: rowDelegate + property Component headerDelegate: headerDelegate + property color backgroundColor: "white" + + // Sort properties + property int sortColumn // Index of currently selected sort column + property bool sortIndicatorVisible: false // enables or disables sort indicator + property string sortIndicatorDirection: "down" // "up" or "down" depending on current state + + // Item properties + default property alias header: tree.columnheader + property alias contentHeader: tree.header + property alias contentFooter: tree.footer + + property alias horizontalScrollBar: scroller.horizontalScrollBar + property alias verticalScrollBar: scroller.verticalScrollBar + + // Viewport properties + property alias contentX: tree.contentX + property alias contentY: tree.contentY + property alias contentHeight : tree.contentHeight + property alias contentWidth: tree.contentWidth + property alias viewportWidth: scroller.availableWidth + property alias viewportHeight: scroller.availableHeight + property alias count: tree.count + property alias section: tree.section + + property alias cacheBuffer: tree.cacheBuffer + property alias currentIndex: tree.currentIndex // Should this be currentRowIndex? + + Accessible.role: Accessible.Table + + // Signals + signal activated + + Component { + id: standardDelegate + Item { + height: Math.max(16, styleitem.implicitHeight) + property int implicitWidth: sizehint.paintedWidth + 4 + Text { + id: label + width: parent.width + anchors.margins: 6 + font: itemstyle.font + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: itemTextAlignment + anchors.verticalCenter: parent.verticalCenter + elide: itemElideMode + text: itemValue ? itemValue : "" + color: itemForeground + renderType: Text.NativeRendering + } + Text { + id: sizehint + font: label.font + text: itemValue ? itemValue : "" + visible: false + } + } + } + + StyleItem { + id: itemstyle + elementType: "item" + visible:false + } + + Component { + id: nativeDelegate + // This gives more native styling, but might be less performant + StyleItem { + elementType: "item" + text: itemValue + selected: itemSelected + } + } + + Component { + id: headerDelegate + StyleItem { + elementType: "header" + activeControl: itemSort + raised: true + sunken: itemPressed + text: itemValue + hover: itemContainsMouse + info: itemPosition + } + } + + Component { + id: rowDelegate + StyleItem { + id: rowstyle + elementType: "itemrow" + activeControl: itemAlternateBackground ? "alternate" : "" + selected: itemSelected ? true : false + height: Math.max(16, styleitem.implicitHeight) + } + } + + Rectangle { + id: colorRect + color: backgroundColor + anchors.fill: frameitem + anchors.margins: frameWidth + anchors.rightMargin: (!frameAroundContents && verticalScrollBar.visible ? verticalScrollBar.width : 0) + frameWidth + anchors.bottomMargin: (!frameAroundContents && horizontalScrollBar.visible ? horizontalScrollBar.height : 0) +frameWidth + } + + StyleItem { + id: frameitem + elementType: "frame" + Component.onCompleted: frameWidth = styleitem.pixelMetric("defaultframewidth"); + sunken: true + visible: frame + anchors.fill: parent + anchors.rightMargin: frame ? (frameAroundContents ? (verticalScrollBar.visible ? verticalScrollBar.width + 2 * frameMargins : 0) : 0) : 0 + anchors.bottomMargin: frame ? (frameAroundContents ? (horizontalScrollBar.visible ? horizontalScrollBar.height + 2 * frameMargins : 0) : 0) : 0 + anchors.topMargin: frame ? frameAroundContents : 0 + anchors.leftMargin: frame ? frameAroundContents : 0 + property int frameWidth + property int scrollbarspacing: styleitem.pixelMetric("scrollbarspacing"); + property int frameMargins : frame ? scrollbarspacing : 0 + } + MouseArea { + id: mousearea + + anchors.fill: tree + + property bool autoincrement: false + property bool autodecrement: false + + onReleased: { + autoincrement = false + autodecrement = false + } + + // Handle vertical scrolling whem dragging mouse outside boundraries + Timer { running: mousearea.autoincrement && verticalScrollBar.visible; repeat: true; interval: 20 ; onTriggered: incrementCurrentIndex()} + Timer { running: mousearea.autodecrement && verticalScrollBar.visible; repeat: true; interval: 20 ; onTriggered: decrementCurrentIndex()} + + onPositionChanged: { + if (mouseY > tree.height && pressed) { + if (autoincrement) return; + autodecrement = false; + autoincrement = true; + } else if (mouseY < 0 && pressed) { + if (autodecrement) return; + autoincrement = false; + autodecrement = true; + } else { + autoincrement = false; + autodecrement = false; + } + var y = Math.min(contentY + tree.height - 5, Math.max(mouseY + contentY, contentY)); + var newIndex = tree.indexAt(0, y); + if (newIndex >= 0) + tree.currentIndex = tree.indexAt(0, y); + } + + onPressed: { + tree.forceActiveFocus() + var x = Math.min(contentWidth - 5, Math.max(mouseX + contentX, 0)) + var y = Math.min(contentHeight - 5, Math.max(mouseY + contentY, 0)) + tree.currentIndex = tree.indexAt(x, y) + } + + onDoubleClicked: { + parent.activated() + } + } + + function decrementCurrentIndex() { + scroller.blockUpdates = true; + tree.decrementCurrentIndex(); + scroller.verticalValue = contentY; + scroller.blockUpdates = false; + } + + function incrementCurrentIndex() { + scroller.blockUpdates = true; + tree.incrementCurrentIndex(); + scroller.verticalValue = contentY; + scroller.blockUpdates = false; + } + + ListView { + id: tree + + property list<TableColumn> columnheader + highlightFollowsCurrentItem: true + model: root.model + interactive: false + + anchors.top: tableColumn.bottom + anchors.left: frameitem.left + anchors.right: frameitem.right + anchors.bottom: frameitem.bottom + anchors.margins: frameWidth + anchors.topMargin: -frameWidth + anchors.rightMargin: (!frameAroundContents && verticalScrollBar.visible ? verticalScrollBar.width: 0) + frameWidth + anchors.bottomMargin: (!frameAroundContents && horizontalScrollBar.visible ? horizontalScrollBar.height : 0) + frameWidth + + focus: true + clip: true + + // Fills extra rows with alternate color + Column { + id: rowfiller + property variant rowHeight: Math.max(1, contentHeight / count) + property int rowCount: height/rowHeight + y: contentHeight + width: parent.width + visible: contentHeight > 0 && alternateRowColor && !verticalScrollBar.visible + height: parent.height - contentHeight + Repeater { + model: visible ? rowfiller.rowCount : 0 + Loader { + width: rowfiller.width + height: rowfiller.rowHeight + sourceComponent: root.rowDelegate + property bool itemAlternateBackground: (index + count) % 2 === 1 + property bool itemSelected: false + property variant model: tree.model + property variant modelData: null + } + } + } + + Keys.onUpPressed: root.decrementCurrentIndex() + Keys.onDownPressed: root.incrementCurrentIndex() + + Keys.onPressed: { + if (event.key == Qt.Key_PageUp) { + verticalScrollBar.value = verticalScrollBar.value - tree.height + } else if (event.key == Qt.Key_PageDown) + verticalScrollBar.value = verticalScrollBar.value + tree.height + } + + onContentYChanged: { + scroller.blockUpdates = true + scroller.verticalValue = tree.contentY + verticalScrollBar.value = tree.contentY + scroller.blockUpdates = false + } + + onContentXChanged: { + scroller.blockUpdates = true + scroller.horizontalValue = tree.contentX + horizontalScrollBar.value = tree.contentX + scroller.blockUpdates = false + } + + delegate: Item { + id: rowitem + width: row.width + height: rowstyle.height + + anchors.margins: frameWidth + property int rowIndex: model.index + property bool itemAlternateBackground: alternateRowColor && rowIndex % 2 == 1 + property variant itemModelData: typeof modelData == "undefined" ? null : modelData + + Loader { + id: rowstyle + // row delegate + sourceComponent: root.rowDelegate + // Row fills the tree width regardless of item size + // But scrollbar should not adjust to it + width: frameitem.width + x: contentX + + property bool itemAlternateBackground: rowitem.itemAlternateBackground + property bool itemSelected: rowitem.ListView.isCurrentItem + property int index: rowitem.rowIndex + property variant model: tree.model + property variant modelData: rowitem.itemModelData + } + Row { + id: row + anchors.left: parent.left + height: parent.height + Repeater { + id: repeater + model: root.header.length + Loader { + id: itemDelegateLoader + height: parent.height + visible: header[index].visible + sourceComponent: header[index].delegate ? header[index].delegate : itemDelegate + property variant model: tree.model + property variant role: header[index].role + property variant modelData: itemModelData + + width: header[index].width + + function getValue() { + if (header[index].role.length && model.get && model.get(rowIndex)[header[index].role]) + return model.get(rowIndex)[header[index].role] + else if (modelData && modelData.hasOwnProperty(header[index].role)) + return modelData[header[index].role] + else if (modelData) + return modelData + return "" + } + property variant itemValue: getValue() + property bool itemSelected: rowitem.ListView.isCurrentItem + property color itemForeground: itemSelected ? rowstyleitem.highlightedTextColor : rowstyleitem.textColor + property int rowIndex: rowitem.rowIndex + property int columnIndex: index + property int itemElideMode: header[index].elideMode + property int itemTextAlignment: header[index].textAlignment + } + } + onWidthChanged: tree.contentWidth = width + } + } + } + + + Text{ id:text } + + Item { + id: tableColumn + + anchors.top: frameitem.top + anchors.left: frameitem.left + anchors.right: frameitem.right + anchors.margins: frameWidth + + clip: true + visible: headerVisible + height: headerVisible ? headerrow.height : frameWidth + + Behavior on height { NumberAnimation{ duration: 80 } } + + Row { + id: headerrow + anchors.top: parent.top + x: -tree.contentX + + Repeater { + id: repeater + + property int targetIndex: -1 + property int dragIndex: -1 + + model: header.length + + delegate: Item { + z:-index + width: header[index].width + visible: header[index].visible + height: headerStyle.height + + Loader { + id: headerStyle + sourceComponent: root.headerDelegate + anchors.left: parent.left + anchors.right: parent.right + property string itemValue: header[index].title + property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : ""; + property bool itemPressed: headerClickArea.pressed + property bool itemContainsMouse: headerClickArea.containsMouse + property string itemPosition: header.length === 1 ? "only" : + index===header.length-1 ? "end" : + index===0 ? "beginning" : "" + } + Rectangle{ + id: targetmark + width: parent.width + height:parent.height + opacity: (index == repeater.targetIndex && repeater.targetIndex != repeater.dragIndex) ? 0.5 : 0 + Behavior on opacity { NumberAnimation{duration:160}} + color: palette.highlight + SystemPalette{id:palette} + } + + MouseArea{ + id: headerClickArea + drag.axis: Qt.YAxis + hoverEnabled: true + anchors.fill: parent + onClicked: { + if (sortColumn == index) + sortIndicatorDirection = sortIndicatorDirection === "up" ? "down" : "up" + sortColumn = index + } + // Here we handle moving header sections + // NOTE: the direction is different from the master branch + // so this indicates that Im using an invalid assumption on item ordering + onPositionChanged: { + if (pressed) { // only do this while dragging + for (var h = header.length-1 ; h >= 0 ; --h) { + if (drag.target.x > headerrow.children[h].x) { + repeater.targetIndex = h + break + } + } + } + } + + onPressed: { + repeater.dragIndex = index + draghandle.x = parent.x + } + + onReleased: { + if (repeater.targetIndex >= 0 && repeater.targetIndex != index ) { + // Rearrange the header sections + var items = new Array + for (var i = 0 ; i< header.length ; ++i) + items.push(header[i]) + items.splice(index, 1); + items.splice(repeater.targetIndex, 0, header[index]); + header = items + if (sortColumn == index) + sortColumn = repeater.targetIndex + } + repeater.targetIndex = -1 + } + drag.maximumX: 1000 + drag.minimumX: -1000 + drag.target: draghandle + } + + Loader { + id: draghandle + property string itemValue: header[index].title + property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : ""; + property bool itemPressed: headerClickArea.pressed + property bool itemContainsMouse: headerClickArea.containsMouse + property string itemPosition + + parent: tableColumn + width: header[index].width + height: parent.height + sourceComponent: root.headerDelegate + visible: headerClickArea.pressed + opacity: 0.5 + } + + + MouseArea { + id: headerResizeHandle + property int offset: 0 + property int minimumSize: 20 + anchors.rightMargin: -width/2 + width: 16 ; height: parent.height + anchors.right: parent.right + onPositionChanged: { + var newHeaderWidth = header[index].width + (mouseX - offset) + header[index].width = Math.max(minimumSize, newHeaderWidth) + } + property bool found:false + + onDoubleClicked: { + var row + var minWidth = 0 + var listdata = tree.children[0] + for (row = 0 ; row < listdata.children.length ; ++row){ + var item = listdata.children[row+1] + if (item && item.children[1] && item.children[1].children[index] && + item.children[1].children[index].children[0].hasOwnProperty("implicitWidth")) + minWidth = Math.max(minWidth, item.children[1].children[index].children[0].implicitWidth) + } + if (minWidth) + header[index].width = minWidth + } + onPressedChanged: if(pressed)offset=mouseX + cursorShape: Qt.SplitHCursor + } + } + } + } + Loader { + id: loader + property string itemValue + property string itemSort + property bool itemPressed + property bool itemContainsMouse + property string itemPosition + + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: headerrow.bottom + anchors.rightMargin: -2 + sourceComponent: root.headerDelegate + width: root.width - headerrow.width + 2 + visible: root.header.length + z:-1 + } + } + + Private.ScrollAreaHelper { + id: scroller + anchors.fill: parent + anchors.topMargin: styleitem.style == "mac" ? tableColumn.height + frameWidth: 0 + scrollSpeed: 2 + } + + StyleItem { + z: 2 + anchors.fill: parent + anchors.margins: -4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + elementType: "focusframe" + } + + StyleItem { + id: styleitem + elementType: "header" + visible:false + contentWidth: 16 + contentHeight: font.pixelSize + } + + StyleItem { + id: rowstyleitem + property color textColor: styleHint("textColor") + property color highlightedTextColor: styleHint("highlightedTextColor") + elementType: "item" + visible: false + } +} diff --git a/src/qtdesktop/TextArea.qml b/src/qtdesktop/TextArea.qml new file mode 100644 index 00000000..c7f9f81a --- /dev/null +++ b/src/qtdesktop/TextArea.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +ScrollArea { + id: area + color: "white" + width: 280 + height: 120 + contentWidth: edit.paintedWidth + (2 * documentMargins) + + property alias text: edit.text + property alias wrapMode: edit.wrapMode + property alias readOnly: edit.readOnly + property bool tabChangesFocus: false + property alias font: edit.font + property alias activeFocusOnPress: edit.activeFocusOnPress + property alias horizontalAlignment: edit.horizontalAlignment + + highlightOnFocus: true + property int documentMargins: 4 + frame: true + + function append (string) { + text += "\n" + string + verticalScrollBar.value = verticalScrollBar.maximumValue + } + + Accessible.role: Accessible.EditableText + // FIXME: probably implement text interface + Accessible.name: text + + TextEdit { + MouseArea { + anchors.fill: parent + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + } + renderType: Text.NativeRendering + + id: edit + selectionColor: syspal.highlight + selectedTextColor: syspal.highlightedText + wrapMode: TextEdit.WordWrap; + width: area.viewportWidth - (2 * documentMargins) + x: documentMargins + y: documentMargins + // height has to be big enough to handle mouse focus + height: Math.max(area.height, paintedHeight) + + selectByMouse: true + readOnly: false + color: syspal.text + + SystemPalette { + id: syspal + colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled + } + + KeyNavigation.priority: KeyNavigation.BeforeItem + KeyNavigation.tab: area.tabChangesFocus ? area.KeyNavigation.tab : null + KeyNavigation.backtab: area.tabChangesFocus ? area.KeyNavigation.backtab : null + + onContentSizeChanged: { + area.contentWidth = paintedWidth + (2 * documentMargins) + } + + // keep textcursor within scrollarea + onCursorPositionChanged: { + if (cursorRectangle.y >= area.contentY + area.viewportHeight - 1.5*cursorRectangle.height - documentMargins) + area.contentY = cursorRectangle.y - area.viewportHeight + 1.5*cursorRectangle.height + documentMargins + else if (cursorRectangle.y < area.contentY) + area.contentY = cursorRectangle.y + + if (cursorRectangle.x >= area.contentX + area.viewportWidth - documentMargins) { + area.contentX = cursorRectangle.x - area.viewportWidth + documentMargins + } else if (cursorRectangle.x < area.contentX) + area.contentX = cursorRectangle.x + } + } + + Keys.onPressed: { + if (event.key == Qt.Key_PageUp) { + verticalValue = verticalValue - area.height + } else if (event.key == Qt.Key_PageDown) + verticalValue = verticalValue + area.height + } +} diff --git a/src/qtdesktop/TextField.qml b/src/qtdesktop/TextField.qml new file mode 100644 index 00000000..f02f50f1 --- /dev/null +++ b/src/qtdesktop/TextField.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "Styles/Settings.js" as Settings + +FocusScope { + id: textfield + property alias text: textInput.text + property alias font: textInput.font + + property int minimumWidth: 0 + property int minimumHeight: 0 + + property int inputHint // values tbd + property bool acceptableInput: textInput.acceptableInput // read only + property alias readOnly: textInput.readOnly // read only + property alias placeholderText: placeholderTextComponent.text + property bool passwordMode: false + property alias selectedText: textInput.selectedText + property alias selectionEnd: textInput.selectionEnd + property alias selectionStart: textInput.selectionStart + property alias validator: textInput.validator + property alias inputMask: textInput.inputMask + property alias horizontalalignment: textInput.horizontalAlignment + property alias echoMode: textInput.echoMode + property alias cursorPosition: textInput.cursorPosition + property alias inputMethodHints: textInput.inputMethodHints + property alias activeFocusOnPress: textInput.activeFocusOnPress + property alias containsMouse: mouseArea.containsMouse + property Component style: Qt.createComponent(Settings.THEME_PATH + "/TextFieldStyle.qml") + + property var styleHints:[] + + implicitWidth: loader.implicitWidth + implicitHeight: loader.implicitHeight + + Accessible.name: text + Accessible.role: Accessible.EditableText + Accessible.description: placeholderText + + + function copy() { + textInput.copy() + } + + function paste() { + textInput.paste() + } + + function cut() { + textInput.cut() + } + + function select(start, end) { + textInput.select(start, end) + } + + function selectAll() { + textInput.selectAll() + } + + function selectWord() { + textInput.selectWord() + } + + function positionAt(x) { + var p = mapToItem(textInput, x, 0); + return textInput.positionAt(p.x); + } + + function positionToRectangle(pos) { + var p = mapToItem(textInput, pos.x, pos.y); + return textInput.positionToRectangle(p); + } + + // Implementation + + Loader { + id: loader + sourceComponent: style + anchors.fill: parent + property Item control: textfield + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textfield.forceActiveFocus() + } + + onFocusChanged: { + if (textfield.activeFocus) + textInput.forceActiveFocus(); + } + + TextInput { // see QTBUG-14936 + id: textInput + selectByMouse: true + selectionColor: loader.item ? loader.item.selectionColor : "black" + selectedTextColor: loader.item ? loader.item.selectedTextColor : "black" + + property Item styleItem: loader.item + anchors.leftMargin: styleItem ? styleItem.leftMargin : 0 + anchors.topMargin: styleItem ? styleItem.topMargin : 0 + anchors.rightMargin: styleItem ? styleItem.rightMargin : 0 + anchors.bottomMargin: styleItem ? styleItem.bottomMargin : 0 + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + color: loader.item ? loader.item.foregroundColor : "darkgray" + echoMode: passwordMode ? TextInput.Password : TextInput.Normal + clip: true + renderType: Text.NativeRendering + } + + Text { + id: placeholderTextComponent + anchors.fill: textInput + font: textInput.font + opacity: !textInput.text.length && !textInput.activeFocus ? 1 : 0 + color: loader.item ? loader.item.placeholderTextColor : "darkgray" + text: "Enter text" + clip: true + elide: Text.ElideRight +// renderType: Text.NativeRendering + Behavior on opacity { NumberAnimation { duration: 90 } } + } + MouseArea { + anchors.fill: parent + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + } +} diff --git a/src/qtdesktop/ToolBar.qml b/src/qtdesktop/ToolBar.qml new file mode 100644 index 00000000..d1aeffab --- /dev/null +++ b/src/qtdesktop/ToolBar.qml @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +StyleItem { + id: toolbar + width: parent ? parent.width : 200 + height: implicitHeight + elementType: "toolbar" + + Accessible.role: Accessible.ToolBar +} diff --git a/src/qtdesktop/ToolButton.qml b/src/qtdesktop/ToolButton.qml new file mode 100644 index 00000000..1cfe087b --- /dev/null +++ b/src/qtdesktop/ToolButton.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 +import "private" as Private +import "Styles/Settings.js" as Settings + +Private.BasicButton { + id: button + + property string iconName + property url iconSource + property string text + + style: Qt.createComponent(Settings.THEME_PATH + "/ToolButtonStyle.qml") + + Image { + id: themeIcon + anchors.centerIn: parent + opacity: enabled ? 1 : 0.5 + antialiasing: true + sourceSize.width: iconSize + //property string iconPath: "image://desktoptheme/" + button.iconName + property int iconSize: 24 //(backgroundItem && backgroundItem.style === "mac" && button.styleHint.indexOf("segmented") !== -1) ? 16 : 24 + //source: iconPath // backgroundItem && backgroundItem.hasThemeIcon(iconName) ? iconPath : "" + fillMode: Image.PreserveAspectFit + Image { + // Use fallback icon + anchors.centerIn: parent + sourceSize: parent.sourceSize + visible: (themeIcon.status != Image.Ready) + source: visible ? button.iconSource : "" + } + } + Accessible.name: text +} diff --git a/src/qtdesktop/plugins.qmltypes b/src/qtdesktop/plugins.qmltypes new file mode 100644 index 00000000..79e15ef6 --- /dev/null +++ b/src/qtdesktop/plugins.qmltypes @@ -0,0 +1,451 @@ +import QtQuick.tooling 1.1 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated with the command 'qmlplugindump QtDesktop 1.0 imports/'. + +Module { + Component { + name: "QDesktopItem" + prototype: "QObject" + exports: ["Desktop 1.0"] + Property { name: "screenWidth"; type: "int"; isReadonly: true } + Property { name: "screenHeight"; type: "int"; isReadonly: true } + Property { name: "availableWidth"; type: "int"; isReadonly: true } + Property { name: "availableHeight"; type: "int"; isReadonly: true } + Property { name: "screenCount"; type: "int"; isReadonly: true } + Signal { name: "screenGeometryChanged" } + Signal { name: "availableGeometryChanged" } + Method { + name: "screenGeometry" + type: "QRect" + Parameter { name: "screen"; type: "int" } + } + Method { + name: "availableGeometry" + type: "QRect" + Parameter { name: "screen"; type: "int" } + } + } + Component { + name: "QFileDialogItem" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["FileDialog 1.0"] + Property { name: "visible"; type: "bool" } + Property { name: "modal"; type: "bool" } + Property { name: "title"; type: "string" } + Property { name: "selectExisting"; type: "bool" } + Property { name: "selectMultiple"; type: "bool" } + Property { name: "selectFolder"; type: "bool" } + Property { name: "folder"; type: "string" } + Property { name: "nameFilters"; type: "QStringList" } + Property { name: "filePath"; type: "string"; isReadonly: true } + Property { name: "filePaths"; type: "QStringList"; isReadonly: true } + Signal { name: "modalityChanged" } + Signal { name: "accepted" } + Signal { name: "rejected" } + Method { name: "open" } + Method { name: "close" } + } + Component { + name: "QFileSystemModel" + prototype: "QAbstractItemModel" + exports: ["FileSystemModel 1.0"] + Property { name: "resolveSymlinks"; type: "bool" } + Property { name: "readOnly"; type: "bool" } + Property { name: "nameFilterDisables"; type: "bool" } + Signal { + name: "rootPathChanged" + Parameter { name: "newPath"; type: "string" } + } + Signal { + name: "fileRenamed" + Parameter { name: "path"; type: "string" } + Parameter { name: "oldName"; type: "string" } + Parameter { name: "newName"; type: "string" } + } + Signal { + name: "directoryLoaded" + Parameter { name: "path"; type: "string" } + } + } + Component { + name: "QQuickComponentsColumnLayout" + defaultProperty: "data" + prototype: "QQuickComponentsLinearLayout" + exports: ["ColumnLayout 1.0"] + } + Component { + name: "QQuickComponentsLayout" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["Layout 1.0"] + attachedType: "QQuickComponentsLayoutAttached" + Enum { + name: "SizePolicy" + values: { + "Fixed": 0, + "Expanding": 1 + } + } + } + Component { + name: "QQuickComponentsLayoutAttached" + prototype: "QObject" + Property { name: "minimumWidth"; type: "double" } + Property { name: "minimumHeight"; type: "double" } + Property { name: "maximumWidth"; type: "double" } + Property { name: "maximumHeight"; type: "double" } + Property { name: "verticalSizePolicy"; type: "QQuickComponentsLayout::SizePolicy" } + Property { name: "horizontalSizePolicy"; type: "QQuickComponentsLayout::SizePolicy" } + } + Component { + name: "QQuickComponentsLinearLayout" + defaultProperty: "data" + prototype: "QQuickComponentsLayout" + Property { name: "spacing"; type: "double" } + Signal { name: "orientationChanged" } + } + Component { + name: "QQuickComponentsPrivate" + prototype: "QObject" + exports: ["PrivateHelper 1.0"] + Method { + name: "showToolTip" + Parameter { name: "item"; type: "QQuickItem"; isPointer: true } + Parameter { name: "pos"; type: "QPointF" } + Parameter { name: "text"; type: "string" } + } + Method { name: "hideToolTip" } + } + Component { + name: "QQuickComponentsRowLayout" + defaultProperty: "data" + prototype: "QQuickComponentsLinearLayout" + exports: ["RowLayout 1.0"] + } + Component { + name: "QRangeModel" + prototype: "QObject" + exports: ["RangeModel 1.0"] + Property { name: "value"; type: "double" } + Property { name: "minimumValue"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "stepSize"; type: "double" } + Property { name: "position"; type: "double" } + Property { name: "positionAtMinimum"; type: "double" } + Property { name: "positionAtMaximum"; type: "double" } + Property { name: "inverted"; type: "bool" } + Signal { + name: "valueChanged" + Parameter { name: "value"; type: "double" } + } + Signal { + name: "positionChanged" + Parameter { name: "position"; type: "double" } + } + Signal { + name: "stepSizeChanged" + Parameter { name: "stepSize"; type: "double" } + } + Signal { + name: "invertedChanged" + Parameter { name: "inverted"; type: "bool" } + } + Signal { + name: "minimumChanged" + Parameter { name: "min"; type: "double" } + } + Signal { + name: "maximumChanged" + Parameter { name: "max"; type: "double" } + } + Signal { + name: "positionAtMinimumChanged" + Parameter { name: "min"; type: "double" } + } + Signal { + name: "positionAtMaximumChanged" + Parameter { name: "max"; type: "double" } + } + Method { name: "toMinimum" } + Method { name: "toMaximum" } + Method { + name: "setValue" + Parameter { name: "value"; type: "double" } + } + Method { + name: "setPosition" + Parameter { name: "position"; type: "double" } + } + Method { + name: "valueForPosition" + type: "double" + Parameter { name: "position"; type: "double" } + } + Method { + name: "positionForValue" + type: "double" + Parameter { name: "value"; type: "double" } + } + } + Component { + name: "QStyleItem" + defaultProperty: "data" + prototype: "QQuickPaintedItem" + exports: ["StyleItem 1.0"] + Property { name: "sunken"; type: "bool" } + Property { name: "raised"; type: "bool" } + Property { name: "active"; type: "bool" } + Property { name: "selected"; type: "bool" } + Property { name: "hasFocus"; type: "bool" } + Property { name: "on"; type: "bool" } + Property { name: "hover"; type: "bool" } + Property { name: "horizontal"; type: "bool" } + Property { name: "elementType"; type: "string" } + Property { name: "text"; type: "string" } + Property { name: "activeControl"; type: "string" } + Property { name: "info"; type: "string" } + Property { name: "style"; type: "string"; isReadonly: true } + Property { name: "hint"; type: "string" } + Property { name: "font"; type: "QFont"; isReadonly: true } + Property { name: "minimum"; type: "int" } + Property { name: "maximum"; type: "int" } + Property { name: "value"; type: "int" } + Property { name: "step"; type: "int" } + Property { name: "paintMargins"; type: "int" } + Property { name: "contentWidth"; type: "int" } + Property { name: "contentHeight"; type: "int" } + Signal { + name: "contentWidthChanged" + Parameter { name: "arg"; type: "int" } + } + Signal { + name: "contentHeightChanged" + Parameter { name: "arg"; type: "int" } + } + Method { + name: "pixelMetric" + type: "int" + Parameter { type: "string" } + } + Method { + name: "styleHint" + type: "QVariant" + Parameter { type: "string" } + } + Method { name: "updateSizeHint" } + Method { name: "updateItem" } + Method { + name: "hitTest" + type: "string" + Parameter { name: "x"; type: "int" } + Parameter { name: "y"; type: "int" } + } + Method { + name: "subControlRect" + type: "QRectF" + Parameter { name: "subcontrolString"; type: "string" } + } + Method { + name: "elidedText" + type: "string" + Parameter { name: "text"; type: "string" } + Parameter { name: "elideMode"; type: "int" } + Parameter { name: "width"; type: "int" } + } + Method { + name: "textWidth" + type: "int" + Parameter { type: "string" } + } + Method { + name: "hasThemeIcon" + type: "bool" + Parameter { type: "string" } + } + Method { + name: "setContentWidth" + Parameter { name: "arg"; type: "int" } + } + Method { + name: "setContentHeight" + Parameter { name: "arg"; type: "int" } + } + } + Component { + name: "QWheelArea" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["WheelArea 1.0"] + Property { name: "verticalDelta"; type: "double" } + Property { name: "horizontalDelta"; type: "double" } + Property { name: "horizontalMinimumValue"; type: "double" } + Property { name: "horizontalMaximumValue"; type: "double" } + Property { name: "verticalMinimumValue"; type: "double" } + Property { name: "verticalMaximumValue"; type: "double" } + Property { name: "horizontalValue"; type: "double" } + Property { name: "verticalValue"; type: "double" } + Property { name: "scrollSpeed"; type: "double" } + Signal { name: "verticalWheelMoved" } + Signal { name: "horizontalWheelMoved" } + } + Component { + name: "QWindowItem" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["Window 0.1", "Window 1.0"] + Property { name: "minimumHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "minimumWidth"; type: "int" } + Property { name: "maximumWidth"; type: "int" } + Property { name: "visible"; type: "bool" } + Property { name: "windowDecoration"; type: "bool" } + Property { name: "modal"; type: "bool" } + Property { name: "deleteOnClose"; type: "bool" } + Property { name: "windowState"; type: "Qt::WindowState" } + Property { name: "title"; type: "string" } + Signal { name: "modalityChanged" } + Method { name: "close" } + } + Component { + name: "QtMenu" + defaultProperty: "menuItems" + prototype: "QtMenuBase" + exports: ["Menu 1.0"] + Property { name: "text"; type: "string" } + Property { name: "model"; type: "QVariant" } + Property { name: "selectedIndex"; type: "int" } + Property { name: "hoveredIndex"; type: "int" } + Property { name: "menuItems"; type: "QtMenuBase"; isList: true; isReadonly: true } + Signal { name: "menuClosed" } + Signal { + name: "modelChanged" + Parameter { name: "newModel"; type: "QVariant" } + } + Signal { name: "rebuldMenu" } + Method { + name: "setModel" + Parameter { name: "newModel"; type: "QVariant" } + } + Method { name: "minimumWidth"; type: "int" } + Method { + name: "setMinimumWidth" + Parameter { name: "w"; type: "int" } + } + Method { + name: "showPopup" + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + Parameter { name: "atActionIndex"; type: "int" } + } + Method { + name: "showPopup" + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + } + Method { name: "hidePopup" } + Method { name: "clearMenuItems" } + Method { + name: "addMenuItem" + Parameter { name: "text"; type: "string" } + } + Method { + name: "itemTextAt" + type: "string" + Parameter { name: "index"; type: "int" } + } + Method { + name: "modelTextAt" + type: "string" + Parameter { name: "index"; type: "int" } + } + Method { name: "modelCount"; type: "int" } + Method { name: "hasNativeModel"; type: "bool" } + } + Component { + name: "QtMenuBar" + defaultProperty: "menus" + prototype: "QQuickItem" + exports: ["MenuBar 1.0"] + Property { name: "menus"; type: "QtMenu"; isList: true; isReadonly: true } + } + Component { + name: "QtMenuBase" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["NativeMenuBase 0.1"] + Property { name: "iconSource"; type: "QUrl" } + Property { name: "iconName"; type: "string" } + } + Component { + name: "QtMenuItem" + defaultProperty: "data" + prototype: "QtMenuBase" + exports: ["MenuItem 1.0"] + Property { name: "text"; type: "string" } + Property { name: "shortcut"; type: "string" } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Signal { name: "triggered" } + Signal { + name: "toggled" + Parameter { type: "bool" } + } + } + Component { + name: "QtMenuSeparator" + defaultProperty: "data" + prototype: "QtMenuBase" + exports: ["Separator 1.0"] + } + Component { + name: "QtSplitterAttached" + prototype: "QObject" + Property { name: "minimumWidth"; type: "double" } + Property { name: "maximumWidth"; type: "double" } + Property { name: "minimumHeight"; type: "double" } + Property { name: "maximumHeight"; type: "double" } + Property { name: "percentageSize"; type: "double" } + Property { name: "expanding"; type: "bool" } + Property { name: "itemIndex"; type: "int" } + Signal { + name: "minimumWidthChanged" + Parameter { name: "arg"; type: "double" } + } + Signal { + name: "maximumWidthChanged" + Parameter { name: "arg"; type: "double" } + } + Signal { + name: "minimumHeightChanged" + Parameter { name: "arg"; type: "double" } + } + Signal { + name: "maximumHeightChanged" + Parameter { name: "arg"; type: "double" } + } + Signal { + name: "expandingChanged" + Parameter { name: "arg"; type: "bool" } + } + Signal { + name: "percentageWidthSize" + Parameter { name: "arg"; type: "double" } + } + Signal { + name: "itemIndexChanged" + Parameter { name: "arg"; type: "int" } + } + } + Component { + name: "QtSplitterBase" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["Splitter 1.0"] + attachedType: "QtSplitterAttached" + } +} diff --git a/src/qtdesktop/private/BasicButton.qml b/src/qtdesktop/private/BasicButton.qml new file mode 100644 index 00000000..7189e6f5 --- /dev/null +++ b/src/qtdesktop/private/BasicButton.qml @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 as Internal + +Item { + id: button + + signal clicked + property alias pressed: behavior.effectivePressed + property alias containsMouse: behavior.containsMouse + property alias checkable: behavior.checkable // button toggles between checked and !checked + property alias checked: behavior.checked + property bool activeFocusOnPress: false + property alias style: loader.sourceComponent + property var styleHints: [] + + property color textColor: syspal.text + property string tooltip + + Accessible.role: Accessible.Button + Accessible.description: tooltip + + signal toolTipTriggered + + // implementation + + property string __position: "only" + implicitWidth: loader.implicitWidth + implicitHeight: loader.implicitHeight + + Keys.onPressed: { + if (event.key === Qt.Key_Space && !event.isAutoRepeat && !behavior.pressed) + behavior.keyPressed = true; + } + + Keys.onReleased: { + if (event.key === Qt.Key_Space && !event.isAutoRepeat && behavior.keyPressed) { + behavior.keyPressed = false; + if (checkable) + checked = !checked; + button.clicked(); + } + } + + Loader { + id: loader + anchors.fill: parent + sourceComponent: style + property alias control: button + property alias position: button.__position + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + onClicked: button.clicked() + onExited: Internal.PrivateHelper.hideToolTip() + onCanceled: Internal.PrivateHelper.hideToolTip() + onPressed: if (activeFocusOnPress) button.forceActiveFocus() + + Timer { + interval: 1000 + running: containsMouse && !pressed && tooltip.length + onTriggered: Internal.PrivateHelper.showToolTip(behavior, Qt.point(behavior.mouseX, behavior.mouseY), tooltip) + } + } + + SystemPalette { id: syspal } +} diff --git a/src/qtdesktop/private/ButtonBehavior.qml b/src/qtdesktop/private/ButtonBehavior.qml new file mode 100644 index 00000000..1119811c --- /dev/null +++ b/src/qtdesktop/private/ButtonBehavior.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +MouseArea { + property bool checkable: false + property bool checked: false + property bool keyPressed: false + property bool effectivePressed: pressed && containsMouse || keyPressed + + hoverEnabled: true + enabled: !keyPressed + + onCheckableChanged: { + if (!checkable) + checked = false; + } + + onReleased: { + if (checkable && containsMouse) + checked = !checked; + } +} diff --git a/src/qtdesktop/private/ButtonGroup.js b/src/qtdesktop/private/ButtonGroup.js new file mode 100644 index 00000000..5b0d9adb --- /dev/null +++ b/src/qtdesktop/private/ButtonGroup.js @@ -0,0 +1,141 @@ +var self; +var checkHandlers = []; +var visibleButtons = []; +var nonVisibleButtons = []; +var direction; + +function create(that, options) { + self = that; + direction = options.direction || Qt.Horizontal; + self.childrenChanged.connect(rebuild); +// self.widthChanged.connect(resizeChildren); + build(); +} + +function isButton(item) { + if (item && item.hasOwnProperty("__position")) + return true; + return false; +} + +function hasChecked(item) { + return (item && item.hasOwnProperty("checked")); +} + +function destroy() { + self.childrenChanged.disconnect(rebuild); +// self.widthChanged.disconnect(resizeChildren); + cleanup(); +} + +function build() { + visibleButtons = []; + nonVisibleButtons = []; + + for (var i = 0, item; (item = self.children[i]); i++) { + + if (item.hasOwnProperty("styleHint")) + item.styleHint = styleHint; + + if (!hasChecked(item)) + continue; + + item.visibleChanged.connect(rebuild); // Not optimal, but hardly a bottleneck in your app + if (!item.visible) { + nonVisibleButtons.push(item); + continue; + } + visibleButtons.push(item); + + if (self.exclusive && item.hasOwnProperty("checkable")) + item.checkable = true; + + if (self.exclusive) { + item.checked = false; + checkHandlers.push(checkExclusive(item)); + item.checkedChanged.connect(checkHandlers[checkHandlers.length - 1]); + } + } + + var nrButtons = visibleButtons.length; + if (nrButtons == 0) + return; + + if (self.checkedButton) + self.checkedButton.checked = true; + else if (self.exclusive) { + self.checkedButton = visibleButtons[0]; + self.checkedButton.checked = true; + } + + if (nrButtons == 1) { + finishButton(visibleButtons[0], "only"); + } else { + finishButton(visibleButtons[0], direction == Qt.Horizontal ? "leftmost" : "top"); + for (var i = 1; i < nrButtons - 1; i++) + finishButton(visibleButtons[i], direction == Qt.Horizontal ? "h_middle": "v_middle"); + finishButton(visibleButtons[nrButtons - 1], direction == Qt.Horizontal ? "rightmost" : "bottom"); + } +} + +function finishButton(button, position) { + if (isButton(button)) { + button.__position = position; + if (direction == Qt.Vertical) { + button.anchors.left = self.left //mm How to make this not cause binding loops? see QTBUG-17162 + button.anchors.right = self.right + } + } +} + +function cleanup() { + visibleButtons.forEach(function(item, i) { + if (checkHandlers[i]) + item.checkedChanged.disconnect(checkHandlers[i]); + item.visibleChanged.disconnect(rebuild); + }); + checkHandlers = []; + + nonVisibleButtons.forEach(function(item, i) { + item.visibleChanged.disconnect(rebuild); + }); +} + +function rebuild() { + if (self == undefined) + return; + + cleanup(); + build(); +} + +function resizeChildren() { + if (direction != Qt.Horizontal) + return; + + var extraPixels = self.width % visibleButtons; + var buttonSize = (self.width - extraPixels) / visibleButtons; + visibleButtons.forEach(function(item, i) { + if (!item || !item.visible) + return; + item.width = buttonSize + (extraPixels > 0 ? 1 : 0); + if (extraPixels > 0) + extraPixels--; + }); +} + +function checkExclusive(item) { + var button = item; + return function() { + for (var i = 0, ref; (ref = visibleButtons[i]); i++) { + if (ref.checked == (button === ref)) + continue; + + // Disconnect the signal to avoid recursive calls + ref.checkedChanged.disconnect(checkHandlers[i]); + ref.checked = !ref.checked; + ref.checkedChanged.connect(checkHandlers[i]); + } + self.checkedButton = button; + } +} diff --git a/src/qtdesktop/private/ModalPopupBehavior.qml b/src/qtdesktop/private/ModalPopupBehavior.qml new file mode 100644 index 00000000..1e95f6f1 --- /dev/null +++ b/src/qtdesktop/private/ModalPopupBehavior.qml @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +// KNOWN ISSUES +// none + +Item { + id: popupBehavior + + property bool showing: false + property bool whenAlso: true // modifier to the "showing" property + property bool consumeCancelClick: true + property int delay: 0 // delay before popout becomes visible + property int deallocationDelay: 3000 // 3 seconds + + property Component popupComponent + + property alias popup: popupLoader.item // read-only + property alias window: popupBehavior.root // read-only + + signal prepareToShow + signal prepareToHide + signal cancelledByClick + + // implementation + + anchors.fill: parent + + onShowingChanged: notifyChange() + onWhenAlsoChanged: notifyChange() + function notifyChange() { + if(showing && whenAlso) { + if(popupLoader.sourceComponent == undefined) { + popupLoader.sourceComponent = popupComponent; + } + } else { + mouseArea.enabled = false; // disable before opacity is changed in case it has fading behavior + if(Qt.isQtObject(popupLoader.item)) { + popupBehavior.prepareToHide(); + popupLoader.item.opacity = 0; + } + } + } + + property Item root: findRoot() + function findRoot() { + var p = parent; + while(p.parent != undefined) + p = p.parent; + + return p; + } + + MouseArea { + id: mouseArea + anchors.fill: parent + enabled: false // enabled only when popout is showing + onPressed: { + popupBehavior.showing = false; + mouse.accepted = consumeCancelClick; + cancelledByClick(); + } + } + + Loader { + id: popupLoader + } + + Timer { // visibility timer + running: Qt.isQtObject(popupLoader.item) && showing && whenAlso + interval: delay + onTriggered: { + popupBehavior.prepareToShow(); + mouseArea.enabled = true; + popup.opacity = 1; + } + } + + Timer { // deallocation timer + running: Qt.isQtObject(popupLoader.item) && popupLoader.item.opacity == 0 + interval: deallocationDelay + onTriggered: popupLoader.sourceComponent = undefined + } + + states: State { + name: "active" + when: Qt.isQtObject(popupLoader.item) && popupLoader.item.opacity > 0 + ParentChange { target: popupBehavior; parent: root } + } + } + diff --git a/src/qtdesktop/private/ScrollAreaHelper.qml b/src/qtdesktop/private/ScrollAreaHelper.qml new file mode 100644 index 00000000..e99b3276 --- /dev/null +++ b/src/qtdesktop/private/ScrollAreaHelper.qml @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +WheelArea { + id: wheelarea + + property alias horizontalScrollBar: hscrollbar + property alias verticalScrollBar: vscrollbar + property int macOffset: styleitem.style == "mac" ? 1 : 0 + property bool blockUpdates: false + property int availableHeight : height - (hscrollbar.visible ? hscrollbar.height : 0) + property int availableWidth: width - vscrollbar.width + + anchors.fill: parent + anchors.margins: frameWidth + horizontalMinimumValue: hscrollbar.minimumValue + horizontalMaximumValue: hscrollbar.maximumValue + verticalMinimumValue: vscrollbar.minimumValue + verticalMaximumValue: vscrollbar.maximumValue + + onVerticalValueChanged: { + if (!blockUpdates) + verticalScrollBar.value = verticalValue + } + + onHorizontalValueChanged: { + if (!blockUpdates) + horizontalScrollBar.value = horizontalValue + } + + StyleItem { + // This is the filled corner between scrollbars + id: cornerFill + elementType: "scrollareacorner" + width: vscrollbar.width + anchors.right: parent.right + height: hscrollbar.height + anchors.bottom: parent.bottom + visible: hscrollbar.visible && vscrollbar.visible + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + visible: contentWidth > availableWidth + maximumValue: contentWidth > availableWidth ? root.contentWidth - availableWidth : 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.leftMargin: parent.macOffset + anchors.bottomMargin: -parent.macOffset + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: vscrollbar.visible ? vscrollbar.width -parent.macOffset: 0 + onValueChanged: { + if (!blockUpdates) { + contentX = value + horizontalValue = value + } + } + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + // We cannot bind directly to tree.height due to binding loops so we have to redo the calculation here + // visible: contentHeight > availableHeight + maximumValue: contentHeight > availableHeight ? root.contentHeight - availableHeight : 0 + minimumValue: 0 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: 1//parent.macOffset + anchors.rightMargin: -parent.macOffset + anchors.bottomMargin: hscrollbar.visible ? hscrollbar.height - parent.macOffset : 0 + + onValueChanged: { + if (!blockUpdates) { + contentY = value + verticalValue = value + } + } + } +} diff --git a/src/qtdesktop/private/Splitter.qml b/src/qtdesktop/private/Splitter.qml new file mode 100644 index 00000000..a6c18511 --- /dev/null +++ b/src/qtdesktop/private/Splitter.qml @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtDesktop 1.0 + +Splitter { + id: root + default property alias items: splitterItems.children + property alias handles: splitterHandles.children + property Component handleDelegate: Rectangle { width:3; color: "black" } + property int handleWidth: -1 + property real preferredSize: 0 + property int orientation: Qt.Horizontal + + clip: true + Component.onCompleted: d.init(); + onWidthChanged: d.updateLayout(); + onHeightChanged: d.updateLayout(); + + QtObject { + id: d + + property bool horizontal: orientation == Qt.Horizontal + property string size: horizontal ? "width" : "height" + property string minimum: horizontal ? "minimumWidth" : "minimumHeight" + property string maximum: horizontal ? "maximumWidth" : "maximumHeight" + + property string offset: horizontal ? "x" : "y" + property int expandingIndex: -1 + property bool updateLayoutGuard: true + property bool itemWidthGuard: false + property bool itemExpandingGuard: true + + function init() + { + for (var i=0; i<items.length; ++i) { + var item = items[i]; + + item.Splitter.itemIndex = i + // Assign one, and only one, item to be expanding: + if (item.Splitter.expanding === true) { + if (d.expandingIndex === -1 && item.visible === true) + d.expandingIndex = i + else + item.Splitter.expanding = false + } + + // Anchor each item to fill out all space vertically: + if (d.horizontal) { + item.anchors.top = splitterItems.top + item.anchors.bottom = splitterItems.bottom + } else { + item.anchors.left = splitterItems.left + item.anchors.right = splitterItems.right + + } + + // Listen for changes to width and expanding: + propertyChangeListener.createObject(item, {"itemIndex":i}); + if (i < items.length-1) { + // Create a handle for the item, unless its the last: + var handle = handleloader.createObject(splitterHandles, {"handleIndex":i}); + + if (d.horizontal) { + handle.anchors.top = splitterHandles.top + handle.anchors.bottom = splitterHandles.bottom + } else { + handle.anchors.left = splitterHandles.left + handle.anchors.right = splitterHandles.right + } + } + } + + if (d.expandingIndex === -1) { + // INVARIANT: No item was set as expanding. + // We then choose the last visible item instead: + d.expandingIndex = items.length - 1 + for (i=items.length-1; i>=0; --i) { + var item = items[i] + if (item.visible === true) { + d.expandingIndex = i + item = items[i] + break + } + } + if (items.length && item.visible) { + item.Splitter.expanding = true + } + } + + d.itemExpandingGuard = false + d.updateLayoutGuard = false + d.updateLayout() + } + + function accumulatedSize(firstIndex, lastIndex, includeExpandingMinimum) + { + // Go through items and handles, and + // calculate their acummulated width. + var w = 0 + for (var i=firstIndex; i<lastIndex; ++i) { + var item = items[i] + if (item.visible) { + if (i !== d.expandingIndex) + w += item[d.size]; + else if (includeExpandingMinimum && item.Splitter[minimum] != -1) + w += item[minimum] + } + + var handle = handles[i] + if (handle && items[i + ((d.expandingIndex > i) ? 0 : 1)].visible) + w += handle[d.size] + } + return w + } + + function updateLayout() + { + // This function will reposition both handles and + // items according to the _width of the each item_ + if (items.length === 0) + return; + if (d.updateLayoutGuard === true) + return + d.updateLayoutGuard = true + + // Use a temporary variable to store values to avoid breaking + // property bindings when the value does not actually change: + var newValue + + // Ensure all items within min/max: + for (var i=0; i<items.length; ++i) { + if (i !== d.expandingIndex) { + item = items[i]; + // If the item is using percentage width, convert + // that number to real width now: + if (item.Splitter.percentageSize !== -1) { + newValue = item.Splitter.percentageSize * (root[d.size] / 100) + if (newValue !== item[d.size]) + item[d.size] = newValue + } + // Ensure item width is not more than maximumSize: + if (item.Splitter[maximum] !== -1) { + newValue = Math.min(item[d.size], item.Splitter[maximum]) + if (newValue !== item[d.size]) + item[d.size] = newValue + } + // Ensure item width is not more less minimumWidth: + if (item.Splitter[minimum] !== -1) { + newValue = Math.max(item[d.size], item.Splitter[minimum]) + if (newValue !== item[d.size]) + item[d.size] = newValue + } + } + } + + // Special case: set width of expanding item to available space: + newValue = root[d.size] - d.accumulatedSize(0, items.length, false); + var expandingItem = items[d.expandingIndex] + var expandingMinimum = 0 + if (expandingItem.Splitter[minimum] !== -1) + expandingMinimum = expandingItem.Splitter[minimum] + newValue = Math.max(newValue, expandingMinimum) + if (expandingItem[d.size] !== 0 && expandingItem.Splitter.percentageSize !== -1) + expandingItem.Splitter.percentageSize = newValue * (100 / root[d.size]) + if (expandingItem[d.size] !== newValue) + expandingItem[d.size] = newValue + + // Then, position items and handles according to their width: + var item, lastVisibleItem + var handle, lastVisibleHandle + var newpreferredSize = expandingMinimum - expandingItem[d.size] + + for (i=0; i<items.length; ++i) { + // Position item to the right of the previous visible handle: + item = items[i]; + if (item.visible) { + if (lastVisibleHandle) { + newValue = lastVisibleHandle[d.offset] + lastVisibleHandle[d.size] + if (newValue !== item[d.offset]) + item[d.offset] = newValue + } else { + newValue = 0 + if (newValue !== item[d.offset]) + item[d.offset] = newValue + } + newpreferredSize += item[d.size] + lastVisibleItem = item + } + + // Position handle to the right of the previous visible item. We use an alterative way of + // checking handle visibility because that property might not have updated correctly yet: + handle = handles[i] + if (handle && items[i + ((d.expandingIndex > i) ? 0 : 1)].visible) { + newValue = lastVisibleItem[d.offset] + Math.max(0, lastVisibleItem[d.size]) + if (newValue !== handle[d.offset]) + handle[d.offset] = newValue + newpreferredSize += handle[d.size] + lastVisibleHandle = handle + } + } + + root.preferredSize = newpreferredSize + d.updateLayoutGuard = false + } + } + + Component { + id: handleloader + Loader { + id: myHandle + property int handleIndex: 0 + property Item handle: myHandle + property Item splitterItem: items[handleIndex + ((d.expandingIndex > handleIndex) ? 0 : 1)] + + // 'splitterRow' should be an alias, but that fails to resolve runtime: + property Item splitterRow: root + property Item background: item + + visible: splitterItem.visible + sourceComponent: handleDelegate + onWidthChanged: d.updateLayout() + + onXChanged: { + // For some unknown reason, dragging by X axis only not working in MouseArea, so + // to enable it Drag.XandYAxis should be used, therefore not only Y coordinate + // changes, but also X and we need to filter out this events, if we have splitter, + // that should move vertically + if (d.horizontal) { + moveHandle() + } + } + + onYChanged: { + moveHandle() + } + + function moveHandle() { + // Moving the handle means resizing an item. Which one, + // left or right, depends on where the expanding item is. + // 'updateLayout' will override in case new width violates max/min. + // And 'updateLayout will be triggered when an item changes width. + if (d.updateLayoutGuard) + return + + var leftHandle, leftItem, rightItem, rightHandle + var leftEdge, rightEdge, newWidth, leftStopX, rightStopX + var i + + if (d.expandingIndex > handleIndex) { + // Resize item to the left. + // Ensure that the handle is not crossing other handles. So + // find the first visible handle to the left to determine the left edge: + leftEdge = 0 + for (i=handleIndex-1; i>=0; --i) { + leftHandle = handles[i] + if (leftHandle.visible) { + leftEdge = leftHandle[d.offset] + leftHandle[d.size] + break; + } + } + + // Ensure: leftStopX >= myHandle[d.offset] >= rightStopX + var min = d.accumulatedSize(handleIndex+1, items.length, true) + rightStopX = root[d.size] - min - myHandle[d.size] + leftStopX = Math.max(leftEdge, myHandle[d.offset]) + myHandle[d.offset] = Math.min(rightStopX, Math.max(leftStopX, myHandle[d.offset])) + + newWidth = myHandle[d.offset] - leftEdge + leftItem = items[handleIndex] + if (root[d.size] != 0 && leftItem.Splitter.percentageSize !== -1) + leftItem.Splitter.percentageSize = newWidth * (100 / root[d.size]) + // The next line will trigger 'updateLayout' inside 'propertyChangeListener': + leftItem[d.size] = newWidth + } else { + // Resize item to the right. + // Ensure that the handle is not crossing other handles. So + // find the first visible handle to the right to determine the right edge: + rightEdge = root[d.size] + for (i=handleIndex+1; i<handles.length; ++i) { + rightHandle = handles[i] + if (rightHandle.visible) { + rightEdge = rightHandle[d.offset] + break; + } + } + + // Ensure: leftStopX <= myHandle[d.offset] <= rightStopX + var min = d.accumulatedSize(0, handleIndex+1, true) + leftStopX = min - myHandle[d.size] + rightStopX = Math.min((rightEdge - myHandle[d.size]), myHandle[d.offset]) + myHandle[d.offset] = Math.max(leftStopX, Math.min(myHandle[d.offset], rightStopX)) + + newWidth = rightEdge - (myHandle[d.offset] + myHandle[d.size]) + rightItem = items[handleIndex+1] + if (root[d.size] !== 0 && rightItem[d.percentageSize] !== -1) + rightItem.Splitter.percentageSize = newWidth * (100 / root[d.size]) + // The next line will trigger 'updateLayout' inside 'propertyChangeListener': + rightItem[d.size] = newWidth + } + } + } + } + + Item { + id: splitterItems + anchors.fill: parent + } + Item { + id: splitterHandles + anchors.fill: parent + } + + Component { + // This dummy item becomes a child of all + // items it the splitter, just to provide a way + // to listen for changes to their width, expanding etc. + id: propertyChangeListener + Item { + id: target + width: parent[d.size] + property bool expanding: parent.Splitter.expanding + property real percentageSize: parent.Splitter.percentageSize + property real minimumWidth: parent.Splitter[d.minimum] + property real maximumSize: parent.Splitter[d.maximum] + property int itemIndex: parent.Splitter.itemIndex + + onPercentageSizeChanged: d.updateLayout(); + onMinimumWidthChanged: d.updateLayout(); + onMaximumSizeChanged: d.updateLayout(); + onExpandingChanged: updateExpandingIndex() + + function updateExpandingIndex() + { + // The following code is needed to avoid a binding + // loop, since we might change 'expanding' again to a different item: + if (d.itemExpandingGuard === true) + return + d.itemExpandingGuard = true + // break binding: + expanding = false + + // 'expanding' follows radio button behavior: + // First, find the new expanding item: + var newIndex = items.length-1 + for (var i=0; i<items.length; ++i) { + var item = items[i] + if (i !== d.expandingIndex && item.Splitter.expanding === true && item.visible === true) { + newIndex = i + break + } + } + item = items[newIndex] + if (item.visible === false) { + // So now we ended up with the last item in the splitter to be + // expanding, but it turns out to not be visible. So we need to + // traverse backwards again to find one that is visible... + for (i=items.length-2; i>=0; --i) { + var item = items[i] + if (item.visible === true) { + newIndex = i + item = items[newIndex] + break + } + } + } + + // Tell the found item that it is expanding: + if (item.Splitter.expanding !== true) + item.Splitter.expanding = true + // ...and the old one that it is not: + if (newIndex !== d.expandingIndex) { + item = items[d.expandingIndex] + if (item.Splitter.expanding !== false) + item.Splitter.expanding = false + } + // update index: + d.expandingIndex = newIndex + d.updateLayout(); + // recreate binding: + expanding = Qt.binding(function() { return parent.Splitter.expanding }) + d.itemExpandingGuard = false + } + + function handleSizeChanged() { + // We need to update the layout. + // The following code is needed to avoid a binding + // loop, since we might change 'width' again to a different value: + if (d.itemWidthGuard === true) + return + d.itemWidthGuard = true + // Break binding: + this[d.size] = 0 + + d.updateLayout() + + // Restablish binding: + width = Qt.binding(function() { return parent[d.size]; }) + d.itemWidthGuard = false + } + + onWidthChanged: handleSizeChanged() + onHeightChanged: handleSizeChanged() + onVisibleChanged: { + // Hiding the expanding item forces us to + // select a new one (and therefore not recommended): + if (d.expandingIndex === itemIndex) { + updateExpandingIndex() + } else { + if (visible) { + // Try to keep all items within the SplitterRow. When an item + // has been hidden, the expanding item might no longer be large enough + // to give away space to the new items width. So we need to resize: + var overflow = d.accumulatedSize(0, items.length, true) - root[d.size]; + if (overflow > 0) + parent[d.size] -= overflow + } + d.updateLayout() + } + } + } + } +} diff --git a/src/qtdesktop/qdesktopitem.cpp b/src/qtdesktop/qdesktopitem.cpp new file mode 100644 index 00000000..15c260af --- /dev/null +++ b/src/qtdesktop/qdesktopitem.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopitem.h" + +QDesktopItem::QDesktopItem(QObject* obj) : QObject(obj) { + connect(&desktopWidget, SIGNAL(resized(int)), this, SIGNAL(screenGeometryChanged())); + connect(&desktopWidget, SIGNAL(resized(int)), this, SIGNAL(availableGeometryChanged())); + connect(&desktopWidget, SIGNAL(workAreaResized(int)), this, SIGNAL(availableGeometryChanged())); + connect(&desktopWidget, SIGNAL(screenCountChanged(int)), this, SIGNAL(screenCountChanged())); +} + +int QDesktopItem::screenCount() const +{ + return desktopWidget.screenCount(); +} + +QRect QDesktopItem::screenGeometry(int screen) const { + return desktopWidget.screenGeometry(screen); +} + +QRect QDesktopItem::availableGeometry(int screen) const { + return desktopWidget.availableGeometry(screen); +} + +int QDesktopItem::screenWidth() const +{ + return desktopWidget.screenGeometry().width(); +} + +int QDesktopItem::screenHeight() const +{ + return desktopWidget.screenGeometry().height(); +} + +int QDesktopItem::availableWidth() const +{ + return desktopWidget.availableGeometry().width(); +} + +int QDesktopItem::availableHeight() const +{ + return desktopWidget.availableGeometry().height(); +} + +QDesktopItem *QDesktopItem::qmlAttachedProperties(QObject *obj) { + return new QDesktopItem(obj); +} diff --git a/src/qtdesktop/qdesktopitem.h b/src/qtdesktop/qdesktopitem.h new file mode 100644 index 00000000..6639b8ee --- /dev/null +++ b/src/qtdesktop/qdesktopitem.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESKTOPITEM_H +#define QDESKTOPITEM_H + +#include <QtWidgets/QDesktopWidget> +#include <QtQml> + +class QDesktopItem : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int screenWidth READ screenWidth NOTIFY screenGeometryChanged) + Q_PROPERTY(int screenHeight READ screenHeight NOTIFY screenGeometryChanged) + Q_PROPERTY(int availableWidth READ availableWidth NOTIFY availableGeometryChanged) + Q_PROPERTY(int availableHeight READ availableHeight NOTIFY availableGeometryChanged) + Q_PROPERTY(int screenCount READ screenCount NOTIFY screenCountChanged) + +public: + QDesktopItem(QObject* obj); + + int screenCount() const; + Q_INVOKABLE QRect screenGeometry(int screen) const; + Q_INVOKABLE QRect availableGeometry(int screen) const; + int screenWidth() const; + int screenHeight() const; + int availableWidth() const; + int availableHeight() const; + static QDesktopItem *qmlAttachedProperties(QObject *obj); + +private: + QDesktopWidget desktopWidget; + +Q_SIGNALS: + void screenGeometryChanged(); + void availableGeometryChanged(); + void screenCountChanged(); +}; + +QML_DECLARE_TYPEINFO(QDesktopItem, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QDesktopItemITEM_H diff --git a/src/qtdesktop/qfiledialogitem.cpp b/src/qtdesktop/qfiledialogitem.cpp new file mode 100644 index 00000000..f32c77f5 --- /dev/null +++ b/src/qtdesktop/qfiledialogitem.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Alberto Mardegan <info@mardy.it> +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmlclass FileDialog QFileDialogItem + \ingroup qt-components + \brief Dialog component for choosing files from a local filesystem. + + FileDialog implements a basic file chooser: it allows the user to select + existing files and/or directories, or create new filenames. +*/ + +/*! + \qmlsignal FileDialog::accepted + + The \a accepted signal is emitted when the user has finished using the + dialog. You can then inspect the \a filePath or \a filePaths properties to + get the selection. + + Example: + + \qml + FileDialog { + onAccepted: { console.log("Selected file: " + filePath) } + } + \endqml +*/ + +/*! + \qmlsignal FileDialog::rejected + + The \a rejected signal is emitted when the user has dismissed the dialog, + either by closing the dialog window or by pressing the Cancel button. +*/ + +#include "qfiledialogitem.h" + +#if QT_VERSION < 0x050000 +#include <QGraphicsScene> +#endif + +QFileDialogItem::QFileDialogItem(): + _dialog(new QFileDialog), + _isOpen(false), + _selectExisting(true), + _selectMultiple(false), + _selectFolder(false) +{ + QObject::connect(_dialog, SIGNAL(accepted()), this, SIGNAL(accepted())); + QObject::connect(_dialog, SIGNAL(rejected()), this, SIGNAL(rejected())); +} + +QFileDialogItem::~QFileDialogItem() +{ + delete _dialog; +} + +/*! + \qmlproperty string FileDialog::title + + The title of the dialog window. +*/ +void QFileDialogItem::setTitle(QString title) +{ + _dialog->setWindowTitle(title); + emit titleChanged(); +} + +/* Intentionally left undocumented, as we might decide to remove it later */ +void QFileDialogItem::setModal(bool modal) +{ + bool visible = _dialog->isVisible(); + _dialog->hide(); + _dialog->setWindowModality(modal ? Qt::WindowModal : Qt::NonModal); + + if (visible) + _dialog->show(); + emit modalityChanged(); +} + +/*! + \qmlproperty bool FileDialog::selectExisting + + Whether only existing files or directories can be selected. + + By default, this property is true. +*/ +void QFileDialogItem::setSelectExisting(bool selectExisting) +{ + if (selectExisting == _selectExisting) return; + _selectExisting = selectExisting; + + updateFileMode(); + + _dialog->setAcceptMode(selectExisting ? + QFileDialog::AcceptOpen : QFileDialog::AcceptSave); + + Q_EMIT selectExistingChanged(); +} + +/*! + \qmlproperty bool FileDialog::selectMultiple + + Whether more than one filename can be selected. + + By default, this property is false. +*/ +void QFileDialogItem::setSelectMultiple(bool selectMultiple) +{ + if (selectMultiple == _selectMultiple) return; + _selectMultiple = selectMultiple; + + updateFileMode(); + + Q_EMIT selectMultipleChanged(); +} + +/*! + \qmlproperty bool FileDialog::selectFolder + + Whether the selected item should be a folder. + + By default, this property is false. +*/ +void QFileDialogItem::setSelectFolder(bool selectFolder) +{ + if (selectFolder == _selectFolder) return; + _selectFolder = selectFolder; + + updateFileMode(); + + Q_EMIT selectFolderChanged(); +} + +void QFileDialogItem::updateFileMode() +{ + QFileDialog::FileMode mode = QFileDialog::AnyFile; + + if (_selectFolder) { + mode = QFileDialog::Directory; + _dialog->setOption(QFileDialog::ShowDirsOnly, true); + } else if (_selectExisting) { + mode = _selectMultiple ? + QFileDialog::ExistingFiles : QFileDialog::ExistingFile; + _dialog->setOption(QFileDialog::ShowDirsOnly, false); + } + _dialog->setFileMode(mode); +} + +/*! + \qmlproperty string FileDialog::folder + + The path to the currently selected folder. Setting this property before + invoking open() will cause the file browser to be initially positioned on + the specified folder. + + The value of this property is also updated after the dialog is closed. + + By default, this property is false. +*/ +void QFileDialogItem::setFolder(const QString &folder) +{ + _dialog->setDirectory(folder); + Q_EMIT folderChanged(); +} + +QString QFileDialogItem::folder() const +{ + return _dialog->directory().absolutePath(); +} + +/*! + \qmlproperty list<string> FileDialog::nameFilters + + A list of strings to be used as file name filters. Each string can be a + space-separated list of filters; filters may include the ? and * wildcards. + The list of filters can also be enclosed in parentheses and a textual + description of the filter can be provided. + + For example: + + \qml + FileDialog { + nameFilters: [ "Image files (*.jpg *.png)", "All files (*)" ] + } + \endqml + + \note Directories are not excluded by filters. +*/ +void QFileDialogItem::setNameFilters(const QStringList &nameFilters) +{ + _dialog->setNameFilters(nameFilters); + Q_EMIT nameFiltersChanged(); +} + +/*! + \qmlproperty string FileDialog::filePath + + The path of the file which was selected by the user. + + \note This property is set only if exactly one file was selected. In all + other cases, it will return an empty string. + + \sa filePaths +*/ +QString QFileDialogItem::filePath() const +{ + QStringList files = filePaths(); + return (files.count() == 1) ? files[0] : QString(); +} + +/*! + \qmlproperty list<string> FileDialog::filePaths + + The list of file paths which were selected by the user. +*/ +QStringList QFileDialogItem::filePaths() const +{ + return _dialog->selectedFiles(); +} + +void QFileDialogItem::setVisible(bool visible) +{ + if (visible) + open(); + else + close(); +} + +/*! + \qmlmethod void FileDialog::open() + + Shows the dialog to the user. +*/ +void QFileDialogItem::open() +{ +#if QT_VERSION < 0x050000 + /* We must set the QtDeclarative scene as parent widget for the + * QDialog, so that it will be positioned on top of it. + * This is also necessary for the modality to work. + */ + if (_dialog->parentWidget() == 0) { + QList<QGraphicsView *> views = scene()->views(); + if (!views.isEmpty()) { + _dialog->setParent(views[0], Qt::Dialog); + } + } +#endif + + if (!isVisible()) { + _dialog->show(); + emit visibleChanged(); + } + _isOpen = true; +} + +/*! + \qmlmethod void FileDialog::close() + + Closes the dialog. +*/ +void QFileDialogItem::close() +{ + _isOpen = false; + _dialog->hide(); + emit visibleChanged(); +} + +#if QT_VERSION < 0x050000 +QVariant QFileDialogItem::itemChange(GraphicsItemChange change, + const QVariant &value) +{ + if (change == QGraphicsItem::QGraphicsItem::ItemVisibleHasChanged) { + bool visible = value.toBool(); + + if (visible && _isOpen) { + _dialog->show(); + } else { + _dialog->hide(); + } + emit visibleChanged(); + } + + return QDeclarativeItem::itemChange(change, value); +} +#endif diff --git a/src/qtdesktop/qfiledialogitem.h b/src/qtdesktop/qfiledialogitem.h new file mode 100644 index 00000000..1870a3a9 --- /dev/null +++ b/src/qtdesktop/qfiledialogitem.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Alberto Mardegan <info@mardy.it> +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILEDIALOGITEM_H +#define QFILEDIALOGITEM_H + +#include <QApplication> +#if QT_VERSION < 0x050000 +#include <QDeclarativeItem> +#include <QDeclarativeView> +#else +#include <QtQuick/QQuickItem> +#include <QtQuick/QQuickView> +#endif +#include <QFileDialog> + +#if QT_VERSION < 0x050000 +class QFileDialogItem : public QDeclarativeItem +#else +class QFileDialogItem : public QQuickItem +#endif +{ + Q_OBJECT + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(bool modal READ modal WRITE setModal NOTIFY modalityChanged) + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_PROPERTY(bool selectExisting READ selectExisting \ + WRITE setSelectExisting NOTIFY selectExistingChanged) + Q_PROPERTY(bool selectMultiple READ selectMultiple \ + WRITE setSelectMultiple NOTIFY selectMultipleChanged) + Q_PROPERTY(bool selectFolder READ selectFolder \ + WRITE setSelectFolder NOTIFY selectFolderChanged) + Q_PROPERTY(QString folder READ folder WRITE setFolder NOTIFY folderChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters \ + WRITE setNameFilters NOTIFY nameFiltersChanged) + Q_PROPERTY(QString filePath READ filePath NOTIFY accepted) + Q_PROPERTY(QStringList filePaths READ filePaths NOTIFY accepted) + +public: + QFileDialogItem(); + ~QFileDialogItem(); + + bool isVisible() const { return _dialog->isVisible(); } + QString title() const { return _dialog->windowTitle(); } + bool modal() const { return _dialog->isModal(); } + bool selectExisting() const { return _selectExisting; } + bool selectMultiple() const { return _selectMultiple; } + bool selectFolder() const { return _selectFolder; } + QString folder() const; + QStringList nameFilters() const { return _dialog->nameFilters(); } + QString filePath() const; + QStringList filePaths() const; + + void setVisible(bool visible); + void setTitle(QString title); + void setModal(bool modal); + void setSelectExisting(bool selectExisting); + void setSelectMultiple(bool selectMultiple); + void setSelectFolder(bool selectFolder); + void setFolder(const QString &folder); + void setNameFilters(const QStringList &nameFilters); + +public Q_SLOTS: + void open(); + void close(); + +Q_SIGNALS: + void titleChanged(); + void modalityChanged(); + void accepted(); + void rejected(); + void selectExistingChanged(); + void selectMultipleChanged(); + void selectFolderChanged(); + void folderChanged(); + void nameFiltersChanged(); + void visibleChanged(); + +protected: +#if QT_VERSION < 0x050000 + QVariant itemChange(GraphicsItemChange change, const QVariant &value); +#endif + +private: + void updateFileMode(); + +private: + QFileDialog *_dialog; + bool _isOpen; + bool _selectExisting; + bool _selectMultiple; + bool _selectFolder; +}; + +#endif // QFILEDIALOGITEM_H diff --git a/src/qtdesktop/qmldir b/src/qtdesktop/qmldir new file mode 100644 index 00000000..c3863d8c --- /dev/null +++ b/src/qtdesktop/qmldir @@ -0,0 +1,33 @@ +module QtDesktop +plugin styleplugin plugin +ApplicationWindow 1.0 ApplicationWindow.qml +Button 1.0 Button.qml +ButtonRow 1.0 ButtonRow.qml +ButtonColumn 1.0 ButtonColumn.qml +CheckBox 1.0 CheckBox.qml +ComboBox 1.0 ComboBox.qml +ContextMenu 1.0 ContextMenu.qml +Dial 1.0 Dial.qml +Dialog 1.0 Dialog.qml +Frame 1.0 Frame.qml +GroupBox 1.0 GroupBox.qml +Label 1.0 Label.qml +ProgressBar 1.0 ProgressBar.qml +RadioButton 1.0 RadioButton.qml +ScrollArea 1.0 ScrollArea.qml +ScrollBar 1.0 ScrollBar.qml +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +SplitterRow 1.0 SplitterRow.qml +SplitterColumn 1.0 SplitterColumn.qml +StatusBar 1.0 StatusBar.qml +Tab 1.0 Tab.qml +TabBar 1.0 TabBar.qml +TabFrame 1.0 TabFrame.qml +TableView 1.0 TableView.qml +TableColumn 1.0 TableColumn.qml +TextArea 1.0 TextArea.qml +TextField 1.0 TextField.qml +ToolBar 1.0 ToolBar.qml +ToolButton 1.0 ToolButton.qml + diff --git a/src/qtdesktop/qquickcomponentsprivate.cpp b/src/qtdesktop/qquickcomponentsprivate.cpp new file mode 100644 index 00000000..54b41b4c --- /dev/null +++ b/src/qtdesktop/qquickcomponentsprivate.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickcomponentsprivate.h" +#include <QToolTip> +#include <QQuickWindow> + + +QQuickComponentsPrivate::QQuickComponentsPrivate(QObject *parent) + : QObject(parent) +{ + +} + +void QQuickComponentsPrivate::showToolTip(QQuickItem *item, const QPointF &pos, const QString &str) +{ + if (!item || !item->window()) + return; + + QToolTip::showText(item->window()->mapToGlobal(item->mapToScene(pos).toPoint()), str); +} + +void QQuickComponentsPrivate::hideToolTip() +{ + QToolTip::hideText(); +} diff --git a/src/qtdesktop/qquickcomponentsprivate.h b/src/qtdesktop/qquickcomponentsprivate.h new file mode 100644 index 00000000..5a5fa794 --- /dev/null +++ b/src/qtdesktop/qquickcomponentsprivate.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKCOMPONENTSPRIVATE_H +#define QQUICKCOMPONENTSPRIVATE_H + +#include <QObject> +#include <QQuickItem> + +class QQuickComponentsPrivate : public QObject +{ + Q_OBJECT + +public: + QQuickComponentsPrivate(QObject *parent = 0); + + Q_INVOKABLE void showToolTip(QQuickItem *item, const QPointF &pos, const QString &text); + Q_INVOKABLE void hideToolTip(); +}; + +#endif diff --git a/src/qtdesktop/qquicklayout.cpp b/src/qtdesktop/qquicklayout.cpp new file mode 100644 index 00000000..36619359 --- /dev/null +++ b/src/qtdesktop/qquicklayout.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklayout.h" +#include <QEvent> +#include <QApplication> +#include <QtCore/qnumeric.h> + + +static const qreal q_declarativeLayoutMaxSize = 10e8; + + +QQuickComponentsLayoutAttached::QQuickComponentsLayoutAttached(QObject *parent) + : QObject(parent), + m_minimumWidth(0), + m_minimumHeight(0), + m_maximumWidth(q_declarativeLayoutMaxSize), + m_maximumHeight(q_declarativeLayoutMaxSize), + m_verticalSizePolicy(QQuickComponentsLayout::Fixed), + m_horizontalSizePolicy(QQuickComponentsLayout::Fixed) +{ + +} + +void QQuickComponentsLayoutAttached::setMinimumWidth(qreal width) +{ + if (qIsNaN(width) || m_minimumWidth == width) + return; + + m_minimumWidth = width; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMinimumHeight(qreal height) +{ + if (qIsNaN(height) || m_minimumHeight == height) + return; + + m_minimumHeight = height; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMaximumWidth(qreal width) +{ + if (qIsNaN(width) || m_maximumWidth == width) + return; + + m_maximumWidth = width; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setMaximumHeight(qreal height) +{ + if (qIsNaN(height) || m_maximumHeight == height) + return; + + m_maximumHeight = height; + updateLayout(); +} + +void QQuickComponentsLayoutAttached::setVerticalSizePolicy(QQuickComponentsLayout::SizePolicy policy) +{ + if (m_verticalSizePolicy != policy) { + m_verticalSizePolicy = policy; + updateLayout(); + } +} + +void QQuickComponentsLayoutAttached::setHorizontalSizePolicy(QQuickComponentsLayout::SizePolicy policy) +{ + if (m_horizontalSizePolicy != policy) { + m_horizontalSizePolicy = policy; + updateLayout(); + } +} + +void QQuickComponentsLayoutAttached::updateLayout() +{ + if (m_layout) + m_layout->invalidate(); +} + + + +QQuickComponentsLayout::QQuickComponentsLayout(QQuickItem *parent) + : QQuickItem(parent), + m_dirty(false) +{ + +} + +QQuickComponentsLayout::~QQuickComponentsLayout() +{ + +} + +void QQuickComponentsLayout::setupItemLayout(QQuickItem *item) +{ + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(item); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + info->m_layout = this; +} + +QQuickComponentsLayoutAttached *QQuickComponentsLayout::qmlAttachedProperties(QObject *object) +{ + return new QQuickComponentsLayoutAttached(object); +} + +bool QQuickComponentsLayout::event(QEvent *e) +{ + if (e->type() == QEvent::LayoutRequest) + reconfigureTopDown(); + + return QQuickItem::event(e); +} + +void QQuickComponentsLayout::invalidate() +{ + if (m_dirty) + return; + + QQuickComponentsLayout *layout = this; + QQuickComponentsLayout *parentLayout = 0; + + while (!layout->m_dirty) { + layout->m_dirty = true; + parentLayout = qobject_cast<QQuickComponentsLayout *>(layout->parentItem()); + + if (!parentLayout) + break; + else + layout = parentLayout; + } + + // just post events for top level layouts + if (!parentLayout) + QApplication::postEvent(layout, new QEvent(QEvent::LayoutRequest)); +} + +void QQuickComponentsLayout::reconfigureTopDown() +{ + const QList<QQuickItem *> &children = childItems(); + + reconfigureLayout(); + + foreach (QQuickItem *child, children) { + QQuickComponentsLayout *layout = qobject_cast<QQuickComponentsLayout *>(child); + + if (layout && layout->m_dirty) + layout->reconfigureTopDown(); + } + + m_dirty = false; +} + +void QQuickComponentsLayout::reconfigureLayout() +{ + +} diff --git a/src/qtdesktop/qquicklayout.h b/src/qtdesktop/qquicklayout.h new file mode 100644 index 00000000..86f50266 --- /dev/null +++ b/src/qtdesktop/qquicklayout.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELAYOUT_H +#define QDECLARATIVELAYOUT_H + +#include <QPointer> +#include <QQuickItem> + +class QQuickComponentsLayoutAttached; + + +class QQuickComponentsLayout : public QQuickItem +{ + Q_OBJECT + Q_ENUMS(SizePolicy) + +public: + enum SizePolicy { + Fixed, + Expanding + }; + + explicit QQuickComponentsLayout(QQuickItem *parent = 0); + ~QQuickComponentsLayout(); + + static QQuickComponentsLayoutAttached *qmlAttachedProperties(QObject *object); + +protected: + void invalidate(); + bool event(QEvent *e); + void reconfigureTopDown(); + virtual void reconfigureLayout(); + void setupItemLayout(QQuickItem *item); + +private: + bool m_dirty; + + friend class QQuickComponentsLayoutAttached; +}; + + +class QQuickComponentsLayoutAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth) + Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight) + Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth) + Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight) + Q_PROPERTY(QQuickComponentsLayout::SizePolicy verticalSizePolicy READ verticalSizePolicy WRITE setVerticalSizePolicy) + Q_PROPERTY(QQuickComponentsLayout::SizePolicy horizontalSizePolicy READ horizontalSizePolicy WRITE setHorizontalSizePolicy) + +public: + QQuickComponentsLayoutAttached(QObject *object); + + qreal minimumWidth() const { return m_minimumWidth; } + void setMinimumWidth(qreal width); + + qreal minimumHeight() const { return m_minimumHeight; } + void setMinimumHeight(qreal height); + + qreal maximumWidth() const { return m_maximumWidth; } + void setMaximumWidth(qreal width); + + qreal maximumHeight() const { return m_maximumHeight; } + void setMaximumHeight(qreal height); + + QQuickComponentsLayout::SizePolicy verticalSizePolicy() const { return m_verticalSizePolicy; } + void setVerticalSizePolicy(QQuickComponentsLayout::SizePolicy policy); + + QQuickComponentsLayout::SizePolicy horizontalSizePolicy() const { return m_horizontalSizePolicy; } + void setHorizontalSizePolicy(QQuickComponentsLayout::SizePolicy policy); + +protected: + void updateLayout(); + +private: + qreal m_minimumWidth; + qreal m_minimumHeight; + qreal m_maximumWidth; + qreal m_maximumHeight; + QQuickComponentsLayout::SizePolicy m_verticalSizePolicy; + QQuickComponentsLayout::SizePolicy m_horizontalSizePolicy; + QPointer<QQuickComponentsLayout> m_layout; + + friend class QQuickComponentsLayout; +}; + +QML_DECLARE_TYPE(QQuickComponentsLayout) +QML_DECLARE_TYPEINFO(QQuickComponentsLayout, QML_HAS_ATTACHED_PROPERTIES) + +#endif diff --git a/src/qtdesktop/qquicklayoutengine.cpp b/src/qtdesktop/qquicklayoutengine.cpp new file mode 100644 index 00000000..f11a2107 --- /dev/null +++ b/src/qtdesktop/qquicklayoutengine.cpp @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklayoutengine_p.h" + + +/* + This function is a modification of qGeomCalc() included in "QtCore/kernel/qlayoutengine_p.h". + It is used as a helper function to handle linear layout recalculations for QQuickItems. + + chain contains input and output parameters describing the geometry. + count is the count of items in the chain; pos and space give the + interval (relative to parentWidget topLeft). +*/ +void qDeclarativeLayoutCalculate(QVector<QQuickComponentsLayoutInfo> &chain, int start, + int count, qreal pos, qreal space, qreal spacer) +{ + if (chain.count() == 0) + return; + + bool wannaGrow = false; + qreal totalStretch = 0; + qreal totalSpacing = 0; + qreal totalSizeHint = 0; + qreal totalMinimumSize = 0; + + const int end = start + count; + const int spacerCount = chain.count() - 1; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + data->done = false; + + totalStretch += data->stretch; + totalSizeHint += data->smartSizeHint(); + totalMinimumSize += data->minimumSize; + + // don't count last spacing + if (i < end - 1) + totalSpacing += data->effectiveSpacer(spacer); + + wannaGrow = (wannaGrow || data->expansive || data->stretch > 0); + } + + qreal extraSpace = 0; + + if (space < totalMinimumSize + totalSpacing) { + // Less space than minimumSize; take from the biggest first + qreal minSize = totalMinimumSize + totalSpacing; + + // shrink the spacers proportionally + if (spacer >= 0) { + spacer = minSize > 0 ? spacer * space / minSize : 0; + totalSpacing = spacer * spacerCount; + } + + QList<qreal> list; + + for (int i = start; i < end; i++) + list << chain.at(i).minimumSize; + + qSort(list); + + qreal spaceLeft = space - totalSpacing; + + qreal sum = 0; + int idx = 0; + qreal spaceUsed = 0; + qreal current = 0; + + while (idx < count && spaceUsed < spaceLeft) { + current = list.at(idx); + spaceUsed = sum + current * (count - idx); + sum += current; + ++idx; + } + + --idx; + + int items = count - idx; + qreal deficit = spaceUsed - spaceLeft; + qreal deficitPerItem = deficit / items; + qreal maxval = current - deficitPerItem; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + data->done = true; + + if (data->minimumSize > 0) + data->size = data->minimumSize; + else + data->size = qMin<qreal>(data->minimumSize, maxval); + } + } else if (space < totalSizeHint + totalSpacing) { + /* + Less space than smartSizeHint(), but more than minimumSize. + Currently take space equally from each, as in Qt 2.x. + Commented-out lines will give more space to stretchier + items. + */ + int n = count; + qreal spaceLeft = space - totalSpacing; + qreal overdraft = totalSizeHint - spaceLeft; + + // first give to the fixed ones + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->minimumSize >= data->smartSizeHint()) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->smartSizeHint(); + n--; + } + } + + bool finished = (n == 0); + + while (!finished) { + finished = true; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + qreal w = overdraft / n; + data->size = data->smartSizeHint() - w; + + if (data->size < data->minimumSize) { + data->done = true; + data->size = data->minimumSize; + finished = false; + overdraft -= data->smartSizeHint() - data->minimumSize; + n--; + break; + } + } + } + } else { // extra space + int n = count; + qreal spaceLeft = space - totalSpacing; + + // first give to the fixed ones, and handle non-expansiveness + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + if (data->maximumSize <= data->smartSizeHint() + || (wannaGrow && !data->expansive && data->stretch == 0) + || (!data->expansive && data->stretch == 0)) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->size; + totalStretch -= data->stretch; + n--; + } + } + + extraSpace = spaceLeft; + + /* + Do a trial distribution and calculate how much it is off. + If there are more deficit pixels than surplus pixels, give + the minimum size items what they need, and repeat. + Otherwise give to the maximum size items, and repeat. + + Paul Olav Tvete has a wonderful mathematical proof of the + correctness of this principle, but unfortunately this + comment is too small to contain it. + */ + qreal surplus, deficit; + + do { + surplus = deficit = 0; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (data->done) + continue; + + extraSpace = 0; + + qreal w; + + if (totalStretch <= 0) + w = (spaceLeft / n); + else + w = (spaceLeft * data->stretch) / totalStretch; + + data->size = w; + + if (w < data->smartSizeHint()) + deficit += data->smartSizeHint() - w; + else if (w > data->maximumSize) + surplus += w - data->maximumSize; + } + + if (deficit > 0 && surplus <= deficit) { + // give to the ones that have too little + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->size < data->smartSizeHint()) { + data->done = true; + data->size = data->smartSizeHint(); + spaceLeft -= data->smartSizeHint(); + totalStretch -= data->stretch; + n--; + } + } + } + + if (surplus > 0 && surplus >= deficit) { + // take from the ones that have too much + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + + if (!data->done && data->size > data->maximumSize) { + data->done = true; + data->size = data->maximumSize; + spaceLeft -= data->maximumSize; + totalStretch -= data->stretch; + n--; + } + } + } + } while (n > 0 && surplus != deficit); + + if (n == 0) + extraSpace = spaceLeft; + } + + /* + As a last resort, we distribute the unwanted space equally + among the spacers (counting the start and end of the chain). We + could, but don't, attempt a sub-pixel allocation of the extra + space. + */ + qreal extra = extraSpace / (spacerCount + 2); + qreal p = pos + extra; + + for (int i = start; i < end; i++) { + QQuickComponentsLayoutInfo *data = &chain[i]; + data->pos = p; + p += data->size; + p += data->effectiveSpacer(spacer) + extra; + } +} diff --git a/src/qtdesktop/qquicklayoutengine_p.h b/src/qtdesktop/qquicklayoutengine_p.h new file mode 100644 index 00000000..c4cdaf08 --- /dev/null +++ b/src/qtdesktop/qquicklayoutengine_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELAYOUTENGINE_H +#define QDECLARATIVELAYOUTENGINE_H + +#include <QVector> + +struct QQuickComponentsLayoutInfo +{ + QQuickComponentsLayoutInfo() + : stretch(1), + sizeHint(0), + spacing(0), + minimumSize(0), + maximumSize(0), + expansive(true), + done(false), + pos(0), + size(0) + { } + + inline qreal smartSizeHint() { + return (stretch > 0) ? minimumSize : sizeHint; + } + + inline qreal effectiveSpacer(qreal value) const { + return value + spacing; + } + + qreal stretch; + qreal sizeHint; + qreal spacing; + qreal minimumSize; + qreal maximumSize; + bool expansive; + + // result + bool done; + qreal pos; + qreal size; +}; + +void qDeclarativeLayoutCalculate(QVector<QQuickComponentsLayoutInfo> &chain, int start, + int count, qreal pos, qreal space, qreal spacer); + +#endif diff --git a/src/qtdesktop/qquicklinearlayout.cpp b/src/qtdesktop/qquicklinearlayout.cpp new file mode 100644 index 00000000..995551d1 --- /dev/null +++ b/src/qtdesktop/qquicklinearlayout.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklinearlayout.h" +#include "qquicklayoutengine_p.h" +#include <QtCore/qnumeric.h> + +static const qreal q_declarativeLayoutDefaultSpacing = 4.0; + + +QQuickComponentsLinearLayout::QQuickComponentsLinearLayout(Orientation orientation, + QQuickItem *parent) + : QQuickComponentsLayout(parent), + m_spacing(q_declarativeLayoutDefaultSpacing), + m_orientation(orientation) +{ + +} + +qreal QQuickComponentsLinearLayout::spacing() const +{ + return m_spacing; +} + +void QQuickComponentsLinearLayout::setSpacing(qreal spacing) +{ + if (qIsNaN(spacing) || m_spacing == spacing) + return; + + m_spacing = spacing; + invalidate(); +} + +QQuickComponentsLinearLayout::Orientation QQuickComponentsLinearLayout::orientation() const +{ + return m_orientation; +} + +void QQuickComponentsLinearLayout::setOrientation(Orientation orientation) +{ + if (m_orientation == orientation) + return; + + m_orientation = orientation; + invalidate(); + + emit orientationChanged(); +} + +void QQuickComponentsLinearLayout::componentComplete() +{ + QQuickComponentsLayout::componentComplete(); + updateLayoutItems(); + invalidate(); +} + +void QQuickComponentsLinearLayout::updateLayoutItems() +{ + const QList<QQuickItem *> &children = childItems(); + + foreach (QQuickItem *child, children) + insertLayoutItem(child); +} + +void QQuickComponentsLinearLayout::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (isComponentComplete()) { + if (change == ItemChildAddedChange) + insertLayoutItem(value.item); + else if (change == ItemChildRemovedChange) + removeLayoutItem(value.item); + } + + QQuickComponentsLayout::itemChange(change, value); +} + +void QQuickComponentsLinearLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickComponentsLayout::geometryChanged(newGeometry, oldGeometry); + invalidate(); +} + +void QQuickComponentsLinearLayout::insertLayoutItem(QQuickItem *item) +{ + m_items.append(item); + setupItemLayout(item); + + invalidate(); + QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); +} + +void QQuickComponentsLinearLayout::removeLayoutItem(QQuickItem *item) +{ + if (!m_items.removeOne(item)) + return; + + invalidate(); + QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); +} + +void QQuickComponentsLinearLayout::onItemDestroyed() +{ + if (!m_items.removeOne(static_cast<QQuickItem *>(sender()))) + return; + + invalidate(); +} + +void QQuickComponentsLinearLayout::reconfigureLayout() +{ + if (!isComponentComplete()) + return; + + const int count = m_items.count(); + + if (count == 0) + return; + + qreal totalSpacing = 0; + qreal totalSizeHint = 0; + qreal totalMinimumSize = 0; + qreal totalMaximumSize = 0; + + QVector<QQuickComponentsLayoutInfo> itemData; + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(item); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + + QQuickComponentsLayoutInfo data; + + if (m_orientation == Horizontal) { + data.sizeHint = item->implicitWidth(); + data.minimumSize = info->minimumWidth(); + data.maximumSize = info->maximumWidth(); + data.expansive = (info->horizontalSizePolicy() == QQuickComponentsLayout::Expanding); + data.stretch = info->horizontalSizePolicy() == Expanding ? 1.0 : 0; + } else { + data.sizeHint = item->implicitHeight(); + data.minimumSize = info->minimumHeight(); + data.maximumSize = info->maximumHeight(); + data.expansive = (info->verticalSizePolicy() == QQuickComponentsLayout::Expanding); + data.stretch = info->verticalSizePolicy() == Expanding ? 1.0 : 0; + } + + itemData.append(data); + + // sum + totalSizeHint += data.sizeHint; + totalMinimumSize += data.minimumSize; + totalMaximumSize += data.maximumSize; + + // don't count last spacing + if (i < count - 1) + totalSpacing += data.spacing + m_spacing; + } + + if (m_orientation == Horizontal) { + qDeclarativeLayoutCalculate(itemData, 0, count, 0, width(), m_spacing); + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + const QQuickComponentsLayoutInfo &data = itemData.at(i); + + item->setX(data.pos); + item->setY(height()/2 - item->height()/2); + item->setWidth(data.size); + } + } else { + qDeclarativeLayoutCalculate(itemData, 0, count, 0, height(), m_spacing); + + for (int i = 0; i < count; i++) { + QQuickItem *item = m_items.at(i); + const QQuickComponentsLayoutInfo &data = itemData.at(i); + + item->setY(data.pos); + item->setX(width()/2 - item->width()/2); + item->setHeight(data.size); + } + } + + // propagate hints to upper levels + QObject *attached = qmlAttachedPropertiesObject<QQuickComponentsLayout>(this); + QQuickComponentsLayoutAttached *info = static_cast<QQuickComponentsLayoutAttached *>(attached); + + if (m_orientation == Horizontal) { + setImplicitWidth(totalSizeHint); + info->setMinimumWidth(totalMinimumSize + totalSpacing); + info->setMaximumWidth(totalMaximumSize + totalSpacing); + } else { + setImplicitHeight(totalSizeHint); + info->setMinimumHeight(totalMinimumSize + totalSpacing); + info->setMaximumHeight(totalMaximumSize + totalSpacing); + } +} diff --git a/src/qtdesktop/qquicklinearlayout.h b/src/qtdesktop/qquicklinearlayout.h new file mode 100644 index 00000000..8cd73e86 --- /dev/null +++ b/src/qtdesktop/qquicklinearlayout.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELINEARLAYOUT_H +#define QDECLARATIVELINEARLAYOUT_H + +#include "qquicklayout.h" + + +class QQuickComponentsLinearLayout : public QQuickComponentsLayout +{ + Q_OBJECT + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) + +public: + enum Orientation { + Vertical, + Horizontal + }; + + explicit QQuickComponentsLinearLayout(Orientation orientation, + QQuickItem *parent = 0); + ~QQuickComponentsLinearLayout() {} + + qreal spacing() const; + void setSpacing(qreal spacing); + + Orientation orientation() const; + void setOrientation(Orientation orientation); + + void componentComplete(); + +signals: + void spacingChanged(); + void orientationChanged(); + +protected: + void updateLayoutItems(); + void reconfigureLayout(); + void insertLayoutItem(QQuickItem *item); + void removeLayoutItem(QQuickItem *item); + void itemChange(ItemChange change, const ItemChangeData &data); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + +protected slots: + void onItemDestroyed(); + +private: + qreal m_spacing; + Orientation m_orientation; + QList<QQuickItem *> m_items; +}; + + +class QQuickComponentsRowLayout : public QQuickComponentsLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickComponentsRowLayout(QQuickItem *parent = 0) + : QQuickComponentsLinearLayout(Horizontal, parent) {} +}; + + +class QQuickComponentsColumnLayout : public QQuickComponentsLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickComponentsColumnLayout(QQuickItem *parent = 0) + : QQuickComponentsLinearLayout(Vertical, parent) {} +}; + +#endif diff --git a/src/qtdesktop/qrangemodel.cpp b/src/qtdesktop/qrangemodel.cpp new file mode 100644 index 00000000..ac876824 --- /dev/null +++ b/src/qtdesktop/qrangemodel.cpp @@ -0,0 +1,534 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QRangeModel + \brief The QRangeModel class, helps users to build components that depend + on some value and/or position to be in a certain range previously defined + + With this class, the user sets a value range and a position range, which + represent the valid values/positions the model can assume. It is worth telling + that the value property always has priority over the position property. A nice use + case, would be a Slider implementation with the help of QRangeModel. If the user sets + a value range to [0,100], a position range to [50,100] and sets the value + to 80, the equivalent position would be 90. After that, if the user decides to + resize the slider, the value would be the same, but the knob position would + be updated due to the new position range. + + \ingroup qt-components +*/ + +#include <QEvent> +#include <QtWidgets/QApplication> +#include <QtWidgets/QGraphicsSceneEvent> +#include <QDebug> + +#ifndef QT_NO_ACCESSIBILITY +#include <QAccessible> +#endif + +#include "qrangemodel.h" +#include "qrangemodel_p.h" + +QRangeModelPrivate::QRangeModelPrivate(QRangeModel *qq) + : q_ptr(qq) +{ +} + +QRangeModelPrivate::~QRangeModelPrivate() +{ +} + +void QRangeModelPrivate::init() +{ + minimum = 0; + maximum = 99; + stepSize = 0; + value = 0; + pos = 0; + posatmin = 0; + posatmax = 0; + inverted = false; +} + +/*! + Calculates the position that is going to be seen outside by the component + that is using QRangeModel. It takes into account the \l stepSize, + \l positionAtMinimum, \l positionAtMaximum properties + and \a position that is passed as parameter. +*/ + +qreal QRangeModelPrivate::publicPosition(qreal position) const +{ + // Calculate the equivalent stepSize for the position property. + const qreal min = effectivePosAtMin(); + const qreal max = effectivePosAtMax(); + const qreal valueRange = maximum - minimum; + const qreal positionValueRatio = valueRange ? (max - min) / valueRange : 0; + const qreal positionStep = stepSize * positionValueRatio; + + if (positionStep == 0) + return (min < max) ? qBound(min, position, max) : qBound(max, position, min); + + const int stepSizeMultiplier = (position - min) / positionStep; + + // Test whether value is below minimum range + if (stepSizeMultiplier < 0) + return min; + + qreal leftEdge = (stepSizeMultiplier * positionStep) + min; + qreal rightEdge = ((stepSizeMultiplier + 1) * positionStep) + min; + + if (min < max) { + leftEdge = qMin(leftEdge, max); + rightEdge = qMin(rightEdge, max); + } else { + leftEdge = qMax(leftEdge, max); + rightEdge = qMax(rightEdge, max); + } + + if (qAbs(leftEdge - position) <= qAbs(rightEdge - position)) + return leftEdge; + return rightEdge; +} + +/*! + Calculates the value that is going to be seen outside by the component + that is using QRangeModel. It takes into account the \l stepSize, + \l minimumValue, \l maximumValue properties + and \a value that is passed as parameter. +*/ + +qreal QRangeModelPrivate::publicValue(qreal value) const +{ + // It is important to do value-within-range check this + // late (as opposed to during setPosition()). The reason is + // QML bindings; a position that is initially invalid because it lays + // outside the range, might become valid later if the range changes. + + if (stepSize == 0) + return qBound(minimum, value, maximum); + + const int stepSizeMultiplier = (value - minimum) / stepSize; + + // Test whether value is below minimum range + if (stepSizeMultiplier < 0) + return minimum; + + const qreal leftEdge = qMin(maximum, (stepSizeMultiplier * stepSize) + minimum); + const qreal rightEdge = qMin(maximum, ((stepSizeMultiplier + 1) * stepSize) + minimum); + const qreal middle = (leftEdge + rightEdge) / 2; + + return (value <= middle) ? leftEdge : rightEdge; +} + +/*! + Checks if the \l value or \l position, that is seen by the user, has changed and emits the changed signal if it + has changed. +*/ + +void QRangeModelPrivate::emitValueAndPositionIfChanged(const qreal oldValue, const qreal oldPosition) +{ + Q_Q(QRangeModel); + + // Effective value and position might have changed even in cases when e.g. d->value is + // unchanged. This will be the case when operating with values outside range: + const qreal newValue = q->value(); + const qreal newPosition = q->position(); + if (!qFuzzyCompare(newValue, oldValue)) + emit q->valueChanged(newValue); + if (!qFuzzyCompare(newPosition, oldPosition)) + emit q->positionChanged(newPosition); +} + +/*! + Constructs a QRangeModel with \a parent +*/ + +QRangeModel::QRangeModel(QObject *parent) + : QObject(parent), d_ptr(new QRangeModelPrivate(this)) +{ + Q_D(QRangeModel); + d->init(); +} + +/*! + \internal + Constructs a QRangeModel with private class pointer \a dd and \a parent +*/ + +QRangeModel::QRangeModel(QRangeModelPrivate &dd, QObject *parent) + : QObject(parent), d_ptr(&dd) +{ + Q_D(QRangeModel); + d->init(); +} + +/*! + Destroys the QRangeModel +*/ + +QRangeModel::~QRangeModel() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Sets the range of valid positions, that \l position can assume externally, with + \a min and \a max. + Such range is represented by \l positionAtMinimum and \l positionAtMaximum +*/ + +void QRangeModel::setPositionRange(qreal min, qreal max) +{ + Q_D(QRangeModel); + + bool emitPosAtMinChanged = !qFuzzyCompare(min, d->posatmin); + bool emitPosAtMaxChanged = !qFuzzyCompare(max, d->posatmax); + + if (!(emitPosAtMinChanged || emitPosAtMaxChanged)) + return; + + const qreal oldPosition = position(); + d->posatmin = min; + d->posatmax = max; + + // When a new positionRange is defined, the position property must be updated based on the value property. + // For instance, imagine that you have a valueRange of [0,100] and a position range of [20,100], + // if a user set the value to 50, the position would be 60. If this positionRange is updated to [0,100], then + // the new position, based on the value (50), will be 50. + // If the newPosition is different than the old one, it must be updated, in order to emit + // the positionChanged signal. + d->pos = d->equivalentPosition(d->value); + + if (emitPosAtMinChanged) + emit positionAtMinimumChanged(d->posatmin); + if (emitPosAtMaxChanged) + emit positionAtMaximumChanged(d->posatmax); + + d->emitValueAndPositionIfChanged(value(), oldPosition); +} +/*! + Sets the range of valid values, that \l value can assume externally, with + \a min and \a max. The range has the following constraint: \a min must be less or equal \a max + Such range is represented by \l minimumValue and \l maximumValue +*/ + +void QRangeModel::setRange(qreal min, qreal max) +{ + Q_D(QRangeModel); + + bool emitMinimumChanged = !qFuzzyCompare(min, d->minimum); + bool emitMaximumChanged = !qFuzzyCompare(max, d->maximum); + + if (!(emitMinimumChanged || emitMaximumChanged)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + + d->minimum = min; + d->maximum = qMax(min, max); + + // Update internal position if it was changed. It can occurs if internal value changes, due to range update + d->pos = d->equivalentPosition(d->value); + + if (emitMinimumChanged) + emit minimumChanged(d->minimum); + if (emitMaximumChanged) + emit maximumChanged(d->maximum); + + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::minimumValue + \brief the minimum value that \l value can assume + + This property's default value is 0 +*/ + +void QRangeModel::setMinimum(qreal min) +{ + Q_D(const QRangeModel); + setRange(min, d->maximum); +} + +qreal QRangeModel::minimum() const +{ + Q_D(const QRangeModel); + return d->minimum; +} + +/*! + \property QRangeModel::maximumValue + \brief the maximum value that \l value can assume + + This property's default value is 99 +*/ + +void QRangeModel::setMaximum(qreal max) +{ + Q_D(const QRangeModel); + // if the new maximum value is smaller than + // minimum, update minimum too + setRange(qMin(d->minimum, max), max); +} + +qreal QRangeModel::maximum() const +{ + Q_D(const QRangeModel); + return d->maximum; +} + +/*! + \property QRangeModel::stepSize + \brief the value that is added to the \l value and \l position property + + Example: If a user sets a range of [0,100] and stepSize + to 30, the valid values that are going to be seen externally would be: 0, 30, 60, 90, 100. +*/ + +void QRangeModel::setStepSize(qreal stepSize) +{ + Q_D(QRangeModel); + + stepSize = qMax(qreal(0.0), stepSize); + if (qFuzzyCompare(stepSize, d->stepSize)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + d->stepSize = stepSize; + + emit stepSizeChanged(d->stepSize); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +qreal QRangeModel::stepSize() const +{ + Q_D(const QRangeModel); + return d->stepSize; +} + +/*! + Returns a valid position, respecting the \l positionAtMinimum, + \l positionAtMaximum and the \l stepSize properties. + Such calculation is based on the parameter \a value (which is valid externally). +*/ + +qreal QRangeModel::positionForValue(qreal value) const +{ + Q_D(const QRangeModel); + + const qreal unconstrainedPosition = d->equivalentPosition(value); + return d->publicPosition(unconstrainedPosition); +} + +/*! + \property QRangeModel::position + \brief the current position of the model + + Represents a valid external position, based on the \l positionAtMinimum, + \l positionAtMaximum and the \l stepSize properties. + The user can set it internally with a position, that is not within the current position range, + since it can become valid if the user changes the position range later. +*/ + +qreal QRangeModel::position() const +{ + Q_D(const QRangeModel); + + // Return the internal position but observe boundaries and + // stepSize restrictions. + return d->publicPosition(d->pos); +} + +void QRangeModel::setPosition(qreal newPosition) +{ + Q_D(QRangeModel); + + if (qFuzzyCompare(newPosition, d->pos)) + return; + + const qreal oldPosition = position(); + const qreal oldValue = value(); + + // Update position and calculate new value + d->pos = newPosition; + d->value = d->equivalentValue(d->pos); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::positionAtMinimum + \brief the minimum value that \l position can assume + + This property's default value is 0 +*/ + +void QRangeModel::setPositionAtMinimum(qreal min) +{ + Q_D(QRangeModel); + setPositionRange(min, d->posatmax); +} + +qreal QRangeModel::positionAtMinimum() const +{ + Q_D(const QRangeModel); + return d->posatmin; +} + +/*! + \property QRangeModel::positionAtMaximum + \brief the maximum value that \l position can assume + + This property's default value is 0 +*/ + +void QRangeModel::setPositionAtMaximum(qreal max) +{ + Q_D(QRangeModel); + setPositionRange(d->posatmin, max); +} + +qreal QRangeModel::positionAtMaximum() const +{ + Q_D(const QRangeModel); + return d->posatmax; +} + +/*! + Returns a valid value, respecting the \l minimumValue, + \l maximumValue and the \l stepSize properties. + Such calculation is based on the parameter \a position (which is valid externally). +*/ + +qreal QRangeModel::valueForPosition(qreal position) const +{ + Q_D(const QRangeModel); + + const qreal unconstrainedValue = d->equivalentValue(position); + return d->publicValue(unconstrainedValue); +} + +/*! + \property QRangeModel::value + \brief the current value of the model + + Represents a valid external value, based on the \l minimumValue, + \l maximumValue and the \l stepSize properties. + The user can set it internally with a value, that is not within the current range, + since it can become valid if the user changes the range later. +*/ + +qreal QRangeModel::value() const +{ + Q_D(const QRangeModel); + + // Return internal value but observe boundaries and + // stepSize restrictions + return d->publicValue(d->value); +} + +void QRangeModel::setValue(qreal newValue) +{ + Q_D(QRangeModel); + + if (qFuzzyCompare(newValue, d->value)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + + // Update relative value and position + d->value = newValue; + d->pos = d->equivalentPosition(d->value); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::inverted + \brief the model is inverted or not + + The model can be represented with an inverted behavior, e.g. when \l value assumes + the maximum value (represented by \l maximumValue) the \l position will be at its + minimum (represented by \l positionAtMinimum). +*/ + +void QRangeModel::setInverted(bool inverted) +{ + Q_D(QRangeModel); + if (inverted == d->inverted) + return; + + d->inverted = inverted; + emit invertedChanged(d->inverted); + + // After updating the internal value, the position property can change. + setPosition(d->equivalentPosition(d->value)); +} + +bool QRangeModel::inverted() const +{ + Q_D(const QRangeModel); + return d->inverted; +} + +/*! + Sets the \l value to \l minimumValue. +*/ + +void QRangeModel::toMinimum() +{ + Q_D(const QRangeModel); + setValue(d->minimum); +} + +/*! + Sets the \l value to \l maximumValue. +*/ + +void QRangeModel::toMaximum() +{ + Q_D(const QRangeModel); + setValue(d->maximum); +} diff --git a/src/qtdesktop/qrangemodel.h b/src/qtdesktop/qrangemodel.h new file mode 100644 index 00000000..675967ae --- /dev/null +++ b/src/qtdesktop/qrangemodel.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRANGEMODEL_H +#define QRANGEMODEL_H + +#include <QtCore/qobject.h> +//#include <QtGui/qgraphicsitem.h> +#include <QtWidgets/qabstractslider.h> +#include <QtQml/qqml.h> + +class QRangeModelPrivate; + +class QRangeModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged USER true) + Q_PROPERTY(qreal minimumValue READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY(qreal maximumValue READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal positionAtMinimum READ positionAtMinimum WRITE setPositionAtMinimum NOTIFY positionAtMinimumChanged) + Q_PROPERTY(qreal positionAtMaximum READ positionAtMaximum WRITE setPositionAtMaximum NOTIFY positionAtMaximumChanged) + Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged) + +public: + QRangeModel(QObject *parent = 0); + virtual ~QRangeModel(); + + void setRange(qreal min, qreal max); + void setPositionRange(qreal min, qreal max); + + void setStepSize(qreal stepSize); + qreal stepSize() const; + + void setMinimum(qreal min); + qreal minimum() const; + + void setMaximum(qreal max); + qreal maximum() const; + + void setPositionAtMinimum(qreal posAtMin); + qreal positionAtMinimum() const; + + void setPositionAtMaximum(qreal posAtMax); + qreal positionAtMaximum() const; + + void setInverted(bool inverted); + bool inverted() const; + + qreal value() const; + qreal position() const; + + Q_INVOKABLE qreal valueForPosition(qreal position) const; + Q_INVOKABLE qreal positionForValue(qreal value) const; + +public Q_SLOTS: + void toMinimum(); + void toMaximum(); + void setValue(qreal value); + void setPosition(qreal position); + +Q_SIGNALS: + void valueChanged(qreal value); + void positionChanged(qreal position); + + void stepSizeChanged(qreal stepSize); + + void invertedChanged(bool inverted); + + void minimumChanged(qreal min); + void maximumChanged(qreal max); + void positionAtMinimumChanged(qreal min); + void positionAtMaximumChanged(qreal max); + +protected: + QRangeModel(QRangeModelPrivate &dd, QObject *parent); + QRangeModelPrivate* d_ptr; + +private: + Q_DISABLE_COPY(QRangeModel) + Q_DECLARE_PRIVATE(QRangeModel) + +}; + +QML_DECLARE_TYPE(QRangeModel) + +#endif // QRANGEMODEL_H diff --git a/src/qtdesktop/qrangemodel_p.h b/src/qtdesktop/qrangemodel_p.h new file mode 100644 index 00000000..83b28949 --- /dev/null +++ b/src/qtdesktop/qrangemodel_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRANGEMODEL_P_H +#define QRANGEMODEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Components 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 "qrangemodel.h" + +class QRangeModelPrivate +{ + Q_DECLARE_PUBLIC(QRangeModel) +public: + QRangeModelPrivate(QRangeModel *qq); + virtual ~QRangeModelPrivate(); + + void init(); + + qreal posatmin, posatmax; + qreal minimum, maximum, stepSize, pos, value; + + uint inverted : 1; + + QRangeModel *q_ptr; + + inline qreal effectivePosAtMin() const { + return inverted ? posatmax : posatmin; + } + + inline qreal effectivePosAtMax() const { + return inverted ? posatmin : posatmax; + } + + inline qreal equivalentPosition(qreal value) const { + // Return absolute position from absolute value + const qreal valueRange = maximum - minimum; + if (valueRange == 0) + return effectivePosAtMin(); + + const qreal scale = (effectivePosAtMax() - effectivePosAtMin()) / valueRange; + return (value - minimum) * scale + effectivePosAtMin(); + } + + inline qreal equivalentValue(qreal pos) const { + // Return absolute value from absolute position + const qreal posRange = effectivePosAtMax() - effectivePosAtMin(); + if (posRange == 0) + return minimum; + + const qreal scale = (maximum - minimum) / posRange; + return (pos - effectivePosAtMin()) * scale + minimum; + } + + qreal publicPosition(qreal position) const; + qreal publicValue(qreal value) const; + void emitValueAndPositionIfChanged(const qreal oldValue, const qreal oldPosition); +}; + +#endif // QRANGEMODEL_P_H diff --git a/src/qtdesktop/qstyleitem.cpp b/src/qtdesktop/qstyleitem.cpp new file mode 100644 index 00000000..1acfb8b5 --- /dev/null +++ b/src/qtdesktop/qstyleitem.cpp @@ -0,0 +1,1072 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstyleitem.h" + +#include <QtGui/QPainter> +#include <QtWidgets/QStyle> +#include <QtWidgets/QStyleOption> +#include <QtWidgets/QApplication> +#include <QtWidgets/QMainWindow> +#include <QtWidgets/QGroupBox> +#include <QtWidgets/QToolBar> +#include <QtWidgets/QMenu> +#include <QtWidgets/QtWidgets> +#include <QtCore/QStringBuilder> + +#ifdef Q_OS_MAC +#include <Carbon/Carbon.h> + +static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect()) +{ + return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(), + convertRect.width() - rect.width(), convertRect.height() - rect.height()); +} + +/*! \internal + + Returns the CoreGraphics CGContextRef of the paint device. 0 is + returned if it can't be obtained. It is the caller's responsibility to + CGContextRelease the context when finished using it. + + \warning This function is only available on Mac OS X. + \warning This function is duplicated in qmacstyle_mac.mm +*/ +CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) +{ + + if (pdev->devType() == QInternal::Image) { + const QImage *i = static_cast<const QImage*>(pdev); + QImage *image = const_cast< QImage*>(i); + CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); + uint flags = kCGImageAlphaPremultipliedFirst; + flags |= kCGBitmapByteOrder32Host; + CGContextRef ret = 0; + + ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + + CGContextTranslateCTM(ret, 0, image->height()); + CGContextScaleCTM(ret, 1, -1); + return ret; + } + return 0; +} + +#endif + +QStyleItem::QStyleItem(QQuickPaintedItem *parent) + : QQuickPaintedItem(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_sharedWidget(false), + m_minimum(0), + m_maximum(100), + m_value(0), + m_step(0), + m_paintMargins(0), + m_contentWidth(0), + m_contentHeight(0) + +{ + m_font = qApp->font(); + setFlag(QQuickItem::ItemHasContents, true); + setSmooth(false); + + 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(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(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(hasFocusChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(elementTypeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(textChanged()), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(contentWidthChanged(int)), this, SLOT(updateSizeHint())); + connect(this, SIGNAL(contentHeightChanged(int)), this, SLOT(updateSizeHint())); +} + +QStyleItem::~QStyleItem() +{ + delete m_styleoption; + m_styleoption = 0; +} + +void QStyleItem::initStyleOption() +{ + QString type = elementType(); + if (m_styleoption) + m_styleoption->state = 0; + + switch (m_itemType) { + case Button: { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(m_styleoption); + opt->text = text(); + opt->features = (activeControl() == "default") ? + QStyleOptionButton::DefaultButton : + QStyleOptionButton::None; + } + break; + case ItemRow: { + if (!m_styleoption) + m_styleoption = new QStyleOptionViewItem(); + + QStyleOptionViewItem *opt = qstyleoption_cast<QStyleOptionViewItem*>(m_styleoption); + opt->features = 0; + if (activeControl() == "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<QStyleOptionViewItem*>(m_styleoption); + opt->features = QStyleOptionViewItem::HasDisplay; + opt->text = text(); + opt->textElideMode = Qt::ElideRight; + QPalette pal = m_styleoption->palette; + pal.setBrush(QPalette::Base, Qt::NoBrush); + m_styleoption->palette = pal; + } + break; + case Header: { + if (!m_styleoption) + m_styleoption = new QStyleOptionHeader(); + + QStyleOptionHeader *opt = qstyleoption_cast<QStyleOptionHeader*>(m_styleoption); + opt->text = text(); + opt->sortIndicator = activeControl() == "down" ? + QStyleOptionHeader::SortDown + : activeControl() == "up" ? + QStyleOptionHeader::SortUp : QStyleOptionHeader::None; + if (info() == QLatin1String("beginning")) + opt->position = QStyleOptionHeader::Beginning; + else if (info() == QLatin1String("end")) + opt->position = QStyleOptionHeader::End; + else if (info() == QLatin1String("only")) + opt->position = QStyleOptionHeader::OnlyOneSection; + else + opt->position = QStyleOptionHeader::Middle; + } + break; + case ToolButton: { + if (!m_styleoption) + m_styleoption = new QStyleOptionToolButton(); + + QStyleOptionToolButton *opt = + qstyleoption_cast<QStyleOptionToolButton*>(m_styleoption); + opt->subControls = QStyle::SC_ToolButton; + opt->state |= QStyle::State_AutoRaise; + opt->activeSubControls = QStyle::SC_ToolButton; + } + break; + case ToolBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionToolBar(); + } + break; + case Tab: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTab(); + + QStyleOptionTab *opt = qstyleoption_cast<QStyleOptionTab*>(m_styleoption); + opt->text = text(); + opt->shape = info() == "South" ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; + if (activeControl() == QLatin1String("beginning")) + opt->position = QStyleOptionTab::Beginning; + else if (activeControl() == QLatin1String("end")) + opt->position = QStyleOptionTab::End; + else if (activeControl() == QLatin1String("only")) + opt->position = QStyleOptionTab::OnlyOneTab; + else + opt->position = QStyleOptionTab::Middle; + + } break; + + case Menu: { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + } + break; + case Frame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrame(); + + QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(m_styleoption); + opt->frameShape = QFrame::StyledPanel; + opt->lineWidth = 1; + opt->midLineWidth = 1; + } + break; + case TabFrame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTabWidgetFrame(); + QStyleOptionTabWidgetFrame *opt = qstyleoption_cast<QStyleOptionTabWidgetFrame*>(m_styleoption); + opt->shape = (info() == "South") ? 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 MenuItem: + case ComboBoxItem: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + + QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(m_styleoption); + opt->checked = false; + opt->text = text(); + } + break; + case CheckBox: + case RadioButton: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(m_styleoption); + if (!on()) + opt->state |= QStyle::State_Off; + opt->text = text(); + } + break; + case Edit: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrame(); + + QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(m_styleoption); + opt->lineWidth = 1; // this must be non-zero + } + break; + case ComboBox :{ + if (!m_styleoption) + m_styleoption = new QStyleOptionComboBox(); + QStyleOptionComboBox *opt = qstyleoption_cast<QStyleOptionComboBox*>(m_styleoption); + opt->currentText = text(); + } + break; + case SpinBox: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSpinBox(); + + QStyleOptionSpinBox *opt = qstyleoption_cast<QStyleOptionSpinBox*>(m_styleoption); + opt->frame = true; + 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<QStyleOptionSlider*>(m_styleoption); + 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 + if (numOfSteps && (width() / numOfSteps < 5)) + opt->tickInterval = qRound((5*numOfSteps / width()) + 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() == "tick" ? + QSlider::TicksBelow : QSlider::NoTicks); + if (opt->tickPosition != QSlider::NoTicks) + opt->subControls |= QStyle::SC_SliderTickmarks; + + opt->activeSubControls = QStyle::SC_None; + } + break; + case ProgressBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionProgressBar(); + + QStyleOptionProgressBar *opt = qstyleoption_cast<QStyleOptionProgressBar*>(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<QStyleOptionGroupBox*>(m_styleoption); + opt->text = text(); + opt->lineWidth = 1; + opt->subControls = QStyle::SC_GroupBoxLabel; + opt->features = 0; + if (sunken()) { // Qt draws an ugly line here so I ignore it + opt->subControls |= QStyle::SC_GroupBoxFrame; + } else { + opt->features |= QStyleOptionFrame::Flat; + } + if (activeControl() == "checkbox") + opt->subControls |= QStyle::SC_GroupBoxCheckBox; + + } + break; + case ScrollBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSlider(); + + QStyleOptionSlider *opt = qstyleoption_cast<QStyleOptionSlider*>(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: + QStyle::SC_ScrollBarSlider; + + opt->sliderValue = value(); + opt->subControls = QStyle::SC_All; + + } + case MenuBar: + if (!m_styleoption) { + QStyleOptionMenuItem *menuOpt = new QStyleOptionMenuItem(); + menuOpt->menuItemType = QStyleOptionMenuItem::EmptyArea; + m_styleoption = menuOpt; + } + + break; + case MenuBarItem: + if (!m_styleoption) { + QStyleOptionMenuItem *menuOpt = new QStyleOptionMenuItem(); + menuOpt->text = text(); + menuOpt->menuItemType = QStyleOptionMenuItem::Normal; + m_styleoption = menuOpt; + } + break; + default: + break; + } + + if (!m_styleoption) + m_styleoption = new QStyleOption(); + + m_styleoption->styleObject = this; + m_styleoption->rect = QRect(m_paintMargins, m_paintMargins, width() - 2* m_paintMargins, height() - 2 * m_paintMargins); + + if (isEnabled()) + m_styleoption->state |= QStyle::State_Enabled; + if (m_active) + m_styleoption->state |= QStyle::State_Active; + 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; + + if (m_hint.indexOf("mini") != -1) { + m_styleoption->state |= QStyle::State_Mini; + } else if (m_hint.indexOf("small") != -1) { + m_styleoption->state |= QStyle::State_Small; + } + +} + +/* + * Property style + * + * Returns a simplified style name. + * + * QMacStyle = "mac" + * QWindowsXPStyle = "windowsxp" + * QFusionStyle = "fusion" + */ + +QString QStyleItem::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("style")) + style = style.left(style.length() - 5); + return style.toLower(); +} + +QString QStyleItem::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<QStyleOptionComplex*>(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SpinBoxUp) + return "up"; + else if (subcontrol == QStyle::SC_SpinBoxDown) + return "down"; + + } + break; + + case Slider: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_Slider, + qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SliderHandle) + return "handle"; + + } + break; + case ScrollBar: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_ScrollBar, + qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_ScrollBarSlider) + return "handle"; + + if (subcontrol == QStyle::SC_ScrollBarSubLine) + return "up"; + else if (subcontrol == QStyle::SC_ScrollBarSubPage) + return "upPage"; + + if (subcontrol == QStyle::SC_ScrollBarAddLine) + return "down"; + else if (subcontrol == QStyle::SC_ScrollBarAddPage) + return "downPage"; + } + break; + default: + break; + } + return "none"; +} + +QSize QStyleItem::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, 40); + break; + case ToolButton: { + QStyleOptionToolButton *btn = qstyleoption_cast<QStyleOptionToolButton*>(m_styleoption); + int newWidth = qMax(width, btn->fontMetrics.width(btn->text)); + int newHeight = qMax(height, btn->fontMetrics.height()); + size = qApp->style()->sizeFromContents(QStyle::CT_ToolButton, m_styleoption, QSize(newWidth, newHeight)); } + break; + case Button: { + QStyleOptionButton *btn = qstyleoption_cast<QStyleOptionButton*>(m_styleoption); + int newWidth = qMax(width, btn->fontMetrics.width(btn->text)); + int newHeight = qMax(height, btn->fontMetrics.height()); + size = qApp->style()->sizeFromContents(QStyle::CT_PushButton, m_styleoption, QSize(newWidth, newHeight)); } + break; + case ComboBox: { + QStyleOptionComboBox *btn = qstyleoption_cast<QStyleOptionComboBox*>(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 SpinBox: { + QStyleOptionSpinBox *box = qstyleoption_cast<QStyleOptionSpinBox*>(m_styleoption); + int newWidth = qMax(width, box->fontMetrics.width(QLatin1String("0.0"))); + int newHeight = qMax(height, box->fontMetrics.height()); + size = qApp->style()->sizeFromContents(QStyle::CT_SpinBox, 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 Edit: + size = qApp->style()->sizeFromContents(QStyle::CT_LineEdit, m_styleoption, QSize(width,height)); + if (hint().indexOf("rounded") != -1) + size += QSize(0, 3); + break; + case GroupBox: + size = qApp->style()->sizeFromContents(QStyle::CT_GroupBox, m_styleoption, QSize(width,height)); + break; + case Header: + size = qApp->style()->sizeFromContents(QStyle::CT_HeaderSection, m_styleoption, QSize(width,height)); +#ifdef Q_OS_MAC + if (style() =="mac") + size.setHeight(15); +#endif + break; + case ItemRow: + case Item: //fall through + size = qApp->style()->sizeFromContents(QStyle::CT_ItemViewItem, m_styleoption, QSize(width,height)); + break; + case MenuBarItem: //fall through + size = qApp->style()->sizeFromContents(QStyle::CT_MenuBarItem, m_styleoption, QSize(width,height)); + break; + case MenuBar: //fall through + size = qApp->style()->sizeFromContents(QStyle::CT_MenuBar, m_styleoption, QSize(width,height)); + break; + default: + break; + } + return size; +} + +void QStyleItem::updateSizeHint() +{ + QSize implicitSize = sizeFromContents(m_contentWidth, m_contentHeight); + setImplicitSize(implicitSize.width(), implicitSize.height()); +} + +int QStyleItem::pixelMetric(const QString &metric) +{ + + if (metric == "scrollbarExtent") + return qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0) + 1; + else if (metric == "defaultframewidth") + return qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0); + else if (metric == "taboverlap") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ); + else if (metric == "tabbaseoverlap") + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, 0 ); + else if (metric == "tabhspace") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabHSpace, 0 ); + else if (metric == "indicatorwidth") + return qApp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, 0 ); + else if (metric == "tabvspace") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabVSpace, 0 ); + else if (metric == "tabbaseheight") + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0 ); + else if (metric == "tabvshift") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, 0 ); + else if (metric == "menuhmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuHMargin, 0 ); + else if (metric == "menuvmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuVMargin, 0 ); + else if (metric == "menupanelwidth") + return qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0 ); + else if (metric == "splitterwidth") + return qApp->style()->pixelMetric(QStyle::PM_SplitterWidth, 0 ); + else if (metric == "scrollbarspacing") + return abs(qApp->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, 0 )); + return 0; +} + +QVariant QStyleItem::styleHint(const QString &metric) +{ + initStyleOption(); + if (metric == "comboboxpopup") { + return qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, m_styleoption); + } else if (metric == "highlightedTextColor") { + return qApp->palette().highlightedText().color().name(); + } else if (metric == "textColor") { + return qApp->palette().text().color().name(); + } else if (metric == "focuswidget") { + return qApp->style()->styleHint(QStyle::SH_FocusFrame_AboveWidget); + } else if (metric == "tabbaralignment") { + int result = qApp->style()->styleHint(QStyle::SH_TabBar_Alignment); + if (result == Qt::AlignCenter) + return "center"; + return "left"; + } else if (metric == "framearoundcontents") { + return qApp->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents); + } else if (metric == "scrollToClickPosition") + return qApp->style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition); + return 0; +} + +void QStyleItem::setHint(const QStringList &str) +{ + if (m_hint != str) { + m_hint = 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(); + } + } +} + + +void QStyleItem::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 == "menu" || str == "menuitem") { + m_itemType = (str == "menu") ? Menu : MenuItem; + } else if (str == "item" || str == "itemrow" || str == "header") { +#ifdef Q_OS_MAC + m_font.setPointSize(11.0); + emit fontChanged(); +#endif + if (str == "header") { + m_itemType = Header; + } else { + m_itemType = (str == "item") ? Item : ItemRow; + } + } else if (str == "groupbox") { + m_itemType = GroupBox; + } else if (str == "tab") { + m_itemType = Tab; + } else if (str == "tabframe") { + m_itemType = TabFrame; + } else if (str == "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 == "toolbar") { + m_itemType = ToolBar; + } else if (str == "toolbutton") { + m_itemType = ToolButton; + } else if (str == "slider") { + m_itemType = Slider; + } else if (str == "frame") { + m_itemType = Frame; + } else if (str == "combobox") { + m_itemType = ComboBox; + } else if (str == "splitter") { + m_itemType = Splitter; + } else if (str == "progressbar") { + m_itemType = ProgressBar; + } else if (str == "button") { + m_itemType = Button; + } else if (str == "checkbox") { + m_itemType = CheckBox; + } else if (str == "radiobutton") { + m_itemType = RadioButton; + } else if (str == "edit") { + m_itemType = Edit; + } else if (str == "spinbox") { + m_itemType = SpinBox; + } else if (str == "scrollbar") { + m_itemType = ScrollBar; + } else if (str == "widget") { + m_itemType = Widget; + } else if (str == "focusframe") { + m_itemType = FocusFrame; + } else if (str == "dial") { + m_itemType = Dial; + } else if (str == "statusbar") { + m_itemType = StatusBar; + } else if (str == "machelpbutton") { + m_itemType = MacHelpButton; + } else if (str == "scrollareacorner") { + m_itemType = ScrollAreaCorner; + } else if (str == "menubar") { + m_itemType = MenuBar; + } else if (str == "menubaritem") { + m_itemType = MenuBarItem; + } else { + m_itemType = Undefined; + } + updateSizeHint(); +} + +QRectF QStyleItem::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<QStyleOptionComplex*>(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<QStyleOptionComplex*>(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<QStyleOptionComplex*>(m_styleoption), + subcontrol); + } + break; + default: + break; + } + return QRectF(); +} + +void QStyleItem::paint(QPainter *painter) +{ + if (width() < 1 || height() <1) + return; + + initStyleOption(); + + 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 (!qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected) && selected()) + pixpainter.fillRect(m_styleoption->rect, m_styleoption->palette.highlight()); + QPixmapCache::insert(pmKey, pixmap); + } + painter->drawPixmap(0, 0, pixmap); + } + break; + case Item: + qApp->style()->drawControl(QStyle::CE_ItemViewItem, m_styleoption, painter); + break; + case Header: + qApp->style()->drawControl(QStyle::CE_Header, m_styleoption, painter); + break; + case ToolButton: + +#ifdef Q_OS_MAC + if (style() == "mac" && hint().indexOf("segmented") != -1) { + const QPaintDevice *target = painter->device(); + HIThemeSegmentDrawInfo sgi; + sgi.version = 0; + sgi.state = isEnabled() ? kThemeStateActive : kThemeStateDisabled; + if (sunken()) sgi.state |= kThemeStatePressed; + sgi.size = kHIThemeSegmentSizeNormal; + sgi.kind = kHIThemeSegmentKindTextured; + sgi.value = on() && !sunken() ? kThemeButtonOn : kThemeButtonOff; + + sgi.adornment |= kHIThemeSegmentAdornmentLeadingSeparator; + if (sunken()) { + sgi.adornment |= kHIThemeSegmentAdornmentTrailingSeparator; + } + SInt32 button_height; + GetThemeMetric(kThemeMetricButtonRoundedHeight, &button_height); + sgi.position = info() == "leftmost" ? kHIThemeSegmentPositionFirst: + info() == "rightmost" ? kHIThemeSegmentPositionLast : + info() == "h_middle" ? kHIThemeSegmentPositionMiddle : + kHIThemeSegmentPositionOnly; + QRect centered = m_styleoption->rect; + centered.setHeight(button_height); + centered.moveCenter(m_styleoption->rect.center()); + HIRect hirect = qt_hirectForQRect(centered.translated(0, -1), QRect(0, 0, 0, 0)); + HIThemeDrawSegment(&hirect, &sgi, qt_mac_cg_context(target), kHIThemeOrientationNormal); + } else +#endif + qApp->style()->drawComplexControl(QStyle::CC_ToolButton, qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), painter); + break; + case Tab: + qApp->style()->drawControl(QStyle::CE_TabBarTab, m_styleoption, painter); + break; + case Frame: + qApp->style()->drawControl(QStyle::CE_ShapedFrame, m_styleoption, painter); + break; + case FocusFrame: + if (style() == "mac" && hint().indexOf("rounded") != -1) + break; // embedded in the line itself + else + qApp->style()->drawControl(QStyle::CE_FocusFrame, 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 + qApp->style()->drawControl(QStyle::CE_MenuItem, 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: { +#ifdef Q_OS_MAC + if (style() == "mac" && hint().indexOf("rounded") != -1) { + const QPaintDevice *target = painter->device(); + HIThemeFrameDrawInfo fdi; + fdi.version = 0; + fdi.state = kThemeStateActive; + SInt32 frame_size; + GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size); + fdi.kind = kHIThemeFrameTextFieldRound; + if ((m_styleoption->state & QStyle::State_ReadOnly) || !(m_styleoption->state & QStyle::State_Enabled)) + fdi.state = kThemeStateInactive; + fdi.isFocused = hasFocus(); + HIRect hirect = qt_hirectForQRect(m_styleoption->rect, + QRect(frame_size, frame_size, + frame_size * 2, frame_size * 2)); + HIThemeDrawFrame(&hirect, &fdi, qt_mac_cg_context(target), kHIThemeOrientationNormal); + } else +#endif + qApp->style()->drawPrimitive(QStyle::PE_PanelLineEdit, m_styleoption, painter); + } + break; + case MacHelpButton: +#ifdef Q_OS_MAC + { + const QPaintDevice *target = painter->device(); + HIThemeButtonDrawInfo fdi; + fdi.kind = kThemeRoundButtonHelp; + fdi.version = 0; + fdi.adornment = 0; + fdi.state = sunken() ? kThemeStatePressed : kThemeStateActive; + HIRect hirect = qt_hirectForQRect(m_styleoption->rect,QRect(0, 0, 0, 0)); + HIThemeDrawButton(&hirect, &fdi, qt_mac_cg_context(target), kHIThemeOrientationNormal, NULL); + } +#endif + 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<QStyleOptionComplex*>(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: + qApp->style()->drawComplexControl(QStyle::CC_SpinBox, + qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), + painter); + break; + case Slider: + qApp->style()->drawComplexControl(QStyle::CC_Slider, + qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), + painter); + break; + case Dial: + qApp->style()->drawComplexControl(QStyle::CC_Dial, + qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), + painter); + break; + case ProgressBar: + qApp->style()->drawControl(QStyle::CE_ProgressBar, m_styleoption, painter); + break; + case ToolBar: + qApp->style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter); + break; + case StatusBar: + if (style() == "mac") { + m_styleoption->rect.adjust(0, 1, 0, 0); + qApp->style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter); + m_styleoption->rect.adjust(0, -1, 0, 0); + painter->setPen(m_styleoption->palette.dark().color().darker(120)); + painter->drawLine(m_styleoption->rect.topLeft(), m_styleoption->rect.topRight()); + } else { + qApp->style()->drawPrimitive(QStyle::PE_PanelToolBar, m_styleoption, painter); + } + break; + case GroupBox: + qApp->style()->drawComplexControl(QStyle::CC_GroupBox, qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), painter); + break; + case ScrollBar: + qApp->style()->drawComplexControl(QStyle::CC_ScrollBar, qstyleoption_cast<QStyleOptionComplex*>(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); + + QStyleOptionFrame frame; + frame.lineWidth = qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth); + frame.midLineWidth = 0; + frame.rect = m_styleoption->rect; + qApp->style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, painter); + } + break; + default: + break; + } +} + +int QStyleItem::textWidth(const QString &text) +{ + return QFontMetrics(m_font).boundingRect(text).width(); +} + +QString QStyleItem::elidedText(const QString &text, int elideMode, int width) +{ + return qApp->fontMetrics().elidedText(text, Qt::TextElideMode(elideMode), width); +} + +bool QStyleItem::hasThemeIcon(const QString &icon) const +{ + return QIcon::hasThemeIcon(icon); +} diff --git a/src/qtdesktop/qstyleitem.h b/src/qtdesktop/qstyleitem.h new file mode 100644 index 00000000..6b274060 --- /dev/null +++ b/src/qtdesktop/qstyleitem.h @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STYLEWRAPPER_H +#define STYLEWRAPPER_H + +#include <QtQuick/qquickpainteditem.h> +#include <QtWidgets/QStyle> +#include <QEvent> + +class QStyleItem: public QQuickPaintedItem +{ + Q_OBJECT + + 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( 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 info READ info WRITE setInfo NOTIFY infoChanged) + Q_PROPERTY( QString style READ style NOTIFY styleChanged) + Q_PROPERTY( QStringList hint READ hint WRITE setHint NOTIFY hintChanged) + 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) + +public: + QStyleItem(QQuickPaintedItem *parent = 0); + ~QStyleItem(); + + enum Type { + Undefined, + Button, + RadioButton, + CheckBox, + ComboBox, + ComboBoxItem, + Dial, + ToolBar, + ToolButton, + Tab, + TabFrame, + Frame, + FocusFrame, + SpinBox, + Slider, + ScrollBar, + ProgressBar, + Edit, + GroupBox, + Header, + Item, + ItemRow, + 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; } + + 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; } + QString info() const { return m_info; } + QStringList hint() const { return m_hint; } + 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 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;} } + 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 setInfo(const QString &str) { if (m_info != str) {m_info = str; emit infoChanged();}} + void setHint(const QStringList &str); + + int contentWidth() const { return m_contentWidth; } + int contentHeight() const { return m_contentHeight; } + + virtual void initStyleOption (); + +public Q_SLOTS: + int pixelMetric(const QString&); + QVariant styleHint(const QString&); + void updateSizeHint(); + void updateItem(){initStyleOption(); update();} + QString hitTest(int x, int y); + QRectF subControlRect(const QString &subcontrolString); + QString elidedText(const QString &text, int elideMode, int width); + int textWidth(const QString &); + bool hasThemeIcon(const QString &) const; + + void setContentWidth(int arg) + { + if (m_contentWidth != arg) { + m_contentWidth = arg; + emit contentWidthChanged(arg); + } + } + + void setContentHeight(int arg) + { + if (m_contentHeight != arg) { + m_contentHeight = arg; + emit contentHeightChanged(arg); + } + } + +Q_SIGNALS: + void elementTypeChanged(); + void textChanged(); + void sunkenChanged(); + void raisedChanged(); + void activeChanged(); + void selectedChanged(); + void hasFocusChanged(); + void onChanged(); + void hoverChanged(); + void horizontalChanged(); + void minimumChanged(); + void maximumChanged(); + void stepChanged(); + void valueChanged(); + void activeControlChanged(); + void infoChanged(); + void styleChanged(); + void paintMarginsChanged(); + void hintChanged(); + void fontChanged(); + + void contentWidthChanged(int arg); + void contentHeightChanged(int arg); + +private: + QSize sizeFromContents(int width, int height); + +protected: + QWidget *m_dummywidget; + QStyleOption *m_styleoption; + Type m_itemType; + + QString m_type; + QString m_text; + QString m_activeControl; + QString m_info; + QStringList m_hint; + 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_sharedWidget; + + int m_minimum; + int m_maximum; + int m_value; + int m_step; + int m_paintMargins; + + int m_contentWidth; + int m_contentHeight; + +}; + +#endif //STYLEWRAPPER_H diff --git a/src/qtdesktop/qstyleplugin.cpp b/src/qtdesktop/qstyleplugin.cpp new file mode 100644 index 00000000..500d4ee6 --- /dev/null +++ b/src/qtdesktop/qstyleplugin.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qqml.h> +#include "qstyleplugin.h" +#include "qstyleitem.h" +#include "qrangemodel.h" +#include "qtmenu.h" +#include "qtmenubar.h" +#include "qdesktopitem.h" +#include "qwheelarea.h" +#include "qtsplitterbase.h" +#include "qquicklinearlayout.h" +#include "qquickcomponentsprivate.h" +#include "qfiledialogitem.h" +#include <qqmlextensionplugin.h> + +#include <qqmlengine.h> +#include <qquickimageprovider.h> +#include <QtWidgets/QApplication> +#include <QtQuick/QQuickWindow> +#include <QImage> + +// Load icons from desktop theme +class DesktopIconProvider : public QQuickImageProvider +{ +public: + DesktopIconProvider() + : QQuickImageProvider(QQuickImageProvider::Pixmap) + { + } + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) + { + Q_UNUSED(requestedSize); + Q_UNUSED(size); + int pos = id.lastIndexOf('/'); + QString iconName = id.right(id.length() - pos); + int width = requestedSize.width(); + return QIcon::fromTheme(iconName).pixmap(width); + } +}; + +QObject *registerPrivateModule(QQmlEngine *engine, QJSEngine *jsEngine) +{ + Q_UNUSED(engine); + Q_UNUSED(jsEngine); + return new QQuickComponentsPrivate(); +} + +void StylePlugin::registerTypes(const char *uri) +{ + + // Unfortunately animations do not work on mac without this hack +#ifdef Q_OS_MAC + setenv("QML_BAD_GUI_RENDER_LOOP", "1", 0); +#endif + + qmlRegisterSingletonType<QQuickComponentsPrivate>(uri, 1, 0, "PrivateHelper", registerPrivateModule); + + qmlRegisterType<QStyleItem>(uri, 1, 0, "StyleItem"); + qmlRegisterType<QRangeModel>(uri, 1, 0, "RangeModel"); + qmlRegisterType<QWheelArea>(uri, 1, 0, "WheelArea"); + + qmlRegisterType<QtMenu>(uri, 1, 0, "Menu"); + qmlRegisterType<QtMenuBar>(uri, 1, 0, "MenuBar"); + qmlRegisterType<QtMenuItem>(uri, 1, 0, "MenuItem"); + qmlRegisterType<QtMenuSeparator>(uri, 1, 0, "Separator"); + + qmlRegisterType<QQuickComponentsRowLayout>(uri, 1, 0, "RowLayout"); + qmlRegisterType<QQuickComponentsColumnLayout>(uri, 1, 0, "ColumnLayout"); + qmlRegisterUncreatableType<QQuickComponentsLayout>(uri, 1, 0, "Layout", + QLatin1String("Do not create objects of type Layout")); + + qmlRegisterType<QFileDialogItem>(uri, 1, 0, "FileDialog"); + + qmlRegisterType<QFileSystemModel>(uri, 1, 0, "FileSystemModel"); + qmlRegisterType<QtSplitterBase>(uri, 1, 0, "Splitter"); + qmlRegisterType<QQuickWindow>(uri, 1, 0, "Window"); + + qmlRegisterUncreatableType<QtMenuBase>(uri, 1, 0, "NativeMenuBase", QLatin1String("Do not create objects of type NativeMenuBase")); + qmlRegisterUncreatableType<QDesktopItem>(uri, 1, 0,"Desktop", QLatin1String("Do not create objects of type Desktop")); +} + +void StylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) +{ + Q_UNUSED(uri); + engine->addImageProvider("desktoptheme", new DesktopIconProvider); +} diff --git a/src/qtdesktop/qstyleplugin.h b/src/qtdesktop/qstyleplugin.h new file mode 100644 index 00000000..2bdb2a81 --- /dev/null +++ b/src/qtdesktop/qstyleplugin.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STYLEPLUGIN_H +#define STYLEPLUGIN_H + +#include <QQmlExtensionPlugin> +#include <QtCore/QTimer> +#include <QtWidgets/QFileSystemModel> + +class StylePlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.playground.qtdesktopcomponents.QQmlExtensionInterface" FILE "styleplugin.json") +public: + void registerTypes(const char *uri); + void initializeEngine(QQmlEngine *engine, const char *uri); +}; + +#endif // STYLEPLUGIN_H diff --git a/src/qtdesktop/qtdesktop.pro b/src/qtdesktop/qtdesktop.pro new file mode 100644 index 00000000..d348cd71 --- /dev/null +++ b/src/qtdesktop/qtdesktop.pro @@ -0,0 +1,58 @@ +QT += qml quick widgets + +TARGETPATH = QtDesktop + +QML_FILES = \ + ApplicationWindow.qml \ + Button.qml \ + ButtonColumn.qml \ + ButtonRow.qml \ + CheckBox.qml \ + ComboBox.qml \ + ContextMenu.qml \ + Dial.qml \ + Dialog.qml \ + Frame.qml \ + GroupBox.qml \ + Label.qml \ + ProgressBar.qml \ + RadioButton.qml \ + ScrollArea.qml \ + ScrollBar.qml \ + Slider.qml \ + SpinBox.qml \ + SplitterColumn.qml \ + SplitterRow.qml \ + StatusBar.qml \ + Tab.qml \ + TabBar.qml \ + TabFrame.qml \ + TableColumn.qml \ + TableView.qml \ + TextArea.qml \ + TextField.qml \ + ToolBar.qml \ + ToolButton.qml + +# private qml files +QML_FILES += \ + private/BasicButton.qml \ + private/ButtonBehavior.qml \ + private/ButtonGroup.js \ + private/ModalPopupBehavior.qml \ + private/ScrollAreaHelper.qml \ + private/Splitter.qml + +include(styleplugin.pri) + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 + +mac { + LIBS += -framework Carbon +} + +load(qml_plugin) + +#tmp solution for QTBUG-28200 +TARGET = $$qtLibraryTarget(styleplugin) +DESTDIR = $$QT.core.qml/QtDesktop/plugin diff --git a/src/qtdesktop/qtmenu.cpp b/src/qtdesktop/qtmenu.cpp new file mode 100644 index 00000000..34710293 --- /dev/null +++ b/src/qtdesktop/qtmenu.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmenu.h" +#include "qdebug.h" +#include <qapplication.h> +#include <qmenubar.h> +#include <qabstractitemmodel.h> + +QtMenu::QtMenu(QQuickItem *parent) + : QtMenuBase(parent), + dummy(0), + m_selectedIndex(0), + m_highlightedIndex(0), + m_hasNativeModel(false) +{ + m_qmenu = new QMenu(0); + connect(m_qmenu, SIGNAL(aboutToHide()), this, SIGNAL(menuClosed())); +} + +QtMenu::~QtMenu() +{ + delete m_qmenu; +} + +void QtMenu::setText(const QString &text) +{ + m_qmenu->setTitle(text); + emit textChanged(); +} + +QString QtMenu::text() const +{ + return m_qmenu->title(); +} + +void QtMenu::setSelectedIndex(int index) +{ + m_selectedIndex = index; + QList<QAction *> actionList = m_qmenu->actions(); + if (m_selectedIndex >= 0 && m_selectedIndex < actionList.size()) + m_qmenu->setActiveAction(actionList[m_selectedIndex]); + emit selectedIndexChanged(); +} + +void QtMenu::setHoveredIndex(int index) +{ + m_highlightedIndex = index; + QList<QAction *> actionList = m_qmenu->actions(); + if (m_highlightedIndex >= 0 && m_highlightedIndex < actionList.size()) + m_qmenu->setActiveAction(actionList[m_highlightedIndex]); + emit hoveredIndexChanged(); +} + +QQmlListProperty<QtMenuBase> QtMenu::menuItems() +{ + return QQmlListProperty<QtMenuBase>(this, 0, &QtMenu::append_qmenuItem, 0, 0, 0); +} + +void QtMenu::showPopup(qreal x, qreal y, int atActionIndex, QQuickWindow * parentWindow) +{ + if (m_qmenu->isVisible()) + return; + + // If atActionIndex is valid, x and y is specified from the + // the position of the corresponding QAction: + QAction *atAction = 0; + if (atActionIndex >= 0 && atActionIndex < m_qmenu->actions().size()) + atAction = m_qmenu->actions()[atActionIndex]; + + QPointF screenPosition(mapToScene(QPoint(x, y))); + QWindow *tw = parentWindow ? parentWindow : window(); + if (tw) { + screenPosition = tw->mapToGlobal(QPoint(x, y)); + + // calling winId forces a QWindow to be created + // since this needs to be a top-level + // otherwise windowHandle might return 0 + m_qmenu->winId(); + m_qmenu->windowHandle()->setTransientParent(tw); + } + + setHoveredIndex(m_selectedIndex); + m_qmenu->popup(screenPosition.toPoint(), atAction); +} + +void QtMenu::hidePopup() +{ + m_qmenu->close(); +} + +QAction* QtMenu::action() +{ + return m_qmenu->menuAction(); +} + +Q_INVOKABLE void QtMenu::clearMenuItems() +{ + m_qmenu->clear(); + foreach (QtMenuBase *item, m_qmenuItems) { + delete item; + } + m_qmenuItems.clear(); +} + +void QtMenu::addMenuItem(const QString &text) +{ + QtMenuItem *menuItem = new QtMenuItem(this); + menuItem->setText(text); + m_qmenuItems.append(menuItem); + m_qmenu->addAction(menuItem->action()); + + connect(menuItem->action(), SIGNAL(triggered()), this, SLOT(emitSelected())); + connect(menuItem->action(), SIGNAL(hovered()), this, SLOT(emitHovered())); + + if (m_qmenu->actions().size() == 1) + // Inform QML that the selected action (0) now has changed contents: + emit selectedIndexChanged(); +} + +void QtMenu::emitSelected() +{ + QAction *act = qobject_cast<QAction *>(sender()); + if (!act) + return; + m_selectedIndex = m_qmenu->actions().indexOf(act); + emit selectedIndexChanged(); +} + +void QtMenu::emitHovered() +{ + QAction *act = qobject_cast<QAction *>(sender()); + if (!act) + return; + m_highlightedIndex = m_qmenu->actions().indexOf(act); + emit hoveredIndexChanged(); +} + +QString QtMenu::itemTextAt(int index) const +{ + QList<QAction *> actionList = m_qmenu->actions(); + if (index >= 0 && index < actionList.size()) + return actionList[index]->text(); + else + return ""; +} + +QString QtMenu::modelTextAt(int index) const +{ + if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) { + return model->data(model->index(index, 0)).toString(); + } else if (m_model.canConvert(QVariant::StringList)) { + return m_model.toStringList().at(index); + } + return ""; +} + +int QtMenu::modelCount() const +{ + if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) { + return model->rowCount(); + } else if (m_model.canConvert(QVariant::StringList)) { + return m_model.toStringList().count(); + } + return -1; +} + +void QtMenu::append_qmenuItem(QQmlListProperty<QtMenuBase> *list, QtMenuBase *menuItem) +{ + QtMenu *menu = qobject_cast<QtMenu *>(list->object); + if (menu) { + menuItem->setParent(menu); + menu->m_qmenuItems.append(menuItem); + menu->qmenu()->addAction(menuItem->action()); + } +} + +void QtMenu::setModel(const QVariant &newModel) { + if (m_model != newModel) { + + // Clean up any existing connections + if (QAbstractItemModel *oldModel = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) { + disconnect(oldModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(rebuildMenu())); + } + + m_hasNativeModel = false; + m_model = newModel; + + if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(newModel.value<QObject*>())) { + m_hasNativeModel = true; + connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(rebuildMenu())); + } else if (newModel.canConvert(QVariant::StringList)) { + m_hasNativeModel = true; + } + emit modelChanged(m_model); + } +} diff --git a/src/qtdesktop/qtmenu.h b/src/qtdesktop/qtmenu.h new file mode 100644 index 00000000..d718b55b --- /dev/null +++ b/src/qtdesktop/qtmenu.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMLMENU_H +#define QTMLMENU_H +#include <QtCore/qglobal.h> +#include <QtWidgets/qmenu.h> +#include <QtQuick/QtQuick> +#include <QtQml/QtQml> +#include <QtCore/qabstractitemmodel.h> +#include <QtCore/QVariant> +#include "qtmenuitem.h" + +class QtMenu : public QtMenuBase +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedIndexChanged) + Q_PROPERTY(int hoveredIndex READ hoveredIndex WRITE setHoveredIndex NOTIFY hoveredIndexChanged) + Q_PROPERTY(QQmlListProperty<QtMenuBase> menuItems READ menuItems) + Q_CLASSINFO("DefaultProperty", "menuItems") +public: + QtMenu(QQuickItem *parent = 0); + virtual ~QtMenu(); + + void setText(const QString &text); + QString text() const; + + int selectedIndex() const { return m_selectedIndex; } + void setSelectedIndex(int index); + int hoveredIndex() const { return m_highlightedIndex; } + void setHoveredIndex(int index); + + QQmlListProperty<QtMenuBase> menuItems(); + + QMenu* qmenu() { return m_qmenu; } + + QAction* action(); + + Q_INVOKABLE int minimumWidth() const { return m_qmenu->minimumWidth(); } + Q_INVOKABLE void setMinimumWidth(int w) { m_qmenu->setMinimumWidth(w); } + Q_INVOKABLE void showPopup(qreal x, qreal y, int atActionIndex = -1, QQuickWindow *window = 0); + Q_INVOKABLE void hidePopup(); + Q_INVOKABLE void clearMenuItems(); + Q_INVOKABLE void addMenuItem(const QString &text); + Q_INVOKABLE QString itemTextAt(int index) const; + Q_INVOKABLE QString modelTextAt(int index) const; + Q_INVOKABLE int modelCount() const; + + QVariant model() const { return m_model; } + Q_INVOKABLE bool hasNativeModel() const { return m_hasNativeModel; } + +public slots: + void setModel(const QVariant &newModel); + +public: +Q_SIGNALS: + void menuClosed(); + void selectedIndexChanged(); + void hoveredIndexChanged(); + void modelChanged(const QVariant &newModel); + void rebuildMenu(); + void textChanged(); + +private Q_SLOTS: + void emitSelected(); + void emitHovered(); + +private: + static void append_qmenuItem(QQmlListProperty<QtMenuBase> *list, QtMenuBase *menuItem); + + QWidget *dummy; + QMenu *m_qmenu; + QList<QtMenuBase *> m_qmenuItems; + int m_selectedIndex; + int m_highlightedIndex; + bool m_hasNativeModel; + QVariant m_model; +}; + +QML_DECLARE_TYPE(QtMenu) + +#endif // QTMLMENU_H diff --git a/src/qtdesktop/qtmenubar.cpp b/src/qtdesktop/qtmenubar.cpp new file mode 100644 index 00000000..f63f5562 --- /dev/null +++ b/src/qtdesktop/qtmenubar.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmenubar.h" + +#include <QtWidgets/QMenu> +#include <QtWidgets/QMenuBar> + +QtMenuBar::QtMenuBar(QQuickItem *parent) + : QQuickItem(parent) +{ + connect(this, SIGNAL(parentChanged(QQuickItem *)), this, SLOT(updateParent(QQuickItem *))); + setFlag(QQuickItem::ItemHasContents, false); +#ifdef Q_OS_MAC + _menuBar = new QMenuBar(0); +#endif +} + +QtMenuBar::~QtMenuBar() +{ +} + +QQmlListProperty<QtMenu> QtMenuBar::menus() +{ + return QQmlListProperty<QtMenu>(this, 0, &QtMenuBar::append_menu, 0, 0, 0); +} + +QList<QObject*> QtMenuBar::menuList() +{ + return m_menus; +} + +void QtMenuBar::updateParent(QQuickItem *newParent) +{ +#ifdef Q_OS_MAC + _menuBar->clear(); + foreach (QObject *obj, m_menus) { + QtMenu *menu = qobject_cast<QtMenu*>(obj); + _menuBar->addMenu(menu->qmenu()); + } +#endif +} + +void QtMenuBar::append_menu(QQmlListProperty<QtMenu> *list, QtMenu *menu) +{ + QtMenuBar *menuBar = qobject_cast<QtMenuBar *>(list->object); + if (menuBar) { + menu->setParent(menuBar); + menuBar->m_menus.append(menu); +#ifdef Q_OS_MAC + if (menuBar->_menuBar) + menuBar->_menuBar->addMenu(menu->qmenu()); +#endif + menuBar->menuChanged(); + } +} diff --git a/src/qtdesktop/qtmenubar.h b/src/qtdesktop/qtmenubar.h new file mode 100644 index 00000000..6f762bb7 --- /dev/null +++ b/src/qtdesktop/qtmenubar.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMENUBAR_H +#define QTMENUBAR_H + +#include <QtCore/qglobal.h> + +#include <QtQuick/QQuickItem> +#include <QtWidgets> + +#include "qtmenu.h" + +class QtMenuBar: public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QQmlListProperty<QtMenu> menus READ menus NOTIFY menuChanged) + Q_PROPERTY(QList<QObject*> menuList READ menuList NOTIFY menuChanged) + Q_PROPERTY(bool showMenuBar READ showMenuBar NOTIFY showMenuBarChanged) + Q_CLASSINFO("DefaultProperty", "menus") +public: + QtMenuBar(QQuickItem *parent = 0); + ~QtMenuBar(); + + QQmlListProperty<QtMenu> menus(); + QList<QObject*> menuList(); + + bool showMenuBar() { +#ifdef Q_OS_MAC + return false; +#endif + return true; +} + +signals: + void menuChanged(); + void showMenuBarChanged(); + +protected Q_SLOTS: + void updateParent(QQuickItem *newParent); + +private: + static void append_menu(QQmlListProperty<QtMenu> *list, QtMenu *menu); + +private: + QList<QObject *> m_menus; + QMenuBar *_menuBar; +}; + +#endif //QTMENUBAR_H diff --git a/src/qtdesktop/qtmenuitem.cpp b/src/qtdesktop/qtmenuitem.cpp new file mode 100644 index 00000000..9dc58af7 --- /dev/null +++ b/src/qtdesktop/qtmenuitem.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmenuitem.h" + +void QtMenuBase::setIconSource(const QUrl &icon) +{ + _iconSource = icon; + if (_iconName.isEmpty()) + action()->setIcon(QIcon(icon.toLocalFile())); + else + action()->setIcon(QIcon::fromTheme(_iconName, QIcon(_iconSource.toLocalFile()))); + + emit iconSourceChanged(); +} + +QUrl QtMenuBase::iconSource() const +{ + return _iconSource; +} + +void QtMenuBase::setIconName(const QString &icon) +{ + _iconName = icon; + action()->setIcon(QIcon::fromTheme(_iconName, QIcon(_iconSource.toLocalFile()))); + + emit iconNameChanged(); +} + +QString QtMenuBase::iconName() const +{ + return _iconName; +} + +QtMenuSeparator::QtMenuSeparator(QQuickItem *parent) + : QtMenuBase(parent), _action(new QAction(this)) +{ + _action->setSeparator(true); +} + +QtMenuSeparator::~QtMenuSeparator() +{ +} + +QAction * QtMenuSeparator::action() +{ + return _action; +} + +QtMenuItem::QtMenuItem(QQuickItem *parent) + : QtMenuBase(parent), _action(new QAction(this)) +{ + connect(_action, SIGNAL(triggered()), this, SIGNAL(triggered())); + connect(_action, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + connect(_action, SIGNAL(changed()), this, SIGNAL(enabledChanged())); +} + +QtMenuItem::~QtMenuItem() +{ +} + +void QtMenuItem::setText(const QString &text) +{ + _action->setText(text); + emit textChanged(); +} + +void QtMenuItem::setShortcut(const QString &shortcut) +{ + _action->setShortcut(QKeySequence(shortcut)); + emit shortcutChanged(); +} + +void QtMenuItem::setCheckable(bool checkable) +{ + _action->setCheckable(checkable); +} + +void QtMenuItem::setChecked(bool checked) +{ + _action->setChecked(checked); +} + +void QtMenuItem::setEnabled(bool enabled) +{ + _action->setEnabled(enabled); +} + +QString QtMenuItem::text() const +{ + return _action->text(); +} + +QString QtMenuItem::shortcut() const +{ + return _action->shortcut().toString(); +} + +bool QtMenuItem::checkable() const +{ + return _action->isCheckable(); +} + +bool QtMenuItem::checked() const +{ + return _action->isChecked(); +} + +bool QtMenuItem::enabled() const +{ + return _action->isEnabled(); +} + +QAction * QtMenuItem::action() +{ + return _action; +} diff --git a/src/qtdesktop/qtmenuitem.h b/src/qtdesktop/qtmenuitem.h new file mode 100644 index 00000000..5ee11671 --- /dev/null +++ b/src/qtdesktop/qtmenuitem.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMENUITEM_H +#define QTMENUITEM_H + +#include <QtCore/QObject> +#include <QtWidgets/QAction> +#include <QtCore/QUrl> + +#include <QtQuick/QQuickItem> + +class QtMenuBase: public QQuickItem +{ +Q_OBJECT + Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged) + Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged) + +public: + QtMenuBase(QQuickItem *parent = 0) : QQuickItem(parent) {} + + virtual QAction* action() = 0; + + void setIconSource(const QUrl &icon); + QUrl iconSource() const; + + void setIconName(const QString &icon); + QString iconName() const; + +Q_SIGNALS: + void iconSourceChanged(); + void iconNameChanged(); + +private: + QUrl _iconSource; + QString _iconName; +}; + +class QtMenuSeparator : public QtMenuBase +{ + Q_OBJECT +public: + QtMenuSeparator(QQuickItem *parent = 0); + ~QtMenuSeparator(); + QAction* action(); + +private: + QAction *_action; +}; + +class QtMenuItem: public QtMenuBase +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged); + Q_PROPERTY(QString shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged) + Q_PROPERTY(bool checkable READ checkable WRITE setCheckable) + Q_PROPERTY(bool checked READ checked WRITE setChecked NOTIFY toggled) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + +public: + QtMenuItem(QQuickItem *parent = 0); + ~QtMenuItem(); + + void setText(const QString &text); + void setShortcut(const QString &shortcut); + void setCheckable(bool checkable); + void setChecked(bool checked); + void setEnabled(bool enabled); + + QString text() const; + QString shortcut() const; + bool checkable() const; + bool checked() const; + bool enabled() const; + + QAction* action(); + +Q_SIGNALS: + void triggered(); + void textChanged(); + void shortcutChanged(); + void toggled(bool); + void enabledChanged(); + +private: + QAction *_action; +}; + +#endif //QTMENUITEM_H diff --git a/src/qtdesktop/qtsplitterbase.cpp b/src/qtdesktop/qtsplitterbase.cpp new file mode 100644 index 00000000..c2a26fbf --- /dev/null +++ b/src/qtdesktop/qtsplitterbase.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtsplitterbase.h" + +QtSplitterBase::QtSplitterBase(QQuickItem *parent) + : QQuickItem(parent) +{ +} + +QtSplitterAttached *QtSplitterBase::qmlAttachedProperties(QObject *object) +{ + return new QtSplitterAttached(object); +} + +void QtSplitterAttached::setExpanding(bool expanding) +{ + m_expanding = expanding; + emit expandingChanged(expanding); +} + +void QtSplitterAttached::setMaximumWidth(qreal width) +{ + m_maximumWidth = width; + emit maximumWidthChanged(width); +} + +void QtSplitterAttached::setMinimumWidth(qreal width) +{ + m_minimumWidth = width; + emit minimumWidthChanged(width); +} + +void QtSplitterAttached::setMaximumHeight(qreal height) +{ + m_maximumHeight = height; + emit maximumHeightChanged(height); +} + +void QtSplitterAttached::setMinimumHeight(qreal height) +{ + m_minimumHeight = height; + emit minimumHeightChanged(height); +} + +QtSplitterAttached::QtSplitterAttached(QObject *object) + : QObject(object), + m_minimumWidth(-1), + m_maximumWidth(-1), + m_minimumHeight(-1), + m_maximumHeight(-1), + m_percentageSize(-1), + m_itemIndex(-1), + m_expanding(false) +{ +} diff --git a/src/qtdesktop/qtsplitterbase.h b/src/qtdesktop/qtsplitterbase.h new file mode 100644 index 00000000..8bf4ee4d --- /dev/null +++ b/src/qtdesktop/qtsplitterbase.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSPLITTERBASE_H +#define QTSPLITTERBASE_H + +#include <QtQml> +#include <QtQuick> + + +class QtSplitterAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged) + Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged) + Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged) + Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged) + Q_PROPERTY(qreal percentageSize READ percentageSize WRITE setPercentageSize NOTIFY percentageWidthSize) + Q_PROPERTY(bool expanding READ expanding WRITE setExpanding NOTIFY expandingChanged) + Q_PROPERTY(int itemIndex READ itemIndex WRITE setItemIndex NOTIFY itemIndexChanged) + +public: + explicit QtSplitterAttached(QObject *object); + + qreal minimumWidth() const { return m_minimumWidth; } + void setMinimumWidth(qreal width); + + qreal maximumWidth() const { return m_maximumWidth; } + void setMaximumWidth(qreal width); + + qreal minimumHeight() const { return m_minimumHeight; } + void setMinimumHeight(qreal width); + + qreal maximumHeight() const { return m_maximumHeight; } + void setMaximumHeight(qreal width); + + bool expanding() const { return m_expanding; } + void setExpanding(bool expanding); + + qreal percentageSize() const { return m_percentageSize; } + + int itemIndex() const { return m_itemIndex; } + + void setPercentageSize(qreal arg) { m_percentageSize = arg; } + void setItemIndex(int arg) { + if (m_itemIndex != arg) { + m_itemIndex = arg; + emit itemIndexChanged(arg); + } + } + +signals: + void minimumWidthChanged(qreal arg); + void maximumWidthChanged(qreal arg); + void minimumHeightChanged(qreal arg); + void maximumHeightChanged(qreal arg); + void expandingChanged(bool arg); + void percentageWidthSize(qreal arg); + void itemIndexChanged(int arg); + +private: + qreal m_minimumWidth; + qreal m_maximumWidth; + qreal m_minimumHeight; + qreal m_maximumHeight; + qreal m_percentageSize; + int m_itemIndex; + bool m_expanding; + + friend class QtSplitterBase; +}; + + +class QtSplitterBase : public QQuickItem +{ + Q_OBJECT +public: + explicit QtSplitterBase(QQuickItem *parent = 0); + ~QtSplitterBase() {} + + static QtSplitterAttached *qmlAttachedProperties(QObject *object); +}; + +QML_DECLARE_TYPEINFO(QtSplitterBase, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QTSPLITTERBASE_H diff --git a/src/qtdesktop/qwheelarea.cpp b/src/qtdesktop/qwheelarea.cpp new file mode 100644 index 00000000..97aac522 --- /dev/null +++ b/src/qtdesktop/qwheelarea.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwheelarea.h" + + +QWheelArea::QWheelArea(QQuickItem *parent) + : QQuickItem(parent), + m_horizontalMinimumValue(0), + m_horizontalMaximumValue(0), + m_verticalMinimumValue(0), + m_verticalMaximumValue(0), + m_horizontalValue(0), + m_verticalValue(0), + m_verticalDelta(0), + m_horizontalDelta(0), + m_scrollSpeed(1.0) +{ + +} + +QWheelArea::~QWheelArea() +{ + +} + +void QWheelArea::wheelEvent(QWheelEvent *we) +{ + if (we->orientation() == Qt::Vertical) { + setVerticalDelta(we->delta()); + } else { + setHorizontalDelta(we->delta()); + } + we->accept(); +} + +void QWheelArea::setHorizontalMinimumValue(qreal value) +{ + m_horizontalMinimumValue = value; +} + +qreal QWheelArea::horizontalMinimumValue() const +{ + return m_horizontalMinimumValue; +} + +void QWheelArea::setHorizontalMaximumValue(qreal value) +{ + m_horizontalMaximumValue = value; +} + +qreal QWheelArea::horizontalMaximumValue() const +{ + return m_horizontalMaximumValue; +} + +void QWheelArea::setVerticalMinimumValue(qreal value) +{ + m_verticalMinimumValue = value; +} + +qreal QWheelArea::verticalMinimumValue() const +{ + return m_verticalMinimumValue; +} + +void QWheelArea::setVerticalMaximumValue(qreal value) +{ + m_verticalMaximumValue = value; +} + +qreal QWheelArea::verticalMaximumValue() const +{ + return m_verticalMaximumValue; +} + +void QWheelArea::setHorizontalValue(qreal value) +{ + value = qBound<qreal>(m_horizontalMinimumValue, value, m_horizontalMaximumValue); + + if (value != m_horizontalValue) { + m_horizontalValue = value; + emit horizontalValueChanged(); + } +} + +qreal QWheelArea::horizontalValue() const +{ + return m_horizontalValue; +} + +void QWheelArea::setVerticalValue(qreal value) +{ + value = qBound<qreal>(m_verticalMinimumValue, value, m_verticalMaximumValue); + + if (value != m_verticalValue) { + m_verticalValue = value; + emit verticalValueChanged(); + } +} + +qreal QWheelArea::verticalValue() const +{ + return m_verticalValue; +} + +void QWheelArea::setVerticalDelta(qreal value) +{ + m_verticalDelta = m_scrollSpeed * value / 15; + setVerticalValue(m_verticalValue - m_verticalDelta); + + emit verticalWheelMoved(); +} + +qreal QWheelArea::verticalDelta() const +{ + return m_verticalDelta; +} + +void QWheelArea::setHorizontalDelta(qreal value) +{ + m_horizontalDelta = value / 15; + setHorizontalValue(m_horizontalValue - m_horizontalDelta); + + emit horizontalWheelMoved(); +} + +qreal QWheelArea::horizontalDelta() const +{ + return m_horizontalDelta; +} + +void QWheelArea::setScrollSpeed(qreal value) +{ + if (value != m_scrollSpeed) { + m_scrollSpeed = value; + emit scrollSpeedChanged(); + } +} + +qreal QWheelArea::scrollSpeed() const +{ + return m_scrollSpeed; +} diff --git a/src/qtdesktop/qwheelarea.h b/src/qtdesktop/qwheelarea.h new file mode 100644 index 00000000..a112607c --- /dev/null +++ b/src/qtdesktop/qwheelarea.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWHEELAREA_H +#define QWHEELAREA_H + +#include <QtGui/qevent.h> +#include <QtWidgets/qgraphicssceneevent.h> +#include <QtQuick/qquickitem.h> + + +class QWheelArea : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal verticalDelta READ verticalDelta WRITE setVerticalDelta NOTIFY verticalWheelMoved) + Q_PROPERTY(qreal horizontalDelta READ horizontalDelta WRITE setHorizontalDelta NOTIFY horizontalWheelMoved) + Q_PROPERTY(qreal horizontalMinimumValue READ horizontalMinimumValue WRITE setHorizontalMinimumValue) + Q_PROPERTY(qreal horizontalMaximumValue READ horizontalMaximumValue WRITE setHorizontalMaximumValue) + Q_PROPERTY(qreal verticalMinimumValue READ verticalMinimumValue WRITE setVerticalMinimumValue) + Q_PROPERTY(qreal verticalMaximumValue READ verticalMaximumValue WRITE setVerticalMaximumValue) + Q_PROPERTY(qreal horizontalValue READ horizontalValue WRITE setHorizontalValue) + Q_PROPERTY(qreal verticalValue READ verticalValue WRITE setVerticalValue) + Q_PROPERTY(qreal scrollSpeed READ scrollSpeed WRITE setScrollSpeed NOTIFY scrollSpeedChanged) + +public: + QWheelArea(QQuickItem *parent = 0); + virtual ~QWheelArea(); + + void setHorizontalMinimumValue(qreal value); + qreal horizontalMinimumValue() const; + + void setHorizontalMaximumValue(qreal value); + qreal horizontalMaximumValue() const; + + void setVerticalMinimumValue(qreal value); + qreal verticalMinimumValue() const; + + void setVerticalMaximumValue(qreal value); + qreal verticalMaximumValue() const; + + void setHorizontalValue(qreal value); + qreal horizontalValue() const; + + void setVerticalValue(qreal value); + qreal verticalValue() const; + + void setVerticalDelta(qreal value); + qreal verticalDelta() const; + + void setHorizontalDelta(qreal value); + qreal horizontalDelta() const; + + void setScrollSpeed(qreal value); + qreal scrollSpeed() const; + + void wheelEvent(QWheelEvent *event); + +Q_SIGNALS: + void verticalValueChanged(); + void horizontalValueChanged(); + void verticalWheelMoved(); + void horizontalWheelMoved(); + void scrollSpeedChanged(); + +private: + qreal m_horizontalMinimumValue; + qreal m_horizontalMaximumValue; + qreal m_verticalMinimumValue; + qreal m_verticalMaximumValue; + qreal m_horizontalValue; + qreal m_verticalValue; + qreal m_verticalDelta; + qreal m_horizontalDelta; + qreal m_scrollSpeed; + + Q_DISABLE_COPY(QWheelArea) +}; + +QML_DECLARE_TYPE(QWheelArea) + + +#endif // QWHEELAREA_H diff --git a/src/qtdesktop/styleplugin.json b/src/qtdesktop/styleplugin.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/src/qtdesktop/styleplugin.json @@ -0,0 +1 @@ +{} diff --git a/src/qtdesktop/styleplugin.pri b/src/qtdesktop/styleplugin.pri new file mode 100644 index 00000000..5083a873 --- /dev/null +++ b/src/qtdesktop/styleplugin.pri @@ -0,0 +1,35 @@ +HEADERS += \ + qdesktopitem.h \ + qfiledialogitem.h \ + qquickcomponentsprivate.h \ + qquicklayout.h \ + qquicklayoutengine_p.h \ + qquicklinearlayout.h \ + qrangemodel.h \ + qrangemodel_p.h \ + qstyleitem.h \ + qstyleplugin.h \ + qtmenu.h \ + qtmenubar.h \ + qtmenuitem.h \ + qtsplitterbase.h \ + qwheelarea.h + +SOURCES += \ + qdesktopitem.cpp \ + qfiledialogitem.cpp \ + qquickcomponentsprivate.cpp \ + qquicklayout.cpp \ + qquicklayoutengine.cpp \ + qquicklinearlayout.cpp \ + qrangemodel.cpp \ + qstyleitem.cpp \ + qstyleplugin.cpp \ + qtmenu.cpp \ + qtmenubar.cpp \ + qtmenuitem.cpp \ + qtsplitterbase.cpp \ + qwheelarea.cpp + +OTHER_FILES += \ + styleplugin.json |