From 88f140ddd7f634ad4411f4d16cae51a93eb856b7 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig <jens.bache-wiig@nokia.com> Date: Mon, 21 Feb 2011 10:52:17 +0100 Subject: [PATCH] Added widgets --- components/Button.qml | 27 + components/ButtonRow.qml | 5 + components/CheckBox.qml | 26 + components/ChoiceList.qml | 52 ++ components/GroupBox.qml | 27 + components/ProgressBar.qml | 31 + components/RadioButton.qml | 26 + components/ScrollArea.qml | 103 ++++ components/ScrollBar.qml | 109 ++++ components/Slider.qml | 31 + components/SpinBox.qml | 91 +++ components/Switch.qml | 22 + components/Tab.qml | 7 + components/TabBar.qml | 90 +++ components/TabFrame.qml | 72 +++ components/TextArea.qml | 44 ++ components/TextField.qml | 52 ++ components/TextScrollArea.qml | 31 + components/ToolBar.qml | 12 + components/ToolButton.qml | 18 + components/custom/BasicButton.qml | 44 ++ components/custom/BusyIndicator.qml | 27 + components/custom/Button.qml | 39 ++ components/custom/ButtonBlock.qml | 216 +++++++ components/custom/ButtonColumn.qml | 44 ++ components/custom/ButtonGroup.js | 127 ++++ components/custom/ButtonRow.qml | 43 ++ components/custom/CheckBox.qml | 49 ++ components/custom/ChoiceList.qml | 85 +++ components/custom/ProgressBar.qml | 80 +++ components/custom/RadioButton.qml | 13 + components/custom/ScrollDecorator.qml | 20 + components/custom/ScrollIndicator.qml | 56 ++ components/custom/Slider.qml | 291 ++++++++++ components/custom/SpinBox.qml | 142 +++++ components/custom/Switch.qml | 85 +++ components/custom/TextArea.qml | 156 +++++ components/custom/TextField.qml | 196 +++++++ .../custom/behaviors/ButtonBehavior.qml | 31 + .../custom/behaviors/ModalPopupBehavior.qml | 90 +++ .../behaviors/TextEditMouseBehavior.qml | 266 +++++++++ components/custom/components.pro | 49 ++ components/custom/private/ChoiceListPopup.qml | 269 +++++++++ components/custom/qmldir | 17 + .../styles/default/BasicButtonStyle.qml | 8 + .../styles/default/BusyIndicatorStyle.qml | 21 + .../styles/default/ButtonBlockStyle.qml | 77 +++ .../custom/styles/default/ButtonStyle.qml | 102 ++++ .../custom/styles/default/CheckBoxStyle.qml | 34 ++ .../custom/styles/default/ChoiceListStyle.qml | 100 ++++ .../styles/default/ProgressBarStyle.qml | 142 +++++ .../styles/default/RadioButtonStyle.qml | 34 ++ .../styles/default/ScrollIndicatorStyle.qml | 18 + .../custom/styles/default/SliderStyle.qml | 110 ++++ .../custom/styles/default/SpinBoxStyle.qml | 73 +++ .../custom/styles/default/SwitchStyle.qml | 71 +++ .../custom/styles/default/TextFieldStyle.qml | 41 ++ .../styles/default/images/button_normal.png | Bin 0 -> 877 bytes .../styles/default/images/button_pressed.png | Bin 0 -> 803 bytes .../default/images/buttongroup_h_normal.png | Bin 0 -> 482 bytes .../default/images/buttongroup_h_pressed.png | Bin 0 -> 386 bytes .../styles/default/images/checkbox_check.png | Bin 0 -> 557 bytes .../custom/styles/default/images/handle.png | Bin 0 -> 1529 bytes .../styles/default/images/lineedit_normal.png | Bin 0 -> 794 bytes .../images/progress-bar-background.png | Bin 0 -> 484 bytes .../default/images/progress-bar-bar.png | Bin 0 -> 548 bytes .../default/images/progressbar_fill.png | Bin 0 -> 992 bytes .../default/images/progressbar_groove.png | Bin 0 -> 492 bytes .../images/progressbar_indeterminate.png | Bin 0 -> 1152 bytes .../default/images/progressbar_overlay.png | Bin 0 -> 284 bytes .../custom/styles/default/images/qt-logo.png | Bin 0 -> 954 bytes .../default/images/radiobutton_check.png | Bin 0 -> 1331 bytes .../images/radiobutton_check_white.png | Bin 0 -> 1310 bytes .../default/images/radiobutton_normal.png | Bin 0 -> 1752 bytes .../default/images/slider-background.png | Bin 0 -> 293 bytes .../default/images/slider-handle-active.png | Bin 0 -> 506 bytes .../styles/default/images/slider-handle.png | Bin 0 -> 516 bytes .../custom/styles/default/images/slider.png | Bin 0 -> 617 bytes .../styles/default/images/spinbox_down.png | Bin 0 -> 347 bytes .../styles/default/images/spinbox_up.png | Bin 0 -> 341 bytes .../custom/styles/default/images/spinner.png | Bin 0 -> 2629 bytes .../styles/default/images/switch_normal.png | Bin 0 -> 834 bytes .../styles/default/images/switch_pressed.png | Bin 0 -> 709 bytes .../styles/default/tools/ColorConverter.qml | 59 ++ components/custom/visuals/AdjoiningCorner.qml | 31 + components/custom/visuals/AdjoiningVisual.qml | 50 ++ components/images/folder_new.png | Bin 0 -> 1199 bytes components/plugin/qmldir | 1 + components/src.pro | 2 + components/styleitem/qstyleitem.cpp | 547 ++++++++++++++++++ components/styleitem/qstyleitem.h | 197 +++++++ components/styleitem/qstyleplugin.cpp | 83 +++ components/styleitem/qstyleplugin.h | 55 ++ components/styleitem/styleitem.pro | 38 ++ src/Button.qml | 27 + src/ButtonRow.qml | 5 + src/CheckBox.qml | 26 + src/ChoiceList.qml | 52 ++ src/GroupBox.qml | 27 + src/ProgressBar.qml | 31 + src/RadioButton.qml | 26 + src/ScrollArea.qml | 103 ++++ src/ScrollBar.qml | 109 ++++ src/Slider.qml | 31 + src/SpinBox.qml | 91 +++ src/Switch.qml | 22 + src/Tab.qml | 7 + src/TabBar.qml | 90 +++ src/TabFrame.qml | 72 +++ src/TextArea.qml | 44 ++ src/TextField.qml | 52 ++ src/TextScrollArea.qml | 31 + src/ToolBar.qml | 12 + src/ToolButton.qml | 18 + src/components/ButtonGroup.js | 127 ++++ src/components/components.pro | 49 ++ src/components/qmldir | 17 + src/images/folder_new.png | Bin 0 -> 1199 bytes src/plugin/qmldir | 1 + src/styleitem/styleitem.pro | 38 ++ src/widgets/Button.qml | 27 + src/widgets/ButtonRow.qml | 5 + src/widgets/CheckBox.qml | 26 + src/widgets/ChoiceList.qml | 52 ++ src/widgets/GroupBox.qml | 27 + src/widgets/ProgressBar.qml | 31 + src/widgets/RadioButton.qml | 26 + src/widgets/ScrollArea.qml | 103 ++++ src/widgets/ScrollBar.qml | 109 ++++ src/widgets/Slider.qml | 31 + src/widgets/SpinBox.qml | 91 +++ src/widgets/Switch.qml | 22 + src/widgets/Tab.qml | 7 + src/widgets/TabBar.qml | 90 +++ src/widgets/TabFrame.qml | 72 +++ src/widgets/TextArea.qml | 44 ++ src/widgets/TextField.qml | 52 ++ src/widgets/TextScrollArea.qml | 31 + src/widgets/ToolBar.qml | 12 + src/widgets/ToolButton.qml | 18 + 140 files changed, 7189 insertions(+) create mode 100644 components/Button.qml create mode 100644 components/ButtonRow.qml create mode 100644 components/CheckBox.qml create mode 100644 components/ChoiceList.qml create mode 100644 components/GroupBox.qml create mode 100644 components/ProgressBar.qml create mode 100644 components/RadioButton.qml create mode 100644 components/ScrollArea.qml create mode 100644 components/ScrollBar.qml create mode 100644 components/Slider.qml create mode 100644 components/SpinBox.qml create mode 100644 components/Switch.qml create mode 100644 components/Tab.qml create mode 100644 components/TabBar.qml create mode 100644 components/TabFrame.qml create mode 100644 components/TextArea.qml create mode 100644 components/TextField.qml create mode 100644 components/TextScrollArea.qml create mode 100644 components/ToolBar.qml create mode 100644 components/ToolButton.qml create mode 100644 components/custom/BasicButton.qml create mode 100644 components/custom/BusyIndicator.qml create mode 100644 components/custom/Button.qml create mode 100644 components/custom/ButtonBlock.qml create mode 100644 components/custom/ButtonColumn.qml create mode 100644 components/custom/ButtonGroup.js create mode 100644 components/custom/ButtonRow.qml create mode 100644 components/custom/CheckBox.qml create mode 100644 components/custom/ChoiceList.qml create mode 100644 components/custom/ProgressBar.qml create mode 100644 components/custom/RadioButton.qml create mode 100644 components/custom/ScrollDecorator.qml create mode 100644 components/custom/ScrollIndicator.qml create mode 100644 components/custom/Slider.qml create mode 100644 components/custom/SpinBox.qml create mode 100644 components/custom/Switch.qml create mode 100644 components/custom/TextArea.qml create mode 100644 components/custom/TextField.qml create mode 100644 components/custom/behaviors/ButtonBehavior.qml create mode 100644 components/custom/behaviors/ModalPopupBehavior.qml create mode 100644 components/custom/behaviors/TextEditMouseBehavior.qml create mode 100644 components/custom/components.pro create mode 100644 components/custom/private/ChoiceListPopup.qml create mode 100644 components/custom/qmldir create mode 100644 components/custom/styles/default/BasicButtonStyle.qml create mode 100644 components/custom/styles/default/BusyIndicatorStyle.qml create mode 100644 components/custom/styles/default/ButtonBlockStyle.qml create mode 100644 components/custom/styles/default/ButtonStyle.qml create mode 100644 components/custom/styles/default/CheckBoxStyle.qml create mode 100644 components/custom/styles/default/ChoiceListStyle.qml create mode 100644 components/custom/styles/default/ProgressBarStyle.qml create mode 100644 components/custom/styles/default/RadioButtonStyle.qml create mode 100644 components/custom/styles/default/ScrollIndicatorStyle.qml create mode 100644 components/custom/styles/default/SliderStyle.qml create mode 100644 components/custom/styles/default/SpinBoxStyle.qml create mode 100644 components/custom/styles/default/SwitchStyle.qml create mode 100644 components/custom/styles/default/TextFieldStyle.qml create mode 100644 components/custom/styles/default/images/button_normal.png create mode 100644 components/custom/styles/default/images/button_pressed.png create mode 100644 components/custom/styles/default/images/buttongroup_h_normal.png create mode 100644 components/custom/styles/default/images/buttongroup_h_pressed.png create mode 100644 components/custom/styles/default/images/checkbox_check.png create mode 100644 components/custom/styles/default/images/handle.png create mode 100644 components/custom/styles/default/images/lineedit_normal.png create mode 100644 components/custom/styles/default/images/progress-bar-background.png create mode 100644 components/custom/styles/default/images/progress-bar-bar.png create mode 100644 components/custom/styles/default/images/progressbar_fill.png create mode 100644 components/custom/styles/default/images/progressbar_groove.png create mode 100644 components/custom/styles/default/images/progressbar_indeterminate.png create mode 100644 components/custom/styles/default/images/progressbar_overlay.png create mode 100644 components/custom/styles/default/images/qt-logo.png create mode 100644 components/custom/styles/default/images/radiobutton_check.png create mode 100644 components/custom/styles/default/images/radiobutton_check_white.png create mode 100644 components/custom/styles/default/images/radiobutton_normal.png create mode 100644 components/custom/styles/default/images/slider-background.png create mode 100644 components/custom/styles/default/images/slider-handle-active.png create mode 100644 components/custom/styles/default/images/slider-handle.png create mode 100644 components/custom/styles/default/images/slider.png create mode 100644 components/custom/styles/default/images/spinbox_down.png create mode 100644 components/custom/styles/default/images/spinbox_up.png create mode 100644 components/custom/styles/default/images/spinner.png create mode 100644 components/custom/styles/default/images/switch_normal.png create mode 100644 components/custom/styles/default/images/switch_pressed.png create mode 100644 components/custom/styles/default/tools/ColorConverter.qml create mode 100644 components/custom/visuals/AdjoiningCorner.qml create mode 100644 components/custom/visuals/AdjoiningVisual.qml create mode 100644 components/images/folder_new.png create mode 100644 components/plugin/qmldir create mode 100644 components/src.pro create mode 100644 components/styleitem/qstyleitem.cpp create mode 100644 components/styleitem/qstyleitem.h create mode 100644 components/styleitem/qstyleplugin.cpp create mode 100644 components/styleitem/qstyleplugin.h create mode 100644 components/styleitem/styleitem.pro create mode 100644 src/Button.qml create mode 100644 src/ButtonRow.qml create mode 100644 src/CheckBox.qml create mode 100644 src/ChoiceList.qml create mode 100644 src/GroupBox.qml create mode 100644 src/ProgressBar.qml create mode 100644 src/RadioButton.qml create mode 100644 src/ScrollArea.qml create mode 100644 src/ScrollBar.qml create mode 100644 src/Slider.qml create mode 100644 src/SpinBox.qml create mode 100644 src/Switch.qml create mode 100644 src/Tab.qml create mode 100644 src/TabBar.qml create mode 100644 src/TabFrame.qml create mode 100644 src/TextArea.qml create mode 100644 src/TextField.qml create mode 100644 src/TextScrollArea.qml create mode 100644 src/ToolBar.qml create mode 100644 src/ToolButton.qml create mode 100644 src/components/ButtonGroup.js create mode 100644 src/components/components.pro create mode 100644 src/components/qmldir create mode 100644 src/images/folder_new.png create mode 100644 src/plugin/qmldir create mode 100644 src/styleitem/styleitem.pro create mode 100644 src/widgets/Button.qml create mode 100644 src/widgets/ButtonRow.qml create mode 100644 src/widgets/CheckBox.qml create mode 100644 src/widgets/ChoiceList.qml create mode 100644 src/widgets/GroupBox.qml create mode 100644 src/widgets/ProgressBar.qml create mode 100644 src/widgets/RadioButton.qml create mode 100644 src/widgets/ScrollArea.qml create mode 100644 src/widgets/ScrollBar.qml create mode 100644 src/widgets/Slider.qml create mode 100644 src/widgets/SpinBox.qml create mode 100644 src/widgets/Switch.qml create mode 100644 src/widgets/Tab.qml create mode 100644 src/widgets/TabBar.qml create mode 100644 src/widgets/TabFrame.qml create mode 100644 src/widgets/TextArea.qml create mode 100644 src/widgets/TextField.qml create mode 100644 src/widgets/TextScrollArea.qml create mode 100644 src/widgets/ToolBar.qml create mode 100644 src/widgets/ToolButton.qml diff --git a/components/Button.qml b/components/Button.qml new file mode 100644 index 000000000..496d37df2 --- /dev/null +++ b/components/Button.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + + property int buttonHeight: Math.max(22, styleitem.sizeFromContents(100, 6).height) + height: buttonHeight + + QStyleItem { + id:styleitem + elementType:"button" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:button.enabled + text:button.text + } + + background: + QStyleBackground { + style:styleitem + anchors.fill:parent + } +} + diff --git a/components/ButtonRow.qml b/components/ButtonRow.qml new file mode 100644 index 000000000..623c5f442 --- /dev/null +++ b/components/ButtonRow.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 +import "../../../components" as Components + +Components.ButtonRow { +} diff --git a/components/CheckBox.qml b/components/CheckBox.qml new file mode 100644 index 000000000..632dce2d4 --- /dev/null +++ b/components/CheckBox.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.CheckBox{ + id:checkbox + property variant text + width:100 + height:18 + + background: QStyleBackground { + id:styleitem + style:QStyleItem { + elementType:"checkbox" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:checkbox.text + enabled:checkbox.enabled + } + } + checkmark: null +} + diff --git a/components/ChoiceList.qml b/components/ChoiceList.qml new file mode 100644 index 000000000..5015fbefb --- /dev/null +++ b/components/ChoiceList.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ChoiceList { + id:choicelist + + property int buttonHeight: buttonitem.sizeFromContents(100, 18).height + QStyleItem { id:buttonitem; elementType:"combobox" } + height: buttonHeight + topMargin:4 + bottomMargin:4 + + QStyleItem { + id:styleitem + elementType: "combobox" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:choicelist.enabled + } + + background: QStyleBackground { + anchors.fill:parent + style: styleitem + } + + listItem: Item { + id:item + + height:22 + anchors.left:parent.left + width:choicelist.width + QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "menuitem" + text: choicelist.model.get(index).text + selected: highlighted + } + } + } + + popupFrame: QStyleBackground { + property int fw: styleitem.pixelMetric("menupanelwidth"); + anchors.leftMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.rightMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.topMargin: styleitem.pixelMetric("menuvmargin") + fw + anchors.bottomMargin: styleitem.pixelMetric("menuvmargin") + fw + style:QStyleItem{elementType:"menu"} + } +} diff --git a/components/GroupBox.qml b/components/GroupBox.qml new file mode 100644 index 000000000..0d45810d1 --- /dev/null +++ b/components/GroupBox.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item { + width:200 + height:46 + + property alias text: styleitem.text + default property alias children: content.children + property bool checkable: false + + QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + id:styleitem + elementType:"groupbox" + } + + Item { + id:content + anchors.topMargin:22 + anchors.leftMargin:6 + anchors.fill:parent + } + } +} diff --git a/components/ProgressBar.qml b/components/ProgressBar.qml new file mode 100644 index 000000000..bf29bcac9 --- /dev/null +++ b/components/ProgressBar.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ProgressBar { + id:progressbar + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + background: QStyleBackground{ + anchors.fill:parent + style: QStyleItem { + elementType:"progressbar" + + // XXX: since desktop uses int instead of real, the progressbar + // range [0..1] must be stretched to a good precision + property int factor : 1000000 + + value: progressbar.value * factor + minimum: indeterminate ? 0 : progressbar.minimumValue * factor + maximum: indeterminate ? 0 : progressbar.maximumValue * factor + enabled: progressbar.enabled + } + } + indeterminateProgress:null + progress: null +} + diff --git a/components/RadioButton.qml b/components/RadioButton.qml new file mode 100644 index 000000000..3c2c3e547 --- /dev/null +++ b/components/RadioButton.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.RadioButton{ + id:radiobutton + property variant text + width:110 + height:18 + + background: QStyleBackground { + + style: QStyleItem{ + elementType:"radiobutton" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:radiobutton.text + enabled:radiobutton.enabled + } + } + checkmark: null +} + diff --git a/components/ScrollArea.qml b/components/ScrollArea.qml new file mode 100644 index 000000000..3a904ddeb --- /dev/null +++ b/components/ScrollArea.qml @@ -0,0 +1,103 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +FocusScope { + id:scrollarea + width: 100 + height: 100 + + property int contentMargin: 1 + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + property int frameWidth: styleitem.pixelMetric("defaultframewidth"); + property int contentHeight : content.childrenRect.height + property int contentWidth: content.childrenRect.width + property alias color: flickable.color + property bool frame: true + property bool highlightOnFocus: false + + default property alias children: content.children + + property int contentY + property int contentX + + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + + onContentYChanged: { + vscrollbar.value = contentY + } + + onContentXChanged: { + hscrollbar.value = contentX + } + + QStyleBackground { + style: QStyleItem{ + id:styleitem + elementType: frame ? "frame" : "" + sunken: true + } + anchors.fill: parent + anchors.rightMargin: (frameAroundContents && vscrollbar.visible) ? vscrollbar.width + 4 : -frameWidth + anchors.bottomMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + anchors.topMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + + Rectangle { + id:flickable + color: "transparent" + anchors.fill: parent + anchors.margins: frame ? 2 : 0 + clip: true + + Item { + id: docmargins + anchors.fill:parent + anchors.margins:contentMargin + Item { + id: content + x: -scrollarea.contentX + y: -scrollarea.contentY + } + } + } + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + visible: contentWidth > flickable.width + maximumValue: contentWidth > flickable.width ? scrollarea.contentWidth - flickable.width : 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: { return (frame ? 1 : 0) + ( vscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentX = value + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + visible: contentHeight > flickable.height + maximumValue: contentHeight > flickable.height ? scrollarea.contentHeight - flickable.height : 0 + minimumValue: 0 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: { return (frame ? 1 : 0) + (hscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentY = value + } + + QStyleBackground { + z:2 + anchors.fill:parent + anchors.margins:-2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } +} diff --git a/components/ScrollBar.qml b/components/ScrollBar.qml new file mode 100644 index 000000000..ea822b62e --- /dev/null +++ b/components/ScrollBar.qml @@ -0,0 +1,109 @@ +import QtQuick 1.1 +import "../../../components" as Components +import "../plugin" + +MouseArea { + id:scrollbar + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + implicitWidth:orientation == Qt.Horizontal ? 200 : __scrollbarExtent; + implicitHeight:orientation == Qt.Horizontal ? __scrollbarExtent : 200 + + property int orientation : Qt.Horizontal + property alias minimumValue: slider.minimumValue + property alias maximumValue: slider.maximumValue + property alias value: slider.value + + property bool upPressed; + property bool downPressed; + property bool __autoincrement: false + + // Update hover item + onEntered: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + onExited: styleitem.activeControl = "none" + onMouseXChanged: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + hoverEnabled:true + + Timer { running: upPressed || downPressed; interval: 350 ; onTriggered: __autoincrement = true } + Timer { running: __autoincrement; interval: 60 ; repeat: true ; + onTriggered: upPressed ? decrement() : increment() } + + onPressed: { + var control = bgitem.hitTest(mouseX,mouseY) + if (control == "up") { + upPressed = true + } else if (control == "down") { + downPressed = true + } + } + + onReleased: { + __autoincrement = false; + if (upPressed) { + upPressed = false; + decrement() + } else if (downPressed) { + increment() + downPressed = false; + } + } + + function increment() { + value += 30 + if (value > maximumValue) + value = maximumValue + } + + function decrement() { + value -= 30 + if (value < minimumValue) + value = minimumValue + } + + QStyleBackground { + id:bgitem + anchors.fill:parent + style: QStyleItem { + id:styleitem + elementType: "scrollbar" + hover: activeControl != "none" + activeControl: "none" + sunken: upPressed | downPressed + minimum: slider.minimumValue + maximum: slider.maximumValue + value: slider.value + horizontal: orientation == Qt.Horizontal + enabled: parent.enabled + } + } + + property variant handleRect + function updateHandle() { + handleRect = bgitem.subControlRect("handle") + var grooveRect = bgitem.subControlRect("groove"); + var extra = 0 + if (orientation == Qt.Vertical) { + slider.anchors.topMargin = grooveRect.y + extra + slider.anchors.bottomMargin = height - grooveRect.y - grooveRect.height + extra + } else { + slider.anchors.leftMargin = grooveRect.x + extra + slider.anchors.rightMargin = width - grooveRect.x - grooveRect.width + extra + } + } + + onValueChanged: updateHandle() + onMaximumValueChanged: updateHandle() + onMinimumValueChanged: updateHandle() + Component.onCompleted: updateHandle() + Components.Slider { + id:slider + anchors.fill:parent + orientation:scrollbar.orientation + leftMargin: (orientation === Qt.Horizontal) ? handleRect.width/2 : handleRect.height/2 + rightMargin:leftMargin + handle: Item { width:orientation == Qt.Vertical ? handleRect.height : handleRect.width; + height:orientation == Qt.Vertical ? handleRect.width : handleRect.height} + groove:null + valueIndicator:null + inverted:orientation != Qt.Horizontal + } +} diff --git a/components/Slider.qml b/components/Slider.qml new file mode 100644 index 000000000..c6b9c9151 --- /dev/null +++ b/components/Slider.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jens: ContainsMouse breaks drag functionality + +Components.Slider{ + id:slider + minimumWidth:200 + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + groove: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"slider" + sunken: pressed + maximum:slider.maximumValue + minimum:slider.minimumValue + value:slider.value + horizontal:slider.orientation == Qt.Horizontal + enabled:slider.enabled + } + } + + handle: null + valueIndicator: null +} diff --git a/components/SpinBox.qml b/components/SpinBox.qml new file mode 100644 index 000000000..2db428cef --- /dev/null +++ b/components/SpinBox.qml @@ -0,0 +1,91 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.SpinBox { + id:spinbox + + property variant __upRect; + property variant __downRect; + property int __margin: (height -16)/2 + + // Align height with button + topMargin:__margin + bottomMargin:__margin + + property int buttonHeight: edititem.sizeFromContents(100, 20).height + QStyleItem { id:edititem; elementType:"edit" } + height: buttonHeight + clip:false + + background: + Item { + anchors.fill: parent + property variant __editRect + + Rectangle { + id:editBackground + x: __editRect.x - 1 + y: __editRect.y + width: __editRect.width + height: __editRect.height + } + + Item { + id:focusFrame + anchors.fill: editBackground + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -6 + anchors.leftMargin: -5 + anchors.fill: parent + visible:spinbox.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } + + function updateRect() { + __upRect = spinboxbg.subControlRect("up"); + __downRect = spinboxbg.subControlRect("down"); + __editRect = spinboxbg.subControlRect("edit"); + } + + Component.onCompleted:updateRect() + onWidthChanged:updateRect() + onHeightChanged:updateRect() + + QStyleBackground { + id:spinboxbg + anchors.fill:parent + style: QStyleItem { + id: styleitem + elementType: "spinbox" + sunken: downPressed | upPressed + hover: containsMouse + focus: spinbox.activeFocus + enabled: spinbox.enabled + value: (upPressed? 1 : 0) | + (downPressed== 1 ? 1<<1 : 0) | + (upEnabled? (1<<2) : 0) | + (downEnabled == 1 ? (1<<3) : 0) + } + } + } + + up: Item { + x: __upRect.x + y: __upRect.y + width: __upRect.width + height: __upRect.height + } + + down: Item { + x: __downRect.x + y: __downRect.y + width: __downRect.width + height: __downRect.height + } +} diff --git a/components/Switch.qml b/components/Switch.qml new file mode 100644 index 000000000..b82817c9f --- /dev/null +++ b/components/Switch.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Switch { + id:widget + minimumWidth:100 + minimumHeight:30 + + groove:QStyleItem { + elementType:"edit" + sunken: true + } + + handle: QStyleItem { + elementType:"button" + width:widget.width/2 + height:widget.height-4 + hover:containsMouse + } +} + diff --git a/components/Tab.qml b/components/Tab.qml new file mode 100644 index 000000000..e258185ba --- /dev/null +++ b/components/Tab.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id:tab + anchors.fill:parent + property string title +} diff --git a/components/TabBar.qml b/components/TabBar.qml new file mode 100644 index 000000000..2d891256f --- /dev/null +++ b/components/TabBar.qml @@ -0,0 +1,90 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + + +Item { + id: tabbar + property int tabHeight: styleitem.sizeFromContents(100, 24).height + height: tabHeight + + property Item tabFrame + onTabFrameChanged:parent = tabFrame + visible: tabFrame ? tabFrame.tabsVisible : true + property int __overlap : styleitem.pixelMetric("tabvshift"); + property string position: tabFrame ? tabFrame.position : "North" + property string tabBarAlignment: styleitem.styleHint("tabbaralignment"); + property int tabOverlap: styleitem.pixelMetric("taboverlap"); + + function tab(index) { + for (var i = 0; i < tabrow.children.length; ++i) { + if (tabrow.children[i].tabindex == index) { + return tabrow.children[i] + } + } + return null; + } + + QStyleItem { + id:styleitem + elementType: "tab" + text: "generic" + } + + Row { + id:tabrow + states: + State { + when: tabBarAlignment == "center" + name: "centered" + AnchorChanges { + target:tabrow + anchors.horizontalCenter: tabbar.horizontalCenter + } + } + Repeater { + id:repeater + model: tabFrame ? tabFrame.tabs.length : null + delegate: Item { + id:tab + property int tabindex: index + property bool selected : tabFrame.current == index + width: textitem.width + 42 + height: tabHeight + z: selected ? 1 : -1 + + QStyleBackground { + style: QStyleItem { + id:style + elementType: "tab" + selected: tab.selected + text: tabbar.position + + activeControl: tabFrame.count == 1 ? + "only" : + index == 0 ? "beginning" : + index == tabFrame.count-1 ? "end" : "middle" + } + anchors.leftMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "end") + && tab.selected ? -__overlap : 0) + + anchors.rightMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "beginning") + && tab.selected ? -__overlap : 0) + anchors.fill:parent + } + + Text { + id:textitem + anchors.centerIn:parent + text: tabFrame.tabs[index].title + elide: Text.ElideRight + } + + MouseArea { + anchors.fill: parent + onPressed: tabFrame.current = index + } + } + } + } +} diff --git a/components/TabFrame.qml b/components/TabFrame.qml new file mode 100644 index 000000000..01896e753 --- /dev/null +++ b/components/TabFrame.qml @@ -0,0 +1,72 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item{ + id: tabWidget + width:100 + height:100 + property TabBar tabbar + 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 + + onCurrentChanged: __setOpacities() + Component.onCompleted: __setOpacities() + onTabbarChanged: { + tabbar.tabFrame = tabWidget + tabbar.anchors.top = tabWidget.top + tabbar.anchors.left = tabWidget.left + tabbar.anchors.right = tabWidget.right + } + + property int __baseOverlap : style.pixelMetric("tabbaseoverlap"); + function __setOpacities() { + for (var i = 0; i < stack.children.length; ++i) { + stack.children[i].opacity = (i == current ? 1 : 0) + } + } + + QStyleBackground { + id: frame + z:-1 + style: QStyleItem { + id:style + elementType: "tabframe" + text: position + value: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).x : 0 + minimum: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).width : 0 + } + anchors.fill:parent + Item { + id:stack + anchors.fill:parent + anchors.margins: frame ? 2 : 0 + } + anchors.topMargin: tabbar && tabsVisible && position == "North" ? tabbar.height - __baseOverlap : 0 + + states: [ + State { + name: "South" + when: position == "South" && tabbar!= undefined + PropertyChanges { + target: frame + anchors.topMargin: 0 + anchors.bottomMargin: tabbar ? tabbar.height - __baseOverlap: 0 + } + PropertyChanges { + target: tabbar + anchors.topMargin: -__baseOverlap + } + AnchorChanges { + target: tabbar + anchors.top: frame.bottom + anchors.bottom: undefined + } + } + ] + } +} diff --git a/components/TextArea.qml b/components/TextArea.qml new file mode 100644 index 000000000..93ad8f3d9 --- /dev/null +++ b/components/TextArea.qml @@ -0,0 +1,44 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextArea { + id:textarea + leftMargin:12 + rightMargin:12 + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + clip:false + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 14).height + QStyleItem { id:buttonitem; elementType:"button" } + minimumHeight: buttonHeight + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textarea.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textarea + parent:textarea.parent + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textarea.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/components/TextField.qml b/components/TextField.qml new file mode 100644 index 000000000..260584e95 --- /dev/null +++ b/components/TextField.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextField { + id:textfield + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + topMargin:2 + bottomMargin:2 + leftMargin:6 + rightMargin:6 + width:200 + height: editItem.sizeFromContents(100, 20).height + clip:false + + QStyleItem { + id:editItem + elementType:"edit" + sunken:true + focus:textfield.activeFocus + hover:containsMouse + } + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textfield.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textfield + parent:textfield + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textfield.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/components/TextScrollArea.qml b/components/TextScrollArea.qml new file mode 100644 index 000000000..2a7deab68 --- /dev/null +++ b/components/TextScrollArea.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +ScrollArea { + id:area + color: "white" + width: 280 + height: 120 + contentWidth: 200 + + property alias text: edit.text + property alias wrapMode: edit.wrapMode + highlightOnFocus: true + + TextEdit { + id: edit + text: loremIpsum + loremIpsum; + wrapMode: TextEdit.WordWrap; + width: area.contentWidth + selectByMouse:true + + // keep textcursor within scrollarea + onCursorRectangleChanged: + if (cursorRectangle.y >= area.contentY + area.height - 1.5*cursorRectangle.height) + area.contentY = cursorRectangle.y - area.height + 1.5*cursorRectangle.height + else if (cursorRectangle.y < area.contentY) + area.contentY = cursorRectangle.y + + } +} diff --git a/components/ToolBar.qml b/components/ToolBar.qml new file mode 100644 index 000000000..ce61382ee --- /dev/null +++ b/components/ToolBar.qml @@ -0,0 +1,12 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +QStyleBackground { + id:styleitem + width:200 + height:60 + + style: QStyleItem{elementType:"toolbar"} +} + diff --git a/components/ToolButton.qml b/components/ToolButton.qml new file mode 100644 index 000000000..98b2dfebf --- /dev/null +++ b/components/ToolButton.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + minimumWidth:30 + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "toolbutton" + on: pressed | checked + sunken: pressed + raised: containsMouse + hover: containsMouse + } + } +} diff --git a/components/custom/BasicButton.qml b/components/custom/BasicButton.qml new file mode 100644 index 000000000..1116f0b01 --- /dev/null +++ b/components/custom/BasicButton.qml @@ -0,0 +1,44 @@ +import QtQuick 1.1 +import "./behaviors" // ButtonBehavior +import "./styles/default" as DefaultStyles + +Item { + id: button + + signal clicked + property alias pressed: behavior.pressed + property alias containsMouse: behavior.containsMouse + property alias checkable: behavior.checkable // button toggles between checked and !checked + property alias checked: behavior.checked + + property Component background: defaultStyle.background + + property color backgroundColor: syspal.button + property color textColor: syspal.text; + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + // implementation + + property string __position: "only" + implicitWidth: Math.max(minimumWidth, backgroundLoader.item.width) + implicitHeight: Math.max(minimumHeight, backgroundLoader.item.height) + + Loader { + id: backgroundLoader + anchors.fill: parent + sourceComponent: background + property alias styledItem: button + property alias position: button.__position + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + onClicked: button.clicked() + } + + DefaultStyles.BasicButtonStyle { id: defaultStyle } + SystemPalette { id: syspal } +} diff --git a/components/custom/BusyIndicator.qml b/components/custom/BusyIndicator.qml new file mode 100644 index 000000000..00b12ed3f --- /dev/null +++ b/components/custom/BusyIndicator.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles + +Item { + id: busyIndicator + + // Common API: + property bool running: true + + width: backgroundComponent.item.width; + height: backgroundComponent.item.height; + + property Component background: defaultStyle.background + + Loader { + id: backgroundComponent + property bool running: busyIndicator.opacity > 0 && + busyIndicator.visible && + busyIndicator.running +// onRunningChanged: print("Running: " + running) + anchors.fill: parent + sourceComponent: background + + } + + DefaultStyles.BusyIndicatorStyle { id: defaultStyle } +} diff --git a/components/custom/Button.qml b/components/custom/Button.qml new file mode 100644 index 000000000..1bcd8335e --- /dev/null +++ b/components/custom/Button.qml @@ -0,0 +1,39 @@ +import QtQuick 1.1 +import "./styles/default" as DefaultStyles + +BasicButton { + id: button + + property string text + property url iconSource + + property Component label: defaultStyle.label + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + // implementation + + implicitWidth: Math.max(minimumWidth, labelLoader.item.implicitWidth + leftMargin + rightMargin) + implicitHeight: Math.max(minimumHeight, labelLoader.item.implicitHeight + topMargin + bottomMargin) + + minimumWidth: defaultStyle.minimumWidth + minimumHeight: defaultStyle.minimumHeight + + background: defaultStyle.background + + Loader { + id: labelLoader + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.rightMargin: rightMargin + anchors.topMargin: topMargin + anchors.bottomMargin: bottomMargin + property alias styledItem: button + sourceComponent: label + } + + DefaultStyles.ButtonStyle { id: defaultStyle } +} diff --git a/components/custom/ButtonBlock.qml b/components/custom/ButtonBlock.qml new file mode 100644 index 000000000..999d3dd06 --- /dev/null +++ b/components/custom/ButtonBlock.qml @@ -0,0 +1,216 @@ +import QtQuick 1.0 +import "./behaviors" // ButtonBehavior +import "./visuals" // AdjoiningVisual +import "./styles/default" as DefaultStyles + +// KNOWN ISSUES +// 1) When switching between horizontal and vertical orientation after block has been created, the Grid's move +// transition is called *before* the grid item's have actually moved, resulting in incorrect "adjoins" states +// 2) Can't make items in vertical groups all the same width without access to their implicitWidth, see QTBUG-14957 +// 3) Should be generalized into JoinedGroup and ButtonBlock made a specialization. +// 4) ExclusiveSelection support missing + +// NOTES +// 1) The ButtonBlock implementation has no ultimate dependency on AdjoiningVisual, and can therefor be made to work +// with any Component for the item instances. The use of AdjoiningVisual is only for simplifying the implementation +// and styling of the items in the block. The property defining how an item in the block should be joinged with its +// neighbours is "adjoins" which the ButtonBlock "attaches" to the items in the block (i.e. defines in their +// look-up scope) which means the "button" instances does not need to define this property, only read it to draw +// their border appropriately. This "adjoins" property is a *completely* separate concept from the AdjoiningVisual. +// I.e. the coupling between the ButtonGroup and the "button" elements making up the group is the weakest possible. + + +Item { + id: buttonBlock + + property alias model: repeater.model + property variant bindings: {"text":"text", "iconSource":"iconSource", "enabled":"enabled", "opacity":"opacity"} + + property Component buttonBackground: defaultStyle.background + property Component buttonLabel: defaultStyle.label + + property color backgroundColor: syspal.button + property color textColor: syspal.text; + + property int orientation: Qt.Horizontal + signal clicked(int index) + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + width: grid.width + height: grid.height + + Grid { + id: grid + columns: orientation == Qt.Vertical ? 1 : model.count + anchors.centerIn: parent + property int widestItemWidth: 0 + property int talestItemHeight: 0 + + move: Transition { //mm seems "move" transition is not always called after items has been moved + ScriptAction { script: { + if(orientation == Qt.Horizontal) { + grid.leftmostVisibleIndex = grid.__leftmostVisibleIndex(); + grid.rightmostVisibleIndex = grid.__rightmostVisibleIndex(); + } else { + grid.topmostVisibleIndex = grid.__topmostVisibleIndex(); + grid.bottommostVisibleIndex = grid.__bottommostVisibleIndex(); + } + } + } + } + + property int leftmostVisibleIndex + function __leftmostVisibleIndex() { + var leftmostVisibleIndex = 0; + var leftmostItemX = 10000000; + for(var i = 0; i < children.length; i++) { + var child = children[i]; + if(child.x < leftmostItemX && child.opacity > 0) { + leftmostItemX = child.x; + leftmostVisibleIndex = i; + } + } + return leftmostVisibleIndex; + } + + property int rightmostVisibleIndex + function __rightmostVisibleIndex() { + var rightmostVisibleIndex = 0; + var rightmostItemX = 0; + for(var i = 0; i < children.length; i++) { + var child = children[i]; +//mm print("rightmost child? at: " + child.x + "," + child.y) + if(child.x > rightmostItemX && child.opacity > 0) { + rightmostItemX = child.x; + rightmostVisibleIndex = i; + } + } + return rightmostVisibleIndex; + } + + property int topmostVisibleIndex + function __topmostVisibleIndex() { + var topmostVisibleIndex = 0; + var topmostItemY = 10000000; + for(var i = 0; i < children.length; i++) { + var child = children[i]; + if(child.y < topmostItemY && child.opacity > 0) { + topmostItemY = child.y; + topmostVisibleIndex = i; + } + } + return topmostVisibleIndex; + } + + property int bottommostVisibleIndex + function __bottommostVisibleIndex() { + var bottommostVisibleIndex = 0; + var bottommostItemY = 0; + for(var i = 0; i < children.length; i++) { + var child = children[i]; +//mm print("bottommost child? at: " + child.x + "," + child.y) + if(child.y > bottommostItemY && child.opacity > 0) { + bottommostItemY = child.y; + bottommostVisibleIndex = i; + } + } + return bottommostVisibleIndex; + } + + Repeater { + id: repeater + delegate: AdjoiningVisual { + id: blockButton + styledItem: blockButton + styling: buttonBackground + + property alias pressed: behavior.pressed + property alias containsMouse: behavior.containsMouse + property alias checkable: behavior.checkable // button toggles between checked and !checked + property alias checked: behavior.checked + + property string text + property url iconSource + property color textColor: buttonBlock.textColor + property color backgroundColor: buttonBlock.backgroundColor + + Component.onCompleted: { + // Create the Binding objects defined by the ButtonBlock's "bindings" map property to allow + // the properties of the buttons to be bound to properties in the model with different names + + if (bindings == undefined) // jb : bindings is undefined on Mac + return; + var keys = Object.keys(buttonBlock.bindings); + for(var i = 0; i < keys.length; i++) { + var key = keys[i]; + var bindingComponent = + 'import QtQuick 1.0;' + + 'Binding {' + + ' target: blockButton;' + + ' property: "' + key + '";' + + ' value: buttonBlock.model.get(' + index + ').' + bindings[key] + ';' + + '}'; + Qt.createQmlObject(bindingComponent, blockButton); //mm do we ever need to explicitly delete these? + } + + // Find the widest/talest item to make all buttons the same width/height + if(buttonBlock.orientation == Qt.Vertical) //mm Can't make this work without QTBUG-14957 + grid.widestItemWidth = Math.max(grid.widestItemWidth, width); + else + grid.talestItemHeight = Math.max(grid.talestItemHeight, height); + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + onClicked: buttonBlock.clicked(index) + } + + property int adjoins + adjoins: { //mm see QTBUG-14987 + var adjoins; + if(orientation == Qt.Horizontal) { + adjoins = 0x1|0x2; // left and right + if(index == grid.leftmostVisibleIndex) adjoins &= ~0x1; // not left + if(index == grid.rightmostVisibleIndex) adjoins &= ~0x2; // not right + } else { + adjoins = 0x4|0x8; // top and bottom + if(index == grid.topmostVisibleIndex) adjoins &= ~0x4; // not top + if(index == grid.bottommostVisibleIndex) adjoins &= ~0x8; // not bottom + } + return adjoins; + } + + + // width: orientation == Qt.Vertical ? grid.widestItemWidth : item.width + // height: orientation == Qt.Vertical ? item.height : grid.talestItemHeight + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + width: Math.max(minimumWidth, + labelComponent.item.width + leftMargin + rightMargin) + height: Math.max(minimumHeight, + labelComponent.item.height + topMargin + bottomMargin) + + Loader { + id: labelComponent + property variant styledItem: blockButton + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.rightMargin: rightMargin + anchors.topMargin: topMargin + anchors.bottomMargin: bottomMargin + sourceComponent: buttonLabel + } + + } + } + } + + SystemPalette { id: syspal; colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled } + DefaultStyles.ButtonBlockStyle { id: defaultStyle } +} diff --git a/components/custom/ButtonColumn.qml b/components/custom/ButtonColumn.qml new file mode 100644 index 000000000..8d63a855c --- /dev/null +++ b/components/custom/ButtonColumn.qml @@ -0,0 +1,44 @@ +import Qt 4.7 +import "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: 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/components/custom/ButtonGroup.js b/components/custom/ButtonGroup.js new file mode 100644 index 000000000..f2d000029 --- /dev/null +++ b/components/custom/ButtonGroup.js @@ -0,0 +1,127 @@ +var self; +var clickHandlers = []; +var visibleButtons = []; +var nonVisibleButtons = []; +var direction; +var exclusive; + +function create(that, options) { + self = that; + direction = options.direction || Qt.Horizontal; + exclusive = self.exclusive|| options.exclusive; + self.childrenChanged.connect(rebuild); +// self.widthChanged.connect(resizeChildren); + build(); +} + +function isButton(item) { + if (item && item["__position"] !== undefined) + return true; + return false; +} + +function hasChecked(item) { + if (item && item["checked"] !== undefined) + return true; + return false; +} + +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 (!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 (exclusive && hasChecked(item)) { + if (item["checkable"]!==undefined) { + item.checkable = true; + } + clickHandlers[i] = checkExclusive(item); + item.clicked.connect(clickHandlers[i]); + } + } + + if (self.checkedButton && !self.checkedButton.visible) + self.checkedButton = undefined; + + var nrButtons = visibleButtons.length; + if (nrButtons == 0) + return; + + 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 + button.anchors.right = self.right + } + } +} + +function cleanup() { + visibleButtons.forEach(function(item, i) { + if (clickHandlers[i]) + item.clicked.disconnect(clickHandlers[i]); + item.visibleChanged.disconnect(rebuild); + }); + clickHandlers = []; + + nonVisibleButtons.forEach(function(item, i) { + item.visibleChanged.disconnect(rebuild); + }); +} + +function rebuild() { + 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++) { + ref.checked = button === ref; + } + self.checkedButton = button; + } +} diff --git a/components/custom/ButtonRow.qml b/components/custom/ButtonRow.qml new file mode 100644 index 000000000..7c2d3ea7a --- /dev/null +++ b/components/custom/ButtonRow.qml @@ -0,0 +1,43 @@ +import Qt 4.7 +import "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=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: 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/components/custom/CheckBox.qml b/components/custom/CheckBox.qml new file mode 100644 index 000000000..e8b865564 --- /dev/null +++ b/components/custom/CheckBox.qml @@ -0,0 +1,49 @@ +import QtQuick 1.1 +import "./behaviors" +import "./styles/default" as DefaultStyles + +Item { + id: checkBox + + signal clicked + property alias pressed: behavior.pressed + property alias checked: behavior.checked + property alias containsMouse: behavior.containsMouse + + property Component background: defaultStyle.background + property Component checkmark: defaultStyle.checkmark + + property color backgroundColor: syspal.base + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + // implementation + + implicitWidth: minimumWidth + implicitHeight: minimumHeight + + Loader { + id: backgroundLoader + anchors.fill: parent + property alias styledItem: checkBox + sourceComponent: background + } + + Loader { + id: checkmarkLoader + anchors.centerIn: parent + property alias styledItem: checkBox + sourceComponent: checkmark + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + checkable: true + onClicked: checkBox.clicked() + } + + DefaultStyles.CheckBoxStyle { id: defaultStyle } + SystemPalette { id: syspal } +} diff --git a/components/custom/ChoiceList.qml b/components/custom/ChoiceList.qml new file mode 100644 index 000000000..8c5ca81be --- /dev/null +++ b/components/custom/ChoiceList.qml @@ -0,0 +1,85 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles +import "./private" as Private // for ChoiceListPopup + +// KNOWN ISSUES +// 1) Popout list does not have a scrollbar/scroll indicator or similar +// 2) The ChoiceListPopup should ff dynamically loaded, to support radically different implementations +// 3) Mouse wheel scroll events not handled by the popout ListView (see QTBUG-7369) +// 4) Support for configurable bindings between model's and ChoiceList's properties similar to ButtonBlock's is missing + +Item { + id: choiceList + + property alias model: popup.model + property int currentIndex: popup.currentIndex + + property alias containsMouse: mouseArea.containsMouse //mm needed? + property bool pressed: false //mm needed? + + property color textColor: syspal.text + property color backgroundColor: syspal.button + + property Component background: defaultStyle.background + property Component label: defaultStyle.label + property Component listItem: defaultStyle.listItem + property Component popupFrame: defaultStyle.popupFrame + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + property int labelWidth: labelComponent.item.width + property int labelHeight: labelComponent.item.height + + width: Math.max(minimumWidth, + labelComponent.item.width + leftMargin + rightMargin) + height: Math.max(minimumHeight, + labelComponent.item.height + topMargin + bottomMargin) + + // Implementation + + SystemPalette { id: syspal } + Loader { + property alias styledItem: choiceList + sourceComponent: background + anchors.fill: parent + } + + Loader { + id: labelComponent + property alias model: popup.model + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.rightMargin: rightMargin + anchors.topMargin: topMargin + anchors.bottomMargin: bottomMargin + sourceComponent: label + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + drag.target: Item {} // disable dragging in case ChoiceList is on a Flickable + onPressed: { + choiceList.pressed = true; + popup.togglePopup(); + + } + onReleased: choiceList.pressed = false + onCanceled: choiceList.pressed = false // mouse stolen e.g. by Flickable + } + + Private.ChoiceListPopup { + id: popup + listItem: choiceList.listItem + popupFrame: choiceList.popupFrame + } + + DefaultStyles.ChoiceListStyle { id: defaultStyle } +} diff --git a/components/custom/ProgressBar.qml b/components/custom/ProgressBar.qml new file mode 100644 index 000000000..fadbbc5e0 --- /dev/null +++ b/components/custom/ProgressBar.qml @@ -0,0 +1,80 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles + +Item { + id: progressBar + SystemPalette{id:syspal} + + property real value: 0 + property real minimumValue: 0 + property real maximumValue: 1 + property bool indeterminate: false + + property color backgroundColor: syspal.base + property color progressColor: syspal.highlight + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + width: minimumWidth + height: minimumHeight + + property Component background: defaultStyle.background + property Component progress: defaultStyle.progress + property Component indeterminateProgress: defaultStyle.indeterminateProgress + + Loader { + id: groove + property alias indeterminate:progressBar.indeterminate + property alias value:progressBar.value + property alias maximumValue:progressBar.maximumValue + property alias minimumValue:progressBar.minimumValue + + sourceComponent: background + anchors.fill: parent + } + + Item { + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.rightMargin: rightMargin + anchors.topMargin: topMargin + anchors.bottomMargin: bottomMargin + + Loader { + id: progressComponent + property alias styledItem: progressBar + property alias indeterminate:progressBar.indeterminate + property alias value:progressBar.value + property alias maximumValue:progressBar.maximumValue + property alias minimumValue:progressBar.minimumValue + property real complete: (value-minimumValue)/(maximumValue-minimumValue) + + opacity: !indeterminate && value > 0 ? 1 : 0 + width: Math.round((progressBar.width-leftMargin-rightMargin)*(complete)) + height: progressBar.height-topMargin-bottomMargin + anchors.left:parent.left + sourceComponent: progressBar.progress + } + + Loader { + id: indeterminateComponent + property alias styledItem: progressBar + property alias indeterminate:progressBar.indeterminate + property alias value:progressBar.value + property alias maximumValue:progressBar.maximumValue + property alias minimumValue:progressBar.minimumValue + + opacity: indeterminate ? 1 : 0 + anchors.fill: parent + sourceComponent: indeterminateProgress + } + } + + DefaultStyles.ProgressBarStyle { id: defaultStyle } +} diff --git a/components/custom/RadioButton.qml b/components/custom/RadioButton.qml new file mode 100644 index 000000000..f89f2773c --- /dev/null +++ b/components/custom/RadioButton.qml @@ -0,0 +1,13 @@ +import QtQuick 1.1 +import "./styles/default" as DefaultStyles + +CheckBox { + id: radioButton + + // implementation + + checkmark: defaultStyle.checkmark + background: defaultStyle.background + + DefaultStyles.RadioButtonStyle { id: defaultStyle} +} diff --git a/components/custom/ScrollDecorator.qml b/components/custom/ScrollDecorator.qml new file mode 100644 index 000000000..e61a16d20 --- /dev/null +++ b/components/custom/ScrollDecorator.qml @@ -0,0 +1,20 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles + +Item { + id: scrollDecorator + + property Flickable flickableItem + + anchors.fill: parent + + ScrollIndicator { + horizontal: true + scrollItem: scrollDecorator.flickableItem + } + + ScrollIndicator { + horizontal: false + scrollItem: scrollDecorator.flickableItem + } +} diff --git a/components/custom/ScrollIndicator.qml b/components/custom/ScrollIndicator.qml new file mode 100644 index 000000000..cba1dba81 --- /dev/null +++ b/components/custom/ScrollIndicator.qml @@ -0,0 +1,56 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles + +Item { + id: scrollIndicator + + property Flickable scrollItem + property bool horizontal: false + + property Component content: defaultStyle.content + + //private + anchors.left: horizontal ? parent.left : undefined + anchors.right: parent.right + anchors.top: horizontal ? undefined : parent.top + anchors.bottom: parent.bottom + width: horizontal ? parent.width : defaultStyle.minimumWidth + height: horizontal ? defaultStyle.minimumWidth : parent.height + + opacity: (horizontal ? scrollItem.movingHorizontally : scrollItem.movingVertically) ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + + Item { + id: ratationContainer + + anchors.centerIn: parent + rotation: horizontal ? -90 : 0 + width: horizontal ? scrollIndicator.height : scrollIndicator.width // rotate width and heigh back + height: horizontal ? scrollIndicator.width : scrollIndicator.height + + property variant visibleArea: scrollItem.visibleArea + property real scrollItemSize: horizontal ? scrollItem.width : scrollItem.height + property real scrollItemVisibleAreaPos: horizontal ? visibleArea.xPosition : visibleArea.yPosition + property real scrollItemVisibleAreaScrollRatio: horizontal ? visibleArea.widthRatio : visibleArea.heightRatio + property real scrollItemContentPos: horizontal ? scrollItem.contentX : scrollItem.contentY + property real scrollItemContentSize: horizontal ? scrollItem.contentWidth : scrollItem.contentHeight + + property real offset: scrollItemVisibleAreaPos * scrollItemSize + property real length: scrollItemVisibleAreaScrollRatio * scrollItemSize + property real startOvershoot: Math.max(-scrollItemContentPos, 0) + property real endOvershoot: Math.max(scrollItemContentPos-(scrollItemContentSize-scrollItemSize), 0) + property real start: Math.max(offset + endOvershoot, 0) + property real end: Math.min(offset+length-startOvershoot, scrollItemSize) + + Loader { + x: 0 + y: parent.endOvershoot > 0 ? Math.min(parent.start, parent.scrollItemSize-width) : parent.start + width: 12 + height: Math.max(parent.end-parent.start, width) + + sourceComponent: content + } + } + + DefaultStyles.ScrollIndicatorStyle { id: defaultStyle } +} diff --git a/components/custom/Slider.qml b/components/custom/Slider.qml new file mode 100644 index 000000000..789167c66 --- /dev/null +++ b/components/custom/Slider.qml @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions contained +** in the Technology Preview License Agreement accompanying this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +import QtQuick 1.0 +import Qt.labs.components 1.0 +import "./styles/default" as DefaultStyles + +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 + + // NOTE: this property is in/out, the user can set it, create bindings to it, and + // at the same time the slider wants to update. There's no way in QML to do this kind + // of updates AND allow the user bind it (without a Binding object). That's the + // reason this is an alias to a C++ property in range model. + property alias value: range.value + + // CONVENIENCE TO BE USED BY STYLES + SystemPalette { + id: palette + } + property color progressColor: palette.highlight + property color backgroundColor: palette.window + + property int leftMargin: defaultStyle.leftMargin + property int rightMargin: defaultStyle.rightMargin + + // EXTENSIONS + // Indicate that we want animations in the Slider, people customizing should + // look at it to decide whether or not active animations. + property bool animated: true + + // Value indicator displays the current value near the slider + property bool valueIndicatorVisible: true + property int valueIndicatorMargin: 10 + property string valueIndicatorPosition: _isVertical ? "Left" : "Top" + + // Reimplement this function to control how the value is shown in the + // indicator. + function formatValue(v) { + return Math.round(v); + } + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + // Hooks for customizing the pieces of the slider + property Component groove: defaultStyle.groove + property Component handle: defaultStyle.handle + property Component valueIndicator: defaultStyle.valueIndicator + + // PRIVATE/CONVENIENCE + property bool _isVertical: orientation == Qt.Vertical + + width: _isVertical ? minimumHeight : minimumWidth + height: _isVertical ? minimumWidth : minimumHeight + + DefaultStyles.SliderStyle { id: defaultStyle } + + // This is a template slider, so every piece can be modified by passing a + // different Component. The main elements in the implementation are + // + // - the 'range' does the calculations to map position to/from value, + // it also serves as a data storage for both properties; + // + // - the 'fakeHandle' is what the mouse area drags on the screen, it feeds + // the 'range' position and also reads it when convenient; + // + // - the real 'handle' it is the visual representation of the handle, that + // just follows the 'fakeHandle' position. + // + // When the 'updateValueWhileDragging' is false and we are dragging, we stop + // feeding the range with position information, delaying until the next + // mouse release. + // + // Everything is encapsulated in a contents Item, so for the + // vertical slider, we just swap the height/width, make it + // horizontal, and then use rotation to make it vertical again. + + Item { + id: contents + + width: _isVertical ? slider.height : slider.width + height: _isVertical ? slider.width : slider.height + rotation: _isVertical ? -90 : 0 + + anchors.centerIn: slider + + RangeModel { + id: range + minimumValue: 0 + maximumValue: 100 + value: 0 + stepSize: 1.0 + inverted: false + + positionAtMinimum: leftMargin + positionAtMaximum: contents.width - rightMargin + } + + Loader { + id: grooveLoader + anchors.fill: parent + sourceComponent: groove + + property real handlePosition : handleLoader.x + function positionForValue(value) { + return range.positionForValue(value) - leftMargin; + } + } + + Loader { + id: handleLoader + transform: Translate { x: - handleLoader.width / 2 } + + anchors.verticalCenter: grooveLoader.verticalCenter + + sourceComponent: handle + + x: fakeHandle.x + Behavior on x { + id: behavior + enabled: !mouseArea.drag.active && slider.animated + + PropertyAnimation { + duration: behavior.enabled ? 150 : 0 + easing.type: Easing.OutSine + } + } + } + + Item { + id: fakeHandle + width: handleLoader.width + height: handleLoader.height + transform: Translate { x: - handleLoader.width / 2 } + } + + MouseArea { + id: mouseArea + + anchors.centerIn: parent + anchors.horizontalCenterOffset: (slider.leftMargin - slider.rightMargin) / 2 + + width: parent.width + handleLoader.width - slider.rightMargin - slider.leftMargin + height: parent.height + + drag.target: fakeHandle + drag.axis: Drag.XAxis + drag.minimumX: range.positionAtMinimum + drag.maximumX: range.positionAtMaximum + + onPressed: { + // 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. + 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; + } + } + + Loader { + id: valueIndicatorLoader + + transform: Translate { x: - handleLoader.width / 2 } + rotation: _isVertical ? 90 : 0 + visible: valueIndicatorVisible + + // Properties available for the delegate component. Note that the indicatorText + // shows the value for the position the handle is, which is not necessarily the + // available as the current slider.value, since updateValueWhileDragging can + // be set to 'false'. + property string indicatorText: slider.formatValue(range.valueForPosition(handleLoader.x)) + property bool dragging: mouseArea.drag.active + + sourceComponent: valueIndicator + + state: { + if (!_isVertical) + return slider.valueIndicatorPosition; + + if (valueIndicatorPosition == "Right") + return "Bottom"; + if (valueIndicatorPosition == "Top") + return "Right"; + if (valueIndicatorPosition == "Bottom") + return "Left"; + + return "Top"; + } + + anchors.margins: valueIndicatorMargin + + states: [ + State { + name: "Top" + AnchorChanges { + target: valueIndicatorLoader + anchors.bottom: handleLoader.top + anchors.horizontalCenter: handleLoader.horizontalCenter + } + }, + State { + name: "Bottom" + AnchorChanges { + target: valueIndicatorLoader + anchors.top: handleLoader.bottom + anchors.horizontalCenter: handleLoader.horizontalCenter + } + }, + State { + name: "Right" + AnchorChanges { + target: valueIndicatorLoader + anchors.left: handleLoader.right + anchors.verticalCenter: handleLoader.verticalCenter + } + }, + State { + name: "Left" + AnchorChanges { + target: valueIndicatorLoader + anchors.right: handleLoader.left + anchors.verticalCenter: handleLoader.verticalCenter + } + } + ] + } + } + + // 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 + } +} diff --git a/components/custom/SpinBox.qml b/components/custom/SpinBox.qml new file mode 100644 index 000000000..1566a8e72 --- /dev/null +++ b/components/custom/SpinBox.qml @@ -0,0 +1,142 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles + +Item { + id: spinbox + SystemPalette{id:syspal} + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + width: Math.max(minimumWidth, + input.width + leftMargin + rightMargin) + + height: Math.max(minimumHeight, + input.height + topMargin + bottomMargin) + + property real value: 0.0 + property real maximumValue: 99 + property real minimumValue: 0 + property real singlestep: 1 + + 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 activeFocus: input.activeFocus // Forward active focus + + property color backgroundColor: syspal.base + property color textColor: syspal.text + + property Component background: defaultStyle.background + property Component up: defaultStyle.up + property Component down: defaultStyle.down + DefaultStyles.SpinBoxStyle { id: defaultStyle } + + function increment() { + value += singlestep + if (value > maximumValue) + value = maximumValue + input.text = value + } + + function decrement() { + value -= singlestep + if (value < minimumValue) + value = minimumValue + input.text = value + } + + function setValue(v) { + var newval = parseFloat(v) + if (newval > maximumValue) + newval = maximumValue + else if (value < minimumValue) + newval = minimumValue + value = newval + input.text = value + } + + // background + Loader { + id: backgroundComponent + anchors.fill: parent + sourceComponent: background + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } + + TextInput { + id: input + font.pixelSize: 14 + anchors.margins: 5 + anchors.leftMargin: leftMargin + anchors.topMargin: topMargin + anchors.rightMargin: rightMargin + anchors.bottomMargin: bottomMargin + anchors.fill: parent + selectByMouse: true + text: spinbox.value + validator: DoubleValidator { bottom: 11; top: 31 } + onTextChanged: { spinbox.setValue(text); } + color: textColor + opacity: parent.enabled ? 1 : 0.5 + } + + Loader { + id: upButton + property alias pressed : spinbox.upPressed + property alias hover : spinbox.upHovered + property alias enabled : spinbox.upEnabled + sourceComponent: up + MouseArea { + id: mouseUp + anchors.fill: upButton.item + 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() } + } + onLoaded: { + item.parent = spinbox + mouseUp.parent = item + } + } + + Loader { + id: downButton + property alias pressed : spinbox.downPressed + property alias hover : spinbox.downHovered + property alias enabled : spinbox.downEnabled + sourceComponent: down + MouseArea { + id: mouseDown + anchors.fill: downButton.item + onClicked: decrement() + + 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() } + } + onLoaded: { + item.parent = spinbox + mouseDown.parent = item + } + } +} diff --git a/components/custom/Switch.qml b/components/custom/Switch.qml new file mode 100644 index 000000000..8bf18cfe3 --- /dev/null +++ b/components/custom/Switch.qml @@ -0,0 +1,85 @@ +import QtQuick 1.1 +import "./styles/default" as DefaultStyles + +Item { + id: toggleSwitch // "switch" is a reserved word + + signal clicked + property bool pressed: mouseArea.pressed + property bool checked: false + property alias containsMouse: mouseArea.containsMouse + + property color switchColor: syspal.button + property color backgroundColor: syspal.alternateBase + property color positiveHighlightColor: syspal.highlight + property color negativeHighlightColor: "transparent" + property color textColor: syspal.text + + property Component groove: defaultStyle.groove + property Component handle: defaultStyle.handle + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + // implementation + + implicitWidth: Math.max(minimumWidth, grooveLoader.item.implicitWidth) + implicitHeight: Math.max(minimumHeight, grooveLoader.item.implicitHeight) + + onCheckedChanged: snapHandleIntoPlace(); + + Loader { + id: grooveLoader + anchors.fill: parent + property alias styledItem: toggleSwitch + property real handleCenterX: handleLoader.item.x + (handleLoader.item.width/2) + sourceComponent: groove + } + + Loader { + id: handleLoader + anchors.top: parent.top + anchors.bottom: parent.bottom + property alias styledItem: toggleSwitch + sourceComponent: handle + + Component.onCompleted: item.x = checked ? mouseArea.drag.maximumX : mouseArea.drag.minimumX + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + drag.axis: Drag.XAxis + drag.minimumX: 0 + drag.maximumX: toggleSwitch.width - handleLoader.item.width + drag.target: handleLoader.item + + onPressed: toggleSwitch.pressed = true // needed when hover is enabled + onCanceled: { snapHandleIntoPlace(); toggleSwitch.pressed = false; } // mouse stolen e.g. by Flickable + onReleased: { + var wasChecked = checked; + if (drag.active) { + checked = (handleLoader.item.x > (drag.maximumX - drag.minimumX)/2) + } else if (toggleSwitch.pressed && enabled) { // No click if release outside area + checked = !checked; + } + + snapHandleIntoPlace(); + + toggleSwitch.pressed = false + if(checked != wasChecked) + toggleSwitch.clicked(); + } + } + + onWidthChanged: snapHandleIntoPlace() + function snapHandleIntoPlace() { + if(handleLoader.item) + handleLoader.item.x = checked ? mouseArea.drag.maximumX : mouseArea.drag.minimumX; + } + + DefaultStyles.SwitchStyle { id: defaultStyle } + SystemPalette { id: syspal } +} diff --git a/components/custom/TextArea.qml b/components/custom/TextArea.qml new file mode 100644 index 000000000..92263fe6e --- /dev/null +++ b/components/custom/TextArea.qml @@ -0,0 +1,156 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles +import "./behaviors" // TextEditMouseBehavior + +FocusScope { + id: textArea + + property alias text: textEdit.text + property alias placeholderText: placeholderTextComponent.text + property alias font: textEdit.font + property bool passwordMode: false + property bool readOnly: textEdit.readOnly // read only + property int inputHint; // values tbd (alias to TextEdit.inputMethodHints? + property alias selectedText: textEdit.selectedText + property alias selectionEnd: textEdit.selectionEnd + property alias selectionStart: textEdit.selectionStart + property alias horizontalAlignment: textEdit.horizontalAlignment + property alias verticalAlignment: textEdit.verticalAlignment + property alias wrapMode: textEdit.wrapMode //mm Missing from spec + property alias textFormat: textEdit.textFormat + property alias cursorPosition: textEdit.cursorPosition + + property color textColor: syspal.text + property color backgroundColor: syspal.base + property alias containsMouse: mouseEditBehavior.containsMouse + + property Component background: defaultStyle.background + property Component hints: defaultStyle.hints + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + function copy() { + textEdit.copy() + } + + function paste() { + textEdit.paste() + } + + function cut() { + textEdit.cut() + } + + function forceActiveFocus() { + textEdit.forceActiveFocus() + } + + function select(start, end) { + textEdit.select(start, end) + } + + function selectAll() { + textEdit.selectAll() + } + + function selectWord() { + textEdit.selectWord() + } + + function positionAt(x, y) { + var p = mapToItem(textEdit, x, y); + return textEdit.positionAt(p.x, p.y); + } + + function positionToRectangle(pos) { + var p = mapToItem(textEdit, pos.x, pos.y); + return textEdit.positionToRectangle(p); + } + + width: Math.max(minimumWidth, + Math.max(textEdit.width, placeholderTextComponent.width) + leftMargin + rightMargin) + height: Math.max(minimumHeight, + Math.max(textEdit.height, placeholderTextComponent.height) + topMargin + bottomMargin) + + + // Implementation + + property alias activeFocus: textEdit.activeFocus // Forward active focus + property alias desktopBehavior: mouseEditBehavior.desktopBehavior + property alias _hints: hintsLoader.item + clip: true + + SystemPalette { id: syspal } + Loader { id: hintsLoader; sourceComponent: hints } + Loader { sourceComponent: background; anchors.fill: parent } + + Flickable { //mm is FocusScope, so TextArea's root doesn't need to be, no? + id: flickable + clip: true + + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.topMargin: topMargin + anchors.rightMargin: rightMargin + anchors.bottomMargin: bottomMargin + + function ensureVisible(r) { + if (contentX >= r.x) + contentX = r.x; + else if (contentX+width <= r.x+r.width) + contentX = r.x+r.width-width; + if (contentY >= r.y) + contentY = r.y; + else if (contentY+height <= r.y+r.height) + contentY = r.y+r.height-height; + } + + TextEdit { // see QTBUG-14936 + id: textEdit + font.pixelSize: _hints.fontPixelSize + font.bold: _hints.fontBold + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + color: enabled ? textColor: Qt.tint(textColor, "#80ffffff") + wrapMode: desktopBehavior ? TextEdit.NoWrap : TextEdit.WordWrap + onCursorRectangleChanged: flickable.ensureVisible(cursorRectangle) + + onActiveFocusChanged: activeFocus ? openSoftwareInputPanel() : closeSoftwareInputPanel() + } + } + + Text { + id: placeholderTextComponent + x: leftMargin; y: topMargin + font: textEdit.font + opacity: !textEdit.text.length && !textEdit.activeFocus ? 1 : 0 + color: "gray" + clip: true + text: "Enter text" + Behavior on opacity { NumberAnimation { duration: 90 } } + } + + + TextEditMouseBehavior { + id: mouseEditBehavior + anchors.fill: parent + textEdit: textEdit + desktopBehavior: false + copyPasteButtons: ButtonBlock { + opacity: 0 // initially hidden + Behavior on opacity { NumberAnimation { duration: 100 } } + } + } + + DefaultStyles.TextFieldStyle { id: defaultStyle } +} + diff --git a/components/custom/TextField.qml b/components/custom/TextField.qml new file mode 100644 index 000000000..2af29427e --- /dev/null +++ b/components/custom/TextField.qml @@ -0,0 +1,196 @@ +import QtQuick 1.0 +import "./styles/default" as DefaultStyles +import "./behaviors" // TextEditMouseBehavior + +// KNOWN ISSUES +// 1) TextField does not loose focus when !enabled if it is a FocusScope (see QTBUG-16161) + +FocusScope { + id: textField + + property alias text: textInput.text + property alias font: textInput.font + + property int inputHint // values tbd + property bool acceptableInput: textInput.acceptableInput // read only + property bool 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 color textColor: syspal.text + property color backgroundColor: syspal.base + property alias containsMouse: mouseEditBehavior.containsMouse + + property Component background: defaultStyle.background + property Component hints: defaultStyle.hints + + property int minimumWidth: defaultStyle.minimumWidth + property int minimumHeight: defaultStyle.minimumHeight + + property int leftMargin: defaultStyle.leftMargin + property int topMargin: defaultStyle.topMargin + property int rightMargin: defaultStyle.rightMargin + property int bottomMargin: defaultStyle.bottomMargin + + 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); + } + + width: Math.max(minimumWidth, + textInput.width + leftMargin + rightMargin) + + height: Math.max(minimumHeight, + textInput.height + topMargin + bottomMargin) + + // Forward focus property + property alias activeFocus: textInput.activeFocus + + // Implementation + + property alias desktopBehavior: mouseEditBehavior.desktopBehavior + property alias _hints: hintsLoader.item + clip: true + + SystemPalette { id: syspal } + Loader { id: hintsLoader; sourceComponent: hints } + Loader { sourceComponent: background; anchors.fill:parent} + + TextInput { // see QTBUG-14936 + id: textInput + font.pixelSize: _hints.fontPixelSize + font.bold: _hints.fontBold + + anchors.leftMargin: leftMargin + anchors.topMargin: topMargin + anchors.rightMargin: rightMargin + anchors.bottomMargin: bottomMargin + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + opacity: desktopBehavior || activeFocus ? 1 : 0 + color: enabled ? textColor : Qt.tint(textColor, "#80ffffff") + echoMode: passwordMode ? _hints.passwordEchoMode : TextInput.Normal + + onActiveFocusChanged: { + if (!desktopBehavior) + state = (activeFocus ? "focused" : "") + + if (activeFocus) + openSoftwareInputPanel() + else + closeSoftwareInputPanel() + } + + states: [ + State { + name: "" + PropertyChanges { target: textInput; cursorPosition: 0 } + }, + State { + name: "focused" + PropertyChanges { target: textInput; cursorPosition: textInput.text.length } + } + ] + + transitions: Transition { + to: "focused" + SequentialAnimation { + ScriptAction { script: textInput.cursorVisible = false; } + ScriptAction { script: textInput.cursorPosition = textInput.positionAt(textInput.width); } + NumberAnimation { target: textInput; property: "cursorPosition"; duration: 150 } + ScriptAction { script: textInput.cursorVisible = true; } + } + } + } + + Text { + id: placeholderTextComponent + anchors.fill: textInput + font: textInput.font + opacity: !textInput.text.length && !textInput.activeFocus ? 1 : 0 + color: "gray" + text: "Enter text" + Behavior on opacity { NumberAnimation { duration: 90 } } + } + + Text { + id: unfocusedText + clip: true + anchors.fill: textInput + font: textInput.font + opacity: !desktopBehavior && !passwordMode && textInput.text.length && !textInput.activeFocus ? 1 : 0 + color: textInput.color + elide: Text.ElideRight + text: textInput.text + } + + + TextEditMouseBehavior { + id: mouseEditBehavior + anchors.fill: parent + textInput: textInput + desktopBehavior: false + copyPasteButtons: ButtonBlock { + opacity: 0 // initially hidden + Behavior on opacity { NumberAnimation { duration: 100 } } + } + } + + DefaultStyles.TextFieldStyle { id: defaultStyle } +} + + + + + + + + + + + + + + + diff --git a/components/custom/behaviors/ButtonBehavior.qml b/components/custom/behaviors/ButtonBehavior.qml new file mode 100644 index 000000000..391c870a7 --- /dev/null +++ b/components/custom/behaviors/ButtonBehavior.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 + +Item { + id: behavior + + signal clicked + property bool pressed: false // Can't be alias of mouseArea.pressed because the latter is read-only + property alias containsMouse: mouseArea.containsMouse + property bool checkable: false + property bool checked: false + property bool triState: false + + onCheckableChanged: { if(!checkable) checked = false } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onPressed: behavior.pressed = true // needed when hover is enabled + onEntered: if(pressed && enabled) behavior.pressed = true + onExited: behavior.pressed = false + onCanceled: behavior.pressed = false // mouse stolen e.g. by Flickable + onReleased: { + if(behavior.pressed && behavior.enabled) { // No click if release outside area + behavior.pressed = false + if(behavior.checkable) + behavior.checked = !behavior.checked; + behavior.clicked() + } + } + } +} diff --git a/components/custom/behaviors/ModalPopupBehavior.qml b/components/custom/behaviors/ModalPopupBehavior.qml new file mode 100644 index 000000000..108bf02ae --- /dev/null +++ b/components/custom/behaviors/ModalPopupBehavior.qml @@ -0,0 +1,90 @@ +import QtQuick 1.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/components/custom/behaviors/TextEditMouseBehavior.qml b/components/custom/behaviors/TextEditMouseBehavior.qml new file mode 100644 index 000000000..02175d5b9 --- /dev/null +++ b/components/custom/behaviors/TextEditMouseBehavior.qml @@ -0,0 +1,266 @@ +import QtQuick 1.0 + +// KNOWN ISSUES +// 1) Can't tell if the Paste button should be shown or not, see QTBUG-16190 +// 2) Hard to tell if the Select button should be shown (part of QTBUG-16190?) + +Item { + id: mouseBehavior + + property TextInput textInput + property TextEdit textEdit + property Flickable flickable + property bool desktopBehavior: true + property alias containsMouse: mouseArea.containsMouse + + property Component copyPasteButtons + + // Implementation + + property Item textEditor: Qt.isQtObject(textInput) ? textInput : textEdit + + Connections { + target: textInput + onTextChanged: reset() + onCursorPositionChanged: reset() + onSelectedTextChanged: reset() + onActiveFocusChanged: reset() + } + + function reset() { + copyPastePopup.showing = false; // hide and restart the visibility timer + copyPastePopup.showing = selectedText.length > 0 && !desktopBehavior; + copyPastePopup.wasCancelledByClick = false; + copyPastePopup.wasClosedByCopy = false; + } + + Component.onCompleted: { + textEditor.focus = true; + textEditor.selectByMouse = false; + textEditor.activeFocusOnPress = false; + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + drag.target: Item {} // work-around for Flickable stealing the mouse, which is expected (?), see QTBUG-15231 + + property int pressedPos + property int selectionStartAtPress + property int selectionEndAtPress + property bool hadFocusBeforePress + property bool draggingStartHandle + property bool draggingEndHandle + + function characterPositionAt(mouse) { + var mappedMouse = mapToItem(textEditor, mouse.x, mouse.y); + if(Qt.isQtObject(textInput)) { + return textInput.positionAt(mappedMouse.x); + } else { + return textEdit.positionAt(mappedMouse.x, mappedMouse.y); + } + } + + //mm see QTBUG-15814 + onPressed: { + hadFocusBeforePress = textEditor.activeFocus; + selectionStartAtPress = textEditor.selectionStart; + selectionEndAtPress = textEditor.selectionEnd; + + textEditor.forceActiveFocus(); //mm see QTBUG-16157 + var pos = characterPositionAt(mouse); + if(desktopBehavior) { + textEditor.cursorPosition = pos; + } else { + draggingStartHandle = false; // reset both to false, i.e. no dragging of selection endpoints + draggingEndHandle = false; + if(textEditor.selectionStart != textEditor.selectionEnd) { + draggingEndHandle = (pos > selectionStartAtPress + (selectionEndAtPress-selectionStartAtPress)/2); + draggingStartHandle = !draggingEndHandle; + } + } + + pressedPos = textEditor.cursorPosition; + } + + onPressAndHold: { + if(!desktopBehavior) { + if(!textEditor.selectedText.length) { //mm Somehow just having the onPressAndHold impementation interrupts the text selection + textEditor.cursorPosition = characterPositionAt(mouse); + } + } + } + + onReleased: { + if(!desktopBehavior) { + if(mouse.wasHeld) copyPastePopup.showing = true; + } + } + + onClicked: { + if(!desktopBehavior) { + if(!hadFocusBeforePress) + return; + + var pos = characterPositionAt(mouse); + if(textEditor.selectedText.length) { // clicked on or outside selection + if(copyPastePopup.wasClosedByCopy && pos >= textEditor.selectionStart && pos < textEditor.selectionEnd) + copyPastePopup.showing = true; + else + textEditor.select(textEditor.selectionEnd, textEditor.selectionEnd); //mm use deselect() from QtQuick 1.1 (see QTBUG-16059) + } else { // clicked while there's no selection + if(pos == textEditor.cursorPosition) { // Clicked where the cursor already where + copyPastePopup.showing = !copyPastePopup.wasCancelledByClick; + copyPastePopup.wasCancelledByClick = false; + } else { // Clicked in a new place (where the cursor wasn't) + var endOfWordRegEx = /[^\b]\b/g; + endOfWordRegEx.lastIndex = pos; + var endOfWordPosition = pos; + if(endOfWordRegEx.test(textEditor.text)) // updates lastIndex + endOfWordPosition = endOfWordRegEx.lastIndex; + + if(textEditor.cursorPosition != endOfWordPosition) { + textEditor.cursorPosition = endOfWordPosition; + } else { + copyPastePopup.showing = !copyPastePopup.wasCancelledByClick; + copyPastePopup.wasCancelledByClick = false; + } + } + } + } + + textEditor.openSoftwareInputPanel() + } + + onPositionChanged: { + if(!pressed) + return; + + var pos = characterPositionAt(mouse); + if(desktopBehavior) { + textEditor.select(pressedPos, pos); + } else { + if(draggingStartHandle) { + textEditor.select(selectionEndAtPress, pos); + } else if(draggingEndHandle) { + textEditor.select(selectionStartAtPress, pos); + } else if(mouse.wasHeld && textEditor.cursorPosition != pos) { // there's no selection + textEditor.cursorPosition = pos; + copyPastePopup.showing = true; // show once not pressed any more + } + } + } + + onDoubleClicked: { + if(desktopBehavior) + textEditor.selectAll(); + else { + textEditor.cursorPosition = characterPositionAt(mouse); + textEditor.selectWord(); // select word at cursor position + } + } + } + + + function selectionPopoutPoint() { + var point = {x:0, y:0} + + var selectionStartRect = textEditor.positionToRectangle(textEditor.selectionStart); + var mappedStartPoint = mapFromItem(textEditor, selectionStartRect.x, selectionStartRect.y); + mappedStartPoint.x = Math.max(mappedStartPoint.x, 0); + mappedStartPoint.y = Math.max(mappedStartPoint.y, 0); + + var selectioEndRect = textEditor.positionToRectangle(textEditor.selectionEnd); + var mappedEndPoint = mapFromItem(textEditor, selectioEndRect.x, selectioEndRect.y); + mappedEndPoint.x = Math.min(mappedEndPoint.x, textEditor.width); + mappedEndPoint.y = Math.min(mappedEndPoint.y, textEditor.height); + + var multilineSelection = (selectionStartRect.y != selectioEndRect.y); + if(!multilineSelection) { + point.x = mappedStartPoint.x + (mappedEndPoint.x-mappedStartPoint.x)/2 + } else { + point.x = textEditor.x + textEdit.width/2; + } + + point.y = mappedStartPoint.y + return point; + } + + Item { + id: copyPastePopup + + property alias showing: modalPopup.showing + property bool wasCancelledByClick: false + property bool wasClosedByCopy: false + + property bool showCopyAction: textEditor.selectedText.length > 0 + property bool showCutAction: textEditor.selectedText.length > 0 + property bool showPasteAction: true //textEditor.canPaste //mm see QTBUG-16190 + property bool showSelectAction: textEditor.text.length > 0 && textEditor.selectedText.length < textEditor.text.length // need canSelectWord, see QTBUG-16190 + property bool showSelectAllAction: textEditor.text.length > 0 && textEditor.selectedText.length < textEditor.text.length + + ListModel { + id: popupButtonModel + ListElement { text: "Copy"; opacity: 0 } // index: 0 + ListElement { text: "Cut"; opacity: 0 } // index: 1 + ListElement { text: "Paste"; opacity: 1 } // index: 2 + ListElement { text: "Select"; opacity: 0 } // index: 3 + ListElement { text: "Select all"; opacity: 0 } // index: 4 + } + + onShowCopyActionChanged: popupButtonModel.setProperty(0, "opacity", showCopyAction ? 1 : 0); + onShowCutActionChanged: popupButtonModel.setProperty(1, "opacity", showCutAction ? 1 : 0); + onShowPasteActionChanged: popupButtonModel.setProperty(2, "opacity", showPasteAction ? 1 : 0); + onShowSelectActionChanged: popupButtonModel.setProperty(3, "opacity", showSelectAction ? 1 : 0); + onShowSelectAllActionChanged: popupButtonModel.setProperty(4, "opacity", showSelectAllAction ? 1 : 0); + + Component.onCompleted: { + showCopyActionChanged(); + showCutActionChanged(); + showPasteActionChanged(); + showSelectActionChanged(); + showSelectAllActionChanged(); + } + + function positionPopout(popup, window) { // position poput above the text field's cursor + var popoutPoint = selectionPopoutPoint(); + var mappedPos = mapToItem(window, popoutPoint.x, popoutPoint.y); + popup.x = Math.max(mappedPos.x - popup.width/2, 0); + if(popup.x+popup.width > window.width) + popup.x = window.width-popup.width; + + popup.y = mappedPos.y - popup.height; + if(popup.y < 0) + popup.y += popup.height + textEditor.height; + } + + ModalPopupBehavior { + id: modalPopup + consumeCancelClick: false + whenAlso: !mouseArea.pressed + delay: 300 + onPrepareToShow: copyPastePopup.positionPopout(popup, window) + onCancelledByClick: copyPastePopup.wasCancelledByClick = true + + popupComponent: copyPasteButtons + onPopupChanged: if(popup) popup.model = popupButtonModel + + Connections { + target: modalPopup.popup + onClicked: { + if(index == 0) { + textEditor.copy(); + copyPastePopup.showing = false; + copyPastePopup.wasClosedByCopy = true; + } + if(index == 1) textEditor.cut(); + if(index == 2) textEditor.paste(); + if(index == 3) textEditor.selectWord(); + if(index == 4) textEditor.selectAll(); + } + } + } + } +} + diff --git a/components/custom/components.pro b/components/custom/components.pro new file mode 100644 index 000000000..be0663d70 --- /dev/null +++ b/components/custom/components.pro @@ -0,0 +1,49 @@ +TEMPLATE = subdirs # XXX: Avoid call the linker +TARGETPATH = Qt/labs/components/custom + +symbian { + INSTALL_IMPORTS = /resource/qt/imports +} else { + INSTALL_IMPORTS = $$[QT_INSTALL_IMPORTS] +} + +QML_FILES = \ + qmldir \ + BasicButton.qml \ + BusyIndicator.qml \ + ButtonBlock.qml \ + ButtonColumn.qml \ + ButtonRow.qml \ + ButtonGroup.js \ + Button.qml \ + CheckBox.qml \ + ChoiceList.qml \ + ProgressBar.qml \ + RadioButton.qml \ + ScrollDecorator.qml \ + ScrollIndicator.qml \ + Slider.qml \ + SpinBox.qml \ + Switch.qml \ + TextArea.qml \ + TextField.qml + +QML_DIRS = \ + behaviors \ + private \ + styles \ + visuals + +qmlfiles.files = $$QML_FILES +qmlfiles.sources = $$QML_FILES +qmlfiles.path = $$INSTALL_IMPORTS/$$TARGETPATH + +qmldirs.files = $$QML_DIRS +qmldirs.sources = $$QML_DIRS +qmldirs.path = $$INSTALL_IMPORTS/$$TARGETPATH + +INSTALLS += qmlfiles qmldirs + +symbian { + DEPLOYMENT += qmlfiles qmldirs +} diff --git a/components/custom/private/ChoiceListPopup.qml b/components/custom/private/ChoiceListPopup.qml new file mode 100644 index 000000000..61a0d2220 --- /dev/null +++ b/components/custom/private/ChoiceListPopup.qml @@ -0,0 +1,269 @@ +import QtQuick 1.0 + +MouseArea { + id: popup + // There is no global toplevel so we have to make one + // We essentially reparent this item to the root item + Component.onCompleted: { + var p = parent; + while (p.parent != undefined) + p = p.parent + parent = p; + } + + anchors.fill: parent // fill the while app area + opacity: popupFrameLoader.item.opacity // let the frame control opacity, so it can set the behavior + + property string behavior: "MacOS" + property bool desktopBehavior: (behavior == "MacOS" || behavior == "Windows" || behavior == "Linux") + property int previousCurrentIndex: -1 // set in state transition last in this file + + property alias model: listView.model + property alias currentIndex: listView.currentIndex + + property Component listItem + property Component listHighlight + property Component popupFrame + + function togglePopup() { state = (state == "" ? "hidden" : "") } + function setCurrentIndex(index) { listView.currentIndex = index; } + function cancelSelection() { listView.currentIndex = previousCurrentIndex; } + function closePopup() { state = "hidden" } + + function positionPopup() { + switch(behavior) { + case "MacOS": + var mappedListPos = mapFromItem(choiceList, 0, 0); + var itemHeight = Math.max(listView.contentHeight/listView.count, 0); + var currentItemY = Math.max(currentIndex*itemHeight, 0); + currentItemY += Math.floor(itemHeight/2 - choiceList.height/2); // correct for choiceLists that are higher than items in the list + + listView.y = mappedListPos.y - currentItemY; + listView.x = mappedListPos.x; + + listView.width = choiceList.width; + listView.height = listView.contentHeight //mm see QTBUG-16037 + + if(listView.y < topMargin) { + var excess = Math.floor(currentItemY - mappedListPos.y); + listView.y = topMargin; + listView.height += excess; + listView.contentY = excess + topMargin; + + if(listView.contentY != excess+topMargin) //mm setting listView.height seems to make it worse + print("!!! ChoiceListPopup.qml: listView.contentY should be " + excess+topMargin + " but is " + listView.contentY) + } + + if(listView.height+listView.contentY > listView.contentHeight) { + listView.height = listView.contentHeight-listView.contentY; + } + + if(listView.y+listView.height+bottomMargin > popup.height) { + listView.height = popup.height-listView.y-bottomMargin; + } + break; + case "Windows": + var point = popup.mapFromItem(choiceList, 0, listView.height); + listView.y = point.y; + listView.x = point.x; + + listView.width = choiceList.width; + listView.height = 200; + + break; + case "MeeGo": + break; + } + } + + Loader { + id: popupFrameLoader + property alias styledItem: popup.parent + anchors.fill: listView + anchors.leftMargin: -item.anchors.leftMargin + anchors.rightMargin: -item.anchors.rightMargin + anchors.topMargin: -item.anchors.topMargin + anchors.bottomMargin: -item.anchors.bottomMargin + sourceComponent: popupFrame + } + + ListView { + id: listView + focus: true + boundsBehavior: desktopBehavior ? ListView.StopAtBounds : ListView.DragOverBounds + keyNavigationWraps: !desktopBehavior + highlightFollowsCurrentItem: false // explicitly handled below + + interactive: !desktopBehavior // disable flicking. also disables key handling + onCurrentItemChanged: { + if(desktopBehavior) { + positionViewAtIndex(currentIndex, ListView.Contain); + } + } + + property int highlightedIndex: -1 + onHighlightedIndexChanged: positionViewAtIndex(highlightedIndex, ListView.Contain) + + property variant highlightedItem: null + onHighlightedItemChanged: { + if(desktopBehavior) { + positionHighlight(); + } + } + + function positionHighlight() { + if(!Qt.isQtObject(highlightItem)) + return; + + if(!Qt.isQtObject(highlightedItem)) { + highlightItem.opacity = 0; // hide when no item is highlighted + } else { + highlightItem.x = highlightedItem.x; + highlightItem.y = highlightedItem.y; + highlightItem.width = highlightedItem.width; + highlightItem.height = highlightedItem.height; + highlightItem.opacity = 1; // show once positioned + } + } + + function hideHighlight() { + highlightedIndex = -1; + highlightedItem = null; // will trigger positionHighlight() what will hide the highlight + } + + delegate: Item { + id: itemDelegate + width: delegateLoader.item.width + height: delegateLoader.item.height + property int theIndex: index // for some reason the loader can't bind directly to the "index" + + Loader { + id: delegateLoader + property variant model: listView.model + property alias index: itemDelegate.theIndex //mm Somehow the "model" gets through automagically, but not index + property Item styledItem: choiceList + property bool highlighted: theIndex == listView.highlightedIndex + sourceComponent: listItem + MouseArea { // handle list selection on mobile platforms + id:itemMouseArea + anchors.fill: parent + onClicked: { setCurrentIndex(index); closePopup(); } + } + } + + states: State { + name: "highlighted" + when: index == listView.highlightedIndex + StateChangeScript { + script: { + if(Qt.isQtObject(listView.highlightedItem)) { + listView.highlightedItem.yChanged.disconnect(listView.positionHighlight); + } + listView.highlightedItem = itemDelegate; + listView.highlightedItem.yChanged.connect(listView.positionHighlight); + } + } + + } + } + + function firstVisibleItem() { return indexAt(contentX+10,contentY+10); } + function lastVisibleItem() { return indexAt(contentX+width-10,contentY+height-10); } + function itemsPerPage() { return lastVisibleItem() - firstVisibleItem(); } + + Keys.onPressed: { + // with the ListView !interactive (non-flicking) we have to handle arrow keys + if (event.key == Qt.Key_Up) { + if(!highlightedItem) highlightedIndex = lastVisibleItem(); + else if(highlightedIndex > 0) highlightedIndex--; + } else if (event.key == Qt.Key_Down) { + if(!highlightedItem) highlightedIndex = firstVisibleItem(); + else if(highlightedIndex+1 < model.count) highlightedIndex++; + } else if (event.key == Qt.Key_PageUp) { + if(!highlightedItem) highlightedIndex = lastVisibleItem(); + else highlightedIndex = Math.max(highlightedIndex-itemsPerPage(), 0); + } else if (event.key == Qt.Key_PageDown) { + if(!highlightedItem) highlightedIndex = firstVisibleItem(); + else highlightedIndex = Math.min(highlightedIndex+itemsPerPage(), model.count-1); + } else if (event.key == Qt.Key_Home) { + highlightedIndex = 0; + } else if (event.key == Qt.Key_End) { + highlightedIndex = model.count-1; + } else if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + if(highlightedIndex != -1) { + popup.setCurrentIndex(highlightedIndex); + } else { + popup.cancelSelection(); + } + + popup.closePopup(); + } else if (event.key == Qt.Key_Escape) { + popup.cancelSelection(); + popup.closePopup(); + } + event.accepted = true; // consume all keys while popout has focus + } + + highlight: popup.listHighlight + } + + enabled: (state != "hidden") // to avoid stray events when poput is about to close + hoverEnabled: true + onClicked: { popup.cancelSelection(); popup.closePopup(); } // clicked outside the list + onPressed: { + var mappedPos = mapToItem(listView.contentItem, mouse.x, mouse.y); + var indexAt = listView.indexAt(mappedPos.x, mappedPos.y); + if(indexAt != -1) { + listView.currentIndex = indexAt; + } + } + onPositionChanged: { + var mappedPos = mapToItem(listView.contentItem, mouse.x, mouse.y); + var indexAt = listView.indexAt(mappedPos.x, mappedPos.y); + if(!pressed) { // hovering + if(indexAt == listView.highlightedIndex) + return; + + if(indexAt >= 0) { + listView.highlightedIndex = indexAt; + } else { + if(mouse.y > listView.y+listView.height && listView.highlightedIndex+1 < listView.count ) { + listView.highlightedIndex++; + } else if(mouse.y < listView.y && listView.highlightedIndex > 0) { + listView.highlightedIndex--; + } else if(mouse.x < popupFrameLoader.x || mouse.x > popupFrameLoader.x+popupFrameLoader.width) { + listView.hideHighlight(); + } + } + } + } + + state: "hidden" // hidden by default + states: [ + State { + name: "" // not hidden, i.e. showing + PropertyChanges { target: popupFrameLoader.item; opacity: 1 } + }, + State { + name: "hidden" + PropertyChanges { target: popupFrameLoader.item; opacity: 0 } + } + ] + + transitions: [ + Transition { to: ""; + ScriptAction { + script: { + previousCurrentIndex = currentIndex; + positionPopup(); + listView.forceActiveFocus(); + } + } + }, + Transition { to: "hidden"; ScriptAction { script: listView.hideHighlight(); } } + ] +} + + + + diff --git a/components/custom/qmldir b/components/custom/qmldir new file mode 100644 index 000000000..6e256a81d --- /dev/null +++ b/components/custom/qmldir @@ -0,0 +1,17 @@ +BasicButton 1.0 BasicButton.qml +BusyIndicator 1.0 BusyIndicator.qml +ButtonBlock 1.0 ButtonBlock.qml +Button 1.0 Button.qml +ButtonColumn 1.0 ButtonColumn.qml +ButtonRow 1.0 ButtonRow.qml +CheckBox 1.0 CheckBox.qml +ChoiceList 1.0 ChoiceList.qml +ProgressBar 1.0 ProgressBar.qml +RadioButton 1.0 RadioButton.qml +ScrollDecorator 1.0 ScrollDecorator.qml +ScrollIndicator 1.0 ScrollIndicator.qml +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +Switch 1.0 Switch.qml +TextArea 1.0 TextArea.qml +TextField 1.0 TextField.qml diff --git a/components/custom/styles/default/BasicButtonStyle.qml b/components/custom/styles/default/BasicButtonStyle.qml new file mode 100644 index 000000000..08b18040e --- /dev/null +++ b/components/custom/styles/default/BasicButtonStyle.qml @@ -0,0 +1,8 @@ +import QtQuick 1.1 + +QtObject { + property int minimumWidth: 40 + property int minimumHeight: 25 + + property Component background: Component { Item { } } +} diff --git a/components/custom/styles/default/BusyIndicatorStyle.qml b/components/custom/styles/default/BusyIndicatorStyle.qml new file mode 100644 index 000000000..83ef46fd7 --- /dev/null +++ b/components/custom/styles/default/BusyIndicatorStyle.qml @@ -0,0 +1,21 @@ +import QtQuick 1.0 + +QtObject { + property Component background: + Component { + Image { + opacity: running ? 1.0 : 0.7 //mm Should the rotation fade and stop when indicator is !enabled? + source: "images/spinner.png"; + fillMode: Image.PreserveAspectFit + smooth: true + + property int steps: 12 + property int rotationStep: 0 + rotation: rotationStep*(360/steps) + NumberAnimation on rotationStep { + running: busyIndicator.running; from: 0; to: steps; //mm see QTBUG-15652 + loops: Animation.Infinite; duration: 1000 // 1s per revolution + } + } + } +} diff --git a/components/custom/styles/default/ButtonBlockStyle.qml b/components/custom/styles/default/ButtonBlockStyle.qml new file mode 100644 index 000000000..f0bed8654 --- /dev/null +++ b/components/custom/styles/default/ButtonBlockStyle.qml @@ -0,0 +1,77 @@ +import QtQuick 1.0 + +QtObject { + property int minimumWidth: 90 + property int minimumHeight: 32 + + property int leftMargin : 8 + property int topMargin: 8 + property int rightMargin: 8 + property int bottomMargin: 8 + + property Component background: + Component { + id: defaultBackground + Item { + opacity: enabled ? 1 : 0.7 + Rectangle { // Background center fill + anchors.fill: parent + anchors.leftMargin: adjoining&Qt.Horizontal ? 0 : 2 + anchors.rightMargin: anchors.leftMargin + anchors.topMargin: adjoining&Qt.Vertical ? 0 : 2 + anchors.bottomMargin: anchors.topMargin + + radius: adjoining ? 0 : 5 + color: !styledItem.checked ? backgroundColor : Qt.darker(backgroundColor) + } + BorderImage { + anchors.fill: parent + smooth: true + source: { + if(!adjoining) + return styledItem.pressed || styledItem.checked ? "images/button_pressed.png" : "images/button_normal.png"; + else if(adjoining&Qt.Horizontal) + return styledItem.pressed || styledItem.checked ? "images/buttongroup_h_pressed.png" : "images/buttongroup_h_normal.png"; + else // adjoining&Qt.Vertical + return styledItem.pressed || styledItem.checked ? "images/buttongroup_v_pressed.png" : "images/buttongroup_v_normal.png"; + } + border.left: 6; border.top: 6 + border.right: 6; border.bottom: 6 + } + } + } + + property Component label: + Component { + id: defaultLabel + Item { + width: row.width + height: row.height + anchors.centerIn: parent //mm see QTBUG-15619 + opacity: styledItem.enabled ? 1 : 0.5 + transform: Translate { + x: styledItem.pressed || styledItem.checked ? 1 : 0 + y: styledItem.pressed || styledItem.checked ? 1 : 0 + } + + Row { + id: row + anchors.centerIn: parent + spacing: 4 + Image { + source: styledItem.iconSource + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.Stretch //mm Image should shrink if button is too small, depends on QTBUG-14957 + } + + Text { + color: styledItem.textColor + anchors.verticalCenter: parent.verticalCenter + text: styledItem.text + horizontalAlignment: Text.Center + elide: Text.ElideRight //mm can't make layout work as desired without implicit size support, see QTBUG-14957 + } + } + } + } +} diff --git a/components/custom/styles/default/ButtonStyle.qml b/components/custom/styles/default/ButtonStyle.qml new file mode 100644 index 000000000..a0e5f3302 --- /dev/null +++ b/components/custom/styles/default/ButtonStyle.qml @@ -0,0 +1,102 @@ +import QtQuick 1.1 + +QtObject { + property int minimumWidth: 90 + property int minimumHeight: 32 + + property int leftMargin: 8 + property int topMargin: 8 + property int rightMargin: 8 + property int bottomMargin: 8 + + property Component background: Component { + Item { + opacity: enabled ? 1 : 0.7 + clip: true // clip connected buttons, as they overlap to remove the rounded edjes + property bool isPositioned: position != "only" // only evaluate for rows and columns + + Item { + anchors.fill: parent + // Give connected buttons a negative styling margin, to make + // them overlap and the rounded edge can be clipped away + anchors.leftMargin: isPositioned && (position == "rightmost" || position =="h_middle") ? -leftMargin : 0 + anchors.rightMargin: isPositioned && (position == "leftmost" || position =="h_middle") ? -rightMargin : 0 + anchors.topMargin: isPositioned && (position == "bottom" || position =="v_middle") ? -bottomMargin : 0 + anchors.bottomMargin: isPositioned && (position == "top" || position =="v_middle") ? -topMargin : 0 + + Rectangle { // Background center fill + anchors.fill: parent + anchors.leftMargin: anchors.leftMargin + anchors.rightMargin: anchors.rightMargin + anchors.topMargin: anchors.topMargin + anchors.bottomMargin: anchors.bottomMargin + radius: 5 + color: backgroundColor + } + BorderImage { + anchors.fill: parent + smooth: true + source: pressed || checked ? "images/button_pressed.png" : "images/button_normal.png"; + border.left: 6; border.top: 6 + border.right: 6; border.bottom: 6 + } + } + + // Draw straight border lines between connected buttons + Rectangle { + width: 1 + visible: isPositioned && !checked && !pressed && (position == "rightmost" || position == "h_middle") + anchors.top: parent.top + anchors.topMargin: 2 + anchors.bottomMargin: 2 + anchors.bottom: parent.bottom + anchors.left: parent.left + opacity: 0.4 + color: "white" + } + Rectangle { + width: 1 + opacity: 0.4 + visible: isPositioned && !checked && !pressed && (position == "leftmost" || position == "h_middle") + anchors.top: parent.top + anchors.topMargin: 2 + anchors.bottomMargin: 2 + anchors.bottom: parent.bottom + anchors.right: parent.right + color: "black" + } + } + } + + property Component label: Component { + Item { + implicitWidth: row.implicitWidth + implicitHeight: row.implicitHeight + + opacity: enabled ? 1 : 0.5 + transform: Translate { + x: pressed || checked ? 1 : 0 + y: pressed || checked ? 1 : 0 + } + + 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 { + color: textColor + anchors.verticalCenter: parent.verticalCenter + text: styledItem.text + horizontalAlignment: Text.Center + elide: Text.ElideRight //mm can't make layout work as desired without implicit size support, see QTBUG-14957 + } + } + } + } +} diff --git a/components/custom/styles/default/CheckBoxStyle.qml b/components/custom/styles/default/CheckBoxStyle.qml new file mode 100644 index 000000000..f5e5fdded --- /dev/null +++ b/components/custom/styles/default/CheckBoxStyle.qml @@ -0,0 +1,34 @@ +import QtQuick 1.1 + +QtObject { + property int minimumWidth: 32 + property int minimumHeight: 32 + + property Component background: Component { + Item { + width: styledItem.implicitWidth; height: styledItem.implicitHeight + opacity: enabled ? 1 : 0.7 + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + radius: 5 + color: backgroundColor + } + BorderImage { + anchors.fill: parent + source: "images/lineedit_normal.png" + smooth: true + border.left: 6; border.top: 3 + border.right: 6; border.bottom: 3 + } + } + } + + property Component checkmark: Component { + Image { + source: "images/checkbox_check.png" + opacity: (!enabled && checked) || pressed == true ? 0.5 : (!checked ? 0 : 1) + Behavior on opacity { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } + } + } +} diff --git a/components/custom/styles/default/ChoiceListStyle.qml b/components/custom/styles/default/ChoiceListStyle.qml new file mode 100644 index 000000000..12b10ffd5 --- /dev/null +++ b/components/custom/styles/default/ChoiceListStyle.qml @@ -0,0 +1,100 @@ +import QtQuick 1.0 + +QtObject { + property int minimumWidth: 200 + property int minimumHeight: 32 + + property int leftMargin: 8 + property int topMargin: 8 + property int rightMargin: 34 + property int bottomMargin: 8 + + property Component background: Component { + Item { + opacity: enabled ? 1 : 0.8 + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + color: backgroundColor + radius: 5 + } + BorderImage { + anchors.fill: parent + id: backgroundimage + smooth: true + source: styledItem.pressed ? "images/button_pressed.png" : "images/button_normal.png" + width: 80; height: 24 + border.left: 3; border.top: 3 + border.right: 3; border.bottom: 3 + Image { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 10 + opacity: enabled ? 1 : 0.3 + source:"images/spinbox_down.png" + } + } + } + } + + property Component label: Component { + Text { + id:t + color: textColor + text: model && currentIndex >= 0 ? model.get(currentIndex).text : "" + opacity: enabled ? 1 : 0.5 + } + } + + // Popout styling + + property Component popupFrame: Component { + Item { + Behavior on opacity { NumberAnimation { easing.type: Easing.OutQuad; duration: 250 } } + + anchors.leftMargin: 6 + anchors.topMargin: 6 + anchors.rightMargin: 7 + anchors.bottomMargin: 6 + + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + color: backgroundColor + radius: 5 + } + BorderImage { + anchors.fill: parent + id: backgroundimage + smooth: true + source: "images/button_normal.png" + width: 80; height: 24 + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + } + } + } + + property Component listItem: Component { + Rectangle { + width: styledItem.width + height: Math.max(itemText.height, 28) + color: highlighted ? "#556699" : "transparent" + radius:2 + border.width:1 + border.color:Qt.darker(color) + clip:true + Text { + id: itemText + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 6 + + font.bold: index == currentIndex + color: highlighted ? "white" : styledItem.textColor + anchors.margins: 10 + text: model ? model.get(index).text : "" // list properties can't be automatically be added to the scope, so use get() + } + } + } +} diff --git a/components/custom/styles/default/ProgressBarStyle.qml b/components/custom/styles/default/ProgressBarStyle.qml new file mode 100644 index 000000000..7cb9795c1 --- /dev/null +++ b/components/custom/styles/default/ProgressBarStyle.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions contained +** in the Technology Preview License Agreement accompanying this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +import QtQuick 1.0 + +QtObject { + property int minimumWidth: 200 + property int minimumHeight: 25 + + property int leftMargin: 0 + property int rightMargin: 0 + property int topMargin: 0 + property int bottomMargin: 0 + + property Component background: Component { + Item{ + Rectangle{ + anchors.fill:parent + width: parent.width-2 + height: parent.height-2 + color: backgroundColor + radius: 5 + } + BorderImage { + anchors.fill:parent + source:"images/progressbar_groove.png" + border.left:10; border.right:10 + border.top:10; border.bottom:10 + } + } + } + + property Component progress: Component { // progress bar, known duration + BorderImage { // green progress indication + id:progress + opacity: styledItem.enabled ? 1: 0.7 + source: complete > 0.95 ? + "images/progressbar_indeterminate.png" : "images/progressbar_fill.png" + border.left:complete > 0.1 ? 6: 2; + border.right:complete > 0.1 ? 6: 2 + border.top:10; border.bottom:10 + clip:true + + Rectangle{ + anchors.fill:progress + color: styledItem.progressColor + z:-1 + radius:2 + smooth:true + clip:true + anchors.rightMargin:0 + anchors.margins:1 + Image { + id: overlay + NumberAnimation on x { + loops:Animation.Infinite; + from:0; + to:-overlay.sourceSize.width; + duration:2000 + } + width:styledItem.width + sourceSize.width + height:styledItem.height + fillMode:Image.Tile + source: "images/progressbar_overlay.png" + } + } + } + } + + property Component indeterminateProgress: Component { // progress bar, unknown duration + Item { + id: bar + anchors.fill:parent + onWidthChanged:indicator.x = width-indicator.width + BorderImage { + id:indicator + opacity: styledItem.enabled ? 1: 0.7 + Behavior on x { + NumberAnimation{easing.type:Easing.Linear; duration:1000} + } + onXChanged: { + var w = bar.width - indicator.width + if (x == w) x = 0 + else if (x==0) x = w + } + width: 80 + height: parent.height + source:"images/progressbar_indeterminate.png" + border.left:10 ; border.right:10 + border.top:10 ; border.bottom:10 + clip:true + + Rectangle{ + anchors.fill:indicator + color: styledItem.progressColor + z:-1 + radius:2 + smooth:true + clip:true + anchors.rightMargin:0 + anchors.margins:1 + Image { + id: overlay + NumberAnimation on x { + loops:Animation.Infinite; + from:0; + to:-overlay.sourceSize.width; + duration:2000 + } + width:styledItem.width + sourceSize.width + height:styledItem.height + fillMode:Image.Tile + source: "images/progressbar_overlay.png" + } + } + } + } + } +} diff --git a/components/custom/styles/default/RadioButtonStyle.qml b/components/custom/styles/default/RadioButtonStyle.qml new file mode 100644 index 000000000..0381993e4 --- /dev/null +++ b/components/custom/styles/default/RadioButtonStyle.qml @@ -0,0 +1,34 @@ +import QtQuick 1.1 +import "tools" as StyleTools + +QtObject { + property int minimumWidth: 32 + property int minimumHeight: 32 + + property Component background: Component { + Item { + width: styledItem.implicitWidth; height: styledItem.implicitHeight + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + radius: width/2 + color: backgroundColor + } + Image { + opacity: enabled ? 1 : 0.7 + source: "images/radiobutton_normal.png" + fillMode: Image.Stretch + anchors.centerIn: parent + } + } + } + + property Component checkmark: Component { + Image { + StyleTools.ColorConverter { id: cc; color: backgroundColor } + source: cc.grayValue() < 70? "images/radiobutton_check_white.png" : "images/radiobutton_check.png" + opacity: (!enabled && checked) || pressed == true ? 0.5 : (!checked ? 0 : 1) + Behavior on opacity { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } + } + } +} diff --git a/components/custom/styles/default/ScrollIndicatorStyle.qml b/components/custom/styles/default/ScrollIndicatorStyle.qml new file mode 100644 index 000000000..8e8826cda --- /dev/null +++ b/components/custom/styles/default/ScrollIndicatorStyle.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 + +QtObject { + property int minimumWidth: 12 + property int minimumHeight: 40 + + property Component content: Component { + Item { + Rectangle { + anchors.fill: parent + anchors.margins: 3 + border.color: "black" + color: "gray" + radius: width/2 + } + } + } +} diff --git a/components/custom/styles/default/SliderStyle.qml b/components/custom/styles/default/SliderStyle.qml new file mode 100644 index 000000000..d32f13eb7 --- /dev/null +++ b/components/custom/styles/default/SliderStyle.qml @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions contained +** in the Technology Preview License Agreement accompanying this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +import QtQuick 1.0 + +QtObject { + + property int minimumWidth: 200 + property int minimumHeight: 40 + + property int leftMargin : 2 + property int topMargin: 0 + property int rightMargin: 2 + property int bottomMargin: 0 + + property Component groove: Item { + opacity: enabled ? 1.0 : 0.7 + + Rectangle { + color: backgroundColor + anchors.fill: sliderBackground + anchors.margins: 1 + radius: 2 + } + + Rectangle { + property real zeroPos : positionForValue(0) + property real handlePos: handlePosition + color: progressColor + height: 10 + radius: 4 + anchors.verticalCenter: parent.verticalCenter + x: zeroPos + width: handlePos - x + } + + BorderImage { + id: sliderBackground + anchors.verticalCenter: parent.verticalCenter + width: parent.width + border.top: 2 + border.bottom: 2 + border.left: 12 + border.right: 12 + source: "images/slider.png" + } + } + + property Component handle: Item { + width: handleImage.width + height: handleImage.height + anchors.verticalCenter: parent.verticalCenter + + Image { + id: handleImage + Rectangle { + anchors.centerIn: parent + anchors.horizontalCenterOffset: -1 + width: parent.width - 7 + height: parent.height - 7 + smooth: true + color: backgroundColor + radius: Math.floor(parent.width / 2) + z: -1 // behind the image + } + anchors.centerIn: parent; + source: "images/handle.png" + smooth: true + } + } + + property Component valueIndicator: Rectangle { + width: valueText.width + 20 + height: valueText.height + 20 + color: "gray" + opacity: pressed ? 0.9 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + radius: 5 + + Text { + id: valueText + anchors.margins: 10 + anchors.centerIn: parent + text: indicatorText + } + } +} diff --git a/components/custom/styles/default/SpinBoxStyle.qml b/components/custom/styles/default/SpinBoxStyle.qml new file mode 100644 index 000000000..d42267d8d --- /dev/null +++ b/components/custom/styles/default/SpinBoxStyle.qml @@ -0,0 +1,73 @@ +import QtQuick 1.0 + +QtObject { + + property int minimumWidth: 200 + property int minimumHeight: 25 + + property int leftMargin : 8 + property int topMargin: 8 + property int rightMargin: 8 + property int bottomMargin: 8 + + property Component background: + Component { + id: defaultBackground + Item { + opacity: enabled ? 1 : 0.7 + Rectangle { + x: 1 + y: 1 + width: parent.width-2 + height: parent.height-2 + color: backgroundColor + radius: 5 + } + + BorderImage { + anchors.fill: parent + id: backgroundimage + smooth: true + source: "images/lineedit_normal.png" + border.left: 6; border.top: 6 + border.right: 50; border.bottom: 6 + } + } + } + + property Component up: + Component { + id: defaultUp + Item { + anchors.right: parent.right + anchors.top: parent.top + width: 24 + height: parent.height/2 + Image { + anchors.left: parent.left; + anchors.top: parent.top; + anchors.topMargin: 7 + opacity: (upEnabled && enabled) ? (upPressed ? 1 : 0.8) : 0.3 + source: "images/spinbox_up.png" + } + } + } + + property Component down: + Component { + id: defaultDown + Item { + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 24 + height: parent.height/2 + Image { + anchors.left: parent.left; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 7 + opacity: (downEnabled && enabled) ? (downPressed ? 1 : 0.8) : 0.3 + source: "images/spinbox_down.png" + } + } + } +} diff --git a/components/custom/styles/default/SwitchStyle.qml b/components/custom/styles/default/SwitchStyle.qml new file mode 100644 index 000000000..35e6f235e --- /dev/null +++ b/components/custom/styles/default/SwitchStyle.qml @@ -0,0 +1,71 @@ +import QtQuick 1.1 + +QtObject { + property int minimumWidth: 80 + property int minimumHeight: 32 + + property Component groove: Component { + Item { + opacity: enabled ? 1 : 0.7 + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + radius: 5 + color: backgroundColor + } + + Item { // Clipping container of the positive and negative groove highlight + anchors.fill: parent + anchors.margins: 2 + clip: true + + Item { // The highlight item is twice the width of there switch, clipped by its parent, + // and sliding back and forth keeping the center under the handle + height: parent.height + width: 2*parent.width + x: handleCenterX-parent.width-parent.anchors.leftMargin + + Rectangle { // positive background highlight + color: positiveHighlightColor + opacity: 0.8 + anchors.top: parent.top; anchors.bottom: parent.bottom + anchors.left: parent.left; anchors.right: parent.horizontalCenter + } + Rectangle { // negative background highlight + color: negativeHighlightColor + opacity: 0.8 + anchors.top: parent.top; anchors.bottom: parent.bottom + anchors.left: parent.horizontalCenter; anchors.right: parent.right + } + } + } + + BorderImage { // Rounded border + anchors.fill: parent + source: "images/lineedit_normal.png" + border { left: 6; right: 6; top: 3; bottom: 3 } + smooth: true + } + } + } + + property Component handle: Component { + Item { + width: 42 + Rectangle { // center fill + anchors.fill: parent + anchors.margins: 1 + radius: 5 + color: switchColor + } + BorderImage { + anchors.fill: parent + opacity: enabled ? 1 : 0.7 + smooth: true + source: pressed ? "images/button_pressed.png" : "images/button_normal.png" + border { left: 4; top: 4; right: 4; bottom: 4 } + } + Behavior on x { NumberAnimation { easing.type: Easing.OutCubic; duration: 200 } } + } + } +} diff --git a/components/custom/styles/default/TextFieldStyle.qml b/components/custom/styles/default/TextFieldStyle.qml new file mode 100644 index 000000000..38da6b0db --- /dev/null +++ b/components/custom/styles/default/TextFieldStyle.qml @@ -0,0 +1,41 @@ +import QtQuick 1.0 + +QtObject { + + property int minimumWidth: 200 + property int minimumHeight: 25 + + property int leftMargin : 8 + property int topMargin: 8 + property int rightMargin: 8 + property int bottomMargin: 8 + + property Component background: Component { + Item { // see QTBUG-14873 + Rectangle { // Background center fill + anchors.fill: parent + anchors.margins: 1 + radius: 5 + color: backgroundColor + } + BorderImage { // Background border + opacity: enabled ? 1 : 0.7 + anchors.fill: parent + border.left: 6; border.top: 6 + border.right: 6; border.bottom: 6 + smooth: true + source: "images/lineedit_normal.png" + } + } + } + + property Component hints: Component { + Item { + property color textColor: "#444" + property color backgroundColor: "white" + property int fontPixelSize: 14 + property bool fontBold: false + property int passwordEchoMode: TextInput.PasswordEchoOnEdit + } + } +} diff --git a/components/custom/styles/default/images/button_normal.png b/components/custom/styles/default/images/button_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e54f1acba8b1ace3ba8cc456d6f457634d75b085 GIT binary patch literal 877 zcmV-z1CsoSP)<h;3K|Lk000e1NJLTq003?P000{Z1^@s6owT}%00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01b)&01b)({Vk(N00007bV*G`2ign* z3>OJy&2=>Z00QkvL_t(&-tC&dOB_KI$KSi%J@<AcxQFC&UZKH4u-m`Dn4}gFEETQ_ z#KwS)AT~CZNnw*FO^W;nYMWGPJncmkB(l1jxx4-0IlD72MLgq~Kfn>@3lEklzh6G@ z&0`0B--r8ZwOTkaF;Od*%MNHgy7D|vM@B}1hv#PhBM1V=ah&G#^z`iL=qTE@tzA<< zoO7ew?Up#_yGfFK@jS107hDhoj_bOg78Vvt>+9>ouIt_a0N1uDAu~ymp`D$bxxKx; zSB$Zxa=FY+0075vnlm#q>E`BUHHxBdK@haHU+T!V?Psg2tFu>ESHrDV>wO%@AJO-H zh~xO{{{DUl0N>Bf&d#(|>Z#Fa)bl)_TV7uFh-lG_qR6XMDp0T2OS`+fhiRG?+9vgM zad8pO&(FUpiejwW?b@bgSr#G+DJ5NAUP=HcX`9rP5P}<qA;-tZ&AVHrloFC8L2Zw^ zl2ZP^4oE4n*XwE8)DEshL^u!}5n-C9nz*M%oDc%zIM&3e9UKx7hG96+DxuTqXyVkq zoFEbXBaVnb2!UyuYT^_R4gdyb91;=sdOb~?!XhFVAg-Tgr_<5IDXgL>aNt&X+bSWB zV@=#snsNQZBuO-J>Ia92IJn1g&NXq0?{P$gLI}LOoD@ZYj4@4|;xn$lgb&QPEXy=; zPhiFkv`Q&u2>=XjkJ7EObhpO|AvhwML{xa5S7wX}ZIOC1O%n~n7!pF5*Vosg<au73 zh~VVpByBdE<G0l5QmmGimd1{ck5LGb)M~ZNsMqU|=lS!4gM-G}+S*Ibd3bbml)>L0 zs=5@Y#l^+i%F4>yt*tFLilRf;b$_7m`@k5p5%F`Q(U2P(8?suhLY8HjZcvY}N~KbX zqR8Cd-Y%b>o?7j8``zT^WQ6?(v5YZWO8Eg1Ut5+1mSst8n-VL4!8wPbD1I`=cBZDL zegOdB!<Wne0O#lDFAT%bFJjdQ?j{Vw-@fnP+&}*VwN;r8$j7=a00000NkvXXu0mjf D%w(RS literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/button_pressed.png b/components/custom/styles/default/images/button_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a63f1ad49c5676266eaa1a2e54e41a3aa02e6c GIT binary patch literal 803 zcmV+;1Kj+HP)<h;3K|Lk000e1NJLTq003?P000{Z1^@s6owT}%00004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10-#AmK~!jg?b^>v+h7<6@aK8oH;HD+MmlC|CX7u*@Rs9_vcZIT zu?KsppqF}_`#T20+;K=Qg0~&Kj6n~>>tNE0BJ5JAzo<4{L#55zH`&G3Vr4rFOat!+ z0wKA4;eqe_z9i^44)ojK-^a<x$tQ@Yf;0@;rfF7hKV;pT^Ye3E*Y(w@si`?l)2N~- zc)$6iyKv4)qtSpUioS+n=vtQ50=ORB_0T>}OiVmjT3UKR2;r?(s}*l#2>?LTG!+p? zx3{-*l}cqU2!gz-ssRH4&~<&)wryNqUVgT@x%s73DtU1SmTt_>&OTaSUw`Ae?&Fh_ zlXt09>O;3GUuLt}^zQC%u~aG@$C^?aaBy&NwX?JHEtku^-PqW84FDh5<>jTNsw%T> z+bkA~zW_kQ9aI{$x3^bbTU!H4>BDNZI?5D9Q2-ze!!T?%o1M4=N_P`NM4a=0QmQe= zl-{lq5di?A_@YVwf{4BOuv_os;1Z&La1qGC4ZGfqWK|}}^^5>OR%K$zs!W!_s_c6q z4XOUBBr)cY{)60{B+H%WIJw3ph+N|mq}z&wkVsZ#vdF4TFnJtE8bs_J378NfV2n{h z2%4rzeczX#c7_n86d7Zh5CWUcrXZGO)uSj1Pft&4i;IiT;ifX>HAL6K!ot(Dv$H@5 z;iuE-D>^<t4xIC`qobp-m6a7o2yuLPc=-Eo)0gho{QSI~&*!sSTU%GPTJ5J{7~j!x z9Pm7E1Q9=HG8wf{D5MO-AnkVBk2|mgpsK3j`#!p^+bEaI;CWtQdV0Ew-5+8-&l?d! zyeEXbQWS+KiXt~ELx6KmIOief{71cB|1>i*a|{50xBp}Y0H{<d8A|EMy{D80bUK~( h#l=O<ah!Jl^FO9oVyo(%M@j$y002ovPDHLkV1m<CbPWIi literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/buttongroup_h_normal.png b/components/custom/styles/default/images/buttongroup_h_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..bae593818a783187e7b5ff5fceddf99a0c9bd58a GIT binary patch literal 482 zcmV<80UiE{P)<h;3K|Lk000e1NJLTq002k;000{Z1^@s6-}lKL00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01b)&01b)({Vk(N00007bV*G`2ign* z3>q$VX}%Kx00Cl2L_t(o!|j<dZo)7WhW|$#D+&`EBP$~pVC~2edZ}Kc17kOCzzr%E zM1>+*lsH&%-b)8sDU>89c;8~rpZ@pTiD|W3;g9`(kHum!x7OxR0N|6>>-Bq<We6dl zyDC5k0Tg500;mDlf2#smbGzLRr_*VxE}q$JHm^oR=y*JSsg8b(wHD5~Z|^;;jz`+I zO^k@N=kr+rkSckEh}eh-%Cb~BLn9_46hfG&iUC1w+miQQ6Eq}<ndy4Hs-Te(!{u^O zL1PK>-fIW-AM^JP3L$8M22Ogz%%meWK4Q?49vLxarm`%xgL+8Q^xi>rU2B4d1T{@V z&N&s-!*n_&!_26vN(BvdkcdnGB&uWhTP&H)W~p;d{|7xM$QUAG=UnV|ldAc>B@#7# z3DP6KlOWpdc5iu}=T%iz0MOkl04<lxj~L@5O;Z7Y?p^^*mSr#9hr*&L=1G$1%i*2F Y4+kc~lX+oNo&W#<07*qoM6N<$g82Hw>Hq)$ literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/buttongroup_h_pressed.png b/components/custom/styles/default/images/buttongroup_h_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e0c97fd587a87f1718c7199153cdb0cbab74429e GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^IY2DU!3HE}I%aJFQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?i-Fp^K$!8b?qUz1AbW|YuPgg4ZaIDfm4G@yZ=fkmo-U3d8Ta1a zbj)fq5Mg;xsg}9v<faR2XK+8UvUORw{ne`Qk4*O#EX;O3^M3z|CUFfl1NjcenA92V zLY;<>OwMoix%@>-Nq>P@%KN|Pzc#iA>|@BtUVF+iJbSItF^=!A>XuGPj19MVUU1Kp zLFe=*-h}63TXSWO^YcC^Y&m*BYWb8~UpJ;D%)P+S_IS~;t5Hv_gjQ~z=rOm)h3(jZ z7xN2LHYFZ8(4o9B`cL9B4;3~yo*sGGBW;4x*GvT)*%s*eE^eFqJaH=TYv%KZt#T!p zU$0G6Z1GP%!^f~x#PWK{`k+$@J(Y7_N3G6y|M&OTrBg1=4mwr1``z~3Xg|%r$0Rlv d*H5%zyg4Us*UdJ)Oke;pc)I$ztaD0e0svIHpR51? literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/checkbox_check.png b/components/custom/styles/default/images/checkbox_check.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f1f02d2d91b719209e71dd0d26adda9182962b GIT binary patch literal 557 zcmV+|0@D47P)<h;3K|Lk000e1NJLTq000vJ000#T1^@s6qzTp000004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10jfzvK~y-6t<*h?jZqK=;OE}G>nBl2gi@(LrBX#Bkq8MQk)T6_ zN~fb0twu;BN;C>0k?7=G*+N4rgoF*t?*01|XTF<re{Ak<OgD38-t)dQb51Lz<bPRb zD@9dRwQv9*P^XlJ(B1-28&~iS*RdEet<A`+s%jCBaV$bT9Kmb!=VlhtE)+oU7GJTz z=49^1&BA|xbNGyUZm{Ud4eX21N8H8=R?$x>)$=mjfs2KID}a7t9Yc!Mh@OCyQauqr zD$9gryb4C^7&iIsqTnPBVWAmySQ}>w|0#Y4(4f4yQxx3AUfjdgs;bt4{vI5TyaAqI z4ZRWwI>Bmx0FlSv!ex1nPGDP{y^*KaZTeJNBd5lrB7PpHupOt1c*Ck6HDlJu{De!9 zbT(pl<h~pXe-+Qo=+%f>1pD|S@6vLd?ZU&53@`8_q)$m4$&6Ru#do=9-)7|A4~e~5 z5=UTR4d8nm$Cu*lC8~`ij)6tOAZ}j@z-PE7PxhB$+h^I-7Zj_~k)O~``A6u=i`q>o v4gLi-^)@F4vLg3!><!M%Y=YtBB^%mbFa(~Q2<4OQ00000NkvXXu0mjf^T+ez literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/handle.png b/components/custom/styles/default/images/handle.png new file mode 100644 index 0000000000000000000000000000000000000000..bd8fbddfbde6a43773e32fa34ab4f02c7e88ca16 GIT binary patch literal 1529 zcmV<V1qS+wP)<h;3K|Lk000e1NJLTq001KZ001Kh1^@s69@(>500004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11$Ie9K~z|U#hBk~6jv0-zvs+M_D6Q(Zn}+Yt1+6NP%M?=gPLF{ zjXv~ET%?HjmxvF>f5E(nAc$BLL}=+lnn)?Jv?P_9(vSv8vm2W(ChRYFCOf-3w-0k~ zcCseACRuvmGJAJt=6v>?`{R2q2_f*lMnt4O%BD=n2C;(|Q=`vF00O|WY4WPRS0E06 zs=PXqt05=vgpm-+x#4NL2TYj)r~oJfu;u3}0Ows$Z-pTu1<?Y)55NZ?0H7B@HxU`J zSj?yEI<2j(t=qQk0C)*t9za0?l>n?uu&NNkd2bjAVo2vf03T|aHaIvqc;Lc?3(=D& zPX+>kfUi=i_yK5!VXSMKW<7iM%zp6TL2i6}Je|+yrvWTU5EFm}pu8Q>mM{{e1wbo+ zHUMAr_V%{lzJ0rgh`LPEGyn)@7MiAknZe8;A}})r0s(|Vq2$%8SLg5Fzh4CKBY-S` zqHOk7KySc!KtcdwMD*3z*qC<W#EH+->2!>lg>){62=y?Urh$lvnGp(wOv|!<J9Fkt zzECLq0$^Ffyxt0k>p)1RrWHU(M@Prk6B85N-QC?^uB@zl06-9tAR-~}um2<JDu_s! zrWw?Aeen77=L17SLn8o=$al8_FsSYY8<CMe=<>#PB1$}Y^5keXo9$(0N7FPF5pPPi zZ8Ab&W(XlD7K^Q%I(6!gR4O$NU==`KMyaA^nKv>jJwX5?V`F1%S=Ld=wW2=1jT#Yw zh(s=zJ1{vp*+E3Z9zQK!2KGcngFAiW{r&x+<HwJGW|}6+knfab14sxVn0esFjT;(( zPv9;SegK+Em!eW*#YaSgw{G3)Nu^S;-9prxWm&!}SFU^-kH`Dr4hf(1y9q|EDUoyM z&K)cki@lJ8buVFvNE8Z%1J|!#KLp??+%y@AgFVZ=0bn4JNVMg0Io|82C=)_pWMst0 z%tuh$VwmKbqQ;BP%m<GhI~Igz_iY9b5ykuZ`l7P0OaGhF#F0ouw{5$%i68)gYPA|1 z7#Ij+vkD-u1mIXK<}Z~>zGi{|K&4VaPfw2lKmn10f$Sh04!6jSuc;=4!2bRF4Y;#u zL!c=b0RY)-wxsL&db44O2+PaMHr!o&V|=ow<E*Z(mi&Hy(_wU7$HKyb4R<?G{)LK+ z1Hj4UayB!+#%5i+=Vlm2er|3qkD5$%6pVl?3o8JUGcz+L-W1w<X;dzk(~FCXS=m>z z6fAd42d+e%zjyCmw!OXG-bvNah%qxBKYnZhcp)Lmkowr0rZRxS)2C0DiD-_QNeHp0 z(GfyWI2>NOcJ10r)Z}Pc`rkC0lz5)Hbm`L4;lqdj+3V<pLZRa5=;(AlpZ^nXR7%os zP0z?wRpF}mSLt**_vq21nSJ~A*+PhhYpd-{2mxlMOeXXD&6_uU0RBR)YN&1{t{l`< z{N(89s8%YK7Ia-#tMraRh={`B@ZZD3!+8J`aHC;Le;YcOJr4=EBin*2n7>OT60dCA z{xuqnnleHSLkS@ugdoE(s=;7zc4%nmMJ|{78E!pQlzuiO=O!2rkfL5QP4k=c=g<H9 z@ZrO6ySlnkYEUbv`t+&3x+fBetR|Dm@B8}tl1ocVKfo>URJl^FuQ0c(n^YAUgj=$l zjz*&&-MxGF<9IyYna}5=<#Kt;y2&sMYHMpN0(g1(^5yyI>1hkVPcqs?`A16))lD9t z`ie3F;B;qaXY}I5i?Oq3&xYdhxMmoJpNN=<%uFUzotl~|-??+=)$HtS#&Mh(0RLh) z6=fYzeXVT(I0T>vZdoIk8II!++!>Mtu!!0kvin-w1N5#_i2C!H=A1%o0rmf$&%6Z; fcymMD)ydU=y1<_V8yB=W00000NkvXXu0mjfA3n)- literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/lineedit_normal.png b/components/custom/styles/default/images/lineedit_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2253d33f92e4a11742df1633473bef7695c5b6e6 GIT binary patch literal 794 zcmV+#1LgdQP)<h;3K|Lk000e1NJLTq003_Q000{Z1^@s6a(2<T00004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10+&fdK~!jg?b^?4(_kFO@z0Yy-O{wlmfGSnhttA9D5$C0qhy|X z@gV3ycIwXl5&Z}D4|w(#ytr#GUKDX;mx&04l`xHm+Dd-e)wGWXx6H|Oo=gMJ3j!gh zFT8o4hrmM&!vFx-woL#m11QIFTpSDrGPs#gDwQHiX#n60fRFWhodEy^0Nb_|-}kR? zZf@S~bUL@gFuX9COr~iL%$*QLQIKW1zrMcy+On)ywr%g#>vf+n#^$3ax>Kvw9`<^@ zivV5#*at99d1mf}0N@gU`?{_Nj^kLA(j5w5bz@`WTCdmB0JH&oPjgD{j|KqtT-SZl zY&LIpI-NdYj5SK7(u3h}_!7X|v?t`wbwyE>mgjlTD1br`1p3_E+`c49EbYm-zne~{ zP8f#EqtQsFN8hL<N#n)EMILYV#ZeRy&-29Nc#tFs3kwTr4#oYWgM$MAN52Y$5CCAJ zDDst;A;&9^<@0$~E|+<{3`w?4LI}&{ay(v!&|ltpyo^cW$+FB=R#tet3`x#BK@gZM z%RF9&oI3N0#UhWFA*WWJs;WF*h9oOb5Co=a8jqJDNxac$1mE|0ybMXUO+pA;T3X`q zGUU{@S*=!iybMX=MN!1~wwWyy02pKA!^6XzX_`FVjBB^sB7mu?suKzzR8{p;zu&(K z;B(5eap&0D+FC6X3a%tckpSRpv)TMG9*-ZHrYQhm{F&V+2!h9rM&mtzAz_To1Gu%e zwsx=E?P>s?0_YlsF*!3m_uuXA?h*i(0km{oR~^TBPAT0XhGD?AZ3RHB)oR_?-rhEX zAgIJ~{4M2~xg(TPDWA^|P1Ag5S=Jj$>CbzcXWf|geP3~1S4nkZE>Wpe0!`CA{B~pd Y2dceVpMfcWg8%>k07*qoM6N<$f-1XcyZ`_I literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progress-bar-background.png b/components/custom/styles/default/images/progress-bar-background.png new file mode 100644 index 0000000000000000000000000000000000000000..4f30927ed8c34581a96edf764c98e4a687352bbc GIT binary patch literal 484 zcmV<A0UQ2_P)<h;3K|Lk000e1NJLTq004{t000pP1^@s64>&}l0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzhDk(0RCwC#noUl^Kp2L<=}f1zSQ2(5 zO~94j!MJJMcmQwW2{-^OJcnn1jnR#9>B2Q68W%tW#s#H*GuB2z{b9}fOx|?TcJ<}S zH`5<67z_yPFKL?YbievGPdGi!X)y<Tz;HPH?eds&!?|R!?3_f=VU9U>^?K9{!;qAc zs3f4(DkEbIEf&j(Z6qwsqw6qAseUc2H5-kXq=YQs6JHbQK$GWrO=I5seCpf@vtF;y z;`o4k-zOo23jleZTUjXPM#5btE%z`iOrTjO$rm9DC}9_@G^Bj%h~C)rdQxya6bWoP z!z1Uh^^}CA2>je=M1?TL0HCVNYzgDe!52_%Oo>;toE%jFe=JLRDNGOqOS3en3aG@s zyt9s!!X!y@Kb_8KKA+piCsYVHtP9qO>11Xdc_{ZV?RLAXwZ0mSM#;<bYn)}7Lb-sH zaur3<Tc>k4Znaunw={iytxnVQgbx>-BTgOV0?dN*#JT3&ZU_VRlU;vr5bo740RQAe afB^tSnro-)atLk!0000<MNUMnLSTY)Ak$L- literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progress-bar-bar.png b/components/custom/styles/default/images/progress-bar-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..446c13f2c20c5b8ea4e8e3cfbbd689847d9ad5e4 GIT binary patch literal 548 zcmV+<0^9wGP)<h;3K|Lk000e1NJLTq004{t000pP1^@s64>&}l0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz#z{m$RCwC#nmtMbK^TU=nVmI+_`{l* zxE5B5h@QYo!2?)$0}l{VNJyzgAXtQ0*m(zUU}vj>c48rD$VNyJO^lnFaVAbgFrwDJ z4}3ejQ@%WW^TUc-tw#BLo)OWg0{<61s)l0lVzD@%%jFI@=WC3y5P1QubzLcS)@U?# zE0xNfnNn63uT(0n8d**=3sEpJ*CLUKkrtqS&!_f7K#w=sRun~><#PE_n0b*-r}r~U z_kqY=Q(JXOb^1sP5NCqKT#{zQN+9Lzo|)R_=HUw=*46X{y~;Kz4OzfD)&=W?49>~( zybbG$6~;4rmPz6-NC<q>YI<ZGNm*AoPD9`iFfkNHDUCS5uY`GDucSg8;72}$kq`#_ zK^Q4x?GeMW1V%8p-z7N|MoTGg`|ZpkOEnM<`07h1OV$zlYK4(e6jj5i<s&A|p()uk z$Ea7N1kA>EjHo+9y0t{jX7kXxVtY-}RH{%YY=vRC<NN+9=X@M#0j1Pa9LHDndi}Us zt)7^vXXcirgcB#>zHvVT?1t8!gzVLS&s5ir!fj@HZnW3Eo)ZQD<-F*-lERrJKiM?w mEa))kFrPck;D4Am0R{ko|DwO@@+_GE0000<MNUMnLSTYg^zu3Y literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progressbar_fill.png b/components/custom/styles/default/images/progressbar_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..0f8778969a849127acc0d8e83c4ebd6aba53b903 GIT binary patch literal 992 zcmV<610Vc}P)<h;3K|Lk000e1NJLTq001xm001Wl1^@s6Nzu!s00004b3#c}2nYxW zd<bNS00009a7bBm000D6000D60sT^Gw*UYD8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H116@f(K~z|U)mc4H8$l3#Gq(l;iVO&_g<=pwvP6+zkSa<d(WIue z($P^-($Y}#BWUvvQcy*rA%r4IB#_b}Pze6G-MvYH*E#U{*t5?Do^+Be&&}Mt`CK1~ z2mpYHN;5Mv@2l17+T7gSJP{!dC+7q46po^3Ae~1?M}J8~FgZE-W@BTcR;$%?rBeAh zJ3D)EUpVfN#{<#>zdM~?a!L9Mg~H<c`g%zb(aPrL=BMrL?PC!+27t@U%PtK;5O~`1 zhJQ#CP%IW-04S+SrShRxt6dvoz9EG<Ywd$dGdk(Zej=hMA^@bS)#~eVx%{KiXmFCC zZ$1NnG3G%TrIi0ura(k)9VnGbFPZs|wYC={12Gl12>@XjX1b|YRNE1NA|galBq<K$ zg}(InN?mI$hzJS*8Dm&$%>cm60~Ob((5V6U#YG_RNCZJJ6hb;FBqC(3rD3H|UV85n z(Jo>rXGCkw!(uBBIK~}}F$91+Ddes}4UMXX?xc{2<nr)w#e<;N?1{HjC!zpAYfWJo zb{QVR`rwO165`9BwU*(!kchB|bWLKP$(m(S_lqPV<3&uy7}8qz8~RN5Jrva>LXy^Q zV+@!XE&{pat`9uU0A9~wtz{7**GAbGleo;KAxrw?T~D1N)>=!e)slL>E&xy{6ucb? zg1|d!z3Qpo8gc_t-Q3*N4-XH&@9*#b?nlvMVQ+6wUtC-)xEhc!44>>2j$?d$+<lCI z_8eelA)<jDaII~aXti1Z{x^esjz?|eK|)qriijNh&mx5!m>EPQojEYd8W<ZJ%O%y^ ziEQM^gDls66@X`%Lb&Zhl4}>r8$MmF;{duNFp}LU4QZshgOl5ZI{h_<Cl`@8;x*7K z0#6#uw=0_hAOkw^D5)kQ!px*{I8Z%G<cLT_M3jiQ!SdWv=(YyV&(E(H7Z=OTX7g;w zHd9k=Vq&5%rRwzb^h89~rl+UBUR_=Jzw^nC)Cf15%}mOo_BzVe+Aq7iyAuZo2k(}b zmxH#UCx0<Bm|2vF{34>yTU%QncXoDO&Ck!DH5!fcdcCgid+qy9%e6QUxjXvO{#dwg zdueH@3;+~+OSu5xZLwHfSzTRSn3|gEI)(dotSE}S1haI&B%LQGC(VDYyYyvoiO9+T O0000<MNUMnLSTYx$-1fl literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progressbar_groove.png b/components/custom/styles/default/images/progressbar_groove.png new file mode 100644 index 0000000000000000000000000000000000000000..263ced8bf3a8430f0b725678a78248fc2a23a72a GIT binary patch literal 492 zcmeAS@N?(olHy`uVBq!ia0vp^$v~{m!3HFyKYe=-q*#ibJVQ8upoSx*1IXtr@Q5r1 z3WtL*<KLjn?La}v64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<_&Gd*1# zLoyoQPTlBt*g&A|z0UF+l>;IxlNxk`{<Jh$eNeEG>^OR}>(GrEGRz(hf+C{k|0dtr z?%MUv{_gY5H!Zin*_EfNq^@-7V&VhltFpFd<`{mqI=yKsuVT#h-0J6h>wD%3@09Zj z`*LTK&iU>|J2twMJlng!Kd_{G<*AN&S53}3&wIXn+xy?Vf_q(7S-)DSa_*ImAm>~C z<QK0KuUx;#mm)8zDgSt7?&0S;8{f;XFj}^!@^)m>%%A$R4MQ0NqW|4CHEmybAV<!) zzS{Vifyk9L`bG(UCw(^GlPeH>sciOH`HW55LY327ch`5ecbu3|$ei|f_NrA!mgG78 zbVy}bXw(oO>9B%FA%smpi<x68W6LQ9Ct`(@dn~=~wm7-Ca67yBm&V2~dzW&~;<?_8 yovF|77_}6rDjj#(;(7N5Po%-;&0D{H6Fu`SAiwmBZagq%7(8A5T-G@yGywoN3CJM; literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progressbar_indeterminate.png b/components/custom/styles/default/images/progressbar_indeterminate.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea46460b59830404ca61024da78ac8568a09b49 GIT binary patch literal 1152 zcmV-`1b_R9P)<h;3K|Lk000e1NJLTq003YB001Wl1^@s6@WoB+00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00dwF00dwGbSnOq00007bV*G`2ipM) z3=<00Y`GNx00aO@L_t(&-tAkzPa{VZes4SmY{6kCfm?wI$03k%T&NS5k*+|O28q8Q zkcOTLA<?9up`?iTacvM%n!DzTlpIZ}B$t34WbUL0<N!93S$lV8UJAUHiOxQQXT9qm zPja!gyq<5~`@Z+Rv5hk`Ge5@T@t@Y$*Yk|A_|VYM<7hPcDI!8ML|<QDrWw|$l!A0R zeU?ln|GK=qd<_6;000C42!%rNxw*OT=I7__(b3V9Xf*n7m3tAicreD?z=#(Y7oVM+ zoIKjx+zjmP?Y%Hfa~}a<Y++$xd3kyHEfM`z>D_@qK=*>0E|Hw``vE1Q|6Nb7uC7jP zZEgL4u~_W;-QC@%0|NuE>Rq4<NowjOR@;x$)6?g(v$MbR@$vC#!!Z7~EQ{5Wy=ozZ zaIK0e(b~@ml~PuGZE$e#cx-I!OFle2{2&+%W=+#X7eSVQS(fEzR%uCSEkzp+hqJL* z>;XqaP)d=M68#9QN)?fZ(pNWLr4(?^87CqXLNMF5nTrm<Rgl%F{t<S0hE*wr007*% za2TMQ30{J%brZa>t<FAk=fW)s(sf@yC-OcRrId__kP{I~DbcoV*6P*jCwaZa0HqW< zk5&Td78`Z2(lJWBc!9d~P{(~L**L$soqDheA#NlH0Km3wv@8pK1Q;t>H!p`Qo%=yV zB?&?zVnoF5Guhr{QuY{l-OQ9ylCHJh>H$Isv~3$30qkQ7{7^#ctbCmXfHg=<O+{Nw z06INDn<uVi0&K)_fKD^uLII!<f|bt!%y~lhnTJ>X#P5!-<brJ5rb3}W*Voqs01ylY z*&Q~uW{{Pr>E|AzTNTQ&3L$QKKrWXv_xJbz+}POo2RhNPSX^8j%49OryqFlWEUPIF z;kvuKYqogJ5Zuu^L?jIqa~*i0P-uwfcRPx5M0&rT(vZY<38%sHvW;uU>HUN^?LX zdq7uLmtQp6v!Zj<f_w4d&C>8)?g2LpKtyU|3G!U3w7MV{s-$J5$|-za){)6?4XTx0 z)h!n!rTmb;?nu%d2f+IjZ8ZjTG}^@h&^Z_406=vnzz;gzbj4GWAPt9+9jU6LXt`3# z8H}i%fP2kY&N&Dn6i=m6SB7Cc%;)p(yaeCV)6-T`H8L_{93LNF@x#NzKM?UrBog^G zlgTKrz~}S%w$YzRB*FmTi)1qSHUI!uiA3V7?d|PP4h{}d=jZ1NI^mjBO-)S&cXoE3 zt*opJo}Hcj?0nGIlarI*E-fwDhGD!jP4j&&m$SS;?()y%J&WGn-mY*sJd#eQKVMs0 z<3~qFF9G09IoJUJ_@=+V|Ix(6gb@mb0v#gg3)3`ZB9S=FX0s^(_yvmplKc;d<{lzB ST`dy;0000<MNUMnLSTZ$iWCO` literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/progressbar_overlay.png b/components/custom/styles/default/images/progressbar_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8e351f965906de0e757a2848440af05727debb98 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^RzNJv!3HFM3)L?JQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiuQTBIEGZ*dUDN|t3g4a?V)7$)os=+cmF%ZE-;=UEc$mA zn^c{#fMA5a|JDg>x7rGte#vD^lXDi|J#CIwdCAV%Zp=ZmpjfYmEk$QbL<-NAj1-M6 z6)7AdOh4IL9e*tdIH9f~^NEkE)5bY*Vzq`zP}^PRsFEi<y^%3mMR}_ncBy4Mu>IY| zaUxuU>(cJ)u}xo?jXXDhyEEad_p-cChi9Md^SPVCdxBd;w6Z}-*<8b_=<b!n%BgCM aYz)3e3iWZPyKI3zVeoYIb6Mw<&;$Te>SgEv literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/qt-logo.png b/components/custom/styles/default/images/qt-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..005ee5ca3204e0cbd3f9157477421e8d8e26a35e GIT binary patch literal 954 zcmV;r14aCaP)<h;3K|Lk000e1NJLTq000mG000vR1^@s6nP-j900001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igh@ z4>cQHAAXkr00TNnL_t(I%UzR8Y*kehhQGD<Ip;olT54M?R{J1?XnE8U0;#o5AYvzV zA`@l6#DNZoAvhr7i-~byG=_m%V>Du-(P)ezAsUSu9%+EkN=uBjU>`#5ZN)zBy?vZ} z_Hxkn_LjAWd+mR%_5Ewhfnx_7M<++RceI;5Rhx7}+N&7#Y;Y;`D=t?gtNW(%<D&_i z%xy^4WM621cV0x6C<$pe`0%-=mZ+n-HN?eQyij!@;G2XqVlz(T2@x}4#lIB>mA?lz zIdHi3)oT)V*1LUO)lysMFDr@wifU;Y5M)Ie1#mctU4$pgPqdgON@2Q^N4GtOvGC_q zAGhX)@J$lWL$eDxNqT9F7>rHet<?bE7tWtq<igwE5GKn&1V!n-{1UyHANcibR=zv= z6>pt?4o3`tDRwEswZ04=9QlYa6>@gy6P|phjlt0y9NzT`Wo9EyWi4!}ZUzBenbE94 zQ-WwCyB};p)$!xd=OpjR@k{^D_$I-oxdVK5q8nAq$^Bo@RN0KGD-m!|TTzc-$VXWU zF2eUcMkmLx#u9`DuKzViOvJ_E@5x28fRqTJq=OJ6LaY(0im^g&F}pmXjks}pgo0b* z%;5WEa(^RIB2e_c$W#z5@?EYb0wVY}fe~{TM1<_pEKVK12@rwUIm!}g02T^)N>^hw z)&vZUPmdr7DL*8zX$p~}uBr}D{>_gUVI#V_PwQ<YHN(079st@JI`QI4+M7GbM_DH3 zZ}Q*l3@KaAj`B|G!-sI|Tu`NXdkwFBd5rPQ9iG~Dgg3fAW!Ki7e0}{CUd0SQ4WFiW z>>_)&wlVK!5d<mkY|wpORouJs7ktk!JQ(rv6YufJ_Pw0yIZFRO7na*K!cx45!D7V& zLD#t;B18p8Z6loc_;mmdwH#-6-F{*%;GE(~0&6@JC9tV6b2n8%@I8-)JsFOkewM+h zUb4}&3abZIRUD3*^!?9!D>PL^WOct$#S4`A^lyB4<?5WZ{$yZNw~d%g+AsgZH^IQp z+K!&5TVK5CJy3Jsan;2)V^`3Gmzqm@;ea4lYs1DXOYwaFLLqm@N|1Ye%QLx-&0YDm cUcUw4f7bC$T}C^hI{*Lx07*qoM6N<$g6l%Ay8r+H literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/radiobutton_check.png b/components/custom/styles/default/images/radiobutton_check.png new file mode 100644 index 0000000000000000000000000000000000000000..3d433860694359f394b7a50ba847bf93dbed6606 GIT binary patch literal 1331 zcmV-31<d-1P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800004b3#c}2nYxW zd<bNS00009a7bBm000ea000ea0W}m4y#N3J8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11h7d&K~z|U#g|QQ8&wpBpL1u%sS`V?lhzG&qa;m20}U-ufkcri z78NX5v1J7kRN@C9_yMd@7q9{$u|q;Ek=P*dAwVEV$|9i<+DHiw(4aO6b{%_W?qM-w zGqGkI2UX&g?&jWe&w20HIqwx!rB4{344edtKn{?2Oo0}#3v2>gfbGYr^g-YVa27ZQ z+=>I-i328)14d(l$72#Jz}|l)VB)~{#g2YEh-nulfCqpo@Dmw3l0_g7JP}V`&6?Z? z3~&Y*2fiU?H_`}{fX9I)qAkA{7zfS)-vQhEMpQM~@~ZlbsusHX??o%B>eH%vB-w8g zTpZvc@B>i0M=MX_Z{S)SqZ2oI1m}Rez^?~+I)DEBP`zG%7`PxJ1yx<L)-K+>dGpUc zh};i&z;cp69(WS?l;};TVs38k6!4y^UIuU+rzs*51c3`UBC-a&xVpOfc@F{tTn4@b z_Sys<Bf9aMS+izmXI~JJw_Mltip65i^E^bPGadv1^?Kbl8Vv#7ZZsONRjbvz8SW;C za>b${I{VTA!LI=C77B%-N~Mx3l}Z?6_Sv|u%gD%xDV0iMjJYy6IQT)2UD${T7z3OD zGS6;$dU^`DS}Ycw$;nB|<uYSqV+;%oq}mS*3@|!6np4$hXJ%%e??GY<IBtLnJy!3! z?)#qSx#Q#G3=R$g5QZVGR(B@eH-|!@U_|7d`T6;i8D^V6#Q-C~?KF$o+1awHUK$=A z_S)y&Y&O~2+QQo2$uXbLBO*E9_g@kbH^t;OFya#3fiT0*qkwf?*X-`@QmfSt3=Gi@ zg<*)}II5~=E0xM=;Fm757T_6rJUifm>$-k>^@j-#;CY@0Jmk9WSfx@qmS%6#Iuj_F z?(3cbYc0O-cY*_m2qH2Jkjv##38bA(2dcUh1VOKHthHEcNvo<s5Lj#Na!hb2&4(c> zwNBcg<2Z}fTCdq`5(Gh~`Myu9)#|J`OH%|v5QxZi01?S8EG*;_!#Th=zz%RU&B5yG z>d(NPy}iB8O0!m*5*%x-r>fW5eap+s$xCz;*fB&YxRT~XRjsPN+-Nj3dA0{ZRjJi# zzKDDrhT-+Ndrwu9=UD+Z4N(>x&vJI-#*L4F4{NnrtDje(s?_UstE#)!+N<sUFbum( zd>Oc9h;qO-k@ibPv)Ozl48!lYx3|M)vzZy(_kDJDc6{IWx5F@eJq*K6F&Y{g`Xga_ z3iu1K?P@qkBos2sv53gb%*?C68zQ2f=ee%y8h{`OGzfy0wKfNQqN;C(VOUQPt5&Pk z^|mWg$}#jQNT#NyE*fK=a~$W4s-6>(ysECmZK?h2+ECTq_4V}?{Ws7VqUXO)kU;bl zp8|f2w<i;mlanRjw20)gY{D?KBC@fuvGIE%co|p#J|kAz-KsbbTmru009_~|&cwvT z32SY^b=@K0h^n?k<gVj5b!+XdwY9aR3@;K%{Vzz!^Io!ik*H?(1rZU=P7r0_5#U?8 zWO=WT$wgqD=uY(gf$Zi5%n{xCuj%t+(uM;(NR%U1h!WOeFagXH36Dd6&64=vKBwJi pf6ptxFp;)T!Y8ULRSxkz{|C<mldRe*zN!EK002ovPDHLkV1jikUIhRE literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/radiobutton_check_white.png b/components/custom/styles/default/images/radiobutton_check_white.png new file mode 100644 index 0000000000000000000000000000000000000000..b68e7a6987c99020644efac3cde7f54caaee6382 GIT binary patch literal 1310 zcmV+(1>yRMP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800004b3#c}2nYxW zd<bNS00009a7bBm000ea000ea0W}m4y#N3J8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11e-}jK~z|U#h2e}990y@Klkp;WY?tWZjxPhyD5mERjWZQ3RWmS z6n*f?SDzGOpnrhqQ=yP&>4QEg0pA4iQSe3Z2T@iuTMJG61w!Ngm{ywIB)epH?#%V! z&c?}hX0nxnUl^FVKhF8yGv}TkLTk;0kU$AI1)KmJK!kG|7y`RM6SxfolL!?P5Xb^& zfd$}Js9+~l7=;7Og#?QsiA~_(zY>t4;z}s!uj81G;WY3#&;Yhbut*Yt9PmQ8`S+yF z6F>rIfHLqsG1iD9Pyn6>>KK#X50rr=;0K^{WJYTpeR5jsSG3kMW8?SZIia<FS!<n* zj>`y_3~(O!3E00+Cy!zexEAU-)EoT;OF$p^<2XsK>rVT=|8ypkIS0&Wt?N?CjZ&%P zPC(>Qzy@wa3FLqmfiE$4Iu?yaV^K=ECWN>M;QRhSYb`9xvM?6>6L_;+E`OauKmZqk zZ-Ijmf#)zD-%Q%oZnxh6-uFDu?)UqSQi`YpTb4yOn+>wrtN=dHTEA1NRQd_xPGe%l zh76e((v-Jatrg&-UavPj91fjaE_c@&r4;-7`?A~ZiXaG9gb<&kSYbOPASLi1kofP~ z?e;@Lh^xI`FO$#bsaC6$N+se*0C=9q?(VJwyz08{>nS8|14Ri`NjW|6vFCY~<2X!D zPamFkFc>6mP)gD7_oY(m!}ay`QwhtOKve=Kfje<4T-PlD7ka&(Ev30R2L}hVS}lCv zPvH!EdwXcDop!suEQGLPmfQhOj=VQkS`Y-!3Lyfel-$|bq1){e1jk2Zr4&jjJkQhR za``OqF!0;hvLRqgQm!3vPATO@2u-XUU@#ci#bWU(U|tBZ5Vu~&4UQm$C}^!y*F?z; zhr>hVBUqL-8@|R8i2FB(&|23`j7gj)2m*ZHkF}0%+d-$(xe<O&ClLrp_Ja+;_I>}* z>4XqRl1v(G+g8nH^Ox|`5kfdx>ro-&0G<T8Kt4`DrBeA7*vaK`1VM1*w8tr*nwr9K z9J^MlU5gAy&6Eea5)*=}333A9t=ZXG?Kn=V!YHJa<nwuNdwcuy)z#IJ1rD^<Q3t64 zO^Jzu<s@O1O64=))4931p>5m8Di=afC=>!<cX@gFYGi6W#g~9v67%mnnA$HEN~udy z${&lxqCYb;lc?Nr92OQ9Jj=2=Yin!oUcY`lnvB|!_eJ1uAQ)xC2QY;~S~?b6TU&4E z^Z8Y!lpYKQmQqRvL4e~p+On+S)YO#IXf(c9Sy_3nUa$8edmCEon<F{Iq+^({Ah~ko z%K4?GrPmf07thSk&o5;%nOvvS*>qiZvsSCsFJHcVV{FSVu&Mu5bOv+#jua$duHs9; z&!Kq|A%rMk!fTpm2AH(liYPAuPXb?s^LJInIp6}Y&M|eN5F&#~<ujNdlf}gMKF|Yh zX|1DW_z6s@{|%AyJgqF>z~t<SAcPP)IXIMnXMh@GWqDd-avr#e@rj8W$Z=l4BN(s$ zjtLu+5i-CNm>98%30U`n)4*ex!sDJ>vnc+z=5!pR_Ph$rVru&+JWO6`a1ZVIKQ!BC U#7_5uMF0Q*07*qoM6N<$f-QYjUjP6A literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/radiobutton_normal.png b/components/custom/styles/default/images/radiobutton_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..6ceab7ee66870c38426577bfbf9eeffe58b9474e GIT binary patch literal 1752 zcmV;}1}FK6P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800004b3#c}2nYxW zd<bNS00009a7bBm000ea000ea0W}m4y#N3J8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H1231K!K~z|UwU=LP6WJBUe;(UooOFmChY)8li2*?pZ|ky4lZucS z&~CQykao9~U}=G<8>#Fo((W4)5(uNJZ>28?L=-9>cxr{TEE3yNs|#w_C2h*)4^aLz zbqG!dCr(Y4@r3Ea+#wU=ps>3=($QGfnR~wT-81KY*JYX}OEd|n25N8KyjeRkG7=sg z9j)?uy+&PK-DEr-AB#jH8DI>U0G=&nQO^=$mT8(6@9F7z>)N$z8z&|v8ViL&u23jU z8iq0Da=F}IueZ|U@l<)eUazXEUvzYI^zYxl|F6Ix@YTx}cfEuGN!Rt)lF8)mD_5?( zGd(^1k4z>rkWQzE0Ua<LRk{F4mgO>4RX0{uRlT7oO6A_Ydw<{6)%7P}XfZ|>1K>}k zQk_SR9QjDow0pO1-MWy^=O;xqPk}-S0B$TsWx!WmUA?BRu5NdAb@g;_Z}0CaD=Sl_ z*eC@cc>46|uCr&)zCSWD(mOsrJ_zK2S>d_>Fjvfg1Aq+pf$|L-HoO@QhqoU;e*8Br zEiIn_Qwy@0rs;J5$&)7!wzjt3P!y#bcpKOZ#DVp|Y9I`(075_|5ERcUU?rdeYk)>z z6R<TBi5zTeYx}aVuWy%Wn#-IyoypyoE?xS0B9XYMD9SH^w}2L)38)8ZM55(DIZ!65 zw7neo4iFFkRbU<PeV{E8i5%Rzb?bFa)7~~sQ+feFHk;kJef#!-a5#Jr=m4651|TA; zTP~9N1jU{r_lp0Q2_QiMdJXVBpslg7@z*<d?)-yknlU@CBzD4o?AWpWj~_oCc=+() zFfb!L4?MwY9((T%<{QxIbHWV~`&9JIe}&Hs4Gn#)X<GHUbLZLxP>X@Pcki|*5{Y41 zmUjc~z<0%dSBYwTqDo0L+{;|T`XanyYbpd2>wq7qs`{&K+qPXZP4jh|0r#m>r#dxF z`%KsMtf<(o+WzG1jyDD9k|x+R9jqAQ{ikBRC+T#0FrUvqy>Q{eMnIB)mHqwwE#u?k z*F}(>*d8`7BxeyT0#XXZEHInP<*uGTfBtn~g>>)Uy|wv#zH)MM@;@S|IJvo$<i$XW z*sww9z*l2qW1o$Vj<x`*)YsS7I6FIg#}VM9d`XqR42uJV-JpeBE|)b7!w*zQ>2!KU zp-`A&zQgTqe&$%<)iW<-p%{cQH#awP`}XaiG%+y|(sg}`g`d)b#9y=e1$bE4oX-ry zm>d`w2uVdjrGEcE?D@$kg+d`smgVJG->_}27vK3-&E@fUs$#L2CPgBV30andSOdg% zd#G5^F4s2&<Q!5GAi3RcrJ<oAD>XMa5BYq)DDyMjy%>;hDY?6%q9Wk&cxHiVDH@Ib ztGv8?CKL*VvBsyD`LSz*cx4tueDQep0A5v9x2URm9T<~<NAY;PueP?f6>H}Eia<PP zVW}V-amC4Hz^5om+pb-^ZU7kxm^*Obz#oIbV8Z9~1xkQ$zY2(=<hE3MepIhsy}GHa ztjyop*?9waCIQsf*I(bXY11c7O-(<;5*B`}<I+9_UjVU~6;*Ecl`YZywY9Y$bai!| z1-?WC0X#W$=ul4}5O_mX)fm<hTqZ!sl<tdSCQ9zNSi=vL#bU7^2ZKRv-@bi+!4{}a zNp|t##b30yw+{sZfp@X=+<Gi&6#^8okW&r09d0M|3GfwI7nwRB7L7)`6NyBBCX@M5 zNl9jl(i106eAwFB`uB>8ik}J)4Orr&8cXjv*|Gb@uCg3Ux`nXB>l)y-Xf*o%mMvR` zuU@_SUa=^3A3l88Nu$x++&nZlHz#E>nGX%a`1j1r%ybd8_S3G~uH2~!Z7@nK7W+v! z9PUaclgZ7SH-C&J&*t}Sv5U#&%a`9tCX*jcO-+s5xpSvCm&-k3UaUBEp}qe$C>ijD z!{K$2NaTZHFsS$R^!&D_rsmHq@nT||Ti5m2(W6J-OQllp=5o2uv)OFw{{8y{0)%~X zJ_q3Oc>HVEu5D2i<xNFVR_@ue=WKU(_osY~tC`c5X_^*4bLLD(DwX<SE|*)c>w3m8 zj7h^VvM!g)<MDU`Znt}dEX(DgQ0SjKcI^0DcXxM+Z+JN^Hv4+64h{~g!^6Wh4<0<I ul4ZG2Uth1q<MD^9R;_vjq<Mww`Tqc|3GbDPV(Vf60000<MNUMnLSTY+q(jL7 literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/slider-background.png b/components/custom/styles/default/images/slider-background.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba9c4731f7bd4f0aedd487592607d1185ba90b2 GIT binary patch literal 293 zcmV+=0owkFP)<h;3K|Lk000e1NJLTq003bC000IE1^@s6)A#T}0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy$4Nv%RCwC#lrajzFcgMglG><4#l|A3 zi#>y*U{^tK_X=*FMC#z=1w4QU=<3=#)Iy<Z#>QCRCCro$zU7Vo2ajY~HUoe&x<MH@ zY+=wFy7w4kmtYjE<5+_4_ka-M=J_*S*FoEAR+f*gdaHp)DP1M=1VS+e4B{eKieQWZ z?)RZ6ilrAtk$S$Gp^T@%Id>5(MbKIU?hZl-Me4df<$1oVsw%`f)J<du{6JqRWs|1q rm0*<#-VW#j<!&Bpe9$|3{0T4s@?SrIe|=;D00000NkvXXu0mjfXxn&x literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/slider-handle-active.png b/components/custom/styles/default/images/slider-handle-active.png new file mode 100644 index 0000000000000000000000000000000000000000..83cec3f4b3d4f8674326dd981a2df2252f4f2e6c GIT binary patch literal 506 zcmV<W0R{evP)<h;3K|Lk000e1NJLTq000;O000pP1^@s6$9QZo0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzoJmAMRCwCFltD`ZQ4q)H?b}_$ED!_9 zAdn<j3aN{Sy;u-*m%d7fr>uh@o%|wx1L+X#!GqBu7sFGKp#&Y0rPbZH&B$)-)rU6l zhsVJC{deBX4zyY=z+fl^#Zf9sL+MLO3-9uf#Uk(mUaeO5v)Syuq9`U~Y!@UV2!anG zgf$+Iuba*08>R%od97AEM)-qinrXu@AeBnV@L@Wgf^FMiS=QHNGP!6p8qZXcn#pAD z%H?wU2;qSc;5v?!fzCOc6pNtidb-o;++ymA-bzzd_3R*@2jTlvCddZeB?hrL=jX&; zG#1}{Th}yLRp1u`GB=6+*X=b0`xk??h8i7wY|gq2u=#<5Gn~X}S_#ziJc81!2MYt& zbst~){ma8bVI>By!yyneGVpu7-c2HrFunPFYcH1rJWGKQ3h$#4^aq1)ViKDsh-k@5 zrDBvyr8>e-aUbo-7~mfIM3bj(w_9(w+cu^g7H&V<h8v;u_%>YTM<x%{4D}Og#$u~l wjfqJbki3{g1Yz;j9m_3i0AUr8S@0{s0Da(>5XlFVNB{r;07*qoM6N<$g0)=W$N&HU literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/slider-handle.png b/components/custom/styles/default/images/slider-handle.png new file mode 100644 index 0000000000000000000000000000000000000000..765e610ac3adae3ef202e786aec4d18d5246193b GIT binary patch literal 516 zcmV+f0{i`mP)<h;3K|Lk000e1NJLTq000;O000pP1^@s6$9QZo0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzrb$FWRCwC7ls!wsP!xvGO>PpYRVcL< z`{7ywMR4hmr3!+3@vlhfWOXPMr~Z-tgW@1$=umOWXo&@BDhRcfrup*Rn3SxI&4G70 zkmtSU+?yAAy&hl@6o=wb6eXa<EhPls@&Sv4U?1LWHc#{U{3FM43L)eKVwC53AFk`F z)9LiK+wJPuav7X&wOUn#KPifmk!2au>2w@EEEWsUG!0Z${W1*Ws?+JbvXN*un|-L) z>lwLH0mruCXFiW*z!3sx)hdXhm>CQP_t?7e_f09iC>IJ~u2%5hvhjfBVi9<rzx3H` zMY!`r!f{|b4(zIsxzE@%ylu;}Ab}zqgEfwpl)>Nbl9>QD23CRw_<wjyd_gI^`JF%= zd@PK~*uH^jn$NnfUzbazofy1NCcv1XfioJ7?j%W49M?TK&gDQ9gjnD;uGyH);B7qq zW=zIrFGxbA8jXfrtJT_QbdGs+6vqH_=o3%=G8_)u{eEA=){+G2$I@^wkQhzFZL*Ge zut89(Kx-0-Y8nxVX~1Mh<c1IujqXTqTLTED2+h1-0R{jKft<b!y%dfB0000<MNUMn GLSTYFmgp`3 literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/slider.png b/components/custom/styles/default/images/slider.png new file mode 100644 index 0000000000000000000000000000000000000000..3f310e37cecab290854b8552bad74b71ef0f9336 GIT binary patch literal 617 zcmV-v0+#)WP)<h;3K|Lk000e1NJLTq006`Q000aK1^@s6JslFV00004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10p>|WK~!jg?byGoQehm&@%MA?xn!=M2I&WcM-K@OLPUj#(^<o{ zr6mX=`Xy#Vw6<Mph;CyvGz89}gAQWR-PEBDN2sO6k|4U4=Xjomqx}O>hWGn|@A$xX zcs@MO_p6G<A^@)IUIeZHX8?r|n@<C8f!$WC^#VW@i$z@5y`{CjIvR~0b~>H+v)L?M z9*|&&jg?F$x60*mp-?E?R7yQ+x7$0a(P*5|TEA&Fo7a5b{{jTSf;c^Ty)6szSEywf zz_xAMN2=B86T>i0o51bqblUWN|1<Cn_)Z)O353{Gt3a5*Vc+)`lgZ?jWm$Jj;QVkn zd=AWjufRSKB4H4lO#xfL98jL;byKO-brZ;Xp7#m(v8>gXNr+7s5eH-DdESRosdUoR zTCbjukT?ht@;ZovAtJu>p;9W+T4MlyHk&=V=Ej6rhu>RN$8nBFQS{MJO1;kIas}c6 z!z7-(m6X&0D1-RUZ`-zA4#RNI1a{KtbU%~Hyd00m`^4X+koY+fVpA!WTPDYGj#-v< zVX;`8Q-G@1>vy9lx;z*R9(23iy&wpFB7ykd$(;9RR3ec$RH;<X=JWY`K@dFa^?LUe z@#=|Mt#(OkeZw@(Q)_Nih<_#sf_L-z{BghEe+uvm3W%-IX6h|V00000NkvXXu0mjf DB;ptf literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/spinbox_down.png b/components/custom/styles/default/images/spinbox_down.png new file mode 100644 index 0000000000000000000000000000000000000000..a6f3f79e969c11f016fd52b2f2db681b44c7b8a0 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQY^(zo*^7SP{WbZ0pxQQctjQh z)pvm~<6qsy9za3K64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TUc)B=- zNKCCgZ|is1L4fr^qIs0$|7|;pVj>?gXbK(V%$R7w9RAQkrm1V1QD?bqq|(Z3C*sam zgoSjj@i2J%d)~Zf%T}%O*L)hp(fHxK;pesA|7AbiTOaDRcY12&cX2nD6|bxOUGz6; zbTt?AEz68LS|}6qxKPG1d$01M<0ihn3=ABHKb(#FeX&&b?8aigE!V8m>O3YbVPp_^ z9^m!!&bGCVN4WE5rExRN*689(FW1yqS~uh8Nr~b&zvZ@EyPYU;%~4>>=g^tYEzfwV myVyi!zwgYLoO<*7SO5LjA7%cU@gf2gIt-q!elF{r5}E+RM2Z#w literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/spinbox_up.png b/components/custom/styles/default/images/spinbox_up.png new file mode 100644 index 0000000000000000000000000000000000000000..a484194125fa292abfbcc444358c00906990da8b GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQY^(zo*^7SP{WbZ0pxQQctjQh z)pvm~<6qsy9za3K64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1SpdAc}; zNK7p~XP9-^K;+oR^P5s_S(}&b;`o%3aY<rV<*N%zpTDr2rC5H#*XkRK;>$a0%RdNg zn6Q!e=(6C0yf5pk55Irx8XB4ycmKOSLm9)ot=H0HRGzheubZrLa^6gNhME?Eynn2v zvHDYj-k-_YdhL+q_K89BW-Z&fm#fDx|Jp5UO;v`54yCkx>WeNL@O<Ncu`4gTr}ES$ zotf(e1E0)^X0~V(n8u)RYg?_#qU$#2&pzGHuwaT)pvY<yU;ca5;!{(9N**`lR@}F~ i@&2*GE0;}b|1t=bnOZt9+nombj=|H_&t;ucLK6U%`G(g3 literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/spinner.png b/components/custom/styles/default/images/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..664c2b1491498ee0158cb7674602265cc5f5c70c GIT binary patch literal 2629 zcmV-L3cB@)P)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L0E%e<0E%e=v1PL|00007bV*G`2igM< z0yrX}$<`hK013rOL_t(o!?l=ua8%V9z<=M}fELP)f;_|2*y%_$Ar5gAt%|I7ZNw_F z8%aCZkpWthp|sGBv011O+Pce_j5F8{y2T{YN=tWP(+VP)?uFPwwNp*3kEv8Ki%tNw z#M!OX2g!c@qvyu!5)f3*%+9^%?z!ju?svY|`Gk{bx8Hs{B0_U>GXRZ^jb%V3Fvnb* zo12?E8yg#~{{DVxZEYP~ym)aGSRf+XRduI`ya2r2+S+=QQ)ne8GpMDd#RCIq0Tuw0 z0aO(cc^v2jL{$p_B65+cR;p?xaEGe?TSRUIo<0>oYq*E;czoEtk>KU3>W4#Bzij%_ z*4Cy=mMj^is^dijKt%)*8LO%vcymS~k&mrW+&>{;aZ^?Q{f~Xm)JSWxxel0NQ$%F4 z`G7(5>~|va9Kg*t-%L84{&W(I$KzHs8YLc&pA(PAe-VqtDp#&t$?Das#ccO(5!qy< z<1Id=v9WQSr=zM`223^gmid^it*xyJP$(2UsVxhK!<!?K$XV%hnn)yK9TzYbixH2< ziAJM^SS&Uc*a9pQk^AHExZHjB-Fol6_lg<5(JWe`s;KHjV4`o{3932<D3~=~1pWe0 zTU#42FjYVds0BJAk;vF|I$elFB80=?V*y2kXf#SJ7ArMyvkb(ws`^uaRjXF1kxHkC zJn6kBB4xl7-&|A8ZNXf3x3;z(Sh#RuV9S;*gW+&^6!4(=2vybDKspkMj7z7}baZqa z3mA<?z1v4bWVWiRh<FS9Bp#372(W0;B57%9ISRNwiJjqXscBy|pd})rz*c|_8#WA@ z=WA5;Yrvq0s4=vwf%`vE2SwyXV|ijEFkmKlI3ABrYj1D&EG7+PRrL*3-3Gh@aO<tN zTB^De=m6eS)!l7vZQFg;x&-*XXW@WljOhhcZ9guc=Srf{=$$|f@T&2XB?fo`@L((! zvy97mNkkTj$i*!!EjKndH}6@oVuhS}=9z`Iwzl85wY5c5wNgZud258j;TgbMqb3EP zA8rG#>ged`GUGlHSh2tJwmKe<Pf^tefLimlUi(=z8og^cm#}>Ka@MY0dt8?h4u}6F zA|am-{Qy{&PNyF>(v>4ej%a6R=kS04>({U6@ZrOOrlzJrW8HTFtIamQ2`pH-a^+4F z0xc2I=H_M{4ruY>#iFWsY7q{HLn5*fm;n3(s86TUe*>61cdqr=V~-V%QMp7SQ36a; z)%P138uodAtXsFPWa-kS0|s)AfozIKqdSYG{Yfnni3~Yr133>^nNFwk0M}oCy=>pU zT>*l@;Ar3qRUHtKE=eR3WvcotV2Q}1s``Y8?5VG>|F3_MHEY(;)YMe0uO|%%oG^L> zgTae{SwO9-UM(W~RP}O6BoZ~My2Gbu1z?Y={u$_KXlQuWKT#|e8}gZ_(uRW!27~7S zVO6~jxI#oG`opV;%#uVRvBtz#H7;d@7kfqIT~*yBB0s9HuYYyjx^=R2=~Cr0wAr&~ zOIKHy27|#WpdG080Sy?t2$=poCBR$*BftnV&ru)%d=a=5=m!V{0-p)atm8$aSAesM zJVZ%Raxy~_iNt-XS_MoHkx5=EWvmt;-O$ib%V}uAU~r?VE--8LiO3<~0B{g^Lsff9 z>g((8NF)*gV4|u{7LhU&{L6t0MPw_dul*8u(!d>1)k9rfT?aoV(uW>;$f~ceA2j3# zfFYwuBoZS}2i44(GqEho+O=!fQ@~Th=xM+UwUSDuL{%-LhB|-#{K4WEHg4P~fZlS; zEuSlBWo6|U5g8>Sx#ypM{{3Nfw)jCZnY2V?lF3fWRQ2_`y1Hjiha{`2s(uK3S5^OI z{NC##vL85P5{<V?QmNETRh<T$2TV1&-9!U80r(>@?=<P)m8yCHaDiu-#)=OEZ;42c z1>7kj8${$D5%~@<M^&p093paYGMO9?kV>WGbC4PU)2B}_Rn<#<9%DdNj~ahGPDCyM zDlFi&qB#acq~P;KM}Z3O)b?2cD=I1kz_P3nz;8w5H50u`L}Y|H=M0+lcStIgssVO* zM@V0L8h9MoGJpR3e|isH_y38s<2a`Tme1z_ux-0oqF+$edBE3!tAX=;TYa6RQmHcF z@4kb0mx#0*up`4Q=DIGbN+=XMDY#rNhlmWp<#M^ROG``N8D{&x0ywH#XO68k7~Ogx zl}hbPCX+WMlgTr@7dCC$6!1YsGnvdaUO$t`oU-%`-0XZlpUvm<P5#Wjrl!X7fsUCz zeR^3{RaL+P9O(xG*s)`W7_bSMOy)P4Ohz-A%$u1^Cg_cM=9y=tr>Ez*VA*U|ve~TV zgS#e|%N@$)a%z5m$mjFp0s8y<*}Qr4F*+{EWRkkNx}gW#wr%5v8*cEVbcxyS3SY+Y z5>V|p&WFQ6?cKYVY15`1Pm)npjrm;)uoq~sZM(~i5wBul+xAC?rmn6oGMUT}oa?%` ziHNJJ6-8x`77wnwySuEXr{}Dq|HUW4@!4#4w%509J8t6dQ0YWfr>SaZKA(@~^LcFB z))Ph&*L9}?KL-~2YAXRV+xk!_belJ}r>CdgB%6N)c8bU&GiJ;<(%aixVf^b=z=yz` z^78VRjf6(3>UI%vRCUm#U*74i6PRb)_WLI)9(_+$7y7bm?~9%SmV1M`ySu-ns&jxz zKtx2osjA*W6HI>!P_C-q2H3xUe~E3|ABso=&}Tk8;Hy9k_~C{HRMq=|-M)Sa@D5NP z3WeV5?(QxzIur&b`h3>Q)z#HG^ID&(zT(rf`MtfpW#^uI?m&Nkzh&F@tH2LT1QAnU z>H@yyS-ofZmfvl-u1hEsdK<XO_(Sji6^`S);JU6=U0v;!*sd{PM-A{kU)JoUZkTO6 zUqtEv#*Q6ZF#4EQ)n@a`9ucXvZTsDPK98yn`OG1}P$-1sIJmBBg+ifzV6Lie1==0Q z`8B}k(WBLD?<J~wm4UGg$N_-f-d?M`y!>6@pcgJp1+1aBw|5*sUtgd1A!~qDA`-D} zyFZ`LTefXeT3UMi60qYq1=n?P9Opm4T-SBQlkjDiUFPZIwIXu1iPIy1_e7-6r#1!P z4YP#-b3I=~YJp#sm6egp<*;qL-<06Ie&M7mtX`yW97kQ(W#q__p5;ywkp)I70VAb@ zs(Q$OC<3xYXB&X~vf1odfH7mneEJ%-<2c2M1G8q$^0sRfFvi<nQy+ZGB$@cE{x#q| zAKU@pQBP+r>*GuNxAml|{QhjED06uoxKcze1cJaffaj{KtNT6A>yzLUB63hww~EM% n<>lplMo$qD%FD|?QG)*i-|6WSYzBoC00000NkvXXu0mjf?5^_a literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/switch_normal.png b/components/custom/styles/default/images/switch_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ac46b2112d5cb7a7bf8a476bff4f14c2094f253d GIT binary patch literal 834 zcmV-I1HJr-P)<h;3K|Lk000e1NJLTq003?P000{Z1^@s6owT}%00004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10>4Q_K~!jg?b<O&8&Mbs@c;MTUG83!$R*I)C7YvIvN*IT(!ov1 zU>A!;aO~#b<m%9=qf<dj#lgivTBw7IgHxb$DH$vliLLcwn%pJ#z7FxwL<^m~6W(tM z@0Jff{_lHtc~mZ!G06A*M?{pl@xZuqLWp)Yn>`&|x8fi5dR@7$yC|ic8Xg|Dl~Uci zEz!755CoZviwhkD!KY5A^FE)?2f$_H>h-!(O1+(%n{!uIRvvnu*8vbFTCowcPft(X z_4W0a`}_OPecykjweDB|;JWVO%*;$?ZEdZ@%wM$DjijqJt`v*K?CR?3m=K~=tyY(7 zwb~mhm&<52n;#Aj4<CD;_l=o<C0(d-tD&Q#qbJMD%T%k?o>^ySXI`;bbUn|@MN#wz zfH{<;Q@d0uNg;&iIF7QUlo{K$0f2}|0+0z8X#4{a!EqchK0fYP@d7hTt+h#8iV=|{ zA^}``9RMJi*-oe?<Nx$Gj)(}oEz%?|-J}qruW?{zp|v)NOEG4a0Q$B{VrI$ACUGgo z%>9W2Kmdf9aj7Q&h%gMP?^J0Tmu}1~iAW3$4fQ3?Y?bLJFAtI!Oq^+4id`m70%peD zH{xH3GmT5Jc*X%RGwz;|7(7*?choeAOR-zu<IG3q^ozfo<nwu0Q51z*Ys<{IdqH-) zU7?hUtU{siyWMVw=jZ3baU2yzQIvFb#!XU6d2(_hlv3U8?d@|50GiF_=bfFMsfC4w z2SE^oQ55N<3pK6?Aw(vVv3GZOX=G&N>%qZ6Z^pG+t#^BSdoPISX{Az8xm*s+%t;q) z^!{@5eIHv}TXcMU%u7p4uQxU}K=FmxMx)`(&dzSMTCIw0+wpY<BVl3KyCpd~I{I^R za&mEge*PnXtH#Bu)hcanZjJ>(kh}XbjX{M%A)J_)_&z;7{p0%jU;0!ao{N=pyZ`_I M07*qoM6N<$g4~^fu>b%7 literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/images/switch_pressed.png b/components/custom/styles/default/images/switch_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..a04a3f4b0f52626f1145359b45cb6c3f850ee9f6 GIT binary patch literal 709 zcmV;$0y_PPP)<h;3K|Lk000e1NJLTq003?P000{Z1^@s6owT}%00004b3#c}2nYxW zd<bNS00009a7bBm000e&000e&0sSqbNB{r;8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10zyedK~!jg?b<PG+dvow;8&-!&N?Bm3nf{#mV_ow4R&b>HLd9o zFovWWIutKm{A1c5P;k3=D|F4~!63XiV<1D94kZvOkR!>JBCbR0)Ja<k9b&0`&m`_Z zeDHF2pU`RB+uOKqHk;iBAby!3H;yqjw=C=I`Z!-a_`Y8*l}axR!+7F2PNiHfYd2dW z`JFUP^&kk+FbqG0Vfe<j?XSR(;C$aN3n5+~930%++uPd_LO|0fx4ej=2;=eik>`2t z$;ruM!!QyK0G#t)x7)q5zrVjDrG&2QtFDzSu`CPic3WqRJ*-x%ua1t6`WyflWA{6q zPE$$=&iUWoLvEO^>#!^fjYb2<$H&hA^jQ=|cC}iq2q8FymS2nT0NmQz+Ol~Z$9!#V zP1iJy&b6FljG<I2vCYj*`^pld;EIE-x&ZQTXvGy22fhbJXI%a*XGB|NLD5!OP!wE& zEayX8WkFr8IBHIcftr(oqcg6cD7XTl@3{W}H75mRnkKkunioo`%U|9UUVbU1kYyR9 zlo^v!&gS!Zlq3m~Bw2NB<PXv`#rgR;Ow+t@UH5EpS?JL7yr->JtIQaKVHm5flPt-y z3_%cJGMT_}oR76yE#m-?rs><!X!M*h_Ml#`LrMw8sBg&wr4+(2gy(rUJv~LQ*Xs`k z189p2u|f#5*=)Xx<G3S)FzEhCJ|sy3r4%+cHoml4t(UIrz6bC#xP|F-stt$3yT0#N rR#GXsVtsu*+TGp#)NZ#wFOPo%NynoQ#A)9A00000NkvXXu0mjf`6)a4 literal 0 HcmV?d00001 diff --git a/components/custom/styles/default/tools/ColorConverter.qml b/components/custom/styles/default/tools/ColorConverter.qml new file mode 100644 index 000000000..5070ff1eb --- /dev/null +++ b/components/custom/styles/default/tools/ColorConverter.qml @@ -0,0 +1,59 @@ +import QtQuick 1.0 + +// This helper element allows extracting color values +QtObject { + property color color; + + function intValue(dec) + { + var result; + switch (dec) { + case 'a': + result = 10; + break; + case 'b': + result = 11 + break; + case 'c': + result = 12; + break; + case 'd': + result = 13; + break; + case 'e': + result = 14 + case 'f': + result = 15 + break; + default: + result = dec + break; + } + return Number(result); + } + + function convertSubstring(val) { + return 16*intValue(val[0]) + intValue(val[1]) + } + + function grayValue() { + return (red + green + blue)/3 + } + + onColorChanged: { + var string = "" + color + var redString = string.substring(1, 3) + var greenString = string.substring(3,5) + var blueString = string.substring(5,7) + var alphaString = string.substring(7,9) + red = convertSubstring(string.substring(1, 3)) + green = convertSubstring(string.substring(3,5)) + blue = convertSubstring(string.substring(5,7)) + alpha = convertSubstring(string.substring(7,9)) + } + + property int red + property int green + property int blue + property int alpha +} diff --git a/components/custom/visuals/AdjoiningCorner.qml b/components/custom/visuals/AdjoiningCorner.qml new file mode 100644 index 000000000..92027cef4 --- /dev/null +++ b/components/custom/visuals/AdjoiningCorner.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 + +Item { + property string corner: "" // Can we use Qt::Corner? see http://doc.trolltech.com/4.7/qt.html#Corner-enum + property alias styledItem: loader.styledItem + property alias adjoining: loader.adjoining + + clip: true + + anchors { + left: corner == "TopLeftCorner" || corner == "BottomLeftCorner" ? parent.left : parent.horizontalCenter + right: corner == "TopLeftCorner" || corner == "BottomLeftCorner" ? parent.horizontalCenter : parent.right + top: corner == "TopLeftCorner" || corner == "TopRightCorner" ? parent.top : parent.verticalCenter + bottom: corner == "TopLeftCorner" || corner == "TopRightCorner" ? parent.verticalCenter : parent.bottom + } + + Item { + width: parent.width*2 + height: parent.height*2 + x: corner == "TopLeftCorner" || corner == "BottomLeftCorner" ? 0 : -parent.width + y: corner == "TopLeftCorner" || corner == "TopRightCorner" ? 0 : -parent.height + + Loader { + id: loader + anchors.fill: parent + property Item styledItem:loader.styledItem + property int adjoining: 0x0 + sourceComponent: styling + } + } +} diff --git a/components/custom/visuals/AdjoiningVisual.qml b/components/custom/visuals/AdjoiningVisual.qml new file mode 100644 index 000000000..09bc34cc9 --- /dev/null +++ b/components/custom/visuals/AdjoiningVisual.qml @@ -0,0 +1,50 @@ +import QtQuick 1.0 + +Item { + id: adjoiningVisual + property int adjoins: 0 // use enum Qt::DockWidgetArea? see http://doc.trolltech.com/4.7/qt.html#DockWidgetArea-enum + property Item styledItem + property Component styling + +// Qt::LeftDockWidgetArea 0x1 +// Qt::RightDockWidgetArea 0x2 +// Qt::TopDockWidgetArea 0x4 +// Qt::BottomDockWidgetArea 0x8 + + Item { + anchors.fill: parent + + AdjoiningCorner { corner: "TopLeftCorner"; adjoining: topLeftAdjoining(); styledItem: adjoiningVisual.styledItem } + AdjoiningCorner { corner: "TopRightCorner"; adjoining: topRightAdjoining(); styledItem: adjoiningVisual.styledItem } + AdjoiningCorner { corner: "BottomLeftCorner"; adjoining: bottomLeftAdjoining(); styledItem: adjoiningVisual.styledItem } + AdjoiningCorner { corner: "BottomRightCorner"; adjoining: bottomRightAdjoining(); styledItem: adjoiningVisual.styledItem } + } + + function topLeftAdjoining() { + var adjoining = 0; + if(adjoins&0x01) adjoining |= Qt.Horizontal; + if(adjoins&0x04) adjoining |= Qt.Vertical; + return adjoining; + } + + function topRightAdjoining() { + var adjoining = 0; + if(adjoins&0x02) adjoining |= Qt.Horizontal; + if(adjoins&0x04) adjoining |= Qt.Vertical; + return adjoining; + } + + function bottomLeftAdjoining() { + var adjoining = 0; + if(adjoins&0x01) adjoining |= Qt.Horizontal; + if(adjoins&0x08) adjoining |= Qt.Vertical; + return adjoining; + } + + function bottomRightAdjoining() { + var adjoining = 0; + if(adjoins&0x02) adjoining |= Qt.Horizontal; + if(adjoins&0x08) adjoining |= Qt.Vertical; + return adjoining; + } +} diff --git a/components/images/folder_new.png b/components/images/folder_new.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8bb9bd768d8e8ab785d95483ead02ae6800dc5 GIT binary patch literal 1199 zcmV;g1W@~lP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H101k9TSaeirbZlh+MsI9nWpZ;NRH|S>0000NbVXQnL3MO!Z*l-k zVQ_CCLt$)TZDDR?a%E}Xks2xh001d;MObu1WpiV4X>fFDZ*BlWVRL0<Aa7<MN?~ht zVjxp=Wod3@av)@7b7^O8po9f;000BJNkl<ZNQteLO^6&t6vuznRnt8)&TMwwuc%3g z2L+Xg#E;-dLX;fTm|zS9BAz685^_-q9uyG|f}n_a(2IhCBC^TJQ#K*NgBpV$m_(v6 zF_>g`c6MfW=cA{)s-B0L%+9*2hHM@b)l|QFzxV#Hs#}Q&%d^*l_WY_}>aDt3Kzece zdac!cscYUPuC`9W*HJk92_px7S~kFycI-lAJK{H5*Ic8E&yrT&@tI8VfYQZJ^~l(l zmwip|#uxVO*{fCXra&~m+D)M1J<q-M(o_YJ-N2KO!4!9)i@N~{((3y=LS69o(vGrO zId*svK%9I1q0Ns(S_gRVJHz3<CyrYKCr=*#c)D6YRLJYc6$)i;#1wY6Gc7ztQu%<| z%y&DLl1=G}{I<c{8{aGdSnG2joc`^XMY0r&{j9rVbuJV9ywwc6OOU;Hp@YhjUvn5_ zmSlGSu)Fa5e&B{+0l-;iW~wBuWYH*3O%mybvOb5M`wVbPbq9Q%v^M5~Aos%}iJWyz zPnT&lnhUmh??_V18P(#pwbv7wBlyxQWQX7A(KiM^NB!bn;@KZtgZ+2Eya-^er8GH7 zlC*j|g9-v3-n@mitA`mX97b^#d=1<bC_pSCF-RR`hQG?I@|iw=uCEvH;=Vmk_YbTv z^=7?SSd7u!zu^H^j*c=>Dx=aIqXmef0C9hk*2YO{UlA4_C6ix|QhDZT75Y{knO;zV zv+nIDwr*o+Xk<RT0tAvIrcx~-;+dSeiBNA~Me-5N@`spkluS5CYx+HE6D1(W!Ed+l z;A8C=T|gYSMuNaIIeC7G=JoW+8O}}J!${vsiuq|GV&Vj1n`bT_pe1)QG4*-ZzYDO| z5=A+jv;PSIur9}i$}L25F=3`HX`JRsZH}R#eyp88Ve^30k;@fGlK6iC-D=3tOpEiu z3}|hzc0S22AnjCOOy-IKOPPqrrb_^9>IedjUM9eK|1T0*i-^A_6{Jg5fY7Kn>iICt z0`2?LKBu5iorT^=AeX<i(tZ*V>h&5TG%mXZ?KsMa$kgwrf2GxI;;lnGC<)NYV01`m za%95-+3-3-lf~!|tqgdDcY;eT&3cV<f1E+Ql$25iz$m2@5LK(QhsMXppV_!^MhC$^ z)4eit&U5tW_pVy49t0w#lrtSQ^zq{-zHrWOI)DDs%~ut@W6fss?6G5~#sE!6WCeu4 zAaHAEUXE3OQ$QI=l!%~|3TQVxL#HpxFb|}F6%pV4>34c@%}hFh{|2rA&Q3Ns=Tray N002ovPDHLkV1nxxBC7xZ literal 0 HcmV?d00001 diff --git a/components/plugin/qmldir b/components/plugin/qmldir new file mode 100644 index 000000000..e8452efd6 --- /dev/null +++ b/components/plugin/qmldir @@ -0,0 +1 @@ +plugin styleplugin diff --git a/components/src.pro b/components/src.pro new file mode 100644 index 000000000..83e0a3d4c --- /dev/null +++ b/components/src.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = styleitem diff --git a/components/styleitem/qstyleitem.cpp b/components/styleitem/qstyleitem.cpp new file mode 100644 index 000000000..90fa5a367 --- /dev/null +++ b/components/styleitem/qstyleitem.cpp @@ -0,0 +1,547 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** 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 Nokia Corporation 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 NOTgall +** 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 <QtGui/QStyle> +#include <QtGui/QStyleOption> +#include <QtGui/QApplication> +#include <QtGui/QMainWindow> +#include <QtGui/QGroupBox> +#include <QtGui/QToolBar> +#include <QtGui/QMenu> + + +QStyleItem::QStyleItem(QObject*parent) + : QObject(parent), + m_sunken(false), + m_raised(false), + m_active(true), + m_enabled(true), + m_selected(false), + m_focus(false), + m_on(false), + m_horizontal(true), + m_minimum(0), + m_maximum(100), + m_value(0) +{ +} + +void QStyleItem::initStyleOption(QStyleOption *opt) const +{ + if (m_enabled) + opt->state |= QStyle::State_Enabled; + if (m_active) + opt->state |= QStyle::State_Active; + if (m_sunken) + opt->state |= QStyle::State_Sunken; + if (m_raised) + opt->state |= QStyle::State_Raised; + if (m_selected) + opt->state |= QStyle::State_Selected; + if (m_focus) + opt->state |= QStyle::State_HasFocus; + if (m_on) + opt->state |= QStyle::State_On; + if (m_hover) + opt->state |= QStyle::State_MouseOver; + if (m_horizontal) + opt->state |= QStyle::State_Horizontal; +} + +QString QStyleBackground::hitTest(int px, int py) const +{ + QStyle::SubControl subcontrol = QStyle::SC_All; + QStyle::ComplexControl control = QStyle::CC_CustomBase; + QString type = m_style->elementType(); + if (type == QLatin1String("spinbox")) { + control = QStyle::CC_SpinBox; + QStyleOptionSpinBox opt; + opt.rect = QRect(0, 0, width(), height()); + opt.frame = true; + m_style->initStyleOption(&opt); + subcontrol = qApp->style()->hitTestComplexControl(control, &opt, QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SpinBoxUp) + return "up"; + else if (subcontrol == QStyle::SC_SpinBoxDown) + return "down"; + + } else if (type == QLatin1String("slider")) { + control = QStyle::CC_Slider; + QStyleOptionSlider opt; + opt.rect = QRect(0, 0, width(), height()); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.sliderPosition = m_style->value(); + m_style->initStyleOption(&opt); + subcontrol = qApp->style()->hitTestComplexControl(control, &opt, QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SliderHandle) + return "handle"; + } else if (type == QLatin1String("scrollbar")) { + control = QStyle::CC_ScrollBar; + QStyleOptionSlider opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.pageStep = 200; + opt.orientation = m_style->horizontal() ? Qt::Horizontal : Qt::Vertical; + opt.sliderPosition = m_style->value(); + subcontrol = qApp->style()->hitTestComplexControl(control, &opt, QPoint(px,py), 0); + + if (subcontrol == QStyle::SC_ScrollBarSlider) + return "handle"; + if (subcontrol == QStyle::SC_ScrollBarSubLine || subcontrol == QStyle::SC_ScrollBarSubPage) + return "up"; + if (subcontrol == QStyle::SC_ScrollBarAddLine || subcontrol == QStyle::SC_ScrollBarAddPage) + return "down"; + } + return "none"; +} + +QSize QStyleItem::sizeFromContents(int width, int height) const +{ + QString metric = m_type; + if (metric == QLatin1String("checkbox")) { + QStyleOptionButton opt; + initStyleOption(&opt); + opt.text = text(); + return qApp->style()->sizeFromContents(QStyle::CT_CheckBox, &opt, QSize(width,height), &m_dummywidget); + } else if (metric == QLatin1String("button")) { + QStyleOptionButton opt; + initStyleOption(&opt); + opt.text = text(); + return qApp->style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(width,height), &m_dummywidget); + } else if (metric == QLatin1String("tab")) { + QStyleOptionTabV3 opt; + initStyleOption(&opt); + opt.text = text(); + return qApp->style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, QSize(width,height), &m_dummywidget); + } else if (metric == QLatin1String("combobox")) { + QStyleOptionComboBox opt; + initStyleOption(&opt); + return qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, QSize(width,height), &m_dummywidget); + } else if (metric == QLatin1String("spinbox")) { + + QStyleOptionSpinBox opt; + initStyleOption(&opt); + return qApp->style()->sizeFromContents(QStyle::CT_SpinBox, &opt, QSize(width,height), &m_dummywidget); + } else if (metric == QLatin1String("edit")) { + QStyleOptionFrameV3 opt; + initStyleOption(&opt); + return qApp->style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(width,height), &m_dummywidget); + } + return QSize(); +} + +int QStyleItem::pixelMetric(const QString &metric) const +{ + if (metric == "scrollbarExtent") + return qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent); + else if (metric == "defaultframewidth") + return qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + else if (metric == "taboverlap") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabOverlap); + else if (metric == "tabbaseoverlap") + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap); + else if (metric == "tabbaseheight") + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseHeight); + else if (metric == "tabvshift") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabShiftVertical); + else if (metric == "menuhmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuHMargin); + else if (metric == "menuvmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuVMargin); + else if (metric == "menupanelwidth") + return qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth); + return 0; +} + +QVariant QStyleItem::styleHint(const QString &metric) const +{ + if (metric == "focuswidget") + return qApp->style()->styleHint(QStyle::SH_FocusFrame_AboveWidget); + if (metric == "tabbaralignment") { + int result = qApp->style()->styleHint(QStyle::SH_TabBar_Alignment); + if (result == Qt::AlignCenter) + return "center"; + return "left"; + } + if (metric == "framearoundcontents") + return qApp->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents); + return 0; +} + + +QRect QStyleBackground::subControlRect(const QString &subcontrolString) const +{ + QStyle::SubControl subcontrol = QStyle::SC_None; + QString m_type = m_style->elementType(); + if (m_type == QLatin1String("spinbox")) { + QStyle::ComplexControl control = QStyle::CC_SpinBox; + QStyleOptionSpinBox opt; + m_style->initStyleOption(&opt); + opt.rect = QRect(0, 0, width(), height()); + opt.frame = true; + 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, &opt, subcontrol, 0); + } else if (m_type == QLatin1String("slider")) { + QStyle::ComplexControl control = QStyle::CC_Slider; + QStyleOptionSlider opt; + m_style->initStyleOption(&opt); + opt.rect = QRect(0, 0, width(), height()); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.sliderPosition = m_style->value(); + if (subcontrolString == QLatin1String("handle")) + subcontrol = QStyle::SC_SliderHandle; + else if (subcontrolString == QLatin1String("groove")) + subcontrol = QStyle::SC_SliderGroove; + return qApp->style()->subControlRect(control, &opt, subcontrol, 0); + } else if (m_type == QLatin1String("scrollbar")) { + QStyle::ComplexControl control = QStyle::CC_ScrollBar; + QStyleOptionSlider opt; + m_style->initStyleOption(&opt); + opt.rect = QRect(0, 0, width(), height()); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.pageStep = m_style->horizontal() ? width() : height(); + opt.orientation = m_style->horizontal() ? Qt::Horizontal : Qt::Vertical; + opt.sliderPosition = m_style->value(); + 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, &opt, subcontrol, 0); + } + return QRect(); +} + +QStyleBackground::QStyleBackground(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + m_menu(0), + m_style(0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); + setCacheMode(QGraphicsItem::DeviceCoordinateCache); + setSmooth(true); + + m_menu = new QMenu(); + m_menu->ensurePolished(); +} + +void QStyleBackground::setStyle(QStyleItem *style) +{ + if (m_style != style) { + m_style = style; + //connect(&m_dummywidget, SIGNAL(updateRequest()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(onChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(selectedChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(textChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(raisedChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(sunkenChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(hoverChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(maximumChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(minimumChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(valueChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(enabledChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(horizontalChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(focusChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(m_style, SIGNAL(elementTypeChanged()), this, SLOT(updateItem())); + emit styleChanged(); + } +} + + +void QStyleBackground::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + QString type = m_style->elementType(); + if (type == QLatin1String("button")) { + QStyle::ControlElement control = QStyle::CE_PushButton; + QStyleOptionButton opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + + // Dirty hack to fix button label positioning on mac + if (qApp->style()->metaObject()->className() == QLatin1String("QMacStyle")) + opt.rect.translate(0,2); + + qApp->style()->drawControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("toolbutton")) { + QStyle::ComplexControl control = QStyle::CC_ToolButton; + QStyleOptionToolButton opt; + m_style->initStyleOption(&opt); + opt.subControls = QStyle::SC_ToolButton; + opt.rect = QRect(0, 0, width(), height()); + QToolBar bar; + QWidget dummy(&bar); + if (opt.state & QStyle::State_Raised || opt.state & QStyle::State_On) + qApp->style()->drawComplexControl(control, &opt, painter, &dummy); + } + else if (type == QLatin1String("tab")) { + QStyle::ControlElement control = QStyle::CE_TabBarTabShape; + QStyleOptionTabV3 opt; + m_style->initStyleOption(&opt); + int overlap = qApp->style()->pixelMetric(QStyle::PM_TabBarTabOverlap); + opt.rect = QRect(overlap, 0, width()-2*overlap, height()); + if (m_style->text() == "South") + opt.shape = QTabBar::RoundedSouth; + if (m_style->activeControl() == QLatin1String("beginning")) + opt.position = QStyleOptionTabV3::Beginning; + else if (m_style->activeControl() == QLatin1String("end")) + opt.position = QStyleOptionTabV3::End; + else if (m_style->activeControl() == QLatin1String("only")) + opt.position = QStyleOptionTabV3::OnlyOneTab; + else + opt.position = QStyleOptionTabV3::Middle; + qApp->style()->drawControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("menu")) { + QStyleOptionMenuItem opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + QStyleHintReturnMask val; + qApp->style()->styleHint(QStyle::SH_Menu_Mask, &opt, &m_dummywidget, &val); + painter->save(); + painter->setClipRegion(val.region); + m_menu->setContextMenuPolicy(Qt::CustomContextMenu); + m_menu->ensurePolished(); + opt.palette = m_menu->palette(); + painter->fillRect(opt.rect, opt.palette.window()); + painter->restore(); + qApp->style()->drawPrimitive(QStyle::PE_PanelMenu, &opt, painter, m_menu); + QStyleOptionFrame frame; + m_style->initStyleOption(&frame); + frame.lineWidth = qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth); + frame.midLineWidth = 0; + frame.rect = opt.rect; + qApp->style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, painter, m_menu); + // qApp->style()->drawControl(QStyle::CE_MenuVMargin, &opt, painter, m_menu); + } + else if (type == QLatin1String("frame")) { + QStyle::PrimitiveElement control = QStyle::PE_Frame; + QStyleOptionFrameV3 opt; + opt.rect = QRect(0, 0, width(), height()); + opt.frameShape = QFrame::StyledPanel; + opt.lineWidth = 1; + m_style->initStyleOption(&opt); + qApp->style()->drawPrimitive(control, &opt, painter, 0); + } + else if (type == QLatin1String("focusframe")) { + QStyle::ControlElement control = QStyle::CE_FocusFrame; + QStyleOption opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + qApp->style()->drawControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("tabframe")) { + QStyle::PrimitiveElement control = QStyle::PE_FrameTabWidget; + if (m_style->minimum()) { + QStyleOptionTabWidgetFrameV2 opt; + m_style->initStyleOption(&opt); + if (m_style->text() == "South") + opt.shape = QTabBar::RoundedSouth; + opt.selectedTabRect = QRect(m_style->value(), 0, m_style->minimum(), height()); + opt.rect = QRect(0, 0, width(), height()); + qApp->style()->drawPrimitive(control, &opt, painter, 0); + } else { + QStyleOptionTabWidgetFrame opt; + m_style->initStyleOption(&opt); + opt.rect = QRect(0, 0, width(), height()); + qApp->style()->drawPrimitive(control, &opt, painter, 0); + } + } + else if (type == QLatin1String("menuitem")) { + QStyle::ControlElement control = QStyle::CE_MenuItem; + QStyleOptionMenuItem opt; + opt.rect = QRect(0, 0, width(), height()); + opt.text = m_style->text(); + m_style->initStyleOption(&opt); + opt.palette = m_menu->palette(); + qApp->style()->drawControl(control, &opt, painter, m_menu); + } + else if (type == QLatin1String("checkbox")) { + QStyle::ControlElement control = QStyle::CE_CheckBox; + QStyleOptionButton opt; + m_style->initStyleOption(&opt); + if (!(opt.state & QStyle::State_On)) + opt.state |= QStyle::State_Off; + opt.rect = QRect(0, 0, width(), height()); + opt.text = m_style->text(); + qApp->style()->drawControl(control, &opt, painter, 0); + } + else if (type == QLatin1String("radiobutton")) { + QStyle::ControlElement control = QStyle::CE_RadioButton; + QStyleOptionButton opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.text = m_style->text(); + qApp->style()->drawControl(control, &opt, painter, 0); + } + else if (type == QLatin1String("edit")) { + QStyle::PrimitiveElement control = QStyle::PE_PanelLineEdit; + QStyleOptionFrameV3 opt; + opt.rect = QRect(0, 0, width(), height()); + opt.lineWidth = 1; // jens : this must be non-zero + m_style->initStyleOption(&opt); + qApp->style()->drawPrimitive(control, &opt, painter, 0); + } + else if (type == QLatin1String("slidergroove")) { + QStyle::ComplexControl control = QStyle::CC_Slider; + QStyleOptionSlider opt; + opt.rect = QRect(0, 0, width(), height()); + opt.minimum = 0; + opt.maximum = 100; + opt.subControls |= (QStyle::SC_SliderGroove); + opt.activeSubControls = QStyle::SC_SliderHandle; + m_style->initStyleOption(&opt); + qApp->style()->drawComplexControl(control, &opt, painter, 0); + } + else if (type == QLatin1String("combobox")) { + QStyle::ComplexControl control = QStyle::CC_ComboBox; + QStyleOptionComboBox opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + m_dummywidget.activateWindow(); + qApp->style()->drawComplexControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("spinbox")) { + QStyle::ComplexControl control = QStyle::CC_SpinBox; + QStyleOptionSpinBox opt; + opt.rect = QRect(0, 0, width(), height()); + opt.frame = true; + m_style->initStyleOption(&opt); + if (m_style->value() & 0x1) + opt.activeSubControls = QStyle::SC_SpinBoxUp; + else if (m_style->value() & (1<<1)) + opt.activeSubControls = QStyle::SC_SpinBoxDown; + opt.subControls |= QStyle::SC_SpinBoxDown; + opt.subControls |= QStyle::SC_SpinBoxUp; + if (m_style->value() & (1<<2)) + opt.stepEnabled |= QAbstractSpinBox::StepUpEnabled; + if (m_style->value() & (1<<3)) + opt.stepEnabled |= QAbstractSpinBox::StepDownEnabled; + qApp->style()->drawComplexControl(control, &opt, painter, 0); + } + else if (type == QLatin1String("slider")) { + QStyle::ComplexControl control = QStyle::CC_Slider; + QStyleOptionSlider opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.tickPosition = QSlider::TicksBelow; + opt.sliderPosition = m_style->value(); + opt.tickInterval = 1200 / (opt.maximum - opt.minimum); + opt.sliderValue = m_style->value(); + opt.subControls = QStyle::SC_SliderTickmarks | QStyle::SC_SliderGroove | QStyle::SC_SliderHandle; + opt.activeSubControls = QStyle::SC_None; + qApp->style()->drawComplexControl(control, &opt, painter, 0); + } + else if (type == QLatin1String("progressbar")) { + QStyle::ControlElement control = QStyle::CE_ProgressBar; + QStyleOptionProgressBarV2 opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.progress = m_style->value(); + qApp->style()->drawControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("toolbar")) { + QStyle::ControlElement control = QStyle::CE_ToolBar; + QStyleOptionToolBar opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + QMainWindow mw; + QWidget w(&mw); + qApp->style()->drawControl(control, &opt, painter, &w); + } + else if (type == QLatin1String("groupbox")) { + QStyle::ComplexControl control = QStyle::CC_GroupBox; + QStyleOptionGroupBox opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.text = m_style->text(); + opt.lineWidth = 1; + opt.subControls = QStyle::SC_GroupBoxLabel; + // oxygen crashes if we dont pass a widget + qApp->style()->drawComplexControl(control, &opt, painter, &m_dummywidget); + } + else if (type == QLatin1String("scrollbar")) { + QStyle::ComplexControl control = QStyle::CC_ScrollBar; + QStyleOptionSlider opt; + opt.rect = QRect(0, 0, width(), height()); + m_style->initStyleOption(&opt); + opt.minimum = m_style->minimum(); + opt.maximum = m_style->maximum(); + opt.pageStep = m_style->horizontal() ? width() : height(); + opt.orientation = m_style->horizontal() ? Qt::Horizontal : Qt::Vertical; + opt.sliderPosition = m_style->value(); + opt.sliderValue = m_style->value(); + opt.activeSubControls = (m_style->activeControl() == QLatin1String("up")) + ? QStyle::SC_ScrollBarSubLine : + (m_style->activeControl() == QLatin1String("down")) ? + QStyle::SC_ScrollBarAddLine: + QStyle::SC_ScrollBarSlider; + + opt.sliderValue = m_style->value(); + opt.subControls = QStyle::SC_All; + qApp->style()->drawComplexControl(control, &opt, painter, &m_dummywidget); + } +} diff --git a/components/styleitem/qstyleitem.h b/components/styleitem/qstyleitem.h new file mode 100644 index 000000000..5d195252a --- /dev/null +++ b/components/styleitem/qstyleitem.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** 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 Nokia Corporation 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 <QDeclarativeItem> +#include <QtGui/QStyle> +#include <QtGui> +#include <QEvent> + +/** + * This class adds experimental support for + * animated progressbars + */ +class AnimWidget: public QProgressBar +{ +Q_OBJECT +public: + AnimWidget(QWidget *parent = 0): + QProgressBar(parent) { + setMaximum(100); + setMinimum(0); + setValue(50); + // setAttribute(Qt::WA_WState_InPaintEvent); + // setAttribute(Qt::WA_WState_Visible, true); + } +public: + bool event(QEvent *e){ + // emit updateRequest(); + return QProgressBar::event(e); + } +signals: + void updateRequest(); +}; + +class QStyleItem: public QObject +{ + 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 enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY( bool selected READ selected WRITE setSelected NOTIFY selectedChanged) + Q_PROPERTY( bool focus READ focus WRITE setFocus NOTIFY focusChanged) + 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) + + // 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) + +public: + QStyleItem(QObject *parent = 0); + + bool sunken() const { return m_sunken; } + bool raised() const { return m_raised; } + bool active() const { return m_active; } + bool enabled() const { return m_enabled; } + bool selected() const { return m_selected; } + bool focus() 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 value() const { return m_value; } + QString elementType() const { return m_type; } + QString text() const { return m_text; } + QString activeControl() const { return m_activeControl; } + + 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 setEnabled(bool enabled) { if (m_enabled!= enabled) {m_enabled = enabled; emit enabledChanged();}} + void setSelected(bool selected) { if (m_selected!= selected) {m_selected = selected; emit selectedChanged();}} + void setFocus(bool focus) { if (m_focus != focus) {m_focus = focus; emit focusChanged();}} + 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 setElementType(const QString &str) { if (m_type != str) {m_type = str; emit elementTypeChanged();}} + 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();}} + + virtual void initStyleOption(QStyleOption *opt) const; +public Q_SLOTS: + int pixelMetric(const QString&) const; + QVariant styleHint(const QString&) const; + QSize sizeFromContents(int width, int height) const; + +Q_SIGNALS: + void elementTypeChanged(); + void textChanged(); + void sunkenChanged(); + void raisedChanged(); + void activeChanged(); + void enabledChanged(); + void selectedChanged(); + void focusChanged(); + void onChanged(); + void hoverChanged(); + void horizontalChanged(); + void minimumChanged(); + void maximumChanged(); + void valueChanged(); + void activeControlChanged(); + +protected: + QString m_type; + QString m_text; + QString m_activeControl; + bool m_sunken; + bool m_raised; + bool m_active; + bool m_enabled; + bool m_selected; + bool m_focus; + bool m_hover; + bool m_on; + bool m_horizontal; + int m_minimum; + int m_maximum; + int m_value; + AnimWidget m_dummywidget; +}; + +class QStyleBackground: public QDeclarativeItem +{ + Q_OBJECT +public: + Q_PROPERTY( QStyleItem* style READ style WRITE setStyle NOTIFY styleChanged) + + QStyleBackground(QDeclarativeItem *parent = 0); + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +public Q_SLOTS: + QStyleItem *style(){return m_style;} + void setStyle(QStyleItem *style); + void updateItem(){update();} + QString hitTest(int x, int y) const; + QRect subControlRect(const QString &subcontrolString) const; + +Q_SIGNALS: + void styleChanged(); + +private: + AnimWidget m_dummywidget; + QWidget *m_menu; + QStyleItem *m_style; +}; + +#endif //STYLEWRAPPER_H diff --git a/components/styleitem/qstyleplugin.cpp b/components/styleitem/qstyleplugin.cpp new file mode 100644 index 000000000..05cb45c56 --- /dev/null +++ b/components/styleitem/qstyleplugin.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** 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 Nokia Corporation 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 <qdeclarative.h> +#include "qstyleplugin.h" +#include "qstyleitem.h" + +#include <qdeclarativeextensionplugin.h> + +#include <qdeclarativeengine.h> +#include <qdeclarative.h> +#include <qdeclarativeitem.h> +#include <qdeclarativeimageprovider.h> +#include <qdeclarativeview.h> +#include <QApplication> +#include <QImage> + +// Load icons from desktop theme +class DesktopIconProvider : public QDeclarativeImageProvider +{ +public: + DesktopIconProvider() + : QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap) + { + } + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) + { + int pos = id.lastIndexOf('/'); + QString iconName = id.right(id.length() - pos); + int width = qApp->style()->pixelMetric(QStyle::PM_ToolBarIconSize); + return QIcon::fromTheme(iconName).pixmap(width); + } +}; + +void StylePlugin::registerTypes(const char *uri) +{ + qmlRegisterType<QStyleItem>(uri, 1, 0, "QStyleItem"); + qmlRegisterType<QStyleBackground>(uri, 1, 0, "QStyleBackground"); +} + +void StylePlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) +{ + engine->addImageProvider("desktoptheme", new DesktopIconProvider); +} + +Q_EXPORT_PLUGIN2(styleplugin, StylePlugin); diff --git a/components/styleitem/qstyleplugin.h b/components/styleitem/qstyleplugin.h new file mode 100644 index 000000000..45aff70f7 --- /dev/null +++ b/components/styleitem/qstyleplugin.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** 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 Nokia Corporation 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 <QDeclarativeExtensionPlugin> +#include <QtScript/QScriptValue> +#include <QtCore/QTimer> + +class StylePlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + void registerTypes(const char *uri); + void initializeEngine(QDeclarativeEngine *engine, const char *uri); +}; + +#endif // STYLEPLUGIN_H diff --git a/components/styleitem/styleitem.pro b/components/styleitem/styleitem.pro new file mode 100644 index 000000000..b254cd1eb --- /dev/null +++ b/components/styleitem/styleitem.pro @@ -0,0 +1,38 @@ +TEMPLATE = lib +CONFIG += qt plugin +QT += declarative +QT += script + +TARGET = styleplugin + +DESTDIR = ..\\plugin +OBJECTS_DIR = tmp +MOC_DIR = tmp + +HEADERS += qstyleplugin.h \ + qstyleitem.h + +SOURCES += qstyleplugin.cpp \ + qstyleitem.cpp + + +OTHER_FILES += \ + ../widgets/Button.qml \ + ../widgets/CheckBox.qml \ + ../widgets/ChoiceList.qml \ + ../widgets/GroupBox.qml \ + ../widgets/ProgressBar.qml \ + ../widgets/RadioButton.qml \ + ../widgets/ScrollArea.qml \ + ../widgets/ScrollBar.qml \ + ../widgets/Slider.qml \ + ../widgets/SpinBox.qml \ + ../widgets/Switch.qml \ + ../widgets/TextArea.qml \ + ../widgets/TextField.qml \ + ../widgets/ToolBar.qml \ + ../widgets/ToolButton.qml \ + ../gallery.qml \ + ../widgets/Tab.qml \ + ../widgets/TabBar.qml \ + ../widgets/TabFrame.qml diff --git a/src/Button.qml b/src/Button.qml new file mode 100644 index 000000000..496d37df2 --- /dev/null +++ b/src/Button.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + + property int buttonHeight: Math.max(22, styleitem.sizeFromContents(100, 6).height) + height: buttonHeight + + QStyleItem { + id:styleitem + elementType:"button" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:button.enabled + text:button.text + } + + background: + QStyleBackground { + style:styleitem + anchors.fill:parent + } +} + diff --git a/src/ButtonRow.qml b/src/ButtonRow.qml new file mode 100644 index 000000000..623c5f442 --- /dev/null +++ b/src/ButtonRow.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 +import "../../../components" as Components + +Components.ButtonRow { +} diff --git a/src/CheckBox.qml b/src/CheckBox.qml new file mode 100644 index 000000000..632dce2d4 --- /dev/null +++ b/src/CheckBox.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.CheckBox{ + id:checkbox + property variant text + width:100 + height:18 + + background: QStyleBackground { + id:styleitem + style:QStyleItem { + elementType:"checkbox" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:checkbox.text + enabled:checkbox.enabled + } + } + checkmark: null +} + diff --git a/src/ChoiceList.qml b/src/ChoiceList.qml new file mode 100644 index 000000000..5015fbefb --- /dev/null +++ b/src/ChoiceList.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ChoiceList { + id:choicelist + + property int buttonHeight: buttonitem.sizeFromContents(100, 18).height + QStyleItem { id:buttonitem; elementType:"combobox" } + height: buttonHeight + topMargin:4 + bottomMargin:4 + + QStyleItem { + id:styleitem + elementType: "combobox" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:choicelist.enabled + } + + background: QStyleBackground { + anchors.fill:parent + style: styleitem + } + + listItem: Item { + id:item + + height:22 + anchors.left:parent.left + width:choicelist.width + QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "menuitem" + text: choicelist.model.get(index).text + selected: highlighted + } + } + } + + popupFrame: QStyleBackground { + property int fw: styleitem.pixelMetric("menupanelwidth"); + anchors.leftMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.rightMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.topMargin: styleitem.pixelMetric("menuvmargin") + fw + anchors.bottomMargin: styleitem.pixelMetric("menuvmargin") + fw + style:QStyleItem{elementType:"menu"} + } +} diff --git a/src/GroupBox.qml b/src/GroupBox.qml new file mode 100644 index 000000000..0d45810d1 --- /dev/null +++ b/src/GroupBox.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item { + width:200 + height:46 + + property alias text: styleitem.text + default property alias children: content.children + property bool checkable: false + + QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + id:styleitem + elementType:"groupbox" + } + + Item { + id:content + anchors.topMargin:22 + anchors.leftMargin:6 + anchors.fill:parent + } + } +} diff --git a/src/ProgressBar.qml b/src/ProgressBar.qml new file mode 100644 index 000000000..bf29bcac9 --- /dev/null +++ b/src/ProgressBar.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ProgressBar { + id:progressbar + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + background: QStyleBackground{ + anchors.fill:parent + style: QStyleItem { + elementType:"progressbar" + + // XXX: since desktop uses int instead of real, the progressbar + // range [0..1] must be stretched to a good precision + property int factor : 1000000 + + value: progressbar.value * factor + minimum: indeterminate ? 0 : progressbar.minimumValue * factor + maximum: indeterminate ? 0 : progressbar.maximumValue * factor + enabled: progressbar.enabled + } + } + indeterminateProgress:null + progress: null +} + diff --git a/src/RadioButton.qml b/src/RadioButton.qml new file mode 100644 index 000000000..3c2c3e547 --- /dev/null +++ b/src/RadioButton.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.RadioButton{ + id:radiobutton + property variant text + width:110 + height:18 + + background: QStyleBackground { + + style: QStyleItem{ + elementType:"radiobutton" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:radiobutton.text + enabled:radiobutton.enabled + } + } + checkmark: null +} + diff --git a/src/ScrollArea.qml b/src/ScrollArea.qml new file mode 100644 index 000000000..3a904ddeb --- /dev/null +++ b/src/ScrollArea.qml @@ -0,0 +1,103 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +FocusScope { + id:scrollarea + width: 100 + height: 100 + + property int contentMargin: 1 + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + property int frameWidth: styleitem.pixelMetric("defaultframewidth"); + property int contentHeight : content.childrenRect.height + property int contentWidth: content.childrenRect.width + property alias color: flickable.color + property bool frame: true + property bool highlightOnFocus: false + + default property alias children: content.children + + property int contentY + property int contentX + + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + + onContentYChanged: { + vscrollbar.value = contentY + } + + onContentXChanged: { + hscrollbar.value = contentX + } + + QStyleBackground { + style: QStyleItem{ + id:styleitem + elementType: frame ? "frame" : "" + sunken: true + } + anchors.fill: parent + anchors.rightMargin: (frameAroundContents && vscrollbar.visible) ? vscrollbar.width + 4 : -frameWidth + anchors.bottomMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + anchors.topMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + + Rectangle { + id:flickable + color: "transparent" + anchors.fill: parent + anchors.margins: frame ? 2 : 0 + clip: true + + Item { + id: docmargins + anchors.fill:parent + anchors.margins:contentMargin + Item { + id: content + x: -scrollarea.contentX + y: -scrollarea.contentY + } + } + } + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + visible: contentWidth > flickable.width + maximumValue: contentWidth > flickable.width ? scrollarea.contentWidth - flickable.width : 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: { return (frame ? 1 : 0) + ( vscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentX = value + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + visible: contentHeight > flickable.height + maximumValue: contentHeight > flickable.height ? scrollarea.contentHeight - flickable.height : 0 + minimumValue: 0 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: { return (frame ? 1 : 0) + (hscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentY = value + } + + QStyleBackground { + z:2 + anchors.fill:parent + anchors.margins:-2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } +} diff --git a/src/ScrollBar.qml b/src/ScrollBar.qml new file mode 100644 index 000000000..ea822b62e --- /dev/null +++ b/src/ScrollBar.qml @@ -0,0 +1,109 @@ +import QtQuick 1.1 +import "../../../components" as Components +import "../plugin" + +MouseArea { + id:scrollbar + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + implicitWidth:orientation == Qt.Horizontal ? 200 : __scrollbarExtent; + implicitHeight:orientation == Qt.Horizontal ? __scrollbarExtent : 200 + + property int orientation : Qt.Horizontal + property alias minimumValue: slider.minimumValue + property alias maximumValue: slider.maximumValue + property alias value: slider.value + + property bool upPressed; + property bool downPressed; + property bool __autoincrement: false + + // Update hover item + onEntered: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + onExited: styleitem.activeControl = "none" + onMouseXChanged: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + hoverEnabled:true + + Timer { running: upPressed || downPressed; interval: 350 ; onTriggered: __autoincrement = true } + Timer { running: __autoincrement; interval: 60 ; repeat: true ; + onTriggered: upPressed ? decrement() : increment() } + + onPressed: { + var control = bgitem.hitTest(mouseX,mouseY) + if (control == "up") { + upPressed = true + } else if (control == "down") { + downPressed = true + } + } + + onReleased: { + __autoincrement = false; + if (upPressed) { + upPressed = false; + decrement() + } else if (downPressed) { + increment() + downPressed = false; + } + } + + function increment() { + value += 30 + if (value > maximumValue) + value = maximumValue + } + + function decrement() { + value -= 30 + if (value < minimumValue) + value = minimumValue + } + + QStyleBackground { + id:bgitem + anchors.fill:parent + style: QStyleItem { + id:styleitem + elementType: "scrollbar" + hover: activeControl != "none" + activeControl: "none" + sunken: upPressed | downPressed + minimum: slider.minimumValue + maximum: slider.maximumValue + value: slider.value + horizontal: orientation == Qt.Horizontal + enabled: parent.enabled + } + } + + property variant handleRect + function updateHandle() { + handleRect = bgitem.subControlRect("handle") + var grooveRect = bgitem.subControlRect("groove"); + var extra = 0 + if (orientation == Qt.Vertical) { + slider.anchors.topMargin = grooveRect.y + extra + slider.anchors.bottomMargin = height - grooveRect.y - grooveRect.height + extra + } else { + slider.anchors.leftMargin = grooveRect.x + extra + slider.anchors.rightMargin = width - grooveRect.x - grooveRect.width + extra + } + } + + onValueChanged: updateHandle() + onMaximumValueChanged: updateHandle() + onMinimumValueChanged: updateHandle() + Component.onCompleted: updateHandle() + Components.Slider { + id:slider + anchors.fill:parent + orientation:scrollbar.orientation + leftMargin: (orientation === Qt.Horizontal) ? handleRect.width/2 : handleRect.height/2 + rightMargin:leftMargin + handle: Item { width:orientation == Qt.Vertical ? handleRect.height : handleRect.width; + height:orientation == Qt.Vertical ? handleRect.width : handleRect.height} + groove:null + valueIndicator:null + inverted:orientation != Qt.Horizontal + } +} diff --git a/src/Slider.qml b/src/Slider.qml new file mode 100644 index 000000000..c6b9c9151 --- /dev/null +++ b/src/Slider.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jens: ContainsMouse breaks drag functionality + +Components.Slider{ + id:slider + minimumWidth:200 + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + groove: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"slider" + sunken: pressed + maximum:slider.maximumValue + minimum:slider.minimumValue + value:slider.value + horizontal:slider.orientation == Qt.Horizontal + enabled:slider.enabled + } + } + + handle: null + valueIndicator: null +} diff --git a/src/SpinBox.qml b/src/SpinBox.qml new file mode 100644 index 000000000..2db428cef --- /dev/null +++ b/src/SpinBox.qml @@ -0,0 +1,91 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.SpinBox { + id:spinbox + + property variant __upRect; + property variant __downRect; + property int __margin: (height -16)/2 + + // Align height with button + topMargin:__margin + bottomMargin:__margin + + property int buttonHeight: edititem.sizeFromContents(100, 20).height + QStyleItem { id:edititem; elementType:"edit" } + height: buttonHeight + clip:false + + background: + Item { + anchors.fill: parent + property variant __editRect + + Rectangle { + id:editBackground + x: __editRect.x - 1 + y: __editRect.y + width: __editRect.width + height: __editRect.height + } + + Item { + id:focusFrame + anchors.fill: editBackground + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -6 + anchors.leftMargin: -5 + anchors.fill: parent + visible:spinbox.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } + + function updateRect() { + __upRect = spinboxbg.subControlRect("up"); + __downRect = spinboxbg.subControlRect("down"); + __editRect = spinboxbg.subControlRect("edit"); + } + + Component.onCompleted:updateRect() + onWidthChanged:updateRect() + onHeightChanged:updateRect() + + QStyleBackground { + id:spinboxbg + anchors.fill:parent + style: QStyleItem { + id: styleitem + elementType: "spinbox" + sunken: downPressed | upPressed + hover: containsMouse + focus: spinbox.activeFocus + enabled: spinbox.enabled + value: (upPressed? 1 : 0) | + (downPressed== 1 ? 1<<1 : 0) | + (upEnabled? (1<<2) : 0) | + (downEnabled == 1 ? (1<<3) : 0) + } + } + } + + up: Item { + x: __upRect.x + y: __upRect.y + width: __upRect.width + height: __upRect.height + } + + down: Item { + x: __downRect.x + y: __downRect.y + width: __downRect.width + height: __downRect.height + } +} diff --git a/src/Switch.qml b/src/Switch.qml new file mode 100644 index 000000000..b82817c9f --- /dev/null +++ b/src/Switch.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Switch { + id:widget + minimumWidth:100 + minimumHeight:30 + + groove:QStyleItem { + elementType:"edit" + sunken: true + } + + handle: QStyleItem { + elementType:"button" + width:widget.width/2 + height:widget.height-4 + hover:containsMouse + } +} + diff --git a/src/Tab.qml b/src/Tab.qml new file mode 100644 index 000000000..e258185ba --- /dev/null +++ b/src/Tab.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id:tab + anchors.fill:parent + property string title +} diff --git a/src/TabBar.qml b/src/TabBar.qml new file mode 100644 index 000000000..2d891256f --- /dev/null +++ b/src/TabBar.qml @@ -0,0 +1,90 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + + +Item { + id: tabbar + property int tabHeight: styleitem.sizeFromContents(100, 24).height + height: tabHeight + + property Item tabFrame + onTabFrameChanged:parent = tabFrame + visible: tabFrame ? tabFrame.tabsVisible : true + property int __overlap : styleitem.pixelMetric("tabvshift"); + property string position: tabFrame ? tabFrame.position : "North" + property string tabBarAlignment: styleitem.styleHint("tabbaralignment"); + property int tabOverlap: styleitem.pixelMetric("taboverlap"); + + function tab(index) { + for (var i = 0; i < tabrow.children.length; ++i) { + if (tabrow.children[i].tabindex == index) { + return tabrow.children[i] + } + } + return null; + } + + QStyleItem { + id:styleitem + elementType: "tab" + text: "generic" + } + + Row { + id:tabrow + states: + State { + when: tabBarAlignment == "center" + name: "centered" + AnchorChanges { + target:tabrow + anchors.horizontalCenter: tabbar.horizontalCenter + } + } + Repeater { + id:repeater + model: tabFrame ? tabFrame.tabs.length : null + delegate: Item { + id:tab + property int tabindex: index + property bool selected : tabFrame.current == index + width: textitem.width + 42 + height: tabHeight + z: selected ? 1 : -1 + + QStyleBackground { + style: QStyleItem { + id:style + elementType: "tab" + selected: tab.selected + text: tabbar.position + + activeControl: tabFrame.count == 1 ? + "only" : + index == 0 ? "beginning" : + index == tabFrame.count-1 ? "end" : "middle" + } + anchors.leftMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "end") + && tab.selected ? -__overlap : 0) + + anchors.rightMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "beginning") + && tab.selected ? -__overlap : 0) + anchors.fill:parent + } + + Text { + id:textitem + anchors.centerIn:parent + text: tabFrame.tabs[index].title + elide: Text.ElideRight + } + + MouseArea { + anchors.fill: parent + onPressed: tabFrame.current = index + } + } + } + } +} diff --git a/src/TabFrame.qml b/src/TabFrame.qml new file mode 100644 index 000000000..01896e753 --- /dev/null +++ b/src/TabFrame.qml @@ -0,0 +1,72 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item{ + id: tabWidget + width:100 + height:100 + property TabBar tabbar + 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 + + onCurrentChanged: __setOpacities() + Component.onCompleted: __setOpacities() + onTabbarChanged: { + tabbar.tabFrame = tabWidget + tabbar.anchors.top = tabWidget.top + tabbar.anchors.left = tabWidget.left + tabbar.anchors.right = tabWidget.right + } + + property int __baseOverlap : style.pixelMetric("tabbaseoverlap"); + function __setOpacities() { + for (var i = 0; i < stack.children.length; ++i) { + stack.children[i].opacity = (i == current ? 1 : 0) + } + } + + QStyleBackground { + id: frame + z:-1 + style: QStyleItem { + id:style + elementType: "tabframe" + text: position + value: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).x : 0 + minimum: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).width : 0 + } + anchors.fill:parent + Item { + id:stack + anchors.fill:parent + anchors.margins: frame ? 2 : 0 + } + anchors.topMargin: tabbar && tabsVisible && position == "North" ? tabbar.height - __baseOverlap : 0 + + states: [ + State { + name: "South" + when: position == "South" && tabbar!= undefined + PropertyChanges { + target: frame + anchors.topMargin: 0 + anchors.bottomMargin: tabbar ? tabbar.height - __baseOverlap: 0 + } + PropertyChanges { + target: tabbar + anchors.topMargin: -__baseOverlap + } + AnchorChanges { + target: tabbar + anchors.top: frame.bottom + anchors.bottom: undefined + } + } + ] + } +} diff --git a/src/TextArea.qml b/src/TextArea.qml new file mode 100644 index 000000000..93ad8f3d9 --- /dev/null +++ b/src/TextArea.qml @@ -0,0 +1,44 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextArea { + id:textarea + leftMargin:12 + rightMargin:12 + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + clip:false + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 14).height + QStyleItem { id:buttonitem; elementType:"button" } + minimumHeight: buttonHeight + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textarea.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textarea + parent:textarea.parent + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textarea.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/src/TextField.qml b/src/TextField.qml new file mode 100644 index 000000000..260584e95 --- /dev/null +++ b/src/TextField.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextField { + id:textfield + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + topMargin:2 + bottomMargin:2 + leftMargin:6 + rightMargin:6 + width:200 + height: editItem.sizeFromContents(100, 20).height + clip:false + + QStyleItem { + id:editItem + elementType:"edit" + sunken:true + focus:textfield.activeFocus + hover:containsMouse + } + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textfield.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textfield + parent:textfield + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textfield.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/src/TextScrollArea.qml b/src/TextScrollArea.qml new file mode 100644 index 000000000..2a7deab68 --- /dev/null +++ b/src/TextScrollArea.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +ScrollArea { + id:area + color: "white" + width: 280 + height: 120 + contentWidth: 200 + + property alias text: edit.text + property alias wrapMode: edit.wrapMode + highlightOnFocus: true + + TextEdit { + id: edit + text: loremIpsum + loremIpsum; + wrapMode: TextEdit.WordWrap; + width: area.contentWidth + selectByMouse:true + + // keep textcursor within scrollarea + onCursorRectangleChanged: + if (cursorRectangle.y >= area.contentY + area.height - 1.5*cursorRectangle.height) + area.contentY = cursorRectangle.y - area.height + 1.5*cursorRectangle.height + else if (cursorRectangle.y < area.contentY) + area.contentY = cursorRectangle.y + + } +} diff --git a/src/ToolBar.qml b/src/ToolBar.qml new file mode 100644 index 000000000..ce61382ee --- /dev/null +++ b/src/ToolBar.qml @@ -0,0 +1,12 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +QStyleBackground { + id:styleitem + width:200 + height:60 + + style: QStyleItem{elementType:"toolbar"} +} + diff --git a/src/ToolButton.qml b/src/ToolButton.qml new file mode 100644 index 000000000..98b2dfebf --- /dev/null +++ b/src/ToolButton.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + minimumWidth:30 + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "toolbutton" + on: pressed | checked + sunken: pressed + raised: containsMouse + hover: containsMouse + } + } +} diff --git a/src/components/ButtonGroup.js b/src/components/ButtonGroup.js new file mode 100644 index 000000000..f2d000029 --- /dev/null +++ b/src/components/ButtonGroup.js @@ -0,0 +1,127 @@ +var self; +var clickHandlers = []; +var visibleButtons = []; +var nonVisibleButtons = []; +var direction; +var exclusive; + +function create(that, options) { + self = that; + direction = options.direction || Qt.Horizontal; + exclusive = self.exclusive|| options.exclusive; + self.childrenChanged.connect(rebuild); +// self.widthChanged.connect(resizeChildren); + build(); +} + +function isButton(item) { + if (item && item["__position"] !== undefined) + return true; + return false; +} + +function hasChecked(item) { + if (item && item["checked"] !== undefined) + return true; + return false; +} + +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 (!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 (exclusive && hasChecked(item)) { + if (item["checkable"]!==undefined) { + item.checkable = true; + } + clickHandlers[i] = checkExclusive(item); + item.clicked.connect(clickHandlers[i]); + } + } + + if (self.checkedButton && !self.checkedButton.visible) + self.checkedButton = undefined; + + var nrButtons = visibleButtons.length; + if (nrButtons == 0) + return; + + 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 + button.anchors.right = self.right + } + } +} + +function cleanup() { + visibleButtons.forEach(function(item, i) { + if (clickHandlers[i]) + item.clicked.disconnect(clickHandlers[i]); + item.visibleChanged.disconnect(rebuild); + }); + clickHandlers = []; + + nonVisibleButtons.forEach(function(item, i) { + item.visibleChanged.disconnect(rebuild); + }); +} + +function rebuild() { + 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++) { + ref.checked = button === ref; + } + self.checkedButton = button; + } +} diff --git a/src/components/components.pro b/src/components/components.pro new file mode 100644 index 000000000..be0663d70 --- /dev/null +++ b/src/components/components.pro @@ -0,0 +1,49 @@ +TEMPLATE = subdirs # XXX: Avoid call the linker +TARGETPATH = Qt/labs/components/custom + +symbian { + INSTALL_IMPORTS = /resource/qt/imports +} else { + INSTALL_IMPORTS = $$[QT_INSTALL_IMPORTS] +} + +QML_FILES = \ + qmldir \ + BasicButton.qml \ + BusyIndicator.qml \ + ButtonBlock.qml \ + ButtonColumn.qml \ + ButtonRow.qml \ + ButtonGroup.js \ + Button.qml \ + CheckBox.qml \ + ChoiceList.qml \ + ProgressBar.qml \ + RadioButton.qml \ + ScrollDecorator.qml \ + ScrollIndicator.qml \ + Slider.qml \ + SpinBox.qml \ + Switch.qml \ + TextArea.qml \ + TextField.qml + +QML_DIRS = \ + behaviors \ + private \ + styles \ + visuals + +qmlfiles.files = $$QML_FILES +qmlfiles.sources = $$QML_FILES +qmlfiles.path = $$INSTALL_IMPORTS/$$TARGETPATH + +qmldirs.files = $$QML_DIRS +qmldirs.sources = $$QML_DIRS +qmldirs.path = $$INSTALL_IMPORTS/$$TARGETPATH + +INSTALLS += qmlfiles qmldirs + +symbian { + DEPLOYMENT += qmlfiles qmldirs +} diff --git a/src/components/qmldir b/src/components/qmldir new file mode 100644 index 000000000..6e256a81d --- /dev/null +++ b/src/components/qmldir @@ -0,0 +1,17 @@ +BasicButton 1.0 BasicButton.qml +BusyIndicator 1.0 BusyIndicator.qml +ButtonBlock 1.0 ButtonBlock.qml +Button 1.0 Button.qml +ButtonColumn 1.0 ButtonColumn.qml +ButtonRow 1.0 ButtonRow.qml +CheckBox 1.0 CheckBox.qml +ChoiceList 1.0 ChoiceList.qml +ProgressBar 1.0 ProgressBar.qml +RadioButton 1.0 RadioButton.qml +ScrollDecorator 1.0 ScrollDecorator.qml +ScrollIndicator 1.0 ScrollIndicator.qml +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +Switch 1.0 Switch.qml +TextArea 1.0 TextArea.qml +TextField 1.0 TextField.qml diff --git a/src/images/folder_new.png b/src/images/folder_new.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8bb9bd768d8e8ab785d95483ead02ae6800dc5 GIT binary patch literal 1199 zcmV;g1W@~lP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H101k9TSaeirbZlh+MsI9nWpZ;NRH|S>0000NbVXQnL3MO!Z*l-k zVQ_CCLt$)TZDDR?a%E}Xks2xh001d;MObu1WpiV4X>fFDZ*BlWVRL0<Aa7<MN?~ht zVjxp=Wod3@av)@7b7^O8po9f;000BJNkl<ZNQteLO^6&t6vuznRnt8)&TMwwuc%3g z2L+Xg#E;-dLX;fTm|zS9BAz685^_-q9uyG|f}n_a(2IhCBC^TJQ#K*NgBpV$m_(v6 zF_>g`c6MfW=cA{)s-B0L%+9*2hHM@b)l|QFzxV#Hs#}Q&%d^*l_WY_}>aDt3Kzece zdac!cscYUPuC`9W*HJk92_px7S~kFycI-lAJK{H5*Ic8E&yrT&@tI8VfYQZJ^~l(l zmwip|#uxVO*{fCXra&~m+D)M1J<q-M(o_YJ-N2KO!4!9)i@N~{((3y=LS69o(vGrO zId*svK%9I1q0Ns(S_gRVJHz3<CyrYKCr=*#c)D6YRLJYc6$)i;#1wY6Gc7ztQu%<| z%y&DLl1=G}{I<c{8{aGdSnG2joc`^XMY0r&{j9rVbuJV9ywwc6OOU;Hp@YhjUvn5_ zmSlGSu)Fa5e&B{+0l-;iW~wBuWYH*3O%mybvOb5M`wVbPbq9Q%v^M5~Aos%}iJWyz zPnT&lnhUmh??_V18P(#pwbv7wBlyxQWQX7A(KiM^NB!bn;@KZtgZ+2Eya-^er8GH7 zlC*j|g9-v3-n@mitA`mX97b^#d=1<bC_pSCF-RR`hQG?I@|iw=uCEvH;=Vmk_YbTv z^=7?SSd7u!zu^H^j*c=>Dx=aIqXmef0C9hk*2YO{UlA4_C6ix|QhDZT75Y{knO;zV zv+nIDwr*o+Xk<RT0tAvIrcx~-;+dSeiBNA~Me-5N@`spkluS5CYx+HE6D1(W!Ed+l z;A8C=T|gYSMuNaIIeC7G=JoW+8O}}J!${vsiuq|GV&Vj1n`bT_pe1)QG4*-ZzYDO| z5=A+jv;PSIur9}i$}L25F=3`HX`JRsZH}R#eyp88Ve^30k;@fGlK6iC-D=3tOpEiu z3}|hzc0S22AnjCOOy-IKOPPqrrb_^9>IedjUM9eK|1T0*i-^A_6{Jg5fY7Kn>iICt z0`2?LKBu5iorT^=AeX<i(tZ*V>h&5TG%mXZ?KsMa$kgwrf2GxI;;lnGC<)NYV01`m za%95-+3-3-lf~!|tqgdDcY;eT&3cV<f1E+Ql$25iz$m2@5LK(QhsMXppV_!^MhC$^ z)4eit&U5tW_pVy49t0w#lrtSQ^zq{-zHrWOI)DDs%~ut@W6fss?6G5~#sE!6WCeu4 zAaHAEUXE3OQ$QI=l!%~|3TQVxL#HpxFb|}F6%pV4>34c@%}hFh{|2rA&Q3Ns=Tray N002ovPDHLkV1nxxBC7xZ literal 0 HcmV?d00001 diff --git a/src/plugin/qmldir b/src/plugin/qmldir new file mode 100644 index 000000000..e8452efd6 --- /dev/null +++ b/src/plugin/qmldir @@ -0,0 +1 @@ +plugin styleplugin diff --git a/src/styleitem/styleitem.pro b/src/styleitem/styleitem.pro new file mode 100644 index 000000000..b254cd1eb --- /dev/null +++ b/src/styleitem/styleitem.pro @@ -0,0 +1,38 @@ +TEMPLATE = lib +CONFIG += qt plugin +QT += declarative +QT += script + +TARGET = styleplugin + +DESTDIR = ..\\plugin +OBJECTS_DIR = tmp +MOC_DIR = tmp + +HEADERS += qstyleplugin.h \ + qstyleitem.h + +SOURCES += qstyleplugin.cpp \ + qstyleitem.cpp + + +OTHER_FILES += \ + ../widgets/Button.qml \ + ../widgets/CheckBox.qml \ + ../widgets/ChoiceList.qml \ + ../widgets/GroupBox.qml \ + ../widgets/ProgressBar.qml \ + ../widgets/RadioButton.qml \ + ../widgets/ScrollArea.qml \ + ../widgets/ScrollBar.qml \ + ../widgets/Slider.qml \ + ../widgets/SpinBox.qml \ + ../widgets/Switch.qml \ + ../widgets/TextArea.qml \ + ../widgets/TextField.qml \ + ../widgets/ToolBar.qml \ + ../widgets/ToolButton.qml \ + ../gallery.qml \ + ../widgets/Tab.qml \ + ../widgets/TabBar.qml \ + ../widgets/TabFrame.qml diff --git a/src/widgets/Button.qml b/src/widgets/Button.qml new file mode 100644 index 000000000..496d37df2 --- /dev/null +++ b/src/widgets/Button.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + + property int buttonHeight: Math.max(22, styleitem.sizeFromContents(100, 6).height) + height: buttonHeight + + QStyleItem { + id:styleitem + elementType:"button" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:button.enabled + text:button.text + } + + background: + QStyleBackground { + style:styleitem + anchors.fill:parent + } +} + diff --git a/src/widgets/ButtonRow.qml b/src/widgets/ButtonRow.qml new file mode 100644 index 000000000..623c5f442 --- /dev/null +++ b/src/widgets/ButtonRow.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 +import "../../../components" as Components + +Components.ButtonRow { +} diff --git a/src/widgets/CheckBox.qml b/src/widgets/CheckBox.qml new file mode 100644 index 000000000..632dce2d4 --- /dev/null +++ b/src/widgets/CheckBox.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.CheckBox{ + id:checkbox + property variant text + width:100 + height:18 + + background: QStyleBackground { + id:styleitem + style:QStyleItem { + elementType:"checkbox" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:checkbox.text + enabled:checkbox.enabled + } + } + checkmark: null +} + diff --git a/src/widgets/ChoiceList.qml b/src/widgets/ChoiceList.qml new file mode 100644 index 000000000..5015fbefb --- /dev/null +++ b/src/widgets/ChoiceList.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ChoiceList { + id:choicelist + + property int buttonHeight: buttonitem.sizeFromContents(100, 18).height + QStyleItem { id:buttonitem; elementType:"combobox" } + height: buttonHeight + topMargin:4 + bottomMargin:4 + + QStyleItem { + id:styleitem + elementType: "combobox" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled:choicelist.enabled + } + + background: QStyleBackground { + anchors.fill:parent + style: styleitem + } + + listItem: Item { + id:item + + height:22 + anchors.left:parent.left + width:choicelist.width + QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "menuitem" + text: choicelist.model.get(index).text + selected: highlighted + } + } + } + + popupFrame: QStyleBackground { + property int fw: styleitem.pixelMetric("menupanelwidth"); + anchors.leftMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.rightMargin: styleitem.pixelMetric("menuhmargin") + fw + anchors.topMargin: styleitem.pixelMetric("menuvmargin") + fw + anchors.bottomMargin: styleitem.pixelMetric("menuvmargin") + fw + style:QStyleItem{elementType:"menu"} + } +} diff --git a/src/widgets/GroupBox.qml b/src/widgets/GroupBox.qml new file mode 100644 index 000000000..0d45810d1 --- /dev/null +++ b/src/widgets/GroupBox.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item { + width:200 + height:46 + + property alias text: styleitem.text + default property alias children: content.children + property bool checkable: false + + QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + id:styleitem + elementType:"groupbox" + } + + Item { + id:content + anchors.topMargin:22 + anchors.leftMargin:6 + anchors.fill:parent + } + } +} diff --git a/src/widgets/ProgressBar.qml b/src/widgets/ProgressBar.qml new file mode 100644 index 000000000..bf29bcac9 --- /dev/null +++ b/src/widgets/ProgressBar.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.ProgressBar { + id:progressbar + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + background: QStyleBackground{ + anchors.fill:parent + style: QStyleItem { + elementType:"progressbar" + + // XXX: since desktop uses int instead of real, the progressbar + // range [0..1] must be stretched to a good precision + property int factor : 1000000 + + value: progressbar.value * factor + minimum: indeterminate ? 0 : progressbar.minimumValue * factor + maximum: indeterminate ? 0 : progressbar.maximumValue * factor + enabled: progressbar.enabled + } + } + indeterminateProgress:null + progress: null +} + diff --git a/src/widgets/RadioButton.qml b/src/widgets/RadioButton.qml new file mode 100644 index 000000000..3c2c3e547 --- /dev/null +++ b/src/widgets/RadioButton.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.RadioButton{ + id:radiobutton + property variant text + width:110 + height:18 + + background: QStyleBackground { + + style: QStyleItem{ + elementType:"radiobutton" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:radiobutton.text + enabled:radiobutton.enabled + } + } + checkmark: null +} + diff --git a/src/widgets/ScrollArea.qml b/src/widgets/ScrollArea.qml new file mode 100644 index 000000000..3a904ddeb --- /dev/null +++ b/src/widgets/ScrollArea.qml @@ -0,0 +1,103 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +FocusScope { + id:scrollarea + width: 100 + height: 100 + + property int contentMargin: 1 + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + property int frameWidth: styleitem.pixelMetric("defaultframewidth"); + property int contentHeight : content.childrenRect.height + property int contentWidth: content.childrenRect.width + property alias color: flickable.color + property bool frame: true + property bool highlightOnFocus: false + + default property alias children: content.children + + property int contentY + property int contentX + + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + + onContentYChanged: { + vscrollbar.value = contentY + } + + onContentXChanged: { + hscrollbar.value = contentX + } + + QStyleBackground { + style: QStyleItem{ + id:styleitem + elementType: frame ? "frame" : "" + sunken: true + } + anchors.fill: parent + anchors.rightMargin: (frameAroundContents && vscrollbar.visible) ? vscrollbar.width + 4 : -frameWidth + anchors.bottomMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + anchors.topMargin: (frameAroundContents && hscrollbar.visible) ? hscrollbar.height + 4 : -frameWidth + + Rectangle { + id:flickable + color: "transparent" + anchors.fill: parent + anchors.margins: frame ? 2 : 0 + clip: true + + Item { + id: docmargins + anchors.fill:parent + anchors.margins:contentMargin + Item { + id: content + x: -scrollarea.contentX + y: -scrollarea.contentY + } + } + } + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + visible: contentWidth > flickable.width + maximumValue: contentWidth > flickable.width ? scrollarea.contentWidth - flickable.width : 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: { return (frame ? 1 : 0) + ( vscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentX = value + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + visible: contentHeight > flickable.height + maximumValue: contentHeight > flickable.height ? scrollarea.contentHeight - flickable.height : 0 + minimumValue: 0 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: { return (frame ? 1 : 0) + (hscrollbar.visible ? __scrollbarExtent : 0) } + onValueChanged: contentY = value + } + + QStyleBackground { + z:2 + anchors.fill:parent + anchors.margins:-2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } +} diff --git a/src/widgets/ScrollBar.qml b/src/widgets/ScrollBar.qml new file mode 100644 index 000000000..ea822b62e --- /dev/null +++ b/src/widgets/ScrollBar.qml @@ -0,0 +1,109 @@ +import QtQuick 1.1 +import "../../../components" as Components +import "../plugin" + +MouseArea { + id:scrollbar + property int __scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + implicitWidth:orientation == Qt.Horizontal ? 200 : __scrollbarExtent; + implicitHeight:orientation == Qt.Horizontal ? __scrollbarExtent : 200 + + property int orientation : Qt.Horizontal + property alias minimumValue: slider.minimumValue + property alias maximumValue: slider.maximumValue + property alias value: slider.value + + property bool upPressed; + property bool downPressed; + property bool __autoincrement: false + + // Update hover item + onEntered: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + onExited: styleitem.activeControl = "none" + onMouseXChanged: styleitem.activeControl = bgitem.hitTest(mouseX, mouseY) + hoverEnabled:true + + Timer { running: upPressed || downPressed; interval: 350 ; onTriggered: __autoincrement = true } + Timer { running: __autoincrement; interval: 60 ; repeat: true ; + onTriggered: upPressed ? decrement() : increment() } + + onPressed: { + var control = bgitem.hitTest(mouseX,mouseY) + if (control == "up") { + upPressed = true + } else if (control == "down") { + downPressed = true + } + } + + onReleased: { + __autoincrement = false; + if (upPressed) { + upPressed = false; + decrement() + } else if (downPressed) { + increment() + downPressed = false; + } + } + + function increment() { + value += 30 + if (value > maximumValue) + value = maximumValue + } + + function decrement() { + value -= 30 + if (value < minimumValue) + value = minimumValue + } + + QStyleBackground { + id:bgitem + anchors.fill:parent + style: QStyleItem { + id:styleitem + elementType: "scrollbar" + hover: activeControl != "none" + activeControl: "none" + sunken: upPressed | downPressed + minimum: slider.minimumValue + maximum: slider.maximumValue + value: slider.value + horizontal: orientation == Qt.Horizontal + enabled: parent.enabled + } + } + + property variant handleRect + function updateHandle() { + handleRect = bgitem.subControlRect("handle") + var grooveRect = bgitem.subControlRect("groove"); + var extra = 0 + if (orientation == Qt.Vertical) { + slider.anchors.topMargin = grooveRect.y + extra + slider.anchors.bottomMargin = height - grooveRect.y - grooveRect.height + extra + } else { + slider.anchors.leftMargin = grooveRect.x + extra + slider.anchors.rightMargin = width - grooveRect.x - grooveRect.width + extra + } + } + + onValueChanged: updateHandle() + onMaximumValueChanged: updateHandle() + onMinimumValueChanged: updateHandle() + Component.onCompleted: updateHandle() + Components.Slider { + id:slider + anchors.fill:parent + orientation:scrollbar.orientation + leftMargin: (orientation === Qt.Horizontal) ? handleRect.width/2 : handleRect.height/2 + rightMargin:leftMargin + handle: Item { width:orientation == Qt.Vertical ? handleRect.height : handleRect.width; + height:orientation == Qt.Vertical ? handleRect.width : handleRect.height} + groove:null + valueIndicator:null + inverted:orientation != Qt.Horizontal + } +} diff --git a/src/widgets/Slider.qml b/src/widgets/Slider.qml new file mode 100644 index 000000000..c6b9c9151 --- /dev/null +++ b/src/widgets/Slider.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +// jens: ContainsMouse breaks drag functionality + +Components.Slider{ + id:slider + minimumWidth:200 + + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 15).height + QStyleItem { id:buttonitem; elementType:"button" } + height: buttonHeight + + groove: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"slider" + sunken: pressed + maximum:slider.maximumValue + minimum:slider.minimumValue + value:slider.value + horizontal:slider.orientation == Qt.Horizontal + enabled:slider.enabled + } + } + + handle: null + valueIndicator: null +} diff --git a/src/widgets/SpinBox.qml b/src/widgets/SpinBox.qml new file mode 100644 index 000000000..2db428cef --- /dev/null +++ b/src/widgets/SpinBox.qml @@ -0,0 +1,91 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.SpinBox { + id:spinbox + + property variant __upRect; + property variant __downRect; + property int __margin: (height -16)/2 + + // Align height with button + topMargin:__margin + bottomMargin:__margin + + property int buttonHeight: edititem.sizeFromContents(100, 20).height + QStyleItem { id:edititem; elementType:"edit" } + height: buttonHeight + clip:false + + background: + Item { + anchors.fill: parent + property variant __editRect + + Rectangle { + id:editBackground + x: __editRect.x - 1 + y: __editRect.y + width: __editRect.width + height: __editRect.height + } + + Item { + id:focusFrame + anchors.fill: editBackground + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -6 + anchors.leftMargin: -5 + anchors.fill: parent + visible:spinbox.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } + + function updateRect() { + __upRect = spinboxbg.subControlRect("up"); + __downRect = spinboxbg.subControlRect("down"); + __editRect = spinboxbg.subControlRect("edit"); + } + + Component.onCompleted:updateRect() + onWidthChanged:updateRect() + onHeightChanged:updateRect() + + QStyleBackground { + id:spinboxbg + anchors.fill:parent + style: QStyleItem { + id: styleitem + elementType: "spinbox" + sunken: downPressed | upPressed + hover: containsMouse + focus: spinbox.activeFocus + enabled: spinbox.enabled + value: (upPressed? 1 : 0) | + (downPressed== 1 ? 1<<1 : 0) | + (upEnabled? (1<<2) : 0) | + (downEnabled == 1 ? (1<<3) : 0) + } + } + } + + up: Item { + x: __upRect.x + y: __upRect.y + width: __upRect.width + height: __upRect.height + } + + down: Item { + x: __downRect.x + y: __downRect.y + width: __downRect.width + height: __downRect.height + } +} diff --git a/src/widgets/Switch.qml b/src/widgets/Switch.qml new file mode 100644 index 000000000..b82817c9f --- /dev/null +++ b/src/widgets/Switch.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Switch { + id:widget + minimumWidth:100 + minimumHeight:30 + + groove:QStyleItem { + elementType:"edit" + sunken: true + } + + handle: QStyleItem { + elementType:"button" + width:widget.width/2 + height:widget.height-4 + hover:containsMouse + } +} + diff --git a/src/widgets/Tab.qml b/src/widgets/Tab.qml new file mode 100644 index 000000000..e258185ba --- /dev/null +++ b/src/widgets/Tab.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id:tab + anchors.fill:parent + property string title +} diff --git a/src/widgets/TabBar.qml b/src/widgets/TabBar.qml new file mode 100644 index 000000000..2d891256f --- /dev/null +++ b/src/widgets/TabBar.qml @@ -0,0 +1,90 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + + +Item { + id: tabbar + property int tabHeight: styleitem.sizeFromContents(100, 24).height + height: tabHeight + + property Item tabFrame + onTabFrameChanged:parent = tabFrame + visible: tabFrame ? tabFrame.tabsVisible : true + property int __overlap : styleitem.pixelMetric("tabvshift"); + property string position: tabFrame ? tabFrame.position : "North" + property string tabBarAlignment: styleitem.styleHint("tabbaralignment"); + property int tabOverlap: styleitem.pixelMetric("taboverlap"); + + function tab(index) { + for (var i = 0; i < tabrow.children.length; ++i) { + if (tabrow.children[i].tabindex == index) { + return tabrow.children[i] + } + } + return null; + } + + QStyleItem { + id:styleitem + elementType: "tab" + text: "generic" + } + + Row { + id:tabrow + states: + State { + when: tabBarAlignment == "center" + name: "centered" + AnchorChanges { + target:tabrow + anchors.horizontalCenter: tabbar.horizontalCenter + } + } + Repeater { + id:repeater + model: tabFrame ? tabFrame.tabs.length : null + delegate: Item { + id:tab + property int tabindex: index + property bool selected : tabFrame.current == index + width: textitem.width + 42 + height: tabHeight + z: selected ? 1 : -1 + + QStyleBackground { + style: QStyleItem { + id:style + elementType: "tab" + selected: tab.selected + text: tabbar.position + + activeControl: tabFrame.count == 1 ? + "only" : + index == 0 ? "beginning" : + index == tabFrame.count-1 ? "end" : "middle" + } + anchors.leftMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "end") + && tab.selected ? -__overlap : 0) + + anchors.rightMargin: -tabOverlap + (style.text == "North" && (style.activeControl == "middle" || style.activeControl == "beginning") + && tab.selected ? -__overlap : 0) + anchors.fill:parent + } + + Text { + id:textitem + anchors.centerIn:parent + text: tabFrame.tabs[index].title + elide: Text.ElideRight + } + + MouseArea { + anchors.fill: parent + onPressed: tabFrame.current = index + } + } + } + } +} diff --git a/src/widgets/TabFrame.qml b/src/widgets/TabFrame.qml new file mode 100644 index 000000000..01896e753 --- /dev/null +++ b/src/widgets/TabFrame.qml @@ -0,0 +1,72 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Item{ + id: tabWidget + width:100 + height:100 + property TabBar tabbar + 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 + + onCurrentChanged: __setOpacities() + Component.onCompleted: __setOpacities() + onTabbarChanged: { + tabbar.tabFrame = tabWidget + tabbar.anchors.top = tabWidget.top + tabbar.anchors.left = tabWidget.left + tabbar.anchors.right = tabWidget.right + } + + property int __baseOverlap : style.pixelMetric("tabbaseoverlap"); + function __setOpacities() { + for (var i = 0; i < stack.children.length; ++i) { + stack.children[i].opacity = (i == current ? 1 : 0) + } + } + + QStyleBackground { + id: frame + z:-1 + style: QStyleItem { + id:style + elementType: "tabframe" + text: position + value: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).x : 0 + minimum: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).width : 0 + } + anchors.fill:parent + Item { + id:stack + anchors.fill:parent + anchors.margins: frame ? 2 : 0 + } + anchors.topMargin: tabbar && tabsVisible && position == "North" ? tabbar.height - __baseOverlap : 0 + + states: [ + State { + name: "South" + when: position == "South" && tabbar!= undefined + PropertyChanges { + target: frame + anchors.topMargin: 0 + anchors.bottomMargin: tabbar ? tabbar.height - __baseOverlap: 0 + } + PropertyChanges { + target: tabbar + anchors.topMargin: -__baseOverlap + } + AnchorChanges { + target: tabbar + anchors.top: frame.bottom + anchors.bottom: undefined + } + } + ] + } +} diff --git a/src/widgets/TextArea.qml b/src/widgets/TextArea.qml new file mode 100644 index 000000000..93ad8f3d9 --- /dev/null +++ b/src/widgets/TextArea.qml @@ -0,0 +1,44 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextArea { + id:textarea + leftMargin:12 + rightMargin:12 + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + clip:false + // Align with button + property int buttonHeight: buttonitem.sizeFromContents(100, 14).height + QStyleItem { id:buttonitem; elementType:"button" } + minimumHeight: buttonHeight + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textarea.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textarea + parent:textarea.parent + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textarea.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/src/widgets/TextField.qml b/src/widgets/TextField.qml new file mode 100644 index 000000000..260584e95 --- /dev/null +++ b/src/widgets/TextField.qml @@ -0,0 +1,52 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.TextField { + id:textfield + minimumWidth:200 + desktopBehavior:true + placeholderText:"" + topMargin:2 + bottomMargin:2 + leftMargin:6 + rightMargin:6 + width:200 + height: editItem.sizeFromContents(100, 20).height + clip:false + + QStyleItem { + id:editItem + elementType:"edit" + sunken:true + focus:textfield.activeFocus + hover:containsMouse + } + + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem{ + elementType:"edit" + sunken:true + focus:textfield.activeFocus + } + } + + Item{ + id:focusFrame + anchors.fill: textfield + parent:textfield + visible:framestyle.styleHint("focuswidget") + QStyleBackground{ + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible:textfield.activeFocus + style: QStyleItem { + id:framestyle + elementType:"focusframe" + } + } + } +} diff --git a/src/widgets/TextScrollArea.qml b/src/widgets/TextScrollArea.qml new file mode 100644 index 000000000..2a7deab68 --- /dev/null +++ b/src/widgets/TextScrollArea.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +ScrollArea { + id:area + color: "white" + width: 280 + height: 120 + contentWidth: 200 + + property alias text: edit.text + property alias wrapMode: edit.wrapMode + highlightOnFocus: true + + TextEdit { + id: edit + text: loremIpsum + loremIpsum; + wrapMode: TextEdit.WordWrap; + width: area.contentWidth + selectByMouse:true + + // keep textcursor within scrollarea + onCursorRectangleChanged: + if (cursorRectangle.y >= area.contentY + area.height - 1.5*cursorRectangle.height) + area.contentY = cursorRectangle.y - area.height + 1.5*cursorRectangle.height + else if (cursorRectangle.y < area.contentY) + area.contentY = cursorRectangle.y + + } +} diff --git a/src/widgets/ToolBar.qml b/src/widgets/ToolBar.qml new file mode 100644 index 000000000..ce61382ee --- /dev/null +++ b/src/widgets/ToolBar.qml @@ -0,0 +1,12 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +QStyleBackground { + id:styleitem + width:200 + height:60 + + style: QStyleItem{elementType:"toolbar"} +} + diff --git a/src/widgets/ToolButton.qml b/src/widgets/ToolButton.qml new file mode 100644 index 000000000..98b2dfebf --- /dev/null +++ b/src/widgets/ToolButton.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 +import "../../../components" as Components +import "../plugin" + +Components.Button { + id:button + minimumWidth:30 + background: QStyleBackground { + anchors.fill:parent + style: QStyleItem { + elementType: "toolbutton" + on: pressed | checked + sunken: pressed + raised: containsMouse + hover: containsMouse + } + } +} -- GitLab