MenuStyle.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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.Window 2.1
  41. import QtQuick.Controls 1.2
  42. import QtQuick.Controls.Private 1.0
  43. /*!
  44. \qmltype MenuStyle
  45. \inqmlmodule QtQuick.Controls.Styles
  46. \since 5.3
  47. \ingroup controlsstyling
  48. \brief Provides custom styling for Menu.
  49. \target styleData properties
  50. The \b styleData object contains the following read-only properties:
  51. \table
  52. \row \li \b {styleData.index} : int \li The index of the menu item in its menu.
  53. \row \li \b {styleData.type} : enumeration \li The type of menu item. See below for possible values.
  54. \row \li \b {styleData.selected} : bool \li \c true if the menu item is selected.
  55. \row \li \b {styleData.pressed} : bool \li \c true if the menu item is pressed. Available since 5.4.
  56. \row \li \b {styleData.text} : string \li The menu item's text, or title if it's a submenu.
  57. \row \li \b {styleData.underlineMnemonic} : bool \li Whether the style should underline the menu item's label mnemonic.
  58. \row \li \b {styleData.shortcut} : string \li The text for the menu item's shortcut.
  59. \row \li \b {styleData.iconSource} : url \li The source URL to the menu item's icon. Undefined if it has no icon.
  60. \row \li \b {styleData.enabled} : bool \li \c true if the menu item is enabled.
  61. \row \li \b {styleData.checkable} : bool \li \c true if the menu item is checkable.
  62. \row \li \b {styleData.exclusive} : bool \li \c true if the menu item is checkable, and it's part of an \l ExclusiveGroup.
  63. \row \li \b {styleData.checked} : bool \li \c true if the menu item is checkable and currently checked.
  64. \row \li \b {styleData.scrollerDirection} : enumeration \li If the menu item is a scroller, its pointing direction.
  65. Valid values are \c Qt.UpArrow, \c Qt.DownArrow, and \c Qt.NoArrow.
  66. \endtable
  67. The valid values for \b {styleData.type} are:
  68. \list
  69. \li MenuItemType.Item
  70. \li MenuItemType.Menu
  71. \li MenuItemType.Separator
  72. \li MenuItemType.ScrollIndicator
  73. \endlist
  74. \note Styling menus may not be supported on platforms using native menus
  75. through their QPA plugin.
  76. */
  77. Style {
  78. id: styleRoot
  79. padding {
  80. top: 1
  81. bottom: 1
  82. left: 1
  83. right: 1
  84. }
  85. /*! The amount of pixels by which a submenu popup overlaps horizontally its parent menu. */
  86. property int submenuOverlap: 1
  87. /*! The number of milliseconds to wait before opening a submenu. */
  88. property int submenuPopupDelay: 200
  89. /*!
  90. \qmlmethod string MenuStyle::formatMnemonic(string text, bool underline = false)
  91. Returns a rich-text string to render mnemonics for a given menu item \a text.
  92. The mnemonic character is prefixed by an ampersand in the original string.
  93. Passing \c true for \a underline will underline the mnemonic character (e.g.,
  94. \c formatMnemonic("&Open...", true) will return \c "<u>O</u>pen..."). Passing \c false
  95. for \a underline will return the plain text form (e.g., \c formatMnemonic("&Open...", false)
  96. will return \c "Open...").
  97. \sa Label
  98. */
  99. function formatMnemonic(text, underline) {
  100. return underline ? StyleHelpers.stylizeMnemonics(text) : StyleHelpers.removeMnemonics(text)
  101. }
  102. /*! The background frame for the menu popup.
  103. The \l Menu will resize the frame to its contents plus the padding.
  104. */
  105. property Component frame: Rectangle {
  106. color: styleRoot.__backgroundColor
  107. border { width: 1; color: styleRoot.__borderColor }
  108. }
  109. /*! \qmlproperty Object MenuStyle::itemDelegate
  110. The object containing the menu item subcontrol components. These subcontrols are used
  111. for normal menu items only, i.e. not for separators or scroll indicators.
  112. The subcontrols are:
  113. \list
  114. \li \b {itemDelegate.background} : Component
  115. The menu item background component.
  116. Its appearance generally changes with \l {styleData properties} {styleData.selected}
  117. and \l {styleData properties} {styleData.enabled}.
  118. The default implementation shows only when the item is enabled and selected. It remains
  119. invisible otherwise.
  120. \li \b {itemDelegate.label} : Component
  121. Component for the actual text label.
  122. The text itself is fetched from \l {styleData properties} {styleData.text}, and its appearance should depend
  123. on \l {styleData properties} {styleData.enabled} and \l {styleData properties} {styleData.selected}.
  124. If \l {styleData properties} {styleData.underlineMnemonic} is true, the label should underline its mnemonic
  125. character. \l formatMnemonic provides the default formatting.
  126. \li \b {itemDelegate.submenuIndicator} : Component
  127. It indicates that the current menu item is a submenu.
  128. Only used when \l {styleData properties} {styleData.type} equals \c MenuItemType.Menu.
  129. \li \b {itemDelegate.shortcut} : Component
  130. Displays the shortcut attached to the menu item.
  131. Only used when \l {styleData properties} {styleData.shortcut} is not empty.
  132. \li \b {itemDelegate.checkmarkIndicator} : Component
  133. Will be used when \l {styleData properties} {styleData.checkable} is \c true and its appearance
  134. may depend on \l {styleData properties} {styleData.exclusive}, i.e., whether it will behave like a
  135. checkbox or a radio button. Use \l {styleData properties} {styleData.checked} for the checked state.
  136. \endlist
  137. \note This property cannot be overwritten although all of the subcontrol properties can.
  138. */
  139. property alias itemDelegate: internalMenuItem
  140. MenuItemSubControls {
  141. id: internalMenuItem
  142. background: Rectangle {
  143. visible: styleData.selected && styleData.enabled
  144. gradient: Gradient {
  145. id: selectedGradient
  146. GradientStop { color: Qt.lighter(__selectedBackgroundColor, 1.3); position: -0.2 }
  147. GradientStop { color: __selectedBackgroundColor; position: 1.4 }
  148. }
  149. border.width: 1
  150. border.color: Qt.darker(__selectedBackgroundColor, 1)
  151. antialiasing: true
  152. }
  153. label: Text {
  154. text: formatMnemonic(styleData.text, styleData.underlineMnemonic)
  155. color: __currentTextColor
  156. font: styleRoot.font
  157. renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering
  158. }
  159. submenuIndicator: Text {
  160. text: __mirrored ? "\u25c2" : "\u25b8" // BLACK LEFT/RIGHT-POINTING SMALL TRIANGLE
  161. font: styleRoot.font
  162. color: __currentTextColor
  163. style: styleData.selected ? Text.Normal : Text.Raised
  164. styleColor: Qt.lighter(color, 4)
  165. renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering
  166. }
  167. shortcut: Text {
  168. text: styleData.shortcut
  169. font {
  170. bold: styleRoot.font.bold
  171. capitalization: styleRoot.font.capitalization
  172. family: styleRoot.font.family
  173. italic: styleRoot.font.italic
  174. letterSpacing: styleRoot.font.letterSpacing
  175. pixelSize: styleRoot.font.pixelSize * 0.9
  176. strikeout: styleRoot.font.strikeout
  177. underline: styleRoot.font.underline
  178. weight: styleRoot.font.weight
  179. wordSpacing: styleRoot.font.wordSpacing
  180. }
  181. color: __currentTextColor
  182. renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering
  183. }
  184. checkmarkIndicator: Loader {
  185. sourceComponent: styleData.exclusive ? exclusiveCheckMark : nonExclusiveCheckMark
  186. Component {
  187. id: exclusiveCheckMark
  188. Rectangle {
  189. x: 1
  190. width: 10
  191. height: 10
  192. color: "white"
  193. border.color: "gray"
  194. antialiasing: true
  195. radius: height/2
  196. Rectangle {
  197. anchors.centerIn: parent
  198. visible: styleData.checked
  199. width: 4
  200. height: 4
  201. color: "#666"
  202. border.color: "#222"
  203. antialiasing: true
  204. radius: height/2
  205. }
  206. }
  207. }
  208. Component {
  209. id: nonExclusiveCheckMark
  210. BorderImage {
  211. width: 12
  212. height: 12
  213. source: "images/editbox.png"
  214. border.top: 6
  215. border.bottom: 6
  216. border.left: 6
  217. border.right: 6
  218. Rectangle {
  219. antialiasing: true
  220. visible: styleData.checked
  221. color: "#666"
  222. radius: 1
  223. anchors.margins: 4
  224. anchors.fill: parent
  225. border.color: "#222"
  226. Rectangle {
  227. anchors.fill: parent
  228. anchors.margins: 1
  229. color: "transparent"
  230. border.color: "#33ffffff"
  231. }
  232. }
  233. }
  234. }
  235. }
  236. }
  237. /*! Component for the separator menu item.
  238. Will be used when \l {styleData properties} {styleData.type} equals \c MenuItemType.Separator.
  239. */
  240. property Component separator: Item {
  241. implicitHeight: styleRoot.font.pixelSize / 2
  242. Rectangle {
  243. width: parent.width - 2
  244. height: 1
  245. x: 1
  246. anchors.verticalCenter: parent.verticalCenter
  247. color: "darkgray"
  248. }
  249. }
  250. /*! Component for the scroll indicator menu item.
  251. Will be used when \l {styleData properties} {styleData.type} equals \c MenuItemType.ScrollIndicator.
  252. Its appearance should follow \l {styleData properties} {styleData.scrollerDirection}.
  253. This is the item added at the top and bottom of the menu popup when its contents won't fit the screen
  254. to indicate more content is available in the direction of the arrow.
  255. */
  256. property Component scrollIndicator: Image {
  257. anchors.centerIn: parent
  258. source: styleData.scrollerDirection === Qt.UpArrow ? "images/arrow-up.png" : "images/arrow-down.png"
  259. }
  260. /*!
  261. \since QtQuick.Controls.Styles 1.3
  262. The font of the control.
  263. */
  264. property font font
  265. /*! \internal */
  266. property string __menuItemType: "menuitem"
  267. /*! \internal
  268. The menu popup frame background color.
  269. This is set to be a uniform background. If you want a gradient or a pixmap,
  270. you should override \l frame.
  271. \sa frame, borderColor
  272. */
  273. property color __backgroundColor: "#dcdcdc"
  274. /*! \internal
  275. The menu popup frame border color.
  276. The border width is set to 1 pixel. Override \l frame if you want a larger border.
  277. \sa frame, backgroundColor
  278. */
  279. property color __borderColor: "darkgray"
  280. /*! \internal
  281. The maximum height for a popup before it will show scrollers.
  282. */
  283. property int __maxPopupHeight: 600
  284. /*! \internal
  285. The menu item background color when selected.
  286. This property is provided for convenience and only sets the color.
  287. It does not change the style in any other way.
  288. */
  289. property color __selectedBackgroundColor: "#49d"
  290. /*! \internal
  291. The menu item label color.
  292. When set, keyboard shorcuts get the same color as the item's text.
  293. \sa selectedLabelColor, disabledLabelColor
  294. */
  295. property color __labelColor: "#444"
  296. /*! \internal
  297. The menu item label color when selected.
  298. \sa labelColor, selectedLabelColor
  299. */
  300. property color __selectedLabelColor: "white"
  301. /*! \internal
  302. The menu item label color when disabled.
  303. \sa labelColor, disabledLabelColor
  304. */
  305. property color __disabledLabelColor: "gray"
  306. /*! \internal */
  307. readonly property bool __mirrored: Qt.application.layoutDirection === Qt.RightToLeft
  308. /*! \internal
  309. The margin between the frame and the menu item label's left side.
  310. Generally, this should be large enough to fit optional checkmarks on
  311. the label's left side.
  312. */
  313. property int __leftLabelMargin: 18
  314. /*! \internal
  315. The margin between the menu item label's right side and the frame. */
  316. property int __rightLabelMargin: 12
  317. /*! \internal
  318. The minimum spacing between the menu item label's text right side and any
  319. element located on its right (submenu indicator or shortcut).
  320. */
  321. property int __minRightLabelSpacing: 28
  322. /*! \internal */
  323. property Component __scrollerStyle: null
  324. /*! \internal
  325. The menu item contents itself.
  326. The default implementation uses \l MenuItemStyle.
  327. */
  328. property Component menuItemPanel: Item {
  329. id: panel
  330. property QtObject __styleData: styleData
  331. /*! \internal
  332. The current color of the text label.
  333. Use this if you're overriding e.g. \l shortcutIndicator to keep the color matched
  334. with \l label, or to derive new colors from it.
  335. */
  336. property color currentTextColor: !styleData.enabled ? __disabledLabelColor :
  337. styleData.selected ? __selectedLabelColor : __labelColor
  338. implicitWidth: Math.max((parent ? parent.width : 0),
  339. Math.round(__leftLabelMargin + labelLoader.width + __rightLabelMargin +
  340. (rightIndicatorLoader.active ? __minRightLabelSpacing + rightIndicatorLoader.width : 0)))
  341. implicitHeight: Math.round(styleData.type === MenuItemType.Separator ? separatorLoader.implicitHeight :
  342. !!styleData.scrollerDirection ? styleRoot.font.pixelSize * 0.75 : labelLoader.height + 4)
  343. Loader {
  344. property alias styleData: panel.__styleData
  345. property alias __currentTextColor: panel.currentTextColor
  346. anchors.fill: parent
  347. sourceComponent: itemDelegate.background
  348. }
  349. Loader {
  350. id: separatorLoader
  351. property alias styleData: panel.__styleData
  352. property alias __currentTextColor: panel.currentTextColor
  353. anchors.fill: parent
  354. sourceComponent: separator
  355. active: styleData.type === MenuItemType.Separator
  356. }
  357. Loader {
  358. property alias styleData: panel.__styleData
  359. property alias __currentTextColor: panel.currentTextColor
  360. x: __mirrored ? parent.width - width - 4 : 4
  361. anchors.verticalCenterOffset: -1
  362. anchors.verticalCenter: parent.verticalCenter
  363. active: __menuItemType === "menuitem" && styleData.checkable
  364. sourceComponent: itemDelegate.checkmarkIndicator
  365. }
  366. Loader {
  367. id: labelLoader
  368. readonly property real offset: __menuItemType === "menuitem" ? __leftLabelMargin : 6
  369. property alias styleData: panel.__styleData
  370. property alias __currentTextColor: panel.currentTextColor
  371. x: __mirrored ? parent.width - width - offset : offset
  372. y: 1
  373. active: styleData.type !== MenuItemType.Separator
  374. sourceComponent: itemDelegate.label
  375. baselineOffset: item ? item.baselineOffset : 0.0
  376. }
  377. Loader {
  378. id: rightIndicatorLoader
  379. property alias styleData: panel.__styleData
  380. property alias __currentTextColor: panel.currentTextColor
  381. active: styleData.type === MenuItemType.Menu || styleData.shortcut !== ""
  382. sourceComponent: styleData.type === MenuItemType.Menu ? itemDelegate.submenuIndicator : itemDelegate.shortcut
  383. LayoutMirroring.enabled: __mirrored
  384. baselineOffset: item ? item.baselineOffset : 0.0
  385. anchors {
  386. right: parent.right
  387. rightMargin: 6
  388. baseline: !styleData.isSubmenu ? labelLoader.baseline : undefined
  389. }
  390. }
  391. }
  392. }