ScrollViewStyle.qml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2016 The Qt Company Ltd.
  4. ** Contact: https://www.qt.io/licensing/
  5. **
  6. ** This file is part of the Qt Quick Controls module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and The Qt Company. For licensing terms
  14. ** and conditions see https://www.qt.io/terms-conditions. For further
  15. ** information use the contact form at https://www.qt.io/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 3 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL3 included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 3 requirements
  23. ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
  24. **
  25. ** GNU General Public License Usage
  26. ** Alternatively, this file may be used under the terms of the GNU
  27. ** General Public License version 2.0 or (at your option) the GNU General
  28. ** Public license version 3 or any later version approved by the KDE Free
  29. ** Qt Foundation. The licenses are as published by the Free Software
  30. ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
  31. ** included in the packaging of this file. Please review the following
  32. ** information to ensure the GNU General Public License requirements will
  33. ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
  34. ** https://www.gnu.org/licenses/gpl-3.0.html.
  35. **
  36. ** $QT_END_LICENSE$
  37. **
  38. ****************************************************************************/
  39. import QtQuick 2.2
  40. import QtQuick.Controls 1.2
  41. import QtQuick.Controls.Private 1.0
  42. /*!
  43. \qmltype ScrollViewStyle
  44. \inqmlmodule QtQuick.Controls.Styles
  45. \since 5.1
  46. \ingroup viewsstyling
  47. \ingroup controlsstyling
  48. \brief Provides custom styling for ScrollView.
  49. */
  50. Style {
  51. id: root
  52. /*! The \l ScrollView this style is attached to. */
  53. readonly property ScrollView control: __control
  54. /*! This property controls the frame border padding of the scrollView. */
  55. padding {left: 1; top: 1; right: 1; bottom: 1}
  56. /*! This Component paints the corner area between scroll bars */
  57. property Component corner: Rectangle { color: "#ccc" }
  58. /*! This component determines if the flickable should reposition itself at the
  59. mouse location when clicked. */
  60. property bool scrollToClickedPosition: true
  61. /*! This property holds whether the scroll bars are transient. Transient scroll bars
  62. appear when the content is scrolled and disappear when they are no longer needed.
  63. The default value is platform dependent. */
  64. property bool transientScrollBars: Settings.isMobile && Settings.hasTouchScreen
  65. /*! This Component paints the frame around scroll bars. */
  66. property Component frame: Rectangle {
  67. color: control["backgroundVisible"] ? "white": "transparent"
  68. border.color: "#999"
  69. border.width: 1
  70. radius: 1
  71. visible: control.frameVisible
  72. }
  73. /*! This is the minimum extent of the scroll bar handle.
  74. The default value is \c 30.
  75. */
  76. property int minimumHandleLength: 30
  77. /*! This property controls the edge overlap
  78. between the handle and the increment/decrement buttons.
  79. The default value is \c 30.
  80. */
  81. property int handleOverlap: 1
  82. /*! This component controls the appearance of the
  83. scroll bar background.
  84. You can access the following state properties:
  85. \table
  86. \row \li property bool \b styleData.hovered
  87. \row \li property bool \b styleData.horizontal
  88. \endtable
  89. */
  90. property Component scrollBarBackground: Item {
  91. property bool sticky: false
  92. property bool hovered: styleData.hovered
  93. implicitWidth: Math.round(TextSingleton.implicitHeight)
  94. implicitHeight: Math.round(TextSingleton.implicitHeight)
  95. clip: true
  96. opacity: transientScrollBars ? 0.5 : 1.0
  97. visible: !Settings.hasTouchScreen && (!transientScrollBars || sticky)
  98. Rectangle {
  99. anchors.fill: parent
  100. color: "#ddd"
  101. border.color: "#aaa"
  102. anchors.rightMargin: styleData.horizontal ? -2 : -1
  103. anchors.leftMargin: styleData.horizontal ? -2 : 0
  104. anchors.topMargin: styleData.horizontal ? 0 : -2
  105. anchors.bottomMargin: styleData.horizontal ? -1 : -2
  106. }
  107. onHoveredChanged: if (hovered) sticky = true
  108. onVisibleChanged: if (!visible) sticky = false
  109. }
  110. /*! This component controls the appearance of the
  111. scroll bar handle.
  112. You can access the following state properties:
  113. \table
  114. \row \li property bool \b styleData.hovered
  115. \row \li property bool \b styleData.pressed
  116. \row \li property bool \b styleData.horizontal
  117. \endtable
  118. */
  119. property Component handle: Item {
  120. property bool sticky: false
  121. property bool hovered: __activeControl !== "none"
  122. implicitWidth: Math.round(TextSingleton.implicitHeight) + 1
  123. implicitHeight: Math.round(TextSingleton.implicitHeight) + 1
  124. BorderImage {
  125. id: img
  126. opacity: styleData.pressed && !transientScrollBars ? 0.5 : styleData.hovered ? 1 : 0.8
  127. source: "images/scrollbar-handle-" + (transientScrollBars ? "transient" : styleData.horizontal ? "horizontal" : "vertical") + ".png"
  128. border.left: transientScrollBars ? 5 : 2
  129. border.top: transientScrollBars ? 5 : 2
  130. border.right: transientScrollBars ? 5 : 2
  131. border.bottom: transientScrollBars ? 5 : 2
  132. anchors.top: !styleData.horizontal ? parent.top : undefined
  133. anchors.margins: transientScrollBars ? 2 : 0
  134. anchors.bottom: parent.bottom
  135. anchors.right: parent.right
  136. anchors.left: styleData.horizontal ? parent.left : undefined
  137. width: !styleData.horizontal && transientScrollBars ? sticky ? 13 : 10 : parent.width
  138. height: styleData.horizontal && transientScrollBars ? sticky ? 13 : 10 : parent.height
  139. Behavior on width { enabled: !styleData.horizontal && transientScrollBars; NumberAnimation { duration: 100 } }
  140. Behavior on height { enabled: styleData.horizontal && transientScrollBars; NumberAnimation { duration: 100 } }
  141. }
  142. onHoveredChanged: if (hovered) sticky = true
  143. onVisibleChanged: if (!visible) sticky = false
  144. }
  145. /*! This component controls the appearance of the
  146. scroll bar increment button.
  147. You can access the following state properties:
  148. \table
  149. \row \li property bool \b styleData.hovered
  150. \row \li property bool \b styleData.pressed
  151. \row \li property bool \b styleData.horizontal
  152. \endtable
  153. */
  154. property Component incrementControl: Rectangle {
  155. visible: !transientScrollBars
  156. implicitWidth: transientScrollBars ? 0 : Math.round(TextSingleton.implicitHeight)
  157. implicitHeight: transientScrollBars ? 0 : Math.round(TextSingleton.implicitHeight)
  158. Rectangle {
  159. anchors.fill: parent
  160. anchors.bottomMargin: -1
  161. anchors.rightMargin: -1
  162. border.color: "#aaa"
  163. Rectangle {
  164. anchors.fill: parent
  165. anchors.margins: 1
  166. color: "transparent"
  167. border.color: "#44ffffff"
  168. }
  169. Image {
  170. source: styleData.horizontal ? "images/arrow-right.png" : "images/arrow-down.png"
  171. anchors.centerIn: parent
  172. opacity: control.enabled ? 0.6 : 0.5
  173. }
  174. gradient: Gradient {
  175. GradientStop {color: styleData.pressed ? "lightgray" : "white" ; position: 0}
  176. GradientStop {color: styleData.pressed ? "lightgray" : "lightgray" ; position: 1}
  177. }
  178. }
  179. }
  180. /*! This component controls the appearance of the
  181. scroll bar decrement button.
  182. You can access the following state properties:
  183. \table
  184. \row \li property bool \b styleData.hovered
  185. \row \li property bool \b styleData.pressed
  186. \row \li property bool \b styleData.horizontal
  187. \endtable
  188. */
  189. property Component decrementControl: Rectangle {
  190. visible: !transientScrollBars
  191. implicitWidth: transientScrollBars ? 0 : Math.round(TextSingleton.implicitHeight)
  192. implicitHeight: transientScrollBars ? 0 : Math.round(TextSingleton.implicitHeight)
  193. Rectangle {
  194. anchors.fill: parent
  195. anchors.topMargin: styleData.horizontal ? 0 : -1
  196. anchors.leftMargin: styleData.horizontal ? -1 : 0
  197. anchors.bottomMargin: styleData.horizontal ? -1 : 0
  198. anchors.rightMargin: styleData.horizontal ? 0 : -1
  199. color: "lightgray"
  200. Rectangle {
  201. anchors.fill: parent
  202. anchors.margins: 1
  203. color: "transparent"
  204. border.color: "#44ffffff"
  205. }
  206. Image {
  207. source: styleData.horizontal ? "images/arrow-left.png" : "images/arrow-up.png"
  208. anchors.centerIn: parent
  209. anchors.verticalCenterOffset: styleData.horizontal ? 0 : -1
  210. anchors.horizontalCenterOffset: styleData.horizontal ? -1 : 0
  211. opacity: control.enabled ? 0.6 : 0.5
  212. }
  213. gradient: Gradient {
  214. GradientStop {color: styleData.pressed ? "lightgray" : "white" ; position: 0}
  215. GradientStop {color: styleData.pressed ? "lightgray" : "lightgray" ; position: 1}
  216. }
  217. border.color: "#aaa"
  218. }
  219. }
  220. /*! \internal */
  221. property Component __scrollbar: Item {
  222. id: panel
  223. property string activeControl: "none"
  224. property bool scrollToClickPosition: true
  225. property bool isTransient: transientScrollBars
  226. property bool on: false
  227. property bool raised: false
  228. property bool sunken: __styleData.upPressed | __styleData.downPressed | __styleData.handlePressed
  229. states: State {
  230. name: "out"
  231. when: isTransient
  232. && (!__stickyScrollbars || !flickableItem.moving)
  233. && panel.activeControl === "none"
  234. && !panel.on
  235. && !panel.raised
  236. PropertyChanges { target: panel; opacity: 0 }
  237. }
  238. transitions: Transition {
  239. to: "out"
  240. SequentialAnimation {
  241. PauseAnimation { duration: root.__scrollBarFadeDelay }
  242. NumberAnimation { properties: "opacity"; duration: root.__scrollBarFadeDuration }
  243. PropertyAction { target: panel; property: "visible"; value: false }
  244. }
  245. }
  246. implicitWidth: __styleData.horizontal ? 200 : bg.implicitWidth
  247. implicitHeight: __styleData.horizontal ? bg.implicitHeight : 200
  248. function pixelMetric(arg) {
  249. if (arg === "scrollbarExtent")
  250. return (__styleData.horizontal ? bg.height : bg.width);
  251. return 0;
  252. }
  253. function styleHint(arg) {
  254. return false;
  255. }
  256. function hitTest(argX, argY) {
  257. if (itemIsHit(handleControl, argX, argY))
  258. return "handle"
  259. else if (itemIsHit(incrementLoader, argX, argY))
  260. return "up";
  261. else if (itemIsHit(decrementLoader, argX, argY))
  262. return "down";
  263. else if (itemIsHit(bg, argX, argY)) {
  264. if (__styleData.horizontal && argX < handleControl.x || !__styleData.horizontal && argY < handleControl.y)
  265. return "upPage"
  266. else
  267. return "downPage"
  268. }
  269. return "none";
  270. }
  271. function subControlRect(arg) {
  272. if (arg === "handle") {
  273. return Qt.rect(handleControl.x, handleControl.y, handleControl.width, handleControl.height);
  274. } else if (arg === "groove") {
  275. if (__styleData.horizontal) {
  276. return Qt.rect(incrementLoader.width - handleOverlap,
  277. 0,
  278. __control.width - (incrementLoader.width + decrementLoader.width - handleOverlap * 2),
  279. __control.height);
  280. } else {
  281. return Qt.rect(0,
  282. incrementLoader.height - handleOverlap,
  283. __control.width,
  284. __control.height - (incrementLoader.height + decrementLoader.height - handleOverlap * 2));
  285. }
  286. }
  287. return Qt.rect(0,0,0,0);
  288. }
  289. function itemIsHit(argItem, argX, argY) {
  290. var pos = argItem.mapFromItem(__control, argX, argY);
  291. return (pos.x >= 0 && pos.x <= argItem.width && pos.y >= 0 && pos.y <= argItem.height);
  292. }
  293. Loader {
  294. id: incrementLoader
  295. anchors.top: parent.top
  296. anchors.left: parent.left
  297. sourceComponent: decrementControl
  298. property QtObject styleData: QtObject {
  299. readonly property bool hovered: activeControl === "up"
  300. readonly property bool pressed: __styleData.upPressed
  301. readonly property bool horizontal: __styleData.horizontal
  302. }
  303. }
  304. Loader {
  305. id: bg
  306. anchors.top: __styleData.horizontal ? undefined : incrementLoader.bottom
  307. anchors.bottom: __styleData.horizontal ? undefined : decrementLoader.top
  308. anchors.left: __styleData.horizontal ? incrementLoader.right : undefined
  309. anchors.right: __styleData.horizontal ? decrementLoader.left : undefined
  310. sourceComponent: scrollBarBackground
  311. property QtObject styleData: QtObject {
  312. readonly property bool horizontal: __styleData.horizontal
  313. readonly property bool hovered: activeControl !== "none"
  314. }
  315. }
  316. Loader {
  317. id: decrementLoader
  318. anchors.bottom: __styleData.horizontal ? undefined : parent.bottom
  319. anchors.right: __styleData.horizontal ? parent.right : undefined
  320. sourceComponent: incrementControl
  321. property QtObject styleData: QtObject {
  322. readonly property bool hovered: activeControl === "down"
  323. readonly property bool pressed: __styleData.downPressed
  324. readonly property bool horizontal: __styleData.horizontal
  325. }
  326. }
  327. property var flickableItem: control.flickableItem
  328. property int extent: Math.max(minimumHandleLength, __styleData.horizontal ?
  329. Math.min(1, ((flickableItem && flickableItem.contentWidth > 0.0) ? flickableItem.width/flickableItem.contentWidth : 1)) * bg.width :
  330. Math.min(1, ((flickableItem && flickableItem.contentHeight > 0.0) ? flickableItem.height/flickableItem.contentHeight : 1)) * bg.height)
  331. readonly property real range: __control.maximumValue - __control.minimumValue
  332. readonly property real begin: __control.value - __control.minimumValue
  333. Loader {
  334. id: handleControl
  335. height: __styleData.horizontal ? implicitHeight : extent
  336. width: __styleData.horizontal ? extent : implicitWidth
  337. anchors.top: bg.top
  338. anchors.left: bg.left
  339. anchors.topMargin: __styleData.horizontal || range === 0 ? 0 : -handleOverlap + (2 * begin * (bg.height + (2 * handleOverlap) - extent) + range) / (2 * range)
  340. anchors.leftMargin: __styleData.horizontal && range !== 0 ? -handleOverlap + (2 * begin * (bg.width + (2 * handleOverlap) - extent) + range) / (2 * range) : 0
  341. sourceComponent: handle
  342. property QtObject styleData: QtObject {
  343. readonly property bool hovered: activeControl === "handle"
  344. readonly property bool pressed: __styleData.handlePressed
  345. readonly property bool horizontal: __styleData.horizontal
  346. }
  347. readonly property alias __activeControl: panel.activeControl
  348. }
  349. }
  350. /*! \internal */
  351. property bool __externalScrollBars: false
  352. /*! \internal */
  353. property int __scrollBarSpacing: 4
  354. /*! \internal */
  355. property int __scrollBarFadeDelay: 450
  356. /*! \internal */
  357. property int __scrollBarFadeDuration: 200
  358. /*! \internal */
  359. property bool __stickyScrollbars: false
  360. }