From 09332d27a970fb8d7dd6ddbc998ff8adf0084aca Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Thu, 17 Jan 2019 22:27:01 +0000 Subject: [PATCH] Import kirigami2_5.54.0.orig.tar.xz [dgit import orig kirigami2_5.54.0.orig.tar.xz] --- .arcconfig | 4 + .gitignore | 1 + CMakeLists.txt | 132 ++ KF5Kirigami2Config.cmake.in | 15 + KF5Kirigami2Macros.cmake | 93 + LICENSE.LGPL-2 | 481 ++++ Mainpage.dox | 211 ++ README.md | 119 + autotests/CMakeLists.txt | 9 + autotests/tst_keynavigation.qml | 68 + autotests/tst_listskeynavigation.qml | 64 + autotests/tst_pagerow.qml | 141 ++ examples/CMakeLists.txt | 3 + examples/applicationitemapp/CMakeLists.txt | 13 + examples/applicationitemapp/main.cpp | 38 + examples/applicationitemapp/main.qml | 81 + examples/applicationitemapp/resources.qrc | 5 + examples/minimalqmake/3rdparty/README | 6 + examples/minimalqmake/Page1.qml | 26 + examples/minimalqmake/Page1Form.ui.qml | 45 + examples/minimalqmake/kirigami-icons.qrc | 16 + examples/minimalqmake/main.cpp | 42 + examples/minimalqmake/main.qml | 58 + examples/minimalqmake/minimalqmake.pro | 35 + examples/minimalqmake/qml.qrc | 8 + examples/minimalqmake/qtquickcontrols2.conf | 15 + .../multiplatformnotesapp/NotesGeneral.qml | 216 ++ .../multiplatformnotesapp/notesDesktop.qml | 30 + .../multiplatformnotesapp/notesMobile.qml | 31 + .../qmakewithstaticplugin/3rdparty/README | 6 + .../qmakewithstaticplugin/minimalqmake.pro | 10 + examples/qmakewithstaticplugin/src/Page1.qml | 26 + .../src/Page1Form.ui.qml | 45 + .../src/kirigami-icons.qrc | 16 + examples/qmakewithstaticplugin/src/main.cpp | 40 + examples/qmakewithstaticplugin/src/main.qml | 58 + examples/qmakewithstaticplugin/src/qml.qrc | 8 + .../src/qtquickcontrols2.conf | 15 + examples/qmakewithstaticplugin/src/src.pro | 39 + .../AbstractApplicationWindow.qml | 165 ++ examples/simpleexamples/FixedSidebar.qml | 52 + .../simpleexamples/MultipleColumnsGallery.qml | 88 + examples/simpleexamples/Sidebar.qml | 137 ++ examples/simpleexamples/TabBarHeader.qml | 52 + examples/simpleexamples/customdrawer.qml | 50 + examples/simpleexamples/dragPageWidth.qml | 87 + examples/simpleexamples/footer.qml | 79 + examples/simpleexamples/minimal.qml | 69 + examples/simpleexamples/pushpopclear.qml | 82 + examples/simpleexamples/simpleChatApp.qml | 337 +++ examples/staticcmake/3rdparty/CMakeLists.txt | 3 + examples/staticcmake/3rdparty/README | 6 + examples/staticcmake/CMakeLists.txt | 24 + examples/staticcmake/src/CMakeLists.txt | 27 + examples/staticcmake/src/Page1.qml | 26 + examples/staticcmake/src/Page1Form.ui.qml | 52 + examples/staticcmake/src/kirigami-icons.qrc | 15 + examples/staticcmake/src/main.cpp | 78 + examples/staticcmake/src/main.qml | 58 + .../staticcmake/src/qtquickcontrols2.conf | 15 + examples/staticcmake/src/resources.qrc | 8 + kirigami-icons.qrc | 13 + kirigami.pri | 41 + kirigami.pro | 56 + kirigami.qrc | 86 + kirigami.qrc.in | 86 + logo.png | Bin 0 -> 4954 bytes metainfo.yaml | 21 + po/ar/libkirigami2plugin_qt.po | 94 + po/ca/libkirigami2plugin_qt.po | 97 + po/ca@valencia/libkirigami2plugin_qt.po | 97 + po/cs/libkirigami2plugin_qt.po | 90 + po/da/libkirigami2plugin_qt.po | 90 + po/de/libkirigami2plugin_qt.po | 91 + po/el/libkirigami2plugin_qt.po | 96 + po/en_GB/libkirigami2plugin_qt.po | 90 + po/es/libkirigami2plugin_qt.po | 90 + po/eu/libkirigami2plugin_qt.po | 96 + po/fi/libkirigami2plugin_qt.po | 91 + po/fr/libkirigami2plugin_qt.po | 94 + po/gl/libkirigami2plugin_qt.po | 91 + po/hu/libkirigami2plugin_qt.po | 90 + po/ia/libkirigami2plugin_qt.po | 96 + po/id/libkirigami2plugin_qt.po | 90 + po/it/libkirigami2plugin_qt.po | 90 + po/ja/libkirigami2plugin_qt.po | 88 + po/ko/libkirigami2plugin_qt.po | 90 + po/nl/libkirigami2plugin_qt.po | 90 + po/nn/libkirigami2plugin_qt.po | 95 + po/pl/libkirigami2plugin_qt.po | 91 + po/pt/libkirigami2plugin_qt.po | 92 + po/pt_BR/libkirigami2plugin_qt.po | 96 + po/ru/libkirigami2plugin_qt.po | 97 + po/sk/libkirigami2plugin_qt.po | 99 + po/sl/libkirigami2plugin_qt.po | 97 + po/sr/libkirigami2plugin_qt.po | 54 + po/sr@ijekavian/libkirigami2plugin_qt.po | 54 + po/sr@ijekavianlatin/libkirigami2plugin_qt.po | 54 + po/sr@latin/libkirigami2plugin_qt.po | 54 + po/sv/libkirigami2plugin_qt.po | 90 + po/tr/libkirigami2plugin_qt.po | 94 + po/uk/libkirigami2plugin_qt.po | 96 + po/zh_CN/libkirigami2plugin_qt.po | 93 + po/zh_TW/libkirigami2plugin_qt.po | 94 + scripts/gen_icons_qrc.sh | 59 + scripts/gen_qml_qrc.sh | 39 + scripts/gen_qmltypes.sh | 17 + src/CMakeLists.txt | 123 + src/Messages.sh | 4 + src/controls/AboutPage.qml | 212 ++ src/controls/AbstractApplicationHeader.qml | 73 + src/controls/AbstractApplicationItem.qml | 366 +++ src/controls/AbstractApplicationWindow.qml | 326 +++ src/controls/AbstractCard.qml | 69 + src/controls/AbstractItemViewHeader.qml | 49 + src/controls/AbstractListItem.qml | 35 + src/controls/Action.qml | 170 ++ src/controls/ActionToolBar.qml | 194 ++ src/controls/ApplicationHeader.qml | 37 + src/controls/ApplicationItem.qml | 174 ++ src/controls/ApplicationWindow.qml | 176 ++ src/controls/BasicListItem.qml | 97 + src/controls/Card.qml | 108 + src/controls/CardsGridView.qml | 88 + src/controls/CardsLayout.qml | 91 + src/controls/CardsListView.qml | 47 + src/controls/ContextDrawer.qml | 174 ++ src/controls/FormLayout.qml | 347 +++ src/controls/GlobalDrawer.qml | 583 +++++ src/controls/Heading.qml | 88 + src/controls/InlineMessage.qml | 300 +++ src/controls/ItemViewHeader.qml | 114 + src/controls/Label.qml | 47 + src/controls/LinkButton.qml | 65 + src/controls/ListItemDragHandle.qml | 207 ++ src/controls/OverlayDrawer.qml | 155 ++ src/controls/OverlaySheet.qml | 106 + src/controls/Page.qml | 376 +++ src/controls/PageRow.qml | 786 +++++++ src/controls/ScrollablePage.qml | 186 ++ src/controls/Separator.qml | 39 + src/controls/SwipeListItem.qml | 56 + src/controls/Theme.qml | 82 + src/controls/ToolBarApplicationHeader.qml | 134 ++ src/controls/Units.qml | 136 ++ src/controls/UrlButton.qml | 55 + src/controls/plugins.qmltypes | 2059 +++++++++++++++++ src/controls/private/ActionButton.qml | 502 ++++ src/controls/private/ActionIconGroup.qml | 29 + src/controls/private/ActionMenuItemBase.qml | 37 + src/controls/private/ActionMenuItemQt510.qml | 27 + src/controls/private/ActionMenuItemQt59.qml | 22 + src/controls/private/ActionsMenu.qml | 77 + src/controls/private/BannerImage.qml | 149 ++ src/controls/private/CardsGridViewPrivate.qml | 39 + src/controls/private/CardsListViewPrivate.qml | 34 + src/controls/private/CornerShadow.qml | 72 + .../private/DefaultListItemBackground.qml | 49 + src/controls/private/EdgeShadow.qml | 58 + .../private/PageActionPropertyGroup.qml | 28 + .../private/PrivateActionToolButton.qml | 117 + .../private/RefreshableScrollView.qml | 255 ++ src/controls/private/SwipeItemEventFilter.qml | 47 + .../globaltoolbar/AbstractPageHeader.qml | 45 + .../globaltoolbar/BreadcrumbControl.qml | 98 + .../PageRowGlobalToolBarStyleGroup.qml | 51 + .../globaltoolbar/PageRowGlobalToolBarUI.qml | 104 + .../private/globaltoolbar/TabBarControl.qml | 42 + .../globaltoolbar/TitlesPageHeader.qml | 48 + .../globaltoolbar/ToolBarPageHeader.qml | 120 + src/controls/qmldir | 7 + .../templates/AbstractApplicationHeader.qml | 207 ++ src/controls/templates/AbstractCard.qml | 165 ++ src/controls/templates/AbstractListItem.qml | 129 ++ src/controls/templates/ApplicationHeader.qml | 392 ++++ src/controls/templates/InlineMessage.qml | 135 ++ src/controls/templates/OverlayDrawer.qml | 484 ++++ src/controls/templates/OverlaySheet.qml | 533 +++++ src/controls/templates/SwipeListItem.qml | 429 ++++ src/controls/templates/private/BackButton.qml | 55 + .../templates/private/ContextIcon.qml | 80 + .../templates/private/ForwardButton.qml | 51 + .../templates/private/GenericDrawerIcon.qml | 48 + .../templates/private/IconPropertiesGroup.qml | 27 + src/controls/templates/private/MenuIcon.qml | 78 + .../templates/private/PassiveNotification.qml | 153 ++ src/controls/templates/private/ScrollView.qml | 207 ++ src/controls/templates/qmldir | 10 + src/delegaterecycler.cpp | 334 +++ src/delegaterecycler.h | 89 + src/desktopicon.cpp | 540 +++++ src/desktopicon.h | 118 + src/enums.cpp | 22 + src/enums.h | 55 + src/formlayoutattached.cpp | 129 ++ src/formlayoutattached.h | 169 ++ src/kirigamiplugin.cpp | 184 ++ src/kirigamiplugin.h | 73 + src/libkirigami/CMakeLists.txt | 94 + src/libkirigami/basictheme.cpp | 325 +++ src/libkirigami/basictheme_p.h | 99 + src/libkirigami/kirigamipluginfactory.cpp | 39 + src/libkirigami/kirigamipluginfactory.h | 65 + .../org.kde.KWin.TabletModeManager.xml | 13 + src/libkirigami/platformtheme.cpp | 728 ++++++ src/libkirigami/platformtheme.h | 270 +++ src/libkirigami/tabletmodewatcher.cpp | 140 ++ src/libkirigami/tabletmodewatcher.h | 88 + src/mnemonicattached.cpp | 321 +++ src/mnemonicattached.h | 169 ++ src/qmldir | 48 + src/scenepositionattached.cpp | 79 + src/scenepositionattached.h | 76 + src/settings.cpp | 141 ++ src/settings.h | 107 + src/styles/Material/AbstractListItem.qml | 42 + src/styles/Material/Label.qml | 46 + src/styles/Material/SwipeListItem.qml | 70 + src/styles/Material/Theme.qml | 105 + .../AbstractApplicationHeader.qml | 55 + .../org.kde.desktop/AbstractListItem.qml | 30 + .../org.kde.desktop/ApplicationWindow.qml | 29 + src/styles/org.kde.desktop/SwipeListItem.qml | 30 + src/styles/org.kde.desktop/Theme.qml | 90 + src/styles/org.kde.desktop/Units.qml | 126 + tests/KeyboardListTest.qml | 45 + tests/KeyboardTest.qml | 56 + tests/actionsMenu.qml | 104 + tests/cardsList.qml | 44 + 229 files changed, 26549 insertions(+) create mode 100644 .arcconfig create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 KF5Kirigami2Config.cmake.in create mode 100644 KF5Kirigami2Macros.cmake create mode 100644 LICENSE.LGPL-2 create mode 100644 Mainpage.dox create mode 100644 README.md create mode 100644 autotests/CMakeLists.txt create mode 100644 autotests/tst_keynavigation.qml create mode 100644 autotests/tst_listskeynavigation.qml create mode 100644 autotests/tst_pagerow.qml create mode 100644 examples/CMakeLists.txt create mode 100644 examples/applicationitemapp/CMakeLists.txt create mode 100644 examples/applicationitemapp/main.cpp create mode 100644 examples/applicationitemapp/main.qml create mode 100644 examples/applicationitemapp/resources.qrc create mode 100644 examples/minimalqmake/3rdparty/README create mode 100644 examples/minimalqmake/Page1.qml create mode 100644 examples/minimalqmake/Page1Form.ui.qml create mode 100644 examples/minimalqmake/kirigami-icons.qrc create mode 100644 examples/minimalqmake/main.cpp create mode 100644 examples/minimalqmake/main.qml create mode 100644 examples/minimalqmake/minimalqmake.pro create mode 100644 examples/minimalqmake/qml.qrc create mode 100644 examples/minimalqmake/qtquickcontrols2.conf create mode 100644 examples/multiplatformnotesapp/NotesGeneral.qml create mode 100644 examples/multiplatformnotesapp/notesDesktop.qml create mode 100644 examples/multiplatformnotesapp/notesMobile.qml create mode 100644 examples/qmakewithstaticplugin/3rdparty/README create mode 100644 examples/qmakewithstaticplugin/minimalqmake.pro create mode 100644 examples/qmakewithstaticplugin/src/Page1.qml create mode 100644 examples/qmakewithstaticplugin/src/Page1Form.ui.qml create mode 100644 examples/qmakewithstaticplugin/src/kirigami-icons.qrc create mode 100644 examples/qmakewithstaticplugin/src/main.cpp create mode 100644 examples/qmakewithstaticplugin/src/main.qml create mode 100644 examples/qmakewithstaticplugin/src/qml.qrc create mode 100644 examples/qmakewithstaticplugin/src/qtquickcontrols2.conf create mode 100644 examples/qmakewithstaticplugin/src/src.pro create mode 100644 examples/simpleexamples/AbstractApplicationWindow.qml create mode 100644 examples/simpleexamples/FixedSidebar.qml create mode 100644 examples/simpleexamples/MultipleColumnsGallery.qml create mode 100644 examples/simpleexamples/Sidebar.qml create mode 100644 examples/simpleexamples/TabBarHeader.qml create mode 100644 examples/simpleexamples/customdrawer.qml create mode 100644 examples/simpleexamples/dragPageWidth.qml create mode 100644 examples/simpleexamples/footer.qml create mode 100644 examples/simpleexamples/minimal.qml create mode 100644 examples/simpleexamples/pushpopclear.qml create mode 100644 examples/simpleexamples/simpleChatApp.qml create mode 100644 examples/staticcmake/3rdparty/CMakeLists.txt create mode 100644 examples/staticcmake/3rdparty/README create mode 100644 examples/staticcmake/CMakeLists.txt create mode 100644 examples/staticcmake/src/CMakeLists.txt create mode 100644 examples/staticcmake/src/Page1.qml create mode 100644 examples/staticcmake/src/Page1Form.ui.qml create mode 100644 examples/staticcmake/src/kirigami-icons.qrc create mode 100644 examples/staticcmake/src/main.cpp create mode 100644 examples/staticcmake/src/main.qml create mode 100644 examples/staticcmake/src/qtquickcontrols2.conf create mode 100644 examples/staticcmake/src/resources.qrc create mode 100644 kirigami-icons.qrc create mode 100644 kirigami.pri create mode 100644 kirigami.pro create mode 100644 kirigami.qrc create mode 100644 kirigami.qrc.in create mode 100644 logo.png create mode 100644 metainfo.yaml create mode 100644 po/ar/libkirigami2plugin_qt.po create mode 100644 po/ca/libkirigami2plugin_qt.po create mode 100644 po/ca@valencia/libkirigami2plugin_qt.po create mode 100644 po/cs/libkirigami2plugin_qt.po create mode 100644 po/da/libkirigami2plugin_qt.po create mode 100644 po/de/libkirigami2plugin_qt.po create mode 100644 po/el/libkirigami2plugin_qt.po create mode 100644 po/en_GB/libkirigami2plugin_qt.po create mode 100644 po/es/libkirigami2plugin_qt.po create mode 100644 po/eu/libkirigami2plugin_qt.po create mode 100644 po/fi/libkirigami2plugin_qt.po create mode 100644 po/fr/libkirigami2plugin_qt.po create mode 100644 po/gl/libkirigami2plugin_qt.po create mode 100644 po/hu/libkirigami2plugin_qt.po create mode 100644 po/ia/libkirigami2plugin_qt.po create mode 100644 po/id/libkirigami2plugin_qt.po create mode 100644 po/it/libkirigami2plugin_qt.po create mode 100644 po/ja/libkirigami2plugin_qt.po create mode 100644 po/ko/libkirigami2plugin_qt.po create mode 100644 po/nl/libkirigami2plugin_qt.po create mode 100644 po/nn/libkirigami2plugin_qt.po create mode 100644 po/pl/libkirigami2plugin_qt.po create mode 100644 po/pt/libkirigami2plugin_qt.po create mode 100644 po/pt_BR/libkirigami2plugin_qt.po create mode 100644 po/ru/libkirigami2plugin_qt.po create mode 100644 po/sk/libkirigami2plugin_qt.po create mode 100644 po/sl/libkirigami2plugin_qt.po create mode 100644 po/sr/libkirigami2plugin_qt.po create mode 100644 po/sr@ijekavian/libkirigami2plugin_qt.po create mode 100644 po/sr@ijekavianlatin/libkirigami2plugin_qt.po create mode 100644 po/sr@latin/libkirigami2plugin_qt.po create mode 100644 po/sv/libkirigami2plugin_qt.po create mode 100644 po/tr/libkirigami2plugin_qt.po create mode 100644 po/uk/libkirigami2plugin_qt.po create mode 100644 po/zh_CN/libkirigami2plugin_qt.po create mode 100644 po/zh_TW/libkirigami2plugin_qt.po create mode 100755 scripts/gen_icons_qrc.sh create mode 100755 scripts/gen_qml_qrc.sh create mode 100755 scripts/gen_qmltypes.sh create mode 100644 src/CMakeLists.txt create mode 100644 src/Messages.sh create mode 100644 src/controls/AboutPage.qml create mode 100644 src/controls/AbstractApplicationHeader.qml create mode 100644 src/controls/AbstractApplicationItem.qml create mode 100644 src/controls/AbstractApplicationWindow.qml create mode 100644 src/controls/AbstractCard.qml create mode 100644 src/controls/AbstractItemViewHeader.qml create mode 100644 src/controls/AbstractListItem.qml create mode 100644 src/controls/Action.qml create mode 100644 src/controls/ActionToolBar.qml create mode 100644 src/controls/ApplicationHeader.qml create mode 100644 src/controls/ApplicationItem.qml create mode 100644 src/controls/ApplicationWindow.qml create mode 100644 src/controls/BasicListItem.qml create mode 100644 src/controls/Card.qml create mode 100644 src/controls/CardsGridView.qml create mode 100644 src/controls/CardsLayout.qml create mode 100644 src/controls/CardsListView.qml create mode 100644 src/controls/ContextDrawer.qml create mode 100644 src/controls/FormLayout.qml create mode 100644 src/controls/GlobalDrawer.qml create mode 100644 src/controls/Heading.qml create mode 100644 src/controls/InlineMessage.qml create mode 100644 src/controls/ItemViewHeader.qml create mode 100644 src/controls/Label.qml create mode 100644 src/controls/LinkButton.qml create mode 100644 src/controls/ListItemDragHandle.qml create mode 100644 src/controls/OverlayDrawer.qml create mode 100644 src/controls/OverlaySheet.qml create mode 100644 src/controls/Page.qml create mode 100644 src/controls/PageRow.qml create mode 100644 src/controls/ScrollablePage.qml create mode 100644 src/controls/Separator.qml create mode 100644 src/controls/SwipeListItem.qml create mode 100644 src/controls/Theme.qml create mode 100644 src/controls/ToolBarApplicationHeader.qml create mode 100644 src/controls/Units.qml create mode 100644 src/controls/UrlButton.qml create mode 100644 src/controls/plugins.qmltypes create mode 100644 src/controls/private/ActionButton.qml create mode 100644 src/controls/private/ActionIconGroup.qml create mode 100644 src/controls/private/ActionMenuItemBase.qml create mode 100644 src/controls/private/ActionMenuItemQt510.qml create mode 100644 src/controls/private/ActionMenuItemQt59.qml create mode 100644 src/controls/private/ActionsMenu.qml create mode 100644 src/controls/private/BannerImage.qml create mode 100644 src/controls/private/CardsGridViewPrivate.qml create mode 100644 src/controls/private/CardsListViewPrivate.qml create mode 100644 src/controls/private/CornerShadow.qml create mode 100644 src/controls/private/DefaultListItemBackground.qml create mode 100644 src/controls/private/EdgeShadow.qml create mode 100644 src/controls/private/PageActionPropertyGroup.qml create mode 100644 src/controls/private/PrivateActionToolButton.qml create mode 100644 src/controls/private/RefreshableScrollView.qml create mode 100644 src/controls/private/SwipeItemEventFilter.qml create mode 100644 src/controls/private/globaltoolbar/AbstractPageHeader.qml create mode 100644 src/controls/private/globaltoolbar/BreadcrumbControl.qml create mode 100644 src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml create mode 100644 src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml create mode 100644 src/controls/private/globaltoolbar/TabBarControl.qml create mode 100644 src/controls/private/globaltoolbar/TitlesPageHeader.qml create mode 100644 src/controls/private/globaltoolbar/ToolBarPageHeader.qml create mode 100644 src/controls/qmldir create mode 100644 src/controls/templates/AbstractApplicationHeader.qml create mode 100644 src/controls/templates/AbstractCard.qml create mode 100644 src/controls/templates/AbstractListItem.qml create mode 100644 src/controls/templates/ApplicationHeader.qml create mode 100644 src/controls/templates/InlineMessage.qml create mode 100644 src/controls/templates/OverlayDrawer.qml create mode 100644 src/controls/templates/OverlaySheet.qml create mode 100644 src/controls/templates/SwipeListItem.qml create mode 100644 src/controls/templates/private/BackButton.qml create mode 100644 src/controls/templates/private/ContextIcon.qml create mode 100644 src/controls/templates/private/ForwardButton.qml create mode 100644 src/controls/templates/private/GenericDrawerIcon.qml create mode 100644 src/controls/templates/private/IconPropertiesGroup.qml create mode 100644 src/controls/templates/private/MenuIcon.qml create mode 100644 src/controls/templates/private/PassiveNotification.qml create mode 100644 src/controls/templates/private/ScrollView.qml create mode 100644 src/controls/templates/qmldir create mode 100644 src/delegaterecycler.cpp create mode 100644 src/delegaterecycler.h create mode 100644 src/desktopicon.cpp create mode 100644 src/desktopicon.h create mode 100644 src/enums.cpp create mode 100644 src/enums.h create mode 100644 src/formlayoutattached.cpp create mode 100644 src/formlayoutattached.h create mode 100644 src/kirigamiplugin.cpp create mode 100644 src/kirigamiplugin.h create mode 100644 src/libkirigami/CMakeLists.txt create mode 100644 src/libkirigami/basictheme.cpp create mode 100644 src/libkirigami/basictheme_p.h create mode 100644 src/libkirigami/kirigamipluginfactory.cpp create mode 100644 src/libkirigami/kirigamipluginfactory.h create mode 100644 src/libkirigami/org.kde.KWin.TabletModeManager.xml create mode 100644 src/libkirigami/platformtheme.cpp create mode 100644 src/libkirigami/platformtheme.h create mode 100644 src/libkirigami/tabletmodewatcher.cpp create mode 100644 src/libkirigami/tabletmodewatcher.h create mode 100644 src/mnemonicattached.cpp create mode 100644 src/mnemonicattached.h create mode 100644 src/qmldir create mode 100644 src/scenepositionattached.cpp create mode 100644 src/scenepositionattached.h create mode 100644 src/settings.cpp create mode 100644 src/settings.h create mode 100644 src/styles/Material/AbstractListItem.qml create mode 100644 src/styles/Material/Label.qml create mode 100644 src/styles/Material/SwipeListItem.qml create mode 100644 src/styles/Material/Theme.qml create mode 100644 src/styles/org.kde.desktop/AbstractApplicationHeader.qml create mode 100644 src/styles/org.kde.desktop/AbstractListItem.qml create mode 100644 src/styles/org.kde.desktop/ApplicationWindow.qml create mode 100644 src/styles/org.kde.desktop/SwipeListItem.qml create mode 100644 src/styles/org.kde.desktop/Theme.qml create mode 100644 src/styles/org.kde.desktop/Units.qml create mode 100644 tests/KeyboardListTest.qml create mode 100644 tests/KeyboardTest.qml create mode 100644 tests/actionsMenu.qml create mode 100644 tests/cardsList.qml diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000..bc0df43 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "phabricator.uri" : "https://phabricator.kde.org/" +} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a9d35c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..103d763 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,132 @@ +cmake_minimum_required(VERSION 3.5) + +set(KF5_VERSION "5.54.0") # handled by release scripts +set(KF5_DEP_VERSION "5.54.0") # handled by release scripts + +project(kirigami2 VERSION ${KF5_VERSION}) + +set(REQUIRED_QT_VERSION 5.9.0) + +SET(CMAKE_CXX_STANDARD 11) + +################# Disallow in-source build ################# + +if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "kirigami requires an out of source build. Please create a separate build directory and run 'cmake path_to_kirigami [options]' there.") +endif() + +option(BUILD_SHARED_LIBS "Build a shared module" ON) +option(DESKTOP_ENABLED "Build and install The Desktop style" ON) +option(STATIC_LIBRARY "Build as a static library (deprecated, use BUILD_SHARED_LIBS instead)" OFF) +option(BUILD_EXAMPLES "Build and install examples" OFF) +option(DISABLE_DBUS "Build without D-Bus support" OFF) + +if(NOT BUILD_SHARED_LIBS) + set(STATIC_LIBRARY 1) +elseif(STATIC_LIBRARY) + set(BUILD_SHARED_LIBS 0) +endif() + +# Make CPack available to easy generate binary packages +include(CPack) +include(FeatureSummary) + +find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Gui Svg QuickControls2) +if (BUILD_TESTING) + find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG QUIET) +endif() + +set(CMAKE_AUTOMOC ON) +set(AUTOMOC_MOC_OPTIONS -Muri=org.kde.kirigami) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(STATIC_LIBRARY) + add_definitions(-DKIRIGAMI_BUILD_TYPE_STATIC) + add_definitions(-DQT_PLUGIN) + add_definitions(-DQT_STATICPLUGIN=1) +else(STATIC_LIBRARY) + if (BUILD_TESTING) + add_subdirectory(autotests) + endif() +endif(STATIC_LIBRARY) + +################# set KDE specific information ################# + +find_package(ECM 5.54.0 NO_MODULE) +set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") + +# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) + +include(GenerateExportHeader) +include(ECMSetupVersion) +include(ECMGenerateHeaders) +include(CMakePackageConfigHelpers) +include(ECMPoQmTools) +include(ECMQMLModules) +include(KDEInstallDirs) +include(KDECMakeSettings) +include(ECMQtDeclareLoggingCategory) +include(ECMAddQch) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) + +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Kirigami2") + +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF5Kirigami2Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF5Kirigami2Config.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + PATH_VARS KF5_INCLUDE_INSTALL_DIR CMAKE_INSTALL_PREFIX +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/KF5Kirigami2Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5Kirigami2ConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/KF5Kirigami2Macros.cmake" + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel +) + +install(EXPORT KF5Kirigami2Targets + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + FILE KF5Kirigami2Targets.cmake + NAMESPACE KF5:: +) + + +ecm_setup_version(${KF5_VERSION} + VARIABLE_PREFIX KIRIGAMI2 + VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kirigami_version.h" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5Kirigami2ConfigVersion.cmake" + SOVERSION 5 +) + +#use dbus on linux, bsd etc, but not andoid and apple stuff +if (UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT(APPLE) AND NOT(DISABLE_DBUS)) + find_package(Qt5DBus) + add_definitions(-DKIRIGAMI_ENABLE_DBUS) +endif() + +if(BUILD_EXAMPLES AND CMAKE_SYSTEM_NAME STREQUAL "Android") + find_package(Qt5AndroidExtras ${REQUIRED_QT_VERSION} REQUIRED) +endif() + + +ecm_find_qmlmodule(QtGraphicalEffects 1.0) + + +add_subdirectory(src) + +if (BUILD_EXAMPLES AND NOT STATIC_LIBRARY) + add_subdirectory(examples) +endif() + +if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") + ecm_install_po_files_as_qm(po) +endif() + +feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) + diff --git a/KF5Kirigami2Config.cmake.in b/KF5Kirigami2Config.cmake.in new file mode 100644 index 0000000..3196055 --- /dev/null +++ b/KF5Kirigami2Config.cmake.in @@ -0,0 +1,15 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt5Core @REQUIRED_QT_VERSION@) + +# Any changes in this ".cmake" file will be overwritten by CMake, the source is the ".cmake.in" file. + +include("${CMAKE_CURRENT_LIST_DIR}/KF5Kirigami2Targets.cmake") + +set(Kirigami2_INSTALL_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@") + +#set(Kirigami2_LIBRARIES KF5::Kirigami2) + +include("${CMAKE_CURRENT_LIST_DIR}/KF5Kirigami2Macros.cmake") +@PACKAGE_INCLUDE_QCHTARGETS@ diff --git a/KF5Kirigami2Macros.cmake b/KF5Kirigami2Macros.cmake new file mode 100644 index 0000000..f5b8eb7 --- /dev/null +++ b/KF5Kirigami2Macros.cmake @@ -0,0 +1,93 @@ + +include(CMakeParseArguments) +include(ExternalProject) + + +function(kirigami_package_breeze_icons) + set(_multiValueArgs ICONS) + cmake_parse_arguments(ARG "" "" "${_multiValueArgs}" ${ARGN} ) + + if(NOT ARG_ICONS) + message(FATAL_ERROR "No ICONS argument given to kirigami_package_breeze_icons") + endif() + + #include icons used by Kirigami components themselves + set(ARG_ICONS ${ARG_ICONS} go-next go-previous go-up handle-sort overflow-menu-left overflow-menu-right go-next-symbolic go-next-symbolic-rtl go-previous-symbolic go-previous-symbolic-rtl overflow-menu) + + function(_find_breeze_icon icon varName) + #HACKY + SET(path "") + file(GLOB_RECURSE path ${_BREEZEICONS_DIR}/icons/*/48/${icon}.svg ) + + #search in other sizes as well + if (path STREQUAL "") + file(GLOB_RECURSE path ${_BREEZEICONS_DIR}/icons/*/32/${icon}.svg ) + if (path STREQUAL "") + file(GLOB_RECURSE path ${_BREEZEICONS_DIR}/icons/*/22/${icon}.svg ) + endif() + endif() + if (path STREQUAL "") + file(GLOB_RECURSE path ${_BREEZEICONS_DIR}/icons/*/symbolic/${icon}.svg ) + endif() + if (path STREQUAL "") + return() + endif() + + list(LENGTH path _count_paths) + if (_count_paths GREATER 1) + message(WARNING "Found more than one version of '${icon}': ${path}") + endif() + list(GET path 0 path) + get_filename_component(path "${path}" REALPATH) + + SET(${varName} ${path} PARENT_SCOPE) + endfunction() + + if (BREEZEICONS_DIR AND NOT EXISTS ${BREEZEICONS_DIR}) + message(FATAL_ERROR "BREEZEICONS_DIR variable does not point to existing dir: \"${BREEZEICONS_DIR}\"") + endif() + + set(_BREEZEICONS_DIR "${BREEZEICONS_DIR}") + + #FIXME: this is a terrible hack + if(NOT _BREEZEICONS_DIR) + set(_BREEZEICONS_DIR "${CMAKE_BINARY_DIR}/breeze-icons/src/breeze-icons") + + # replacement for ExternalProject_Add not yet working + # first time config? + if (NOT EXISTS ${_BREEZEICONS_DIR}) + find_package(Git) + execute_process(COMMAND ${GIT_EXECUTABLE} clone --depth 1 git://anongit.kde.org/breeze-icons.git ${_BREEZEICONS_DIR}) + endif() + + # external projects are only pulled at make time, not configure time + # so this is too late to work with the _find_breeze_icon() method + # _find_breeze_icon() would need to be turned into a target/command + if (FALSE) + ExternalProject_Add( + breeze-icons + PREFIX breeze-icons + GIT_REPOSITORY git://anongit.kde.org/breeze-icons.git + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + ) + endif() + endif() + + message (STATUS "Found external breeze icons:") + foreach(_iconName ${ARG_ICONS}) + set(_iconPath "") + _find_breeze_icon(${_iconName} _iconPath) + message (STATUS ${_iconPath}) + if (EXISTS ${_iconPath}) + install(FILES ${_iconPath} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/icons/ RENAME ${_iconName}.svg) + endif() + endforeach() + + #generate an index.theme that qiconloader can understand + file(WRITE ${CMAKE_BINARY_DIR}/index.theme "[Icon Theme]\nName=Breeze\nDirectories=icons\n[icons]\nSize=32\nType=Scalable") + install(FILES ${CMAKE_BINARY_DIR}/index.theme DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/) +endfunction() + diff --git a/LICENSE.LGPL-2 b/LICENSE.LGPL-2 new file mode 100644 index 0000000..5bc8fb2 --- /dev/null +++ b/LICENSE.LGPL-2 @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Mainpage.dox b/Mainpage.dox new file mode 100644 index 0000000..f07b295 --- /dev/null +++ b/Mainpage.dox @@ -0,0 +1,211 @@ +/* + This file is part of Kirigami + Copyright (C) 2016 Marco Martin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +/** \mainpage kirigami + + +\section overview Introduction +Kirigami is a set of QtQuick components at the moment targeted for mobile use (in the future desktop as well) targeting both Plasma Mobile and Android. It’s not a whole set of components, all the “Primitive” ones like buttons and textboxes are a job for QtQuickControls (soon QtQuickControls2) but it’s a set of high level components to make the creation of applications that look and feel great on mobile as well as desktop devices and follow the Kirigami Human Interface Guidelines . +The target of those components is anybody that wants to do an application using QtQuick as its main UI, especially if targeting a mobile platform, without adding many dependencies. They work on a variety of platforms, such as Plasma Mobile, Desktop Linux, Android and Windows. +It is a Tier-1 KDE Framework starting with KDE Frameworks 5.37. + +\section components Main Components +- \link org::kde::kirigami::ApplicationWindow ApplicationWindow \endlink +- \link org::kde::kirigami::Action Action \endlink +- \link org::kde::kirigami::GlobalDrawer GlobalDrawer \endlink +- \link org::kde::kirigami::ContextDrawer ContextDrawer \endlink +- \link org::kde::kirigami::OverlayDrawer OverlayDrawer \endlink +- \link org::kde::kirigami::Page Page \endlink +- \link org::kde::kirigami::ScrollablePage ScrollablePage \endlink +- \link org::kde::kirigami::OverlaySheet OverlaySheet \endlink +- \link org::kde::kirigami::Theme Theme \endlink +- \link org::kde::kirigami::Units Units \endlink +- \link org::kde::kirigami::Icon Icon \endlink +- \link org::kde::kirigami::AbstractApplicationHeader AbstractApplicationHeader \endlink +- \link org::kde::kirigami::AbstractApplicationWindow AbstractApplicationWindow \endlink +- \link org::kde::kirigami::AbstractListItem AbstractListItem \endlink +- \link org::kde::kirigami::ApplicationHeader ApplicationHeader \endlink +- \link org::kde::kirigami::BasicListItem BasicListItem \endlink +- \link org::kde::kirigami::SwipeListItem SwipeListItem \endlink +- \link org::kde::kirigami::Heading Heading \endlink +- \link org::kde::kirigami::Label Label \endlink + + +\section example Minimal Example + +@code +import QtQuick 2.1 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + header: Kirigami.ApplicationHeader {} + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + pageStack.initialPage: mainPageComponent + Component { + id: mainPageComponent + Kirigami.ScrollablePage { + title: "Hello" + actions { + main: Kirigami.Action { + iconName: sheet.sheetOpen ? "dialog-cancel" : "document-edit" + onTriggered: { + print("Action button in buttons page clicked"); + sheet.sheetOpen = !sheet.sheetOpen + } + } + left: Kirigami.Action { + iconName: "go-previous" + onTriggered: { + print("Left action triggered") + } + } + right: Kirigami.Action { + iconName: "go-next" + onTriggered: { + print("Right action triggered") + } + } + contextualActions: [ + Kirigami.Action { + text:"Action for buttons" + iconName: "bookmarks" + onTriggered: print("Action 1 clicked") + }, + Kirigami.Action { + text:"Action 2" + iconName: "folder" + enabled: false + }, + Kirigami.Action { + text: "Action for Sheet" + visible: sheet.sheetOpen + } + ] + } + Kirigami.OverlaySheet { + id: sheet + onSheetOpenChanged: page.actions.main.checked = sheetOpen + QQC2.Label { + wrapMode: Text.WordWrap + text: "Lorem ipsum dolor sit amet" + } + } + //Page contents... + } + } +} +@endcode + +\section deployment Deployment +CMake is recomended for both building Kirigami and the project using it, QMake is supported as well, so we can have several configurations, depending what is the host build system and how the deployment needs to be done. +Kirigami can be built in two ways: both as a module or statically linked in the application, leading to four combinations: +* Kirigami built as a module with CMake +* Kirigami statically built with CMake (needed to link statically from applications built with CMake) +* Kirigami built as a module with QMake +* Kirigami statically built with QMake (needed to link statically from applications built with QMake) + +The simplest and recomended way to use Kirigami is to just use the module provided by the Linux distribution, or build it as a module and deploy it together the main application. +For example when building an application on Android with CMake, if Kirigami for Android is built and installed in the same temporary directory before the application, the create-apk- step of the application will include the Kirigami files as well in the APK. + +If QMake needs to be used, it's recomended to follow the schema of the example app present in the folder examples/minimalqmake of the Kirigami source code. + +It will use Kirigami statically linked only on Android, while on desktop systems it will use the version provided by the distribution. What platforms use the static version and what the dynamic one can be freely adjusted. +The application needs to have a folder called "3rdparty" containing clones of two KDE repositories: kirigami and breeze-icons (available at git://anongit.kde.org/kirigami.git and git://anongit.kde.org/breeze-icons.git). +The relevant part in the .pro file is: + +@code +android: { + include(3rdparty/kirigami/kirigami.pri) +} +@endcode + +While the main.cpp file will have something like: +@code +#include +#include +#ifdef Q_OS_ANDROID +#include "./3rdparty/kirigami/src/kirigamiplugin.h" +#endif + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + +#ifdef Q_OS_ANDROID + KirigamiPlugin::getInstance().registerTypes(); +#endif +.... +} +@endcode + +@authors +Marco Martin \
+Sebastian Kuegler \
+Aleix Pol Gonzalez \
+Dirk Hohndel \
+ +@maintainers +Marco Martin \ + +@licenses +@lgpl + +*/ + + +// DOXYGEN_SET_RECURSIVE = YES +// DOXYGEN_SET_EXCLUDE_PATTERNS += *_p.h */private/* */examples/* +// DOXYGEN_SET_PROJECT_NAME = Kirigami +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/README.md b/README.md new file mode 100644 index 0000000..476112e --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# Kirigami + +QtQuick plugins to build user interfaces based on the KDE UX guidelines + +## Introduction + +Kirigami is a set of QtQuick components at the moment targeted for mobile use (in the future desktop as well) targeting both Plasma Mobile and Android. It’s not a whole set of components, all the “Primitive” ones like buttons and textboxes are a job for QtQuickControls (soon QtQuickControls2) but it’s a set of high level components to make the creation of applications that look and feel great on mobile as well as desktop devices and follow the Kirigami Human Interface Guidelines. + +## Build examples to desktop +Build all examples available +```sh +mkdir build +cd build +cmake .. -DBUILD_EXAMPLES=ON +make +``` +Than, you can run: +```sh +./examples/applicationitemapp/applicationitemapp +# or +./examples/galleryapp/kirigami2gallery +``` + +## Build the gallery example app on Android: +Make sure to install **android-sdk**, **android-ndk** and **android-qt5-arch**, where **arch** should be the same architecture that you aim to deploy. +```sh +mkdir build +cd build +cmake .. \ + -DQTANDROID_EXPORTED_TARGET=kirigami2gallery \ + -DBUILD_EXAMPLES=on \ + -DANDROID_APK_DIR=../examples/galleryapp \ + -DECM_DIR=/path/to/share/ECM/cmake \ + -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake \ + -DECM_ADDITIONAL_FIND_ROOT_PATH=/path/to/Qt5.7.0/5.7/{arch} \ + -DCMAKE_PREFIX_PATH=/path/to/Qt5.7.0/5.7/{arch}/path/to/Qt5Core \ + -DANDROID_NDK=/path/to/Android/Sdk/ndk-bundle \ + -DANDROID_SDK_ROOT=/path/to/Android/Sdk/ \ + -DANDROID_SDK_BUILD_TOOLS_REVISION=26.0.2 \ + -DCMAKE_INSTALL_PREFIX=/path/to/dummy/install/prefix +``` + +You need a `-DCMAKE_INSTALL_PREFIX` to somewhere in your home, but using an absolute path. + +If you have a local checkout of the breeze-icons repo, you can avoid the cloning of the build dir +by passing also `-DBREEZEICONS_DIR=/path/to/existing/sources/of/breeze-icons` + +``` +make create-apk-kirigami2gallery +``` + +`./kirigami2gallery_build_apk/build/outputs/apk/kirigami2gallery_build_apk-debug.apk` will be generated + +To directly install on a phone: +``` +adb install -r ./kirigami2gallery_build_apk/build/outputs/apk/kirigami2gallery_build_apk-debug.apk +``` +To perform this, your device need to be configureted with `USB debugging` and `install via USB` in `Developer options`. + +> Some ambient variables must be set before the process: `ANDROID_NDK`, `ANDROID_SDK_ROOT`, `Qt5_android` and `JAVA_HOME` +``` +export ANDROID_NDK=/path/to/android-ndk +export ANDROID_SDK_ROOT=/path/to/android-sdk +export Qt5_android=/path/to/android-qt5/5.7.0/{arch} +export PATH=$ANDROID_SDK_ROOT/platform-tools/:$PATH +# adapt the following path to your ant installation +export ANT=/usr/bin/ant +export JAVA_HOME=/path/to/lib/jvm/java-8-openjdk/ +``` +# Build on your application Android, ship it together Kirigami + +1) Build kirigami +``` + +use the same procedure mentioned above (but without BUILD_EXAMPLES switch + +cd into kirigami sources directory. + +mkdir build +cd build + +cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/share/ECM/toolchain/Android.cmake -DCMAKE_PREFIX_PATH=/path/to/Qt5.7.0/5.7/android_armv7/ -DCMAKE_INSTALL_PREFIX=/path/to/dummy/install/prefix -DECM_DIR=/path/to/share/ECM/cmake + +``` +make +make install +``` +(note, omit the make create-apk-kirigami2gallery step) + +2) Build your application +``` +This guide assumes you build your application with CMake and use Extra-cmake-modules from KDE frameworks. + + +cd into your application sources directory. + +mkdir build +cd build + +cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/share/ECM/toolchain/Android.cmake -DQTANDROID_EXPORTED_TARGET=yourapp -DANDROID_APK_DIR=../examples/galleryapp/ -DCMAKE_PREFIX_PATH=/path/to/Qt5.7.0/5.7/android_armv7/ -DCMAKE_INSTALL_PREFIX=/path/to/dummy/install/prefix + +Note, -DCMAKE_INSTALL_PREFIX folder will be the same as where kirigami was installed, since you need to create an apk package that contains both the kirigami build and the build of your application. + +``` +make +make install +make create-apk-yourapp +``` + +where make create-apk-yourapp dependes from the actual name of your application + +# Build a QMake-based application + +* Base upon the example in examples/minimalqmake +* on android, it builds it statically, on desktop systems it uses the one distribution provided (static linking mode may be useful for other systems such as iOS or Windows) +* in order to have static linking working, clone kirigami.git and breeze-icons.git under the 3rdparty folder +* in your main.cpp you'll have, only on android KirigamiPlugin::getInstance().registerTypes(); which will make the import work +* qtcreator should be able to do deployment on android out of the box + diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt new file mode 100644 index 0000000..02338bb --- /dev/null +++ b/autotests/CMakeLists.txt @@ -0,0 +1,9 @@ +if(NOT Qt5Test_FOUND) + message(STATUS "Qt5Test not found, autotests will not be built.") + return() +endif() + +add_test(NAME qmltests COMMAND qmltestrunner WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +set_property(TEST qmltests PROPERTY ENVIRONMENT +"QML2_IMPORT_PATH=${CMAKE_BINARY_DIR}/bin") diff --git a/autotests/tst_keynavigation.qml b/autotests/tst_keynavigation.qml new file mode 100644 index 0000000..812e57b --- /dev/null +++ b/autotests/tst_keynavigation.qml @@ -0,0 +1,68 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.1 +import org.kde.kirigami 2.4 as Kirigami +import QtTest 1.0 +import "../tests" + +TestCase { + id: testCase + width: 400 + height: 400 + when: mainWindow.visible + name: "KeyboardNavigation" + + KeyboardTest { + id: mainWindow + width: 480 + height: 360 + visible: true + } + + SignalSpy { + id: spyActive + target: mainWindow + signalName: "activeChanged" + } + SignalSpy { + id: spyLastKey + target: mainWindow.pageStack.currentItem + signalName: "lastKeyChanged" + } + + function test_press() { + compare(mainWindow.pageStack.depth, 2) + compare(mainWindow.pageStack.currentIndex, 1) + if (!mainWindow.active) + spyActive.wait(5000) + verify(mainWindow.active) + keyClick("A") + spyLastKey.wait() + compare(mainWindow.pageStack.currentItem.lastKey, "A") + keyClick(Qt.Key_Left, Qt.AltModifier) + compare(mainWindow.pageStack.currentIndex, 0) + compare(mainWindow.pageStack.currentItem.lastKey, "") + keyClick("B") + spyLastKey.wait() + compare(mainWindow.pageStack.currentItem.lastKey, "B") + } +} diff --git a/autotests/tst_listskeynavigation.qml b/autotests/tst_listskeynavigation.qml new file mode 100644 index 0000000..62e23a7 --- /dev/null +++ b/autotests/tst_listskeynavigation.qml @@ -0,0 +1,64 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.1 +import org.kde.kirigami 2.4 as Kirigami +import QtTest 1.0 +import "../tests" + +TestCase { + id: testCase + width: 400 + height: 400 + when: mainWindow.visible + name: "KeyboardListsNavigation" + + KeyboardListTest { + id: mainWindow + width: 480 + height: 360 + visible: true + } + + SignalSpy { + id: spyActive + target: mainWindow + signalName: "activeChanged" + } + SignalSpy { + id: spyCurrentIndex + target: mainWindow.pageStack.currentItem.flickable + signalName: "currentIndexChanged" + } + + function test_press() { + compare(mainWindow.pageStack.depth, 1) + compare(mainWindow.pageStack.currentIndex, 0) + if (!mainWindow.active) + spyActive.wait(5000) + verify(mainWindow.active) + compare(mainWindow.pageStack.currentItem.flickable.currentIndex, 0) + keyClick(Qt.Key_Down) + spyCurrentIndex.wait() + compare(mainWindow.pageStack.currentItem.flickable.currentIndex, 1) + } +} diff --git a/autotests/tst_pagerow.qml b/autotests/tst_pagerow.qml new file mode 100644 index 0000000..76405b6 --- /dev/null +++ b/autotests/tst_pagerow.qml @@ -0,0 +1,141 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.1 +import org.kde.kirigami 2.4 as Kirigami +import QtTest 1.0 + +TestCase { + id: testCase +// when: mainWindow.visible + width: 400 + height: 400 +// visible: true + when: mainWindow.visible + name: "GoBack" + + function applicationWindow() { return mainWindow; } + + Kirigami.ApplicationWindow { + id: mainWindow + width: 480 + height: 360 + visible: true + pageStack.initialPage: Kirigami.Page { + Rectangle { + anchors.fill: parent + color: "green" + } + } + } + + Component { + id: randomPage + Kirigami.Page { + Rectangle { + anchors.fill: parent + color: "red" + } + } + } + + SignalSpy { + id: spyCurrentIndex + target: mainWindow.pageStack + signalName: "currentIndexChanged" + } + + SignalSpy { + id: spyActive + target: mainWindow + signalName: "activeChanged" + } + + function init() { + mainWindow.pageStack.clear() + spyActive.clear() + spyCurrentIndex.clear() + } + + function test_pop() { + compare(mainWindow.pageStack.depth, 0) + mainWindow.pageStack.push(randomPage) + compare(mainWindow.pageStack.depth, 1) + mainWindow.pageStack.pop() + compare(mainWindow.pageStack.depth, 0) + } + + function test_goBack() { + compare(mainWindow.pageStack.depth, 0) + mainWindow.pageStack.push(randomPage) + mainWindow.pageStack.push(randomPage) + compare(mainWindow.pageStack.depth, 2) + compare(mainWindow.pageStack.currentIndex, 1) + compare(spyCurrentIndex.count, 2) + spyActive.clear() + mainWindow.requestActivate() + spyCurrentIndex.clear() + if (!mainWindow.active) + spyActive.wait() + verify(mainWindow.active) + keyClick(Qt.Key_Left, Qt.AltModifier) + + spyCurrentIndex.wait() + + compare(mainWindow.pageStack.depth, 2) + compare(mainWindow.pageStack.currentIndex, 0) + compare(spyCurrentIndex.count, 1) + mainWindow.pageStack.pop() + compare(mainWindow.pageStack.depth, 1) + } + + property int destructions: 0 + Component { + id: destroyedPage + Kirigami.Page { + id: page + Rectangle { + anchors.fill: parent + color: "blue" + Component.onDestruction: { + console.log("ko", page) + testCase.destructions++ + } + } + } + } + SignalSpy { + id: spyDestructions + target: testCase + signalName: "destructionsChanged" + } + function test_clearPages() { + mainWindow.pageStack.push(destroyedPage) + mainWindow.pageStack.push(destroyedPage) + mainWindow.pageStack.push(destroyedPage) + compare(mainWindow.pageStack.depth, 3) + mainWindow.pageStack.clear() + + compare(mainWindow.pageStack.depth, 0) + console.log(spyDestructions.wait()) + compare(testCase.destructions, 3) + } +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..217c8b9 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(applicationitemapp) + diff --git a/examples/applicationitemapp/CMakeLists.txt b/examples/applicationitemapp/CMakeLists.txt new file mode 100644 index 0000000..5f6102b --- /dev/null +++ b/examples/applicationitemapp/CMakeLists.txt @@ -0,0 +1,13 @@ + +set(applicationitemapp_SRCS + main.cpp + ) + +qt5_add_resources(RESOURCES resources.qrc) + +add_executable(applicationitemapp ${applicationitemapp_SRCS} ${RESOURCES}) +target_link_libraries(applicationitemapp Qt5::Core Qt5::Qml Qt5::Quick Qt5::Svg) + +install(TARGETS applicationitemapp ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +include(${CMAKE_SOURCE_DIR}/KF5Kirigami2Macros.cmake) diff --git a/examples/applicationitemapp/main.cpp b/examples/applicationitemapp/main.cpp new file mode 100644 index 0000000..a695c8a --- /dev/null +++ b/examples/applicationitemapp/main.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + + +Q_DECL_EXPORT int main(int argc, char *argv[]) +{ + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QApplication app(argc, argv); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl(QStringLiteral("qrc:///main.qml"))); + view.show(); + + return app.exec(); +} diff --git a/examples/applicationitemapp/main.qml b/examples/applicationitemapp/main.qml new file mode 100644 index 0000000..9d02016 --- /dev/null +++ b/examples/applicationitemapp/main.qml @@ -0,0 +1,81 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationItem { + id: root + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + handleVisible: true + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + + pageStack.initialPage: mainPageComponent + + Component { + id: mainPageComponent + Kirigami.Page { + title: "Hello" + actions { + contextualActions: [ + Kirigami.Action { + text: "action 1" + }, + Kirigami.Action { + text: "action 2" + } + ] + } + Rectangle { + color: "red" + anchors.fill: parent + } + } + } + + +} diff --git a/examples/applicationitemapp/resources.qrc b/examples/applicationitemapp/resources.qrc new file mode 100644 index 0000000..89f4bbe --- /dev/null +++ b/examples/applicationitemapp/resources.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/examples/minimalqmake/3rdparty/README b/examples/minimalqmake/3rdparty/README new file mode 100644 index 0000000..aad19dd --- /dev/null +++ b/examples/minimalqmake/3rdparty/README @@ -0,0 +1,6 @@ +Add here, with either a script that does a git checkout +or as git submodules the two projects: + +git://anongit.kde.org/kirigami.git +git://anongit.kde.org/breeze-icons.git + diff --git a/examples/minimalqmake/Page1.qml b/examples/minimalqmake/Page1.qml new file mode 100644 index 0000000..9dec282 --- /dev/null +++ b/examples/minimalqmake/Page1.qml @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 + +Page1Form { + button1.onClicked: { + console.log("Button Pressed. Entered text: " + textField1.text); + } +} diff --git a/examples/minimalqmake/Page1Form.ui.qml b/examples/minimalqmake/Page1Form.ui.qml new file mode 100644 index 0000000..4f87915 --- /dev/null +++ b/examples/minimalqmake/Page1Form.ui.qml @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.Page { + title: qsTr("Page 1") + property alias textField1: textField1 + property alias button1: button1 + + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + anchors.top: parent.top + + TextField { + id: textField1 + placeholderText: qsTr("Text Field") + } + + Button { + id: button1 + text: qsTr("Press Me") + } + } +} diff --git a/examples/minimalqmake/kirigami-icons.qrc b/examples/minimalqmake/kirigami-icons.qrc new file mode 100644 index 0000000..73cae11 --- /dev/null +++ b/examples/minimalqmake/kirigami-icons.qrc @@ -0,0 +1,16 @@ + + + 3rdparty/breeze-icons/icons/actions/32/application-menu.svg + 3rdparty/breeze-icons/icons/actions/32/document-decrypt.svg + 3rdparty/breeze-icons/icons/actions/32/folder-sync.svg + 3rdparty/breeze-icons/icons/actions/symbolic/go-next-symbolic.svg + 3rdparty/breeze-icons/icons/actions/symbolic/go-previous-symbolic.svg + 3rdparty/breeze-icons/icons/actions/22/go-up.svg + 3rdparty/breeze-icons/icons/actions/22/handle-left.svg + 3rdparty/breeze-icons/icons/actions/22/overflow-menu.svg + 3rdparty/breeze-icons/icons/actions/22/handle-right.svg + 3rdparty/breeze-icons/icons/actions/32/view-list-icons.svg + 3rdparty/breeze-icons/icons/categories/32/applications-graphics.svg + 3rdparty/breeze-icons/icons/actions/symbolic/media-record-symbolic.svg + + diff --git a/examples/minimalqmake/main.cpp b/examples/minimalqmake/main.cpp new file mode 100644 index 0000000..887d4ce --- /dev/null +++ b/examples/minimalqmake/main.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#ifdef Q_OS_ANDROID +#include "./3rdparty/kirigami/src/kirigamiplugin.h" +#endif + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + +#ifdef Q_OS_ANDROID + KirigamiPlugin::getInstance().registerTypes(); +#endif + + engine.load(QUrl(QLatin1String("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/minimalqmake/main.qml b/examples/minimalqmake/main.qml new file mode 100644 index 0000000..2a56ad2 --- /dev/null +++ b/examples/minimalqmake/main.qml @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + visible: true + title: qsTr("Hello World") + + header: Kirigami.ApplicationHeader {} + pageStack.initialPage: Page1 {} + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } +} diff --git a/examples/minimalqmake/minimalqmake.pro b/examples/minimalqmake/minimalqmake.pro new file mode 100644 index 0000000..fdd0e18 --- /dev/null +++ b/examples/minimalqmake/minimalqmake.pro @@ -0,0 +1,35 @@ +TEMPLATE = app + +QT += qml quick + +android: { + include(3rdparty/kirigami/kirigami.pri) +} + +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/examples/minimalqmake/qml.qrc b/examples/minimalqmake/qml.qrc new file mode 100644 index 0000000..44587bd --- /dev/null +++ b/examples/minimalqmake/qml.qrc @@ -0,0 +1,8 @@ + + + main.qml + Page1.qml + Page1Form.ui.qml + qtquickcontrols2.conf + + diff --git a/examples/minimalqmake/qtquickcontrols2.conf b/examples/minimalqmake/qtquickcontrols2.conf new file mode 100644 index 0000000..c22fe2d --- /dev/null +++ b/examples/minimalqmake/qtquickcontrols2.conf @@ -0,0 +1,15 @@ +; This file can be edited to change the style of the application +; See Styling Qt Quick Controls 2 in the documentation for details: +; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html + +[Controls] +Style=Material + +[Universal] +Theme=Light +;Accent=Steel + +[Material] +Theme=Light +Accent=BlueGrey +Primary=BlueGray diff --git a/examples/multiplatformnotesapp/NotesGeneral.qml b/examples/multiplatformnotesapp/NotesGeneral.qml new file mode 100644 index 0000000..36b809f --- /dev/null +++ b/examples/multiplatformnotesapp/NotesGeneral.qml @@ -0,0 +1,216 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + property string currentFile + + + header: Kirigami.ToolBarApplicationHeader { + } + + pageStack.initialPage: iconView + + Kirigami.ScrollablePage { + id: iconView + title: "Notes" + actions { + contextualActions: [ + Kirigami.Action { + id: sortAction + iconName: "view-sort-ascending-symbolic" + tooltip: "Sort Ascending" + } + ] + } + background: Rectangle { + color: Kirigami.Thmeme.backgroundColor + } + + GridView { + id: view + model: 100 + cellWidth: Kirigami.Units.gridUnit * 9 + cellHeight: cellWidth + currentIndex: -1 + highlightMoveDuration: 0 + highlight: Rectangle { + color: Kirigami.Theme.highlightColor + } + delegate: MouseArea { + width: view.cellWidth + height: view.cellHeight + Kirigami.Icon { + source: "text-plain" + anchors { + fill: parent + margins: Kirigami.Units.gridUnit + } + QQC2.Label { + anchors { + top: parent.bottom + horizontalCenter: parent.horizontalCenter + } + text: "File " + modelData + } + } + onClicked: { + view.currentIndex = index; + root.currentFile = "File " + modelData; + if (root.pageStack.depth < 2) { + root.pageStack.push(editorComponent); + } + root.pageStack.currentIndex = 1 + } + } + } + } + + Component { + id: editorComponent + Kirigami.ScrollablePage { + id: editor + title: root.currentFile + actions { + main: Kirigami.Action { + id: shareAction + iconName: "document-share" + text: "Share..." + tooltip: "Share this document with your device" + checkable: true + onCheckedChanged: sheet.sheetOpen = checked; + } + contextualActions: [ + Kirigami.Action { + iconName: "format-text-bold-symbolic" + tooltip: "Bold" + }, + Kirigami.Action { + iconName: "format-text-underline-symbolic" + tooltip: "Underline" + }, + Kirigami.Action { + iconName: "format-text-italic-symbolic" + tooltip: "Italic" + } + ] + } + background: Rectangle { + color: Kirigami.Theme.backgroundColor + Rectangle { + anchors.fill: parent + color: "yellow" + opacity: 0.2 + } + } + + Kirigami.OverlaySheet { + id: sheet + onSheetOpenChanged: shareAction.checked = sheetOpen + ListView { + implicitWidth: Kirigami.Units.gridUnit * 30 + model: ListModel { + ListElement { + title: "Share with phone \"Nokia 3310\"" + description: "You selected this phone 12 times before. It's currently connected via bluetooth" + buttonText: "Push Sync" + } + ListElement { + title: "Share with phone \"My other Nexus5\"" + description: "You selected this phone 0 times before. It's currently connected to your laptop via Wifi" + buttonText: "push sync" + } + ListElement { + title: "Share with NextCloud" + description: "You currently do not have a server set up for sharing and storing notes from Katie. If you want to set one up click here" + buttonText: "Setup..." + } + ListElement { + title: "Send document via email" + description: "This will send the document as an attached file to your own email for later sync" + buttonText: "Send As Email" + } + } + header: Kirigami.AbstractListItem { + height: Kirigami.Units.gridUnit * 6 + hoverEnabled: false + RowLayout { + Kirigami.Icon { + source: "documentinfo" + width: Kirigami.Units.iconSizes.large + height: width + } + QQC2.Label { + Layout.fillWidth: true + Layout.minimumWidth: 0 + wrapMode: Text.WordWrap + text: "This document has already automatically synced with your phone \"Dancepartymeister 12\". If you want to sync with another device or do further actions you can do that here" + } + } + } + delegate: Kirigami.AbstractListItem { + height: Kirigami.Units.gridUnit * 6 + hoverEnabled: false + //TODO: bug in overlaysheet + rightPadding: Kirigami.Units.gridUnit * 1.5 + RowLayout { + ColumnLayout { + Layout.fillWidth: true + Layout.minimumWidth: 0 + QQC2.Label { + wrapMode: Text.WordWrap + text: model.title + } + QQC2.Label { + Layout.fillWidth: true + Layout.minimumWidth: 0 + wrapMode: Text.WordWrap + text: model.description + } + } + QQC2.Button { + text: model.buttonText + onClicked: sheet.close() + } + } + } + } + } + QQC2.TextArea { + background: Item {} + wrapMode: TextEdit.WordWrap + selectByMouse: true + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sollicitudin, lorem at semper pretium, tortor nisl pellentesque risus, eget eleifend odio ipsum ac mi. Donec justo ex, elementum vitae gravida vel, pretium ac lacus. Duis non metus ac enim viverra auctor in non nunc. Sed sit amet luctus nisi. Proin justo nulla, vehicula eget porta sit amet, aliquet vitae dolor. Mauris sed odio auctor, tempus ipsum ac, placerat enim. Ut in dolor vel ante dictum auctor. + + Praesent blandit rhoncus augue. Phasellus consequat luctus pulvinar. Pellentesque rutrum laoreet dolor, sit amet pellentesque tellus mattis sed. Sed accumsan cursus tortor. Morbi et risus dolor. Nullam facilisis ipsum justo, nec sollicitudin mi pulvinar ac. Nulla facilisi. Donec maximus turpis eget mollis laoreet. Phasellus vel mauris et est mattis auctor eget sit amet turpis. Aliquam dignissim euismod purus, eu efficitur neque fermentum eu. Suspendisse potenti. Praesent mattis ex vitae neque rutrum tincidunt. Etiam placerat leo viverra pulvinar tincidunt. + + Proin vel rutrum massa. Proin volutpat aliquet dapibus. Maecenas aliquet elit eu venenatis venenatis. Ut elementum, lacus vel auctor auctor, velit massa elementum ligula, quis elementum ex nisi aliquam mauris. Nulla facilisi. Pellentesque aliquet egestas venenatis. Donec iaculis ultrices laoreet. Vestibulum cursus rhoncus sollicitudin. + + Proin quam libero, bibendum eget sodales id, gravida quis enim. Duis fermentum libero vitae sapien hendrerit, in tincidunt tortor semper. Nullam quam nisi, feugiat sed rutrum vitae, dignissim quis risus. Ut ultricies pellentesque est, ut gravida massa convallis sed. Ut placerat dui non felis interdum, id malesuada nulla ornare. Phasellus volutpat purus placerat velit porta tristique. Donec molestie leo in turpis bibendum pharetra. Fusce fermentum diam vitae neque laoreet, sed aliquam leo sollicitudin. + + Ut facilisis massa arcu, eu suscipit ante varius sed. Morbi augue leo, mattis eu tempor vitae, condimentum sed urna. Curabitur ac blandit orci. Vestibulum quis consequat nunc. Proin imperdiet commodo imperdiet. Aenean mattis augue et imperdiet ultricies. Ut id feugiat nulla, et sollicitudin dui. Etiam scelerisque ligula ac euismod hendrerit. Integer in quam nibh. Pellentesque risus massa, porttitor quis fermentum eu, dictum varius magna. Morbi euismod bibendum lacus efficitur pretium. Phasellus elementum porttitor enim nec dictum. Morbi et augue laoreet, convallis quam quis, egestas quam." + } + } + } +} diff --git a/examples/multiplatformnotesapp/notesDesktop.qml b/examples/multiplatformnotesapp/notesDesktop.qml new file mode 100644 index 0000000..8b296b9 --- /dev/null +++ b/examples/multiplatformnotesapp/notesDesktop.qml @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +NotesGeneral { + id: root + + header: Kirigami.ToolBarApplicationHeader { + } +} diff --git a/examples/multiplatformnotesapp/notesMobile.qml b/examples/multiplatformnotesapp/notesMobile.qml new file mode 100644 index 0000000..9085d8f --- /dev/null +++ b/examples/multiplatformnotesapp/notesMobile.qml @@ -0,0 +1,31 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +NotesGeneral { + id: root + + header: Kirigami.ApplicationHeader { + } + contextDrawer: Kirigami.ContextDrawer {} +} diff --git a/examples/qmakewithstaticplugin/3rdparty/README b/examples/qmakewithstaticplugin/3rdparty/README new file mode 100644 index 0000000..aad19dd --- /dev/null +++ b/examples/qmakewithstaticplugin/3rdparty/README @@ -0,0 +1,6 @@ +Add here, with either a script that does a git checkout +or as git submodules the two projects: + +git://anongit.kde.org/kirigami.git +git://anongit.kde.org/breeze-icons.git + diff --git a/examples/qmakewithstaticplugin/minimalqmake.pro b/examples/qmakewithstaticplugin/minimalqmake.pro new file mode 100644 index 0000000..fe95bd2 --- /dev/null +++ b/examples/qmakewithstaticplugin/minimalqmake.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + kirigami \ + src + +src.subdir = src +kirigami.subdir = 3rdparty/kirigami + +src.depends = kirigami diff --git a/examples/qmakewithstaticplugin/src/Page1.qml b/examples/qmakewithstaticplugin/src/Page1.qml new file mode 100644 index 0000000..9dec282 --- /dev/null +++ b/examples/qmakewithstaticplugin/src/Page1.qml @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 + +Page1Form { + button1.onClicked: { + console.log("Button Pressed. Entered text: " + textField1.text); + } +} diff --git a/examples/qmakewithstaticplugin/src/Page1Form.ui.qml b/examples/qmakewithstaticplugin/src/Page1Form.ui.qml new file mode 100644 index 0000000..4f87915 --- /dev/null +++ b/examples/qmakewithstaticplugin/src/Page1Form.ui.qml @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.Page { + title: qsTr("Page 1") + property alias textField1: textField1 + property alias button1: button1 + + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + anchors.top: parent.top + + TextField { + id: textField1 + placeholderText: qsTr("Text Field") + } + + Button { + id: button1 + text: qsTr("Press Me") + } + } +} diff --git a/examples/qmakewithstaticplugin/src/kirigami-icons.qrc b/examples/qmakewithstaticplugin/src/kirigami-icons.qrc new file mode 100644 index 0000000..73cae11 --- /dev/null +++ b/examples/qmakewithstaticplugin/src/kirigami-icons.qrc @@ -0,0 +1,16 @@ + + + 3rdparty/breeze-icons/icons/actions/32/application-menu.svg + 3rdparty/breeze-icons/icons/actions/32/document-decrypt.svg + 3rdparty/breeze-icons/icons/actions/32/folder-sync.svg + 3rdparty/breeze-icons/icons/actions/symbolic/go-next-symbolic.svg + 3rdparty/breeze-icons/icons/actions/symbolic/go-previous-symbolic.svg + 3rdparty/breeze-icons/icons/actions/22/go-up.svg + 3rdparty/breeze-icons/icons/actions/22/handle-left.svg + 3rdparty/breeze-icons/icons/actions/22/overflow-menu.svg + 3rdparty/breeze-icons/icons/actions/22/handle-right.svg + 3rdparty/breeze-icons/icons/actions/32/view-list-icons.svg + 3rdparty/breeze-icons/icons/categories/32/applications-graphics.svg + 3rdparty/breeze-icons/icons/actions/symbolic/media-record-symbolic.svg + + diff --git a/examples/qmakewithstaticplugin/src/main.cpp b/examples/qmakewithstaticplugin/src/main.cpp new file mode 100644 index 0000000..b8d79cf --- /dev/null +++ b/examples/qmakewithstaticplugin/src/main.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + + +#include + +Q_IMPORT_PLUGIN(KirigamiPlugin) + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + + engine.load(QUrl(QLatin1String("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/qmakewithstaticplugin/src/main.qml b/examples/qmakewithstaticplugin/src/main.qml new file mode 100644 index 0000000..2a56ad2 --- /dev/null +++ b/examples/qmakewithstaticplugin/src/main.qml @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + visible: true + title: qsTr("Hello World") + + header: Kirigami.ApplicationHeader {} + pageStack.initialPage: Page1 {} + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } +} diff --git a/examples/qmakewithstaticplugin/src/qml.qrc b/examples/qmakewithstaticplugin/src/qml.qrc new file mode 100644 index 0000000..44587bd --- /dev/null +++ b/examples/qmakewithstaticplugin/src/qml.qrc @@ -0,0 +1,8 @@ + + + main.qml + Page1.qml + Page1Form.ui.qml + qtquickcontrols2.conf + + diff --git a/examples/qmakewithstaticplugin/src/qtquickcontrols2.conf b/examples/qmakewithstaticplugin/src/qtquickcontrols2.conf new file mode 100644 index 0000000..c22fe2d --- /dev/null +++ b/examples/qmakewithstaticplugin/src/qtquickcontrols2.conf @@ -0,0 +1,15 @@ +; This file can be edited to change the style of the application +; See Styling Qt Quick Controls 2 in the documentation for details: +; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html + +[Controls] +Style=Material + +[Universal] +Theme=Light +;Accent=Steel + +[Material] +Theme=Light +Accent=BlueGrey +Primary=BlueGray diff --git a/examples/qmakewithstaticplugin/src/src.pro b/examples/qmakewithstaticplugin/src/src.pro new file mode 100644 index 0000000..0b7f446 --- /dev/null +++ b/examples/qmakewithstaticplugin/src/src.pro @@ -0,0 +1,39 @@ +TEMPLATE = app + +QT += qml quick quickcontrols2 + +#android: { +# include(3rdparty/kirigami/kirigami.pri) +#} + +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +LIBS += ../3rdparty/kirigami/org/kde/kirigami.2/libkirigamiplugin.a + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +TARGET = minimalqmake + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/examples/simpleexamples/AbstractApplicationWindow.qml b/examples/simpleexamples/AbstractApplicationWindow.qml new file mode 100644 index 0000000..558a7bb --- /dev/null +++ b/examples/simpleexamples/AbstractApplicationWindow.qml @@ -0,0 +1,165 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.AbstractApplicationWindow { + id: root + width: 500 + height: 800 + visible: true + + globalDrawer: Kirigami.GlobalDrawer { + title: "Widget gallery" + titleIcon: "applications-graphics" + + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "Sync" + iconName: "folder-sync" + Kirigami.Action { + text: "action 4" + } + Kirigami.Action { + text: "action 5" + } + }, + Kirigami.Action { + text: "Checkable" + iconName: "view-list-details" + checkable: true + checked: false + onTriggered: { + print("Action checked:" + checked) + } + }, + Kirigami.Action { + text: "Settings" + iconName: "configure" + checkable: true + //Need to do this, otherwise it breaks the bindings + property bool current: pageStack.currentItem ? pageStack.currentItem.objectName == "settingsPage" : false + onCurrentChanged: { + checked = current; + } + onTriggered: { + pageStack.push(settingsComponent); + } + } + ] + + Controls.CheckBox { + checked: true + text: "Option 1" + } + Controls.CheckBox { + text: "Option 2" + } + Controls.CheckBox { + text: "Option 3" + } + Controls.Slider { + Layout.fillWidth: true + value: 0.5 + } + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + + header: Kirigami.ApplicationHeader {} + + pageStack: Controls.StackView { + anchors.fill: parent + property int currentIndex: 0 + focus: true + onCurrentIndexChanged: { + if (depth > currentIndex+1) { + pop(get(currentIndex)); + } + } + onDepthChanged: { + currentIndex = depth-1; + } + initialItem: mainPageComponent + + Keys.onReleased: { + if (event.key == Qt.Key_Back || + (event.key === Qt.Key_Left && (event.modifiers & Qt.AltModifier))) { + event.accepted = true; + if (root.contextDrawer && root.contextDrawer.drawerOpen) { + root.contextDrawer.close(); + } else if (root.globalDrawer && root.globalDrawer.drawerOpen) { + root.globalDrawer.close(); + } else { + var backEvent = {accepted: false} + if (root.pageStack.currentIndex >= 1) { + root.pageStack.currentItem.backRequested(backEvent); + if (!backEvent.accepted) { + if (root.pageStack.depth > 1) { + root.pageStack.currentIndex = Math.max(0, root.pageStack.currentIndex - 1); + backEvent.accepted = true; + } else { + Qt.quit(); + } + } + } + + if (!backEvent.accepted) { + Qt.quit(); + } + } + } + } + } + + + Component { + id: settingsComponent + Kirigami.Page { + title: "Settings" + objectName: "settingsPage" + Rectangle { + anchors.fill: parent + } + } + } + + //Main app content + Component { + id: mainPageComponent + MultipleColumnsGallery {} + } + +} diff --git a/examples/simpleexamples/FixedSidebar.qml b/examples/simpleexamples/FixedSidebar.qml new file mode 100644 index 0000000..d0b9d32 --- /dev/null +++ b/examples/simpleexamples/FixedSidebar.qml @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + width: Kirigami.Units.gridUnit * 60 + height: Kirigami.Units.gridUnit * 40 + + + pageStack.initialPage: mainPageComponent + globalDrawer: Kirigami.OverlayDrawer { + drawerOpen: true + modal: false + contentItem: Item { + implicitWidth: Kirigami.Units.gridUnit * 10 + + Kirigami.Label { + text: "This is a sidebar" + width: parent.width - Kirigami.Units.smallSpacing * 2 + wrapMode: Text.WordWrap + anchors.horizontalCenter: parent.horizontalCenter + } + + } + } + + //Main app content + Component { + id: mainPageComponent + MultipleColumnsGallery {} + } +} diff --git a/examples/simpleexamples/MultipleColumnsGallery.qml b/examples/simpleexamples/MultipleColumnsGallery.qml new file mode 100644 index 0000000..4f8750d --- /dev/null +++ b/examples/simpleexamples/MultipleColumnsGallery.qml @@ -0,0 +1,88 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.0 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 + +ScrollablePage { + id: page + Layout.fillWidth: true + implicitWidth: Units.gridUnit * (Math.floor(Math.random() * 35) + 8) + + title: "Multiple Columns" + + actions { + contextualActions: [ + Action { + text:"Action for buttons" + iconName: "bookmarks" + onTriggered: print("Action 1 clicked") + }, + Action { + text:"Action 2" + iconName: "folder" + enabled: false + } + ] + } + + ColumnLayout { + width: page.width + spacing: Units.smallSpacing + + Controls.Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: "This page is used to test multiple columns: you can push and pop an arbitrary number of pages, each new page will have a random implicit width between 8 and 35 grid units.\nIf you enlarge the window enough, you can test how the application behaves with multiple columns." + } + Item { + Layout.minimumWidth: Units.gridUnit *2 + Layout.minimumHeight: Layout.minimumWidth + } + Controls.Label { + anchors.horizontalCenter: parent.horizontalCenter + text: "Page implicitWidth: " + page.implicitWidth + } + Controls.Button { + text: "Push Another Page" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: pageStack.push(Qt.resolvedUrl("MultipleColumnsGallery.qml")); + } + Controls.Button { + text: "Pop A Page" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: pageStack.pop(); + } + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + Controls.TextField { + id: edit + text: page.title + } + Controls.Button { + text: "Rename Page" + onClicked: page.title = edit.text; + } + } + } + + +} diff --git a/examples/simpleexamples/Sidebar.qml b/examples/simpleexamples/Sidebar.qml new file mode 100644 index 0000000..67d1157 --- /dev/null +++ b/examples/simpleexamples/Sidebar.qml @@ -0,0 +1,137 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Controls 2.3 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.5 as Kirigami + +Kirigami.ApplicationWindow { + id: root + width: Kirigami.Units.gridUnit * 60 + height: Kirigami.Units.gridUnit * 40 + + + pageStack.initialPage: mainPageComponent + globalDrawer: Kirigami.OverlayDrawer { + id: drawer + drawerOpen: true + modal: false + //leftPadding: Kirigami.Units.largeSpacing + rightPadding: Kirigami.Units.largeSpacing + contentItem: ColumnLayout { + Layout.preferredWidth: Kirigami.Units.gridUnit * 20 + + Kirigami.Label { + anchors.horizontalCenter: parent.horizontalCenter + text: "This is a sidebar" + Layout.fillWidth: true + width: parent.width - Kirigami.Units.smallSpacing * 2 + wrapMode: Text.WordWrap + } + Controls.Button { + anchors.horizontalCenter: parent.horizontalCenter + text: "Modal" + checkable: true + Layout.fillWidth: true + checked: false + onCheckedChanged: drawer.modal = checked + } + Item { + Layout.fillHeight: true + } + } + } + contextDrawer: Kirigami.OverlayDrawer { + id: contextDrawer + drawerOpen: true + edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge + modal: false + leftPadding: Kirigami.Units.largeSpacing + rightPadding: Kirigami.Units.largeSpacing + contentItem: ColumnLayout { + Layout.preferredWidth: Kirigami.Units.gridUnit * 10 + + Kirigami.Label { + anchors.horizontalCenter: parent.horizontalCenter + text: "This is a sidebar" + Layout.fillWidth: true + width: parent.width - Kirigami.Units.smallSpacing * 2 + wrapMode: Text.WordWrap + } + Controls.Button { + anchors.horizontalCenter: parent.horizontalCenter + text: "Modal" + checkable: true + Layout.fillWidth: true + checked: false + onCheckedChanged: contextDrawer.modal = checked + } + Item { + Layout.fillHeight: true + } + } + } + + menuBar: Controls.MenuBar { + Controls.Menu { + title: qsTr("&File") + Controls.Action { text: qsTr("&New...") } + Controls.Action { text: qsTr("&Open...") } + Controls.Action { text: qsTr("&Save") } + Controls.Action { text: qsTr("Save &As...") } + Controls.MenuSeparator { } + Controls.Action { text: qsTr("&Quit") } + } + Controls.Menu { + title: qsTr("&Edit") + Controls.Action { text: qsTr("Cu&t") } + Controls.Action { text: qsTr("&Copy") } + Controls.Action { text: qsTr("&Paste") } + } + Controls.Menu { + title: qsTr("&Help") + Controls.Action { text: qsTr("&About") } + } + } + header: Controls.ToolBar { + contentItem: RowLayout { + Controls.ToolButton { + text: "Global ToolBar" + } + Item { + Layout.fillWidth: true + } + Controls.TextField { + + } + } + } + //Main app content + Component { + id: mainPageComponent + MultipleColumnsGallery {} + } + footer: Controls.ToolBar { + position: ToolBar.Footer + contentItem: Controls.Label { + text: "Global Footer" + } + } +} diff --git a/examples/simpleexamples/TabBarHeader.qml b/examples/simpleexamples/TabBarHeader.qml new file mode 100644 index 0000000..7c87a3e --- /dev/null +++ b/examples/simpleexamples/TabBarHeader.qml @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + width: 500 + height: 800 + visible: true + + + header: Kirigami.ApplicationHeader { + headerStyle: Kirigami.ApplicationHeaderStyle.TabBar + } + + + + pageStack.initialPage: mainPageComponent + + + Component.onCompleted: { + pageStack.push(mainPageComponent); + pageStack.push(mainPageComponent); + pageStack.currentIndex = 0; + } + + //Main app content + Component { + id: mainPageComponent + MultipleColumnsGallery {} + } + +} diff --git a/examples/simpleexamples/customdrawer.qml b/examples/simpleexamples/customdrawer.qml new file mode 100644 index 0000000..d9d973d --- /dev/null +++ b/examples/simpleexamples/customdrawer.qml @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + globalDrawer: Kirigami.OverlayDrawer { + contentItem: Rectangle { + implicitWidth: Kirigami.Units.gridUnit * 10 + color: "red" + anchors.fill: parent + } + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + + pageStack.initialPage: mainPageComponent + + Component { + id: mainPageComponent + Kirigami.ScrollablePage { + title: "Hello" + Rectangle { + anchors.fill: parent + } + } + } + + +} diff --git a/examples/simpleexamples/dragPageWidth.qml b/examples/simpleexamples/dragPageWidth.qml new file mode 100644 index 0000000..81b16f1 --- /dev/null +++ b/examples/simpleexamples/dragPageWidth.qml @@ -0,0 +1,87 @@ +/* + * Copyright 2017 Eike Hein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 + +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + property int defaultColumnWidth: Kirigami.Units.gridUnit * 13 + property int columnWidth: defaultColumnWidth + + pageStack.defaultColumnWidth: columnWidth + pageStack.initialPage: [firstPageComponent, secondPageComponent] + + MouseArea { + id: dragHandle + + visible: pageStack.wideMode + + anchors.top: parent.top + anchors.bottom: parent.bottom + + x: columnWidth - (width / 2) + width: Kirigami.Units.devicePixelRatio * 2 + + property int dragRange: (Kirigami.Units.gridUnit * 5) + property int _lastX: -1 + + cursorShape: Qt.SplitHCursor + + onPressed: _lastX = mouseX + + onPositionChanged: { + if (mouse.x > _lastX) { + columnWidth = Math.min((defaultColumnWidth + dragRange), + columnWidth + (mouse.x - _lastX)); + } else if (mouse.x < _lastX) { + columnWidth = Math.max((defaultColumnWidth - dragRange), + columnWidth - (_lastX - mouse.x)); + } + } + + Rectangle { + anchors.fill: parent + + color: "blue" + } + } + + Component { + id: firstPageComponent + + Kirigami.Page { + id: firstPage + + background: Rectangle { color: "red" } + } + } + + Component { + id: secondPageComponent + + Kirigami.Page { + id: secondPage + + background: Rectangle { color: "green" } + } + } +} diff --git a/examples/simpleexamples/footer.qml b/examples/simpleexamples/footer.qml new file mode 100644 index 0000000..6176da1 --- /dev/null +++ b/examples/simpleexamples/footer.qml @@ -0,0 +1,79 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + footer: Controls.ToolBar { + //height: Kirigami.Units.gridUnit * 3 + RowLayout { + Controls.ToolButton { + text: "text" + } + } + } + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + + pageStack.initialPage: mainPageComponent + + Component { + id: mainPageComponent + Kirigami.ScrollablePage { + title: "Hello" + Rectangle { + anchors.fill: parent + } + } + } + + +} diff --git a/examples/simpleexamples/minimal.qml b/examples/simpleexamples/minimal.qml new file mode 100644 index 0000000..029a956 --- /dev/null +++ b/examples/simpleexamples/minimal.qml @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } + contextDrawer: Kirigami.ContextDrawer { + id: contextDrawer + } + + pageStack.initialPage: mainPageComponent + + Component { + id: mainPageComponent + Kirigami.ScrollablePage { + title: "Hello" + Rectangle { + anchors.fill: parent + } + } + } + + +} diff --git a/examples/simpleexamples/pushpopclear.qml b/examples/simpleexamples/pushpopclear.qml new file mode 100644 index 0000000..a36b080 --- /dev/null +++ b/examples/simpleexamples/pushpopclear.qml @@ -0,0 +1,82 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + header: Kirigami.ApplicationHeader { + } + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + + actions: [ + Kirigami.Action { + text: "push" + onTriggered: pageStack.push(secondPageComponent) + }, + Kirigami.Action { + text: "pop" + onTriggered: pageStack.pop() + }, + Kirigami.Action { + text: "clear" + onTriggered: pageStack.clear() + }, + Kirigami.Action { + text: "replace" + onTriggered: pageStack.replace(secondPageComponent) + } + ] + } + + pageStack.initialPage: mainPageComponent + + Component { + id: mainPageComponent + Kirigami.Page { + title: "First Page" + Rectangle { + anchors.fill: parent + Kirigami.Label { + text: "First Page" + } + } + } + } + + Component { + id: secondPageComponent + Kirigami.Page { + title: "Second Page" + Rectangle { + color: "red" + anchors.fill: parent + Kirigami.Label { + text: "Second Page" + } + } + } + } + +} diff --git a/examples/simpleexamples/simpleChatApp.qml b/examples/simpleexamples/simpleChatApp.qml new file mode 100644 index 0000000..a8721a1 --- /dev/null +++ b/examples/simpleexamples/simpleChatApp.qml @@ -0,0 +1,337 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.2 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + id: root + + //header: Kirigami.ToolBarApplicationHeader {} + //FIXME: perhaps the default logic for going widescreen should be refined upstream + wideScreen: width > columnWidth * 3 + property int columnWidth: Kirigami.Units.gridUnit * 13 + property int footerHeight: Math.round(Kirigami.Units.gridUnit * 2.5) + + globalDrawer: Kirigami.GlobalDrawer { + contentItem.implicitWidth: columnWidth + title: "Chat App" + titleIcon: "konversation" + modal: true + drawerOpen: false + + actions: [ + Kirigami.Action { + text: "Rooms" + iconName: "view-list-icons" + }, + Kirigami.Action { + text: "Contacts" + iconName: "tag-people" + }, + Kirigami.Action { + text: "Search" + iconName: "search" + } + ] + } + contextDrawer: Kirigami.OverlayDrawer { + id: contextDrawer + //they can depend on the page like that or be defined directly here + edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge + modal: !root.wideScreen + onModalChanged: drawerOpen = !modal + handleVisible: applicationWindow == undefined ? false : applicationWindow().controlsVisible + + //here padding 0 as listitems look better without as opposed to any other control + topPadding: 0 + bottomPadding: 0 + leftPadding: 0 + rightPadding: 0 + + contentItem: ColumnLayout { + + readonly property int implicitWidth: root.columnWidth + spacing: 0 + QQC2.Control { + Layout.fillWidth: true + background: Rectangle { + anchors.fill: parent + color: Kirigami.Theme.highlightColor + opacity: 0.8 + } + + padding: Kirigami.Units.gridUnit + + contentItem: ColumnLayout { + id: titleLayout + spacing: Kirigami.Units.gridUnit + + RowLayout { + spacing: Kirigami.Units.gridUnit + Rectangle { + color: Kirigami.Theme.highlightedTextColor + radius: width + implicitWidth: Kirigami.Units.iconSizes.medium + implicitHeight: implicitWidth + } + ColumnLayout { + QQC2.Label { + Layout.fillWidth: true + color: Kirigami.Theme.highlightedTextColor + text: "KDE" + } + QQC2.Label { + Layout.fillWidth: true + color: Kirigami.Theme.highlightedTextColor + font.pointSize: Kirigami.Units.fontMetrics.font.pointSize * 0.8 + text: "#kde: kde.org" + } + } + } + QQC2.Label { + Layout.fillWidth: true + color: Kirigami.Theme.highlightedTextColor + text: "Main room for KDE community, other rooms are listed at kde.org/rooms" + wrapMode: Text.WordWrap + } + } + } + + Kirigami.Separator { + Layout.fillWidth: true + } + + QQC2.ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + ListView { + model: 50 + delegate: Kirigami.BasicListItem { + label: "Person " + modelData + separatorVisible: false + reserveSpaceForIcon: false + } + } + } + + Kirigami.Separator { + Layout.fillWidth: true + Layout.maximumHeight: 1//implicitHeight + } + Kirigami.BasicListItem { + label: "Group call" + icon: "call-start" + separatorVisible: false + } + Kirigami.BasicListItem { + label: "Send Attachment" + icon: "mail-attachment" + separatorVisible: false + } + } + } + + pageStack.defaultColumnWidth: columnWidth + pageStack.initialPage: [channelsComponent, chatComponent] + + Component { + id: channelsComponent + Kirigami.ScrollablePage { + title: "Channels" + actions.main: Kirigami.Action { + icon.name: "search" + text: "Search" + } + background: Rectangle { + anchors.fill: parent + color: Kirigami.Theme.backgroundColor + } + footer: QQC2.ToolBar { + height: root.footerHeight + padding: Kirigami.Units.smallSpacing + RowLayout { + anchors.fill: parent + spacing: Kirigami.Units.smallSpacing + //NOTE: icon support in tool button in Qt 5.11 + QQC2.ToolButton { + Layout.fillHeight: true + //make it square + implicitWidth: height + Kirigami.Icon { + anchors.centerIn: parent + width: Kirigami.Units.iconSizes.smallMedium + height: width + source: "configure" + } + onClicked: root.pageStack.layers.push(secondLayerComponent); + } + QQC2.ComboBox { + Layout.fillWidth: true + Layout.fillHeight: true + model: ["First", "Second", "Third"] + } + } + } + ListView { + id: channelsList + currentIndex: 2 + model: 30 + delegate: Kirigami.BasicListItem { + label: "#Channel " + modelData + checkable: true + checked: channelsList.currentIndex == index + separatorVisible: false + reserveSpaceForIcon: false + } + } + } + } + + Component { + id: chatComponent + Kirigami.ScrollablePage { + title: "#KDE" + actions { + left: Kirigami.Action { + icon.name: "documentinfo" + text: "Channel info" + } + main: Kirigami.Action { + icon.name: "search" + text: "Search" + } + } + actions.contextualActions: [ + Kirigami.Action { + text: "Room Settings" + iconName: "configure" + Kirigami.Action { + text: "Setting 1" + } + Kirigami.Action { + text: "Setting 2" + } + }, + Kirigami.Action { + text: "Shared Media" + iconName: "document-share" + Kirigami.Action { + text: "Media 1" + } + Kirigami.Action { + text: "Media 2" + } + Kirigami.Action { + text: "Media 3" + } + } + ] + background: Rectangle { + anchors.fill: parent + color: Kirigami.Theme.backgroundColor + } + footer: QQC2.Control { + height: footerHeight + padding: Kirigami.Units.smallSpacing + background: Rectangle { + color: Kirigami.Theme.backgroundColor + Kirigami.Separator { + Rectangle { + anchors.fill: parent + color: Kirigami.Theme.focusColor + visible: chatTextInput.activeFocus + } + anchors { + left: parent.left + right: parent.right + top: parent.top + } + } + } + contentItem: RowLayout { + QQC2.TextField { + Layout.fillWidth: true + id: chatTextInput + background: Item {} + } + //NOTE: icon support in tool button in Qt 5.11 + QQC2.ToolButton { + Layout.fillHeight: true + //make it square + implicitWidth: height + Kirigami.Icon { + anchors.centerIn: parent + width: Kirigami.Units.iconSizes.smallMedium + height: width + source: "go-next" + } + } + } + } + + ListView { + id: channelsList + verticalLayoutDirection: ListView.BottomToTop + currentIndex: 2 + model: 30 + delegate: Item { + height: Kirigami.Units.gridUnit * 4 + ColumnLayout { + x: Kirigami.Units.gridUnit + anchors.verticalCenter: parent.verticalCenter + QQC2.Label { + text: modelData % 2 ? "John Doe" : "John Applebaum" + } + QQC2.Label { + text: "Message " + modelData + } + } + } + } + } + } + + Component { + id: secondLayerComponent + Kirigami.Page { + title: "Settings" + background: Rectangle { + color: Kirigami.Theme.backgroundColor + } + footer: QQC2.ToolBar { + height: root.footerHeight + QQC2.ToolButton { + Layout.fillHeight: true + //make it square + implicitWidth: height + Kirigami.Icon { + anchors.centerIn: parent + width: Kirigami.Units.iconSizes.smallMedium + height: width + source: "configure" + } + onClicked: root.pageStack.layers.pop(); + } + } + } + } +} diff --git a/examples/staticcmake/3rdparty/CMakeLists.txt b/examples/staticcmake/3rdparty/CMakeLists.txt new file mode 100644 index 0000000..e10afb2 --- /dev/null +++ b/examples/staticcmake/3rdparty/CMakeLists.txt @@ -0,0 +1,3 @@ +set(BUILD_SHARED_LIBS 0) + +add_subdirectory(kirigami) diff --git a/examples/staticcmake/3rdparty/README b/examples/staticcmake/3rdparty/README new file mode 100644 index 0000000..aad19dd --- /dev/null +++ b/examples/staticcmake/3rdparty/README @@ -0,0 +1,6 @@ +Add here, with either a script that does a git checkout +or as git submodules the two projects: + +git://anongit.kde.org/kirigami.git +git://anongit.kde.org/breeze-icons.git + diff --git a/examples/staticcmake/CMakeLists.txt b/examples/staticcmake/CMakeLists.txt new file mode 100644 index 0000000..4f362f2 --- /dev/null +++ b/examples/staticcmake/CMakeLists.txt @@ -0,0 +1,24 @@ +project(minimal) +cmake_minimum_required(VERSION 3.2) +if (POLICY CMP0063) + cmake_policy(SET CMP0063 NEW) +endif() + + +find_package(ECM REQUIRED CONFIG) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + +set(BREEZEICONS_DIR ${CMAKE_SOURCE_DIR}/3rdparty/breeze-icons/) + +find_package(Qt5 REQUIRED Core Quick Multimedia Test Widgets QuickControls2) + +include(KDEInstallDirs) +include(KDECompilerSettings) +include(KDECMakeSettings) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_subdirectory(3rdparty) +add_subdirectory(src) + diff --git a/examples/staticcmake/src/CMakeLists.txt b/examples/staticcmake/src/CMakeLists.txt new file mode 100644 index 0000000..4423d56 --- /dev/null +++ b/examples/staticcmake/src/CMakeLists.txt @@ -0,0 +1,27 @@ + +include_directories(${CMAKE_SOURCE_DIR}/3rdparty/kirigami/src) +include(${CMAKE_SOURCE_DIR}/3rdparty/kirigami/KF5Kirigami2Macros.cmake) + +set(minimal_SRCS + main.cpp + ) + +qt5_add_resources(RESOURCES kirigami-icons.qrc resources.qrc) + +if (CMAKE_SYSTEM_NAME STREQUAL "Android") + set(minimal_EXTRA_LIBS Qt5::AndroidExtras + #FIXME: we shouldn't have to link to it but otherwise the lib won't be packaged on Android + Qt5::QuickControls2) +else () +#qstyle-based qqc2 style needs a QApplication + set(minimal_EXTRA_LIBS Qt5::Widgets) +endif() + + +add_executable(minimal ${minimal_SRCS} ${RESOURCES}) +#kirigamiplugin is the static library built by us +target_link_libraries(minimal kirigamiplugin Qt5::Core Qt5::Qml Qt5::Quick Qt5::QuickControls2 ${minimal_EXTRA_LIBS}) + +#install(TARGETS minimal ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +kirigami_package_breeze_icons(ICONS application-menu document-decrypt folder-sync go-next go-previous go-up handle-left handle-right view-list-icons applications-graphics media-record-symbolic) diff --git a/examples/staticcmake/src/Page1.qml b/examples/staticcmake/src/Page1.qml new file mode 100644 index 0000000..9dec282 --- /dev/null +++ b/examples/staticcmake/src/Page1.qml @@ -0,0 +1,26 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 + +Page1Form { + button1.onClicked: { + console.log("Button Pressed. Entered text: " + textField1.text); + } +} diff --git a/examples/staticcmake/src/Page1Form.ui.qml b/examples/staticcmake/src/Page1Form.ui.qml new file mode 100644 index 0000000..6a127ce --- /dev/null +++ b/examples/staticcmake/src/Page1Form.ui.qml @@ -0,0 +1,52 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.Page { + title: qsTr("Page 1") + property alias textField1: textField1 + property alias button1: button1 + actions { + main: Kirigami.Action { + text: "Sync" + icon.name: "folder-sync" + onTriggered: showPassiveNotification("Action clicked") + } + } + + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 20 + anchors.top: parent.top + + TextField { + id: textField1 + placeholderText: qsTr("Text Field") + } + + Button { + id: button1 + text: qsTr("Press Me") + } + } +} diff --git a/examples/staticcmake/src/kirigami-icons.qrc b/examples/staticcmake/src/kirigami-icons.qrc new file mode 100644 index 0000000..f8992e1 --- /dev/null +++ b/examples/staticcmake/src/kirigami-icons.qrc @@ -0,0 +1,15 @@ + + + ../3rdparty/breeze-icons/icons/actions/32/application-menu.svg + ../3rdparty/breeze-icons/icons/actions/32/document-decrypt.svg + ../3rdparty/breeze-icons/icons/actions/32/folder-sync.svg + ../3rdparty/breeze-icons/icons/actions/22/go-next.svg + ../3rdparty/breeze-icons/icons/actions/22/go-previous.svg + ../3rdparty/breeze-icons/icons/actions/22/go-up.svg + ../3rdparty/breeze-icons/icons/actions/22/handle-left.svg + ../3rdparty/breeze-icons/icons/actions/22/handle-right.svg + ../3rdparty/breeze-icons/icons/actions/32/view-list-icons.svg + ../3rdparty/breeze-icons/icons/categories/32/applications-graphics.svg + ../3rdparty/breeze-icons/icons/actions/symbolic/media-record-symbolic.svg + + diff --git a/examples/staticcmake/src/main.cpp b/examples/staticcmake/src/main.cpp new file mode 100644 index 0000000..57ac9d9 --- /dev/null +++ b/examples/staticcmake/src/main.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef Q_OS_ANDROID +#include +#else +#include +#endif + +#include +#include +#include +#include + +#ifdef Q_OS_ANDROID +#include + +// WindowManager.LayoutParams +#define FLAG_TRANSLUCENT_STATUS 0x04000000 +#define FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 0x80000000 +// View +#define SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 0x00002000 + +#endif + + + +Q_IMPORT_PLUGIN(KirigamiPlugin) + +Q_DECL_EXPORT int main(int argc, char *argv[]) +{ + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +//The desktop QQC2 style needs it to be a QApplication +#ifdef Q_OS_ANDROID + QGuiApplication app(argc, argv); +#else + QApplication app(argc, argv); +#endif + + //qputenv("QML_IMPORT_TRACE", "1"); + + QQmlApplicationEngine engine; + + engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); + + if (engine.rootObjects().isEmpty()) { + return -1; + } + + //HACK to color the system bar on Android, use qtandroidextras and call the appropriate Java methods +#ifdef Q_OS_ANDROID + QtAndroid::runOnAndroidThread([=]() { + QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;"); + window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS); + window.callMethod("setStatusBarColor", "(I)V", QColor("#2196f3").rgba()); + window.callMethod("setNavigationBarColor", "(I)V", QColor("#2196f3").rgba()); + }); +#endif + + return app.exec(); +} diff --git a/examples/staticcmake/src/main.qml b/examples/staticcmake/src/main.qml new file mode 100644 index 0000000..2a56ad2 --- /dev/null +++ b/examples/staticcmake/src/main.qml @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow { + visible: true + title: qsTr("Hello World") + + header: Kirigami.ApplicationHeader {} + pageStack.initialPage: Page1 {} + + globalDrawer: Kirigami.GlobalDrawer { + title: "Hello App" + titleIcon: "applications-graphics" + actions: [ + Kirigami.Action { + text: "View" + iconName: "view-list-icons" + Kirigami.Action { + text: "action 1" + } + Kirigami.Action { + text: "action 2" + } + Kirigami.Action { + text: "action 3" + } + }, + Kirigami.Action { + text: "action 3" + }, + Kirigami.Action { + text: "action 4" + } + ] + } +} diff --git a/examples/staticcmake/src/qtquickcontrols2.conf b/examples/staticcmake/src/qtquickcontrols2.conf new file mode 100644 index 0000000..c22fe2d --- /dev/null +++ b/examples/staticcmake/src/qtquickcontrols2.conf @@ -0,0 +1,15 @@ +; This file can be edited to change the style of the application +; See Styling Qt Quick Controls 2 in the documentation for details: +; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html + +[Controls] +Style=Material + +[Universal] +Theme=Light +;Accent=Steel + +[Material] +Theme=Light +Accent=BlueGrey +Primary=BlueGray diff --git a/examples/staticcmake/src/resources.qrc b/examples/staticcmake/src/resources.qrc new file mode 100644 index 0000000..44587bd --- /dev/null +++ b/examples/staticcmake/src/resources.qrc @@ -0,0 +1,8 @@ + + + main.qml + Page1.qml + Page1Form.ui.qml + qtquickcontrols2.conf + + diff --git a/kirigami-icons.qrc b/kirigami-icons.qrc new file mode 100644 index 0000000..36a45cf --- /dev/null +++ b/kirigami-icons.qrc @@ -0,0 +1,13 @@ + + + breeze-icons/icons/actions/32/application-menu.svg + breeze-icons/icons/actions/32/document-decrypt.svg + breeze-icons/icons/actions/32/folder-sync.svg + breeze-icons/icons/actions/22/go-next.svg + breeze-icons/icons/actions/22/go-previous.svg + breeze-icons/icons/actions/22/go-up.svg + breeze-icons/icons/actions/22/handle-left.svg + breeze-icons/icons/actions/22/handle-right.svg + breeze-icons/icons/actions/32/view-list-icons.svg + + diff --git a/kirigami.pri b/kirigami.pri new file mode 100644 index 0000000..1c0bc33 --- /dev/null +++ b/kirigami.pri @@ -0,0 +1,41 @@ + +QT += core qml quick gui svg network quickcontrols2 +HEADERS += $$PWD/src/kirigamiplugin.h \ + $$PWD/src/enums.h \ + $$PWD/src/settings.h \ + $$PWD/src/formlayoutattached.h \ + $$PWD/src/mnemonicattached.h \ + $$PWD/src/scenepositionattached.h \ + $$PWD/src/libkirigami/basictheme_p.h \ + $$PWD/src/libkirigami/platformtheme.h \ + $$PWD/src/libkirigami/kirigamipluginfactory.h \ + $$PWD/src/libkirigami/tabletmodewatcher.h \ + $$PWD/src/desktopicon.h \ + $$PWD/src/delegaterecycler.h +SOURCES += $$PWD/src/kirigamiplugin.cpp \ + $$PWD/src/enums.cpp \ + $$PWD/src/settings.cpp \ + $$PWD/src/formlayoutattached.cpp \ + $$PWD/src/mnemonicattached.cpp \ + $$PWD/src/scenepositionattached.cpp \ + $$PWD/src/libkirigami/basictheme.cpp \ + $$PWD/src/libkirigami/platformtheme.cpp \ + $$PWD/src/libkirigami/kirigamipluginfactory.cpp \ + $$PWD/src/libkirigami/tabletmodewatcher.cpp \ + $$PWD/src/desktopicon.h \ + $$PWD/src/desktopicon.cpp \ + $$PWD/src/delegaterecycler.cpp +INCLUDEPATH += $$PWD/src $$PWD/src/libkirigami +DEFINES += KIRIGAMI_BUILD_TYPE_STATIC + +API_VER=1.0 + +RESOURCES += $$PWD/kirigami.qrc + +exists($$_PRO_FILE_PWD_/kirigami-icons.qrc) { + message("Using icons QRC file shipped by the project") + RESOURCES += $$_PRO_FILE_PWD_/kirigami-icons.qrc +} else { + message("Using icons QRCfile shipped in kirigami") + RESOURCES += $$PWD/kirigami-icons.qrc +} diff --git a/kirigami.pro b/kirigami.pro new file mode 100644 index 0000000..9421ae7 --- /dev/null +++ b/kirigami.pro @@ -0,0 +1,56 @@ +TEMPLATE = lib +CONFIG += static plugin + +QT += qml quick gui quickcontrols2 svg +URI = org.kde.kirigami +QMAKE_MOC_OPTIONS += -Muri=org.kde.kirigami +HEADERS += $$PWD/src/kirigamiplugin.h \ + $$PWD/src/enums.h \ + $$PWD/src/settings.h \ + $$PWD/src/formlayoutattached.h \ + $$PWD/src/mnemonicattached.h \ + $$PWD/src/scenepositionattached.h \ + $$PWD/src/libkirigami/basictheme_p.h \ + $$PWD/src/libkirigami/platformtheme.h \ + $$PWD/src/libkirigami/kirigamipluginfactory.h \ + $$PWD/src/libkirigami/tabletmodewatcher.h \ + $$PWD/src/desktopicon.h \ + $$PWD/src/delegaterecycler.h +SOURCES += $$PWD/src/kirigamiplugin.cpp \ + $$PWD/src/enums.cpp \ + $$PWD/src/settings.cpp \ + $$PWD/src/formlayoutattached.cpp \ + $$PWD/src/mnemonicattached.cpp \ + $$PWD/src/scenepositionattached.cpp \ + $$PWD/src/libkirigami/basictheme.cpp \ + $$PWD/src/libkirigami/platformtheme.cpp \ + $$PWD/src/libkirigami/kirigamipluginfactory.cpp \ + $$PWD/src/libkirigami/tabletmodewatcher.cpp \ + $$PWD/src/desktopicon.cpp \ + $$PWD/src/delegaterecycler.cpp +RESOURCES += $$PWD/kirigami.qrc +DEFINES += KIRIGAMI_BUILD_TYPE_STATIC + + + +API_VER=1.0 + +TARGET = $$qtLibraryTarget(org/kde/kirigami.2/kirigamiplugin) + +importPath = $$[QT_INSTALL_QML]/org/kde/kirigami.2 +target.path = $${importPath} + +controls.path = $${importPath} +controls.files += $$PWD/src/controls/* + +#For now ignore Desktop and Plasma stuff in qmake +styles.path = $${importPath}/styles +styles.files += $$PWD/src/styles/* + +INSTALLS += target controls styles + + + + + + diff --git a/kirigami.qrc b/kirigami.qrc new file mode 100644 index 0000000..d3c2313 --- /dev/null +++ b/kirigami.qrc @@ -0,0 +1,86 @@ + + + src/controls/AbstractApplicationWindow.qml + src/controls/ContextDrawer.qml + src/controls/Action.qml + src/controls/Page.qml + src/controls/PageRow.qml + src/controls/AbstractListItem.qml + src/controls/Theme.qml + src/controls/AbstractCard.qml + src/controls/templates/AbstractCard.qml + src/controls/Card.qml + src/controls/CardsLayout.qml + src/controls/CardsListView.qml + src/controls/CardsGridView.qml + src/controls/ActionToolBar.qml + src/controls/templates/InlineMessage.qml + src/controls/InlineMessage.qml + src/controls/ToolBarApplicationHeader.qml + src/controls/private/PrivateActionToolButton.qml + src/controls/private/RefreshableScrollView.qml + src/controls/private/SwipeItemEventFilter.qml + src/controls/private/PageActionPropertyGroup.qml + src/controls/private/ActionIconGroup.qml + src/controls/private/CornerShadow.qml + src/controls/private/ActionButton.qml + src/controls/private/DefaultListItemBackground.qml + src/controls/private/BannerImage.qml + src/controls/private/EdgeShadow.qml + src/controls/private/globaltoolbar/AbstractPageHeader.qml + src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml + src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml + src/controls/private/PrivateActionToolButton.qml + src/controls/private/globaltoolbar/TitlesPageHeader.qml + src/controls/private/globaltoolbar/ToolBarPageHeader.qml + src/controls/private/globaltoolbar/BreadcrumbControl.qml + src/controls/private/globaltoolbar/TabBarControl.qml + src/controls/private/ActionsMenu.qml + src/controls/private/ActionMenuItemQt59.qml + src/controls/private/ActionMenuItemBase.qml + src/controls/Separator.qml + src/controls/OverlayDrawer.qml + src/controls/OverlaySheet.qml + src/controls/GlobalDrawer.qml + src/controls/templates/AbstractListItem.qml + src/controls/templates/private/MenuIcon.qml + src/controls/templates/private/GenericDrawerIcon.qml + src/controls/templates/private/PassiveNotification.qml + src/controls/templates/private/ContextIcon.qml + src/controls/templates/private/ScrollView.qml + src/controls/templates/private/BackButton.qml + src/controls/templates/private/IconPropertiesGroup.qml + src/controls/templates/private/ForwardButton.qml + src/controls/templates/OverlayDrawer.qml + src/controls/templates/OverlaySheet.qml + src/controls/templates/SwipeListItem.qml + src/controls/templates/ApplicationHeader.qml + src/controls/templates/AbstractApplicationHeader.qml + src/controls/Units.qml + src/controls/SwipeListItem.qml + src/controls/ApplicationWindow.qml + src/controls/AbstractApplicationItem.qml + src/controls/ApplicationItem.qml + src/controls/ApplicationHeader.qml + src/controls/Heading.qml + src/controls/ScrollablePage.qml + src/controls/AboutPage.qml + src/controls/UrlButton.qml + src/controls/LinkButton.qml + src/controls/Label.qml + src/controls/BasicListItem.qml + src/controls/AbstractApplicationHeader.qml + src/controls/FormLayout.qml + src/controls/ListItemDragHandle.qml + src/styles/Material/AbstractListItem.qml + src/styles/Material/Theme.qml + src/styles/Material/SwipeListItem.qml + src/styles/Material/Label.qml + src/styles/org.kde.desktop/AbstractListItem.qml + src/styles/org.kde.desktop/Theme.qml + src/styles/org.kde.desktop/Units.qml + src/styles/org.kde.desktop/SwipeListItem.qml + src/styles/org.kde.desktop/ApplicationWindow.qml + src/styles/org.kde.desktop/AbstractApplicationHeader.qml + + diff --git a/kirigami.qrc.in b/kirigami.qrc.in new file mode 100644 index 0000000..4f6ce9a --- /dev/null +++ b/kirigami.qrc.in @@ -0,0 +1,86 @@ + + + @kirigami_QML_DIR@/src/controls/AbstractApplicationWindow.qml + @kirigami_QML_DIR@/src/controls/ContextDrawer.qml + @kirigami_QML_DIR@/src/controls/Action.qml + @kirigami_QML_DIR@/src/controls/Page.qml + @kirigami_QML_DIR@/src/controls/PageRow.qml + @kirigami_QML_DIR@/src/controls/AbstractListItem.qml + @kirigami_QML_DIR@/src/controls/Theme.qml + @kirigami_QML_DIR@/src/controls/AbstractCard.qml + @kirigami_QML_DIR@/src/controls/templates/AbstractCard.qml + @kirigami_QML_DIR@/src/controls/Card.qml + @kirigami_QML_DIR@/src/controls/CardsLayout.qml + @kirigami_QML_DIR@/src/controls/CardsListView.qml + @kirigami_QML_DIR@/src/controls/CardsGridView.qml + @kirigami_QML_DIR@/src/controls/ActionToolBar.qml + @kirigami_QML_DIR@/src/controls/templates/InlineMessage.qml + @kirigami_QML_DIR@/src/controls/InlineMessage.qml + @kirigami_QML_DIR@/src/controls/ToolBarApplicationHeader.qml + @kirigami_QML_DIR@/src/controls/private/PrivateActionToolButton.qml + @kirigami_QML_DIR@/src/controls/private/RefreshableScrollView.qml + @kirigami_QML_DIR@/src/controls/private/SwipeItemEventFilter.qml + @kirigami_QML_DIR@/src/controls/private/PageActionPropertyGroup.qml + @kirigami_QML_DIR@/src/controls/private/ActionIconGroup.qml + @kirigami_QML_DIR@/src/controls/private/CornerShadow.qml + @kirigami_QML_DIR@/src/controls/private/ActionButton.qml + @kirigami_QML_DIR@/src/controls/private/DefaultListItemBackground.qml + @kirigami_QML_DIR@/src/controls/private/BannerImage.qml + @kirigami_QML_DIR@/src/controls/private/EdgeShadow.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/AbstractPageHeader.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/BreadcrumbControl.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml + @kirigami_QML_DIR@/src/controls/private/PrivateActionToolButton.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/TabBarControl.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/TitlesPageHeader.qml + @kirigami_QML_DIR@/src/controls/private/globaltoolbar/ToolBarPageHeader.qml + @kirigami_QML_DIR@/src/controls/private/ActionsMenu.qml + @kirigami_QML_DIR@/src/controls/private/@kirigami_ActionMenuItem@ + @kirigami_QML_DIR@/src/controls/private/ActionMenuItemBase.qml + @kirigami_QML_DIR@/src/controls/Separator.qml + @kirigami_QML_DIR@/src/controls/OverlayDrawer.qml + @kirigami_QML_DIR@/src/controls/OverlaySheet.qml + @kirigami_QML_DIR@/src/controls/GlobalDrawer.qml + @kirigami_QML_DIR@/src/controls/templates/AbstractListItem.qml + @kirigami_QML_DIR@/src/controls/templates/private/MenuIcon.qml + @kirigami_QML_DIR@/src/controls/templates/private/GenericDrawerIcon.qml + @kirigami_QML_DIR@/src/controls/templates/private/PassiveNotification.qml + @kirigami_QML_DIR@/src/controls/templates/private/ContextIcon.qml + @kirigami_QML_DIR@/src/controls/templates/private/ScrollView.qml + @kirigami_QML_DIR@/src/controls/templates/private/BackButton.qml + @kirigami_QML_DIR@/src/controls/templates/private/IconPropertiesGroup.qml + @kirigami_QML_DIR@/src/controls/templates/private/ForwardButton.qml + @kirigami_QML_DIR@/src/controls/templates/OverlayDrawer.qml + @kirigami_QML_DIR@/src/controls/templates/OverlaySheet.qml + @kirigami_QML_DIR@/src/controls/templates/SwipeListItem.qml + @kirigami_QML_DIR@/src/controls/templates/ApplicationHeader.qml + @kirigami_QML_DIR@/src/controls/templates/AbstractApplicationHeader.qml + @kirigami_QML_DIR@/src/controls/Units.qml + @kirigami_QML_DIR@/src/controls/SwipeListItem.qml + @kirigami_QML_DIR@/src/controls/ApplicationWindow.qml + @kirigami_QML_DIR@/src/controls/AbstractApplicationItem.qml + @kirigami_QML_DIR@/src/controls/ApplicationItem.qml + @kirigami_QML_DIR@/src/controls/ApplicationHeader.qml + @kirigami_QML_DIR@/src/controls/Heading.qml + @kirigami_QML_DIR@/src/controls/ScrollablePage.qml + @kirigami_QML_DIR@/src/controls/AboutPage.qml + @kirigami_QML_DIR@/src/controls/UrlButton.qml + @kirigami_QML_DIR@/src/controls/LinkButton.qml + @kirigami_QML_DIR@/src/controls/Label.qml + @kirigami_QML_DIR@/src/controls/BasicListItem.qml + @kirigami_QML_DIR@/src/controls/AbstractApplicationHeader.qml + @kirigami_QML_DIR@/src/controls/FormLayout.qml + @kirigami_QML_DIR@/src/controls/ListItemDragHandle.qml + @kirigami_QML_DIR@/src/styles/Material/AbstractListItem.qml + @kirigami_QML_DIR@/src/styles/Material/Theme.qml + @kirigami_QML_DIR@/src/styles/Material/SwipeListItem.qml + @kirigami_QML_DIR@/src/styles/Material/Label.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/AbstractListItem.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/Theme.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/Units.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/SwipeListItem.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/ApplicationWindow.qml + @kirigami_QML_DIR@/src/styles/org.kde.desktop/AbstractApplicationHeader.qml + + diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a63448dd83b45947471963aeea2689466633153b GIT binary patch literal 4954 zcmXw72Qb{v`~F5qfL=Y{}Pj5#Mr%Mn-I9+s3uNM-8J4A0$L-Z&SK}1RPB#2J5 zh>!?Tg46%^{muM$X7}CQd1rR#-S>U>d7r1ohPUA`1PlNGI9f;Z4oTwv>y+fA@q?<} zFiAkM8fa5WQVXYaj3=$Bd~__a0D#E(uY*cbo>-AK+5NRF{O@`@`v=+iIRQaIL1GWR z+_4UJK2BoZelB_2$_M~pm_}==n+E4^JwL`W-h0#E+0uS}*6Q6rs_3A{8%fzWITYwc zeGx~UfydXEkDMz_4GctvclKC6T}mGOJYs$G804Id7LdMnO@iqfGejUo-cFDzahErS z@DB6C;P+{yam%+%tGs{-QHqGjrweWi+dg$8D)TB?zF&%a*c<>TP_kzm%b-Rs53r+{ zaGzu}Tz-$>CFya@I7ZwRlmb9ihOVDj0eFFOKp8ASg~`NnlciG?Q7+MREltdfHZ<*L zh=Mvh>G78Ic|0UtFvkm)iLr~Cb;XRfNMTg49ay!LSwNQ8M$=O705gxQJ zp2ZBW`DdTZU5E9Q-cCzC+6wz?L~#+m0pL`Daj?C6M^j}(aVh`VRXMS&@do$lyeL;U zj}4SZC97%7$n0#ZgFBk27HKW^va|`?Z~jpLSK)^9i|Sg!Y*%MUz_g~;jFA9@2Zl%g zd~Z%wYV0Tq#(?d;z!VP3=hM1puJMDpkmYDU;UTs(gYYs2@{$2X*vF|T8Wf8zV)?21 zvu0`nd5RuldGNofD-vMTWn4z9KReKX^GFoGhALkZYBU@L%C3`io1i|EM_HEiY>)7g z5+$$GZgL!T-a1~)hs-fWT*K^Z^YB;L;CQm@K)JcO*AjRKEmTxg>gR`b`gG$a-FmCc z;28aZa4fmAi;M5poLPDn>tP48C2JNdk1lV{4rqC3(%sRaELt)a*IA%R1a?MfFP}6@ zaSU4g8a)E*+kidH+bq>oRAS~^{-zSLV9EVg?z4XmD^!^#?3l9Q-9*ul@kB^=2h^h0 zys=^XVBwY!QdhQso2DJ&6$Br&_`t_UoL^E!g`HZZ?n)I~f)fO3PzoS&a&k#&>6pR6 zen$s4dMzr|D4gTXFA9O3O{}W6qSj)9gV{Nwi4dQrTivoZ7UozvslkBu?f!wjiSPTz zJZR+L_>mfsuH)!rbZksp%0`xQe~{;+AZ}I`*Q@;!6uZ4d0Vs#F@p9ZPYpX&SzD#ti z$&>T?K2bUDBmc+M!vZbkEL(4%2jHpdbyymAW8-cEK(UFHQkQd6_i8O4`wdPShrbs` zJi}6Rb5_?Vkp-Hv{DweXt1C>lr}JWVRsl~SKmZNeUjjHD3F7$y9TagRV(H>YLRA&i z$2P@Yaq)<(@uyZXsOItJW!ExFIrT7QlyN6?6Vo*IZvEGI;p*O6HGp#(23OS7@UY9> zPw=9uXE^@=Mn&01ovr)GLzdWsKGp{=tk#m5@B?#?+y%&nBQC-hsr&=@vGI?9POgHI}9O9n8#SJK_YyXZ2I z{veq#0(X9Xj-KXL$<^d%7<`!D)~49_?c?sMpwIr#peuE=9_C0nxm0{78A5P8WUi5)8>oWbN!Z-e>h!lO8@8 zFUg{j)q)t8RX(JJn=Qq;?jcsgbf(UUxR5Xg|Xt*w_w_R8g$wb|A(FJL=T8tD$ z)|Us$Kt@BuF8`6S79Es$jugAP&e?wS=eE3Z*=dNLo^*|QThX+=aIQSCcCxgjma->p znYk+bT{B$uswMwkX|ihH)_l;N$cwaqpNJ?Ctx`}8OApWJsPWv$!O#a0ksB+1W~s`T zaraw%&OQ#N7lw6kPfSjxD&MgECxfehorN>y#_5)DVHzx!t4p!RhuaZyWpHrUPD!%A zt5fYR7*Bx2mr$CN__oTg2NQSf=E7bVki6zmmy{H(<7GR=SMof5w1#{2abIBq?`Af+ z@q8?z18Qszg3~7RFrd$;DQ@D)f|a?`pLuS`$Gz&j5ZF?2&&|`pavzrr7!A5kg3 z2oxRLP0auxf1jwGVoE$$eRuNPTc?1PCa&Rf0V2$oXqB6b7{nXszHXH5rF=mR5R#Jm zsyzuF9?BK@f9>Dq8P%DAPolPn8!BL`x{;p{`} zRzI2Qu<9z2hMEFr3Q3vhBznp&6ddIW&`|T=16BI_zjoOF$*NPpNKL+*OnaGeaL&c$ z8H)_F;8bMn8pvukIRuXiLm;>W80%u_en6^=CNKTjl2Vw2QeJ4~7%wGwE^(B2cWg*e z6~vE5-n^^MPByU*usIOV?|Y}nSQ9s&b@H)Ih|7(aHuy6C(d@nc1a)KcExiyr^;)-E zAKODi>k&xsuQJxLDeb!<`&%tpqZ#$Ze2l#tr|u?>9ix=Ugc)tR-2Nm2!9l=oe|^ts zcxTi0TyBua$e8T2JQC;kd;XruO3zTnFuK4Sx-W}Ur+s01c@DXv0!*%zinJ~^xp;qx zh@G3aN}M4k7Dp(3kO3Yt8!z>6c6mpgiiE4?(r_0>hH}bvo?d(TSE4VWWJ8+uryx$f zDN~9P$(FwayO@YQ2##FE@~clg8I+D3|cG8enA{(#wqL^gH9c2vop|F?wOcivYCC)>>ls7C2svTe%tFD&Xwcp zegFPHQgoP4?K7g1oU=?vAVW+(67un}v1T)^`^>4k|K*0uwSkiN?Gt#l+8TH>NT?b| z5p%SAc==B2tNnHJg(mSe(*0^I8mO6>k)Qbp0^1U=Y{p@?AAQIwbtrusvadL3ku1>X zdwM9U9G?9SBz;eQz5WON^VjoSt`9905zD^voR=YkZa~)XQ-}VG=Vo@=0;Ff})yrdf zuJqP-)w!?npZ#@Jkfyp&@EUI!+}OLd`-pRs-Fnhi;)&Qgr^}aoz7Sfz z(V@^taJ+ptWG3APx8N1`!K*)u^}R+^)bCuJ_0Fk#gYRln;>q?bc7cCxfbwd6L}=;@J|RGP|6eHd>>|HYPF6PQ#ywb+KAgx3VyJnSzo&n_pPiGnS<`qd9Qu7(Y7ad? zX!pagI$Fh}vC&ts?{&fHvt3n>#pVm2Z}TeMs0aywD9&LMw}u}OqN8tc zF!X^-8@jJWhvn?v`eDBPS+OzYbln)V9goU@uI6*34i?o>{R>SyJwE(r-LtS5rnx$e z880U&LH&)}jt5Y4^G;zM)KMJS1Nc7c5oQgMk?a>jmee3d^*+rmMmhOT$yFrgT zMnxjc&jQyC#Y5k>YVL8yEhKR%y>X6+x;H&rB17KXDC-0^-iFsy=tM2wxi_sqojl6# zW?pNZ1n0Qms}75cyS=k;)XJQJc(Mq^G~VQR38IWqH+-q$nJUci^n03-;mxW(qvZ9% zDA~2fG@WVIUUqiV|KdO0X%z`LMFD*leHUTHqe7~e`Pyu$LM2VuF!LuuOW|Qu$yYfT zY=^08Yh=8Nd=WsA0o-Lg;`HlUb;{FB$Djaa+0M7Zs}UqPv$1`V`m^}4P@_!|$YP@F zI#477U9hbBVdc$bnOqdGIaN|Ax&O@jflGq80Nvz$@Y`-iT%(?ay^aNK^(3sNJ-0@W z4e*$4RB%uTm5_gYzr`y}B@J9#vra%kIslwG#MF5Qikne~<0ZeUK3ZFI+W6KWx*E}& zDUjLx3{?(oYkj26gW`bux8}3UJwB1q;!c0Av6*$eJ6@=oc3AMLbGw_##55IbHiiG} z;zTV677inm?lZoZx5zl^g(%x*KKnCLpzi7UTbkU(W!>juxYtu&7#gZwRP0p*bIPcn z&aF^UG*uVqVrT#0F*NL}n8if*l$; zJvklIOE3PERWb&=sKewsSZJB(S6&k`qJHRUNyyBU5mvh_(cz5|Ms|I*0e|)UTvdBe zj{jy-z|J&}+1pR&&=<2l6R9jCuy0I3vKyer1&E)1ig)U|pKeC+roW7x^^o=7o>;<2 zkhCfF@^u1ri#8GeNJ}2o&hZdODC6|Bl^uzhO@}^b@X0RSYPaK-knk zfR$2_?2{WCM=oy;D~)K*M_i`(=yVn_en(#7ClpeJ-o`rq!#c-o9 z)7otJZ*oQz$oQXJ^$77UBpkH?GZ!=>xsc(7>e{arv6qnf7Eg3rWSYz2I_SJGM@vuDY5}@7^n$4j32Ll@V%EZKPpjbP`hz`|tnuC{jS+_K>1k z!_R(fJ2hPh_GIHoI6(%AW3?e&&fYmXo>h+%FqTUgRkmX4bm=>kIi0c5!9H0EC?goQ? z>I1ky_MM4QSAh9{;JcD{u0E2>+)XyyKPU=qUXy#J4S|v!ghO57>Mdc#WSwjrs6>8r z$U}Njyd)`?-3jk8GBo_2=l$?d^hb0JD;08>66*S(TlaJ3F6nbeQ<%h!KdGwvH{0jo ztH^mpHapuy@k;>jqjE7&`lLEDbKTnpt%Iy9fQ>iT?44$}H9zGt4~f>}g(Eih!44Tu zRemv$K6Z>rXugj!8i(km*%2?9Hu~+$es&Q`3I41$-bYZoWkBG_$9~|8L0C4GjQ+2B z@-M(y6=($n;u1bP$Mow-m-C}{;R5SzBWW_t1LP`vqZ3rXXnCwk!Hg=%wt&2dd(v#u zNAclYPZfuLU%#Nwv0vai{hcBu5dIrS1%=a{3addX;%`?OT*AmYpHgOdX(_XT0U@>z z%5X$31w?;p6>bHXhidI7Gnj?M#f{nnl&@-u?i$Aw*c#Nw?Csv+rSwX@(sH27Vp=xbX-)Re%zI{+5yZHu#w z@|WRkCO>`c!vyKdo#1!%^j;D<&!5Y@sC>-3sR_qyGmz?L^xvqA!^55y?_@Lj$+V2- z<~K;YjmQ;7P12D(fi|d5K@~&mIuUC9Jnas>sD(gFYRCb=l(TSTS$tEqdgU+C|!sY!7Ir1Py_{Vhs2e&R73f zlEe!%f^_w|7^8VN$q=X?|Dy<=HB)|a2gaKoUB}-_gFAu&8lIt6kMIC{s=LOHTx4Bj zfE2EBF)SkJQ$#I;cJV+c40n@9mQjF~TiM?}Jp3K;BsY`CDLnjaw>u`z5XgqonKg;; z4Gaw6ISH|aktdZehlhqX{F<&O#P06y_D7wqUS9m#=r7ENN`Ns*zF)f87(p{2;&h$o zR`6EylBZ>>y%rx^%`#vtMVBRjj{z-bcT7(QtuJ@q60EcB^!, 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-06-09 23:09+0300\n" +"Last-Translator: Safa Alfulaij \n" +"Language-Team: Arabic \n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "إجراءات" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "عُد" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "إجراءات" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "تنقّل للخلف" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "تنقّل للأمام" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "إجراءات أخرى" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/ca/libkirigami2plugin_qt.po b/po/ca/libkirigami2plugin_qt.po new file mode 100644 index 0000000..dce95b2 --- /dev/null +++ b/po/ca/libkirigami2plugin_qt.po @@ -0,0 +1,97 @@ +# Translation of libkirigami2plugin_qt.po to Catalan +# Copyright (C) 2016-2018 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Antoni Bella Pérez , 2016. +# Josep Ma. Ferrer , 2017, 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2019-01-05 16:19+0100\n" +"Last-Translator: Josep Ma. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Quant al " + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Drets d'autor" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Llicència:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Biblioteques en ús" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Autors" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Atribucions" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Traductors" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Accions" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Enrere" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Més accions" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navega enrere" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navega endavant" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Més accions" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Copia l'adreça de l'enllaç" diff --git a/po/ca@valencia/libkirigami2plugin_qt.po b/po/ca@valencia/libkirigami2plugin_qt.po new file mode 100644 index 0000000..5140a54 --- /dev/null +++ b/po/ca@valencia/libkirigami2plugin_qt.po @@ -0,0 +1,97 @@ +# Translation of libkirigami2plugin_qt.po to Catalan (Valencian) +# Copyright (C) 2016-2018 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Antoni Bella Pérez , 2016. +# Josep Ma. Ferrer , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2018-06-27 19:36+0100\n" +"Last-Translator: Josep Ma. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Accions" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Arrere" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Més accions" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navega arrere" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navega avant" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Més accions" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/cs/libkirigami2plugin_qt.po b/po/cs/libkirigami2plugin_qt.po new file mode 100644 index 0000000..0fc374c --- /dev/null +++ b/po/cs/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Vít Pelčák , 2016, 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-09 15:34+0100\n" +"Last-Translator: Vit Pelcak \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Činnosti" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Zpět" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Další činnosti" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Přejít zpět" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Přejít vpřed" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Další činnosti" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/da/libkirigami2plugin_qt.po b/po/da/libkirigami2plugin_qt.po new file mode 100644 index 0000000..1ae6389 --- /dev/null +++ b/po/da/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Martin Schlander , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-12 09:52+0100\n" +"Last-Translator: Martin Schlander \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Handlinger" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Tilbage" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Flere handlinger" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navigér tilbage" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navigér fremad" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Flere handlinger" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/de/libkirigami2plugin_qt.po b/po/de/libkirigami2plugin_qt.po new file mode 100644 index 0000000..58f6456 --- /dev/null +++ b/po/de/libkirigami2plugin_qt.po @@ -0,0 +1,91 @@ +# Frederik Schwarzer , 2016, 2018. +# Burkhard Lück , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-02 09:44+0100\n" +"Last-Translator: Burkhard Lück \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Aktionen" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Zurück" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Weitere Aktionen" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Zurück gehen" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Vorwärts gehen" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Weitere Aktionen" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/el/libkirigami2plugin_qt.po b/po/el/libkirigami2plugin_qt.po new file mode 100644 index 0000000..c564b60 --- /dev/null +++ b/po/el/libkirigami2plugin_qt.po @@ -0,0 +1,96 @@ +# Stelios , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2017-02-06 15:09+0200\n" +"Last-Translator: Stelios \n" +"Language-Team: Greek \n" +"Language: el_GR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Ενέργειες" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Πίσω" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Ενέργειες" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Ενέργειες" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/en_GB/libkirigami2plugin_qt.po b/po/en_GB/libkirigami2plugin_qt.po new file mode 100644 index 0000000..42b4b0b --- /dev/null +++ b/po/en_GB/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Steve Allewell , 2016, 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-06-30 13:29+0000\n" +"Last-Translator: Steve Allewell \n" +"Language-Team: British English \n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Actions" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Back" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "More Actions" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navigate Back" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navigate Forward" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "More Actions" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/es/libkirigami2plugin_qt.po b/po/es/libkirigami2plugin_qt.po new file mode 100644 index 0000000..0b13971 --- /dev/null +++ b/po/es/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Eloy Cuadra , 2016, 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: libkirigamiplugin_qt\n" +"PO-Revision-Date: 2018-07-03 12:21+0100\n" +"Last-Translator: Eloy Cuadra \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Acciones" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Atrás" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Más acciones" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Retroceder una página" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Avanzar una página" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Más acciones" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/eu/libkirigami2plugin_qt.po b/po/eu/libkirigami2plugin_qt.po new file mode 100644 index 0000000..0a85ec7 --- /dev/null +++ b/po/eu/libkirigami2plugin_qt.po @@ -0,0 +1,96 @@ +# Translation of libkirigami2plugin_qt.po to Euskara/Basque (eu). +# Copyright (C) 2017-2018, Free Software Foundation. +# This file is distributed under the same license as the frameworks package. +# KDE Euskaratzeko proiektuaren arduraduna . +# +# Translators: +# Iñigo Salvador Azurmendi , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2018-06-30 02:00+0100\n" +"Last-Translator: Iñigo Salvador Azurmendi \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Ekintzak" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Atzera" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Ekintza gehiago" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Nabigatu atzera" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Nabigatu aurrera" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Ekintza gehiago" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/fi/libkirigami2plugin_qt.po b/po/fi/libkirigami2plugin_qt.po new file mode 100644 index 0000000..3ce6d38 --- /dev/null +++ b/po/fi/libkirigami2plugin_qt.po @@ -0,0 +1,91 @@ +# Lasse Liehu , 2017. +# Tommi Nieminen , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-12 17:29+0200\n" +"Last-Translator: Tommi Nieminen \n" +"Language-Team: Finnish \n" +"Language: fi_FI\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Toiminnot" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Takaisin" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Lisää toimintoja" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Siirry taaksepäin" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Siirry eteenpäin" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Lisää toimintoja" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/fr/libkirigami2plugin_qt.po b/po/fr/libkirigami2plugin_qt.po new file mode 100644 index 0000000..9782581 --- /dev/null +++ b/po/fr/libkirigami2plugin_qt.po @@ -0,0 +1,94 @@ +# Vincent Pinon , 2016, 2017. +# Simon Depiets , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-06-29 15:08+0800\n" +"Last-Translator: Simon Depiets \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Actions" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Retour" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Actions supplémentaires" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navigation arrière" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navigation avant" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Actions supplémentaires" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/gl/libkirigami2plugin_qt.po b/po/gl/libkirigami2plugin_qt.po new file mode 100644 index 0000000..01635ba --- /dev/null +++ b/po/gl/libkirigami2plugin_qt.po @@ -0,0 +1,91 @@ +# Adrián Chaves Fernández (Gallaecio) , 2017. +# Adrián Chaves (Gallaecio) , 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2019-01-05 10:47+0100\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Sobre" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Dereitos de copia" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Licenza:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Bibliotecas usadas" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Autores" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Recoñecementos" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Tradutores" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Accións" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Atrás" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Máis accións" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Volver" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Continuar" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Máis accións" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Copiar o enderezo da ligazón" diff --git a/po/hu/libkirigami2plugin_qt.po b/po/hu/libkirigami2plugin_qt.po new file mode 100644 index 0000000..f94bfff --- /dev/null +++ b/po/hu/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Kiszel Kristóf , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-10-13 21:10+0200\n" +"Last-Translator: Kristof Kiszel \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Műveletek" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Vissza" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "További műveletek" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Vissza" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Előre" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "További műveletek" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/ia/libkirigami2plugin_qt.po b/po/ia/libkirigami2plugin_qt.po new file mode 100644 index 0000000..99c8e24 --- /dev/null +++ b/po/ia/libkirigami2plugin_qt.po @@ -0,0 +1,96 @@ +# giovanni , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2017-09-14 23:23+0100\n" +"Last-Translator: giovanni \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Actiones" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Retro" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Actiones" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Actiones" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/id/libkirigami2plugin_qt.po b/po/id/libkirigami2plugin_qt.po new file mode 100644 index 0000000..17cf68d --- /dev/null +++ b/po/id/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Wantoyo , 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-16 07:44+0700\n" +"Last-Translator: wantoyo \n" +"Language-Team: Indonesian \n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Aksi" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Mundur" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Aksi Selebihnya" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navigasi Mundur" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navigasi Maju" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Aksi Selebihnya" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/it/libkirigami2plugin_qt.po b/po/it/libkirigami2plugin_qt.po new file mode 100644 index 0000000..f659152 --- /dev/null +++ b/po/it/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Vincenzo Reale , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-06-27 19:45+0100\n" +"Last-Translator: Vincenzo Reale \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Azioni" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Indietro" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Altre azioni" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Naviga indietro" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Naviga in avanti" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Altre azioni" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/ja/libkirigami2plugin_qt.po b/po/ja/libkirigami2plugin_qt.po new file mode 100644 index 0000000..d1d48ea --- /dev/null +++ b/po/ja/libkirigami2plugin_qt.po @@ -0,0 +1,88 @@ +msgid "" +msgstr "" +"Project-Id-Version: libkirigamiplugin_qt\n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/ko/libkirigami2plugin_qt.po b/po/ko/libkirigami2plugin_qt.po new file mode 100644 index 0000000..29ce99f --- /dev/null +++ b/po/ko/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Shinjo Park , 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-08-14 23:16+0100\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "동작" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "뒤로" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "더 많은 동작" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "이전 탐색" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "다음 탐색" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "더 많은 동작" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/nl/libkirigami2plugin_qt.po b/po/nl/libkirigami2plugin_qt.po new file mode 100644 index 0000000..fd0b28c --- /dev/null +++ b/po/nl/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Freek de Kruijf , 2016, 2017, 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2019-01-05 10:42+0100\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Info over" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Copyright" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Licentie:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Bibliotheken in gebruik" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Auteurs" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Dankbetuigingen" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Vertalers" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Acties" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Terug" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Meer acties" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Naar achteren navigeren" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Naar voren navigeren" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Meer acties" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Koppelingsadres kopiëren" diff --git a/po/nn/libkirigami2plugin_qt.po b/po/nn/libkirigami2plugin_qt.po new file mode 100644 index 0000000..afdd661 --- /dev/null +++ b/po/nn/libkirigami2plugin_qt.po @@ -0,0 +1,95 @@ +# Translation of libkirigami2plugin_qt to Norwegian Nynorsk +# +# Karl Ove Hufthammer , 2016, 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2019-01-05 14:08+0100\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 19.03.70\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Qt-Contexts: true\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Om" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Opphavsrett" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Lisens:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Brukte bibliotek" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Forfattarar" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Kreditering" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Omsetjarar" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Handlingar" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Tilbake" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Fleire handlingar" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Naviger tilbake" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Naviger fram" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Fleire handlingar" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Kopier lenkjeadresse" diff --git a/po/pl/libkirigami2plugin_qt.po b/po/pl/libkirigami2plugin_qt.po new file mode 100644 index 0000000..e653067 --- /dev/null +++ b/po/pl/libkirigami2plugin_qt.po @@ -0,0 +1,91 @@ +# Łukasz Wojniłowicz , 2016, 2017, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-07-14 07:17+0100\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Działania" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Wstecz" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Więcej działań" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Przejdź wstecz" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Przejdź naprzód" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Więcej działań" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/pt/libkirigami2plugin_qt.po b/po/pt/libkirigami2plugin_qt.po new file mode 100644 index 0000000..ac711bd --- /dev/null +++ b/po/pt/libkirigami2plugin_qt.po @@ -0,0 +1,92 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2019-01-06 10:33+0000\n" +"Last-Translator: José Nuno Coelho Pires \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Acerca" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "'Copyright'" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Licença:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Bibliotecas usadas" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Autores" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Créditos" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Tradutores" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Acções" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Recuar" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Mais Acções" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navegar para Trás" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navegar para a Frente" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Mais Acções" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Copiar o endereço da ligação" diff --git a/po/pt_BR/libkirigami2plugin_qt.po b/po/pt_BR/libkirigami2plugin_qt.po new file mode 100644 index 0000000..0d74050 --- /dev/null +++ b/po/pt_BR/libkirigami2plugin_qt.po @@ -0,0 +1,96 @@ +# Translation of libkirigami2plugin_qt.po to Brazilian Portuguese +# Copyright (C) 2016-2019 This_file_is_part_of_KDE +# This file is distributed under the same license as the PACKAGE package. +# +# Luiz Fernando Ranghetti , 2016, 2017, 2018. +# André Marcelo Alvarenga , 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"PO-Revision-Date: 2019-01-05 14:32-0200\n" +"Last-Translator: André Marcelo Alvarenga \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 18.12.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Sobre" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Copyright" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Licença:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Bibliotecas em uso" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Autores" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Créditos" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Tradutores" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Ações" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Voltar" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Mais ações" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Voltar" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Avançar" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Mais ações" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Copiar endereço do link" diff --git a/po/ru/libkirigami2plugin_qt.po b/po/ru/libkirigami2plugin_qt.po new file mode 100644 index 0000000..7a327fc --- /dev/null +++ b/po/ru/libkirigami2plugin_qt.po @@ -0,0 +1,97 @@ +# Alexander Potashev , 2016, 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2017-11-28 13:27+0300\n" +"Last-Translator: Alexander Potashev \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Действия" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Назад" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Действия" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Перейти назад" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Перейти вперёд" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Действия" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/sk/libkirigami2plugin_qt.po b/po/sk/libkirigami2plugin_qt.po new file mode 100644 index 0000000..fff6f55 --- /dev/null +++ b/po/sk/libkirigami2plugin_qt.po @@ -0,0 +1,99 @@ +# translation of libkirigamiplugin_qt.po to Slovak +# Roman Paholik , 2016. +msgid "" +msgstr "" +"Project-Id-Version: libkirigamiplugin_qt\n" +"Report-Msgid-Bugs-To: http://bugs.kde.org\n" +"POT-Creation-Date: 2016-08-05 07:24+0000\n" +"PO-Revision-Date: 2016-08-07 12:15+0100\n" +"Last-Translator: Roman Paholik \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Akcie" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Späť" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Akcie" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Akcie" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/sl/libkirigami2plugin_qt.po b/po/sl/libkirigami2plugin_qt.po new file mode 100644 index 0000000..042a7e5 --- /dev/null +++ b/po/sl/libkirigami2plugin_qt.po @@ -0,0 +1,97 @@ +# Andrej Mernik , 2016, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2018-01-12 21:16+0100\n" +"Last-Translator: Andrej Mernik \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Dejanja" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Nazaj" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Dejanja" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Krmari nazaj" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Krmari naprej" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Dejanja" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/sr/libkirigami2plugin_qt.po b/po/sr/libkirigami2plugin_qt.po new file mode 100644 index 0000000..e0ac5de --- /dev/null +++ b/po/sr/libkirigami2plugin_qt.po @@ -0,0 +1,54 @@ +# Translation of libkirigami2plugin_qt.po into Serbian. +# Chusslove Illich , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2017-10-06 17:14+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Environment: kde\n" +"X-Qt-Contexts: true\n" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Радње" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Назад" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Радње" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Иди назад" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Иди напред" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Радње" diff --git a/po/sr@ijekavian/libkirigami2plugin_qt.po b/po/sr@ijekavian/libkirigami2plugin_qt.po new file mode 100644 index 0000000..8fa8d0f --- /dev/null +++ b/po/sr@ijekavian/libkirigami2plugin_qt.po @@ -0,0 +1,54 @@ +# Translation of libkirigami2plugin_qt.po into Serbian. +# Chusslove Illich , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2017-10-06 17:14+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@ijekavian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Environment: kde\n" +"X-Qt-Contexts: true\n" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Радње" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Назад" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Радње" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Иди назад" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Иди напред" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Радње" diff --git a/po/sr@ijekavianlatin/libkirigami2plugin_qt.po b/po/sr@ijekavianlatin/libkirigami2plugin_qt.po new file mode 100644 index 0000000..52ef345 --- /dev/null +++ b/po/sr@ijekavianlatin/libkirigami2plugin_qt.po @@ -0,0 +1,54 @@ +# Translation of libkirigami2plugin_qt.po into Serbian. +# Chusslove Illich , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2017-10-06 17:14+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@ijekavianlatin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Environment: kde\n" +"X-Qt-Contexts: true\n" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Radnje" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Nazad" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Radnje" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Idi nazad" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Idi napred" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Radnje" diff --git a/po/sr@latin/libkirigami2plugin_qt.po b/po/sr@latin/libkirigami2plugin_qt.po new file mode 100644 index 0000000..17cfc66 --- /dev/null +++ b/po/sr@latin/libkirigami2plugin_qt.po @@ -0,0 +1,54 @@ +# Translation of libkirigami2plugin_qt.po into Serbian. +# Chusslove Illich , 2017. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2017-10-06 17:14+0200\n" +"Last-Translator: Chusslove Illich \n" +"Language-Team: Serbian \n" +"Language: sr@latin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: qtrich\n" +"X-Environment: kde\n" +"X-Qt-Contexts: true\n" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Radnje" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Nazad" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Radnje" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Idi nazad" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Idi napred" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Radnje" diff --git a/po/sv/libkirigami2plugin_qt.po b/po/sv/libkirigami2plugin_qt.po new file mode 100644 index 0000000..7176e4b --- /dev/null +++ b/po/sv/libkirigami2plugin_qt.po @@ -0,0 +1,90 @@ +# Stefan Asserhäll , 2016, 2017, 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"PO-Revision-Date: 2019-01-06 11:29+0100\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Om" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Copyright" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Licens:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Använda bibliotek" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Upphovsmän" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Tack till" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Översättare" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Åtgärder" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Tillbaka" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Fler åtgärder" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Navigera bakåt" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Navigera framåt" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Fler åtgärder" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Kopiera länkadress" diff --git a/po/tr/libkirigami2plugin_qt.po b/po/tr/libkirigami2plugin_qt.po new file mode 100644 index 0000000..0561940 --- /dev/null +++ b/po/tr/libkirigami2plugin_qt.po @@ -0,0 +1,94 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2017-10-23 09:50+0000\n" +"Last-Translator: Kaan \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Pootle 2.5.1.1\n" +"X-Qt-Contexts: true\n" +"X-POOTLE-MTIME: 1497529432.000000\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Eylemler" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Geri" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Eylemler" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Geriye Git" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "İleri Git" + +#: controls/ToolBarApplicationHeader.qml:126 +#, fuzzy +#| msgctxt "ContextDrawer|" +#| msgid "Actions" +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Eylemler" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/uk/libkirigami2plugin_qt.po b/po/uk/libkirigami2plugin_qt.po new file mode 100644 index 0000000..5ff5bf9 --- /dev/null +++ b/po/uk/libkirigami2plugin_qt.po @@ -0,0 +1,96 @@ +# Translation of libkirigami2plugin_qt.po to Ukrainian +# Copyright (C) 2016-2019 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Yuri Chornoivan , 2016, 2017, 2018, 2019. +msgid "" +msgstr "" +"Project-Id-Version: libkirigami2plugin_qt\n" +"PO-Revision-Date: 2019-01-05 09:23+0200\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 2.0\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "Про програму" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "%1 <%2>" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "Авторські права" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "Ліцензування:" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "Використані бібліотеки:" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "Автори" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "Подяки" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "Перекладачі" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "Дії" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "Назад" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "Інші дії" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "Перейти назад" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "Перейти далі" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "Інші дії" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "Копіювати адресу посилання" diff --git a/po/zh_CN/libkirigami2plugin_qt.po b/po/zh_CN/libkirigami2plugin_qt.po new file mode 100644 index 0000000..533f983 --- /dev/null +++ b/po/zh_CN/libkirigami2plugin_qt.po @@ -0,0 +1,93 @@ +# Weng Xuetian , 2016. +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"PO-Revision-Date: 2019-01-05 20:42\n" +"Last-Translator: guoyunhe \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: crowdin.com\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf5-trunk/messages/frameworks/libkirigami2plugin_qt.pot\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "动作" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "后退" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "更多动作" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "后退" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "前进" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "更多动作" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/po/zh_TW/libkirigami2plugin_qt.po b/po/zh_TW/libkirigami2plugin_qt.po new file mode 100644 index 0000000..bc5aa0b --- /dev/null +++ b/po/zh_TW/libkirigami2plugin_qt.po @@ -0,0 +1,94 @@ +# Jeff Huang , 2016. +# Franklin Weng , 2017. +# pan93412 , 2018. +msgid "" +msgstr "" +"Project-Id-Version: libkirigamiplugin_qt\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-09-22 20:41+0800\n" +"PO-Revision-Date: 2018-07-09 21:44+0800\n" +"Last-Translator: pan93412 \n" +"Language-Team: Chinese \n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"X-Qt-Contexts: true\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: controls/AboutPage.qml:79 +msgctxt "AboutPage|" +msgid "About" +msgstr "" + +#: controls/AboutPage.qml:107 +#, qt-format +msgctxt "AboutPage|" +msgid "%1 <%2>" +msgstr "" + +#: controls/AboutPage.qml:142 +msgctxt "AboutPage|" +msgid "Copyright" +msgstr "" + +#: controls/AboutPage.qml:164 +msgctxt "AboutPage|" +msgid "License:" +msgstr "" + +#: controls/AboutPage.qml:173 +msgctxt "AboutPage|" +msgid "Libraries in use" +msgstr "" + +#: controls/AboutPage.qml:186 +msgctxt "AboutPage|" +msgid "Authors" +msgstr "" + +#: controls/AboutPage.qml:194 +msgctxt "AboutPage|" +msgid "Credits" +msgstr "" + +#: controls/AboutPage.qml:203 +msgctxt "AboutPage|" +msgid "Translators" +msgstr "" + +#: controls/ContextDrawer.qml:77 +msgctxt "ContextDrawer|" +msgid "Actions" +msgstr "動作" + +#: controls/GlobalDrawer.qml:446 +msgctxt "GlobalDrawer|" +msgid "Back" +msgstr "返回" + +#: controls/private/globaltoolbar/ToolBarPageHeader.qml:112 +msgctxt "ToolBarPageHeader|" +msgid "More Actions" +msgstr "更多動作" + +#: controls/templates/private/BackButton.qml:50 +msgctxt "BackButton|" +msgid "Navigate Back" +msgstr "返回" + +#: controls/templates/private/ForwardButton.qml:46 +msgctxt "ForwardButton|" +msgid "Navigate Forward" +msgstr "往前" + +#: controls/ToolBarApplicationHeader.qml:126 +msgctxt "ToolBarApplicationHeader|" +msgid "More Actions" +msgstr "更多動作" + +#: controls/UrlButton.qml:51 +msgctxt "UrlButton|" +msgid "Copy link address" +msgstr "" diff --git a/scripts/gen_icons_qrc.sh b/scripts/gen_icons_qrc.sh new file mode 100755 index 0000000..9606f20 --- /dev/null +++ b/scripts/gen_icons_qrc.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +SRC_DIR="src/" +BREEZEICONS_DIR="breeze-icons" +ICONS_SIZES=(48 32 22) +TAB=" " + +kirigami_dir="$(cd $(dirname $(readlink -f $0))/.. && pwd)" + +case $1 in +-h|--help) + echo "usage: $(basename $0)" + exit 1 + ;; +esac + +if [[ ! -d ${kirigami_dir}/${BREEZEICONS_DIR} ]]; then + echo "could not find ${BREEZEICONS_DIR}, please clone breeze-icons frist into ${BREEZEICONS_DIR}:" + echo "cd ${kirigami_dir} && git clone --depth 1 git://anongit.kde.org/breeze-icons.git ${BREEZEICONS_DIR}" + exit 1 +fi + +pushd ${kirigami_dir} > /dev/null + +# find strings associated to variable with 'icon' in name and put them into an array +if [[ -n $(which ag 2>/dev/null) ]]; then + possible_icons=($(ag --ignore Icon.qml --file-search-regex "\.qml" --only-matching --nonumbers --noheading --nofilename "icon.*\".+\"" ${SRC_DIR} | egrep -o "*\".+\"")) + # try to find in Icon { ... source: "xyz" ... } + possible_icons+=($(ag --ignore Icon.qml --file-search-regex "\.qml" -A 15 "Icon\s*{" ${SRC_DIR} | egrep "source:" | egrep -o "*\".+\"")) +else + possible_icons=($(find ${SRC_DIR} -name "*.qml" -and -not -name "Icon.qml" -exec egrep "icon.*\".+\"" {} \; | egrep -o "*\".+\"")) +fi + +# sort array and filter out all entry which are not a string ("...") +IFS=$'\n' icons=($(sort -u <<<"${possible_icons[*]}" | egrep -o "*\".+\"" | sed 's/\"//g')) +unset IFS + +#printf "%s\n" "${icons[@]}" + +# generate .qrc +echo "" +echo "${TAB}" + +for icon in ${icons[@]}; do + for size in ${ICONS_SIZES[@]}; do + file=$(find breeze-icons/icons/*/${size}/ -name "${icon}.*" -print -quit) + + if [[ -n ${file} ]]; then + echo -e "${TAB}${TAB}${file}" + #echo ${file} + break + fi + done +done + +echo "${TAB}" +echo "" + +popd > /dev/null diff --git a/scripts/gen_qml_qrc.sh b/scripts/gen_qml_qrc.sh new file mode 100755 index 0000000..df61e07 --- /dev/null +++ b/scripts/gen_qml_qrc.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +TAB=" " + +kirigami_dir="$(cd $(dirname $(readlink -f $0))/.. && pwd)" + +case $1 in +-h|--help) + echo "usage: $(basename $0) [QRC_FILE]" + exit 1 + ;; +esac + +pushd ${kirigami_dir} > /dev/null + +tmpfile=$(mktemp) + +echo "" > ${tmpfile} +echo "${TAB}" >> ${tmpfile} + +for i in $(find src/controls/ -name *.qml); do + echo -e "${TAB}${TAB}${i}" >> ${tmpfile}; +done +for i in $(find src/styles/ -name *.qml); do + echo -e "${TAB}${TAB}${i}" >> ${tmpfile}; +done + +echo "${TAB}" >> ${tmpfile} +echo "" >> ${tmpfile} + +if [[ -n $1 ]]; then + cat ${tmpfile} > $1 +else + cat ${tmpfile} +fi + +unlink ${tmpfile} + +popd > /dev/null diff --git a/scripts/gen_qmltypes.sh b/scripts/gen_qmltypes.sh new file mode 100755 index 0000000..8606f99 --- /dev/null +++ b/scripts/gen_qmltypes.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +QMLPLUGINDUMP=${QMLPLUGINDUMP-qmlplugindump} + +case $1 in +-h|--help) + echo "usage: $(basename $0) IMPORT_PATH" + echo "it uses either '$(which qmlplugindump)' or the one set by 'QMLPLUGINDUMP'" + exit 1 + ;; +esac + +[[ -z ${1} ]] && { echo "no import path not given, exit"; exit 1; } + +echo "using '${QMLPLUGINDUMP}' as dump tool" >&2 + +${QMLPLUGINDUMP} -noinstantiate -notrelocatable -platform xcb org.kde.kirigami 2.0 "${1}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..3e1c35a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,123 @@ +project(kirigami) + +if (NOT STATIC_LIBRARY) + ecm_create_qm_loader(kirigami_QM_LOADER libkirigami2plugin_qt) +else() + set(KIRIGAMI_STATIC_FILES + libkirigami/basictheme.cpp + libkirigami/platformtheme.cpp + libkirigami/tabletmodewatcher.cpp + libkirigami/kirigamipluginfactory.cpp) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libkirigami ${CMAKE_CURRENT_BINARY_DIR}/libkirigami) + +set(kirigami_SRCS + kirigamiplugin.cpp + enums.cpp + delegaterecycler.cpp + desktopicon.cpp + settings.cpp + formlayoutattached.cpp + scenepositionattached.cpp + mnemonicattached.cpp + ${kirigami_QM_LOADER} + ${KIRIGAMI_STATIC_FILES} + ) + +add_subdirectory(libkirigami) + +if(STATIC_LIBRARY) + # Set some variables to insert the right files in the QRC + if(Qt5Qml_VERSION VERSION_LESS 5.10) + set(kirigami_ActionMenuItem ActionMenuItemQt59.qml) + else() + set(kirigami_ActionMenuItem ActionMenuItemQt510.qml) + endif() + + # `rcc` is a bit dumb and isn't designed to use auto generated files, to + # avoid poluting the source directory, use absolute paths + set(kirigami_QML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) + + # First, pre-process the QRC to add the files associated with the right Qt + # version. + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/../kirigami.qrc.in + ${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc + @ONLY + ) + + # When using the static library, all QML files need to be shipped within the + # .a file. + qt5_add_resources( + RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc + ) +endif(STATIC_LIBRARY) + + +add_library(kirigamiplugin ${kirigami_SRCS} ${RESOURCES}) + +if(STATIC_LIBRARY) + SET_TARGET_PROPERTIES(kirigamiplugin PROPERTIES + AUTOMOC_MOC_OPTIONS -Muri=org.kde.kirigami) + if (UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT(APPLE) AND NOT(DISABLE_DBUS)) + set(Kirigami_EXTRA_LIBS Qt5::DBus) + else() + set(Kirigami_EXTRA_LIBS "") + endif() +else(STATIC_LIBRARY) + set(Kirigami_EXTRA_LIBS KF5::Kirigami2) +endif(STATIC_LIBRARY) + + +target_link_libraries(kirigamiplugin + PUBLIC + Qt5::Core + PRIVATE + ${Kirigami_EXTRA_LIBS} Qt5::Qml Qt5::Quick Qt5::QuickControls2 + ) + +if (NOT STATIC_LIBRARY) + + add_custom_target(copy) + + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2) + add_custom_command(TARGET copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/controls ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/) + add_custom_command(TARGET copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/styles ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/styles) + + add_dependencies(kirigamiplugin copy) + + install(DIRECTORY controls/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2) + if(Qt5Qml_VERSION VERSION_LESS 5.10) + install(FILES controls/private/ActionMenuItemQt59.qml DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/private + RENAME ActionMenuItem.qml) + else() + install(FILES controls/private/ActionMenuItemQt510.qml DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/private + RENAME ActionMenuItem.qml) + endif() + + if (PLASMA_ENABLED) + install(DIRECTORY styles/Plasma DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) + endif() + if (DESKTOP_ENABLED) + install(DIRECTORY styles/org.kde.desktop DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) + endif() + if (PLASMA_ENABLED AND DESKTOP_ENABLED) + install(DIRECTORY styles/org.kde.desktop.plasma DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) + endif() + install(DIRECTORY styles/Material DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) + + install(FILES ${platformspecific} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2) + + include(ECMGeneratePriFile) + ecm_generate_pri_file(BASE_NAME Kirigami2 LIB_NAME KF5Kirigami2 DEPS "core qml quick svg" FILENAME_VAR PRI_FILENAME ) + install(FILES ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) + +endif(NOT STATIC_LIBRARY) + +install(TARGETS kirigamiplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2) diff --git a/src/Messages.sh b/src/Messages.sh new file mode 100644 index 0000000..49c04b5 --- /dev/null +++ b/src/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACT_TR_STRINGS `find . -name \*.qml` -o $podir/libkirigami2plugin_qt.pot +rm -f rc.cpp + diff --git a/src/controls/AboutPage.qml b/src/controls/AboutPage.qml new file mode 100644 index 0000000..6840ca3 --- /dev/null +++ b/src/controls/AboutPage.qml @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library/Lesser General Public License + * version 2, or (at your option) any later version, as published by the + * Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library/Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Controls 2.4 as QQC2 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.5 + +/** + * An about page that is ready to integrate in a kirigami app + * + * Allows to have a page that will show the copyright notice of the application + * together with the contributors and some information of which platform it's + * running on. + * + * @since 5.52 + * @since org.kde.kirigami 2.6 + */ +ScrollablePage +{ + id: page + /** + * An object with the same shape of KAboutData + * + * For example: + * @code + * aboutData: { + "displayName" : "KirigamiApp", + "productName" : "kirigami/app", + "componentName" : "kirigamiapp", + "shortDescription" : "A Kirigami example", + "homepage" : "", + "bugAddress" : "submit@bugs.kde.org", + "version" : "5.14.80", + "otherText" : "", + "authors" : [ + { + "name" : "...", + "task" : "", + "emailAddress" : "somebody@kde.org", + "webAddress" : "", + "ocsUsername" : "" + } + ], + "credits" : [], + "translators" : [], + "licenses" : [ + { + "name" : "GPL v2", + "text" : "long, boring, license text", + "spdx" : "GPL-2.0" + } + ], + "copyrightStatement" : "© 2010-2018 Plasma Development Team", + "desktopFileName" : "org.kde.kirigamiapp" + } + @endcode + * + * @see KAboutData + */ + property var aboutData + + title: qsTr("About") + Component { + id: licencePage + ScrollablePage { + property alias text: content.text + QQC2.TextArea { + id: content + readOnly: true + } + } + } + + Component { + id: personDelegate + AbstractCard { + Layout.fillWidth: true + contentItem: RowLayout { + Layout.preferredHeight: Units.iconSizes.medium + Icon { + Layout.fillHeight: true + Layout.alignment: Qt.AlignVCenter + Layout.minimumWidth: Units.iconSizes.medium + Layout.maximumWidth: Units.iconSizes.medium + source: "user" //TODO: use ocs once we don't need to depend on attica, was using gravatar but it didn't feel right + fallback: "user" + } + QQC2.Label { + Layout.fillWidth: true + text: qsTr("%1 <%2>").arg(modelData.name).arg(modelData.emailAddress); + } + } + } + } + + ColumnLayout { + GridLayout { + columns: 2 + Layout.fillWidth: true + Layout.preferredHeight: Units.iconSizes.huge + + Icon { + Layout.rowSpan: 2 + Layout.fillHeight: true + Layout.minimumWidth: height + Layout.rightMargin: Units.largeSpacing + source: page.aboutData.programLogo || page.aboutData.programIconName + } + Heading { + Layout.fillWidth: true + text: page.aboutData.displayName + " " + page.aboutData.version + } + Heading { + Layout.fillWidth: true + level: 2 + text: page.aboutData.shortDescription + } + } + + Separator { + Layout.fillWidth: true + } + + Heading { + text: qsTr("Copyright") + } + QQC2.Label { + Layout.leftMargin: Units.gridUnit + text: aboutData.otherText + visible: text.length > 0 + } + QQC2.Label { + Layout.leftMargin: Units.gridUnit + text: aboutData.copyrightStatement + visible: text.length > 0 + } + UrlButton { + Layout.leftMargin: Units.gridUnit + url: aboutData.homepage + visible: url.length > 0 + } + + Repeater { + model: aboutData.licenses + delegate: RowLayout { + Layout.leftMargin: Units.gridUnit + QQC2.Label { text: qsTr("License:" ) } + LinkButton { + text: modelData.name + onClicked: applicationWindow().pageStack.push(licencePage, { text: modelData.text, title: modelData.name } ) + } + } + } + + Heading { + text: qsTr("Libraries in use") + visible: Settings.information + } + Repeater { + model: Settings.information + delegate: QQC2.Label { + Layout.leftMargin: Units.gridUnit + id: libraries + text: modelData + } + } + Heading { + Layout.fillWidth: true + text: qsTr("Authors") + } + + Repeater { + model: aboutData.authors + delegate: personDelegate + } + Heading { + text: qsTr("Credits") + visible: repCredits.count > 0 + } + Repeater { + id: repCredits + model: aboutData.translators + delegate: personDelegate + } + Heading { + text: qsTr("Translators") + visible: repTranslators.count > 0 + } + Repeater { + id: repTranslators + model: aboutData.translators + delegate: personDelegate + } + } +} diff --git a/src/controls/AbstractApplicationHeader.qml b/src/controls/AbstractApplicationHeader.qml new file mode 100644 index 0000000..2611b82 --- /dev/null +++ b/src/controls/AbstractApplicationHeader.qml @@ -0,0 +1,73 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.5 + +import "private" +import "templates" as T + + +/** + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * minimumHeight: default is 0, i.e. hidden + * * preferredHeight: default is Units.gridUnit * 1.6 + * * maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + */ +T.AbstractApplicationHeader { + id: root + + Theme.inherit: false + Theme.textColor: root.parent.Theme.highlightedTextColor + Theme.backgroundColor: root.parent.Theme.highlightColor + Theme.highlightColor: root.parent.Theme.backgroundColor + + background: Rectangle { + color: Theme.backgroundColor + EdgeShadow { + id: shadow + visible: root.separatorVisible + anchors { + right: parent.right + left: parent.left + top: parent.bottom + } + edge: Qt.TopEdge + opacity: (!root.page.header || root.page.header.toString().indexOf("ToolBar") === -1) + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } +} + diff --git a/src/controls/AbstractApplicationItem.qml b/src/controls/AbstractApplicationItem.qml new file mode 100644 index 0000000..437606f --- /dev/null +++ b/src/controls/AbstractApplicationItem.qml @@ -0,0 +1,366 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Templates 2.0 as T2 +import QtQuick.Window 2.2 +import "templates/private" +import org.kde.kirigami 2.4 +import QtGraphicalEffects 1.0 + +/** + * A window that provides some basic features needed for all apps + * Use this class only if you need a custom content for your application, + * different from the Page Row behavior recommended by the HIG and provided + * by ApplicationItem. + * It is recommended to use ApplicationItem instead + * @see ApplicationItem + * + * It's usually used as a root QML component for the application. + * It provides support for a central page stack, side drawers and + * a top ApplicationHeader, as well as basic support for the + * Android back button + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationItem { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * + * pageStack: PageStack { + * ... + * } + * [...] + * } + * @endcode + * + * @inherit QtQuick.Item + */ +Item { + id: root + + /** + * pageStack: StackView + * Readonly. + * The stack used to allocate the pages and to manage the transitions + * between them. + * Put a container here, such as QQuickControls PageStack + */ + property Item pageStack + LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + property alias overlay: overlayRoot + Item { + anchors.fill: parent + parent: root.parent + z: 999999 + Rectangle { + z: -1 + anchors.fill: parent + color: "black" + visible: contextDrawer && contextDrawer.modal + parent: contextDrawer ? contextDrawer.background.parent.parent : overlayRoot + opacity: contextDrawer ? contextDrawer.position * 0.6 : 0 + } + Rectangle { + z: -1 + anchors.fill: parent + color: "black" + visible: globalDrawer && globalDrawer.modal + parent: contextDrawer ? globalDrawer.background.parent.parent : overlayRoot + opacity: contextDrawer ? globalDrawer.position * 0.6 : 0 + } + Item { + id: overlayRoot + z: -1 + anchors.fill: parent + } + Window.onWindowChanged: { + if (globalDrawer) { + globalDrawer.visible = globalDrawer.drawerOpen; + } + if (contextDrawer) { + contextDrawer.visible = contextDrawer.drawerOpen; + } + } + } + + /** + * copatibility with Applicationwindow + */ + readonly property Item activeFocusItem: Window.activeFocusItem + /** + * Shows a little passive notification at the bottom of the app window + * lasting for few seconds, with an optional action button. + * + * @param message The text message to be shown to the user. + * @param timeout How long to show the message: + * possible values: "short", "long" or the number of milliseconds + * @param actionText Text in the action button, if any. + * @param callBack A JavaScript function that will be executed when the + * user clicks the button. + */ + function showPassiveNotification(message, timeout, actionText, callBack) { + if (!internal.__passiveNotification) { + var component = Qt.createComponent("templates/private/PassiveNotification.qml"); + internal.__passiveNotification = component.createObject(overlay.parent); + } + + internal.__passiveNotification.showNotification(message, timeout, actionText, callBack); + } + + /** + * Hide the passive notification, if any is shown + */ + function hidePassiveNotification() { + if(internal.__passiveNotification) { + internal.__passiveNotification.hideNotification(); + } + } + + + /** + * @returns a pointer to this application window + * can be used anywhere in the application. + */ + function applicationWindow() { + return root; + } + + /** + * header: ApplicationHeader + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * Layout.minimumHeight: default is 0, i.e. hidden + * * Layout.preferredHeight: default is Units.gridUnit * 1.6 + * * Layout.maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + */ + property Item header + onHeaderChanged: header.parent = contentItemRoot + + /** + * footer: ApplicationHeader + * An item that can be used as a footer for the application. + */ + property Item footer + onFooterChanged: footer.parent = contentItemRoot + + /** + * controlsVisible: bool + * This property controls whether the standard chrome of the app, such + * as the Action button, the drawer handles and the application + * header should be visible or not. + */ + property bool controlsVisible: true + + /** + * globalDrawer: OverlayDrawer + * The drawer for global actions, that will be opened by sliding from the + * left screen edge or by dragging the ActionButton to the right. + * It is recommended to use the GlobalDrawer class here + */ + property OverlayDrawer globalDrawer + + /** + * wideScreen: bool + * If true the application is considered to be in "widescreen" mode, such as on desktops or horizontal tablets. + * Different styles can have an own logic for deciding this + */ + property bool wideScreen: width >= Units.gridUnit * 60 + + /** + * contextDrawer: OverlayDrawer + * The drawer for context-dependent actions, that will be opened by sliding from the + * right screen edge or by dragging the ActionButton to the left. + * It is recommended to use the ContextDrawer class here. + * The contents of the context drawer should depend from what page is + * loaded in the main pageStack + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationItem { + * [...] + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * [...] + * } + * @endcode + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.Page { + * [...] + * contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * @endcode + * + * When this page will be the current one, the context drawer will visualize + * contextualActions defined as property in that page. + */ + property OverlayDrawer contextDrawer + + /** + * reachableMode: bool + * When true the application is in reachable mode for single hand use. + * the whole content of the application is moved down the screen to be + * reachable with the thumb. if wideScreen is true, or reachableModeEnabled is false, + * tis property has no effect. + */ + property bool reachableMode: false + + /** + * When true the application will go into reachable mode on pull down + */ + property bool reachableModeEnabled: true + + MouseArea { + parent: contentItem.parent + z: -1 + anchors.fill: parent + onClicked: root.reachableMode = false; + visible: root.reachableMode && root.reachableModeEnabled + Rectangle { + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.3) + opacity: 0.15 + Icon { + anchors.horizontalCenter: parent.horizontalCenter + y: x + width: Units.iconSizes.large + height: width + source: "go-up" + } + } + } + + /** + * contentItem: Item + * This property holds the Item of the main part of the Application UI + */ + default property alias __data: contentItemRoot.data + readonly property Item contentItem: Item { + id: contentItemRoot + parent: root + anchors.fill: parent + + anchors.left: contentItem.parent.left + anchors.right: contentItem.parent.right + anchors.topMargin: header && controlsVisible ? header.height : 0 + anchors.leftMargin: root.globalDrawer && (root.globalDrawer.modal === false) ? root.globalDrawer.contentItem.width * root.globalDrawer.position : 0 + anchors.rightMargin: root.contextDrawer && root.contextDrawer.modal === false ? root.contextDrawer.contentItem.width * root.contextDrawer.position : 0 + transform: Translate { + Behavior on y { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + y: root.reachableMode && root.reachableModeEnabled && !root.wideScreen ? root.height/2 : 0 + x: root.globalDrawer && root.globalDrawer.modal === true && root.globalDrawer.toString().indexOf("SplitDrawer") === 0 ? root.globalDrawer.contentItem.width * root.globalDrawer.position : 0 + } + + Binding { + when: root.header + target: root.header + property: "y" + value: root.header ? -root.header.height : 0 + } + } + + //Don't want overscroll in landscape mode + onWidthChanged: { + if (width > height) { + root.reachableMode = false; + } + } + + Binding { + when: globalDrawer !== undefined && root.visible + target: globalDrawer + property: "parent" + value: overlay + } + Binding { + when: contextDrawer !== undefined && root.visible + target: contextDrawer + property: "parent" + value: overlay + } + onPageStackChanged: pageStack.parent = contentItem; + + implicitWidth: Units.gridUnit * 30 + implicitHeight: Units.gridUnit * 45 + visible: true + + QtObject { + id: internal + property Item __passiveNotification + } +} diff --git a/src/controls/AbstractApplicationWindow.qml b/src/controls/AbstractApplicationWindow.qml new file mode 100644 index 0000000..322fcb9 --- /dev/null +++ b/src/controls/AbstractApplicationWindow.qml @@ -0,0 +1,326 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as QQC2 +import "templates/private" +import org.kde.kirigami 2.4 +import QtGraphicalEffects 1.0 + +/** + * A window that provides some basic features needed for all apps + * Use this class only if you need a custom content for your application, + * different from the Page Row behavior recommended by the HIG and provided + * by ApplicationWindow. + * It is recommended to use ApplicationWindow instead + * @see ApplicationWindow + * + * It's usually used as a root QML component for the application. + * It provides support for a central page stack, side drawers and + * a top ApplicationHeader, as well as basic support for the + * Android back button + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * + * pageStack: PageStack { + * ... + * } + * [...] + * } + * @endcode + * + * @inherit QtQuick.Controls.ApplicationWindow + */ +QQC2.ApplicationWindow { + id: root + + /** + * pageStack: StackView + * Readonly. + * The stack used to allocate the pages and to manage the transitions + * between them. + * Put a container here, such as QQuickControls PageStack + */ + property Item pageStack + LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + /** + * Shows a little passive notification at the bottom of the app window + * lasting for few seconds, with an optional action button. + * + * @param message The text message to be shown to the user. + * @param timeout How long to show the message: + * possible values: "short", "long" or the number of milliseconds + * @param actionText Text in the action button, if any. + * @param callBack A JavaScript function that will be executed when the + * user clicks the button. + */ + function showPassiveNotification(message, timeout, actionText, callBack) { + if (!internal.__passiveNotification) { + var component = Qt.createComponent("templates/private/PassiveNotification.qml"); + internal.__passiveNotification = component.createObject(overlay.parent); + } + + internal.__passiveNotification.showNotification(message, timeout, actionText, callBack); + } + + /** + * Hide the passive notification, if any is shown + */ + function hidePassiveNotification() { + if(internal.__passiveNotification) { + internal.__passiveNotification.hideNotification(); + } + } + + + /** + * @returns a pointer to this application window + * can be used anywhere in the application. + */ + function applicationWindow() { + return root; + } + + /** + * header: ApplicationHeader + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * Layout.minimumHeight: default is 0, i.e. hidden + * * Layout.preferredHeight: default is Units.gridUnit * 1.6 + * * Layout.maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + * //FIXME: this should become an actual ApplicationHeader + */ + //header: undefined + + /** + * controlsVisible: bool + * This property controls whether the standard chrome of the app, such + * as the Action button, the drawer handles and the application + * header should be visible or not. + */ + property bool controlsVisible: true + + /** + * globalDrawer: OverlayDrawer + * The drawer for global actions, that will be opened by sliding from the + * left screen edge or by dragging the ActionButton to the right. + * It is recommended to use the GlobalDrawer class here + */ + property OverlayDrawer globalDrawer + + /** + * wideScreen: bool + * If true the application is considered to be in "widescreen" mode, such as on desktops or horizontal tablets. + * Different styles can have an own logic for deciding this + */ + property bool wideScreen: width >= Units.gridUnit * 60 + + /** + * contextDrawer: OverlayDrawer + * The drawer for context-dependent actions, that will be opened by sliding from the + * right screen edge or by dragging the ActionButton to the left. + * It is recommended to use the ContextDrawer class here. + * The contents of the context drawer should depend from what page is + * loaded in the main pageStack + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * [...] + * } + * @endcode + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.Page { + * [...] + * contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * @endcode + * + * When this page will be the current one, the context drawer will visualize + * contextualActions defined as property in that page. + */ + property OverlayDrawer contextDrawer + + /** + * reachableMode: bool + * When true the application is in reachable mode for single hand use. + * the whole content of the application is moved down the screen to be + * reachable with the thumb. if wideScreen is true, or reachableModeEnabled is false, + * tis property has no effect. + */ + property bool reachableMode: false + + /** + * When true the application will go into reachable mode on pull down + */ + property bool reachableModeEnabled: true + + color: Theme.backgroundColor + + MouseArea { + parent: contentItem.parent + z: -1 + anchors.fill: parent + onClicked: root.reachableMode = false; + visible: root.reachableMode && root.reachableModeEnabled + Rectangle { + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.3) + opacity: 0.15 + Icon { + anchors.horizontalCenter: parent.horizontalCenter + y: x + width: Units.iconSizes.large + height: width + source: "go-up" + } + } + } + + contentItem.anchors.left: contentItem.parent.left + contentItem.anchors.right: contentItem.parent.right + contentItem.anchors.topMargin: root.wideScreen && header && controlsVisible ? header.height : 0 + contentItem.anchors.leftMargin: root.globalDrawer && (root.globalDrawer.modal === false) ? root.globalDrawer.width * root.globalDrawer.position : 0 + contentItem.anchors.rightMargin: root.contextDrawer && root.contextDrawer.modal === false ? root.contextDrawer.width * root.contextDrawer.position : 0 + + Binding { + when: menuBar !== undefined + target: menuBar + property: "x" + value: -contentItem.x + } + Binding { + when: header !== undefined + target: header + property: "x" + value: -contentItem.x + } + Binding { + when: footer !== undefined + target: footer + property: "x" + value: -contentItem.x + } + + contentItem.transform: Translate { + Behavior on y { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + y: root.reachableMode && root.reachableModeEnabled && !root.wideScreen ? root.height/2 : 0 + x: root.globalDrawer && root.globalDrawer.modal === true && root.globalDrawer.toString().indexOf("SplitDrawer") === 0 ? root.globalDrawer.contentItem.width * root.globalDrawer.position : 0 + } + //Don't want overscroll in landscape mode + onWidthChanged: { + if (width > height) { + root.reachableMode = false; + } + } + Binding { + when: globalDrawer !== undefined && root.visible + target: globalDrawer + property: "parent" + value: overlay + } + Binding { + when: contextDrawer !== undefined && root.visible + target: contextDrawer + property: "parent" + value: overlay + } + onPageStackChanged: pageStack.parent = contentItem; + + width: Units.gridUnit * 30 + height: Units.gridUnit * 45 + visible: true + + + QtObject { + id: internal + property Item __passiveNotification + } + + Shortcut { + sequence: StandardKey.Quit + onActivated: root.close() + } +} diff --git a/src/controls/AbstractCard.qml b/src/controls/AbstractCard.qml new file mode 100644 index 0000000..5ffbeb4 --- /dev/null +++ b/src/controls/AbstractCard.qml @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 as Kirigami +import "templates" as T + +/** + * A AbstractCard is the base for cards. A Card is a visual object that serves + * as an entry point for more detailed information. An abstractCard is empty, + * providing just the look and the base properties and signals for an ItemDelegate. + * It can be filled with any custom layout of items, its content is organized + * in 3 properties: header, contentItem and footer. + * Use this only when you need particular custom contents, for a standard layout + * for cards, use the Card component. + * + * @see Card + * @inherits T.AbstractCard + * @since 2.4 + */ +T.AbstractCard { + id: root + + background: Rectangle { + color: Kirigami.Theme.backgroundColor + Rectangle { + anchors.fill: parent + color: Kirigami.Theme.highlightColor + opacity: { + if (root.showClickFeedback || highlighted) { + return (root.highlighted || root.down) ? 0.3 : (root.hovered ? 0.1 : 0); + } else { + return 0; + } + } + Behavior on opacity { + OpacityAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 1 + radius: 12 + samples: 32 + color: Qt.rgba(0, 0, 0, 0.5) + } + } +} diff --git a/src/controls/AbstractItemViewHeader.qml b/src/controls/AbstractItemViewHeader.qml new file mode 100644 index 0000000..0ba4f52 --- /dev/null +++ b/src/controls/AbstractItemViewHeader.qml @@ -0,0 +1,49 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Templates 2.0 as T2 +import org.kde.kirigami 2.4 as Kirigami + +/** + * An item that can be used as an header for a ListView. + * It will play nice with the margin policies of ScrollablePage and can + * automatically shrink when the list is scrolled, like the behavior + * of list headers in many mobile applications. + * @since 2.1 + * @inherit QtQuick.Controls.Control + */ +T2.Control { + property int minimumHeight: Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing * 2 + property int maximumHeight: Kirigami.Units.gridUnit * 6 + + property ListView view: ListView.view + + width: view.width + + implicitHeight: topPadding + bottomPadding + (view.headerPositioning === ListView.InlineHeader + ? maximumHeight + : Math.min(maximumHeight, Math.max(minimumHeight, maximumHeight - Math.max(0, view.contentY)))) + + + z: 9 + topPadding: applicationWindow() && !applicationWindow().wideScreen && applicationWindow().header ? applicationWindow().header.paintedHeight : 0 + rightPadding: Kirigami.Units.gridUnit + +} diff --git a/src/controls/AbstractListItem.qml b/src/controls/AbstractListItem.qml new file mode 100644 index 0000000..8f907d1 --- /dev/null +++ b/src/controls/AbstractListItem.qml @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.1 +import "private" +import "templates" as T + +/** + * An item delegate for the primitive ListView component. + * + * It's intended to make all listviews look coherent. + * + * @inherit QtQuick.Item + */ +T.AbstractListItem { + id: listItem + + background: DefaultListItemBackground {} +} diff --git a/src/controls/Action.qml b/src/controls/Action.qml new file mode 100644 index 0000000..7e18ca2 --- /dev/null +++ b/src/controls/Action.qml @@ -0,0 +1,170 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import "private" + +/** + * An item that represents an abstract Action + * + * @inherit QtObject + */ +QtObject { + id: root + + /** + * Emitted whenever a action's checked property changes. + * This usually happens at the same time as triggered. + * @param checked + */ + signal toggled(bool checked) + + /** + * Emitted when either the menu item or its bound action have been activated. Includes the object that triggered the event if relevant (e.g. a Button). + * You shouldn't need to emit this signal, use trigger() instead. + * @param source Object that triggered the event if relevant, often null + */ + signal triggered(QtObject source) + + /** + * visible: bool + * True (default) when the graphic representation of the action + * is supposed to be visible. + * It's up to the action representation to honor this property. + */ + property bool visible: true + + /** + * checkable: bool + * Whether action can be checked, or toggled. Defaults to false. + */ + property bool checkable: false + + /** + * checked: bool + * Whether the action is checked. Defaults to false. + */ + property bool checked: false + + /** + * enabled: bool + * Whether the action is enabled, and can be triggered. Defaults to true. + */ + property bool enabled: true + + /** + * iconName: string + * Sets the icon name for the action. This will pick the icon with the given name from the current theme. + */ + property alias iconName: iconGroup.name + + /** + * iconSource: string + * Sets the icon file or resource url for the action. Defaults to the empty URL. Use this if you want a specific file rather than an icon from the theme + */ + property alias iconSource: iconGroup.source + + /** + * metadata for the icon, such as width/height.name and source + * * name This property holds the name of the icon to use. + * The icon will be loaded from the platform theme. + * If the icon is found in the theme, it will always be used; + * even if icon.source is also set. If the icon is not found, + * icon.source will be used instead. + * For more information on theme icons, see QIcon::fromTheme(). + * + * * source This property holds the name of the icon to use. + * The icon will be loaded as a regular image. + * If icon.name is set and refers to a valid theme icon, + * it will always be used instead of this property. + * + * * width This property holds the width of the icon. + * The icon's width will never exceed this value, + * though it will shrink when necessary. + * height This property holds the height of the icon. + * The icon's height will never exceed this value, + * though it will shrink when necessary. + * + * *color This property holds the color of the icon. + * The icon is tinted with the specified color, unless the color is set to "transparent". + */ + property ActionIconGroup icon: ActionIconGroup { + id: iconGroup + } + + /** + * shortcut : keysequence + * Shortcut bound to the action. The keysequence can be a string or a Qt standard key. + */ + property alias shortcut: shortcutItem.sequence + + /** + * Text for the action. This text will show as the button text, or as title in a menu item, depending from the way the developer will choose to represent it + */ + property string text + + /** + * A tooltip text to be shown when hovering the control bound to this action. Not all controls support tooltips on all platforms + */ + property string tooltip + + /** + * children: list + * A list of children actions. + * Useful for tree-like menus + * @code + * Action { + * text: "Tools" + * Action { + * text: "Action1" + * } + * Action { + * text: "Action2" + * } + * } + * @endcode + */ + + /** + * separator: bool + * Whether the action is is a separator action; defaults to false. + */ + property bool separator: false + + default property alias children: root.__children + property list __children + property Shortcut __shortcut: Shortcut { + property bool checked: false + id: shortcutItem + enabled: root.enabled + onActivated: root.trigger(); + } + function trigger(source) { + if (!enabled) { + return; + } + root.triggered(source); + if (root.checkable) { + root.checked = !root.checked; + root.toggled(root.checked); + } + } + + onCheckedChanged: root.toggled(root.checked); +} diff --git a/src/controls/ActionToolBar.qml b/src/controls/ActionToolBar.qml new file mode 100644 index 0000000..c21fdca --- /dev/null +++ b/src/controls/ActionToolBar.qml @@ -0,0 +1,194 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.5 as Kirigami +import "private" + +/** + * This is a simple toolbar built out of a list of actions + * each action is represented by a ToolButton, those that won't fit + * the size will go in a menu under a button with the overflow ... icon + * + * @inherits Item + * @since 2.5 + */ +Item { + id: root + /** + * actions: list + * if the card should provide clickable actions, put them in this property, + * they will be put in the footer as a list of ToolButtons plus an optional + * overflow menu, when not all of them will fit in the available Card width. + */ + property list actions + + /** + * actions: hiddenActions + * This list of actions is for those you always want in the menu, even if there + * is enough space. + * @since 2.6 + */ + property list hiddenActions + + /** + * flat: bool + * Wether we want our buttons to have a flat appearance. Default: true + */ + property bool flat: true + + implicitHeight: actionsLayout.implicitHeight + + implicitWidth: { + var width = 0; + for (var i = 0; i < actionsLayout.children.length; ++i) { + if (actionsLayout.children[i].kirigamiAction && actionsLayout.children[i].kirigamiAction.visible) { + width += actionsLayout.children[i].implicitWidth + actionsLayout.spacing; + } + } + width += moreButton.width; + return width; + } + + Layout.maximumWidth: implicitWidth + Layout.fillWidth: true + + RowLayout { + id: actionsLayout + anchors.fill: parent + //anchors.rightMargin: moreButton.width + + spacing: Kirigami.Units.smallSpacing + property var overflowSet: [] + + // TODO use Array.findIndex once we depend on Qt 5.9 + function findIndex(array, cb) { + for (var i = 0, length = array.length; i < length; ++i) { + if (cb(array[i])) { + return i; + } + } + return -1; + } + + Repeater { + model: root.actions + delegate: PrivateActionToolButton { + id: actionDelegate + flat: root.flat + readonly property bool fits: { + var minX = 0; + for (var i = 0; i < index; ++i) { + if (actionsLayout.children[i].visible) { + minX += actionsLayout.children[i].implicitWidth + actionsLayout.spacing; + } + } + return minX + implicitWidth < actionsLayout.width - moreButton.width + } + + visible: modelData.visible && fits + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.minimumWidth: implicitWidth + kirigamiAction: modelData + onFitsChanged: updateOverflowSet() + function updateOverflowSet() { + var index = actionsLayout.findIndex(actionsLayout.overflowSet, function(act) { + return act === modelData}); + + if ((fits || !modelData.visible) && index > -1) { + actionsLayout.overflowSet.splice(index, 1); + } else if (!fits && modelData.visible && index === -1) { + actionsLayout.overflowSet.push(modelData); + } + actionsLayout.overflowSetChanged(); + } + Connections { + target: modelData + onVisibleChanged: actionDelegate.updateOverflowSet(); + } + Component.onCompleted: { + actionDelegate.updateOverflowSet(); + } + } + } + Controls.ToolButton { + id: moreButton + + Layout.alignment: Qt.AlignRight + Kirigami.Icon { + anchors.fill: parent + source: "overflow-menu" + anchors.margins: 4 + } + + //checkable: true + checked: menu.visible + visible: hiddenActions.length > 0 || actionsLayout.overflowSet.length > 0; + onClicked: menu.visible ? menu.close() : menu.open() + + ActionsMenu { + id: menu + y: -height + x: -width + moreButton.width + actions: root.actions + submenuComponent: Component { + ActionsMenu {} + } + itemDelegate: ActionMenuItem { + visible: actionsLayout.findIndex(actionsLayout.overflowSet, function(act) {return act === ourAction}) > -1 && (ourAction.visible === undefined || ourAction.visible) + } + Instantiator { + + model: root.hiddenActions + delegate: QtObject { + readonly property QtObject action: modelData + property QtObject item: null + + Component.onDestruction: if (item) item.destroy() + + function create() { + if (!action.children || action.children.length === 0) { + item = menu.itemDelegate.createObject(null, { ourAction: action }); + menu.addItem(item) + } else if (menu.submenuComponent) { + item = menu.submenuComponent.createObject(null, { title: action.text, actions: action.children }); + menu.addMenu(item) + } + //break the binding + item.visible = true; + } + function remove() { + if (!action.children || action.children.length === 0) { + menu.removeItem(item) + } else if (menu.submenuComponent) { + menu.removeMenu(item) + } + } + } + + onObjectAdded: object.create() + onObjectRemoved: object.remove() + } + } + } + } +} diff --git a/src/controls/ApplicationHeader.qml b/src/controls/ApplicationHeader.qml new file mode 100644 index 0000000..914ef75 --- /dev/null +++ b/src/controls/ApplicationHeader.qml @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import "templates" as T + + +/** + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * minimumHeight: default is 0, i.e. hidden + * * preferredHeight: default is Units.gridUnit * 1.6 + * * maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + */ +T.ApplicationHeader { + id: header +} diff --git a/src/controls/ApplicationItem.qml b/src/controls/ApplicationItem.qml new file mode 100644 index 0000000..326201f --- /dev/null +++ b/src/controls/ApplicationItem.qml @@ -0,0 +1,174 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import "templates/private" +import org.kde.kirigami 2.4 as Kirigami +import QtGraphicalEffects 1.0 + +/** + * A window that provides some basic features needed for all apps + * This version is an Item as opposed to a window, it's intended + * for use into a QQuickView + * + * It's usually used as a root QML component for the application. + * It's based around the PageRow component, the application will be + * about pages adding and removal. + * For most of the usages, this class should be used instead + * of AbstractApplicationWidnow + * @see AbstractApplicationWidnow + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationItem { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * + * pageStack.initialPage: Kirigami.Page { + * mainAction: Kirigami.Action { + * iconName: "edit" + * onTriggered: { + * // do stuff + * } + * } + * contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * [...] + * } + * @endcode + * +*/ +AbstractApplicationItem { + id: root + + /** + * pageStack: StackView + * Readonly. + * The stack used to allocate the pages and to manage the transitions + * between them. + * It's using a PageRow, while having the same API as PageStack, + * it positions the pages as adjacent columns, with as many columns + * as can fit in the screen. An handheld device would usually have a single + * fullscreen column, a tablet device would have many tiled columns. + */ + property alias pageStack: __pageStack + + //redefines here as here we can know a pointer to PageRow + wideScreen: width >= applicationWindow().pageStack.defaultColumnWidth*2 + + PageRow { + id: __pageStack + anchors { + fill: parent + //HACK: workaround a bug in android iOS keyboard management + bottomMargin: ((Qt.platform.os == "android" || Qt.platform.os == "ios") || !Qt.inputMethod.visible) ? 0 : Qt.inputMethod.keyboardRectangle.height + onBottomMarginChanged: { + if (bottomMargin > 0) { + root.reachableMode = false; + } + } + } + //FIXME + onCurrentIndexChanged: root.reachableMode = false; + + function goBack() { + //NOTE: drawers are handling the back button by themselves + var backEvent = {accepted: false} + if (root.pageStack.currentIndex >= 1) { + root.pageStack.currentItem.backRequested(backEvent); + if (!backEvent.accepted) { + root.pageStack.flickBack(); + backEvent.accepted = true; + } + } + + if (Kirigami.Settings.isMobile && !backEvent.accepted && Qt.platform.os !== "ios") { + Qt.quit(); + } + } + function goForward() { + root.pageStack.currentIndex = Math.min(root.pageStack.depth-1, root.pageStack.currentIndex + 1); + } + Keys.onBackPressed: { + goBack(); + event.accepted = true + } + Shortcut { + sequence: "Forward" + onActivated: __pageStack.goForward(); + } + Shortcut { + sequence: StandardKey.Forward + onActivated: __pageStack.goForward(); + } + Shortcut { + sequence: StandardKey.Back + onActivated: __pageStack.goBack(); + } + + Rectangle { + z: -1 + anchors.fill: parent + color: Kirigami.Theme.backgroundColor + } + focus: true + } +} diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml new file mode 100644 index 0000000..3695772 --- /dev/null +++ b/src/controls/ApplicationWindow.qml @@ -0,0 +1,176 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import "templates/private" +import org.kde.kirigami 2.4 as Kirigami +import QtGraphicalEffects 1.0 + +/** + * A window that provides some basic features needed for all apps + * + * It's usually used as a root QML component for the application. + * It's based around the PageRow component, the application will be + * about pages adding and removal. + * For most of the usages, this class should be used instead + * of AbstractApplicationWidnow + * @see AbstractApplicationWidnow + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * + * pageStack.initialPage: Kirigami.Page { + * mainAction: Kirigami.Action { + * iconName: "edit" + * onTriggered: { + * // do stuff + * } + * } + * contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * [...] + * } + * @endcode + * +*/ +AbstractApplicationWindow { + id: root + + /** + * pageStack: StackView + * Readonly. + * The stack used to allocate the pages and to manage the transitions + * between them. + * It's using a PageRow, while having the same API as PageStack, + * it positions the pages as adjacent columns, with as many columns + * as can fit in the screen. An handheld device would usually have a single + * fullscreen column, a tablet device would have many tiled columns. + */ + property alias pageStack: __pageStack + + //redefines here as here we can know a pointer to PageRow + wideScreen: width >= applicationWindow().pageStack.defaultColumnWidth * 1.5 + + PageRow { + id: __pageStack + globalToolBar.style: Kirigami.ApplicationHeaderStyle.Auto + anchors { + fill: parent + //HACK: workaround a bug in android iOS keyboard management + bottomMargin: ((Qt.platform.os == "android" || Qt.platform.os == "ios") || !Qt.inputMethod.visible) ? 0 : Qt.inputMethod.keyboardRectangle.height + onBottomMarginChanged: { + if (bottomMargin > 0) { + root.reachableMode = false; + } + } + } + //FIXME + onCurrentIndexChanged: root.reachableMode = false; + + function goBack() { + //NOTE: drawers are handling the back button by themselves + var backEvent = {accepted: false} + if (root.pageStack.layers.depth > 1) { + root.pageStack.layers.currentItem.backRequested(backEvent); + if (!backEvent.accepted) { + root.pageStack.layers.pop(); + backEvent.accepted = true; + } + } else { + root.pageStack.currentItem.backRequested(backEvent); + if (root.pageStack.currentIndex >= 1) { + if (!backEvent.accepted) { + root.pageStack.flickBack(); + backEvent.accepted = true; + } + } + } + + if (Kirigami.Settings.isMobile && !backEvent.accepted && Qt.platform.os !== "ios") { + Qt.quit(); + } + } + function goForward() { + root.pageStack.currentIndex = Math.min(root.pageStack.depth-1, root.pageStack.currentIndex + 1); + } + Keys.onBackPressed: { + goBack(); + event.accepted = true + } + Shortcut { + sequence: "Forward" + onActivated: __pageStack.goForward(); + } + Shortcut { + sequence: StandardKey.Forward + onActivated: __pageStack.goForward(); + } + Shortcut { + sequence: StandardKey.Back + onActivated: __pageStack.goBack(); + } + + focus: true + } +} diff --git a/src/controls/BasicListItem.qml b/src/controls/BasicListItem.qml new file mode 100644 index 0000000..19e003b --- /dev/null +++ b/src/controls/BasicListItem.qml @@ -0,0 +1,97 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 + +/** + * An item delegate for the primitive ListView component. + * + * It's intended to make all listviews look coherent. + * It has a default icon and a label + * + */ +AbstractListItem { + id: listItem + + /** + * string: bool + * A single text label the list item will contain + */ + property alias label: listItem.text + + /** + * icon: var + * A single icon that will be displayed in the list item. + * The icon can be a grouped property with name,size,color etc, as QtQuickControls2 icons are defined. + * The icon can also be either a QIcon, a string name of a fdo compatible name, + * or any url accepted by the Image element. + */ + property var icon + + /** + * reserveSpaceForIcon: bool + * If true, even when there is no icon the space will be reserved for it + * It's useful in layouts where only some entries have an icon, + * having the text all horizontally aligned + */ + property alias reserveSpaceForIcon: iconItem.visible + + /** + * reserveSpaceForLabel: bool + * If false, the label will not try to be as wide as possible + * It's useful in layouts containing entries without text + */ + property alias reserveSpaceForLabel: labelItem.visible + + default property alias _basicDefault: layout.children + + contentItem: RowLayout { + id: layout + spacing: Units.smallSpacing*2 + property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (listItem.ListView.view ? listItem.ListView.view.activeFocus : false) + Icon { + id: iconItem + source: { + if (listItem.icon && listItem.icon.hasOwnProperty) { + if (listItem.icon.hasOwnProperty("name") && listItem.icon.name !== "") + return listItem.icon.name; + if (listItem.icon.hasOwnProperty("source")) + return listItem.icon.source; + } + return listItem.icon; + } + Layout.minimumHeight: Units.iconSizes.smallMedium + Layout.maximumHeight: Layout.minimumHeight + Layout.minimumWidth: height + selected: layout.indicateActiveFocus && (listItem.highlighted || listItem.checked || listItem.pressed) + color: listItem.icon && listItem.icon.color && listItem.icon.color.a > 0 ? listItem.icon.color : (selected ? Theme.highlightedTextColor : Theme.textColor) + } + QQC2.Label { + id: labelItem + text: listItem.text + Layout.fillWidth: true + color: layout.indicateActiveFocus && (listItem.highlighted || listItem.checked || listItem.pressed) ? listItem.activeTextColor : listItem.textColor + elide: Text.ElideRight + font: listItem.font + } + } +} diff --git a/src/controls/Card.qml b/src/controls/Card.qml new file mode 100644 index 0000000..67d8dc6 --- /dev/null +++ b/src/controls/Card.qml @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.5 as Kirigami +import "private" + +/** + * This is the standard layout of a Card. + * It is recommended to use this class when the concept of Cards is needed + * in the application. + * This Card has default items as header and footer. The header is an + * image that can contain an optional title and icon, accessible via the + * banner grouped property. + * The footer will show a series of toolbuttons (and eventual overflow menu) + * representing the actions list accessible with the list property actions. + * It is possible even tough is discouraged to override the footer: + * in this case the actions property shouldn't be used. + * + * @inherits AbstractCard + * @since 2.4 + */ +Kirigami.AbstractCard { + id: root + + /** + * actions: list + * if the card should provide clickable actions, put them in this property, + * they will be put in the footer as a list of ToolButtons plus an optional + * overflow menu, when not all of them will fit in the available Card width. + */ + property list actions + + /** + * actions: hiddenActions + * This list of actions is for those you always want in the menu, even if there + * is enough space. + * @since 2.6 + */ + property list hiddenActions + + /** + * banner: Image + * Gropuped property to control the banner image present in the header, it + * has the following sub properties: + * * url source: the source for the image, it understands any url + * valid for an Image component + * * string title: the title for the banner, shown as contrasting + * text over the image + * * Qt.Alignment titleAlignment: the alignment of the title inside the image, + * a combination of flags is supported + * (default: Qt.AlignTop | Qt.AlignLeft) + * * string titleIcon: the optional icon to put in the banner: + * it can be either a freedesktop-compatible icon name (recommended) + * or any url supported by Image + * * titleLevel: The Kirigami Heading level for the title, it controls the font size, default 1 + * * wrapMode: if the header should be able to do wrapping + * + * It also has the full set of properties a QML Image has, such as sourceSize and fillMode + */ + readonly property alias banner: bannerImage + + header: BannerImage { + id: bannerImage + anchors.leftMargin: -root.leftPadding + anchors.topMargin: -root.topPadding + anchors.rightMargin: root.headerOrientation == Qt.Vertical ? -root.rightPadding : 0 + anchors.bottomMargin: root.headerOrientation == Qt.Horizontal ? -root.bottomPadding : 0 + height: Layout.preferredHeight + implicitWidth: root.headerOrientation == Qt.Horizontal ? sourceSize.width : Layout.preferredWidth + } + + onHeaderChanged: { + if (!header) { + return; + } + + header.anchors.leftMargin = Qt.binding(function() {return -root.leftPadding}); + header.anchors.topMargin = Qt.binding(function() {return -root.topPadding}); + header.anchors.rightMargin = Qt.binding(function() {return root.headerOrientation == Qt.Vertical ? -root.rightPadding : 0}); + header.anchors.bottomMargin = Qt.binding(function() {return root.headerOrientation == Qt.Horizontal ? -root.bottomPadding : 0}); + } + + footer: Kirigami.ActionToolBar { + id: actionsToolBar + actions: root.actions + hiddenActions: root.hiddenActions + visible: root.footer == actionsToolBar + } +} diff --git a/src/controls/CardsGridView.qml b/src/controls/CardsGridView.qml new file mode 100644 index 0000000..696831b --- /dev/null +++ b/src/controls/CardsGridView.qml @@ -0,0 +1,88 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami +import "private" + +/** + * CardsGridView is used to display a grid of Cards generated from any model. + * The behavior is same as CardsLayout, and it allows cards to be put in one or two + * columns depending from the available width. + * GridView has the limitation that every Card must have the same exact height, + * so cellHeight must be manually set to a value in which the content fits + * for every item. + * If possible use cards only when you don't need to instantiate a lot + * and use CardsLayout intead. + * @inherits GridView + * @see CardsLayout + * @since 2.4 + */ +CardsGridViewPrivate { + id: root + + /** + * columns: int + * how many columns the gridview has + * @since 2.5 + */ + readonly property int columns: Math.max(1, + Math.min(maximumColumns > 0 ? maximumColumns : Infinity, + Math.floor(width/minimumColumnWidth), + Math.ceil(width/maximumColumnWidth)) + ); + + /** + * maximumColumns: int + * Maximum value for columns if the user wants to limit it + * @since 2.5 + */ + property int maximumColumns: Infinity + + /** + * maximumColumnWidth: int + * The maximum width the columns may have. the cards will never + * get wider than this size, when the GridView is wider than + * maximumColumnWidth, it will switch from one to two columns. + * If the default needs to be overridden for some reason, + * it is advised to express this unit as a multiple + * of Kirigami.Units.gridUnit + */ + property int maximumColumnWidth: Kirigami.Units.gridUnit * 20 + + /** + * minimumColumnWidth: int + * The minimum width the columns may have. the cards will never + * get smaller than this size. + * If the default needs to be overridden for some reason, + * it is advised to express this unit as a multiple + * of Kirigami.Units.gridUnit + * @since 2.5 + */ + property int minimumColumnWidth: Kirigami.Units.gridUnit * 12 + + cellWidth: Math.floor(width/columns) + cellHeight: Math.max(Kirigami.Units.gridUnit * 15, Math.min(cellWidth, maximumColumnWidth) / 1.2) + + default property alias delegate: root._delegateComponent + + topMargin: Kirigami.Units.largeSpacing * 2 +} diff --git a/src/controls/CardsLayout.qml b/src/controls/CardsLayout.qml new file mode 100644 index 0000000..8033714 --- /dev/null +++ b/src/controls/CardsLayout.qml @@ -0,0 +1,91 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + +/** + * A GridLayout optimized for showing one or two columns of cards, + * depending on the available space. + * It Should be used when the cards are not instantiated by a model or by a + * model which has always very few items (In the case of a big model + * CardsListView or CardsGridview should be used instead). + * They are presented as a grid of two columns which will remain + * centered if the application is really wide, or become a single + * column if there is not enough space for two columns, + * such as a mobile phone screen. + * A CardsLayout should always be contained within a ColumnLayout. + * @inherits GridLayout + * @since 2.4 + */ +GridLayout { + /** + * maximumColumns: int + * The layout will never lay out the items in more columns than maximumColumns + * Default: 2 + * @since 2.5 + */ + property int maximumColumns: 2 + + /** + * maximumColumnWidth: int + * The maximum width the columns may have. the cards will never + * get wider than this size, when the GridLayout is wider than + * maximumColumnWidth, it will switch from one to two columns. + * If the default needs to be overridden for some reason, + * it is advised to express this unit as a multiple + * of Kirigami.Units.gridUnit + */ + property int maximumColumnWidth: Kirigami.Units.gridUnit * 20 + + /** + * minimumColumnWidth: int + * The minimumWidth the columns may have. The layout will try to dispose items + * in a number of columns that will respect this size constraint. + * @since 2.5 + */ + property int minimumColumnWidth: Kirigami.Units.gridUnit * 12 + + columns: Math.max(1, Math.min(maximumColumns > 0 ? maximumColumns : Infinity, + Math.floor(width/minimumColumnWidth), + Math.ceil(width/maximumColumnWidth))); + + rowSpacing: Kirigami.Units.largeSpacing * columns + columnSpacing: Kirigami.Units.largeSpacing * columns + + + //NOTE: this default width which defaults to 2 columns is just to remove a binding loop on columns + width: maximumColumnWidth*2 + Kirigami.Units.largeSpacing + //same computation of columns, but on the parent size + Layout.preferredWidth: maximumColumnWidth * Math.max(1, Math.min(maximumColumns > 0 ? maximumColumns : Infinity, + Math.floor(parent.width/minimumColumnWidth), + Math.ceil(parent.width/maximumColumnWidth))) + Kirigami.Units.largeSpacing * (columns - 1) + + Layout.maximumWidth: Layout.preferredWidth + Layout.alignment: Qt.AlignHCenter + + Component.onCompleted: childrenChanged() + onChildrenChanged: { + for (var i = 0; i < children.length; ++i) { + children[i].Layout.fillHeight = true; + } + } +} diff --git a/src/controls/CardsListView.qml b/src/controls/CardsListView.qml new file mode 100644 index 0000000..b189d5a --- /dev/null +++ b/src/controls/CardsListView.qml @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami +import "private" +/** + * CardsListView is a ListView which can have AbstractCard as its delegate: it will + * automatically assign the proper spacings and margins around the cards adhering + * to the design guidelines. + * CardsListView should be used only with cards which can look good at any + * horizontal size, so It is recommended to use directly AbstractCard with an + * appropriate layout inside, because they are stretching for the whole list width. + * Therefore is discouraged to use it with the Card type, unless it has + * Horizontal as headerOrientation. + * The choice between using this view with AbstractCard or a normal ListView + * with AbstractListItem/BasicListItem is purely a choice based on aesthetics alone. + * It is discouraged to tweak the properties of this ListView. + * @inherits ListView + * @since 2.4 + */ +CardsListViewPrivate { + id: root + spacing: Kirigami.Units.largeSpacing * 2 + topMargin: headerPositioning != ListView.InlineHeader ? spacing : 0 + + property alias delegate: root._delegateComponent + headerPositioning: ListView.OverlayHeader +} diff --git a/src/controls/ContextDrawer.qml b/src/controls/ContextDrawer.qml new file mode 100644 index 0000000..13510ff --- /dev/null +++ b/src/controls/ContextDrawer.qml @@ -0,0 +1,174 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 + +import "templates/private" + +/** + * A drawer specialization that will show a list of actions that are + * specific of the current page shown by the application + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * [...] + * } + * @endcode + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.Page { + * [...] + * contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * @endcode + * + * @inherit AbstractDrawer + */ +OverlayDrawer { + id: root + + /** + * title: string + * A title for the action list that will be shown to the user when opens the drawer + */ + property string title: qsTr("Actions") + + /** + * actions: list + * This can be any type of object that a ListView can accept as model. + * It expects items compatible with either QAction or Kirigami Action + */ + property var actions: pageStack.layers.depth > 1 + ? pageStack.layers.currentItem.contextualActions + : (pageStack.currentItem ? pageStack.currentItem.contextualActions : null) + // Disable for empty menus or when we have a global toolbar + enabled: menu.count > 0 && + (typeof applicationWindow() === "undefined" || !applicationWindow().pageStack.globalToolBar || applicationWindow().pageStack.globalToolBar.actualStyle !== ApplicationHeaderStyle.ToolBar) + edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge + drawerOpen: false + + //list items go to edges, have their own padding + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + handleVisible: applicationWindow == undefined ? false : applicationWindow().controlsVisible + + contentItem: ScrollView { + //this just to create the attached property + Theme.inherit: true + implicitWidth: Units.gridUnit * 20 + ListView { + id: menu + interactive: contentHeight > height + model: { + if (typeof root.actions == "undefined") { + return null; + } + if (root.actions.length === 0) { + return null; + } else { + return root.actions[0].text !== undefined && + root.actions[0].trigger !== undefined ? + root.actions : + root.actions[0]; + } + } + topMargin: root.handle.y > 0 ? menu.height - menu.contentHeight : 0 + header: Item { + height: heading.height + width: menu.width + Heading { + id: heading + anchors { + left: parent.left + right: parent.right + margins: Units.largeSpacing + } + elide: Text.ElideRight + level: 2 + text: root.title + } + } + delegate: BasicListItem { + id: listItem + + readonly property bool isSeparator: modelData.hasOwnProperty("separator") && modelData.separator + + checked: modelData.checked + icon: modelData.icon + supportsMouseEvents: true + separatorVisible: false + reserveSpaceForIcon: !isSeparator + reserveSpaceForLabel: !isSeparator + + label: model ? (model.tooltip ? model.tooltip : model.text) : (modelData.tooltip ? modelData.tooltip : modelData.text) + enabled: !isSeparator && (model ? model.enabled : modelData.enabled) + visible: model ? model.visible : modelData.visible + opacity: enabled ? 1.0 : 0.6 + + Separator { + id: separatorAction + + visible: listItem.isSeparator + Layout.fillWidth: true + } + + onClicked: { + root.drawerOpen = false; + if (modelData && modelData.trigger !== undefined) { + modelData.trigger(); + // assume the model is a list of QAction or Action + } else if (menu.model.length > index) { + menu.model[index].trigger(); + } else { + console.warning("Don't know how to trigger the action") + } + } + } + } + } +} diff --git a/src/controls/FormLayout.qml b/src/controls/FormLayout.qml new file mode 100644 index 0000000..b8775fc --- /dev/null +++ b/src/controls/FormLayout.qml @@ -0,0 +1,347 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.2 +import org.kde.kirigami 2.4 as Kirigami + +/** + * This is the base class for Form layouts conforming to the + * Kirigami Human interface guidelines. The layout will + * be divided in two columns: on the right there will be a column + * of fields, on the left their labels specified in the FormData attached + * property. + * + * Example: + * @code + * import org.kde.kirigami 2.3 as Kirigami + * Kirigami.FormLayout { + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * Kirigami.Separator { + * Kirigami.FormData.label: "Section Title" + * Kirigami.FormData.isSection: true + * } + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * TextField { + * } + * } + * @endcode + * @inherits QtQuick.Item + * @since 2.3 + */ +Item { + id: root + + /** + * wideMode: bool + * If true the layout will be optimized for a wide screen, such as + * a desktop machine (the labels will be on a left column, + * the fields on a right column beside it), if false (such as on a phone) + * everything is laid out in a single column. + * by default this will be based on whether the application is + * wide enough for the layout of being in such mode. + * It can be overridden by reassigning the property + */ + property bool wideMode: width >= lay.wideImplicitWidth + + implicitWidth: lay.implicitWidth + implicitHeight: lay.implicitHeight + Layout.preferredHeight: lay.implicitHeight + + /** + * twinFormLayouts: list + * If for some implementation reason multiple FormLayouts has to appear + * on the same page, they can have each other in twinFormLayouts, + * so they will vertically align each other perfectly + * @since 5.53 + */ + //should be list but we can't have a recursive declaration + property list twinFormLayouts + + Layout.fillWidth: true + + GridLayout { + id: lay + property int wideImplicitWidth + columns: root.wideMode ? 2 : 1 + rowSpacing: Kirigami.Units.smallSpacing + columnSpacing: Kirigami.Units.smallSpacing + property var knownItems: [] + property var buddies: [] + property int knownItemsImplicitWidth: { + var hint = 0; + for (var i in knownItems) { + hint = Math.max(hint, knownItems[i].Layout.preferredWidth > 0 ? knownItems[i].Layout.preferredWidth : knownItems[i].implicitWidth); + } + return hint; + } + property int buddiesImplicitWidth: { + var hint = 0; + for (var i in buddies) { + if (buddies[i].visible) { + hint = Math.max(hint, buddies[i].implicitWidth); + } + } + return hint; + } + anchors { + left: root.wideMode ? undefined : parent.left + top: parent.top + //to make room for the invisible spacer elements + topMargin: -lay.columnSpacing + // right: parent.right + horizontalCenter: root.wideMode ? parent.horizontalCenter : undefined + } + width: Math.min(implicitWidth, parent.width) + Timer { + id: hintCompression + onTriggered: { + if (root.wideMode) { + lay.wideImplicitWidth = lay.implicitWidth; + } + } + } + onImplicitWidthChanged: hintCompression.restart(); + //This invisible row is used to sync alignment between multiple layouts + Item { + Layout.preferredWidth: { + var hint = 1; + for (var i in root.twinFormLayouts) { + hint = Math.max(hint, root.twinFormLayouts[i].children[0].buddiesImplicitWidth); + } + return hint; + } + } + Item { + Layout.preferredWidth: { + var hint = 1; + for (var i in root.twinFormLayouts) { + hint = Math.max(hint, root.twinFormLayouts[i].children[0].knownItemsImplicitWidth); + } + return hint; + } + } + } + + Item { + id: temp + } + + Timer { + id: relayoutTimer + interval: 0 + onTriggered: { + var __items = children; + //exclude the layout and temp + for (var i = 2; i < __items.length; ++i) { + var item = __items[i]; + + //skip items that are already there + if (lay.knownItems.indexOf(item) != -1 || + //exclude Repeaters + //NOTE: this is an heuristic but there are't better ways + (item.hasOwnProperty("model") && item.model !== undefined && item.children.length === 0)) { + continue; + } + lay.knownItems.push(item); + + var itemContainer = itemComponent.createObject(temp, {"item": item}) + + //if section, label goes after the separator + if (item.Kirigami.FormData.isSection) { + //put an extra spacer + var placeHolder = placeHolderComponent.createObject(lay, {"item": item}); + itemContainer.parent = lay; + } + + var buddy; + if (item.Kirigami.FormData.checkable) { + buddy = checkableBuddyComponent.createObject(lay, {"item": item}) + } else { + buddy = buddyComponent.createObject(lay, {"item": item}) + } + + itemContainer.parent = lay; + lay.buddies.push(buddy); + } + lay.knownItemsChanged(); + lay.buddiesChanged(); + hintCompression.triggered(); + } + } + + onChildrenChanged: relayoutTimer.restart(); + + Component { + id: itemComponent + Item { + id: container + property var item + enabled: item.enabled + visible: item.visible + + //NOTE: work around a GridLayout quirk which doesn't lay out items with null size hints causing things to be laid out incorrectly in some cases + implicitWidth: Math.max(item.implicitWidth, 1) + implicitHeight: Math.max(item.implicitHeight, 1) + Layout.preferredWidth: Math.max(1, item.Layout.preferredWidth > 0 ? item.Layout.preferredWidth : item.implicitWidth) + Layout.preferredHeight: Math.max(1, item.Layout.preferredHeight > 0 ? item.Layout.preferredHeight : item.implicitHeight) + + Layout.minimumWidth: item.Layout.minimumWidth + Layout.minimumHeight: item.Layout.minimumHeight + + Layout.maximumWidth: item.Layout.maximumWidth + Layout.maximumHeight: item.Layout.maximumHeight + + Layout.leftMargin: root.wideMode ? 0 : Kirigami.Units.largeSpacing + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillWidth: item.Layout.fillWidth || item.Kirigami.FormData.isSection + Layout.columnSpan: item.Kirigami.FormData.isSection ? lay.columns : 1 + onItemChanged: { + if (!item) { + container.destroy(); + } + } + onXChanged: item.x = x + lay.x; + //Assume lay.y is always 0 + onYChanged: item.y = y + lay.y; + onWidthChanged: item.width = width; + Connections { + target: lay + onXChanged: item.x = x + lay.x; + } + } + } + Component { + id: placeHolderComponent + Item { + property var item + enabled: item.enabled + visible: item.visible + width: Kirigami.Units.smallSpacing + height: Kirigami.Units.smallSpacing + onItemChanged: { + if (!item) { + labelItem.destroy(); + } + } + } + } + Component { + id: buddyComponent + Kirigami.Heading { + id: labelItem + + property var item + enabled: item.enabled + visible: item.visible + Kirigami.MnemonicData.enabled: item.Kirigami.FormData.buddyFor && item.Kirigami.FormData.buddyFor.activeFocusOnTab + Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.FormLabel + Kirigami.MnemonicData.label: item.Kirigami.FormData.label + text: Kirigami.MnemonicData.richTextLabel + + level: item.Kirigami.FormData.isSection ? 3 : 5 + + Layout.columnSpan: item.Kirigami.FormData.isSection ? lay.columns : 1 + Layout.preferredHeight: item.Kirigami.FormData.label.length > 0 ? Math.max(implicitHeight, item.Kirigami.FormData.buddyFor.height) : Kirigami.Units.smallSpacing + + Layout.alignment: item.Kirigami.FormData.isSection + ? Qt.AlignLeft + : (root.wideMode + ? (Qt.AlignRight | Qt.AlignTop) + : (Qt.AlignLeft | Qt.AlignBottom)) + verticalAlignment: root.wideMode ? Text.AlignVCenter : Text.AlignBottom + + //Layout.topMargin: item.Kirigami.FormData.buddyFor.y + onItemChanged: { + if (!item) { + labelItem.destroy(); + } + } + Shortcut { + sequence: labelItem.Kirigami.MnemonicData.sequence + onActivated: item.Kirigami.FormData.buddyFor.forceActiveFocus() + } + } + } + Component { + id: checkableBuddyComponent + CheckBox { + id: labelItem + property var item + visible: item.visible + Kirigami.MnemonicData.enabled: item.Kirigami.FormData.buddyFor && item.Kirigami.FormData.buddyFor.activeFocusOnTab + Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.FormLabel + Kirigami.MnemonicData.label: item.Kirigami.FormData.label + + Layout.columnSpan: item.Kirigami.FormData.isSection ? lay.columns : 1 + Layout.preferredHeight: item.Kirigami.FormData.label.length > 0 ? implicitHeight : Kirigami.Units.smallSpacing + + Layout.alignment: item.Kirigami.FormData.isSection + ? Qt.AlignLeft + : (root.wideMode + ? (Qt.AlignRight | (item.Kirigami.FormData.buddyFor.height > height * 2 ? Qt.AlignTop : Qt.AlignVCenter)) + : (Qt.AlignLeft | Qt.AlignBottom)) + Layout.topMargin: item.Kirigami.FormData.buddyFor.height > implicitHeight * 2 ? Kirigami.Units.smallSpacing/2 : 0 + + activeFocusOnTab: indicator.visible && indicator.enabled + text: labelItem.Kirigami.MnemonicData.richTextLabel + enabled: labelItem.item.Kirigami.FormData.enabled + checked: labelItem.item.Kirigami.FormData.checked + + onItemChanged: { + if (!item) { + labelItem.destroy(); + } + } + Shortcut { + sequence: labelItem.Kirigami.MnemonicData.sequence + onActivated: { + checked = !checked + item.Kirigami.FormData.buddyFor.forceActiveFocus() + } + } + onCheckedChanged: { + item.Kirigami.FormData.checked = checked + } + contentItem: Kirigami.Heading { + id: labelItemHeading + level: labelItem.item.Kirigami.FormData.isSection ? 3 : 5 + text: labelItem.text + verticalAlignment: root.wideMode ? Text.AlignVCenter : Text.AlignBottom + enabled: labelItem.item.Kirigami.FormData.enabled + leftPadding: parent.indicator.width + } + Rectangle { + enabled: labelItem.indicator.enabled + anchors.left: labelItemHeading.left + anchors.right: labelItemHeading.right + anchors.top: labelItemHeading.bottom + anchors.leftMargin: labelItemHeading.leftPadding + height: 1 * Kirigami.Units.devicePixelRatio + color: Kirigami.Theme.highlightColor + visible: labelItem.activeFocus && labelItem.indicator.visible + } + } + } +} diff --git a/src/controls/GlobalDrawer.qml b/src/controls/GlobalDrawer.qml new file mode 100644 index 0000000..7e514cf --- /dev/null +++ b/src/controls/GlobalDrawer.qml @@ -0,0 +1,583 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Templates 2.0 as T2 +import QtQuick.Controls 2.0 as QQC2 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +import "private" +import "templates/private" + +/** + * A drawer specialization intended for the global actions of the application + * valid regardless of the application state (think about the menubar + * of a desktop application). + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * [...] + * } + * @endcode + * + */ +OverlayDrawer { + id: root + edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.RightEdge : Qt.LeftEdge + + /** + * title: string + * A title to be displayed on top of the drawer + */ + property alias title: bannerImage.title + + /** + * icon: var + * An icon to be displayed alongside the title. + * It can be a QIcon, a fdo-compatible icon name, or any url understood by Image + */ + property alias titleIcon: bannerImage.titleIcon + + /** + * bannerImageSource: string + * An image to be used as background for the title and icon for + * a decorative purpose. + * It accepts any url format supported by Image + */ + property alias bannerImageSource: bannerImage.source + + /** + * actions: list + * The list of actions can be nested having a tree structure. + * A tree depth bigger than 2 is discouraged. + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [ + * Kirigami.Action { + * text: "View" + * iconName: "view-list-icons" + * Kirigami.Action { + * text: "action 1" + * } + * Kirigami.Action { + * text: "action 2" + * } + * Kirigami.Action { + * text: "action 3" + * } + * }, + * Kirigami.Action { + * text: "Sync" + * iconName: "folder-sync" + * } + * ] + * } + * [...] + * } + * @endcode + */ + property list actions + + + /** + * content: list default property + * Any random Item can be instantiated inside the drawer and + * will be displayed underneath the actions list. + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [...] + * Button { + * text: "Button" + * onClicked: //do stuff + * } + * } + * [...] + * } + * @endcode + */ + default property alias content: mainContent.data + + /** + * topContent: list default property + * Items that will be instantiated inside the drawer and + * will be displayed on top of the actions list. + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * globalDrawer: Kirigami.GlobalDrawer { + * actions: [...] + * topContent: [Button { + * text: "Button" + * onClicked: //do stuff + * }] + * } + * [...] + * } + * @endcode + */ + property alias topContent: topContent.data + + /** + * showContentWhenCollapsed: bool + * If true, when the drawer is collapsed as a sidebar, the content items + * at the bottom will be hidden (default false). + * If you want to keep some items visible and some invisible, set this to + * false and control the visibility/opacity of individual items, + * binded to the collapsed property + * @since 2.5 + */ + property bool showContentWhenCollapsed: false + + /** + * showTopContentWhenCollapsed: bool + * If true, when the drawer is collapsed as a sidebar, the top content items + * at the top will be hidden (default false). + * If you want to keep some items visible and some invisible, set this to + * false and control the visibility/opacity of individual items, + * binded to the collapsed property + * @since 2.5 + */ + property bool showTopContentWhenCollapsed: false + + /** + * resetMenuOnTriggered: bool + * + * On the actions menu, whenever a leaf action is triggered, the menu + * will reset to its parent. + */ + property bool resetMenuOnTriggered: true + + /** + * currentSubMenu: Action + * + * Points to the action acting as a submenu + */ + readonly property Action currentSubMenu: stackView.currentItem ? stackView.currentItem.current: null + + /** + * Notifies that the banner has been clicked + */ + signal bannerClicked() + + /** + * Reverts the menu back to its initial state + */ + function resetMenu() { + stackView.pop(stackView.get(0, T2.StackView.DontLoad)); + if (root.modal) { + root.drawerOpen = false; + } + } + + rightPadding: !Settings.isMobile && mainFlickable.contentHeight > mainFlickable.height ? Units.gridUnit : Units.smallSpacing + + contentItem: ScrollView { + id: scrollView + //ensure the attached property exists + Theme.inherit: true + anchors.fill: parent + implicitWidth: Math.min (Units.gridUnit * 20, root.parent.width * 0.8) + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Flickable { + id: mainFlickable + contentWidth: width + contentHeight: mainColumn.Layout.minimumHeight + ColumnLayout { + id: mainColumn + width: mainFlickable.width + spacing: 0 + height: Math.max(root.height, Layout.minimumHeight) + + //TODO: cable visible of bannerimage + Item { + implicitHeight: root.collapsible + ? Math.max(collapseButton.height + Units.smallSpacing, bannerImage.Layout.preferredHeight) + : bannerImage.Layout.preferredHeight + + Layout.fillWidth: true + visible: !bannerImage.empty || root.collapsible + + BannerImage { + id: bannerImage + anchors.fill: parent + opacity: !root.collapsed + fillMode: Image.PreserveAspectCrop + + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + leftPadding: root.collapsible ? collapseButton.width + Units.smallSpacing*2 : topPadding + MouseArea { + anchors.fill: parent + onClicked: root.bannerClicked() + } + EdgeShadow { + edge: Qt.BottomEdge + visible: bannerImageSource != "" + anchors { + left: parent.left + right: parent.right + bottom: parent.top + } + } + } + PrivateActionToolButton { + id: collapseButton + readonly property bool noTitle: (!root.title || root.title.length===0) && (!root.titleIcon || root.title.length===0) + anchors { + top: parent.top + left: parent.left + topMargin: root.collapsed || noTitle ? 0 : Units.smallSpacing + Units.iconSizes.large/2 - height/2 + leftMargin: root.collapsed || noTitle ? 0 : Units.smallSpacing + Behavior on leftMargin { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + Behavior on topMargin { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + width: Units.iconSizes.smallMedium + Units.largeSpacing * 2 + height: width + + Behavior on y { + YAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + + visible: root.collapsible + kirigamiAction: Action { + icon.name: "application-menu" + checkable: true + checked: !root.collapsed + onCheckedChanged: root.collapsed = !checked + } + } + } + + ColumnLayout { + id: topContent + spacing: 0 + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: root.leftPadding + Layout.rightMargin: root.rightPadding + Layout.bottomMargin: Units.smallSpacing + Layout.topMargin: root.topPadding + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: implicitHeight * opacity + //NOTE: why this? just Layout.fillWidth: true doesn't seem sufficient + //as items are added only after this column creation + Layout.minimumWidth: parent.width - root.leftPadding - root.rightPadding + visible: children.length > 0 && childrenRect.height > 0 && opacity > 0 + opacity: !root.collapsed || showTopContentWhenCollapsed + Behavior on opacity { + //not an animator as is binded + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + T2.StackView { + id: stackView + Layout.fillWidth: true + Layout.minimumHeight: currentItem ? currentItem.implicitHeight : 0 + Layout.maximumHeight: Layout.minimumHeight + property ActionsMenu openSubMenu + initialItem: menuComponent + //NOTE: it's important those are NumberAnimation and not XAnimators + // as while the animation is running the drawer may close, and + //the animator would stop when not drawing see BUG 381576 + popEnter: Transition { + NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * -stackView.width; to: 0; duration: 400; easing.type: Easing.OutCubic } + } + + popExit: Transition { + NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * stackView.width; duration: 400; easing.type: Easing.OutCubic } + } + + pushEnter: Transition { + NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * stackView.width; to: 0; duration: 400; easing.type: Easing.OutCubic } + } + + pushExit: Transition { + NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * -stackView.width; duration: 400; easing.type: Easing.OutCubic } + } + + replaceEnter: Transition { + NumberAnimation { property: "x"; from: (stackView.mirrored ? -1 : 1) * stackView.width; to: 0; duration: 400; easing.type: Easing.OutCubic } + } + + replaceExit: Transition { + NumberAnimation { property: "x"; from: 0; to: (stackView.mirrored ? -1 : 1) * -stackView.width; duration: 400; easing.type: Easing.OutCubic } + } + } + Item { + Layout.fillWidth: true + Layout.fillHeight: root.actions.length>0 + Layout.minimumHeight: Units.smallSpacing + } + + ColumnLayout { + id: mainContent + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: root.leftPadding + Layout.rightMargin: root.rightPadding + Layout.fillWidth: true + Layout.fillHeight: true + //NOTE: why this? just Layout.fillWidth: true doesn't seem sufficient + //as items are added only after this column creation + Layout.minimumWidth: parent.width - root.leftPadding - root.rightPadding + visible: children.length > 0 && (opacity > 0 || mainContentAnimator.running) + opacity: !root.collapsed || showContentWhenCollapsed + Behavior on opacity { + OpacityAnimator { + id: mainContentAnimator + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + Item { + Layout.minimumWidth: Units.smallSpacing + Layout.minimumHeight: root.bottomPadding + } + + Component { + id: menuComponent + + Column { + spacing: 0 + property alias model: actionsRepeater.model + property Action current + + property int level: 0 + Layout.maximumHeight: Layout.minimumHeight + + move: Transition { + YAnimator { + duration: Units.longDuration/2 + easing.type: Easing.InOutQuad + } + } + + BasicListItem { + id: backItem + visible: level > 0 + supportsMouseEvents: true + icon: (LayoutMirroring.enabled ? "go-previous-symbolic-rtl" : "go-previous-symbolic") + + label: MnemonicData.richTextLabel + MnemonicData.enabled: backItem.enabled && backItem.visible + MnemonicData.controlType: MnemonicData.MenuItem + MnemonicData.label: qsTr("Back") + + separatorVisible: false + onClicked: stackView.pop() + } + Shortcut { + sequence: backItem.MnemonicData.sequence + onActivated: backItem.clicked() + } + + Repeater { + id: actionsRepeater + model: actions + delegate: + BasicListItem { + id: listItem + supportsMouseEvents: true + readonly property bool wideMode: width > height * 2 + readonly property bool isSeparator: modelData.hasOwnProperty("separator") && modelData.separator + reserveSpaceForIcon: !isSeparator + reserveSpaceForLabel: !isSeparator + checked: modelData.checked || (actionsMenu && actionsMenu.visible) + width: parent.width + + icon: modelData.iconName + + label: width > height * 2 ? MnemonicData.richTextLabel : "" + + MnemonicData.enabled: listItem.enabled && listItem.visible + MnemonicData.controlType: MnemonicData.MenuItem + MnemonicData.label: modelData.text + property ActionsMenu actionsMenu: ActionsMenu { + x: Qt.application.layoutDirection == Qt.RightToLeft ? -width : listItem.width + actions: modelData.children + submenuComponent: Component { + ActionsMenu {} + } + onVisibleChanged: { + if (visible) { + stackView.openSubMenu = listItem.actionsMenu; + } else if (stackView.openSubMenu == listItem.actionsMenu) { + stackView.openSubMenu = null; + } + } + } + + separatorVisible: false + //TODO: animate the hide by collapse + visible: (model ? model.visible || model.visible===undefined : modelData.visible) && opacity > 0 + opacity: (!root.collapsed || icon.length > 0) + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration/2 + easing.type: Easing.InOutQuad + } + } + enabled: !isSeparator && ( (model && model.enabled !== undefined) ? model.enabled : modelData.enabled) + opacity: enabled ? 1.0 : 0.3 + + Separator { + id: separatorAction + + visible: listItem.isSeparator + Layout.fillWidth: true + } + + Icon { + Shortcut { + sequence: listItem.MnemonicData.sequence + onActivated: listItem.clicked() + } + isMask: true + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: !Settings.isMobile && mainFlickable.contentHeight > mainFlickable.height ? Units.gridUnit : 0 + Layout.leftMargin: !root.collapsed ? 0 : parent.width - listItem.width + Layout.preferredHeight: !root.collapsed ? Units.iconSizes.smallMedium : Units.iconSizes.small/2 + selected: listItem.checked || listItem.pressed + Layout.preferredWidth: Layout.preferredHeight + source: (LayoutMirroring.enabled ? "go-next-symbolic-rtl" : "go-next-symbolic") + visible: !listItem.isSeparator && modelData.children!==undefined && modelData.children.length > 0 + } + data: [ + QQC2.ToolTip { + visible: !listItem.isSeparator && (modelData.tooltip.length || root.collapsed) && (!actionsMenu || !actionsMenu.visible) && listItem.hovered && text.length > 0 + text: modelData.tooltip.length ? modelData.tooltip : modelData.text + delay: 1000 + timeout: 5000 + y: listItem.height/2 - height/2 + x: Qt.application.layoutDirection == Qt.RightToLeft ? -width : listItem.width + } + ] + + onHoveredChanged: { + if (!hovered) { + return; + } + if (stackView.openSubMenu) { + stackView.openSubMenu.visible = false; + + if (!listItem.actionsMenu.hasOwnProperty("count") || listItem.actionsMenu.count>0) { + if (listItem.actionsMenu.hasOwnProperty("popup")) { + listItem.actionsMenu.popup(listItem, listItem.width, 0) + } else { + listItem.actionsMenu.visible = true; + } + } + } + } + onClicked: { + modelData.trigger(); + if (modelData.children!==undefined && modelData.children.length > 0) { + if (root.collapsed) { + //fallbacks needed for Qt 5.9 + if ((!listItem.actionsMenu.hasOwnProperty("count") || listItem.actionsMenu.count>0) && !listItem.actionsMenu.visible) { + stackView.openSubMenu = listItem.actionsMenu; + if (listItem.actionsMenu.hasOwnProperty("popup")) { + listItem.actionsMenu.popup(listItem, listItem.width, 0) + } else { + listItem.actionsMenu.visible = true; + } + } + } else { + stackView.push(menuComponent, {model: modelData.children, level: level + 1, current: modelData }); + } + } else if (root.resetMenuOnTriggered) { + root.resetMenu(); + } + checked = Qt.binding(function() { return modelData.checked || (actionsMenu && actionsMenu.visible) }); + } + } + } + } + } + } + } + } +} + diff --git a/src/controls/Heading.qml b/src/controls/Heading.qml new file mode 100644 index 0000000..19f3b37 --- /dev/null +++ b/src/controls/Heading.qml @@ -0,0 +1,88 @@ +/* +* Copyright 2012 by Sebastian Kügler +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.0 +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 + +/** + * A heading label used for subsections of texts. + * + * The characteristics of the text will be automatically set according to the + * plasma Theme. Use this components for section titles or headings in your UI, + * for example page or section titles. + * + * Example usage: + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * [...] + * Column { + * Kirigami.Heading { + * text: "Apples in the sunlight" + * level: 2 + * } + * [...] + * } + * @endcode + * + * The most important property is "text", which applies to the text property of + * Label. See PlasmaComponents Label and primitive QML Text element API for + * additional properties, methods and signals. + * @inherits QtQuick.Controls.Label + */ +QQC2.Label { + id: heading + + /** + * level: int + * The level determines how big the section header is display, values + * between 1 (big) and 5 (small) are accepted + */ + property int level: 1 + + /** + * step: int + * adjust the point size in between a level and another. + * DEPRECATED + */ + property int step: 0 + + font.pointSize: headerPointSize(level) + font.weight: level <= 4 ? Font.Light : Font.Normal + font.styleName: level <= 4 ? "Light" : "Regular" + wrapMode: Text.WordWrap + + function headerPointSize(l) { + var n = Theme.defaultFont.pointSize; + var s; + switch (l) { + case 1: + return Math.round(n * 1.80) + step; + case 2: + return Math.round(n * 1.30) + step; + case 3: + return Math.round(n * 1.20) + step; + case 4: + return Math.round(n * 1.10) + step; + default: + return n + step; + } + } +} diff --git a/src/controls/InlineMessage.qml b/src/controls/InlineMessage.qml new file mode 100644 index 0000000..4da6e54 --- /dev/null +++ b/src/controls/InlineMessage.qml @@ -0,0 +1,300 @@ +/* + * Copyright 2018 Eike Hein + * Copyright 2018 Marco Martin + * Copyright 2018 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.7 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.5 as Kirigami +import "private" + +import "templates" as T + +/** + * An inline message item with support for informational, positive, + * warning and error types, and with support for associated actions. + * + * InlineMessage can be used to give information to the user or + * interact with the user, without requiring the use of a dialog. + * + * The InlineMessage item is hidden by default. It also manages its + * height (and implicitHeight) during an animated reveal when shown. + * You should avoid setting height on an InlineMessage unless it is + * already visible. + * + * Optionally an icon can be set, defaulting to an icon appropriate + * to the message type otherwise. + * + * Optionally a close button can be shown. + * + * Actions are added from left to right. If more actions are set than + * can fit, an overflow menu is provided. + * + * Example: + * @code + * InlineMessage { + * type: Kirigami.MessageType.Error + * + * text: "My error message" + * + * actions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * } + * @endcode + * + * @since 5.45 + */ + +T.InlineMessage { + id: root + + implicitHeight: visible ? contentLayout.implicitHeight + (2 * (background.border.width + Kirigami.Units.smallSpacing)) : 0 + + property bool _animating: false + + leftPadding: background.border.width + Kirigami.Units.smallSpacing + topPadding: background.border.width + Kirigami.Units.smallSpacing + rightPadding: background.border.width + Kirigami.Units.smallSpacing + bottomPadding: background.border.width + Kirigami.Units.smallSpacing + + Behavior on implicitHeight { + enabled: !root.visible + + SequentialAnimation { + PropertyAction { targets: root; property: "_animating"; value: true } + NumberAnimation { duration: Kirigami.Units.longDuration } + } + } + + onVisibleChanged: { + if (!visible) { + contentLayout.opacity = 0.0; + } + } + + opacity: visible ? 1.0 : 0.0 + + Behavior on opacity { + enabled: !root.visible + + NumberAnimation { duration: Kirigami.Units.shortDuration } + } + + onOpacityChanged: { + if (opacity == 0.0) { + contentLayout.opacity = 0.0; + } else if (opacity == 1.0) { + contentLayout.opacity = 1.0; + } + } + + onImplicitHeightChanged: { + height = implicitHeight; + } + + background: Rectangle { + id: bgBorderRect + + color: { + if (root.type == Kirigami.MessageType.Positive) { + return Kirigami.Theme.positiveTextColor; + } else if (root.type == Kirigami.MessageType.Warning) { + return Kirigami.Theme.neutralTextColor; + } else if (root.type == Kirigami.MessageType.Error) { + return Kirigami.Theme.negativeTextColor; + } + + return Kirigami.Theme.activeTextColor; + } + + radius: Kirigami.Units.smallSpacing / 2 + + Rectangle { + id: bgFillRect + + anchors.fill: parent + anchors.margins: Kirigami.Units.devicePixelRatio + + color: Kirigami.Theme.backgroundColor + + radius: bgBorderRect.radius * 0.60 + } + + Rectangle { + anchors.fill: bgFillRect + + color: bgBorderRect.color + + opacity: 0.20 + + radius: bgFillRect.radius + } + + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 1 + radius: 12 + samples: 32 + color: Qt.rgba(0, 0, 0, 0.5) + } + } + + contentItem: GridLayout { + id: contentLayout + + // Used to defer opacity animation until we know if InlineMessage was + // initialized visible. + property bool complete: false + + Behavior on opacity { + enabled: root.visible && contentLayout.complete + + SequentialAnimation { + NumberAnimation { duration: Kirigami.Units.shortDuration * 2 } + PropertyAction { targets: root; property: "_animating"; value: false } + } + } + + rowSpacing: Kirigami.Units.largeSpacing + columnSpacing: Kirigami.Units.smallSpacing + + Kirigami.Icon { + id: icon + + width: Kirigami.Units.iconSizes.smallMedium + height: width + + Layout.alignment: text.lineCount > 1 ? Qt.AlignTop : Qt.AlignVCenter + + Layout.minimumWidth: width + Layout.minimumHeight: height + + source: { + if (root.icon.source) { + return root.icon.source; + } + + if (root.type == Kirigami.MessageType.Positive) { + return "dialog-positive"; + } else if (root.type == Kirigami.MessageType.Warning) { + return "dialog-warning"; + } else if (root.type == Kirigami.MessageType.Error) { + return "dialog-error"; + } + + return "dialog-information"; + } + + color: root.icon.color + } + + MouseArea { + implicitHeight: text.implicitHeight + + Layout.fillWidth: true + Layout.alignment: text.lineCount > 1 ? Qt.AlignTop : Qt.AlignVCenter + Layout.row: 0 + Layout.column: 1 + + cursorShape: text.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + + Controls.Label { + id: text + + width: parent.width + + color: Kirigami.Theme.textColor + wrapMode: Text.WordWrap + elide: Text.ElideRight + + text: root.text + + onLinkHovered: root.linkHovered(link) + onLinkActivated: root.linkActivated(link) + } + //this must be child of an item which doesn't try to resize it + TextMetrics { + id: messageTextMetrics + + font: text.font + text: text.text + } + } + + Kirigami.ActionToolBar { + id: actionsLayout + + flat: false + actions: root.actions + visible: root.actions.length + + Layout.alignment: Qt.AlignRight + + Layout.row: { + if (messageTextMetrics.width + Kirigami.Units.smallSpacing > + (contentLayout.width - icon.width - actionsLayout.width + - closeButton.width - (3 * contentLayout.columnSpacing))) { + return 1; + } + return 0; + } + Layout.column: Layout.row ? 0 : 2 + Layout.columnSpan: Layout.row ? (closeButton.visible ? 3 : 2) : 1 + } + + Controls.ToolButton { + id: closeButton + + visible: root.showCloseButton + + Layout.alignment: text.lineCount > 1 || actionsLayout.Layout.row ? Qt.AlignTop : Qt.AlignVCenter + Layout.row: 0 + Layout.column: actionsLayout.Layout.row ? 2 : 3 + + //TODO: use toolbuttons icons when we can depend from Qt 5.10 + Kirigami.Icon { + anchors.centerIn: parent + source: "dialog-close" + width: Kirigami.Units.iconSizes.smallMedium + height: width + } + + onClicked: root.visible = false + } + + Component.onCompleted: complete = true + } +} diff --git a/src/controls/ItemViewHeader.qml b/src/controls/ItemViewHeader.qml new file mode 100644 index 0000000..4f94a73 --- /dev/null +++ b/src/controls/ItemViewHeader.qml @@ -0,0 +1,114 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Templates 2.0 as T2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 as Kirigami +import "private" + +/** + * An item that can be used as an header for a ListView. + * It will play nice with the margin policies of ScrollablePage and can + * automatically shrink when the list is scrolled, like the behavior + * of list headers in many mobile applications. + * It provides some default content: a title and an optional background image + * @since 2.1 + */ +Kirigami.AbstractItemViewHeader { + id: root + property alias title: heading.text + property alias color: heading.color + + property alias backgroundImage: image + + maximumHeight: (backgroundImage.hasImage ? 10 : 6) * Kirigami.Units.gridUnit - (applicationWindow().header ? applicationWindow().header.height : 0) - bottomPadding + bottomPadding: Kirigami.Units.smallSpacing + leftPadding: Kirigami.Units.smallSpacing + + background: Rectangle { + id: backgroundItem + color: Kirigami.Theme.backgroundColor + Image { + id: image + anchors.fill: parent + readonly property bool hasImage: backgroundImage.status === Image.Ready || backgroundImage.status === Image.Loading + fillMode: Image.PreserveAspectCrop + asynchronous: true + } + EdgeShadow { + edge: root.view.headerPositioning == ListView.InlineHeader ? Qt.BottomEdge : Qt.TopEdge + anchors { + right: parent.right + left: parent.left + top: root.view.headerPositioning == ListView.InlineHeader ? undefined : parent.bottom + bottom: root.view.headerPositioning == ListView.InlineHeader ? parent.top : undefined + } + } + + readonly property Page page: { + var obj = root.view; + while(obj && !obj.hasOwnProperty("title") && !obj.hasOwnProperty("isCurrentPage")) { + obj = obj.parent + } + return obj; + } + Rectangle { + id: rect + color: backgroundItem.page && backgroundItem.page.isCurrentPage ? Kirigami.Theme.highlightColor : Kirigami.Theme.disabledTextColor + height: root.bottomPadding + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + } + } + + contentItem: Item { + Kirigami.Heading { + id: heading + anchors { + fill: parent + margins: Kirigami.Units.smallSpacing + } + + height: undefined + text: page.title + fontSizeMode: Text.Fit + minimumPointSize: 10 + font.pointSize: 30 + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignBottom + color: root.backgroundImage.hasImage ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.highlightColor + opacity: 1 + elide: Text.ElideRight + + layer.enabled: root.backgroundImage.hasImage + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 2 + radius: Kirigami.Units.smallSpacing*2 + samples: 32 + color: Qt.rgba(0, 0, 0, 0.7) + } + } + } +} + diff --git a/src/controls/Label.qml b/src/controls/Label.qml new file mode 100644 index 0000000..6a10b90 --- /dev/null +++ b/src/controls/Label.qml @@ -0,0 +1,47 @@ +/* +* Copyright (C) 2011 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.1 +import QtQuick.Window 2.2 +import org.kde.kirigami 2.4 +import QtQuick.Controls 2.0 as Controls + +/** + * This is a label which uses the current Theme. + * + * The characteristics of the text will be automatically set according to the + * current Theme. If you need a more customized text item use the Text component + * from QtQuick. + * + * You can use all elements of the QML Text component, in particular the "text" + * property to define the label text. + * + * @inherit QtQuick.Templates.Label + * @deprecated use QtQuick.Templates.Label directly, it will be styled appropriately + */ +Controls.Label { + height: Math.round(Math.max(paintedHeight, Units.gridUnit * 1.6)) + verticalAlignment: lineCount > 1 ? Text.AlignTop : Text.AlignVCenter + + activeFocusOnTab: false + + Component.onCompleted: { + console.warn("Kirigami.Label is deprecated. Use QtQuickControls2.Label instead") + } +} diff --git a/src/controls/LinkButton.qml b/src/controls/LinkButton.qml new file mode 100644 index 0000000..4d739d0 --- /dev/null +++ b/src/controls/LinkButton.qml @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library/Lesser General Public License + * version 2, or (at your option) any later version, as published by the + * Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library/Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 +import org.kde.kirigami 2.0 +import QtQuick.Controls 2.1 as QQC2 + +/** + * Shows a Button that looks like a link + * + * Uses the link color settings and allows to trigger an action when clicked. + * + * Maps to the Command Link in the HIG: + * https://hig.kde.org/components/navigation/commandlink.html + * + * @since 5.52 + * @since org.kde.kirigami 2.6 + */ +QQC2.Label { + id: control + + property Action action: null + property alias acceptedButtons: area.acceptedButtons + Accessible.role: Accessible.Button + Accessible.name: text + Accessible.onPressAction: control.clicked(null) + + text: action ? action.text : "" + enabled: !action || action.enabled + onClicked: if (action) action.trigger() + + font.underline: control.enabled && area.containsMouse + color: enabled ? Theme.linkColor : Theme.textColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + + signal pressed(QtObject mouse) + signal clicked(QtObject mouse) + MouseArea { + id: area + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onClicked: control.clicked(mouse) + onPressed: control.pressed(mouse) + } +} diff --git a/src/controls/ListItemDragHandle.qml b/src/controls/ListItemDragHandle.qml new file mode 100644 index 0000000..ab609e6 --- /dev/null +++ b/src/controls/ListItemDragHandle.qml @@ -0,0 +1,207 @@ +/* +* Copyright (C) 2018 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + +/** + * Implements a drag handle supposed to be in items in ListViews to reorder items + * The ListView must visualize a model which supports item reordering, + * such as ListModel.move() or QAbstractItemModel instances with moveRows() correctly implemented. + * In order for ListItemDragHandle to work correctly, the listItem that is being dragged + * should not directly be the delegate of the ListView, but a child of it. + * + * It is recommended to use DelagateRecycler as base delegate like the following code: + * @code + * ... + * Component { + * id: delegateComponent + * Kirigami.AbstractListItem { + * id: listItem + * contentItem: RowLayout { + * Kirigami.ListItemDragHandle { + * listItem: listItem + * listView: mainList + * onMoveRequested: listModel.move(oldIndex, newIndex, 1) + * } + * Controls.Label { + * text: model.label + * } + * } + * } + * } + * ListView { + * id: mainList + * + * model: ListModel { + * id: listModel + * ListItem { + * lablel: "Item 1" + * } + * ListItem { + * lablel: "Item 2" + * } + * ListItem { + * lablel: "Item 3" + * } + * } + * //this is optional to make list items animated when reordered + * moveDisplaced: Transition { + * YAnimator { + * duration: Kirigami.Units.longDuration + * easing.type: Easing.InOutQuad + * } + * } + * delegate: Kirigami.DelegateRecycler { + * width: mainList.width + * sourceComponent: delegateComponent + * } + * } + * ... + * @endcode + * + * @inherits Item + * @since 2.5 + */ +Item { + id: root + + /** + * listItem: Item + * The id of the delegate that we want to drag around, which *must* + * be a child of the actual ListView's delegate + */ + property Item listItem + + /** + * listView: Listview + * The id of the ListView the delegates belong to. + */ + property ListView listView + + /** + * Emitted when the drag handle wants to move the item in the model + * The following example does the move in the case a ListModel is used + * @code + * onMoveRequested: listModel.move(oldIndex, newIndex, 1) + * @endcode + * @param oldIndex the index the item is currently at + * @param newIndex the index we want to move the item to + */ + signal moveRequested(int oldIndex, int newIndex) + + /** + * Emitted when the drag operation is complete and the item has been + * dropped in the new final position + */ + signal dropped() + + implicitWidth: Kirigami.Units.iconSizes.smallMedium + implicitHeight: implicitWidth + + MouseArea { + id: mouseArea + anchors.fill: parent + drag { + target: listItem + axis: Drag.YAxis + minimumY: 0 + maximumY: listView.height - listItem.height + } + Kirigami.Icon { + id: internal + source: "handle-sort" + property int startY + property int mouseDownY + property Item originalParent + property int autoScrollThreshold: listItem.height * 3 + opacity: mouseArea.pressed || (!Kirigami.Settings.tabletMode && listItem.hovered) ? 1 : 0.6 + + function arrangeItem() { + var newIndex = listView.indexAt(1, listView.contentItem.mapFromItem(listItem, 0, 0).y + internal.mouseDownY); + + if (Math.abs(listItem.y - internal.startY) > height && newIndex > -1 && newIndex !== index) { + root.moveRequested(index, newIndex); + } + } + + anchors.fill: parent + } + preventStealing: true + + + onPressed: { + internal.originalParent = listItem.parent; + listItem.parent = listView; + listItem.y = internal.originalParent.mapToItem(listItem.parent, listItem.x, listItem.y).y; + internal.originalParent.z = 99; + internal.startY = listItem.y; + internal.mouseDownY = mouse.y; + } + + onPositionChanged: { + if (!pressed) { + return; + } + internal.arrangeItem(); + + scrollTimer.interval = 500 * Math.max(0.1, (1-Math.max(internal.autoScrollThreshold - listItem.y, listItem.y - listView.height + internal.autoScrollThreshold + listItem.height) / internal.autoScrollThreshold)); + scrollTimer.running = (listItem.y < internal.autoScrollThreshold || + listItem.y > listView.height - internal.autoScrollThreshold); + } + onReleased: { + listItem.y = internal.originalParent.mapFromItem(listItem, 0, 0).y; + listItem.parent = internal.originalParent; + dropAnimation.running = true; + scrollTimer.running = false; + root.dropped(); + } + onCanceled: released() + SequentialAnimation { + id: dropAnimation + YAnimator { + target: listItem + from: listItem.y + to: 0 + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + PropertyAction { + target: listItem.parent + property: "z" + value: 0 + } + } + Timer { + id: scrollTimer + interval: 500 + repeat: true + onTriggered: { + if (listItem.y < internal.autoScrollThreshold) { + listView.contentY = Math.max(0, listView.contentY - Kirigami.Units.gridUnit) + } else { + listView.contentY = Math.min(listView.contentHeight - listView.height, listView.contentY + Kirigami.Units.gridUnit) + } + internal.arrangeItem(); + } + } + } +} + diff --git a/src/controls/OverlayDrawer.qml b/src/controls/OverlayDrawer.qml new file mode 100644 index 0000000..0ef1718 --- /dev/null +++ b/src/controls/OverlayDrawer.qml @@ -0,0 +1,155 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtGraphicalEffects 1.0 +import QtQuick.Templates 2.0 as T2 +import org.kde.kirigami 2.5 + +import "private" +import "templates" as T + +/** + * Overlay Drawers are used to expose additional UI elements needed for + * small secondary tasks for which the main UI elements are not needed. + * For example in Okular Active, an Overlay Drawer is used to display + * thumbnails of all pages within a document along with a search field. + * This is used for the distinct task of navigating to another page. + */ +T.OverlayDrawer { + id: root + +//BEGIN Properties + focus: false + modal: true + drawerOpen: !modal + closePolicy: modal ? T2.Popup.CloseOnEscape | T2.Popup.CloseOnReleaseOutside : T2.Popup.NoAutoClose + handleVisible: (modal || !drawerOpen) && (typeof(applicationWindow)===typeof(Function) && applicationWindow() ? applicationWindow().controlsVisible : true) + + onPositionChanged: { + if (!modal && !root.peeking && !root.animating) { + position = 1; + } + } + + background: Rectangle { + color: Theme.backgroundColor + + Item { + parent: root.handle + anchors.fill: parent + + DropShadow { + anchors.fill: handleGraphics + visible: !parent.parent.handleAnchor || root.handle.pressed || (root.modal && root.position > 0) + horizontalOffset: 0 + verticalOffset: Units.devicePixelRatio + radius: Units.gridUnit /2 + samples: 16 + color: Qt.rgba(0, 0, 0, root.handle.pressed ? 0.6 : 0.4) + source: handleGraphics + } + Rectangle { + id: handleGraphics + anchors.centerIn: parent + Theme.colorSet: parent.parent.handleAnchor ? parent.parent.handleAnchor.Theme.colorSet : Theme.Button + Theme.backgroundColor: parent.parent.handleAnchor ? parent.parent.handleAnchor.Theme.backgroundColor : undefined + Theme.textColor: parent.parent.handleAnchor ? parent.parent.handleAnchor.Theme.textColor : undefined + Theme.inherit: false + color: parent.parent.handleAnchor && !root.visible + ? "transparent" + : (root.handle.pressed ? Theme.highlightColor : Theme.backgroundColor) + width: Units.iconSizes.smallMedium + Units.smallSpacing * 2 + height: width + radius: Units.devicePixelRatio * 2 + Loader { + anchors.centerIn: parent + width: height + height: Units.iconSizes.smallMedium + source: { + var edge = root.edge; + if (Qt.application.layoutDirection == Qt.RightToLeft) { + if (edge === Qt.LeftEdge) { + edge = Qt.RightEdge; + } else { + edge = Qt.LeftEdge; + } + } + switch(edge) { + case Qt.LeftEdge: + return Qt.resolvedUrl("templates/private/MenuIcon.qml"); + case Qt.RightEdge: { + if (root.hasOwnProperty("actions")) { + return Qt.resolvedUrl("templates/private/ContextIcon.qml"); + } else { + return Qt.resolvedUrl("templates/private/GenericDrawerIcon.qml"); + } + } + default: + return ""; + } + } + onItemChanged: { + if(item) { + item.drawer = Qt.binding(function(){return root}); + item.color = Qt.binding(function(){return root.handle.pressed ? Theme.highlightedTextColor : Theme.textColor}); + } + } + } + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } + + + Separator { + anchors { + right: root.edge == Qt.RightEdge ? parent.left : (root.edge == Qt.LeftEdge ? undefined : parent.right) + left: root.edge == Qt.LeftEdge ? parent.right : (root.edge == Qt.RightEdge ? undefined : parent.left) + top: root.edge == Qt.TopEdge ? parent.bottom : (root.edge == Qt.BottomEdge ? undefined : parent.top) + bottom: root.edge == Qt.BottomEdge ? parent.top : (root.edge == Qt.TopEdge ? undefined : parent.bottom) + } + visible: !root.modal + } + EdgeShadow { + z: -2 + visible: root.modal + edge: root.edge + anchors { + right: root.edge == Qt.RightEdge ? parent.left : (root.edge == Qt.LeftEdge ? undefined : parent.right) + left: root.edge == Qt.LeftEdge ? parent.right : (root.edge == Qt.RightEdge ? undefined : parent.left) + top: root.edge == Qt.TopEdge ? parent.bottom : (root.edge == Qt.BottomEdge ? undefined : parent.top) + bottom: root.edge == Qt.BottomEdge ? parent.top : (root.edge == Qt.TopEdge ? undefined : parent.bottom) + } + + opacity: root.position == 0 ? 0 : 1 + + Behavior on opacity { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } +} diff --git a/src/controls/OverlaySheet.qml b/src/controls/OverlaySheet.qml new file mode 100644 index 0000000..ff0869e --- /dev/null +++ b/src/controls/OverlaySheet.qml @@ -0,0 +1,106 @@ +/* +* Copyright (C) 2016 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.5 +import org.kde.kirigami 2.4 +import "private" +import "templates" as T + +/** + * An overlay sheet that covers the current Page content. + * Its contents can be scrolled up or down, scrolling all the way up or + * all the way down, dismisses it. + * Use this for big, modal dialogs or information display, that can't be + * logically done as a new separate Page, even if potentially + * are taller than the screen space. + */ +T.OverlaySheet { + id: root + + background: Item { + anchors.fill: parent + //Why not a shadow or rectangularglow? + //on some android devices they break badly when the OverlaySheet is bigger than + //the screen + CornerShadow { + corner: Qt.BottomRightCorner + anchors { + right: parent.left + bottom: parent.top + } + } + CornerShadow { + corner: Qt.BottomLeftCorner + anchors { + left: parent.right + bottom: parent.top + } + } + CornerShadow { + corner: Qt.TopRightCorner + anchors { + right: parent.left + top: parent.bottom + } + } + CornerShadow { + corner: Qt.TopLeftCorner + anchors { + left: parent.right + top: parent.bottom + } + } + EdgeShadow { + edge: Qt.BottomEdge + anchors { + left: parent.left + right: parent.right + bottom: parent.top + } + } + EdgeShadow { + edge: Qt.TopEdge + anchors { + left: parent.left + right: parent.right + top: parent.bottom + } + } + EdgeShadow { + edge: Qt.LeftEdge + anchors { + top: parent.top + bottom: parent.bottom + left: parent.right + } + } + EdgeShadow { + edge: Qt.RightEdge + anchors { + top: parent.top + bottom: parent.bottom + right: parent.left + } + } + Rectangle { + anchors.fill: parent + color: Theme.backgroundColor + } + } +} diff --git a/src/controls/Page.qml b/src/controls/Page.qml new file mode 100644 index 0000000..2bd19ac --- /dev/null +++ b/src/controls/Page.qml @@ -0,0 +1,376 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami +import "private" +import QtQuick.Templates 2.0 as T2 + +/** + * Page is a container for all the app pages: everything pushed to the + * ApplicationWindow stackView should be a Page instabnce (or a subclass, + * such as ScrollablePage) + * @see ScrollablePage + * @inherit QtQuick.Templates.Page + */ +T2.Page { + id: root + + /** + * leftPadding: int + * default contents padding at left + */ + leftPadding: Kirigami.Units.gridUnit + + /** + * topPadding: int + * default contents padding at top + */ + topPadding: Kirigami.Units.gridUnit + + /** + * rightPadding: int + * default contents padding at right + */ + rightPadding: Kirigami.Units.gridUnit + + /** + * bottomPadding: int + * default contents padding at bottom + */ + bottomPadding: actionButtons.item ? actionButtons.height : Kirigami.Units.gridUnit + + /** + * flickable: Flickable + * if the central element of the page is a Flickable + * (ListView and Gridview as well) you can set it there. + * normally, you wouldn't need to do that, but just use the + * ScrollablePage element instead + * @see ScrollablePage + * Use this if your flickable has some non standard properties, such as not covering the whole Page + */ + property Flickable flickable + + /** + * actions.contextualActions: list + * Defines the contextual actions for the page: + * an easy way to assign actions in the right sliding panel + * + * Example usage: + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.ApplicationWindow { + * [...] + * contextDrawer: Kirigami.ContextDrawer { + * id: contextDrawer + * } + * [...] + * } + * @endcode + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * + * Kirigami.Page { + * [...] + * actions.contextualActions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * [...] + * } + * @endcode + */ + //TODO: remove + property alias contextualActions: actionsGroup.contextualActions + + /** + * actions.main: Action + * An optional single action for the action button. + * it can be a Kirigami.Action or a QAction + * + * Example usage: + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * Kirigami.Page { + * actions.main: Kirigami.Action { + * iconName: "edit" + * onTriggered: { + * // do stuff + * } + * } + * } + * @endcode + */ + //TODO: remove + property alias mainAction: actionsGroup.main + + /** + * actions.left: Action + * An optional extra action at the left of the main action button. + * it can be a Kirigami.Action or a QAction + * + * Example usage: + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * Kirigami.Page { + * actions.left: Kirigami.Action { + * iconName: "edit" + * onTriggered: { + * // do stuff + * } + * } + * } + * @endcode + */ + //TODO: remove + property alias leftAction: actionsGroup.left + + /** + * actions.right: Action + * An optional extra action at the right of the main action button. + * it can be a Kirigami.Action or a QAction + * + * Example usage: + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * Kirigami.Page { + * actions.right: Kirigami.Action { + * iconName: "edit" + * onTriggered: { + * // do stuff + * } + * } + * } + * @endcode + */ + //TODO: remove + property alias rightAction: actionsGroup.right + + /** + * Actions properties are grouped. + * + * @code + * import org.kde.kirigami 2.4 as Kirigami + * Kirigami.Page { + * actions { + * main: Kirigami.Action {...} + * left: Kirigami.Action {...} + * right: Kirigami.Action {...} + * contextualActions: [ + * Kirigami.Action {...}, + * Kirigami.Action {...} + * ] + * } + * } + * @endcode + */ + readonly property alias actions: actionsGroup + + /** + * isCurrentPage: bool + * + * Specifies if it's the currently selected page in the window's pages row. + * + * @since 2.1 + */ + readonly property bool isCurrentPage: typeof applicationWindow === "undefined" || !globalToolBar.row + ? true + : (globalToolBar.row.layers.depth > 1 + ? globalToolBar.row.layers.currentItem === root + : globalToolBar.row.currentItem === root) + + /** + * overlay: Item + * an item which stays on top of every other item in the page, + * if you want to make sure some elements are completely in a + * layer on top of the whole content, parent items to this one. + * It's a "local" version of ApplicationWindow's overlay + * @since 2.5 + */ + readonly property alias overlay: overlayItem + + /** + * emitted When the application requests a Back action + * For instance a global "back" shortcut or the Android + * Back button has been pressed. + * The page can manage the back event by itself, + * and if it set event.accepted = true, it will stop the main + * application to manage the back event. + */ + signal backRequested(var event); + + // Look for sheets and cose them + //FIXME: port Sheets to Popup? + onBackRequested: { + for(var i in root.resources) { + var item = root.resources[i]; + if (item.hasOwnProperty("close") && item.hasOwnProperty("sheetOpen") && item.sheetOpen) { + item.close() + event.accepted = true; + return; + } + } + } + + /** + * globalToolBarItem: Item + * The item used as global toolbar for the page + * present only if we are in a PageRow as a page or as a layer, + * and the style is either Titles or ToolBar + * @since 2.5 + */ + readonly property Item globalToolBarItem: globalToolBar.item + + //NOTE: contentItem will be created if not existing (and contentChildren of Page would become its children) This with anchors enforces the geometry we want, where globalToolBar is a super-header, on top of header + contentItem: Item { + anchors { + top: root.header + ? root.header.bottom + : (globalToolBar.visible ? globalToolBar.bottom : parent.top) + topMargin: root.topPadding + root.spacing + bottom: root.footer ? root.footer.top : parent.bottom + bottomMargin: root.bottomPadding + root.spacing + } + } + + + //FIXME: on material the shadow would bleed over + clip: root.header != null; + + onHeaderChanged: { + if (header) { + header.anchors.top = Qt.binding(function() {return globalToolBar.visible ? globalToolBar.bottom : root.top}); + } + } + + Component.onCompleted: { + headerChanged(); + parentChanged(root.parent); + } + onParentChanged: { + if (!parent) { + return; + } + globalToolBar.stack = null; + globalToolBar.row = null; + + if (root.parent.hasOwnProperty("__pageRow")) { + globalToolBar.row = root.parent.__pageRow; + } + if (root.T2.StackView.view) { + globalToolBar.stack = root.T2.StackView.view; + globalToolBar.row = root.T2.StackView.view.parent; + } + if (globalToolBar.row) { + globalToolBar.row.globalToolBar.actualStyleChanged.connect(globalToolBar.syncSource); + globalToolBar.syncSource(); + } + } + + //in data in order for them to not be considered for contentItem, contentChildren, contentData + data: [ + PageActionPropertyGroup { + id: actionsGroup + }, + + Item { + id: overlayItem + parent: root + z: 9997 + anchors.fill: parent + }, + //global top toolbar if we are in a PageRow (in the row or as a layer) + Loader { + id: globalToolBar + z: 9999 + height: item ? item.implicitHeight : 0 + anchors { + left: parent.left + right: parent.right + top: parent.top + } + property Kirigami.PageRow row + property T2.StackView stack + + // property Component toolbarComponent: Qt.createComponent(Qt.resolvedUrl(row.globalToolBar.actualStyle == Kirigami.ApplicationHeaderStyle.ToolBar ? "private/globaltoolbar/ToolBarPageHeader.qml" : "private/globaltoolbar/TitlesPageHeader.qml")) + + visible: active + active: row && (stack != null || row.globalToolBar.actualStyle === Kirigami.ApplicationHeaderStyle.ToolBar || globalToolBar.row.globalToolBar.actualStyle == Kirigami.ApplicationHeaderStyle.Titles) + + function syncSource() { + if (row && active) { + setSource(Qt.resolvedUrl(row.globalToolBar.actualStyle === Kirigami.ApplicationHeaderStyle.ToolBar ? "private/globaltoolbar/ToolBarPageHeader.qml" : "private/globaltoolbar/TitlesPageHeader.qml"), + //TODO: find container reliably, remove assumption + {"pageRow": Qt.binding(function() {return row}), + "page": root, + "current": Qt.binding(function() {return stack || !root.parent ? true : row.currentIndex === root.parent.level})}); + } + } + + Separator { + z: 999 + anchors.verticalCenter: globalToolBar.verticalCenter + height: globalToolBar.height * 0.6 + visible: !root.T2.StackView.view && globalToolBar.row && root.parent && globalToolBar.row.contentItem.contentX < root.parent.x - globalToolBar.row.globalToolBar.leftReservedSpace + Kirigami.Theme.textColor: globalToolBar.item ? globalToolBar.item.Kirigami.Theme.textColor : undefined + } + }, + + //bottom action buttons + Loader { + id: actionButtons + z: 9999 + parent: root + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + //It should be T2.Page, Qt 5.7 doesn't like it + property Item page: root + height: item ? item.height : 0 + active: typeof applicationWindow !== "undefined" && (!globalToolBar.row || globalToolBar.row.globalToolBar.actualStyle !== Kirigami.ApplicationHeaderStyle.ToolBar) && + //Legacy + (typeof applicationWindow === "undefined" || + (!applicationWindow().header || applicationWindow().header.toString().indexOf("ToolBarApplicationHeader") === -1) && + (!applicationWindow().footer || applicationWindow().footer.toString().indexOf("ToolBarApplicationHeader") === -1)) + source: Qt.resolvedUrl("./private/ActionButton.qml") + } + ] + + Layout.fillWidth: true +} diff --git a/src/controls/PageRow.qml b/src/controls/PageRow.qml new file mode 100644 index 0000000..6a9b13b --- /dev/null +++ b/src/controls/PageRow.qml @@ -0,0 +1,786 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Layouts 1.2 +import QtQml.Models 2.2 +import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.0 as QQC2 +import org.kde.kirigami 2.4 +import "private/globaltoolbar" as GlobalToolBar +import "templates" as KT + +/** + * PageRow implements a row-based navigation model, which can be used + * with a set of interlinked information pages. Items are pushed in the + * back of the row and the view scrolls until that row is visualized. + * A PageRowcan show a single page or a multiple set of columns, depending + * on the window width: on a phone a single column should be fullscreen, + * while on a tablet or a desktop more than one column should be visible. + * @inherit QtQuick.Templates.Control + */ +T.Control { + id: root + +//BEGIN PROPERTIES + /** + * This property holds the number of items currently pushed onto the view + */ + readonly property int depth: popScrollAnim.running && popScrollAnim.pendingDepth > -1 ? popScrollAnim.pendingDepth : pagesLogic.count + + /** + * The last Page in the Row + */ + readonly property Item lastItem: pagesLogic.count ? pagesLogic.get(pagesLogic.count - 1).page : null + + /** + * The currently visible Item + */ + readonly property Item currentItem: mainView.currentItem ? mainView.currentItem.page : null + + /** + * the index of the currently visible Item + */ + property alias currentIndex: mainView.currentIndex + + /** + * The initial item when this PageRow is created + */ + property variant initialPage + + /** + * The main flickable of this Row + */ + contentItem: mainView + + /** + * The default width for a column + * default is wide enough for 30 grid units. + * Pages can override it with their Layout.fillWidth, + * implicitWidth Layout.minimumWidth etc. + */ + property int defaultColumnWidth: Units.gridUnit * 20 + + /** + * interactive: bool + * If true it will be possible to go back/forward by dragging the + * content themselves with a gesture. + * Otherwise the only way to go back will be programmatically + * default: true + */ + property alias interactive: mainView.interactive + + /** + * wideMode: bool + * If true, the PageRow is wide enough that willshow more than one column at once + * @since 5.37 + */ + readonly property bool wideMode: root.width >= root.defaultColumnWidth*2 && pagesLogic.count >= 2 + + /** + * separatorVisible: bool + * True if the separator between pages should be visible + * default: true + * @since 5.38 + */ + property bool separatorVisible: true + + /** + * globalToolBar: grouped property + * Controls the appearance of an optional global toolbar for the whole PageRow. + * It's a grouped property comprised of the following properties: + * * style: (Kirigami.ApplicationHeaderStyle) can have the following values: + * ** Auto: depending on application formfactor, it can behave automatically like other values, such as a Breadcrumb on mobile and ToolBar on desktop + * ** Breadcrumb: it will show a breadcrumb of all the page titles in the stack, for easy navigation + * ** Titles: each page will only have its own tile on top + * ** TabBar: the global toolbar will look like a TabBar to select the pages + * ** ToolBar: each page will have the title on top together buttons and menus to represent all of the page actions: not available on Mobile systems. + * ** None: no global toolbar will be shown + * + * * actualStyle: this will represent the actual style of the toolbar: it can be different from style in the case style is Auto + * * showNavigationButtons: if true, forward and backward navigation buttons will be shown on the left of the toolbar + * * minimumHeight: (int) minimum height of the header, which will be resized when scrolling, only in Mobile mode (default: preferredHeight, sliding but no scaling) + property int preferredHeight: (int) the height the toolbar will usually have + property int maximumHeight: (int) The height the toolbar will have in mobile mode when the app is in reachable mode (default: preferredHeight * 1.5) + * * leftReservedSpace: (int, readonly) how many pixels are reserved at the left of the page toolBar (for navigation buttons or drawer handle) + property int rightReservedSpace: (int, readonly) how many pixels are reserved at the right of the page toolbar (drawer handle) + * @since 5.48 + */ + readonly property alias globalToolBar: globalToolBar +//END PROPERTIES + +//BEGIN FUNCTIONS + /** + * Pushes a page on the stack. + * The page can be defined as a component, item or string. + * If an item is used then the page will get re-parented. + * If a string is used then it is interpreted as a url that is used to load a page + * component. + * + * @param page The page can also be given as an array of pages. + * In this case all those pages will + * be pushed onto the stack. The items in the stack can be components, items or + * strings just like for single pages. + * Additionally an object can be used, which specifies a page and an optional + * properties property. + * This can be used to push multiple pages while still giving each of + * them properties. + * When an array is used the transition animation will only be to the last page. + * + * @param properties The properties argument is optional and allows defining a + * map of properties to set on the page. + * @return The new created page + */ + function push(page, properties) { + //don't push again things already there + if (page.createObject === undefined && typeof page != "string" && pagesLogic.containsPage(page)) { + print("The item " + page + " is already in the PageRow"); + return; + } + + if (popScrollAnim.running) { + popScrollAnim.running = false; + popScrollAnim.popPageCleanup(popScrollAnim.pendingPage); + } + + popScrollAnim.popPageCleanup(currentItem); + + // figure out if more than one page is being pushed + var pages; + if (page instanceof Array) { + pages = page; + page = pages.pop(); + if (page.createObject === undefined && page.parent === undefined && typeof page != "string") { + properties = properties || page.properties; + page = page.page; + } + } + + // push any extra defined pages onto the stack + if (pages) { + var i; + for (i = 0; i < pages.length; i++) { + var tPage = pages[i]; + var tProps; + if (tPage.createObject === undefined && tPage.parent === undefined && typeof tPage != "string") { + if (pagesLogic.containsPage(tPage)) { + print("The item " + page + " is already in the PageRow"); + continue; + } + tProps = tPage.properties; + tPage = tPage.page; + } + + var container = pagesLogic.initPage(tPage, tProps); + pagesLogic.append(container); + } + } + + // initialize the page + var container = pagesLogic.initPage(page, properties); + pagesLogic.append(container); + container.visible = container.page.visible = true; + + mainView.currentIndex = container.level; + pagePushed(container.page); + return container.page + } + + /** + * Pops a page off the stack. + * @param page If page is specified then the stack is unwound to that page, + * to unwind to the first page specify + * page as null. + * @return The page instance that was popped off the stack. + */ + function pop(page) { + if (depth == 0) { + return; + } + + //if a pop was animating, stop it + if (popScrollAnim.running) { + popScrollAnim.running = false; + popScrollAnim.popPageCleanup(popScrollAnim.pendingPage); + //if a push was animating, stop it + } else { + mainView.positionViewAtIndex(mainView.currentIndex, ListView.Beginning); + } + + popScrollAnim.from = mainView.contentX + + if ((!page || !page.parent) && pagesLogic.count > 1) { + page = pagesLogic.get(pagesLogic.count - 2).page; + } + popScrollAnim.to = page && page.parent ? page.parent.x : 0; + popScrollAnim.pendingPage = page; + popScrollAnim.pendingDepth = page && page.parent ? page.parent.level + 1 : 0; + + popScrollAnim.running = true; + } + + /** + * Emitted when a page has been pushed + * @param page the new page + * @since 2.5 + */ + signal pagePushed(Item page) + + /** + * Emitted when a page has been removed from the row. + * @param page the page that has been removed: at this point it's still valid, + * but may be auto deleted soon. + * @since 2.5 + */ + signal pageRemoved(Item page) + + SequentialAnimation { + id: popScrollAnim + property real from + property real to + property var pendingPage + property int pendingDepth: -1 + function popPageCleanup(page) { + if (pagesLogic.count == 0) { + return; + } + if (popScrollAnim.running) { + popScrollAnim.running = false; + } + + var oldPage = pagesLogic.get(pagesLogic.count-1).page; + if (page !== undefined) { + // an unwind target has been specified - pop until we find it + while (page !== oldPage && pagesLogic.count > 1) { + pagesLogic.removePage(oldPage.parent.level); + + oldPage = pagesLogic.get(pagesLogic.count-1).page; + } + } else { + pagesLogic.removePage(pagesLogic.count-1); + } + } + NumberAnimation { + target: mainView + properties: "contentX" + duration: Units.shortDuration + from: popScrollAnim.from + to: popScrollAnim.to + } + ScriptAction { + script: { + //snap + mainView.flick(100, 0) + popScrollAnim.popPageCleanup(popScrollAnim.pendingPage); + } + } + } + /** + * Replaces a page on the stack. + * @param page The page can also be given as an array of pages. + * In this case all those pages will + * be pushed onto the stack. The items in the stack can be components, items or + * strings just like for single pages. + * Additionally an object can be used, which specifies a page and an optional + * properties property. + * This can be used to push multiple pages while still giving each of + * them properties. + * When an array is used the transition animation will only be to the last page. + * @param properties The properties argument is optional and allows defining a + * map of properties to set on the page. + * @see push() for details. + */ + function replace(page, properties) { + if (currentIndex>=1) + popScrollAnim.popPageCleanup(pagesLogic.get(currentIndex-1).page); + else if (currentIndex==0) + popScrollAnim.popPageCleanup(); + else + console.warn("There's no page to replace"); + return push(page, properties); + } + + /** + * Clears the page stack. + * Destroy (or reparent) all the pages contained. + */ + function clear() { + return pagesLogic.clearPages(); + } + + /** + * @return the page at idx + * @param idx the depth of the page we want + */ + function get(idx) { + return pagesLogic.get(idx).page; + } + + /** + * go back to the previous index and scroll to the left to show one more column + */ + function flickBack() { + if (depth > 1) { + currentIndex = Math.max(0, currentIndex - 1); + } + + if (LayoutMirroring.enabled) { + if (!mainView.atEnd) { + mainViewScrollAnim.from = mainView.contentX + mainViewScrollAnim.to = Math.min(mainView.contentWidth - mainView.width, mainView.contentX + defaultColumnWidth) + mainViewScrollAnim.running = true; + } + } else { + if (mainView.contentX - mainView.originX > 0) { + mainViewScrollAnim.from = mainView.contentX + mainViewScrollAnim.to = Math.max(mainView.originX, mainView.contentX - defaultColumnWidth) + mainViewScrollAnim.running = true; + } + } + } + + /** + * layers: QtQuick.Controls.PageStack + * Access to the modal layers. + * Sometimes an application needs a modal page that always covers all the rows. + * For instance the full screen image of an image viewer or a settings page. + * @since 5.38 + */ + property alias layers: layersStack +//END FUNCTIONS + + onInitialPageChanged: { + clear(); + if (initialPage) { + push(initialPage, null) + } + } + + Keys.forwardTo: [currentItem] + + SequentialAnimation { + id: mainViewScrollAnim + property real from + property real to + NumberAnimation { + target: mainView + properties: "contentX" + duration: Units.longDuration + from: mainViewScrollAnim.from + to: mainViewScrollAnim.to + } + ScriptAction { + script: mainView.flick(100, 0) + } + } + + GlobalToolBar.PageRowGlobalToolBarStyleGroup { + id: globalToolBar + readonly property int leftReservedSpace: globalToolBarUI.item ? globalToolBarUI.item.leftReservedSpace : 0 + readonly property int rightReservedSpace: globalToolBarUI.item ? globalToolBarUI.item.rightReservedSpace : 0 + readonly property int height: globalToolBarUI.height + readonly property Item leftHandleAnchor: globalToolBarUI.item ? globalToolBarUI.item.leftHandleAnchor : null + readonly property Item rightHandleAnchor: globalToolBarUI.item ? globalToolBarUI.item.rightHandleAnchor : null + } + + QQC2.StackView { + id: layersStack + z: 99 + visible: depth > 1 || busy + anchors { + fill: parent + } + //placeholder as initial item + initialItem: Item {} + + function clear () { + //don't let it kill the main page row + var d = root.depth; + for (var i = 1; i < d; ++i) { + pop(); + } + } + + popEnter: Transition { + OpacityAnimator { + from: 0 + to: 1 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + } + popExit: Transition { + ParallelAnimation { + OpacityAnimator { + from: 1 + to: 0 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: 0 + to: height/2 + duration: Units.longDuration + easing.type: Easing.InCubic + } + } + } + + pushEnter: Transition { + ParallelAnimation { + //NOTE: It's a PropertyAnimation instead of an Animator because with an animator the item will be visible for an instant before starting to fade + PropertyAnimation { + property: "opacity" + from: 0 + to: 1 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: height/2 + to: 0 + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + } + + pushExit: Transition { + OpacityAnimator { + from: 1 + to: 0 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + } + + replaceEnter: Transition { + ParallelAnimation { + OpacityAnimator { + from: 0 + to: 1 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + YAnimator { + from: height/2 + to: 0 + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + } + + replaceExit: Transition { + ParallelAnimation { + OpacityAnimator { + from: 1 + to: 0 + duration: Units.longDuration + easing.type: Easing.InCubic + } + YAnimator { + from: 0 + to: -height/2 + duration: Units.longDuration + easing.type: Easing.InOutCubic + } + } + } + } + + Loader { + id: globalToolBarUI + anchors { + left: parent.left + top: parent.top + right: parent.right + } + z: 100 + active: globalToolBar.actualStyle != ApplicationHeaderStyle.None + visible: active + height: active ? implicitHeight : 0 + source: Qt.resolvedUrl("private/globaltoolbar/PageRowGlobalToolBarUI.qml"); + } + + ListView { + id: mainView + boundsBehavior: Flickable.StopAtBounds + orientation: Qt.Horizontal + snapMode: ListView.SnapToItem + currentIndex: 0 + property int marginForLast: count > 1 ? pagesLogic.get(count-1).page.width - pagesLogic.get(count-1).width : 0 + leftMargin: LayoutMirroring.enabled ? marginForLast : 0 + rightMargin: LayoutMirroring.enabled ? 0 : marginForLast + preferredHighlightBegin: 0 + preferredHighlightEnd: 0 + highlightMoveDuration: Units.longDuration + highlightFollowsCurrentItem: true + onMovementEnded: currentIndex = Math.max(0, indexAt(contentX, 0)) + onFlickEnded: onMovementEnded(); + onCurrentIndexChanged: { + if (currentItem) { + currentItem.page.forceActiveFocus(); + } + } + opacity: layersStack.depth < 2 + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + + + model: ObjectModel { + id: pagesLogic + readonly property var componentCache: new Array() + readonly property int roundedDefaultColumnWidth: root.width < root.defaultColumnWidth*2 ? root.width : root.defaultColumnWidth + + function removePage(id) { + if (id < 0 || id >= count) { + print("Tried to remove an invalid page index:" + id); + return; + } + + var item = pagesLogic.get(id); + if (item.owner) { + item.page.visible = false; + item.page.parent = item.owner; + } + //FIXME: why reparent ing is necessary? + //is destroy just an async deleteLater() that isn't executed immediately or it actually leaks? + pagesLogic.remove(id); + item.parent = root; + root.pageRemoved(item.page); + if (item.page.parent===item) { + item.page.destroy(1) + } + item.destroy(); + } + function clearPages () { + popScrollAnim.running = false; + popScrollAnim.pendingDepth = -1; + while (count > 0) { + removePage(count-1); + } + } + function initPage(page, properties) { + var container = containerComponent.createObject(mainView, { + "level": pagesLogic.count, + "page": page + }); + + var pageComp; + if (page.createObject) { + // page defined as component + pageComp = page; + } else if (typeof page == "string") { + // page defined as string (a url) + pageComp = pagesLogic.componentCache[page]; + if (!pageComp) { + pageComp = pagesLogic.componentCache[page] = Qt.createComponent(page); + } + } + if (pageComp) { + // instantiate page from component + page = pageComp.createObject(container.pageParent, properties || {}); + + if (pageComp.status === Component.Error) { + throw new Error("Error while loading page: " + pageComp.errorString()); + } + } else { + // copy properties to the page + for (var prop in properties) { + if (properties.hasOwnProperty(prop)) { + page[prop] = properties[prop]; + } + } + } + + container.page = page; + if (page.parent === null || page.parent === container.pageParent) { + container.owner = null; + } + + // the page has to be reparented + if (page.parent !== container) { + page.parent = container; + } + + return container; + } + function containsPage(page) { + for (var i = 0; i < pagesLogic.count; ++i) { + var candidate = pagesLogic.get(i); + if (candidate.page === page) { + print("The item " + page + " is already in the PageRow"); + return; + } + } + } + } + T.ScrollIndicator.horizontal: T.ScrollIndicator { + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + height: Units.smallSpacing + contentItem: Rectangle { + height: Units.smallSpacing + width: Units.smallSpacing + color: Theme.textColor + opacity: 0 + onXChanged: { + opacity = 0.3 + scrollIndicatorTimer.restart(); + } + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + Timer { + id: scrollIndicatorTimer + interval: Units.longDuration * 4 + onTriggered: parent.opacity = 0; + } + } + } + + onContentWidthChanged: mainView.positionViewAtIndex(root.currentIndex, ListView.Contain) + } + + Component { + id: containerComponent + + MouseArea { + id: container + height: mainView.height + width: root.width + state: page + ? (page.visible ? (!root.wideMode ? "vertical" : (container.level >= pagesLogic.count - 1 ? "last" : "middle")) : "hidden") + : ""; + acceptedButtons: Qt.LeftButton | Qt.BackButton | Qt.ForwardButton + + property int level + + readonly property int hint: page && page.implicitWidth ? page.implicitWidth : root.defaultColumnWidth + readonly property int roundedHint: Math.floor(root.width/hint) > 0 ? root.width/Math.floor(root.width/hint) : root.width + property T.Control __pageRow: root + + property Item footer + + property Item page + onPageChanged: { + if (page) { + owner = page.parent; + page.parent = container; + page.anchors.left = container.left; + page.anchors.top = container.top; + page.anchors.right = container.right; + page.anchors.bottom = container.bottom; + page.anchors.topMargin = Qt.binding(function() {return globalToolBar.actualStyle == ApplicationHeaderStyle.TabBar || globalToolBar.actualStyle == ApplicationHeaderStyle.Breadcrumb ? globalToolBarUI.height : 0}); + } else { + pagesLogic.remove(level); + } + } + property Item owner + drag.filterChildren: true + onPressed: { + switch (mouse.button) { + case Qt.BackButton: + root.flickBack(); + break; + case Qt.ForwardButton: + root.currentIndex = Math.min(root.depth, root.currentIndex + 1); + break; + default: + root.currentIndex = level; + break; + } + mouse.accepted = false; + } + onFocusChanged: { + if (focus) { + root.currentIndex = level; + } + } + + //TODO: move in Page itself? + Separator { + z: 999 + anchors { + top: page ? page.top : parent.top + bottom: parent.bottom + left: parent.left + //ensure a sharp angle + topMargin: -width + (globalToolBar.actualStyle == ApplicationHeaderStyle.ToolBar || globalToolBar.actualStyle == ApplicationHeaderStyle.Titles ? globalToolBarUI.height : 0) + } + visible: root.separatorVisible && mainView.contentX < container.x + } + states: [ + State { + name: "vertical" + PropertyChanges { + target: container + width: root.width + } + PropertyChanges { + target: container.page ? container.page.anchors : null + rightMargin: 0 + } + }, + State { + name: "last" + PropertyChanges { + target: container + width: pagesLogic.roundedDefaultColumnWidth + } + PropertyChanges { + target: container.page.anchors + rightMargin: { + return -(root.width - pagesLogic.roundedDefaultColumnWidth*2); + } + } + }, + State { + name: "middle" + PropertyChanges { + target: container + width: pagesLogic.roundedDefaultColumnWidth + } + PropertyChanges { + target: container.page.anchors + rightMargin: 0 + } + }, + State { + name: "hidden" + PropertyChanges { + target: container + width: 0 + } + } + ] + } + } +} diff --git a/src/controls/ScrollablePage.qml b/src/controls/ScrollablePage.qml new file mode 100644 index 0000000..5cd98ed --- /dev/null +++ b/src/controls/ScrollablePage.qml @@ -0,0 +1,186 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 +import "private" + +/** + * ScrollablePage is a container for all the app pages: everything pushed to the + * ApplicationWindow stackView should be a Page or ScrollablePage instabnce. + * This Page subclass is for content that has to be scrolled around, such as + * bigger content than the screen that would normally go in a Flickable + * or a ListView. + * Scrolling and scrolling indicators will be automatically managed + * + * + * @code + * ScrollablePage { + * id: root + * //The rectangle will automatically bescrollable + * Rectangle { + * width: root.width + * height: 99999 + * } + * } + * @endcode + * + * Another behavior added by this class is a "scroll down to refresh" behavior + * It also can give the contents of the flickable to have more top margins in order + * to make possible to scroll down the list to reach it with the thumb while using the + * phone with a single hand. + * + * Implementations should handle the refresh themselves as follows + * + * @code + * Kirigami.ScrollablePage { + * id: view + * supportsRefreshing: true + * onRefreshingChanged: { + * if (refreshing) { + * myModel.refresh(); + * } + * } + * ListView { + * //NOTE: MyModel doesn't come from the components, + * //it's purely an example on how it can be used together + * //some application logic that can update the list model + * //and signals when it's done. + * model: MyModel { + * onRefreshDone: view.refreshing = false; + * } + * delegate: BasicListItem {} + * } + * } + * [...] + * @endcode + * + */ +Page { + id: root + + /** + * refreshing: bool + * If true the list is asking for refresh and will show a loading spinner. + * it will automatically be set to true when the user pulls down enough the list. + * This signals the application logic to start its refresh procedure. + * The application itself will have to set back this property to false when done. + */ + property alias refreshing: scrollView.refreshing + + /** + * supportsRefreshing: bool + * If true the list supports the "pull down to refresh" behavior. + * default is false. + */ + property alias supportsRefreshing: scrollView.supportsRefreshing + + /** + * flickable: Flickable + * The main Flickable item of this page + */ + property alias flickable: scrollView.flickableItem + + /** + * verticalScrollBarPolicy: Qt.ScrollBarPolicy + * The vertical scrollbar policy + */ + property alias verticalScrollBarPolicy: scrollView.verticalScrollBarPolicy + + /** + * horizontalScrollBarPolicy: Qt.ScrollBarPolicy + * The horizontal scrollbar policy + */ + property alias horizontalScrollBarPolicy: scrollView.horizontalScrollBarPolicy + + /** + * The main content Item of this page. + * In the case of a ListView or GridView, both contentItem and flickable + * will be a pointer to the ListView (or GridView) + * NOTE: can't be contentItem as Page's contentItem is final + */ + default property QtObject mainItem + + /** + * keyboardNavigationEnabled: bool + * If true, and if flickable is an item view, like a ListView or + * a GridView, it will be possible to navigate the list current item + * to next and previous items with keyboard up/down arrow buttons. + * Also, any key event will be forwarded to the current list item. + * default is true. + */ + property bool keyboardNavigationEnabled: true + + Theme.colorSet: flickable && flickable.hasOwnProperty("model") ? Theme.View : Theme.Window + + clip: true + contentItem: RefreshableScrollView { + id: scrollView + //NOTE: here to not expose it to public api + property QtObject oldMainItem + page: root + clip: false + topPadding: contentItem == flickableItem ? 0 : root.topPadding + leftPadding: root.leftPadding + rightPadding: root.rightPadding + (root.flickable.ScrollBar.vertical && root.flickable.ScrollBar.vertical.visible ? root.flickable.ScrollBar.vertical.width : 0) + bottomPadding: contentItem == flickableItem ? 0 : root.bottomPadding + anchors { + top: root.header + ? root.header.bottom + //FIXME: for nowassuming globalToolBarItem is in a Loader, which needs to be got rid of + : (globalToolBarItem && globalToolBarItem.parent && globalToolBarItem.visible ? + globalToolBarItem.parent.bottom : parent.top) + bottom: root.footer ? root.footer.top : parent.bottom + left: parent.left + right: parent.right + } + } + + anchors.topMargin: 0 + + Keys.forwardTo: root.keyboardNavigationEnabled && root.flickable + ? (("currentItem" in root.flickable) && root.flickable.currentItem ? + [ root.flickable.currentItem, root.flickable ] : [ root.flickable ]) + : [] + + //HACK to get the mainItem as the last one, all the other eventual items as an overlay + //no idea if is the way the user expects + onMainItemChanged: { + if (mainItem.hasOwnProperty("anchors")) { + scrollView.contentItem = mainItem + //don't try to reparent drawers + } else if (mainItem.hasOwnProperty("dragMargin")) { + return; + //reparent sheets + } else if (mainItem.hasOwnProperty("sheetOpen")) { + if (mainItem.parent === root || mainItem.parent === null) { + mainItem.parent = root; + } + root.data.push(mainItem); + return; + } + + if (scrollView.oldMainItem && scrollView.oldMainItem.hasOwnProperty("parent") && scrollView.oldMainItem.parent !== applicationWindow().overlay) { + scrollView.oldMainItem.parent = overlay + } + scrollView.oldMainItem = mainItem + } +} diff --git a/src/controls/Separator.qml b/src/controls/Separator.qml new file mode 100644 index 0000000..0cfafcb --- /dev/null +++ b/src/controls/Separator.qml @@ -0,0 +1,39 @@ +/* + * Copyright 2012 Marco Martin + * Copyright 2016 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 + +/** + * A visual separator + * + * Useful for splitting one set of items from another. + * + * @inherit QtQuick.Rectangle + */ + +Rectangle { + height: Math.floor(Units.devicePixelRatio) + width: Math.floor(Units.devicePixelRatio) + Layout.preferredWidth: Math.floor(Units.devicePixelRatio) + Layout.preferredHeight: Math.floor(Units.devicePixelRatio) + color: Qt.tint(Theme.textColor, Qt.rgba(Theme.backgroundColor.r, Theme.backgroundColor.g, Theme.backgroundColor.b, 0.7)) +} diff --git a/src/controls/SwipeListItem.qml b/src/controls/SwipeListItem.qml new file mode 100644 index 0000000..8517800 --- /dev/null +++ b/src/controls/SwipeListItem.qml @@ -0,0 +1,56 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.5 +import "private" +import "templates" as T + +/** + * An item delegate Intended to support extra actions obtainable + * by uncovering them by dragging away the item with the handle + * This acts as a container for normal list items. + * Any subclass of AbstractListItem can be assigned as the contentItem property. + * @code + * ListView { + * model: myModel + * delegate: SwipeListItem { + * QQC2.Label { + * text: model.text + * } + * actions: [ + * Action { + * iconName: "document-decrypt" + * onTriggered: print("Action 1 clicked") + * }, + * Action { + * iconName: model.action2Icon + * onTriggered: //do something + * } + * ] + * } + * + * } + * @endcode + * + */ +T.SwipeListItem { + id: listItem + + background: DefaultListItemBackground {} +} diff --git a/src/controls/Theme.qml b/src/controls/Theme.qml new file mode 100644 index 0000000..8ef8054 --- /dev/null +++ b/src/controls/Theme.qml @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 + +pragma Singleton + +/** + * A set of named colors for the application + * @inherit QtQuick.QtObject + */ +QtObject { + id: theme + + property color textColor: "#31363b" + property color disabledTextColor: "#9931363b" + + property color highlightColor: "#2196F3" + property color highlightedTextColor: "#eff0fa" + property color backgroundColor: "#eff0f1" + property color activeTextColor: "#0176D3" + property color linkColor: "#2196F3" + property color visitedLinkColor: "#2196F3" + + property color negativeTextColor: "#DA4453" + property color neutralTextColor: "#F67400" + property color positiveTextColor: "#27AE60" + + property color buttonTextColor: "#31363b" + property color buttonBackgroundColor: "#eff0f1" + property color buttonHoverColor: "#2196F3" + property color buttonFocusColor: "#2196F3" + + property color viewTextColor: "#31363b" + property color viewBackgroundColor: "#fcfcfc" + property color viewHoverColor: "#2196F3" + property color viewFocusColor: "#2196F3" + + property color selectionTextColor: "#eff0fa" + property color selectionBackgroundColor: "#2196F3" + property color selectionHoverColor: "#2196F3" + property color selectionFocusColor: "#2196F3" + + property color tooltipTextColor: "#eff0f1" + property color tooltipBackgroundColor: "#31363b" + property color tooltipHoverColor: "#2196F3" + property color tooltipFocusColor: "#2196F3" + + property color complementaryTextColor: "#eff0f1" + property color complementaryBackgroundColor: "#31363b" + property color complementaryHoverColor: "#2196F3" + property color complementaryFocusColor: "#2196F3" + + property font defaultFont: fontMetrics.font + + property list children: [ + TextMetrics { + id: fontMetrics + } + ] + function __propagateColorSet(object, context) {} + function __propagateTextColor(object, color) {} + function __propagateBackgroundColor(object, color) {} + function __propagatePrimaryColor(object, color) {} + function __propagateAccentColor(object, color) {} +} diff --git a/src/controls/ToolBarApplicationHeader.qml b/src/controls/ToolBarApplicationHeader.qml new file mode 100644 index 0000000..13ca4a9 --- /dev/null +++ b/src/controls/ToolBarApplicationHeader.qml @@ -0,0 +1,134 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import "private" +import org.kde.kirigami 2.4 + + +/** + * This Application header represents a toolbar that + * will display the actions of the current page. + * Both Contextual actions and the main, left and right actions + */ +ApplicationHeader { + id: header + + preferredHeight: 42 + maximumHeight: preferredHeight + headerStyle: ApplicationHeaderStyle.Titles + + //FIXME: needs a property definition to have its own type in qml + property string _internal: "" + + Component.onCompleted: print("Warning: ToolbarApplicationHeader is deprecated, remove and use the automatic internal toolbar instead.") + pageDelegate: Item { + id: delegateItem + readonly property bool current: __appWindow.pageStack.currentIndex === index + implicitWidth: titleTextMetrics.width/2 + buttonTextMetrics.collapsedButtonsWidth + + RowLayout { + id: titleLayout + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + right: actionsLayout.left + } + Separator { + id: separator + Layout.preferredHeight: parent.height * 0.6 + } + + Heading { + id: title + Layout.fillWidth: true + + Layout.preferredWidth: implicitWidth + Layout.minimumWidth: Math.min(titleTextMetrics.width, delegateItem.width - buttonTextMetrics.requiredWidth) + leftPadding: Units.largeSpacing + opacity: delegateItem.current ? 1 : 0.4 + maximumLineCount: 1 + color: Theme.textColor + elide: Text.ElideRight + text: page ? page.title : "" + } + } + + TextMetrics { + id: titleTextMetrics + text: page ? page.title : "" + font: title.font + } + TextMetrics { + id: buttonTextMetrics + text: (page.actions.left ? page.actions.left.text : "") + (page.actions.main ? page.actions.main.text : "") + (page.actions.right ? page.actions.right.text : "") + readonly property int collapsedButtonsWidth: ctxActionsButton.width + (page.actions.left ? ctxActionsButton.width + Units.gridUnit : 0) + (page.actions.main ? ctxActionsButton.width + Units.gridUnit : 0) + (page.actions.right ? ctxActionsButton.width + Units.gridUnit : 0) + readonly property int requiredWidth: width + collapsedButtonsWidth + } + + RowLayout { + id: actionsLayout + anchors { + verticalCenter: parent.verticalCenter + right: ctxActionsButton.visible ? ctxActionsButton.left : parent.right + } + + readonly property bool toobig: delegateItem.width - titleTextMetrics.width - Units.gridUnit < buttonTextMetrics.requiredWidth + + PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + kirigamiAction: page && page.actions ? page.actions.left : null + showText: !parent.toobig + } + PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: Units.smallSpacing + kirigamiAction: page && page.actions ? page.actions.main : null + showText: !parent.toobig + flat: false + } + PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + kirigamiAction: page && page.actions ? page.actions.right : null + showText: !parent.toobig + } + } + + PrivateActionToolButton { + id: ctxActionsButton + showMenuArrow: page.actions.contextualActions.length === 1 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: Units.smallSpacing + } + Action { + id: overflowAction + icon.name: "overflow-menu" + tooltip: qsTr("More Actions") + visible: children.length > 0 + children: page && page.actions.contextualActions ? page.actions.contextualActions : null + } + + kirigamiAction: page && page.actions.contextualActions.length === 1 ? page.actions.contextualActions[0] : overflowAction + } + } +} diff --git a/src/controls/Units.qml b/src/controls/Units.qml new file mode 100644 index 0000000..ae83330 --- /dev/null +++ b/src/controls/Units.qml @@ -0,0 +1,136 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Window 2.2 +import org.kde.kirigami 2.4 + +pragma Singleton + +/** + * A set of values to define semantically sizes and durations + * @inherit QtQuick.QtObject + */ +QtObject { + id: units + + /** + * The fundamental unit of space that should be used for sizes, expressed in pixels. + * Given the screen has an accurate DPI settings, it corresponds to a width of + * the capital letter M + */ + property int gridUnit: fontMetrics.height + + /** + * units.iconSizes provides access to platform-dependent icon sizing + * + * The icon sizes provided are normalized for different DPI, so icons + * will scale depending on the DPI. + * + * Icon sizes from KIconLoader, adjusted to devicePixelRatio: + * * small + * * smallMedium + * * medium + * * large + * * huge + * * enormous + * + * Not devicePixelRation-adjusted:: + * * desktop + */ + property QtObject iconSizes: QtObject { + property int small: Math.floor(fontMetrics.roundedIconSize(16 * devicePixelRatio) * (Settings.isMobile ? 1.5 : 1)) + property int smallMedium: Math.floor(fontMetrics.roundedIconSize(22 * devicePixelRatio) * (Settings.isMobile ? 1.5 : 1)) + property int medium: Math.floor(fontMetrics.roundedIconSize(32 * devicePixelRatio) * (Settings.isMobile ? 1.5 : 1)) + property int large: Math.floor(fontMetrics.roundedIconSize(48 * devicePixelRatio) * (Settings.isMobile ? 1.5 : 1)) + property int huge: Math.floor(fontMetrics.roundedIconSize(64 * devicePixelRatio) * (Settings.isMobile ? 1.5 : 1)) + property int enormous: Math.floor(128 * devicePixelRatio * (Settings.isMobile ? 1.5 : 1)) + } + + /** + * units.smallSpacing is the amount of spacing that should be used around smaller UI elements, + * for example as spacing in Columns. Internally, this size depends on the size of + * the default font as rendered on the screen, so it takes user-configured font size and DPI + * into account. + */ + property int smallSpacing: Math.floor(gridUnit/4) + + /** + * units.largeSpacing is the amount of spacing that should be used inside bigger UI elements, + * for example between an icon and the corresponding text. Internally, this size depends on + * the size of the default font as rendered on the screen, so it takes user-configured font + * size and DPI into account. + */ + property int largeSpacing: smallSpacing*2 + + /** + * The ratio between physical and device-independent pixels. This value does not depend on the \ + * size of the configured font. If you want to take font sizes into account when scaling elements, + * use theme.mSize(theme.defaultFont), units.smallSpacing and units.largeSpacing. + * The devicePixelRatio follows the definition of "device independent pixel" by Microsoft. + */ + property real devicePixelRatio: Math.max(1, ((fontMetrics.font.pixelSize*0.75) / fontMetrics.font.pointSize)) + + /** + * units.longDuration should be used for longer, screen-covering animations, for opening and + * closing of dialogs and other "not too small" animations + */ + property int longDuration: 250 + + /** + * units.shortDuration should be used for short animations, such as accentuating a UI event, + * hover events, etc.. + */ + property int shortDuration: 150 + + /** + * time in ms by which the display of tooltips will be delayed. + * + * @sa ToolTip.delay property + */ + property int toolTipDelay: 700 + + /** + * How much the mouse scroll wheel scrolls, expressed in lines of text. + * Note: this is strictly for classical mouse wheels, touchpads 2 figer scrolling won't be affected + */ + readonly property int wheelScrollLines: 3 + + /** + * metrics used by the default font + */ + property variant fontMetrics: TextMetrics { + text: "M" + function roundedIconSize(size) { + if (size < 16) { + return size; + } else if (size < 22) { + return 16; + } else if (size < 32) { + return 22; + } else if (size < 48) { + return 32; + } else if (size < 64) { + return 48; + } else { + return size; + } + } + } +} diff --git a/src/controls/UrlButton.qml b/src/controls/UrlButton.qml new file mode 100644 index 0000000..25a8233 --- /dev/null +++ b/src/controls/UrlButton.qml @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library/Lesser General Public License + * version 2, or (at your option) any later version, as published by the + * Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library/Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 +import org.kde.kirigami 2.0 as Kirigami +import QtQuick.Controls 2.1 as QQC2 + +/** + * A link button that contains a URL + * + * It will open the url by default, allow to copy it if triggered with the + * secondary mouse button. + * + * @since 5.52 + * @since org.kde.kirigami 2.6 + */ +LinkButton +{ + id: button + property string url + text: url + visible: text.length > 0 + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onPressed: if (mouse.button === Qt.RightButton) { + menu.popup() + } + onClicked: if (mouse.button !== Qt.RightButton) { + Qt.openUrlExternally(url) + } + + QQC2.Menu { + id: menu + QQC2.MenuItem { + text: qsTr("Copy link address") + onClicked: app.copyTextToClipboard(button.url) + } + } +} diff --git a/src/controls/plugins.qmltypes b/src/controls/plugins.qmltypes new file mode 100644 index 0000000..2b7081a --- /dev/null +++ b/src/controls/plugins.qmltypes @@ -0,0 +1,2059 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -noinstantiate -notrelocatable org.kde.kirigami 2.5 /opt/kde5/qml' + +Module { + dependencies: [ + "QtGraphicalEffects 1.0", + "QtQml 2.1", + "QtQml.Models 2.2", + "QtQuick 2.9", + "QtQuick.Controls 2.4", + "QtQuick.Controls.Fusion 2.4", + "QtQuick.Controls.Fusion.impl 2.4", + "QtQuick.Controls.Imagine 2.4", + "QtQuick.Controls.Imagine.impl 2.4", + "QtQuick.Controls.Material 2.4", + "QtQuick.Controls.Material.impl 2.4", + "QtQuick.Controls.Styles 1.4", + "QtQuick.Controls.Styles.Plasma 2.0", + "QtQuick.Controls.Universal 2.4", + "QtQuick.Controls.Universal.impl 2.4", + "QtQuick.Controls.impl 2.4", + "QtQuick.Extras 1.4", + "QtQuick.Layouts 1.2", + "QtQuick.Templates 2.4", + "QtQuick.Window 2.3", + "org.kde.kconfig 1.0", + "org.kde.kquickcontrolsaddons 2.0", + "org.kde.plasma.components 2.0", + "org.kde.plasma.core 2.0", + "org.kde.plasma.extras 2.0" + ] + Component { + name: "ApplicationHeaderStyle" + prototype: "QObject" + exports: ["org.kde.kirigami/ApplicationHeaderStyle 2.0"] + isCreatable: false + exportMetaObjectRevisions: [0] + Enum { + name: "Status" + values: { + "Auto": 0, + "Breadcrumb": 1, + "Titles": 2, + "TabBar": 3, + "ToolBar": 4, + "None": 5 + } + } + } + Component { + name: "DelegateRecycler" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["org.kde.kirigami/DelegateRecycler 2.4"] + exportMetaObjectRevisions: [0] + Property { name: "sourceComponent"; type: "QQmlComponent"; isPointer: true } + } + Component { + name: "DesktopIcon" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["org.kde.kirigami/Icon 2.0"] + exportMetaObjectRevisions: [0] + Property { name: "source"; type: "QVariant" } + Property { name: "smooth"; type: "bool" } + Property { name: "implicitWidth"; type: "int"; isReadonly: true } + Property { name: "implicitHeight"; type: "int"; isReadonly: true } + Property { name: "enabled"; type: "bool" } + Property { name: "active"; type: "bool" } + Property { name: "valid"; type: "bool"; isReadonly: true } + Property { name: "selected"; type: "bool" } + Property { name: "isMask"; type: "bool" } + Property { name: "color"; type: "QColor" } + } + Component { + name: "FormLayoutAttached" + prototype: "QObject" + exports: ["org.kde.kirigami/FormData 2.3"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "label"; type: "string" } + Property { name: "isSection"; type: "bool" } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Property { name: "buddyFor"; type: "QQuickItem"; isPointer: true } + } + Component { + name: "Kirigami::PlatformTheme" + prototype: "QObject" + exports: ["org.kde.kirigami/Theme 2.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Enum { + name: "ColorSet" + values: { + "View": 0, + "Window": 1, + "Button": 2, + "Selection": 3, + "Tooltip": 4, + "Complementary": 5 + } + } + Enum { + name: "ColorGroup" + values: { + "Disabled": 1, + "Active": 0, + "Inactive": 2, + "Normal": 0 + } + } + Property { name: "colorSet"; type: "ColorSet" } + Property { name: "colorGroup"; type: "ColorGroup" } + Property { name: "inherit"; type: "bool" } + Property { name: "textColor"; type: "QColor" } + Property { name: "disabledTextColor"; type: "QColor" } + Property { name: "highlightedTextColor"; type: "QColor" } + Property { name: "activeTextColor"; type: "QColor" } + Property { name: "linkColor"; type: "QColor" } + Property { name: "visitedLinkColor"; type: "QColor" } + Property { name: "negativeTextColor"; type: "QColor" } + Property { name: "neutralTextColor"; type: "QColor" } + Property { name: "positiveTextColor"; type: "QColor" } + Property { name: "backgroundColor"; type: "QColor" } + Property { name: "highlightColor"; type: "QColor" } + Property { name: "focusColor"; type: "QColor" } + Property { name: "hoverColor"; type: "QColor" } + Property { name: "defaultFont"; type: "QFont"; isReadonly: true } + Property { name: "palette"; type: "QPalette"; isReadonly: true } + Signal { name: "colorsChanged" } + Signal { + name: "defaultFontChanged" + Parameter { name: "font"; type: "QFont" } + } + Signal { + name: "colorSetChanged" + Parameter { name: "colorSet"; type: "Kirigami::PlatformTheme::ColorSet" } + } + Signal { + name: "colorGroupChanged" + Parameter { name: "colorGroup"; type: "Kirigami::PlatformTheme::ColorGroup" } + } + Signal { + name: "paletteChanged" + Parameter { name: "pal"; type: "QPalette" } + } + Signal { + name: "inheritChanged" + Parameter { name: "inherit"; type: "bool" } + } + Method { + name: "iconFromTheme" + type: "QIcon" + Parameter { name: "name"; type: "string" } + Parameter { name: "customColor"; type: "QColor" } + } + Method { + name: "iconFromTheme" + type: "QIcon" + Parameter { name: "name"; type: "string" } + } + } + Component { + name: "MessageType" + prototype: "QObject" + exports: ["org.kde.kirigami/MessageType 2.4"] + isCreatable: false + exportMetaObjectRevisions: [0] + Enum { + name: "Type" + values: { + "Information": 0, + "Positive": 1, + "Warning": 2, + "Error": 3 + } + } + } + Component { + name: "MnemonicAttached" + prototype: "QObject" + exports: ["org.kde.kirigami/MnemonicData 2.3"] + isCreatable: false + exportMetaObjectRevisions: [0] + Enum { + name: "ControlType" + values: { + "ActionElement": 0, + "DialogButton": 1, + "MenuItem": 2, + "FormLabel": 3, + "SecondaryControl": 4 + } + } + Property { name: "label"; type: "string" } + Property { name: "richTextLabel"; type: "string"; isReadonly: true } + Property { name: "mnemonicLabel"; type: "string"; isReadonly: true } + Property { name: "enabled"; type: "bool" } + Property { name: "controlType"; type: "MnemonicAttached::ControlType" } + Property { name: "sequence"; type: "QKeySequence"; isReadonly: true } + } + Component { + name: "ScenePositionAttached" + prototype: "QObject" + exports: ["org.kde.kirigami/ScenePosition 2.5"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "x"; type: "int"; isReadonly: true } + Property { name: "y"; type: "int"; isReadonly: true } + } + Component { + name: "Settings" + prototype: "QObject" + exports: ["org.kde.kirigami/Settings 2.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [0] + Property { name: "tabletModeAvailable"; type: "bool"; isReadonly: true } + Property { name: "isMobile"; type: "bool"; isReadonly: true } + Property { name: "tabletMode"; type: "bool"; isReadonly: true } + Property { name: "style"; type: "string"; isReadonly: true } + Property { name: "mouseWheelScrollLines"; type: "int"; isReadonly: true } + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/AbstractApplicationHeader 2.0" + exports: ["org.kde.kirigami/AbstractApplicationHeader 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentItem" + Property { name: "minimumHeight"; type: "int" } + Property { name: "preferredHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "pageRow"; type: "PageRow_QMLTYPE_5"; isPointer: true } + Property { name: "page"; type: "Page_QMLTYPE_14"; isPointer: true } + Property { name: "paintedHeight"; type: "int"; isReadonly: true } + Property { name: "leftPadding"; type: "int" } + Property { name: "topPadding"; type: "int" } + Property { name: "rightPadding"; type: "int" } + Property { name: "bottomPadding"; type: "int" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "__appWindow"; type: "QObject"; isPointer: true } + Property { name: "background"; type: "QQuickItem"; isPointer: true } + Property { name: "contentItem"; type: "QObject"; isList: true; isReadonly: true } + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/AbstractApplicationItem 2.1" + exports: ["org.kde.kirigami/AbstractApplicationItem 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "__data" + Property { name: "pageStack"; type: "QQuickItem"; isPointer: true } + Property { name: "activeFocusItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "header"; type: "QQuickItem"; isPointer: true } + Property { name: "footer"; type: "QQuickItem"; isPointer: true } + Property { name: "controlsVisible"; type: "bool" } + Property { name: "globalDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "wideScreen"; type: "bool" } + Property { name: "contextDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "reachableMode"; type: "bool" } + Property { name: "reachableModeEnabled"; type: "bool" } + Property { name: "contentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "overlay"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "__data"; type: "QObject"; isList: true; isReadonly: true } + Method { + name: "showPassiveNotification" + type: "QVariant" + Parameter { name: "message"; type: "QVariant" } + Parameter { name: "timeout"; type: "QVariant" } + Parameter { name: "actionText"; type: "QVariant" } + Parameter { name: "callBack"; type: "QVariant" } + } + Method { name: "hidePassiveNotification"; type: "QVariant" } + Method { name: "applicationWindow"; type: "QVariant" } + } + Component { + prototype: "QQuickApplicationWindow" + name: "org.kde.kirigami/AbstractApplicationWindow 2.0" + exports: ["org.kde.kirigami/AbstractApplicationWindow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + Property { name: "pageStack"; type: "QQuickItem"; isPointer: true } + Property { name: "controlsVisible"; type: "bool" } + Property { name: "globalDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "wideScreen"; type: "bool" } + Property { name: "contextDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "reachableMode"; type: "bool" } + Property { name: "reachableModeEnabled"; type: "bool" } + Method { + name: "showPassiveNotification" + type: "QVariant" + Parameter { name: "message"; type: "QVariant" } + Parameter { name: "timeout"; type: "QVariant" } + Parameter { name: "actionText"; type: "QVariant" } + Parameter { name: "callBack"; type: "QVariant" } + } + Method { name: "hidePassiveNotification"; type: "QVariant" } + Method { name: "applicationWindow"; type: "QVariant" } + } + Component { + prototype: "QQuickAbstractButton" + name: "QtQuick.Controls/AbstractButton 2.0" + exports: ["QtQuick.Controls/AbstractButton 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickItemDelegate" + name: "org.kde.kirigami/AbstractCard 2.4" + exports: ["org.kde.kirigami/AbstractCard 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "data" + Property { name: "header"; type: "QQuickItem"; isPointer: true } + Property { name: "headerOrientation"; type: "int" } + Property { name: "footer"; type: "QQuickItem"; isPointer: true } + Property { name: "showClickFeedback"; type: "bool" } + } + Component { + prototype: "QQuickControl" + name: "org.kde.kirigami/AbstractItemViewHeader 2.1" + exports: ["org.kde.kirigami/AbstractItemViewHeader 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + Property { name: "minimumHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "view"; type: "QQuickListView"; isPointer: true } + } + Component { + prototype: "QQuickItemDelegate" + name: "org.kde.kirigami/AbstractListItem 2.0" + exports: ["org.kde.kirigami/AbstractListItem 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "_default" + Property { name: "supportsMouseEvents"; type: "bool" } + Property { name: "sectionDelegate"; type: "bool" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "textColor"; type: "QColor" } + Property { name: "backgroundColor"; type: "QColor" } + Property { name: "activeTextColor"; type: "QColor" } + Property { name: "activeBackgroundColor"; type: "QColor" } + Property { name: "containsMouse"; type: "bool"; isReadonly: true } + Property { name: "_default"; type: "QQuickItem"; isPointer: true } + } + Component { + prototype: "QObject" + name: "org.kde.kirigami/Action 2.0" + exports: ["org.kde.kirigami/Action 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "children" + Property { name: "visible"; type: "bool" } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Property { name: "icon"; type: "ActionIconGroup_QMLTYPE_52"; isPointer: true } + Property { name: "text"; type: "string" } + Property { name: "tooltip"; type: "string" } + Property { name: "__children"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "__shortcut"; type: "QQuickShortcut"; isPointer: true } + Property { name: "iconName"; type: "string" } + Property { name: "iconSource"; type: "string" } + Property { name: "shortcut"; type: "QVariant" } + Property { name: "children"; type: "QObject"; isList: true; isReadonly: true } + Signal { + name: "toggled" + Parameter { name: "checked"; type: "bool" } + } + Signal { + name: "triggered" + Parameter { name: "source"; type: "QObject"; isPointer: true } + } + Method { + name: "trigger" + type: "QVariant" + Parameter { name: "source"; type: "QVariant" } + } + } + Component { + prototype: "QQuickAction" + name: "QtQuick.Controls/Action 2.3" + exports: ["QtQuick.Controls/Action 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + } + Component { + prototype: "QQuickActionGroup" + name: "QtQuick.Controls/ActionGroup 2.3" + exports: ["QtQuick.Controls/ActionGroup 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "actions" + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/ActionToolBar 2.5" + exports: ["org.kde.kirigami/ActionToolBar 2.5"] + exportMetaObjectRevisions: [5] + isComposite: true + defaultProperty: "data" + Property { name: "actions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "hiddenActions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "flat"; type: "bool" } + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/ApplicationHeader 2.0" + exports: ["org.kde.kirigami/ApplicationHeader 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentItem" + Property { name: "headerStyle"; type: "int" } + Property { name: "backButtonEnabled"; type: "bool" } + Property { name: "pageDelegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "minimumHeight"; type: "int" } + Property { name: "preferredHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "pageRow"; type: "PageRow_QMLTYPE_5"; isPointer: true } + Property { name: "page"; type: "Page_QMLTYPE_14"; isPointer: true } + Property { name: "paintedHeight"; type: "int"; isReadonly: true } + Property { name: "leftPadding"; type: "int" } + Property { name: "topPadding"; type: "int" } + Property { name: "rightPadding"; type: "int" } + Property { name: "bottomPadding"; type: "int" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "__appWindow"; type: "QObject"; isPointer: true } + Property { name: "background"; type: "QQuickItem"; isPointer: true } + Property { name: "contentItem"; type: "QObject"; isList: true; isReadonly: true } + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/ApplicationItem 2.1" + exports: ["org.kde.kirigami/ApplicationItem 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "__data" + Property { name: "pageStack"; type: "PageRow_QMLTYPE_5"; isReadonly: true; isPointer: true } + Property { name: "activeFocusItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "header"; type: "QQuickItem"; isPointer: true } + Property { name: "footer"; type: "QQuickItem"; isPointer: true } + Property { name: "controlsVisible"; type: "bool" } + Property { name: "globalDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "wideScreen"; type: "bool" } + Property { name: "contextDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "reachableMode"; type: "bool" } + Property { name: "reachableModeEnabled"; type: "bool" } + Property { name: "contentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "overlay"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "__data"; type: "QObject"; isList: true; isReadonly: true } + Method { + name: "showPassiveNotification" + type: "QVariant" + Parameter { name: "message"; type: "QVariant" } + Parameter { name: "timeout"; type: "QVariant" } + Parameter { name: "actionText"; type: "QVariant" } + Parameter { name: "callBack"; type: "QVariant" } + } + Method { name: "hidePassiveNotification"; type: "QVariant" } + Method { name: "applicationWindow"; type: "QVariant" } + } + Component { + prototype: "QQuickApplicationWindow" + name: "QtQuick.Controls/ApplicationWindow 2.0" + exports: ["QtQuick.Controls/ApplicationWindow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickApplicationWindow" + name: "org.kde.kirigami/ApplicationWindow 2.0" + exports: ["org.kde.kirigami/ApplicationWindow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + Property { name: "pageStack"; type: "PageRow_QMLTYPE_5"; isReadonly: true; isPointer: true } + Property { name: "controlsVisible"; type: "bool" } + Property { name: "globalDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "wideScreen"; type: "bool" } + Property { name: "contextDrawer"; type: "OverlayDrawer_QMLTYPE_23"; isPointer: true } + Property { name: "reachableMode"; type: "bool" } + Property { name: "reachableModeEnabled"; type: "bool" } + Method { + name: "showPassiveNotification" + type: "QVariant" + Parameter { name: "message"; type: "QVariant" } + Parameter { name: "timeout"; type: "QVariant" } + Parameter { name: "actionText"; type: "QVariant" } + Parameter { name: "callBack"; type: "QVariant" } + } + Method { name: "hidePassiveNotification"; type: "QVariant" } + Method { name: "applicationWindow"; type: "QVariant" } + } + Component { + prototype: "QQuickItemDelegate" + name: "org.kde.kirigami/BasicListItem 2.0" + exports: ["org.kde.kirigami/BasicListItem 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "_basicDefault" + Property { name: "icon"; type: "QVariant" } + Property { name: "label"; type: "string" } + Property { name: "reserveSpaceForIcon"; type: "bool" } + Property { name: "_basicDefault"; type: "QQuickItem"; isList: true; isReadonly: true } + Property { name: "supportsMouseEvents"; type: "bool" } + Property { name: "sectionDelegate"; type: "bool" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "textColor"; type: "QColor" } + Property { name: "backgroundColor"; type: "QColor" } + Property { name: "activeTextColor"; type: "QColor" } + Property { name: "activeBackgroundColor"; type: "QColor" } + Property { name: "containsMouse"; type: "bool"; isReadonly: true } + Property { name: "_default"; type: "QQuickItem"; isPointer: true } + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Material.impl/BoxShadow 2.0" + exports: ["QtQuick.Controls.Material.impl/BoxShadow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "offsetX"; type: "int" } + Property { name: "offsetY"; type: "int" } + Property { name: "blurRadius"; type: "int" } + Property { name: "spreadRadius"; type: "int" } + Property { name: "source"; type: "QQuickItem"; isPointer: true } + Property { name: "fullWidth"; type: "bool" } + Property { name: "fullHeight"; type: "bool" } + Property { name: "glowRadius"; type: "double" } + Property { name: "spread"; type: "double" } + Property { name: "color"; type: "QColor" } + Property { name: "cornerRadius"; type: "double" } + Property { name: "cached"; type: "bool" } + } + Component { + prototype: "QQuickBusyIndicator" + name: "QtQuick.Controls/BusyIndicator 2.0" + exports: ["QtQuick.Controls/BusyIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickButton" + name: "QtQuick.Controls/Button 2.0" + exports: ["QtQuick.Controls/Button 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickButtonGroup" + name: "QtQuick.Controls/ButtonGroup 2.0" + exports: ["QtQuick.Controls/ButtonGroup 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/ButtonPanel 2.3" + exports: ["QtQuick.Controls.Fusion.impl/ButtonPanel 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "highlighted"; type: "bool" } + } + Component { + prototype: "QQuickItemDelegate" + name: "org.kde.kirigami/Card 2.4" + exports: ["org.kde.kirigami/Card 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "data" + Property { name: "actions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "hiddenActions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "banner"; type: "BannerImage_QMLTYPE_85"; isReadonly: true; isPointer: true } + Property { name: "header"; type: "QQuickItem"; isPointer: true } + Property { name: "headerOrientation"; type: "int" } + Property { name: "footer"; type: "QQuickItem"; isPointer: true } + Property { name: "showClickFeedback"; type: "bool" } + } + Component { + prototype: "QQuickGridView" + name: "org.kde.kirigami/CardsGridView 2.4" + exports: ["org.kde.kirigami/CardsGridView 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "delegate" + Property { name: "columns"; type: "int"; isReadonly: true } + Property { name: "maximumColumns"; type: "int" } + Property { name: "maximumColumnWidth"; type: "int" } + Property { name: "minimumColumnWidth"; type: "int" } + Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "_delegateComponent"; type: "QQmlComponent"; isPointer: true } + } + Component { + prototype: "QQuickGridLayout" + name: "org.kde.kirigami/CardsLayout 2.4" + exports: ["org.kde.kirigami/CardsLayout 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "data" + Property { name: "maximumColumns"; type: "int" } + Property { name: "maximumColumnWidth"; type: "int" } + Property { name: "minimumColumnWidth"; type: "int" } + } + Component { + prototype: "QQuickListView" + name: "org.kde.kirigami/CardsListView 2.4" + exports: ["org.kde.kirigami/CardsListView 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "data" + Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "_delegateComponent"; type: "QQmlComponent"; isPointer: true } + } + Component { + prototype: "QQuickCheckBox" + name: "QtQuick.Controls/CheckBox 2.0" + exports: ["QtQuick.Controls/CheckBox 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickCheckDelegate" + name: "QtQuick.Controls/CheckDelegate 2.0" + exports: ["QtQuick.Controls/CheckDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Material.impl/CheckIndicator 2.0" + exports: ["QtQuick.Controls.Material.impl/CheckIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "checkState"; type: "int" } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/CheckIndicator 2.3" + exports: ["QtQuick.Controls.Fusion.impl/CheckIndicator 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "pressedColor"; type: "QColor"; isReadonly: true } + Property { name: "checkMarkColor"; type: "QColor"; isReadonly: true } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Universal.impl/CheckIndicator 2.0" + exports: ["QtQuick.Controls.Universal.impl/CheckIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "partiallyChecked"; type: "bool"; isReadonly: true } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras.Private/CircularButton 1.0" + exports: ["QtQuick.Extras.Private/CircularButton 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "isDefault"; type: "bool" } + Property { name: "menu"; type: "Menu_QMLTYPE_126"; isPointer: true } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "exclusiveGroup"; type: "QQuickExclusiveGroup1"; isPointer: true } + Property { name: "action"; type: "QQuickAction1"; isPointer: true } + Property { name: "activeFocusOnPress"; type: "bool" } + Property { name: "text"; type: "string" } + Property { name: "tooltip"; type: "string" } + Property { name: "iconSource"; type: "QUrl" } + Property { name: "iconName"; type: "string" } + Property { name: "__position"; type: "string" } + Property { name: "__iconOverriden"; type: "bool"; isReadonly: true } + Property { name: "__action"; type: "QQuickAction1"; isPointer: true } + Property { name: "__iconAction"; type: "QQuickAction1"; isReadonly: true; isPointer: true } + Property { name: "__behavior"; type: "QVariant" } + Property { name: "__effectivePressed"; type: "bool" } + Property { name: "pressed"; type: "bool"; isReadonly: true } + Property { name: "hovered"; type: "bool"; isReadonly: true } + Signal { name: "clicked" } + Method { name: "accessiblePressAction"; type: "QVariant" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QObject" + name: "QtQuick.Extras.Private/CircularButtonStyleHelper 1.0" + exports: ["QtQuick.Extras.Private/CircularButtonStyleHelper 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "buttonColorUpTop"; type: "QColor" } + Property { name: "buttonColorUpBottom"; type: "QColor" } + Property { name: "buttonColorDownTop"; type: "QColor" } + Property { name: "buttonColorDownBottom"; type: "QColor" } + Property { name: "outerArcColorTop"; type: "QColor" } + Property { name: "outerArcColorBottom"; type: "QColor" } + Property { name: "innerArcColorTop"; type: "QColor" } + Property { name: "innerArcColorBottom"; type: "QColor" } + Property { name: "innerArcColorBottomStop"; type: "double" } + Property { name: "shineColor"; type: "QColor" } + Property { name: "smallestAxis"; type: "double" } + Property { name: "outerArcLineWidth"; type: "double" } + Property { name: "innerArcLineWidth"; type: "double" } + Property { name: "shineArcLineWidth"; type: "double" } + Property { name: "implicitWidth"; type: "double" } + Property { name: "implicitHeight"; type: "double" } + Property { name: "textColorUp"; type: "QColor" } + Property { name: "textColorDown"; type: "QColor" } + Property { name: "textRaisedColorUp"; type: "QColor" } + Property { name: "textRaisedColorDown"; type: "QColor" } + Property { name: "radius"; type: "double" } + Property { name: "halfRadius"; type: "double" } + Property { name: "outerArcRadius"; type: "double" } + Property { name: "innerArcRadius"; type: "double" } + Property { name: "shineArcRadius"; type: "double" } + Property { name: "zeroAngle"; type: "double" } + Property { name: "buttonColorTop"; type: "QColor" } + Property { name: "buttonColorBottom"; type: "QColor" } + Method { + name: "toPixels" + type: "QVariant" + Parameter { name: "percentageOfSmallestAxis"; type: "QVariant" } + } + Method { + name: "paintBackground" + type: "QVariant" + Parameter { name: "ctx"; type: "QVariant" } + } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/CircularGauge 1.0" + exports: ["QtQuick.Extras/CircularGauge 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "tickmarksVisible"; type: "bool" } + Property { name: "minimumValue"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "value"; type: "double" } + Property { name: "stepSize"; type: "double" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras.Private/CircularTickmarkLabel 1.0" + exports: ["QtQuick.Extras.Private/CircularTickmarkLabel 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "minimumValueAngle"; type: "double" } + Property { name: "maximumValueAngle"; type: "double" } + Property { name: "angleRange"; type: "double"; isReadonly: true } + Property { name: "tickmarkStepSize"; type: "double" } + Property { name: "tickmarkInset"; type: "double" } + Property { name: "tickmarkCount"; type: "int"; isReadonly: true } + Property { name: "minorTickmarkCount"; type: "int" } + Property { name: "minorTickmarkInset"; type: "double" } + Property { name: "labelInset"; type: "double" } + Property { name: "labelStepSize"; type: "double" } + Property { name: "labelCount"; type: "int"; isReadonly: true } + Property { name: "__tickmarkCount"; type: "double"; isReadonly: true } + Property { name: "tickmarksVisible"; type: "bool" } + Property { name: "minimumValue"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "stepSize"; type: "double" } + Method { + name: "valueToAngle" + type: "QVariant" + Parameter { name: "value"; type: "QVariant" } + } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickComboBox" + name: "QtQuick.Controls/ComboBox 2.0" + exports: ["QtQuick.Controls/ComboBox 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickContainer" + name: "QtQuick.Controls/Container 2.0" + exports: ["QtQuick.Controls/Container 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickDrawer" + name: "org.kde.kirigami/ContextDrawer 2.0" + exports: ["org.kde.kirigami/ContextDrawer 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + Property { name: "title"; type: "string" } + Property { name: "actions"; type: "QVariant" } + Property { name: "drawerOpen"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Property { name: "peeking"; type: "bool" } + Property { name: "animating"; type: "bool"; isReadonly: true } + Property { name: "collapsible"; type: "bool" } + Property { name: "collapsed"; type: "bool" } + Property { name: "collapsedSize"; type: "int" } + Property { name: "handleOpenIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleClosedIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleVisible"; type: "bool" } + Property { name: "handle"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "__internal"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickControl" + name: "QtQuick.Controls/Control 2.0" + exports: ["QtQuick.Controls/Control 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Material.impl/CursorDelegate 2.0" + exports: ["QtQuick.Controls.Material.impl/CursorDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/DelayButton 1.0" + exports: ["QtQuick.Extras/DelayButton 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "delay"; type: "int" } + Property { name: "__progress"; type: "double" } + Property { name: "progress"; type: "double"; isReadonly: true } + Signal { name: "activated" } + Property { name: "isDefault"; type: "bool" } + Property { name: "menu"; type: "Menu_QMLTYPE_126"; isPointer: true } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "exclusiveGroup"; type: "QQuickExclusiveGroup1"; isPointer: true } + Property { name: "action"; type: "QQuickAction1"; isPointer: true } + Property { name: "activeFocusOnPress"; type: "bool" } + Property { name: "text"; type: "string" } + Property { name: "tooltip"; type: "string" } + Property { name: "iconSource"; type: "QUrl" } + Property { name: "iconName"; type: "string" } + Property { name: "__position"; type: "string" } + Property { name: "__iconOverriden"; type: "bool"; isReadonly: true } + Property { name: "__action"; type: "QQuickAction1"; isPointer: true } + Property { name: "__iconAction"; type: "QQuickAction1"; isReadonly: true; isPointer: true } + Property { name: "__behavior"; type: "QVariant" } + Property { name: "__effectivePressed"; type: "bool" } + Property { name: "pressed"; type: "bool"; isReadonly: true } + Property { name: "hovered"; type: "bool"; isReadonly: true } + Signal { name: "clicked" } + Method { name: "accessiblePressAction"; type: "QVariant" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickDelayButton" + name: "QtQuick.Controls/DelayButton 2.2" + exports: ["QtQuick.Controls/DelayButton 2.2"] + exportMetaObjectRevisions: [2] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/Dial 1.1" + exports: ["QtQuick.Extras/Dial 1.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + Property { name: "__wrap"; type: "bool" } + Property { name: "activeFocusOnPress"; type: "bool" } + Property { name: "tickmarksVisible"; type: "bool" } + Property { name: "value"; type: "double" } + Property { name: "minimumValue"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "hovered"; type: "bool"; isReadonly: true } + Property { name: "stepSize"; type: "double" } + Property { name: "pressed"; type: "bool"; isReadonly: true } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/Dial 1.0" + exports: ["QtQuick.Extras/Dial 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "__wrap"; type: "bool" } + Property { name: "activeFocusOnPress"; type: "bool" } + Property { name: "tickmarksVisible"; type: "bool" } + Property { name: "value"; type: "double" } + Property { name: "minimumValue"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "hovered"; type: "bool"; isReadonly: true } + Property { name: "stepSize"; type: "double" } + Property { name: "pressed"; type: "bool"; isReadonly: true } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickDial" + name: "QtQuick.Controls/Dial 2.0" + exports: ["QtQuick.Controls/Dial 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickDialog" + name: "QtQuick.Controls/Dialog 2.1" + exports: ["QtQuick.Controls/Dialog 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickDialogButtonBox" + name: "QtQuick.Controls/DialogButtonBox 2.1" + exports: ["QtQuick.Controls/DialogButtonBox 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickDrawer" + name: "QtQuick.Controls/Drawer 2.0" + exports: ["QtQuick.Controls/Drawer 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Material.impl/ElevationEffect 2.0" + exports: ["QtQuick.Controls.Material.impl/ElevationEffect 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "source"; type: "QVariant" } + Property { name: "elevation"; type: "int" } + Property { name: "fullWidth"; type: "bool" } + Property { name: "fullHeight"; type: "bool" } + Property { name: "sourceItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "_shadows"; type: "QVariant"; isReadonly: true } + Property { name: "_shadow"; type: "QVariant"; isReadonly: true } + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/FormLayout 2.3" + exports: ["org.kde.kirigami/FormLayout 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "wideMode"; type: "bool" } + } + Component { + prototype: "QQuickFrame" + name: "QtQuick.Controls/Frame 2.0" + exports: ["QtQuick.Controls/Frame 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/Gauge 1.0" + exports: ["QtQuick.Extras/Gauge 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "orientation"; type: "int" } + Property { name: "tickmarkAlignment"; type: "int" } + Property { name: "__tickmarkAlignment"; type: "int" } + Property { name: "__tickmarksInside"; type: "bool" } + Property { name: "tickmarkStepSize"; type: "double" } + Property { name: "minorTickmarkCount"; type: "int" } + Property { name: "formatValue"; type: "QVariant" } + Property { name: "minimumValue"; type: "double" } + Property { name: "value"; type: "double" } + Property { name: "maximumValue"; type: "double" } + Property { name: "font"; type: "QFont" } + Property { name: "__hiddenText"; type: "QQuickText"; isReadonly: true; isPointer: true } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickDrawer" + name: "org.kde.kirigami/GlobalDrawer 2.0" + exports: ["org.kde.kirigami/GlobalDrawer 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "content" + Property { name: "actions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "showContentWhenCollapsed"; type: "bool" } + Property { name: "showTopContentWhenCollapsed"; type: "bool" } + Property { name: "resetMenuOnTriggered"; type: "bool" } + Property { name: "currentSubMenu"; type: "Action_QMLTYPE_53"; isReadonly: true; isPointer: true } + Property { name: "title"; type: "string" } + Property { name: "titleIcon"; type: "QVariant" } + Property { name: "bannerImageSource"; type: "QUrl" } + Property { name: "content"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "topContent"; type: "QObject"; isList: true; isReadonly: true } + Signal { name: "bannerClicked" } + Method { name: "resetMenu"; type: "QVariant" } + Property { name: "drawerOpen"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Property { name: "peeking"; type: "bool" } + Property { name: "animating"; type: "bool"; isReadonly: true } + Property { name: "collapsible"; type: "bool" } + Property { name: "collapsed"; type: "bool" } + Property { name: "collapsedSize"; type: "int" } + Property { name: "handleOpenIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleClosedIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleVisible"; type: "bool" } + Property { name: "handle"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "__internal"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickGroupBox" + name: "QtQuick.Controls/GroupBox 2.0" + exports: ["QtQuick.Controls/GroupBox 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickLabel" + name: "org.kde.kirigami/Heading 2.0" + exports: ["org.kde.kirigami/Heading 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "level"; type: "int" } + Property { name: "step"; type: "int" } + Method { + name: "headerPointSize" + type: "QVariant" + Parameter { name: "l"; type: "QVariant" } + } + } + Component { + prototype: "QQuickControl" + name: "org.kde.kirigami/InlineMessage 2.4" + exports: ["org.kde.kirigami/InlineMessage 2.4"] + exportMetaObjectRevisions: [4] + isComposite: true + defaultProperty: "data" + Property { name: "_animating"; type: "bool" } + Property { name: "type"; type: "int" } + Property { name: "icon"; type: "IconPropertiesGroup_QMLTYPE_22"; isPointer: true } + Property { name: "text"; type: "string" } + Property { name: "showCloseButton"; type: "bool" } + Property { name: "actions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "animating"; type: "bool"; isReadonly: true } + Signal { + name: "linkHovered" + Parameter { name: "link"; type: "string" } + } + Signal { + name: "linkActivated" + Parameter { name: "link"; type: "string" } + } + } + Component { + prototype: "QQuickItemDelegate" + name: "QtQuick.Controls/ItemDelegate 2.0" + exports: ["QtQuick.Controls/ItemDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickControl" + name: "org.kde.kirigami/ItemViewHeader 2.1" + exports: ["org.kde.kirigami/ItemViewHeader 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + Property { name: "title"; type: "string" } + Property { name: "color"; type: "QColor" } + Property { name: "backgroundImage"; type: "QQuickImage"; isReadonly: true; isPointer: true } + Property { name: "minimumHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "view"; type: "QQuickListView"; isPointer: true } + } + Component { + prototype: "QQuickLabel" + name: "org.kde.kirigami/Label 2.0" + exports: ["org.kde.kirigami/Label 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickLabel" + name: "QtQuick.Controls/Label 2.0" + exports: ["QtQuick.Controls/Label 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/ListItemDragHandle 2.5" + exports: ["org.kde.kirigami/ListItemDragHandle 2.5"] + exportMetaObjectRevisions: [5] + isComposite: true + defaultProperty: "data" + Property { name: "listItem"; type: "QQuickItem"; isPointer: true } + Property { name: "listView"; type: "QQuickListView"; isPointer: true } + Signal { + name: "moveRequested" + Parameter { name: "oldIndex"; type: "int" } + Parameter { name: "newIndex"; type: "int" } + } + Signal { name: "dropped" } + } + Component { + prototype: "QQuickMenu" + name: "QtQuick.Controls/Menu 2.0" + exports: ["QtQuick.Controls/Menu 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickMenuBar" + name: "QtQuick.Controls/MenuBar 2.3" + exports: ["QtQuick.Controls/MenuBar 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickMenuBarItem" + name: "QtQuick.Controls/MenuBarItem 2.3" + exports: ["QtQuick.Controls/MenuBarItem 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickMenuItem" + name: "QtQuick.Controls/MenuItem 2.0" + exports: ["QtQuick.Controls/MenuItem 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickMenuSeparator" + name: "QtQuick.Controls/MenuSeparator 2.1" + exports: ["QtQuick.Controls/MenuSeparator 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickDrawer" + name: "org.kde.kirigami/OverlayDrawer 2.0" + exports: ["org.kde.kirigami/OverlayDrawer 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + Property { name: "drawerOpen"; type: "bool" } + Property { name: "enabled"; type: "bool" } + Property { name: "peeking"; type: "bool" } + Property { name: "animating"; type: "bool"; isReadonly: true } + Property { name: "collapsible"; type: "bool" } + Property { name: "collapsed"; type: "bool" } + Property { name: "collapsedSize"; type: "int" } + Property { name: "handleOpenIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleClosedIcon"; type: "QObject"; isReadonly: true; isPointer: true } + Property { name: "handleVisible"; type: "bool" } + Property { name: "handle"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "__internal"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QObject" + name: "org.kde.kirigami/OverlaySheet 2.0" + exports: ["org.kde.kirigami/OverlaySheet 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentItem" + Property { name: "contentItem"; type: "QQuickItem"; isPointer: true } + Property { name: "sheetOpen"; type: "bool" } + Property { name: "leftPadding"; type: "int" } + Property { name: "topPadding"; type: "int" } + Property { name: "rightPadding"; type: "int" } + Property { name: "bottomPadding"; type: "int" } + Property { name: "header"; type: "QQuickItem"; isPointer: true } + Property { name: "footer"; type: "QQuickItem"; isPointer: true } + Property { name: "background"; type: "QQuickItem"; isPointer: true } + Property { name: "parent"; type: "QQuickItem"; isPointer: true } + Property { name: "rootItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "showCloseButton"; type: "bool" } + Method { name: "open"; type: "QVariant" } + Method { name: "close"; type: "QVariant" } + } + Component { + prototype: "QQuickPage" + name: "org.kde.kirigami/Page 2.0" + exports: ["org.kde.kirigami/Page 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + Property { name: "flickable"; type: "QQuickFlickable"; isPointer: true } + Property { name: "isCurrentPage"; type: "bool"; isReadonly: true } + Property { name: "contextualActions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "mainAction"; type: "QObject"; isPointer: true } + Property { name: "leftAction"; type: "QObject"; isPointer: true } + Property { name: "rightAction"; type: "QObject"; isPointer: true } + Property { + name: "actions" + type: "PageActionPropertyGroup_QMLTYPE_3" + isReadonly: true + isPointer: true + } + Signal { + name: "backRequested" + Parameter { name: "event"; type: "QVariant" } + } + } + Component { + prototype: "QQuickPage" + name: "QtQuick.Controls/Page 2.0" + exports: ["QtQuick.Controls/Page 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickPageIndicator" + name: "QtQuick.Controls/PageIndicator 2.0" + exports: ["QtQuick.Controls/PageIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickControl" + name: "org.kde.kirigami/PageRow 2.0" + exports: ["org.kde.kirigami/PageRow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "depth"; type: "int"; isReadonly: true } + Property { name: "lastItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "currentItem"; type: "QQuickItem"; isReadonly: true; isPointer: true } + Property { name: "initialPage"; type: "QVariant" } + Property { name: "defaultColumnWidth"; type: "int" } + Property { name: "wideMode"; type: "bool"; isReadonly: true } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "currentIndex"; type: "int" } + Property { name: "interactive"; type: "bool" } + Property { + name: "globalToolBar" + type: "PageRowGlobalToolBarStyleGroup_QMLTYPE_4" + isReadonly: true + isPointer: true + } + Property { name: "layers"; type: "QQuickStackView"; isReadonly: true; isPointer: true } + Signal { + name: "pagePushed" + Parameter { name: "page"; type: "QQuickItem"; isPointer: true } + } + Signal { + name: "pageRemoved" + Parameter { name: "page"; type: "QQuickItem"; isPointer: true } + } + Method { + name: "push" + type: "QVariant" + Parameter { name: "page"; type: "QVariant" } + Parameter { name: "properties"; type: "QVariant" } + } + Method { + name: "pop" + type: "QVariant" + Parameter { name: "page"; type: "QVariant" } + } + Method { + name: "replace" + type: "QVariant" + Parameter { name: "page"; type: "QVariant" } + Parameter { name: "properties"; type: "QVariant" } + } + Method { name: "clear"; type: "QVariant" } + Method { + name: "get" + type: "QVariant" + Parameter { name: "idx"; type: "QVariant" } + } + Method { name: "flickBack"; type: "QVariant" } + } + Component { + prototype: "QQuickPane" + name: "QtQuick.Controls/Pane 2.0" + exports: ["QtQuick.Controls/Pane 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/PieMenu 1.0" + exports: ["QtQuick.Extras/PieMenu 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "menuItems" + Property { name: "selectionAngle"; type: "double"; isReadonly: true } + Property { name: "triggerMode"; type: "int" } + Property { name: "title"; type: "string" } + Property { name: "boundingItem"; type: "QQuickItem"; isPointer: true } + Property { name: "__protectedScope"; type: "QObject"; isPointer: true } + Property { name: "activationMode"; type: "int" } + Property { name: "menuItems"; type: "QQuickMenuItem1"; isList: true; isReadonly: true } + Property { name: "currentIndex"; type: "int"; isReadonly: true } + Property { name: "currentItem"; type: "QQuickMenuItem1"; isReadonly: true; isPointer: true } + Property { name: "__mouseThief"; type: "QQuickMouseThief"; isReadonly: true; isPointer: true } + Method { + name: "popup" + type: "QVariant" + Parameter { name: "x"; type: "QVariant" } + Parameter { name: "y"; type: "QVariant" } + } + Method { + name: "addItem" + type: "QVariant" + Parameter { name: "text"; type: "QVariant" } + } + Method { + name: "insertItem" + type: "QVariant" + Parameter { name: "before"; type: "QVariant" } + Parameter { name: "text"; type: "QVariant" } + } + Method { + name: "removeItem" + type: "QVariant" + Parameter { name: "item"; type: "QVariant" } + } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickLoader" + name: "QtQuick.Extras.Private/PieMenuIcon 1.0" + exports: ["QtQuick.Extras.Private/PieMenuIcon 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "PieMenu_QMLTYPE_222"; isPointer: true } + Property { name: "styleData"; type: "QObject"; isPointer: true } + Property { name: "iconSource"; type: "string"; isReadonly: true } + } + Component { + prototype: "QQuickPopup" + name: "QtQuick.Controls/Popup 2.0" + exports: ["QtQuick.Controls/Popup 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickProgressBar" + name: "QtQuick.Controls/ProgressBar 2.0" + exports: ["QtQuick.Controls/ProgressBar 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRadioButton" + name: "QtQuick.Controls/RadioButton 2.0" + exports: ["QtQuick.Controls/RadioButton 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRadioDelegate" + name: "QtQuick.Controls/RadioDelegate 2.0" + exports: ["QtQuick.Controls/RadioDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/RadioIndicator 2.3" + exports: ["QtQuick.Controls.Fusion.impl/RadioIndicator 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "pressedColor"; type: "QColor"; isReadonly: true } + Property { name: "checkMarkColor"; type: "QColor"; isReadonly: true } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Material.impl/RadioIndicator 2.0" + exports: ["QtQuick.Controls.Material.impl/RadioIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Universal.impl/RadioIndicator 2.0" + exports: ["QtQuick.Controls.Universal.impl/RadioIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QVariant" } + } + Component { + prototype: "QQuickRangeSlider" + name: "QtQuick.Controls/RangeSlider 2.0" + exports: ["QtQuick.Controls/RangeSlider 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Material.impl/RectangularGlow 2.0" + exports: ["QtQuick.Controls.Material.impl/RectangularGlow 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "glowRadius"; type: "double" } + Property { name: "spread"; type: "double" } + Property { name: "color"; type: "QColor" } + Property { name: "cornerRadius"; type: "double" } + Property { name: "cached"; type: "bool" } + } + Component { + prototype: "QQuickRoundButton" + name: "QtQuick.Controls/RoundButton 2.1" + exports: ["QtQuick.Controls/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickScrollBar" + name: "QtQuick.Controls/ScrollBar 2.0" + exports: ["QtQuick.Controls/ScrollBar 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickScrollIndicator" + name: "QtQuick.Controls/ScrollIndicator 2.0" + exports: ["QtQuick.Controls/ScrollIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickScrollView" + name: "QtQuick.Controls/ScrollView 2.2" + exports: ["QtQuick.Controls/ScrollView 2.2"] + exportMetaObjectRevisions: [2] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickPage" + name: "org.kde.kirigami/ScrollablePage 2.0" + exports: ["org.kde.kirigami/ScrollablePage 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "mainItem" + Property { name: "mainItem"; type: "QObject"; isPointer: true } + Property { name: "keyboardNavigationEnabled"; type: "bool" } + Property { name: "refreshing"; type: "bool" } + Property { name: "supportsRefreshing"; type: "bool" } + Property { name: "flickable"; type: "QQuickFlickable"; isPointer: true } + Property { name: "verticalScrollBarPolicy"; type: "int" } + Property { name: "horizontalScrollBarPolicy"; type: "int" } + Property { name: "isCurrentPage"; type: "bool"; isReadonly: true } + Property { name: "contextualActions"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "mainAction"; type: "QObject"; isPointer: true } + Property { name: "leftAction"; type: "QObject"; isPointer: true } + Property { name: "rightAction"; type: "QObject"; isPointer: true } + Property { + name: "actions" + type: "PageActionPropertyGroup_QMLTYPE_3" + isReadonly: true + isPointer: true + } + Signal { + name: "backRequested" + Parameter { name: "event"; type: "QVariant" } + } + } + Component { + prototype: "QQuickRectangle" + name: "org.kde.kirigami/Separator 2.0" + exports: ["org.kde.kirigami/Separator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickSlider" + name: "QtQuick.Controls/Slider 2.0" + exports: ["QtQuick.Controls/Slider 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/SliderGroove 2.3" + exports: ["QtQuick.Controls.Fusion.impl/SliderGroove 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "offset"; type: "double" } + Property { name: "progress"; type: "double" } + Property { name: "visualProgress"; type: "double" } + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Material.impl/SliderHandle 2.0" + exports: ["QtQuick.Controls.Material.impl/SliderHandle 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "value"; type: "double" } + Property { name: "handleHasFocus"; type: "bool" } + Property { name: "handlePressed"; type: "bool" } + Property { name: "handleHovered"; type: "bool" } + Property { name: "initialSize"; type: "int"; isReadonly: true } + Property { name: "control"; type: "QVariant"; isReadonly: true } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/SliderHandle 2.3" + exports: ["QtQuick.Controls.Fusion.impl/SliderHandle 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "palette"; type: "QVariant" } + Property { name: "pressed"; type: "bool" } + Property { name: "hovered"; type: "bool" } + Property { name: "vertical"; type: "bool" } + Property { name: "visualFocus"; type: "bool" } + } + Component { + prototype: "QQuickSpinBox" + name: "QtQuick.Controls/SpinBox 2.0" + exports: ["QtQuick.Controls/SpinBox 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickStackView" + name: "QtQuick.Controls/StackView 2.0" + exports: ["QtQuick.Controls/StackView 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/StatusIndicator 1.0" + exports: ["QtQuick.Extras/StatusIndicator 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "active"; type: "bool" } + Property { name: "color"; type: "QColor" } + Property { name: "on"; type: "bool" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/StatusIndicator 1.1" + exports: ["QtQuick.Extras/StatusIndicator 1.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + Property { name: "active"; type: "bool" } + Property { name: "color"; type: "QColor" } + Property { name: "on"; type: "bool" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickSwipeDelegate" + name: "QtQuick.Controls/SwipeDelegate 2.0" + exports: ["QtQuick.Controls/SwipeDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickItemDelegate" + name: "org.kde.kirigami/SwipeListItem 2.0" + exports: ["org.kde.kirigami/SwipeListItem 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "_default" + Property { name: "sectionDelegate"; type: "bool" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "actions"; type: "Action_QMLTYPE_53"; isList: true; isReadonly: true } + Property { name: "textColor"; type: "QColor" } + Property { name: "backgroundColor"; type: "QColor" } + Property { name: "activeTextColor"; type: "QColor" } + Property { name: "activeBackgroundColor"; type: "QColor" } + Property { name: "supportsMouseEvents"; type: "bool" } + Property { name: "containsMouse"; type: "bool"; isReadonly: true } + Property { name: "actionsVisible"; type: "bool" } + Property { name: "_default"; type: "QQuickItem"; isPointer: true } + } + Component { + prototype: "QQuickSwipeView" + name: "QtQuick.Controls/SwipeView 2.0" + exports: ["QtQuick.Controls/SwipeView 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickSwitch" + name: "QtQuick.Controls/Switch 2.0" + exports: ["QtQuick.Controls/Switch 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickSwitchDelegate" + name: "QtQuick.Controls/SwitchDelegate 2.0" + exports: ["QtQuick.Controls/SwitchDelegate 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Universal.impl/SwitchIndicator 2.0" + exports: ["QtQuick.Controls.Universal.impl/SwitchIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + } + Component { + prototype: "QQuickRectangle" + name: "QtQuick.Controls.Fusion.impl/SwitchIndicator 2.3" + exports: ["QtQuick.Controls.Fusion.impl/SwitchIndicator 2.3"] + exportMetaObjectRevisions: [3] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "pressedColor"; type: "QColor"; isReadonly: true } + Property { name: "checkMarkColor"; type: "QColor"; isReadonly: true } + } + Component { + prototype: "QQuickItem" + name: "QtQuick.Controls.Material.impl/SwitchIndicator 2.0" + exports: ["QtQuick.Controls.Material.impl/SwitchIndicator 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "control"; type: "QQuickItem"; isPointer: true } + Property { name: "handle"; type: "QQuickRectangle"; isReadonly: true; isPointer: true } + } + Component { + prototype: "QQuickTabBar" + name: "QtQuick.Controls/TabBar 2.0" + exports: ["QtQuick.Controls/TabBar 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickTabButton" + name: "QtQuick.Controls/TabButton 2.0" + exports: ["QtQuick.Controls/TabButton 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickTextArea" + name: "QtQuick.Controls/TextArea 2.0" + exports: ["QtQuick.Controls/TextArea 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickTextField" + name: "QtQuick.Controls/TextField 2.0" + exports: ["QtQuick.Controls/TextField 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickText" + name: "QtQuick.Extras.Private/TextSingleton 1.0" + exports: ["QtQuick.Extras.Private/TextSingleton 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + isCreatable: false + isSingleton: true + defaultProperty: "data" + } + Component { + prototype: "QObject" + name: "org.kde.kirigami/Theme 2.0" + exports: ["org.kde.kirigami/Theme 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + isCreatable: false + isSingleton: true + Property { name: "textColor"; type: "QColor" } + Property { name: "disabledTextColor"; type: "QColor" } + Property { name: "highlightColor"; type: "QColor" } + Property { name: "highlightedTextColor"; type: "QColor" } + Property { name: "backgroundColor"; type: "QColor" } + Property { name: "activeTextColor"; type: "QColor" } + Property { name: "linkColor"; type: "QColor" } + Property { name: "visitedLinkColor"; type: "QColor" } + Property { name: "hoverColor"; type: "QColor" } + Property { name: "focusColor"; type: "QColor" } + Property { name: "negativeTextColor"; type: "QColor" } + Property { name: "neutralTextColor"; type: "QColor" } + Property { name: "positiveTextColor"; type: "QColor" } + Property { name: "buttonTextColor"; type: "QColor" } + Property { name: "buttonBackgroundColor"; type: "QColor" } + Property { name: "buttonHoverColor"; type: "QColor" } + Property { name: "buttonFocusColor"; type: "QColor" } + Property { name: "viewTextColor"; type: "QColor" } + Property { name: "viewBackgroundColor"; type: "QColor" } + Property { name: "viewHoverColor"; type: "QColor" } + Property { name: "viewFocusColor"; type: "QColor" } + Property { name: "selectionTextColor"; type: "QColor" } + Property { name: "selectionBackgroundColor"; type: "QColor" } + Property { name: "selectionHoverColor"; type: "QColor" } + Property { name: "selectionFocusColor"; type: "QColor" } + Property { name: "tooltipTextColor"; type: "QColor" } + Property { name: "tooltipBackgroundColor"; type: "QColor" } + Property { name: "tooltipHoverColor"; type: "QColor" } + Property { name: "tooltipFocusColor"; type: "QColor" } + Property { name: "complementaryTextColor"; type: "QColor" } + Property { name: "complementaryBackgroundColor"; type: "QColor" } + Property { name: "complementaryHoverColor"; type: "QColor" } + Property { name: "complementaryFocusColor"; type: "QColor" } + Property { name: "defaultFont"; type: "QFont" } + Property { name: "children"; type: "QObject"; isList: true; isReadonly: true } + Method { + name: "__propagateColorSet" + type: "QVariant" + Parameter { name: "object"; type: "QVariant" } + Parameter { name: "context"; type: "QVariant" } + } + Method { + name: "__propagateTextColor" + type: "QVariant" + Parameter { name: "object"; type: "QVariant" } + Parameter { name: "color"; type: "QVariant" } + } + Method { + name: "__propagateBackgroundColor" + type: "QVariant" + Parameter { name: "object"; type: "QVariant" } + Parameter { name: "color"; type: "QVariant" } + } + Method { + name: "__propagatePrimaryColor" + type: "QVariant" + Parameter { name: "object"; type: "QVariant" } + Parameter { name: "color"; type: "QVariant" } + } + Method { + name: "__propagateAccentColor" + type: "QVariant" + Parameter { name: "object"; type: "QVariant" } + Parameter { name: "color"; type: "QVariant" } + } + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/ToggleButton 1.0" + exports: ["QtQuick.Extras/ToggleButton 1.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + Property { name: "isDefault"; type: "bool" } + Property { name: "menu"; type: "Menu_QMLTYPE_126"; isPointer: true } + Property { name: "checkable"; type: "bool" } + Property { name: "checked"; type: "bool" } + Property { name: "exclusiveGroup"; type: "QQuickExclusiveGroup1"; isPointer: true } + Property { name: "action"; type: "QQuickAction1"; isPointer: true } + Property { name: "activeFocusOnPress"; type: "bool" } + Property { name: "text"; type: "string" } + Property { name: "tooltip"; type: "string" } + Property { name: "iconSource"; type: "QUrl" } + Property { name: "iconName"; type: "string" } + Property { name: "__position"; type: "string" } + Property { name: "__iconOverriden"; type: "bool"; isReadonly: true } + Property { name: "__action"; type: "QQuickAction1"; isPointer: true } + Property { name: "__iconAction"; type: "QQuickAction1"; isReadonly: true; isPointer: true } + Property { name: "__behavior"; type: "QVariant" } + Property { name: "__effectivePressed"; type: "bool" } + Property { name: "pressed"; type: "bool"; isReadonly: true } + Property { name: "hovered"; type: "bool"; isReadonly: true } + Signal { name: "clicked" } + Method { name: "accessiblePressAction"; type: "QVariant" } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickToolBar" + name: "QtQuick.Controls/ToolBar 2.0" + exports: ["QtQuick.Controls/ToolBar 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickItem" + name: "org.kde.kirigami/ToolBarApplicationHeader 2.0" + exports: ["org.kde.kirigami/ToolBarApplicationHeader 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentItem" + Property { name: "_internal"; type: "string" } + Property { name: "headerStyle"; type: "int" } + Property { name: "backButtonEnabled"; type: "bool" } + Property { name: "pageDelegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "minimumHeight"; type: "int" } + Property { name: "preferredHeight"; type: "int" } + Property { name: "maximumHeight"; type: "int" } + Property { name: "pageRow"; type: "PageRow_QMLTYPE_5"; isPointer: true } + Property { name: "page"; type: "Page_QMLTYPE_14"; isPointer: true } + Property { name: "paintedHeight"; type: "int"; isReadonly: true } + Property { name: "leftPadding"; type: "int" } + Property { name: "topPadding"; type: "int" } + Property { name: "rightPadding"; type: "int" } + Property { name: "bottomPadding"; type: "int" } + Property { name: "separatorVisible"; type: "bool" } + Property { name: "__appWindow"; type: "QObject"; isPointer: true } + Property { name: "background"; type: "QQuickItem"; isPointer: true } + Property { name: "contentItem"; type: "QObject"; isList: true; isReadonly: true } + } + Component { + prototype: "QQuickToolButton" + name: "QtQuick.Controls/ToolButton 2.0" + exports: ["QtQuick.Controls/ToolButton 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickToolSeparator" + name: "QtQuick.Controls/ToolSeparator 2.1" + exports: ["QtQuick.Controls/ToolSeparator 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QQuickToolTip" + name: "QtQuick.Controls/ToolTip 2.0" + exports: ["QtQuick.Controls/ToolTip 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickFocusScope" + name: "QtQuick.Extras/Tumbler 1.2" + exports: ["QtQuick.Extras/Tumbler 1.2"] + exportMetaObjectRevisions: [2] + isComposite: true + defaultProperty: "data" + Property { name: "__highlightMoveDuration"; type: "int" } + Property { name: "columnCount"; type: "int"; isReadonly: true } + Property { name: "__columnRow"; type: "QQuickRow"; isReadonly: true; isPointer: true } + Property { name: "__movementDelayTimer"; type: "QQmlTimer"; isReadonly: true; isPointer: true } + Method { + name: "__isValidColumnIndex" + type: "QVariant" + Parameter { name: "index"; type: "QVariant" } + } + Method { + name: "__isValidColumnAndItemIndex" + type: "QVariant" + Parameter { name: "columnIndex"; type: "QVariant" } + Parameter { name: "itemIndex"; type: "QVariant" } + } + Method { + name: "currentIndexAt" + type: "QVariant" + Parameter { name: "columnIndex"; type: "QVariant" } + } + Method { + name: "setCurrentIndexAt" + type: "QVariant" + Parameter { name: "columnIndex"; type: "QVariant" } + Parameter { name: "itemIndex"; type: "QVariant" } + Parameter { name: "interval"; type: "QVariant" } + } + Method { + name: "getColumn" + type: "QVariant" + Parameter { name: "columnIndex"; type: "QVariant" } + } + Method { + name: "addColumn" + type: "QVariant" + Parameter { name: "column"; type: "QVariant" } + } + Method { + name: "insertColumn" + type: "QVariant" + Parameter { name: "index"; type: "QVariant" } + Parameter { name: "column"; type: "QVariant" } + } + Method { + name: "__viewAt" + type: "QVariant" + Parameter { name: "index"; type: "QVariant" } + } + Property { name: "style"; type: "QQmlComponent"; isPointer: true } + Property { name: "__style"; type: "QObject"; isPointer: true } + Property { name: "__panel"; type: "QQuickItem"; isPointer: true } + Property { name: "styleHints"; type: "QVariant" } + Property { name: "__styleData"; type: "QObject"; isPointer: true } + } + Component { + prototype: "QQuickTumbler" + name: "QtQuick.Controls/Tumbler 2.0" + exports: ["QtQuick.Controls/Tumbler 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } + Component { + prototype: "QObject" + name: "QtQuick.Extras/TumblerColumn 1.2" + exports: ["QtQuick.Extras/TumblerColumn 1.2"] + exportMetaObjectRevisions: [2] + isComposite: true + Property { name: "__tumbler"; type: "QQuickItem"; isPointer: true } + Property { name: "__index"; type: "int" } + Property { name: "__currentIndex"; type: "int" } + Property { name: "model"; type: "QVariant" } + Property { name: "role"; type: "string" } + Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "highlight"; type: "QQmlComponent"; isPointer: true } + Property { name: "columnForeground"; type: "QQmlComponent"; isPointer: true } + Property { name: "visible"; type: "bool" } + Property { name: "activeFocus"; type: "bool"; isReadonly: true } + Property { name: "width"; type: "double" } + Property { name: "currentIndex"; type: "int"; isReadonly: true } + } + Component { + prototype: "QObject" + name: "org.kde.kirigami/Units 2.0" + exports: ["org.kde.kirigami/Units 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + isCreatable: false + isSingleton: true + Property { name: "gridUnit"; type: "int" } + Property { name: "iconSizes"; type: "QObject"; isPointer: true } + Property { name: "smallSpacing"; type: "int" } + Property { name: "largeSpacing"; type: "int" } + Property { name: "devicePixelRatio"; type: "double" } + Property { name: "longDuration"; type: "int" } + Property { name: "shortDuration"; type: "int" } + Property { name: "toolTipDelay"; type: "int" } + Property { name: "wheelScrollLines"; type: "int"; isReadonly: true } + Property { name: "fontMetrics"; type: "QVariant" } + } +} diff --git a/src/controls/private/ActionButton.qml b/src/controls/private/ActionButton.qml new file mode 100644 index 0000000..2dea626 --- /dev/null +++ b/src/controls/private/ActionButton.qml @@ -0,0 +1,502 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +import "../templates/private" + +Item { + id: root + Theme.colorSet: Theme.Button + Theme.inherit: false + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + bottomMargin: root.page.footer ? root.page.footer.height : 0 + } + //smallSpacing for the shadow + height: button.height + Units.smallSpacing + clip: true + + readonly property Page page: root.parent.page + //either Action or QAction should work here + + function isActionAvailable(action) { return action && (action.visible === undefined || action.visible); } + + readonly property QtObject action: root.page && isActionAvailable(root.page.mainAction) ? root.page.mainAction : null + readonly property QtObject leftAction: root.page && isActionAvailable(root.page.leftAction) ? root.page.leftAction : null + readonly property QtObject rightAction: root.page && isActionAvailable(root.page.rightAction) ? root.page.rightAction : null + + readonly property bool hasApplicationWindow: typeof applicationWindow !== "undefined" && applicationWindow + readonly property bool hasGlobalDrawer: typeof globalDrawer !== "undefined" && globalDrawer + readonly property bool hasContextDrawer: typeof contextDrawer !== "undefined" && contextDrawer + + transform: Translate { + id: translateTransform + y: mouseArea.internalVisibility ? 0 : button.height + Behavior on y { + NumberAnimation { + duration: Units.longDuration + easing.type: mouseArea.internalVisibility == true ? Easing.InQuad : Easing.OutQuad + } + } + } + + onWidthChanged: button.x = root.width/2 - button.width/2 + Item { + id: button + x: root.width/2 - button.width/2 + + anchors.bottom: edgeMouseArea.bottom + + implicitWidth: implicitHeight + Units.iconSizes.smallMedium*2 + Units.gridUnit + implicitHeight: Units.iconSizes.medium + Units.largeSpacing * 2 + + + onXChanged: { + if (mouseArea.pressed || edgeMouseArea.pressed || fakeContextMenuButton.pressed) { + if (root.hasGlobalDrawer && globalDrawer.enabled && globalDrawer.modal) { + globalDrawer.peeking = true; + globalDrawer.visible = true; + globalDrawer.position = Math.min(1, Math.max(0, (x - root.width/2 + button.width/2)/globalDrawer.contentItem.width + mouseArea.drawerShowAdjust)); + } + if (root.hasContextDrawer && contextDrawer.enabled && contextDrawer.modal) { + contextDrawer.peeking = true; + contextDrawer.visible = true; + contextDrawer.position = Math.min(1, Math.max(0, (root.width/2 - button.width/2 - x)/contextDrawer.contentItem.width + mouseArea.drawerShowAdjust)); + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + + visible: action != null || leftAction != null || rightAction != null + property bool internalVisibility: (!root.hasApplicationWindow || (applicationWindow().controlsVisible && applicationWindow().height > root.height*2)) && (root.action === null || root.action.visible === undefined || root.action.visible) + preventStealing: true + + drag { + target: button + //filterChildren: true + axis: Drag.XAxis + minimumX: root.hasContextDrawer && contextDrawer.enabled && contextDrawer.modal ? 0 : root.width/2 - button.width/2 + maximumX: root.hasGlobalDrawer && globalDrawer.enabled && globalDrawer.modal ? root.width : root.width/2 - button.width/2 + } + + property var downTimestamp; + property int startX + property int startMouseY + property real drawerShowAdjust + + readonly property int currentThird: (3*mouseX)/width + readonly property QtObject actionUnderMouse: { + switch(currentThird) { + case 0: return leftAction; + case 1: return action; + case 2: return rightAction; + default: return null + } + } + + hoverEnabled: true + + Controls.ToolTip.visible: containsMouse && !Settings.tabletMode && actionUnderMouse + Controls.ToolTip.text: actionUnderMouse ? actionUnderMouse.text : "" + Controls.ToolTip.delay: Units.toolTipDelay + + onPressed: { + //search if we have a page to set to current + if (root.hasApplicationWindow && applicationWindow().pageStack.currentIndex !== undefined && root.page.parent.level !== undefined) { + //search the button parent's parent, that is the page parent + //this will make the context drawer open for the proper page + applicationWindow().pageStack.currentIndex = root.page.parent.level; + } + downTimestamp = (new Date()).getTime(); + startX = button.x + button.width/2; + startMouseY = mouse.y; + drawerShowAdjust = 0; + } + onReleased: { + if (root.hasGlobalDrawer) globalDrawer.peeking = false; + if (root.hasContextDrawer) contextDrawer.peeking = false; + //pixel/second + var x = button.x + button.width/2; + var speed = ((x - startX) / ((new Date()).getTime() - downTimestamp) * 1000); + drawerShowAdjust = 0; + + //project where it would be a full second in the future + if (root.hasContextDrawer && root.hasGlobalDrawer && globalDrawer.modal && x + speed > Math.min(root.width/4*3, root.width/2 + globalDrawer.contentItem.width/2)) { + globalDrawer.open(); + contextDrawer.close(); + } else if (root.hasContextDrawer && x + speed < Math.max(root.width/4, root.width/2 - contextDrawer.contentItem.width/2)) { + if (root.hasContextDrawer && contextDrawer.modal) { + contextDrawer.open(); + } + if (root.hasGlobalDrawer && globalDrawer.modal) { + globalDrawer.close(); + } + } else { + if (root.hasGlobalDrawer && globalDrawer.modal) { + globalDrawer.close(); + } + if (root.hasContextDrawer && contextDrawer.modal) { + contextDrawer.close(); + } + } + //Don't rely on native onClicked, but fake it here: + //Qt.startDragDistance is not adapted to devices dpi in case + //of Android, so consider the button "clicked" when: + //*the button has been dragged less than a gridunit + //*the finger is still on the button + if (Math.abs((button.x + button.width/2) - startX) < Units.gridUnit && + mouse.y > 0) { + if (!actionUnderMouse) { + return; + } + + //if an action has been assigned, trigger it + if (actionUnderMouse && actionUnderMouse.trigger) { + actionUnderMouse.trigger(); + } + + if (actionUnderMouse.children.length > 0) { + var subMenuUnderMouse; + switch (actionUnderMouse) { + case leftAction: + subMenuUnderMouse = leftActionSubMenu; + break; + case mainAction: + subMenuUnderMouse = mainActionSubMenu; + break + case rightAction: + subMenuUnderMouse = rightActionSubMenu; + break; + } + if (subMenuUnderMouse && !subMenuUnderMouse.visible) { + subMenuUnderMouse.visible = true; + } + } + } + } + + onPositionChanged: { + drawerShowAdjust = Math.min(0.3, Math.max(0, (startMouseY - mouse.y)/(Units.gridUnit*15))); + button.xChanged(); + } + onPressAndHold: { + if (!actionUnderMouse) { + return; + } + + //if an action has been assigned, show a message like a tooltip + if (actionUnderMouse && actionUnderMouse.text && Settings.tabletMode) { + Controls.ToolTip.show(actionUnderMouse.text, 3000) + } + } + Connections { + target: root.hasGlobalDrawer ? globalDrawer : null + onPositionChanged: { + if ( globalDrawer && globalDrawer.modal && !mouseArea.pressed && !edgeMouseArea.pressed && !fakeContextMenuButton.pressed) { + button.x = globalDrawer.contentItem.width * globalDrawer.position + root.width/2 - button.width/2; + } + } + } + Connections { + target: root.hasContextDrawer ? contextDrawer : null + onPositionChanged: { + if (contextDrawer && contextDrawer.modal && !mouseArea.pressed && !edgeMouseArea.pressed && !fakeContextMenuButton.pressed) { + button.x = root.width/2 - button.width/2 - contextDrawer.contentItem.width * contextDrawer.position; + } + } + } + + Item { + id: background + anchors { + fill: parent + } + + Rectangle { + id: buttonGraphics + radius: width/2 + anchors.centerIn: parent + height: parent.height - Units.smallSpacing*2 + width: height + enabled: root.action && root.action.enabled + visible: root.action + readonly property bool pressed: root.action && root.action.enabled && ((root.action == mouseArea.actionUnderMouse && mouseArea.pressed) || root.action.checked) + property color baseColor: root.action && root.action.icon && root.action.icon.color && root.action.icon.color != undefined && root.action.icon.color.a > 0 ? root.action.icon.color : Theme.highlightColor + color: pressed ? Qt.darker(baseColor, 1.3) : baseColor + + ActionsMenu { + id: mainActionSubMenu + y: -height + x: -width/2 + parent.width/2 + actions: root.action ? root.action.children : "" + submenuComponent: Component { + ActionsMenu {} + } + } + Icon { + id: icon + anchors.centerIn: parent + width: Units.iconSizes.smallMedium + height: width + source: root.action && root.action.iconName ? root.action.iconName : "" + selected: true + color: (selected ? Theme.highlightedTextColor : Theme.textColor) + } + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + Behavior on x { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + //left button + Rectangle { + id: leftButtonGraphics + z: -1 + anchors { + left: parent.left + bottom: parent.bottom + bottomMargin: Units.smallSpacing + } + enabled: root.leftAction && root.leftAction.enabled + radius: Units.devicePixelRatio*2 + height: Units.iconSizes.smallMedium + Units.smallSpacing * 2 + width: height + (root.action ? Units.gridUnit*2 : 0) + visible: root.leftAction + + readonly property bool pressed: root.leftAction && root.leftAction.enabled && ((mouseArea.actionUnderMouse == root.leftAction && mouseArea.pressed) || root.leftAction.checked) + property color baseColor: root.leftAction && root.leftAction.icon && root.leftAction.icon.color && root.leftAction.icon.color != undefined && root.leftAction.icon.color.a > 0 ? root.leftAction.icon.color : Theme.highlightColor + color: pressed ? baseColor : Theme.backgroundColor + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + ActionsMenu { + id: leftActionSubMenu + y: -height + x: -width/2 + parent.width/2 + actions: root.leftAction ? root.leftAction.children : "" + submenuComponent: Component { + ActionsMenu {} + } + } + Icon { + source: root.leftAction && root.leftAction.iconName ? root.leftAction.iconName : "" + width: Units.iconSizes.smallMedium + height: width + selected: leftButtonGraphics.pressed + color: (selected ? Theme.highlightedTextColor : Theme.textColor) + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + margins: Units.smallSpacing * 2 + } + } + } + //right button + Rectangle { + id: rightButtonGraphics + z: -1 + anchors { + right: parent.right + //verticalCenter: parent.verticalCenter + bottom: parent.bottom + bottomMargin: Units.smallSpacing + } + enabled: root.rightAction && root.rightAction.enabled + radius: Units.devicePixelRatio*2 + height: Units.iconSizes.smallMedium + Units.smallSpacing * 2 + width: height + (root.action ? Units.gridUnit*2 : 0) + visible: root.rightAction + readonly property bool pressed: root.rightAction && root.rightAction.enabled && ((mouseArea.actionUnderMouse == root.rightAction && mouseArea.pressed) || root.rightAction.checked) + property color baseColor: root.rightAction && root.rightAction.icon && root.rightAction.icon.color && root.rightAction.icon.color != undefined && root.rightAction.icon.color.a > 0 ? root.rightAction.icon.color : Theme.highlightColor + color: pressed ? baseColor : Theme.backgroundColor + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + ActionsMenu { + id: rightActionSubMenu + y: -height + x: -width/2 + parent.width/2 + actions: root.rightAction ? root.rightAction.children : "" + submenuComponent: Component { + ActionsMenu {} + } + } + Icon { + source: root.rightAction && root.rightAction.iconName ? root.rightAction.iconName : "" + width: Units.iconSizes.smallMedium + height: width + selected: rightButtonGraphics.pressed + color: (selected ? Theme.highlightedTextColor : Theme.textColor) + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + margins: Units.smallSpacing * 2 + } + } + } + } + + DropShadow { + anchors.fill: background + horizontalOffset: 0 + verticalOffset: Units.devicePixelRatio + radius: Units.gridUnit /2 + samples: 16 + color: Qt.rgba(0, 0, 0, mouseArea.pressed ? 0.6 : 0.4) + source: background + } + } + } + + MouseArea { + id: fakeContextMenuButton + anchors { + right: edgeMouseArea.right + bottom: parent.bottom + margins: Units.smallSpacing + } + drag { + target: button + axis: Drag.XAxis + minimumX: root.hasContextDrawer && contextDrawer.enabled && contextDrawer.modal ? 0 : root.width/2 - button.width/2 + maximumX: root.hasGlobalDrawer && globalDrawer.enabled && globalDrawer.modal ? root.width : root.width/2 - button.width/2 + } + visible: root.page.actions && root.page.actions.contextualActions.length > 0 && (applicationWindow === undefined || applicationWindow().wideScreen) + //using internal pagerow api + && (root.page && root.page.parent ? root.page.parent.level < applicationWindow().pageStack.depth-1 : false) + + width: Units.iconSizes.smallMedium + Units.smallSpacing*2 + height: width + + + DropShadow { + anchors.fill: handleGraphics + horizontalOffset: 0 + verticalOffset: Units.devicePixelRatio + radius: Units.gridUnit /2 + samples: 16 + color: Qt.rgba(0, 0, 0, fakeContextMenuButton.pressed ? 0.6 : 0.4) + source: handleGraphics + } + Rectangle { + id: handleGraphics + anchors.fill: parent + color: fakeContextMenuButton.pressed ? Theme.highlightColor : Theme.backgroundColor + radius: Units.devicePixelRatio + Icon { + anchors.centerIn: parent + width: Units.iconSizes.smallMedium + selected: fakeContextMenuButton.pressed + height: width + source: "overflow-menu" + } + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + onPressed: { + mouseArea.onPressed(mouse) + } + onReleased: { + if (globalDrawer) { + globalDrawer.peeking = false; + } + if (contextDrawer) { + contextDrawer.peeking = false; + } + var pos = root.mapFromItem(fakeContextMenuButton, mouse.x, mouse.y); + if (contextDrawer) { + if (pos.x < root.width/2) { + contextDrawer.open(); + } else if (contextDrawer.drawerOpen && mouse.x > 0 && mouse.x < width) { + contextDrawer.close(); + } + } + if (globalDrawer) { + if (globalDrawer.position > 0.5) { + globalDrawer.open(); + } else { + globalDrawer.close(); + } + } + if (containsMouse && (!globalDrawer || !globalDrawer.drawerOpen || !globalDrawer.modal) && + (!contextDrawer || !contextDrawer.drawerOpen || !contextDrawer.modal)) { + contextMenu.visible = !contextMenu.visible; + } + } + ActionsMenu { + id: contextMenu + x: parent.width - width + y: -height + actions: root.page.actions.contextualActions + submenuComponent: Component { + ActionsMenu {} + } + } + } + + MouseArea { + id: edgeMouseArea + z:99 + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + drag { + target: button + //filterChildren: true + axis: Drag.XAxis + minimumX: root.hasContextDrawer && contextDrawer.enabled && contextDrawer.modal ? 0 : root.width/2 - button.width/2 + maximumX: root.hasGlobalDrawer && globalDrawer.enabled && globalDrawer.modal ? root.width : root.width/2 - button.width/2 + } + height: Units.smallSpacing * 3 + + onPressed: mouseArea.onPressed(mouse) + onPositionChanged: mouseArea.positionChanged(mouse) + onReleased: mouseArea.released(mouse) + } +} diff --git a/src/controls/private/ActionIconGroup.qml b/src/controls/private/ActionIconGroup.qml new file mode 100644 index 0000000..19a5ea1 --- /dev/null +++ b/src/controls/private/ActionIconGroup.qml @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQml 2.1 + +QtObject { + property string name + property string source + property int width + property int height + property color color: Qt.rgba(0, 0, 0, 0) +} + diff --git a/src/controls/private/ActionMenuItemBase.qml b/src/controls/private/ActionMenuItemBase.qml new file mode 100644 index 0000000..001c828 --- /dev/null +++ b/src/controls/private/ActionMenuItemBase.qml @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.3 +import QtQuick.Controls 2.1 as Controls + +Controls.MenuItem { + id: menuItem + + property QtObject ourAction + + text: ourAction.text + visible: ourAction.visible !== undefined ? ourAction.visible : true + enabled: ourAction.enabled + checkable: ourAction.checkable + checked: ourAction.checked + height: visible ? implicitHeight : 0 + onTriggered: { + ourAction.trigger() + } +} diff --git a/src/controls/private/ActionMenuItemQt510.qml b/src/controls/private/ActionMenuItemQt510.qml new file mode 100644 index 0000000..7ee07bd --- /dev/null +++ b/src/controls/private/ActionMenuItemQt510.qml @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.3 +import QtQuick.Controls 2.3 as Controls + +ActionMenuItemBase +{ + icon.name: ourAction.icon.name + autoExclusive: ourAction.Controls.ActionGroup && ourAction.Controls.ActionGroup.group && ourAction.Controls.ActionGroup.group.exclusive +} diff --git a/src/controls/private/ActionMenuItemQt59.qml b/src/controls/private/ActionMenuItemQt59.qml new file mode 100644 index 0000000..711a097 --- /dev/null +++ b/src/controls/private/ActionMenuItemQt59.qml @@ -0,0 +1,22 @@ +/* + * Copyright 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +ActionMenuItemBase +{ +} diff --git a/src/controls/private/ActionsMenu.qml b/src/controls/private/ActionsMenu.qml new file mode 100644 index 0000000..37d937f --- /dev/null +++ b/src/controls/private/ActionsMenu.qml @@ -0,0 +1,77 @@ +/* + * Copyright 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.3 +import QtQuick.Controls 2.1 as Controls +import org.kde.kirigami 2.4 as Kirigami + +Controls.Menu +{ + id: theMenu + property alias actions: actionsInstantiator.model + property Component submenuComponent + //renamed to work on both Qt 5.9 and 5.10 + property Component itemDelegate: Component {ActionMenuItem {}} + property Component separatorDelegate: Component { + Controls.MenuSeparator { + contentItem: Rectangle { + implicitHeight: Math.floor(Kirigami.Units.devicePixelRatio) + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + } + } + } + + Item { + id: invisibleItems + visible: false + } + Instantiator { + id: actionsInstantiator + + delegate: QtObject { + readonly property QtObject action: modelData + property QtObject item: null + + function create() { + if (!action.children || action.children.length === 0) { + if (action.hasOwnProperty("separator") && action.separator) { + item = theMenu.separatorDelegate.createObject(null, {}); + } + else { + item = theMenu.itemDelegate.createObject(null, { ourAction: action }); + } + theMenu.addItem(item) + } else if (theMenu.submenuComponent) { + item = theMenu.submenuComponent.createObject(null, { title: action.text, actions: action.children }); + theMenu.addMenu(item) + } + } + function remove() { + if (!action.children || action.children.length === 0) { + theMenu.removeItem(item) + } else if (theMenu.submenuComponent) { + theMenu.removeMenu(item) + } + } + } + + onObjectAdded: object.create() + onObjectRemoved: object.remove() + } +} diff --git a/src/controls/private/BannerImage.qml b/src/controls/private/BannerImage.qml new file mode 100644 index 0000000..1706d48 --- /dev/null +++ b/src/controls/private/BannerImage.qml @@ -0,0 +1,149 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 as Kirigami + +/** + * This Component is used as the header of GlobalDrawer and as the header + * of Card, It can be accessed there as a grouped property but can never + * be instantiated directly + */ +Image { + id: root + + /* + * FIXME: compatibility + */ + property alias imageSource: root.source + property alias iconSource: root.titleIcon + + /** + * title: string + * A title to be displayed on top of the image + */ + property alias title: heading.text + + /** + * icon: var + * An icon to be displayed alongside the title. + * It can be a QIcon, a fdo-compatible icon name, or any url understood by Image + */ + property alias titleIcon: headingIcon.source + + /** + * titleAlignment: Qt.Alignment + */ + property int titleAlignment: Qt.AlignTop | Qt.AlignLeft + + /** + * titleLevel: a Kirigami Heading level, default 1 + */ + property alias titleLevel: heading.level + + /** + * wrapMode: if the header should be able to do wrapping + */ + property alias titleWrapMode: heading.wrapMode + + property int leftPadding: headingIcon.valid ? Kirigami.Units.smallSpacing * 2 : Kirigami.Units.largeSpacing + property int topPadding: headingIcon.valid ? Kirigami.Units.smallSpacing * 2 : Kirigami.Units.largeSpacing + property int rightPadding: headingIcon.valid ? Kirigami.Units.smallSpacing * 2 : Kirigami.Units.largeSpacing + property int bottomPadding: headingIcon.valid ? Kirigami.Units.smallSpacing * 2 : Kirigami.Units.largeSpacing + + Layout.fillWidth: true + + Layout.preferredWidth: titleLayout.implicitWidth || sourceSize.width + Layout.preferredHeight: source != "" ? width/(sourceSize.width / sourceSize.height) : Layout.minimumHeight + Layout.minimumHeight: titleLayout.implicitHeight > 0 ? titleLayout.implicitHeight + Kirigami.Units.smallSpacing * 2 : 0 + property int implicitWidth: Layout.preferredWidth + + readonly property bool empty: bannerImage.title !== undefined && bannerImage.title.length === 0 && + bannerImage.source !== undefined && bannerImage.source.length === 0 && + bannerImage.titleIcon !== undefined &&bannerImage.titleIcon.length === 0 + + + + fillMode: Image.PreserveAspectCrop + asynchronous: true + + LinearGradient { + anchors { + left: parent.left + right: parent.right + top: root.status != +Image.Ready || (root.titleAlignment & Qt.AlignTop) ? parent.top : undefined + bottom: root.status != +Image.Ready || (root.titleAlignment & Qt.AlignBottom) ? parent.bottom : undefined + } + visible: root.source != "" && root.title != "" && ((root.titleAlignment & Qt.AlignTop) || (root.titleAlignment & Qt.AlignBottom)) + height: Math.min(parent.height, titleLayout.height * 2) + start: Qt.point(0, 0) + end: Qt.point(0, height) + gradient: Gradient { + GradientStop { + position: (root.titleAlignment & Qt.AlignTop) ? 0.0 : 1.0 + color: Qt.rgba(0, 0, 0, 0.8) + } + GradientStop { + position: (root.titleAlignment & Qt.AlignTop) ? 1.0 : 0.0 + color: Qt.rgba(0, 0, 0, root.status == +Image.Ready ? 0 : 0.3) + } + } + } + + RowLayout { + id: titleLayout + anchors { + left: root.titleAlignment & Qt.AlignLeft ? parent.left : undefined + top: root.titleAlignment & Qt.AlignTop ? parent.top : undefined + right: root.titleAlignment & Qt.AlignRight ? parent.right : undefined + bottom: root.titleAlignment & Qt.AlignBottom ? parent.bottom : undefined + horizontalCenter: root.titleAlignment & Qt.AlignHCenter ? parent.horizontalCenter : undefined + verticalCenter: root.titleAlignment & Qt.AlignVCenter ? parent.verticalCenter : undefined + + leftMargin: root.leftPadding + topMargin: root.topPadding + rightMargin: root.rightPadding + bottomMargin: root.bottomPadding + } + width: Math.min(implicitWidth, parent.width -root.leftPadding - root.rightPadding) + height: Math.min(implicitHeight, parent.height - root.topPadding - root.bottomPadding) + Kirigami.Icon { + id: headingIcon + Layout.minimumWidth: Kirigami.Units.iconSizes.large + Layout.minimumHeight: width + visible: valid + isMask: false + } + Kirigami.Heading { + id: heading + Layout.fillWidth: true + Layout.fillHeight: true + visible: text.length > 0 + level: 1 + color: source != "" ? "white" : Kirigami.Theme.textColor + wrapMode: Text.NoWrap + elide: Text.ElideRight + } + } +} diff --git a/src/controls/private/CardsGridViewPrivate.qml b/src/controls/private/CardsGridViewPrivate.qml new file mode 100644 index 0000000..2d3d298 --- /dev/null +++ b/src/controls/private/CardsGridViewPrivate.qml @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + + +GridView { + id: root + + property Component _delegateComponent + delegate: Kirigami.DelegateRecycler { + width: Math.min(root.cellWidth, root.maximumColumnWidth) - Kirigami.Units.largeSpacing * 2 + + //in grid views align the cells in the middle + anchors.left: parent.left + anchors.leftMargin: (width + Kirigami.Units.largeSpacing*2) * (index % root.columns ) + root.width/2 - (root.columns*(width + Kirigami.Units.largeSpacing*2))/2 + + sourceComponent: root._delegateComponent + } +} diff --git a/src/controls/private/CardsListViewPrivate.qml b/src/controls/private/CardsListViewPrivate.qml new file mode 100644 index 0000000..c0a016f --- /dev/null +++ b/src/controls/private/CardsListViewPrivate.qml @@ -0,0 +1,34 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.4 as Kirigami + + +ListView { + id: root + + property Component _delegateComponent + delegate: Kirigami.DelegateRecycler { + width: root.width - Kirigami.Units.largeSpacing * 4 + x: Kirigami.Units.largeSpacing * 2 + sourceComponent: root._delegateComponent + } +} diff --git a/src/controls/private/CornerShadow.qml b/src/controls/private/CornerShadow.qml new file mode 100644 index 0000000..80d0c0b --- /dev/null +++ b/src/controls/private/CornerShadow.qml @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +RadialGradient { + id: shadow + /** + * corner: enumeration + * This property holds the corner of the shadow that will determine + * the direction of the gradient. + * The acceptable values are: + * Qt.TopLeftCorner, TopRightCorner, BottomLeftCorner, BottomRightCorner + */ + property int corner: Qt.TopRightCorner + + width: Units.gridUnit/2 + height: Units.gridUnit/2 + + horizontalOffset: { + switch (corner) { + case Qt.TopLeftCorner: + case Qt.BottomLeftCorner: + return -width/2; + default: + return width/2; + } + } + verticalOffset: { + switch (corner) { + case Qt.TopLeftCorner: + case Qt.TopRightCorner: + return -width/2; + default: + return width/2; + } + } + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.rgba(0, 0, 0, 0.2) + } + GradientStop { + position: 0.3 + color: Qt.rgba(0, 0, 0, 0.1) + } + GradientStop { + position: 1.0 + color: "transparent" + } + } +} + diff --git a/src/controls/private/DefaultListItemBackground.qml b/src/controls/private/DefaultListItemBackground.qml new file mode 100644 index 0000000..e4bf38a --- /dev/null +++ b/src/controls/private/DefaultListItemBackground.qml @@ -0,0 +1,49 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 + +Rectangle { + id: background + color: listItem.checked || listItem.highlighted || (listItem.supportsMouseEvents && listItem.pressed && !listItem.checked && !listItem.sectionDelegate) ? listItem.activeBackgroundColor : listItem.backgroundColor + + visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true + Rectangle { + id: internal + property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (listItem.ListView.view ? listItem.ListView.view.activeFocus : false) + anchors.fill: parent + visible: !Settings.tabletMode && listItem.supportsMouseEvents + color: listItem.activeBackgroundColor + opacity: (listItem.hovered || listItem.highlighted || listItem.activeFocus) && !listItem.pressed ? 0.5 : 0 + Behavior on opacity { NumberAnimation { duration: Units.longDuration } } + } + + readonly property bool __separatorVisible: listItem.separatorVisible + + on__SeparatorVisibleChanged: { + if (__separatorVisible) { + var newObject = Qt.createQmlObject('import QtQuick 2.0; import org.kde.kirigami 2.4; Separator {anchors {left: parent.left; right: parent.right; bottom: parent.top} visible: listItem.separatorVisible}', + background); + newObject = Qt.createQmlObject('import QtQuick 2.0; import org.kde.kirigami 2.4; Separator {anchors {left: parent.left; right: parent.right; bottom: parent.bottom} visible: listItem.separatorVisible}', + background); + } + } +} + diff --git a/src/controls/private/EdgeShadow.qml b/src/controls/private/EdgeShadow.qml new file mode 100644 index 0000000..4319427 --- /dev/null +++ b/src/controls/private/EdgeShadow.qml @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +LinearGradient { + id: shadow + /** + * edge: enumeration + * This property holds the edge of the shadow that will determine + * the direction of the gradient. + * The acceptable values are: + * Qt.TopEdge: The top edge of the content item. + * Qt.LeftEdge: The left edge of the content item (default). + * Qt.RightEdge: The right edge of the content item. + * Qt.BottomEdge: The bottom edge of the content item. + */ + property int edge: Qt.LeftEdge + + implicitWidth: Units.gridUnit/2 + implicitHeight: Units.gridUnit/2 + + start: Qt.point((edge !== Qt.RightEdge ? 0 : width), (edge !== Qt.BottomEdge ? 0 : height)) + end: Qt.point((edge !== Qt.LeftEdge ? 0 : width), (edge !== Qt.TopEdge ? 0 : height)) + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.rgba(0, 0, 0, 0.2) + } + GradientStop { + position: 0.3 + color: Qt.rgba(0, 0, 0, 0.1) + } + GradientStop { + position: 1.0 + color: "transparent" + } + } +} + diff --git a/src/controls/private/PageActionPropertyGroup.qml b/src/controls/private/PageActionPropertyGroup.qml new file mode 100644 index 0000000..a999f37 --- /dev/null +++ b/src/controls/private/PageActionPropertyGroup.qml @@ -0,0 +1,28 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQml 2.1 + +QtObject { + property QtObject main + property QtObject left + property QtObject right + property list contextualActions +} + diff --git a/src/controls/private/PrivateActionToolButton.qml b/src/controls/private/PrivateActionToolButton.qml new file mode 100644 index 0000000..66dc20e --- /dev/null +++ b/src/controls/private/PrivateActionToolButton.qml @@ -0,0 +1,117 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.4 + +Controls.ToolButton { + id: control + + implicitWidth: menuArrow.visible || (showText && ( kirigamiAction ? kirigamiAction.text.length > 0 : text.length > 0)) + ? Math.max(layout.implicitWidth + Units.largeSpacing*2, background.implicitWidth) + : implicitHeight + implicitHeight: background.implicitHeight + + Theme.colorSet: Theme.Button + Theme.inherit: kirigamiAction && kirigamiAction.icon.color.a === 0 + Theme.backgroundColor: kirigamiAction && kirigamiAction.icon.color.a ? kirigamiAction.icon.color : undefined + Theme.textColor: kirigamiAction && !flat && kirigamiAction.icon.color.a ? Theme.highlightedTextColor : undefined + + hoverEnabled: true + flat: true + //TODO: replace with upstream action when we depend on Qt 5.10 + property Action kirigamiAction + property bool showText: true + property bool showMenuArrow: true + + //we need our own text delegate + text: "" + checkable: kirigamiAction && kirigamiAction.checkable + checked: (kirigamiAction && kirigamiAction.checked) || menu.visible + enabled: kirigamiAction && kirigamiAction.enabled + opacity: enabled ? 1 : 0.4 + visible: kirigamiAction && kirigamiAction.visible + onClicked: { + if (kirigamiAction) { + kirigamiAction.trigger(); + } + //fallbacks needed for Qt 5.9 + if (kirigamiAction.children.length > 0 && !menu.visible) { + if (menu.hasOwnProperty("popup")) { + menu.popup(control, 0, control.height) + } else { + menu.visible = true; + } + } + } + + ActionsMenu { + id: menu + y: control.height + actions: control.kirigamiAction ? control.kirigamiAction.children : null + submenuComponent: Component { + ActionsMenu {} + } + } + + contentItem: MouseArea { + hoverEnabled: true + onPressed: mouse.accepted = false + Theme.colorSet: checked && (!control.flat && control.kirigamiAction && control.kirigamiAction.icon.color.a) ? Theme.Selection : control.Theme.colorSet + Theme.inherit: control.kirigamiAction && Theme.colorSet != Theme.Selection && control.kirigamiAction.icon.color.a === 0 + RowLayout { + id: layout + + anchors.centerIn: parent + Icon { + id: mainIcon + Layout.minimumWidth: Units.iconSizes.smallMedium + Layout.minimumHeight: Units.iconSizes.smallMedium + source: control.kirigamiAction ? (control.kirigamiAction.icon ? control.kirigamiAction.icon.name : control.kirigamiAction.iconName) : "" + visible: control.kirigamiAction && control.kirigamiAction.iconName != "" + color: control.flat && control.kirigamiAction && control.kirigamiAction.icon && control.kirigamiAction.icon.color.a > 0 ? control.kirigamiAction.icon.color : label.color + } + Controls.Label { + id: label + MnemonicData.enabled: control.enabled + MnemonicData.controlType: MnemonicData.ActionElement + MnemonicData.label: control.kirigamiAction ? control.kirigamiAction.text : "" + + text: MnemonicData.richTextLabel + visible: control.showText && text.length > 0 + } + Icon { + id: menuArrow + Layout.minimumWidth: Units.iconSizes.small + Layout.minimumHeight: Units.iconSizes.small + source: "arrow-down" + visible: showMenuArrow && menu.actions && menu.actions.length > 0 + } + } + } + Controls.ToolTip { + visible: control.hovered && text.length > 0 + text: kirigamiAction ? (kirigamiAction.tooltip.length ? kirigamiAction.tooltip : kirigamiAction.text) : "" + delay: 1000 + timeout: 5000 + y: control.height + } +} diff --git a/src/controls/private/RefreshableScrollView.qml b/src/controls/private/RefreshableScrollView.qml new file mode 100644 index 0000000..ecaa9bd --- /dev/null +++ b/src/controls/private/RefreshableScrollView.qml @@ -0,0 +1,255 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 as QQC2 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 +import "../templates/private" as P + +P.ScrollView { + id: root + + /** + * type: bool + * If true the list is asking for refresh and will show a loading spinner. + * it will automatically be set to true when the user pulls down enough the list. + * This signals the application logic to start its refresh procedure. + * The application itself will have to set back this property to false when done. + */ + property bool refreshing: false + + /** + * type: bool + * If true the list supports the "pull down to refresh" behavior. + */ + property bool supportsRefreshing: false + + /** + * leftPadding: int + * default contents padding at left + */ + property int leftPadding: Units.gridUnit + + /** + * topPadding: int + * default contents padding at top + */ + property int topPadding: Units.gridUnit + + /** + * rightPadding: int + * default contents padding at right + */ + property int rightPadding: Units.gridUnit + + /** + * bottomPadding: int + * default contents padding at bottom + */ + property int bottomPadding: Units.gridUnit + + /** + * Set when this scrollview manages a whole page + */ + property Page page + + property Item _swipeFilter + + onRefreshingChanged: flickableItem.topMargin = topPadding + (refreshing ? busyIndicatorFrame.height : 0); + children: [ + Item { + id: busyIndicatorFrame + z: 99 + y: root.flickableItem.verticalLayoutDirection === ListView.BottomToTop + ? -root.flickableItem.contentY+height + : -root.flickableItem.contentY-height + width: root.flickableItem.width + height: busyIndicator.height + Units.gridUnit * 2 + QQC2.BusyIndicator { + id: busyIndicator + anchors.centerIn: parent + running: root.refreshing + visible: root.refreshing + //Android busywidget QQC seems to be broken at custom sizes + } + property int headerItemHeight: (root.flickableItem.headerItem + ? (root.flickableItem.headerItem.maximumHeight ? root.flickableItem.headerItem.maximumHeight : root.flickableItem.headerItem.height) + : 0) + Rectangle { + id: spinnerProgress + anchors { + fill: busyIndicator + margins: Math.ceil(Units.smallSpacing) + } + radius: width + visible: supportsRefreshing && !refreshing && progress > 0 + color: "transparent" + opacity: 0.8 + border.color: Theme.backgroundColor + border.width: Math.ceil(Units.smallSpacing) + //also take into account the listview header height if present + property real progress: supportsRefreshing && !refreshing ? ((parent.y - busyIndicatorFrame.headerItemHeight)/busyIndicatorFrame.height) : 0 + } + ConicalGradient { + source: spinnerProgress + visible: spinnerProgress.visible + anchors.fill: spinnerProgress + gradient: Gradient { + GradientStop { position: 0.00; color: Theme.highlightColor } + GradientStop { position: spinnerProgress.progress; color: Theme.highlightColor } + GradientStop { position: spinnerProgress.progress + 0.01; color: "transparent" } + GradientStop { position: 1.00; color: "transparent" } + } + } + + onYChanged: { + //it's overshooting enough and not reachable: start countdown for reachability + + if (y - busyIndicatorFrame.headerItemHeight > root.topPadding + Units.gridUnit && !applicationWindow().reachableMode) { + overshootResetTimer.running = true; + //not reachable and not overshooting enough, stop reachability countdown + } else if (typeof(applicationWindow) == "undefined" || !applicationWindow().reachableMode) { + //it's important it doesn't restart + overshootResetTimer.running = false; + } + + if (!supportsRefreshing) { + return; + } + + //also take into account the listview header height if present + if (!root.refreshing && y - busyIndicatorFrame.headerItemHeight > busyIndicatorFrame.height/2 + topPadding) { + refreshTriggerTimer.running = true; + } else { + refreshTriggerTimer.running = false; + } + } + Timer { + id: refreshTriggerTimer + interval: 500 + onTriggered: { + //also take into account the listview header height if present + if (!root.refreshing && parent.y - busyIndicatorFrame.headerItemHeight > busyIndicatorFrame.height/2 + topPadding) { + root.refreshing = true; + } + } + } + Connections { + enabled: typeof applicationWindow !== "undefined" + target: typeof applicationWindow !== "undefined" ? applicationWindow() : null + onReachableModeChanged: { + overshootResetTimer.running = applicationWindow().reachableMode; + } + } + Timer { + id: overshootResetTimer + interval: (typeof applicationWindow !== "undefined" && applicationWindow().reachableMode) ? 8000 : 2000 + onTriggered: { + //put it there because widescreen may have changed since timer start + if (!Settings.isMobile || (typeof applicationWindow !== "undefined" && applicationWindow().wideScreen) || root.flickableItem.verticalLayoutDirection === ListView.BottomToTop) { + return; + } + applicationWindow().reachableMode = !applicationWindow().reachableMode; + } + } + + Binding { + target: root.flickableItem + property: "flickableDirection" + value: Flickable.VerticalFlick + } + + Binding { + target: root.flickableItem + property: "bottomMargin" + value: root.page.bottomPadding + } + + Binding { + target: root.contentItem + property: "width" + value: root.flickableItem.width + } + } + ] + + onHeightChanged: { + if (!Window.window || height < 0) { + return; + } + var focusItem = Window.window.activeFocusItem; + + if (!focusItem) { + return; + } + + //NOTE: there is no function to know if an item is descended from another, + //so we have to walk the parent hierarchy by hand + var isDescendent = false; + var candidate = focusItem.parent; + while (candidate) { + if (candidate === root) { + isDescendent = true; + break; + } + candidate = candidate.parent; + } + if (!isDescendent) { + return; + } + + var cursorY = 0; + if (focusItem.cursorPosition !== undefined) { + cursorY = focusItem.positionToRectangle(focusItem.cursorPosition).y; + } + + var pos = focusItem.mapToItem(root.contentItem, 0, cursorY); + + //focused item already visible? add some margin for the space of the action buttons + if (pos.y >= root.flickableItem.contentY && pos.y <= root.flickableItem.contentY + root.flickableItem.height - Units.gridUnit * 8) { + return; + } + root.flickableItem.contentY = pos.y; + } + + Component.onCompleted: leftPaddingChanged() + onRightPaddingChanged: leftPaddingChanged() + onLeftPaddingChanged: { + //for gridviews do apply margins + if (root.contentItem == root.flickableItem) { + if (typeof root.flickableItem.cellWidth != "undefined") { + flickableItem.anchors.leftMargin = leftPadding; + flickableItem.anchors.rightMargin = rightPadding; + } else { + flickableItem.anchors.leftMargin = 0; + flickableItem.anchors.rightMargin = 0; + } + flickableItem.anchors.topMargin = 0; + flickableItem.anchors.bottomMargin = 0; + } else { + flickableItem.anchors.leftMargin = leftPadding; + flickableItem.anchors.topMargin = topPadding; + flickableItem.anchors.rightMargin = rightPadding; + flickableItem.anchors.bottomMargin = bottomPadding; + } + } +} diff --git a/src/controls/private/SwipeItemEventFilter.qml b/src/controls/private/SwipeItemEventFilter.qml new file mode 100644 index 0000000..db9ff3f --- /dev/null +++ b/src/controls/private/SwipeItemEventFilter.qml @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.4 + + +MouseArea { + id: swipeFilter + anchors { + right: parent.right + top: parent.top + bottom: parent.bottom + } + + z: 99999 + property Item currentItem + property real peek + + preventStealing: true + width: Units.gridUnit + onPressed: { + var mapped = mapToItem(parent.flickableItem.contentItem, mouse.x, mouse.y); + currentItem = parent.flickableItem.itemAt(mapped.x, mapped.y); + } + onPositionChanged: { + var mapped = mapToItem(parent.flickableItem.contentItem, mouse.x, mouse.y); + currentItem = parent.flickableItem.itemAt(mapped.x, mapped.y); + peek = 1 - mapped.x / parent.flickableItem.contentItem.width; + } +} diff --git a/src/controls/private/globaltoolbar/AbstractPageHeader.qml b/src/controls/private/globaltoolbar/AbstractPageHeader.qml new file mode 100644 index 0000000..779a6f0 --- /dev/null +++ b/src/controls/private/globaltoolbar/AbstractPageHeader.qml @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.5 + +AbstractApplicationHeader { + id: root + // anchors.fill: parent + property Item container + property bool current + + minimumHeight: pageRow.globalToolBar.minimumHeight + maximumHeight: pageRow.globalToolBar.maximumHeight + preferredHeight: pageRow.globalToolBar.preferredHeight + + separatorVisible: pageRow.globalToolBar.separatorVisible + + leftPadding: Math.min(Qt.application.layoutDirection == Qt.LeftToRight + ? Math.max(0, pageRow.ScenePosition.x - page.ScenePosition.x + pageRow.globalToolBar.leftReservedSpace) + : Math.max(0, -pageRow.width + pageRow.ScenePosition.x + page.ScenePosition.x + page.width + pageRow.globalToolBar.leftReservedSpace), + root.width/2) + + rightPadding: Qt.application.layoutDirection == Qt.LeftToRight + ? Math.max(0, -pageRow.width - pageRow.ScenePosition.x + page.ScenePosition.x + page.width + pageRow.globalToolBar.rightReservedSpace) + : Math.max(0, pageRow.ScenePosition.x - page.ScenePosition.x + pageRow.globalToolBar.rightReservedSpace) +} diff --git a/src/controls/private/globaltoolbar/BreadcrumbControl.qml b/src/controls/private/globaltoolbar/BreadcrumbControl.qml new file mode 100644 index 0000000..7bf2235 --- /dev/null +++ b/src/controls/private/globaltoolbar/BreadcrumbControl.qml @@ -0,0 +1,98 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + + + +Flickable { + id: root + + property Kirigami.PageRow pageRow: parent.pageRow + + contentHeight: height + contentWidth: mainLayout.width + clip: true + + Connections { + target: pageRow + onCurrentIndexChanged: { + var currentItem = mainLayout.children[pageRow.currentIndex]; + listScrollAnim.running = false + listScrollAnim.from = root.contentX; + listScrollAnim.to = Math.max( 0, + Math.min(currentItem.x + currentItem.width/2 - root.width/2, + root.contentWidth - root.width)) + listScrollAnim.running = true; + } + } + + RowLayout { + id: mainLayout + height: parent.height + Repeater { + id: mainRepeater + model: pageRow.depth + delegate: MouseArea { + Layout.preferredWidth: delegateLayout.implicitWidth + Layout.fillHeight: true + onClicked: pageRow.currentIndex = modelData; + RowLayout { + id: delegateLayout + anchors.fill: parent + readonly property Kirigami.Page page: pageRow.get(modelData) + spacing: 0 + + Kirigami.Icon { + visible: modelData > 0 + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: Kirigami.Units.iconSizes.small + Layout.preferredWidth: Layout.preferredHeight + isMask: true + color: Kirigami.Theme.textColor + source: LayoutMirroring.enabled ? "go-next-symbolic-rtl" : "go-next-symbolic" + } + Kirigami.Heading { + Layout.leftMargin: Kirigami.Units.largeSpacing + font.pointSize: -1 + font.pixelSize: Math.max(1, mainLayout.height * 0.6) + color: Kirigami.Theme.textColor + verticalAlignment: Text.AlignVCenter + wrapMode: Text.NoWrap + text: delegateLayout.page ? delegateLayout.page.title : "" + opacity: modelData == pageRow.currentIndex ? 1 : 0.4 + } + } + } + } + } + + NumberAnimation { + id: listScrollAnim + target: root + property: "contentX" + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } +} + + diff --git a/src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml b/src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml new file mode 100644 index 0000000..c1f53c6 --- /dev/null +++ b/src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 as Kirigami + +QtObject { + id: globalToolBar + property int style: Kirigami.ApplicationHeaderStyle.None + readonly property int actualStyle: { + if (style == Kirigami.ApplicationHeaderStyle.Auto) { + //Legacy: if ApplicationHeader or ToolbarApplicationHeader are in the header or footer, disable the toolbar here + if (typeof applicationWindow !== "undefined" && applicationWindow().header && applicationWindow().header.toString().indexOf("ApplicationHeader") !== -1) { + return Kirigami.ApplicationHeaderStyle.None + } + + //non legacy logic + return (Kirigami.Settings.isMobile + ? (root.wideMode ? Kirigami.ApplicationHeaderStyle.Titles : Kirigami.ApplicationHeaderStyle.Breadcrumb) + : Kirigami.ApplicationHeaderStyle.ToolBar) + } else { + //forbid ToolBar on mobile systems + return Kirigami.Settings.isMobile && style == Kirigami.ApplicationHeaderStyle.ToolBar ? Kirigami.ApplicationHeaderStyle.Breadcrumb : style; + } + } + + property bool showNavigationButtons: style != Kirigami.ApplicationHeaderStyle.TabBar && (!Kirigami.Settings.isMobile || Qt.platform.os == "ios") + property bool separatorVisible: true + + property int minimumHeight: 0 + property int preferredHeight: (actualStyle == Kirigami.ApplicationHeaderStyle.ToolBar + ? Kirigami.Units.iconSizes.medium + : Kirigami.Units.gridUnit * 1.8) + Kirigami.Units.smallSpacing * 2 + property int maximumHeight: preferredHeight +} diff --git a/src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml b/src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml new file mode 100644 index 0000000..8730643 --- /dev/null +++ b/src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml @@ -0,0 +1,104 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami +import "../../templates/private" as TemplatesPrivate + + +Kirigami.AbstractApplicationHeader { + id: header + readonly property int leftReservedSpace: buttonsLayout.visible && buttonsLayout.visibleChildren.length > 1 ? buttonsLayout.width : 0 + readonly property int rightReservedSpace: rightHandleAnchor.visible ? backButton.background.implicitHeight : 0 + + readonly property alias leftHandleAnchor: leftHandleAnchor + readonly property alias rightHandleAnchor: rightHandleAnchor + + height: visible ? implicitHeight : 0 + minimumHeight: globalToolBar.minimumHeight + preferredHeight: globalToolBar.preferredHeight + maximumHeight: globalToolBar.maximumHeight + separatorVisible: globalToolBar.separatorVisible + + RowLayout { + anchors.fill: parent + spacing: 0 + RowLayout { + id: buttonsLayout + Layout.fillHeight: true + + visible: globalToolBar.showNavigationButtons && globalToolBar.actualStyle != Kirigami.ApplicationHeaderStyle.None + + Item { + id: leftHandleAnchor + visible: typeof applicationWindow() !== "undefined" && applicationWindow().globalDrawer && applicationWindow().globalDrawer.enabled && applicationWindow().globalDrawer.handleVisible && + (applicationWindow().globalDrawer.handle.handleAnchor == (Qt.application.layoutDirection == Qt.LeftToRight ? leftHandleAnchor : rightHandleAnchor)) + Layout.fillHeight: true + Layout.preferredWidth: height + } + TemplatesPrivate.BackButton { + id: backButton + Layout.leftMargin: leftHandleAnchor.visible ? 0 : Kirigami.Units.smallSpacing + Layout.fillHeight: true + Layout.preferredWidth: height + } + TemplatesPrivate.ForwardButton { + Layout.fillHeight: true + Layout.preferredWidth: height + } + Kirigami.Separator { + Layout.preferredHeight: parent.parent.height * 0.6 + //FIXME: hacky + opacity: buttonsLayout.visibleChildren.length > 1 + } + } + Loader { + id: breadcrumbLoader + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: -1 + Layout.preferredHeight: -1 + property Kirigami.PageRow pageRow: root + + opacity: pageRow.layers.depth < 2 + active: globalToolBar.actualStyle == Kirigami.ApplicationHeaderStyle.TabBar || globalToolBar.actualStyle == Kirigami.ApplicationHeaderStyle.Breadcrumb + + //TODO: different implementation? + source: globalToolBar.actualStyle == Kirigami.ApplicationHeaderStyle.TabBar ? Qt.resolvedUrl("TabBarControl.qml") : Qt.resolvedUrl("BreadcrumbControl.qml") + + Behavior on opacity { + OpacityAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + Item { + id: rightHandleAnchor + visible: typeof applicationWindow() !== "undefined" && applicationWindow().contextDrawer && + applicationWindow().contextDrawer.enabled && + applicationWindow().contextDrawer.handleVisible && (applicationWindow().contextDrawer.handle.handleAnchor == (Qt.application.layoutDirection == Qt.LeftToRight ? rightHandleAnchor : leftHandleAnchor)) + Layout.fillHeight: true + Layout.preferredWidth: height + } + } + background.opacity: pageRow.layers.depth < 2 && breadcrumbLoader.active +} + diff --git a/src/controls/private/globaltoolbar/TabBarControl.qml b/src/controls/private/globaltoolbar/TabBarControl.qml new file mode 100644 index 0000000..f4fd5ed --- /dev/null +++ b/src/controls/private/globaltoolbar/TabBarControl.qml @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 as Kirigami + + +Controls.TabBar { + id: root + property Kirigami.PageRow pageRow: parent.pageRow + + Repeater { + id: mainRepeater + model: pageRow.depth + delegate: Controls.TabButton { + width: mainRepeater.count == 1 ? implicitWidth : Math.max(implicitWidth, root.width/mainRepeater.count) + height: root.height + readonly property Kirigami.Page page: pageRow.get(modelData) + text: page ? page.title : "" + checked: modelData == pageRow.currentIndex + onClicked: pageRow.currentIndex = modelData; + } + } +} diff --git a/src/controls/private/globaltoolbar/TitlesPageHeader.qml b/src/controls/private/globaltoolbar/TitlesPageHeader.qml new file mode 100644 index 0000000..ee7fbb5 --- /dev/null +++ b/src/controls/private/globaltoolbar/TitlesPageHeader.qml @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 + + + +AbstractPageHeader { + id: root + + Heading { + id: title + anchors.fill: parent + leftPadding: Units.largeSpacing + opacity: root.current ? 1 : 0.4 + maximumLineCount: 1 + verticalAlignment: Text.AlignVCenter + color: Theme.textColor + elide: Text.ElideRight + font.pointSize: -1 + font.pixelSize: Math.max(1, height*0.6) + text: page ? page.title : "" + MouseArea { + anchors.fill: parent + onClicked: page.forceActiveFocus() + } + } +} + diff --git a/src/controls/private/globaltoolbar/ToolBarPageHeader.qml b/src/controls/private/globaltoolbar/ToolBarPageHeader.qml new file mode 100644 index 0000000..f21b88e --- /dev/null +++ b/src/controls/private/globaltoolbar/ToolBarPageHeader.qml @@ -0,0 +1,120 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.2 +import org.kde.kirigami 2.4 +import "../" as Private + + +AbstractPageHeader { + id: root + + implicitWidth: titleTextMetrics.width/2 + buttonTextMetrics.collapsedButtonsWidth + Layout.minimumWidth: ctxActionsButton.width*4 + + MouseArea { + anchors.fill: parent + onClicked: page.forceActiveFocus() + } + RowLayout { + id: titleLayout + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + right: actionsLayout.left + } + + Heading { + id: title + level: 1 + Layout.fillWidth: true + + Layout.preferredWidth: implicitWidth + Layout.minimumWidth: Math.min(titleTextMetrics.width, root.width - buttonTextMetrics.requiredWidth) + leftPadding: Units.largeSpacing + opacity: root.current ? 1 : 0.4 + maximumLineCount: 1 + color: Theme.textColor + elide: Text.ElideRight + text: page ? page.title : "" + } + } + + TextMetrics { + id: titleTextMetrics + text: page ? page.title : "" + font: title.font + } + TextMetrics { + id: buttonTextMetrics + text: (page.actions.left ? page.actions.left.text : "") + (page.actions.main ? page.actions.main.text : "") + (page.actions.right ? page.actions.right.text : "") + readonly property int collapsedButtonsWidth: ctxActionsButton.width + (page.actions.left ? ctxActionsButton.width + Units.gridUnit : 0) + (page.actions.main ? ctxActionsButton.width + Units.gridUnit : 0) + (page.actions.right ? ctxActionsButton.width + Units.gridUnit : 0) + readonly property int requiredWidth: width + collapsedButtonsWidth + } + + RowLayout { + id: actionsLayout + anchors { + verticalCenter: parent.verticalCenter + right: ctxActionsButton.visible ? ctxActionsButton.left : parent.right + } + + readonly property bool toobig: root.width - root.leftPadding - root.rightPadding - titleTextMetrics.width - Units.gridUnit < buttonTextMetrics.requiredWidth + + Private.PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + kirigamiAction: page && page.actions ? page.actions.left : null + showText: !parent.toobig + } + Private.PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: Units.smallSpacing + kirigamiAction: page && page.actions ? page.actions.main : null + showText: !parent.toobig + flat: false + } + Private.PrivateActionToolButton { + Layout.alignment: Qt.AlignVCenter + kirigamiAction: page && page.actions ? page.actions.right : null + showText: !parent.toobig + } + } + + Private.PrivateActionToolButton { + id: ctxActionsButton + showMenuArrow: page.actions.contextualActions.length == 1 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: Units.smallSpacing + } + Action { + id: overflowAction + icon.name: "overflow-menu" + tooltip: qsTr("More Actions") + visible: children.length > 0 + children: page && page.actions.contextualActions ? page.actions.contextualActions : null + } + + kirigamiAction: page && page.actions.contextualActions.length === 1 ? page.actions.contextualActions[0] : overflowAction + } +} + diff --git a/src/controls/qmldir b/src/controls/qmldir new file mode 100644 index 0000000..a64b286 --- /dev/null +++ b/src/controls/qmldir @@ -0,0 +1,7 @@ +module org.kde.kirigami +plugin kirigamiplugin +classname KirigamiPlugin +depends QtQuick.Controls 2.0 +depends QtGraphicalEffects 1.0 +designersupported + diff --git a/src/controls/templates/AbstractApplicationHeader.qml b/src/controls/templates/AbstractApplicationHeader.qml new file mode 100644 index 0000000..dd157b7 --- /dev/null +++ b/src/controls/templates/AbstractApplicationHeader.qml @@ -0,0 +1,207 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import "private" +import org.kde.kirigami 2.4 + + +/** + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * minimumHeight: default is 0, i.e. hidden + * * preferredHeight: default is Units.gridUnit * 1.6 + * * preferredHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + * @inherit QtQuick.Item + */ +Item { + id: root + z: 90 + property int minimumHeight: 0 + property int preferredHeight: Units.gridUnit * 2 + property int maximumHeight: Units.gridUnit * 3 + + property PageRow pageRow: __appWindow.pageStack + property Page page: pageRow.currentItem + + default property alias contentItem: mainItem.data + readonly property int paintedHeight: headerItem.y + headerItem.height - 1 + + property int leftPadding: 0 + property int topPadding: 0 + property int rightPadding: 0 + property int bottomPadding: 0 + property bool separatorVisible: true + + LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + //FIXME: remove + property QtObject __appWindow: applicationWindow(); + + anchors { + left: parent.left + right: parent.right + } + implicitHeight: preferredHeight + + /** + * background: Item + * This property holds the background item. + * Note: the background will be automatically sized as the whole control + */ + property Item background + + onBackgroundChanged: { + background.z = -1; + background.parent = headerItem; + background.anchors.fill = headerItem; + } + + onMinimumHeightChanged: implicitHeight = preferredHeight; + onPreferredHeightChanged: implicitHeight = preferredHeight; + + opacity: height > 0 ? 1 : 0 + + NumberAnimation { + id: heightAnim + target: root + property: "implicitHeight" + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + Connections { + target: __appWindow + onControlsVisibleChanged: { + heightAnim.from = root.implicitHeight + heightAnim.to = __appWindow.controlsVisible ? root.preferredHeight : 0; + heightAnim.restart(); + } + } + + Item { + id: headerItem + property real computedRootHeight: root.preferredHeight + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + + height: __appWindow.reachableMode && __appWindow.reachableModeEnabled ? root.maximumHeight : (root.minimumHeight > 0 ? Math.max(root.height, root.minimumHeight) : root.preferredHeight) + + //FIXME: see FIXME below + Connections { + target: root.page ? root.page.globalToolBarItem : null + enabled: headerSlideConnection.passive && target + onImplicitHeightChanged: root.implicitHeight = root.page.globalToolBarItem.implicitHeight + } + + Connections { + id: headerSlideConnection + target: root.page ? root.page.flickable : null + enabled: !passive + property int oldContentY + property bool updatingContentY: false + + //FIXME HACK: if we are in global mode, meaning if we are the toolbar showing the global breadcrumb (but the pages are showing their own toolbar), not to try to mess with page contentY. + //A better solution is needed + readonly property bool passive: root.pageRow && parent.parent == root.pageRow && root.pageRow.globalToolBar.actualStyle !== ApplicationHeaderStyle.TabBar && root.pageRow.globalToolBar.actualStyle != ApplicationHeaderStyle.Breadcrumb + + onContentYChanged: { + if (updatingContentY || !Settings.isMobile || + !__appWindow.controlsVisible || + !root.page || + root.page.flickable.atYBeginning || + root.page.flickable.atYEnd) { + oldContentY = root.page.flickable.contentY; + return; + //TODO: merge + //if moves but not dragging, just update oldContentY + } else if (!root.page.flickable.dragging) { + oldContentY = root.page.flickable.contentY; + return; + } + + if ((root.pageRow ? root.pageRow.wideMode : __appWindow.wideScreen) || !Settings.isMobile) { + root.implicitHeight = root.preferredHeight; + } else { + var oldHeight = root.implicitHeight; + + root.implicitHeight = Math.max(root.minimumHeight, + Math.min(root.preferredHeight, + root.implicitHeight + oldContentY - root.page.flickable.contentY)); + + //if the implicitHeight is changed, use that to simulate scroll + if (oldHeight !== implicitHeight) { + updatingContentY = true; + root.page.flickable.contentY -= (oldHeight - root.implicitHeight); + updatingContentY = false; + } else { + oldContentY = root.page.flickable.contentY; + } + + } + } + onMovementEnded: { + if ((root.pageRow ? root.pageRow.wideMode : __appWindow.wideScreen) || !Settings.isMobile) { + return; + } + if (root.height > root.minimumHeight + (root.preferredHeight - root.minimumHeight)/2 ) { + root.implicitHeight = root.preferredHeight; + } else { + root.implicitHeight = root.minimumHeight; + } + } + } + Connections { + target: pageRow + onCurrentItemChanged: { + if (!root.page) { + return; + } + if (root.page.flickable) { + headerSlideConnection.oldContentY = root.page.flickable.contentY; + } else { + headerSlideConnection.oldContentY = 0; + } + + root.implicitHeight = root.preferredHeight; + } + } + + Item { + id: mainItem + clip: childrenRect.width > width + anchors { + fill: parent + leftMargin: root.leftPadding + topMargin: root.topPadding + rightMargin: root.rightPadding + bottomMargin: root.bottomPadding + } + } + } +} + diff --git a/src/controls/templates/AbstractCard.qml b/src/controls/templates/AbstractCard.qml new file mode 100644 index 0000000..9f670f3 --- /dev/null +++ b/src/controls/templates/AbstractCard.qml @@ -0,0 +1,165 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.6 +import QtQuick.Layouts 1.2 +import QtQuick.Templates 2.0 as T +import org.kde.kirigami 2.4 as Kirigami + +/** + * A AbstractCard is the base for cards. A Card is a visual object that serves + * as an entry point for more detailed information. An abstractCard is empty, + * providing just the look and the base properties and signals for an ItemDelegate. + * It can be filled with any custom layout of items, its content is organized + * in 3 properties: header, contentItem and footer. + * Use this only when you need particular custom contents, for a standard layout + * for cards, use the Card component. + * + * @see Card + * @inherits QtQuick.Templates.ItemDelegate + * @since 2.4 + */ +T.ItemDelegate { + id: root + + /** + * header: Item + * This item serves as header, it will be put either on top if headerOrientation + * is Qt.Vertical(default) or on the left if it's Qt.Horizontal + */ + property Item header + + /** + * headerOrientation: Qt.Orientation + * If Qt.Vertical the header will be positioned on top(default), + * if Qt.Horizontal will be positioned on the left (or right if an RTL layout is used) + */ + property int headerOrientation: Qt.Vertical + + /** + * footer: Item + * This item serves as footer, and it will be positioned at the bottom of the card. + */ + property Item footer + + /** + * showClickFeedback: bool + * if true, when clicking or tapping on the card area, the card will be colored + * to show a visual click feedback. + * Use this if you want to do an action in the onClicked signal handler of the card. + */ + property bool showClickFeedback: false + + Layout.fillWidth: true + + implicitWidth: Math.max(background.implicitWidth, mainLayout.implicitWidth) + leftPadding + rightPadding + + implicitHeight: mainLayout.implicitHeight + topPadding + bottomPadding + + hoverEnabled: !Kirigami.Settings.tabletMode && showClickFeedback + //if it's in a CardLayout, try to expand horizontal cards to both columns + Layout.columnSpan: headerOrientation == Qt.Horizontal && parent.hasOwnProperty("columns") ? parent.columns : 1 + + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.View + + topPadding: Kirigami.Units.largeSpacing + leftPadding: Kirigami.Units.largeSpacing + bottomPadding: Kirigami.Units.largeSpacing + rightPadding: Kirigami.Units.largeSpacing + + GridLayout { + id: mainLayout + rowSpacing: root.topPadding + columnSpacing: root.leftPadding + anchors { + top: parent.top + left: parent.left + right: parent.right + leftMargin: root.leftPadding + topMargin: root.topPadding + rightMargin: root.rightPadding + //never anchor bottom, to not have binding loops + } + columns: headerOrientation == Qt.Vertical ? 1 : 2 + function preferredHeight(item) { + if (!item) { + return 0; + } + if (item.Layout.preferredHeight > 0) { + return item.Layout.preferredHeight; + } + return item.implicitHeight + } + Item { + id: headerParent + Layout.fillWidth: true + Layout.fillHeight: root.headerOrientation == Qt.Horizontal + Layout.rowSpan: root.headerOrientation == Qt.Vertical ? 1 : 2 + Layout.preferredWidth: header ? header.implicitWidth : 0 + Layout.preferredHeight: root.headerOrientation == Qt.Vertical ? mainLayout.preferredHeight(header) : -1 + } + Item { + id: contentItemParent + Layout.fillWidth: true + Layout.preferredWidth: contentItem ? contentItem.implicitWidth : 0 + Layout.preferredHeight: mainLayout.preferredHeight(contentItem) + } + Item { + id: footerParent + Layout.fillWidth: true + Layout.preferredWidth: footer ? footer.implicitWidth : 0 + Layout.preferredHeight: mainLayout.preferredHeight(footer) + } + } + +//BEGIN signal handlers + onContentItemChanged: { + if (!contentItem) { + return; + } + + contentItem.parent = contentItemParent; + contentItem.anchors.fill = contentItemParent; + } + onHeaderChanged: { + if (!header) { + return; + } + + header.parent = headerParent; + header.anchors.fill = headerParent; + } + onFooterChanged: { + if (!footer) { + return; + } + + //make the footer always looking it's at the bottom of the card + footer.parent = footerParent; + footer.anchors.left = footerParent.left; + footer.anchors.top = footerParent.top; + footer.anchors.right = footerParent.right; + footer.anchors.topMargin = Qt.binding(function() {return (root.height - root.bottomPadding - root.topPadding) - (footerParent.y + footerParent.height)}); + } + Component.onCompleted: { + contentItemChanged(); + } +//END signal handlers +} diff --git a/src/controls/templates/AbstractListItem.qml b/src/controls/templates/AbstractListItem.qml new file mode 100644 index 0000000..3de5b9b --- /dev/null +++ b/src/controls/templates/AbstractListItem.qml @@ -0,0 +1,129 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.4 +import QtQuick.Templates 2.0 as T2 + +/** + * An item delegate for the primitive ListView component. + * + * It's intended to make all listviews look coherent. + * + * @inherit QtQuick.Templates.ItemDelegate + */ +T2.ItemDelegate { + id: listItem + + /** + * supportsMouseEvents: bool + * Holds if the item emits signals related to mouse interaction. + *TODO: remove + * The default value is false. + */ + property bool supportsMouseEvents: hoverEnabled + + /** + * containsMouse: bool + * True when the user hovers the mouse over the list item + * NOTE: on mobile touch devices this will be true only when pressed is also true + * TODO: remove? + */ + property alias containsMouse: listItem.hovered + + /** + * sectionDelegate: bool + * If true the item will be a delegate for a section, so will look like a + * "title" for the items under it. + */ + property bool sectionDelegate: false + + /** + * separatorVisible: bool + * True if the separator between items is visible + * default: true + */ + property bool separatorVisible: true + + /** + * textColor: color + * Color for the text in the item + * It is advised to leave the default value (Theme.textColor) + * + * Note: if custom text elements are inserted in an AbstractListItem, + * their color property will have to be manually bound with this property + */ + property color textColor: Theme.textColor + + /** + * backgroundColor: color + * Color for the background of the item + * It is advised to leave the default value (Theme.viewBackgroundColor) + */ + property color backgroundColor: "transparent" + + /** + * activeTextColor: color + * Color for the text in the item when pressed or selected + * It is advised to leave the default value (Theme.highlightedTextColor) + * + * Note: if custom text elements are inserted in an AbstractListItem, + * their color property will have to be manually bound with this property + */ + property color activeTextColor: Theme.highlightedTextColor + + /** + * activeBackgroundColor: color + * Color for the background of the item when pressed or selected + * It is advised to leave the default value (Theme.highlightColor) + */ + property color activeBackgroundColor: Theme.highlightColor + + default property alias _default: listItem.contentItem + + Theme.colorGroup: internal.indicateActiveFocus ? Theme.Active : Theme.Inactive + + leftPadding: LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical && internal.view.T2.ScrollBar.vertical.visible ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing + topPadding: Units.largeSpacing + + rightPadding: !LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical && internal.view.T2.ScrollBar.vertical.visible ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing + bottomPadding: Units.largeSpacing + + implicitWidth: contentItem ? contentItem.implicitWidth : Units.gridUnit * 12 + + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 5 + + width: parent && parent.width > 0 ? parent.width : implicitWidth + Layout.fillWidth: true + + opacity: enabled ? 1 : 0.6 + + height: visible ? implicitHeight : 0 + + hoverEnabled: true + + QtObject { + id: internal + property Flickable view: listItem.ListView.view || (listItem.parent ? listItem.parent.ListView.view : null) + property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (view ? view.activeFocus : false) + } + + Accessible.role: Accessible.ListItem +} diff --git a/src/controls/templates/ApplicationHeader.qml b/src/controls/templates/ApplicationHeader.qml new file mode 100644 index 0000000..2f99056 --- /dev/null +++ b/src/controls/templates/ApplicationHeader.qml @@ -0,0 +1,392 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as QQC2 +import QtQuick.Layouts 1.2 +import "private" +import org.kde.kirigami 2.4 + + +/** + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * minimumHeight: default is 0, i.e. hidden + * * preferredHeight: default is Units.gridUnit * 1.6 + * * maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + */ +AbstractApplicationHeader { + id: header + + /** + * headerStyle: int + * The way the separator between pages should be drawn in the header. + * Allowed values are: + * * Breadcrumb: the pages are hierarchical and the separator will look like a > + * * TabBar: the pages are intended to behave like tabbar pages + * and the separator will look limke a dot. + * + * When the header is in wide screen mode, no separator will be drawn. + */ + property int headerStyle: ApplicationHeaderStyle.Auto + + /** + * backButtonEnabled: bool + * if true, there will be a back button present that will make the pagerow scroll back when clicked + */ + property bool backButtonEnabled: (!titleList.isTabBar && (!Settings.isMobile || Qt.platform.os == "ios")) + + onBackButtonEnabledChanged: { + if (backButtonEnabled && !titleList.backButton) { + var component = Qt.createComponent(Qt.resolvedUrl("private/BackButton.qml")); + titleList.backButton = component.createObject(navButtons); + component = Qt.createComponent(Qt.resolvedUrl("private/ForwardButton.qml")); + titleList.forwardButton = component.createObject(navButtons, {"headerFlickable": titleList}); + } else if (titleList.backButton) { + titleList.backButton.destroy(); + titleList.forwardButton.destroy(); + } + } + property Component pageDelegate: Component { + Row { + height: parent.height + + spacing: Units.smallSpacing + + x: Units.smallSpacing + + Icon { + //in tabbar mode this is just a spacer + visible: !titleList.wideMode && ((typeof(modelData) != "undefined" && modelData > 0) || titleList.internalHeaderStyle == ApplicationHeaderStyle.TabBar) + anchors.verticalCenter: parent.verticalCenter + height: Units.iconSizes.small + width: height + selected: header.background && header.background.color && header.background.color === Theme.highlightColor + source: titleList.isTabBar ? "" : (LayoutMirroring.enabled ? "go-next-symbolic-rtl" : "go-next-symbolic") + } + + Heading { + id: title + width: Math.min(parent.width, Math.min(titleList.width, implicitWidth)) + Units.smallSpacing + anchors.verticalCenter: parent.verticalCenter + opacity: current ? 1 : 0.4 + //Scaling animate NativeRendering is too slow + renderType: Text.QtRendering + color: header.background && header.background.color && header.background.color === Theme.highlightColor ? Theme.highlightedTextColor : Theme.textColor + elide: Text.ElideRight + text: page ? page.title : "" + font.pointSize: -1 + font.pixelSize: Math.max(1, titleList.height * 0.7) + verticalAlignment: Text.AlignVCenter + wrapMode: Text.NoWrap + Rectangle { + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: Units.smallSpacing + color: title.color + opacity: 0.6 + visible: titleList.isTabBar && current + } + } + } + } + + Component.onCompleted: print("Warning: ApplicationHeader is deprecated, remove and use the automatic internal toolbar instead.") + + Rectangle { + anchors { + right: titleList.left + verticalCenter: parent.verticalCenter + } + visible: titleList.x > 0 && !titleList.atXBeginning + height: parent.height * 0.7 + color: Theme.highlightedTextColor + width: Math.ceil(Units.smallSpacing / 6) + opacity: 0.4 + } + + QQC2.StackView { + id: stack + anchors { + fill: parent + leftMargin: navButtons.width + rightMargin: __appWindow.contextDrawer && __appWindow.contextDrawer.handleVisible && __appWindow.contextDrawer.handle && __appWindow.contextDrawer.handle.y == 0 ? __appWindow.contextDrawer.handle.width : 0 + } + initialItem: titleList + + popEnter: Transition { + YAnimator { + from: -height + to: 0 + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + popExit: Transition { + YAnimator { + from: 0 + to: height + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + + pushEnter: Transition { + YAnimator { + from: height + to: 0 + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + + pushExit: Transition { + YAnimator { + from: 0 + to: -height + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + + replaceEnter: Transition { + YAnimator { + from: height + to: 0 + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + + replaceExit: Transition { + YAnimator { + from: 0 + to: -height + duration: Units.longDuration + easing.type: Easing.OutCubic + } + } + } + Separator { + id: separator + height: parent.height * 0.6 + visible: navButtons.width > 0 + anchors { + verticalCenter: parent.verticalCenter + left: navButtons.right + } + } + Separator { + height: parent.height * 0.6 + visible: stack.anchors.rightMargin > 0 + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: stack.anchors.rightMargin + } + } + Repeater { + model: pageRow.layers.depth -1 + delegate: Loader { + sourceComponent: header.pageDelegate + readonly property Page page: pageRow.layers.get(modelData+1) + readonly property bool current: true; + Component.onCompleted: stack.push(this) + Component.onDestruction: stack.pop() + } + } + + Row { + id: navButtons + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + topMargin: Units.smallSpacing + bottomMargin: Units.smallSpacing + } + Item { + height: parent.height + width: (applicationWindow().header && applicationWindow().header.toString().indexOf("ToolBarApplicationHeader") === 0) && __appWindow.globalDrawer && __appWindow.globalDrawer.handleVisible && __appWindow.globalDrawer.handle && __appWindow.globalDrawer.handle.y === 0 ? __appWindow.globalDrawer.handle.width : 0 + } + } + + Flickable { + id: titleList + readonly property bool wideMode: pageRow.hasOwnProperty("wideMode") ? pageRow.wideMode : __appWindow.wideScreen + property int internalHeaderStyle: header.headerStyle == ApplicationHeaderStyle.Auto ? (titleList.wideMode ? ApplicationHeaderStyle.Titles : ApplicationHeaderStyle.Breadcrumb) : header.headerStyle + //if scrolling the titlebar should scroll also the pages and vice versa + property bool scrollingLocked: (header.headerStyle == ApplicationHeaderStyle.Titles || titleList.wideMode) + //uses this to have less strings comparisons + property bool scrollMutex + property bool isTabBar: header.headerStyle == ApplicationHeaderStyle.TabBar + + property Item backButton + property Item forwardButton + clip: true + + + boundsBehavior: Flickable.StopAtBounds + readonly property alias model: mainRepeater.model + contentWidth: contentItem.width + contentHeight: height + + readonly property int currentIndex: pageRow && pageRow.currentIndex !== undefined ? pageRow.currentIndex : 0 + readonly property int count: mainRepeater.count + + function gotoIndex(idx) { + //don't actually scroll in widescreen mode + if (titleList.wideMode || contentItem.children.length < 2) { + return; + } + listScrollAnim.running = false + var pos = titleList.contentX; + var destPos; + titleList.contentX = Math.max((contentItem.children[idx].x + contentItem.children[idx].width) - titleList.width, Math.min(titleList.contentX, contentItem.children[idx].x)); + destPos = titleList.contentX; + listScrollAnim.from = pos; + listScrollAnim.to = destPos; + listScrollAnim.running = true; + } + + NumberAnimation { + id: listScrollAnim + target: titleList + property: "contentX" + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + Timer { + id: contentXSyncTimer + interval: 0 + onTriggered: { + titleList.contentX = pageRow.contentItem.contentX - pageRow.contentItem.originX + titleList.originX; + } + } + onCountChanged: contentXSyncTimer.restart(); + onCurrentIndexChanged: gotoIndex(currentIndex); + onModelChanged: gotoIndex(currentIndex); + onContentWidthChanged: gotoIndex(currentIndex); + + onContentXChanged: { + if (movingHorizontally && !titleList.scrollMutex && titleList.scrollingLocked && !pageRow.contentItem.moving) { + titleList.scrollMutex = true; + pageRow.contentItem.contentX = titleList.contentX - titleList.originX + pageRow.contentItem.originX; + titleList.scrollMutex = false; + } + } + onHeightChanged: { + titleList.returnToBounds() + } + onMovementEnded: { + if (titleList.scrollingLocked) { + //this will trigger snap as well + pageRow.contentItem.flick(0,0); + } + } + onFlickEnded: movementEnded(); + + NumberAnimation { + id: scrollTopAnimation + target: pageRow.currentItem && pageRow.currentItem.flickable ? pageRow.currentItem.flickable : null + property: "contentY" + to: 0 + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + + Row { + id: contentItem + spacing: 0 + Repeater { + id: mainRepeater + model: pageRow.depth + delegate: MouseArea { + id: delegate + readonly property int currentIndex: index + readonly property var currentModelData: modelData + clip: true + + width: { + //more columns shown? + if (titleList.scrollingLocked && delegateLoader.page) { + return delegateLoader.page.width - (index == 0 ? navButtons.width : 0) - (index == pageRow.depth-1 ? stack.anchors.rightMargin : 0); + } else { + return Math.min(titleList.width, delegateLoader.implicitWidth + Units.smallSpacing); + } + } + + height: titleList.height + onClicked: { + if (pageRow.currentIndex === modelData) { + //scroll up if current otherwise make current + if (!pageRow.currentItem.flickable) { + return; + } + if (pageRow.currentItem.flickable.contentY > -__appWindow.header.height) { + scrollTopAnimation.to = -pageRow.currentItem.flickable.topMargin; + scrollTopAnimation.running = true; + } + + } else { + pageRow.currentIndex = modelData; + } + } + + Loader { + id: delegateLoader + height: parent.height + x: titleList.wideMode || headerStyle == ApplicationHeaderStyle.Titles ? (Math.min(delegate.width - implicitWidth, Math.max(0, titleList.contentX - delegate.x))) : 0 + width: parent.width - x + + Connections { + target: delegateLoader.page + Component.onDestruction: delegateLoader.sourceComponent = null + } + + sourceComponent: header.pageDelegate + + readonly property Page page: pageRow.get(modelData) + //NOTE: why not use ListViewCurrentIndex? because listview itself resets + //currentIndex in some situations (since here we are using an int as a model, + //even more often) so the property binding gets broken + readonly property bool current: pageRow.currentIndex === index + readonly property int index: parent.currentIndex + readonly property var modelData: parent.currentModelData + } + } + } + } + Connections { + target: titleList.scrollingLocked ? pageRow.contentItem : null + onContentXChanged: { + if (!titleList.dragging && !titleList.movingHorizontally && !titleList.scrollMutex) { + titleList.contentX = pageRow.contentItem.contentX - pageRow.contentItem.originX + titleList.originX; + } + } + } + } +} diff --git a/src/controls/templates/InlineMessage.qml b/src/controls/templates/InlineMessage.qml new file mode 100644 index 0000000..cec0bbd --- /dev/null +++ b/src/controls/templates/InlineMessage.qml @@ -0,0 +1,135 @@ +/* + * Copyright 2018 Eike Hein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Templates 2.0 as T2 +import org.kde.kirigami 2.4 as Kirigami +import "private" + +/** + * An inline message item with support for informational, positive, + * warning and error types, and with support for associated actions. + * + * InlineMessage can be used to give information to the user or + * interact with the user, without requiring the use of a dialog. + * + * The InlineMessage item is hidden by default. It also manages its + * height (and implicitHeight) during an animated reveal when shown. + * You should avoid setting height on an InlineMessage unless it is + * already visible. + * + * Optionally an icon can be set, defaulting to an icon appropriate + * to the message type otherwise. + * + * Optionally a close button can be shown. + * + * Actions are added from left to right. If more actions are set than + * can fit, an overflow menu is provided. + * + * Example: + * @code + * InlineMessage { + * type: Kirigami.MessageType.Error + * + * text: "My error message" + * + * actions: [ + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * }, + * Kirigami.Action { + * iconName: "edit" + * text: "Action text" + * onTriggered: { + * // do stuff + * } + * } + * ] + * } + * @endcode + * + * @since 5.45 + */ + +T2.Control { + id: root + + visible: false + + /** + * Emitted when a link is hovered in the message text. + * @param The hovered link. + */ + signal linkHovered(string link) + + /** + * Emitted when a link is clicked or tapped in the message text. + * @param The clicked or tapped link. + */ + signal linkActivated(string link) + + /** + * type: int + * The message type. One of Information, Positive, Warning or Error. + * + * The default is Kirigami.MessageType.Information. + */ + property int type: Kirigami.MessageType.Information + + /** + * A grouped property describing an optional icon. + * * source: The source of the icon, a freedesktop-compatible icon name is recommended. + * * color: An optional tint color for the icon. + * + * If no custom icon is set, an icon appropriate to the message type + * is shown. + */ + property IconPropertiesGroup icon: IconPropertiesGroup {} + + /** + * text: string + * The message text. + */ + property string text + + /** + * showCloseButton: bool + * When enabled, a close button is shown. + * The default is false. + */ + property bool showCloseButton: false + + /** + * actions: list + * The list of actions to show. Actions are added from left to + * right. If more actions are set than can fit, an overflow menu is + * provided. + */ + property list actions + + /** + * animating: bool + * True while the message item is animating. + */ + readonly property bool animating: hasOwnProperty("_animating") && _animating +} diff --git a/src/controls/templates/OverlayDrawer.qml b/src/controls/templates/OverlayDrawer.qml new file mode 100644 index 0000000..21b72e6 --- /dev/null +++ b/src/controls/templates/OverlayDrawer.qml @@ -0,0 +1,484 @@ +/* + * Copyright 2012 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Templates 2.0 as T2 +import org.kde.kirigami 2.5 +import "private" + +/** + * Overlay Drawers are used to expose additional UI elements needed for + * small secondary tasks for which the main UI elements are not needed. + * For example in Okular Active, an Overlay Drawer is used to display + * thumbnails of all pages within a document along with a search field. + * This is used for the distinct task of navigating to another page. + * @inherits: QtQuick.Templates.Drawer + */ +T2.Drawer { + id: root + + z: modal ? (Math.round((position * 100) / 10) ): 1000000 + +//BEGIN Properties + /** + * drawerOpen: bool + * true when the drawer is open and visible + */ + property bool drawerOpen: false + + /** + * enabled: bool + * This property holds whether the item receives mouse and keyboard events. By default this is true. + */ + property bool enabled: true + + /** + * peeking: true + * When true the drawer is in a state between open and closed. the drawer is visible but not completely open. + * This is usually the case when the user is dragging the drawer from a screen + * edge, so the user is "peeking" what's in the drawer + */ + property bool peeking: false + + /** + * animating: Bool + * True during an animation of a drawer either opening or closing + */ + readonly property bool animating : enterAnimation.animating || exitAnimation.animating || positionResetAnim.running + + /** + * collapsible: Bool + * When true, the drawer can be collapsed to a very thin, usually icon only sidebar. + * Only modal drawers are collapsible. + * Collapsible is not supported in Mobile mode + * @since 2.5 + */ + property bool collapsible: false + + /** + * collapsed: bool + * When true, the drawer will be collapsed to a very thin sidebar, + * usually icon only. + * Only collapsible drawers can be collapsed + */ + property bool collapsed: false + + /** + * collapsedSize: int + * When collapsed, the drawer will be resized to this size + * (which may be width for vertical drawers or height for + * horizontal drawers). + * By default it's just enough to accommodate medium sized icons + */ + property int collapsedSize: Units.iconSizes.medium + + /** + * A grouped property describing an optional icon. + * * source: The source of the icon, a freedesktop-compatible icon name is recommended. + * * color: An optional tint color for the icon. + * + * If no custom icon is set, a menu icon is shown for the application globalDrawer + * and an overflow menu icon is shown for the contextDrawer. + * That's the default for the GlobalDrawer and ContextDrawer components respectively. + * + * For OverlayDrawer the default is view-right-close or view-left-close depending on the drawer location + * @since 2.5 + */ + readonly property QtObject handleOpenIcon: IconPropertiesGroup {source: root.edge === Qt.RightEdge ? "view-right-close" : "view-left-close"} + + /** + * A grouped property describing an optional icon. + * * source: The source of the icon, a freedesktop-compatible icon name is recommended. + * * color: An optional tint color for the icon. + * + * If no custom icon is set, an X icon is shown, + * which will morph into the Menu or overflow icons + * + * For OverlayDrawer the default is view-right-new or view-left-new depending on the drawer location + * @since 2.5 + */ + readonly property QtObject handleClosedIcon: IconPropertiesGroup {source: root.edge === Qt.RightEdge ? "view-right-new" : "view-left-new"} + + /** + * handleVisible: bool + * If true, a little handle will be visible to make opening the drawer easier + * Currently supported only on left and right drawers + */ + property bool handleVisible: typeof(applicationWindow)===typeof(Function) && applicationWindow() ? applicationWindow().controlsVisible : true + + /** + * handle: Item + * Readonly property that points to the item that will act as a physical + * handle for the Drawer + **/ + readonly property Item handle: MouseArea { + id: drawerHandle + z: root.modal ? applicationWindow().overlay.z + (root.position > 0 ? +1 : -1) : root.background.parent.z + 1 + preventStealing: true + hoverEnabled: handleAnchor + parent: applicationWindow().overlay.parent + + property Item handleAnchor: (!Settings.isMobile && applicationWindow().pageStack && applicationWindow().pageStack.globalToolBar && applicationWindow().pageStack.globalToolBar.actualStyle !== ApplicationHeaderStyle.None) + ? (root.edge === Qt.LeftEdge + ? applicationWindow().pageStack.globalToolBar.leftHandleAnchor + : applicationWindow().pageStack.globalToolBar.rightHandleAnchor) + : (applicationWindow().header && applicationWindow().header.toString().indexOf("ToolBarApplicationHeader") !== -1 ? applicationWindow().header : null) + + property int startX + property int mappedStartX + + enabled: root.handleVisible + + onPressed: { + root.peeking = true; + startX = mouse.x; + mappedStartX = mapToItem(parent, startX, 0).x + } + onPositionChanged: { + if (!pressed) { + return; + } + var pos = mapToItem(parent, mouse.x - startX, mouse.y); + switch(root.edge) { + case Qt.LeftEdge: + root.position = pos.x/root.contentItem.width; + break; + case Qt.RightEdge: + root.position = (root.parent.width - pos.x - width)/root.contentItem.width; + break; + default: + } + } + onReleased: { + root.peeking = false; + if (Math.abs(mapToItem(parent, mouse.x, 0).x - mappedStartX) < Qt.styleHints.startDragDistance) { + if (!root.drawerOpen) { + root.close(); + } + root.drawerOpen = !root.drawerOpen; + } + } + onCanceled: { + root.peeking = false + } + x: { + switch(root.edge) { + case Qt.LeftEdge: + return root.background.width * root.position + Units.smallSpacing; + case Qt.RightEdge: + return drawerHandle.parent.width - (root.background.width * root.position) - width - Units.smallSpacing; + default: + return 0; + } + } + y: handleAnchor && anchors.bottom ? handleAnchor.ScenePosition.y : 0 + + anchors { + bottom: drawerHandle.handleAnchor ? undefined : parent.bottom + bottomMargin: { + if (typeof applicationWindow === "undefined") { + return; + } + + var margin = Units.smallSpacing; + if (applicationWindow().footer) { + margin = applicationWindow().footer.height + Units.smallSpacing; + } + + if (!applicationWindow() || !applicationWindow().pageStack || + !applicationWindow().pageStack.contentItem || + !applicationWindow().pageStack.contentItem.itemAt) { + return margin; + } + + var item; + if (applicationWindow().pageStack.layers.depth > 1) { + item = applicationWindow().pageStack.layers.currentItem; + } else { + item = applicationWindow().pageStack.contentItem.itemAt(applicationWindow().pageStack.contentItem.contentX + drawerHandle.x, 0); + } + + //try to take the last item + if (!item) { + item = applicationWindow().pageStack.lastItem; + } + + var pageFooter = item && item.page ? item.page.footer : (item ? item.footer : undefined); + if (pageFooter) { + margin += pageFooter.height; + } + + return margin; + } + Behavior on bottomMargin { + NumberAnimation { + duration: Units.shortDuration + easing.type: Easing.InOutQuad + } + } + } + + visible: root.enabled && (root.edge === Qt.LeftEdge || root.edge === Qt.RightEdge) + width: handleAnchor ? handleAnchor.width : Units.iconSizes.smallMedium + Units.smallSpacing*2 + height: handleAnchor ? handleAnchor.height : width + opacity: root.handleVisible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + transform: Translate { + id: translateTransform + x: root.handleVisible ? 0 : (root.edge === Qt.LeftEdge ? -drawerHandle.width : drawerHandle.width) + Behavior on x { + NumberAnimation { + duration: Units.longDuration + easing.type: !root.handleVisible ? Easing.OutQuad : Easing.InQuad + } + } + } + } + + Theme.colorSet: modal ? Theme.View : Theme.Window + Theme.onColorSetChanged: { + contentItem.Theme.colorSet = Theme.colorSet + background.Theme.colorSet = Theme.colorSet + } +//END Properties + + +//BEGIN reassign properties + //default paddings + leftPadding: Units.smallSpacing + topPadding: Units.smallSpacing + rightPadding: Units.smallSpacing + bottomPadding: Units.smallSpacing + + y: modal ? 0 : ((T2.ApplicationWindow.menuBar ? T2.ApplicationWindow.menuBar.height : 0) + (T2.ApplicationWindow.header ? T2.ApplicationWindow.header.height : 0)) + + height: modal ? parent.height : (parent.height - y - (T2.ApplicationWindow.footer ? T2.ApplicationWindow.footer.height : 0)) + + parent: modal || edge === Qt.LeftEdge || edge === Qt.RightEdge ? T2.ApplicationWindow.overlay : T2.ApplicationWindow.contentItem + + edge: Qt.LeftEdge + modal: true + + dragMargin: enabled && (edge === Qt.LeftEdge || edge === Qt.RightEdge) ? Qt.styleHints.startDragDistance : 0 + + contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) + contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + + implicitWidth: contentWidth + leftPadding + rightPadding + implicitHeight: contentHeight + topPadding + bottomPadding + + //this is a workaround for the height not being propagated automatically only sometimes + // see https://bugs.kde.org/show_bug.cgi?id=398163 + //NOTE: this is NOT a binding, otherwise it causes a binding loop in implicitHeight + Connections { + target: parent + onWidthChanged: { + if (edge === Qt.TopEdge || edge === Qt.BottomEdge) { + width = parent.width; + } + } + onHeightChanged: { + if (edge === Qt.LeftEdge || edge === Qt.RightEdge) { + height = parent.height; + } + } + } + + enter: Transition { + SequentialAnimation { + id: enterAnimation + /*NOTE: why this? the running status of the enter transition is not relaible and + * the SmoothedAnimation is always marked as non running, + * so the only way to get to a reliable animating status is with this + */ + property bool animating + ScriptAction { + script: { + enterAnimation.animating = true + //on non modal dialog we don't want drawers in the overlay + if (!root.modal) { + root.background.parent.parent = applicationWindow().overlay.parent + } + } + } + SmoothedAnimation { + velocity: 5 + } + ScriptAction { + script: enterAnimation.animating = false + } + } + } + + exit: Transition { + SequentialAnimation { + id: exitAnimation + property bool animating + ScriptAction { + script: exitAnimation.animating = true + } + SmoothedAnimation { + velocity: 5 + } + ScriptAction { + script: exitAnimation.animating = false + } + } + } +//END reassign properties + + +//BEGIN signal handlers + onCollapsedChanged: { + if (!__internal.completed) { + return; + } + if ((!collapsible || modal) && collapsed) { + collapsed = true; + } + } + onCollapsibleChanged: { + if (!__internal.completed) { + return; + } + if (!collapsible) { + collapsed = false; + } else if (modal) { + collapsible = false; + } + } + onModalChanged: { + if (!__internal.completed) { + return; + } + if (modal) { + collapsible = false; + } + } + + onPositionChanged: { + if (peeking) { + visible = true + } + } + onVisibleChanged: { + if (peeking) { + visible = true + } else { + drawerOpen = visible; + } + } + onPeekingChanged: { + if (peeking) { + root.enter.enabled = false; + root.exit.enabled = false; + } else { + drawerOpen = position > 0.5 ? 1 : 0; + positionResetAnim.running = true + root.enter.enabled = true; + root.exit.enabled = true; + } + } + onDrawerOpenChanged: { + //sync this property only when the component is properly loaded + if (!__internal.completed) { + return; + } + positionResetAnim.running = false; + if (drawerOpen) { + open(); + } else { + close(); + } + } + + Component.onCompleted: { + //if defined as drawerOpen by default in QML, don't animate + if (root.drawerOpen) { + root.enter.enabled = false; + root.visible = true; + root.position = 1; + root.enter.enabled = true; + } + __internal.completed = true; + contentItem.Theme.colorSet = Theme.colorSet; + background.Theme.colorSet = Theme.colorSet; + } +//END signal handlers + + //this is as hidden as it can get here + property QtObject __internal: QtObject { + //here in order to not be accessible from outside + property bool completed: false + property SequentialAnimation positionResetAnim: SequentialAnimation { + id: positionResetAnim + property alias to: internalAnim.to + NumberAnimation { + id: internalAnim + target: root + to: drawerOpen ? 1 : 0 + property: "position" + duration: (root.position)*Units.longDuration + } + ScriptAction { + script: { + root.drawerOpen = internalAnim.to != 0; + } + } + } + readonly property Item statesItem: Item { + states: [ + State { + when: root.collapsed + PropertyChanges { + target: root + implicitWidth: edge === Qt.TopEdge || edge === Qt.BottomEdge ? applicationWindow().width : Math.min(collapsedSize + leftPadding + rightPadding, Math.round(applicationWindow().width*0.8)) + + implicitHeight: edge === Qt.LeftEdge || edge === Qt.RightEdge ? applicationWindow().height : Math.min(collapsedSize + topPadding + bottomPadding, Math.round(applicationWindow().height*0.8)) + } + }, + State { + when: !root.collapsed + PropertyChanges { + target: root + implicitWidth: edge === Qt.TopEdge || edge === Qt.BottomEdge ? applicationWindow().width : Math.min(contentItem.implicitWidth, Math.round(applicationWindow().width*0.8)) + + implicitHeight: edge === Qt.LeftEdge || edge === Qt.RightEdge ? applicationWindow().height : Math.min(contentHeight + topPadding + bottomPadding, Math.round(applicationWindow().height*0.4)) + + contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) + contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + } + } + ] + transitions: Transition { + reversible: true + NumberAnimation { + properties: root.edge === Qt.TopEdge || root.edge === Qt.BottomEdge ? "implicitHeight" : "implicitWidth" + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } +} diff --git a/src/controls/templates/OverlaySheet.qml b/src/controls/templates/OverlaySheet.qml new file mode 100644 index 0000000..facc1d9 --- /dev/null +++ b/src/controls/templates/OverlaySheet.qml @@ -0,0 +1,533 @@ +/* +* Copyright (C) 2016 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.5 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.2 +import org.kde.kirigami 2.4 +import QtGraphicalEffects 1.0 +import QtQuick.Templates 2.0 as T2 +import "private" +import "../private" + +/** + * An overlay sheet that covers the current Page content. + * Its contents can be scrolled up or down, scrolling all the way up or + * all the way down, dismisses it. + * Use this for big, modal dialogs or information display, that can't be + * logically done as a new separate Page, even if potentially + * are taller than the screen space. + * @inherits: QtQuick.QtObject + */ +QtObject { + id: root + + Theme.colorSet: Theme.View + Theme.inherit: false + + /** + * contentItem: Item + * This property holds the visual content item. + * + * Note: The content item is automatically resized inside the + * padding of the control. + * Conversely, the Sheet will be sized based on the size hints + * of the contentItem, so if you need a custom size sheet, + * redefine contentWidth and contentHeight of your contentItem + */ + default property Item contentItem + + /** + * sheetOpen: bool + * If true the sheet is open showing the contents of the OverlaySheet + * component. + */ + property bool sheetOpen + + /** + * leftPadding: int + * default contents padding at left + */ + property int leftPadding: Units.gridUnit + + /** + * topPadding: int + * default contents padding at top + */ + property int topPadding: Units.gridUnit + + /** + * rightPadding: int + * default contents padding at right + */ + property int rightPadding: Units.gridUnit + + /** + * bottomPadding: int + * default contents padding at bottom + */ + property int bottomPadding: Units.gridUnit + + /** + * header: Item + * an optional item which will be used as the sheet's header, + * always kept on screen + * @since 5.43 + */ + property Item header + + /** + * header: Item + * an optional item which will be used as the sheet's footer, + * always kept on screen + * @since 5.43 + */ + property Item footer + /** + * background: Item + * This property holds the background item. + * + * Note: If the background item has no explicit size specified, + * it automatically follows the control's size. + * In most cases, there is no need to specify width or + * height for a background item. + */ + property Item background + + /** + * showCloseButton: bool + * whether to show the close button in the top-right corner + * @since 5.44 + */ + property alias showCloseButton: closeIcon.visible + + property Item parent + + + function open() { + openAnimation.from = -mainItem.height; + openAnimation.to = openAnimation.topOpenPosition; + openAnimation.running = true; + root.sheetOpen = true; + mainItem.visible = true; + } + + function close() { + if (scrollView.flickableItem.contentY < 0) { + closeAnimation.to = -height; + } else { + closeAnimation.to = scrollView.flickableItem.contentHeight; + } + closeAnimation.running = true; + } + + onBackgroundChanged: { + background.parent = flickableContents; + background.z = -1; + } + onContentItemChanged: { + if (contentItem.hasOwnProperty("contentY") && // Check if flickable + contentItem.hasOwnProperty("contentHeight")) { + contentItem.parent = scrollView; + scrollView.contentItem = contentItem; + } else { + contentItem.parent = contentItemParent; + scrollView.contentItem = flickableContents; + contentItem.anchors.left = contentItemParent.left; + contentItem.anchors.right = contentItemParent.right; + } + scrollView.flickableItem.flickableDirection = Flickable.VerticalFlick; + } + onSheetOpenChanged: { + if (sheetOpen) { + open(); + } else { + close(); + Qt.inputMethod.hide(); + } + } + onHeaderChanged: { + header.parent = headerParent; + header.anchors.fill = headerParent; + + //TODO: special case for actual ListViews + } + onFooterChanged: { + footer.parent = footerParent; + footer.anchors.fill = footerParent; + } + + Component.onCompleted: { + if (!root.parent && typeof applicationWindow !== "undefined") { + root.parent = applicationWindow().overlay + } + } + + readonly property Item rootItem: MouseArea { + id: mainItem + Theme.colorSet: root.Theme.colorSet + Theme.inherit: root.Theme.inherit + //we want to be over any possible OverlayDrawers, including handles + parent: root.parent + + anchors.fill: parent + z: typeof applicationWindow !== "undefined" && root.parent === applicationWindow().overlay ? 0 : 9998 + visible: false + drag.filterChildren: true + hoverEnabled: true + + onClicked: { + var pos = mapToItem(flickableContents, mouse.x, mouse.y); + if (!flickableContents.contains(pos)) { + root.close(); + } + } + + readonly property int contentItemPreferredWidth: root.contentItem.Layout.preferredWidth > 0 ? root.contentItem.Layout.preferredWidth : root.contentItem.implicitWidth + + readonly property int contentItemMaximumWidth: width > Units.gridUnit * 30 ? mainItem.width * 0.95 : width + + onWidthChanged: { + if (!contentItem.contentItem) + return + + var width = Math.max(mainItem.width/2, Math.min(mainItem.width, mainItem.contentItemPreferredWidth)); + contentItem.contentItem.x = (mainItem.width - width)/2 + contentItem.contentItem.width = width; + } + onHeightChanged: { + var focusItem; + + focusItem = Window.activeFocusItem; + + if (!focusItem) { + return; + } + + //NOTE: there is no function to know if an item is descended from another, + //so we have to walk the parent hierarchy by hand + var isDescendent = false; + var candidate = focusItem.parent; + while (candidate) { + if (candidate === root) { + isDescendent = true; + break; + } + candidate = candidate.parent; + } + if (!isDescendent) { + return; + } + + var cursorY = 0; + if (focusItem.cursorPosition !== undefined) { + cursorY = focusItem.positionToRectangle(focusItem.cursorPosition).y; + } + + + var pos = focusItem.mapToItem(flickableContents, 0, cursorY - Units.gridUnit*3); + //focused item already visible? add some margin for the space of the action buttons + if (pos.y >= scrollView.flickableItem.contentY && pos.y <= scrollView.flickableItem.contentY + scrollView.flickableItem.height - Units.gridUnit * 8) { + return; + } + scrollView.flickableItem.contentY = pos.y; + } + + ParallelAnimation { + id: openAnimation + property int margins: Units.gridUnit * 5 + property int topOpenPosition: Math.min(-mainItem.height*0.15, scrollView.flickableItem.contentHeight - mainItem.height + margins) + property alias from: openAnimationInternal.from + property alias to: openAnimationInternal.to + NumberAnimation { + id: openAnimationInternal + target: scrollView.flickableItem + properties: "contentY" + from: -mainItem.height + to: openAnimation.topOpenPosition + duration: Units.longDuration + easing.type: Easing.OutQuad + onRunningChanged: { + //HACK to center listviews + if (!running && contentItem.contentItem) { + var width = Math.max(mainItem.width/2, Math.min(mainItem.contentItemMaximumWidth, mainItem.contentItemPreferredWidth)); + contentItem.contentItem.x = (mainItem.width - width)/2 + contentItem.contentItem.width = width; + } + } + } + OpacityAnimator { + target: mainItem + from: 0 + to: 1 + duration: Units.longDuration + easing.type: Easing.InQuad + } + } + + SequentialAnimation { + id: closeAnimation + property int to: -mainItem.height + ParallelAnimation { + NumberAnimation { + target: scrollView.flickableItem + properties: "contentY" + to: closeAnimation.to + duration: Units.longDuration + easing.type: Easing.InQuad + } + OpacityAnimator { + target: mainItem + from: 1 + to: 0 + duration: Units.longDuration + easing.type: Easing.InQuad + } + } + ScriptAction { + script: { + scrollView.flickableItem.contentY = -mainItem.height; + mainItem.visible = root.sheetOpen = false; + } + } + } + Rectangle { + anchors.fill: parent + color: Theme.textColor + opacity: 0.6 * Math.min( + (Math.min(scrollView.flickableItem.contentY + scrollView.flickableItem.height, scrollView.flickableItem.height) / scrollView.flickableItem.height), + (2 + (scrollView.flickableItem.contentHeight - scrollView.flickableItem.contentY - scrollView.flickableItem.topMargin - scrollView.flickableItem.bottomMargin)/scrollView.flickableItem.height)) + } + + Icon { + id: closeIcon + anchors { + right: headerItem.right + margins: Units.smallSpacing + top: headerItem.top + } + z: 3 + visible: !Settings.isMobile + width: Units.iconSizes.smallMedium + height: width + source: closeMouseArea.containsMouse ? "window-close" : "window-close-symbolic" + active: closeMouseArea.containsMouse + MouseArea { + id: closeMouseArea + hoverEnabled: true + anchors.fill: parent + onClicked: root.close(); + } + } + Rectangle { + id: headerItem + width: flickableContents.width + x: flickableContents.x + visible: root.header + height: Math.max(headerParent.implicitHeight, closeIcon.height) + Units.smallSpacing * 2 + color: Theme.backgroundColor + //different y depending if we're a listview or a normal item + y: Math.max(0, -scrollView.flickableItem.contentY - (scrollView.contentItem != flickableContents ? height : 0)) + z: 2 + Item { + id: headerParent + implicitHeight: header ? header.implicitHeight : 0 + anchors { + fill: parent + margins: Units.smallSpacing + rightMargin: closeIcon.width + Units.smallSpacing + } + } + + EdgeShadow { + z: -2 + edge: Qt.TopEdge + anchors { + right: parent.right + left: parent.left + top: parent.bottom + } + + opacity: parent.y == 0 ? 1 : 0 + + Behavior on opacity { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } + Rectangle { + id: footerItem + width: flickableContents.width + x: flickableContents.x + visible: root.footer + height: footerParent.implicitHeight + Units.smallSpacing * 2 + extraMargin + color: Theme.backgroundColor + y: mainItem.mapFromItem(flickableContents, 0, flickableContents.height).y - height + onHeightChanged: y = Math.min(mainItem.height, mainItem.mapFromItem(flickableContents, 0, flickableContents.height).y) - footerItem.height; + //Show an extra margin when: + //* the application is in mobile mode (no toolbarapplicationheader) + //* the bottom screen controls are visible + //* the sheet is displayed *under* the controls + property int extraMargin: (!root.parent || + typeof applicationWindow === "undefined" || + (root.parent === applicationWindow().overlay) || + !applicationWindow().controlsVisible || + (applicationWindow().pageStack && applicationWindow().pageStack.globalToolBar && applicationWindow().pageStack.globalToolBar.actualStyle === ApplicationHeaderStyle.ToolBar) || + (applicationWindow().header && applicationWindow().header.toString().indexOf("ToolBarApplicationHeader") === 0)) + ? 0 : Units.gridUnit * 3 + Connections { + target: scrollView.flickableItem + onContentYChanged: footerItem.y = Math.min(mainItem.height, mainItem.mapFromItem(flickableContents, 0, flickableContents.height).y) - footerItem.height; + + onHeightChanged: scrollView.flickableItem.contentYChanged() + } + z: 2 + Item { + id: footerParent + implicitHeight: footer ? footer.implicitHeight : 0 + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: Units.smallSpacing + } + } + + EdgeShadow { + z: -2 + edge: Qt.BottomEdge + anchors { + right: parent.right + left: parent.left + bottom: parent.top + } + + opacity: parent.y + parent.height < mainItem.height ? 0 : 1 + + Behavior on opacity { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } + + Item { + id: flickableContents + //anchors.horizontalCenter: parent.horizontalCenter + x: (mainItem.width - width) / 2 + + readonly property real listHeaderHeight: scrollView.flickableItem && root.contentItem.headerItem ? root.contentItem.headerItem.height : 0 + + y: (scrollView.contentItem != flickableContents ? -scrollView.flickableItem.contentY - listHeaderHeight - (headerItem.visible ? headerItem.height : 0): 0) + + width: mainItem.contentItemPreferredWidth <= 0 ? mainItem.width : Math.max(mainItem.width/2, Math.min(mainItem.contentItemMaximumWidth, mainItem.contentItemPreferredWidth)) + + height: (scrollView.contentItem != flickableContents ? scrollView.flickableItem.contentHeight + listHeaderHeight : (root.contentItem.height + topPadding + bottomPadding)) + (headerItem.visible ? headerItem.height : 0) + (footerItem.visible ? footerItem.height : 0) + + Item { + id: contentItemParent + anchors { + fill: parent + leftMargin: leftPadding + topMargin: topPadding + (headerItem.visible ? headerItem.height : 0) + rightMargin: rightPadding + bottomMargin: bottomPadding + (footerItem.visible ? footerItem.height : 0) + } + } + } + Binding { + when: scrollView.flickableItem != null + target: scrollView.flickableItem + property: "topMargin" + //hack needed for smoother open anim + value: openAnimation.running ? -scrollView.flickableItem.contentY : -openAnimation.topOpenPosition + } + Binding { + when: scrollView.flickableItem != null + target: scrollView.flickableItem + property: "bottomMargin" + value: openAnimation.margins + } + + Binding { + target: scrollView.verticalScrollBar ? scrollView.verticalScrollBar.anchors : null + property: "topMargin" + value: headerItem.y + headerItem.height + } + Binding { + target: scrollView.verticalScrollBar + property: "height" + value: mainItem.height - (scrollView.verticalScrollBar ? scrollView.verticalScrollBar.anchors.topMargin : 0) - (mainItem.height - footerItem.y) + } + Binding { + target: scrollView.verticalScrollBar ? scrollView.verticalScrollBar.anchors : null + property: "rightMargin" + value: mainItem.width - flickableContents.width - flickableContents.x + } + + Connections { + target: scrollView.flickableItem + onContentHeightChanged: { + if (openAnimation.running) { + openAnimation.running = false; + open(); + } + } + onDraggingChanged: { + if (scrollView.flickableItem.dragging) { + return; + } + + //close + if ((mainItem.height + scrollView.flickableItem.contentY) < mainItem.height/2) { + closeAnimation.to = -mainItem.height; + closeAnimation.running = true; + + } else if ((mainItem.height*0.6 + scrollView.flickableItem.contentY) > scrollView.flickableItem.contentHeight) { + closeAnimation.to = scrollView.flickableItem.contentHeight; + closeAnimation.running = true; + } + } + } + + Binding { + target: scrollView.verticalScrollBar + property: "visible" + value: scrollView.flickableItem.contentHeight > mainItem.height*0.8 + } + Connections { + target: scrollView.verticalScrollBar + onActiveChanged: { + if (!scrollView.verticalScrollBar.active) { + scrollView.flickableItem.movementEnded(); + } + } + } + ScrollView { + id: scrollView + anchors.fill: parent + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + } + } +} diff --git a/src/controls/templates/SwipeListItem.qml b/src/controls/templates/SwipeListItem.qml new file mode 100644 index 0000000..183ef14 --- /dev/null +++ b/src/controls/templates/SwipeListItem.qml @@ -0,0 +1,429 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls +import org.kde.kirigami 2.4 +import "../private" +import QtQuick.Templates 2.0 as T2 + +/** + * An item delegate Intended to support extra actions obtainable + * by uncovering them by dragging away the item with the handle + * This acts as a container for normal list items. + * Any subclass of AbstractListItem can be assigned as the contentItem property. + * @code + * ListView { + * model: myModel + * delegate: SwipeListItem { + * QQC2.Label { + * text: model.text + * } + * actions: [ + * Action { + * iconName: "document-decrypt" + * onTriggered: print("Action 1 clicked") + * }, + * Action { + * iconName: model.action2Icon + * onTriggered: //do something + * } + * ] + * } + * + * } + * @endcode + * + * @inherit QtQuick.Templates.ItemDelegate + */ +T2.ItemDelegate { + id: listItem + +//BEGIN properties + /** + * supportsMouseEvents: bool + * Holds if the item emits signals related to mouse interaction. + *TODO: remove + * The default value is false. + */ + property alias supportsMouseEvents: listItem.hoverEnabled + + /** + * containsMouse: bool + * True when the user hover the mouse over the list item + * NOTE: on mobile touch devices this will be true only when pressed is also true + */ + property alias containsMouse: listItem.hovered + + /** + * sectionDelegate: bool + * If true the item will be a delegate for a section, so will look like a + * "title" for the items under it. + */ + property bool sectionDelegate: false + + /** + * separatorVisible: bool + * True if the separator between items is visible + * default: true + */ + property bool separatorVisible: true + + /** + * actionsVisible: bool + * True if it's possible to see and access the item actions. + * Actions should go completely out of the way for instance during + * the editing of an item. + * @since 2.5 + */ + property alias actionsVisible: behindItem.visible + + /** + * actions: list + * Defines the actions for the list item: at most 4 buttons will + * contain the actions for the item, that can be revealed by + * sliding away the list item. + */ + property list actions + + /** + * textColor: color + * Color for the text in the item + * + * Note: if custom text elements are inserted in an AbstractListItem, + * their color property will have to be manually bound with this property + */ + property color textColor: Theme.textColor + + /** + * backgroundColor: color + * Color for the background of the item + */ + property color backgroundColor: Theme.backgroundColor + + /** + * activeTextColor: color + * Color for the text in the item when pressed or selected + * It is advised to leave the default value (Theme.highlightedTextColor) + * + * Note: if custom text elements are inserted in an AbstractListItem, + * their color property will have to be manually bound with this property + */ + property color activeTextColor: Theme.highlightedTextColor + + /** + * activeBackgroundColor: color + * Color for the background of the item when pressed or selected + * It is advised to leave the default value (Theme.highlightColor) + */ + property color activeBackgroundColor: Theme.highlightColor + + default property alias _default: listItem.contentItem + + Theme.colorGroup: behindItem.indicateActiveFocus ? Theme.Active : Theme.Inactive + + hoverEnabled: true + implicitWidth: contentItem ? contentItem.implicitWidth : Units.gridUnit * 12 + width: parent ? parent.width : implicitWidth + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 5 + + leftPadding: Units.smallSpacing * 2 + + rightPadding: Units.smallSpacing * 2 + (handleMouse.visible ? handleMouse.width : hovered * actionsLayout.width) + handleMouse.anchors.rightMargin + + topPadding: Units.smallSpacing * 2 + bottomPadding: Units.smallSpacing * 2 + +//END properties + + Item { + id: behindItem + parent: listItem + z: -1 + //TODO: a global "open" state + enabled: background.x !== 0 + property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (view ? view.activeFocus : false) + property Flickable view: listItem.ListView.view || (listItem.parent ? (listItem.parent.ListView.view || listItem.parent) : null) + onViewChanged: { + if (view && Settings.tabletMode && !behindItem.view.parent.parent._swipeFilter) { + var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml")); + behindItem.view.parent.parent._swipeFilter = component.createObject(behindItem.view.parent.parent); + } + } + + anchors { + fill: parent + } + Rectangle { + id: shadowHolder + color: Qt.darker(Theme.backgroundColor, 1.05); + anchors.fill: parent + } + EdgeShadow { + edge: Qt.TopEdge + anchors { + right: parent.right + left: parent.left + top: parent.top + } + } + EdgeShadow { + edge: LayoutMirroring.enabled ? Qt.RightEdge : Qt.LeftEdge + x: LayoutMirroring.enabled ? listItem.background.x - width : (listItem.background.x + listItem.background.width) + anchors { + top: parent.top + bottom: parent.bottom + } + } + MouseArea { + anchors.fill: parent + preventStealing: true + enabled: background.x != 0 + onClicked: { + positionAnimation.from = background.x; + positionAnimation.to = 0; + positionAnimation.running = true; + } + } + Row { + id: actionsLayout + z: 1 + visible: listItem.actionsVisible + parent: Settings.tabletMode ? behindItem : listItem + opacity: Settings.tabletMode || listItem.hovered || !listItem.supportsMouseEvents ? 1 : 0 + Behavior on opacity { + OpacityAnimator { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: Units.gridUnit + } + height: Math.min( parent.height / 1.5, Units.iconSizes.smallMedium) + width: childrenRect.width + property bool exclusive: false + property Item checkedButton + spacing: Units.largeSpacing + Repeater { + model: { + if (listItem.actions.length === 0) { + return null; + } else { + return listItem.actions[0].text !== undefined && + listItem.actions[0].trigger !== undefined ? + listItem.actions : + listItem.actions[0]; + } + } + delegate: Icon { + height: actionsLayout.height + width: height + source: modelData.iconName !== "" ? modelData.iconName : modelData.iconSource + enabled: (modelData && modelData.enabled !== undefined) ? modelData.enabled : true; + visible: (modelData && modelData.visible !== undefined) ? modelData.visible : true; + MouseArea { + id: actionMouse + anchors { + fill: parent; + margins: Settings.tabletMode ? -Units.smallSpacing : 0; + } + enabled: (modelData && modelData.enabled !== undefined) ? modelData.enabled : true; + hoverEnabled: !Settings.tabletMode + onClicked: { + if (modelData && modelData.trigger !== undefined) { + modelData.trigger(); + } + positionAnimation.from = background.x; + positionAnimation.to = 0; + positionAnimation.running = true; + } + Controls.ToolTip.delay: 1000 + Controls.ToolTip.timeout: 5000 + Controls.ToolTip.visible: listItem.visible && (Settings.tabletMode ? actionMouse.pressed : actionMouse.containsMouse) && Controls.ToolTip.text.length > 0 + Controls.ToolTip.text: modelData.tooltip || modelData.text + } + + } + } + } + } + + MouseArea { + id: handleMouse + parent: listItem.background + visible: Settings.tabletMode && listItem.actionsVisible && actions.length > 0 + z: 99 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: !Settings.isMobile && behindItem.view && behindItem.view.T2.ScrollBar && behindItem.view.T2.ScrollBar.vertical && behindItem.view.T2.ScrollBar.vertical.visible ? behindItem.view.T2.ScrollBar.vertical.width : Units.smallSpacing + } + + preventStealing: true + width: Units.iconSizes.smallMedium + height: width + property var downTimestamp; + property int startX + property int startMouseX + + onClicked: { + positionAnimation.from = background.x; + if (listItem.background.x > -listItem.background.width/2) { + positionAnimation.to = (LayoutMirroring.enabled ? -1 : +1) * (-listItem.width + height + handleMouse.anchors.rightMargin); + } else { + positionAnimation.to = 0; + } + positionAnimation.restart(); + } + onPressed: { + downTimestamp = (new Date()).getTime(); + startX = listItem.background.x; + startMouseX = mouse.x; + } + onPositionChanged: { + if (LayoutMirroring.enabled) { + listItem.background.x = Math.max(0, Math.min(listItem.width - height, listItem.background.x - (startMouseX - mouse.x))); + } else { + listItem.background.x = Math.min(0, Math.max(-listItem.width + height, listItem.background.x - (startMouseX - mouse.x))); + } + } + onReleased: { + var speed = ((startX - listItem.background.x) / ((new Date()).getTime() - downTimestamp) * 1000); + var absoluteDelta = startX - listItem.background.x; + if (LayoutMirroring.enabled) { + speed = -speed; + absoluteDelta = -absoluteDelta; + } + + if (Math.abs(speed) < Units.gridUnit) { + return; + } + if (speed > listItem.width/2 || absoluteDelta > listItem.width/2) { + positionAnimation.to = (LayoutMirroring.enabled ? -1 : +1) * (-listItem.width + height + handleMouse.anchors.rightMargin); + } else { + positionAnimation.to = 0; + } + positionAnimation.from = background.x; + positionAnimation.running = true; + } + Icon { + id: handleIcon + anchors.fill: parent + selected: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) + source: (LayoutMirroring.enabled ? (listItem.background.x < listItem.background.width/2 ? "overflow-menu-right" : "overflow-menu-left") : (listItem.background.x < -listItem.background.width/2 ? "overflow-menu-right" : "overflow-menu-left")) + } + } + + NumberAnimation { + id: positionAnimation + property: "x" + target: background + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + +//BEGIN signal handlers + onContentItemChanged: { + if (!contentItem) { + return; + } + contentItem.parent = background; + contentItem.anchors.top = background.top; + contentItem.anchors.left = background.left; + contentItem.anchors.right = background.right; + contentItem.anchors.leftMargin = Qt.binding(function() {return listItem.leftPadding}); + contentItem.anchors.rightMargin = Qt.binding(function() {return listItem.rightPadding}); + contentItem.anchors.topMargin = Qt.binding(function() {return listItem.topPadding}); + contentItem.z = 0; + } + Component.onCompleted: { + //this will happen only once + listItem.contentItemChanged(); + } + Connections { + target: Settings + onTabletModeChanged: { + if (Settings.tabletMode) { + if (!internal.swipeFilterItem) { + var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml")); + listItem.ListView.view.parent.parent._swipeFilter = component.createObject(listItem.ListView.view.parent.parent); + } + } else { + if (listItem.ListView.view.parent.parent._swipeFilter) { + listItem.ListView.view.parent.parent._swipeFilter.destroy(); + positionAnimation.to = 0; + positionAnimation.from = background.x; + positionAnimation.running = true; + } + } + } + } + QtObject { + id: internal + readonly property QtObject swipeFilterItem: (behindItem.view && behindItem.view.parent && behindItem.view.parent.parent && behindItem.view.parent.parent._swipeFilter) ? behindItem.view.parent.parent._swipeFilter : null + + readonly property bool edgeEnabled: swipeFilterItem ? swipeFilterItem.currentItem === listItem || swipeFilterItem.currentItem === listItem.parent : false + } + + Connections { + id: swipeFilterConnection + + target: internal.edgeEnabled ? internal.swipeFilterItem : null + onPeekChanged: { + if (!listItem.actionsVisible) { + return; + } + if (listItem.LayoutMirroring.enabled) { + listItem.background.x = (listItem.background.width - listItem.background.height) * (1 - internal.swipeFilterItem.peek); + } else { + listItem.background.x = -(listItem.background.width - listItem.background.height) * internal.swipeFilterItem.peek; + } + } + onPressed: { + if (internal.edgeEnabled) { + handleMouse.onPressed(mouse); + } + } + onClicked: { + if (Math.abs(listItem.background.x) < Units.gridUnit && internal.edgeEnabled) { + handleMouse.clicked(mouse); + } + } + onReleased: { + if (internal.edgeEnabled) { + handleMouse.released(mouse); + } + } + onCurrentItemChanged: { + if (!internal.edgeEnabled) { + positionAnimation.to = 0; + positionAnimation.from = background.x; + positionAnimation.running = true; + } + } + } + +//END signal handlers + + Accessible.role: Accessible.ListItem +} diff --git a/src/controls/templates/private/BackButton.qml b/src/controls/templates/private/BackButton.qml new file mode 100644 index 0000000..99af43c --- /dev/null +++ b/src/controls/templates/private/BackButton.qml @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls + +import org.kde.kirigami 2.4 + +Controls.ToolButton { + id: button + + enabled: applicationWindow().pageStack.layers.depth > 1 || (applicationWindow().pageStack.depth > 1 && (applicationWindow().pageStack.currentIndex > 0 || applicationWindow().pageStack.contentItem.contentX > 0)) + visible: applicationWindow().pageStack.layers.depth > 1 || applicationWindow().pageStack.contentItem.contentWidth > applicationWindow().pageStack.width + width: height + height: parent.height + + onClicked: { + if (applicationWindow().pageStack.layers && applicationWindow().pageStack.layers.depth > 1) { + applicationWindow().pageStack.layers.pop(); + } else { + applicationWindow().pageStack.goBack(); + } + } + Icon { + anchors.centerIn: parent + width: Math.min(parent.width, Units.iconSizes.smallMedium) + height: width + opacity: parent.enabled ? 1 : 0.6 + source: (LayoutMirroring.enabled ? "go-previous-symbolic-rtl" : "go-previous-symbolic") + } + Controls.ToolTip { + visible: button.hovered + text: qsTr("Navigate Back") + delay: 1000 + timeout: 5000 + y: button.height + } +} diff --git a/src/controls/templates/private/ContextIcon.qml b/src/controls/templates/private/ContextIcon.qml new file mode 100644 index 0000000..7e8edd8 --- /dev/null +++ b/src/controls/templates/private/ContextIcon.qml @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +Item { + id: canvas + width: height + height: Units.iconSizes.smallMedium + property OverlayDrawer drawer + property color color: Theme.textColor + opacity: 0.8 + layer.enabled: true + + Item { + id: iconRoot + anchors { + fill: parent + margins: Units.smallSpacing + } + property int thickness: Math.floor(Units.devicePixelRatio)*2 + Rectangle { + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + //horizontalCenterOffset: -parent.width/2 + topMargin: (parent.height/2 - iconRoot.thickness/2) * drawer.position + } + antialiasing: drawer.position != 0 + transformOrigin: Item.Center + width: (1 - drawer.position) * height + drawer.position * (Math.sqrt(2*(parent.width*parent.width))) + height: iconRoot.thickness + color: canvas.color + rotation: 45 * drawer.position + } + + Rectangle { + anchors.centerIn: parent + width: height + height: iconRoot.thickness + color: canvas.color + } + + + Rectangle { + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + // topMargin: -iconRoot.thickness/2 * drawer.position + bottomMargin: (parent.height/2 - iconRoot.thickness/2) * drawer.position + } + antialiasing: drawer.position != 0 + transformOrigin: Item.Center + width: (1 - drawer.position) * height + drawer.position * (Math.sqrt(2*(parent.width*parent.width))) + height: iconRoot.thickness + color: canvas.color + rotation: -45 * drawer.position + } + } +} + diff --git a/src/controls/templates/private/ForwardButton.qml b/src/controls/templates/private/ForwardButton.qml new file mode 100644 index 0000000..03ea51a --- /dev/null +++ b/src/controls/templates/private/ForwardButton.qml @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.0 as Controls + +import org.kde.kirigami 2.4 + +Controls.ToolButton { + id: button + + property Flickable headerFlickable + enabled: applicationWindow().pageStack.depth > 1 && ( applicationWindow().pageStack.currentIndex < applicationWindow().pageStack.depth-1 || !applicationWindow().pageStack.contentItem.atXEnd) + visible: applicationWindow().pageStack.layers.depth == 1 && applicationWindow().pageStack.contentItem.contentWidth > applicationWindow().pageStack.width + width: height + height: parent.height + + onClicked: applicationWindow().pageStack.goForward(); + + Icon { + anchors.centerIn: parent + width: Math.min(parent.width, Units.iconSizes.smallMedium) + height: width + opacity: parent.enabled ? 1 : 0.6 + source: (LayoutMirroring.enabled ? "go-next-symbolic-rtl" : "go-next-symbolic") + } + Controls.ToolTip { + visible: button.hovered + text: qsTr("Navigate Forward") + delay: 1000 + timeout: 5000 + y: button.height + } +} diff --git a/src/controls/templates/private/GenericDrawerIcon.qml b/src/controls/templates/private/GenericDrawerIcon.qml new file mode 100644 index 0000000..94e2a0c --- /dev/null +++ b/src/controls/templates/private/GenericDrawerIcon.qml @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 as Kirigami + +Item { + width: height + height: Kirigami.Units.iconSizes.smallMedium + property Kirigami.OverlayDrawer drawer + property color color: Theme.textColor + opacity: 0.8 + layer.enabled: true + + Kirigami.Icon { + selected: drawer.handle.pressed + opacity: 1 - drawer.position + anchors.fill: parent + source: drawer.handleClosedIcon.source + color: drawer.handleClosedIcon.color + } + Kirigami.Icon { + selected: drawer.handle.pressed + opacity: drawer.position + anchors.fill: parent + source: drawer.handleOpenIcon.source + color: drawer.handleOpenIcon.color + } +} + diff --git a/src/controls/templates/private/IconPropertiesGroup.qml b/src/controls/templates/private/IconPropertiesGroup.qml new file mode 100644 index 0000000..6e7656a --- /dev/null +++ b/src/controls/templates/private/IconPropertiesGroup.qml @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQml 2.1 + +//this is a subset of those used in QQC2, Kirigami.Action still needs the full one as needs 100% api compatibility +QtObject { + property var source + property color color: Qt.rgba(0, 0, 0, 0) +} + diff --git a/src/controls/templates/private/MenuIcon.qml b/src/controls/templates/private/MenuIcon.qml new file mode 100644 index 0000000..b23dbbd --- /dev/null +++ b/src/controls/templates/private/MenuIcon.qml @@ -0,0 +1,78 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +Item { + id: canvas + width: height + height: Units.iconSizes.smallMedium + property OverlayDrawer drawer + property color color: Theme.textColor + opacity: 0.8 + layer.enabled: true + + Item { + id: iconRoot + anchors { + fill: parent + margins: Units.smallSpacing + } + property int thickness: Math.floor(Units.devicePixelRatio)*2 + + Rectangle { + anchors { + right: parent.right + top: parent.top + topMargin: -iconRoot.thickness/2 * drawer.position + } + antialiasing: drawer.position != 0 + transformOrigin: Item.Right + width: (1 - drawer.position) * parent.width + drawer.position * (Math.sqrt(2*(parent.width*parent.width))) + height: iconRoot.thickness + color: canvas.color + rotation: -45 * drawer.position + } + + Rectangle { + anchors.centerIn: parent + width: parent.width - parent.width * drawer.position + height: iconRoot.thickness + color: canvas.color + } + + Rectangle { + anchors { + right: parent.right + bottom: parent.bottom + bottomMargin: -iconRoot.thickness/2 * drawer.position + } + antialiasing: drawer.position != 0 + transformOrigin: Item.Right + width: (1 - drawer.position) * parent.width + drawer.position * (Math.sqrt(2*(parent.width*parent.width))) + height: iconRoot.thickness + color: canvas.color + rotation: 45 * drawer.position + } + } +} + diff --git a/src/controls/templates/private/PassiveNotification.qml b/src/controls/templates/private/PassiveNotification.qml new file mode 100644 index 0000000..5ac8828 --- /dev/null +++ b/src/controls/templates/private/PassiveNotification.qml @@ -0,0 +1,153 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as QQC2 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.kirigami 2.4 + +MouseArea { + id: root + z: 9999999 + width: background.width + height: background.height + opacity: 0 + enabled: appearAnimation.appear + + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: Units.gridUnit * 4 + } + function showNotification(message, timeout, actionText, callBack) { + if (!message) { + return; + } + appearAnimation.running = false; + appearAnimation.appear = true; + appearAnimation.running = true; + if (timeout == "short") { + timer.interval = 4000; + } else if (timeout == "long") { + timer.interval = 12000; + } else if (timeout > 0) { + timer.interval = timeout; + } else { + timer.interval = 7000; + } + messageLabel.text = message ? message : ""; + actionButton.text = actionText ? actionText : ""; + actionButton.callBack = callBack ? callBack : ""; + + timer.restart(); + } + + function hideNotification() { + appearAnimation.running = false; + appearAnimation.appear = false; + appearAnimation.running = true; + } + + + onClicked: { + appearAnimation.appear = false; + appearAnimation.running = true; + } + + transform: Translate { + id: transform + y: root.height + } + + Timer { + id: timer + interval: 4000 + onTriggered: { + appearAnimation.appear = false; + appearAnimation.running = true; + } + } + ParallelAnimation { + id: appearAnimation + property bool appear: true + NumberAnimation { + target: root + properties: "opacity" + to: appearAnimation.appear ? 1 : 0 + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: transform + properties: "y" + to: appearAnimation.appear ? 0 : background.height + duration: Units.longDuration + easing.type: appearAnimation.appear ? Easing.OutQuad : Easing.InQuad + } + } + + Item { + id: background + width: backgroundRect.width + Units.gridUnit + height: backgroundRect.height + Units.gridUnit + Rectangle { + id: backgroundRect + anchors.centerIn: parent + radius: Units.smallSpacing + color: Theme.textColor + opacity: 0.6 + width: mainLayout.width + Math.round((height - mainLayout.height)) + height: Math.max(mainLayout.height + Units.smallSpacing*2, Units.gridUnit*2) + } + RowLayout { + id: mainLayout + anchors.centerIn: parent + QQC2.Label { + id: messageLabel + Layout.maximumWidth: Math.min(root.parent.width - Units.largeSpacing*2, implicitWidth) + elide: Text.ElideRight + wrapMode: Text.WordWrap + maximumLineCount: 4 + color: Theme.backgroundColor + } + QQC2.Button { + id: actionButton + property var callBack + visible: text != "" + onClicked: { + appearAnimation.appear = false; + appearAnimation.running = true; + if (callBack) { + callBack(); + } + } + } + } + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: 0 + verticalOffset: 0 + radius: Units.gridUnit + samples: 32 + color: Qt.rgba(0, 0, 0, 0.5) + } + } +} + diff --git a/src/controls/templates/private/ScrollView.qml b/src/controls/templates/private/ScrollView.qml new file mode 100644 index 0000000..a92e0c2 --- /dev/null +++ b/src/controls/templates/private/ScrollView.qml @@ -0,0 +1,207 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import org.kde.kirigami 2.4 + +MouseArea { + id: root + default property Item contentItem + property Flickable flickableItem + clip: true + + //TODO: horizontalScrollBarPolicy is completely noop just for compatibility right now + property int horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + property int verticalScrollBarPolicy: Qt.ScrollBarAsNeeded + + readonly property Item verticalScrollBar: flickableItem.ScrollBar.vertical ? flickableItem.ScrollBar.vertical : null + + onVerticalScrollBarPolicyChanged: { + if (flickableItem.ScrollBar.vertical) { + flickableItem.ScrollBar.vertical.visible = verticalScrollBarPolicy != Qt.ScrollBarAlwaysOff; + } + scrollBarCreationTimer.restart(); + } + onHorizontalScrollBarPolicyChanged: { + if (flickableItem.ScrollBar.horizontal) { + flickableItem.ScrollBar.horizontal.visible = horizontalScrollBarPolicy != Qt.ScrollBarAlwaysOff; + } + scrollBarCreationTimer.restart(); + } + + drag.filterChildren: !Settings.tabletMode + onPressed: { + if (Settings.tabletMode) { + return; + } + mouse.accepted = false; + flickableItem.interactive = true; + } + onReleased: { + if (Settings.tabletMode) { + return; + } + mouse.accepted = false; + flickableItem.interactive = false; + } + onWheel: { + if (Settings.tabletMode || flickableItem.contentHeight 0) { + y = flickableItem.height; + } else if (y < 0) { + y = -flickableItem.height; + } + } + + var minYExtent = flickableItem.topMargin - flickableItem.originY; + var maxYExtent = flickableItem.height - (flickableItem.contentHeight + flickableItem.bottomMargin + flickableItem.originY); + + flickableItem.contentY = Math.min(-maxYExtent, Math.max(-minYExtent, flickableItem.contentY - y)); + + //this is just for making the scrollbar appear + flickableItem.flick(0, 0); + flickableItem.cancelFlick(); + } + Connections { + target: flickableItem + enabled: !Settings.tabletMode + onFlickEnded: { + flickableItem.interactive = false; + flickableItem.contentY = Math.round(flickableItem.contentY); + } + onMovementEnded: { + flickableItem.interactive = false; + flickableItem.contentY = Math.round(flickableItem.contentY); + } + } + + onContentItemChanged: { + if (contentItem.hasOwnProperty("contentY")) { + flickableItem = contentItem; + if (typeof(flickableItem.keyNavigationEnabled) != "undefined") { + flickableItem.keyNavigationEnabled = true; + flickableItem.keyNavigationWraps = true; + } + contentItem.parent = flickableParent; + } else { + flickableItem = flickableComponent.createObject(flickableParent); + contentItem.parent = flickableItem.contentItem; + } + //TODO: find a way to make flicking work on laptops with touch screen + flickableItem.interactive = Settings.tabletMode; + flickableItem.anchors.fill = flickableParent; + + scrollBarCreationTimer.restart(); + } + + Timer { + id: scrollBarCreationTimer + interval: 0 + onTriggered: { + //create or destroy the vertical scrollbar + if ((!flickableItem.ScrollBar.vertical) && + verticalScrollBarPolicy != Qt.ScrollBarAlwaysOff) { + flickableItem.ScrollBar.vertical = verticalScrollComponent.createObject(root); + } else if (flickableItem.ScrollBar.vertical && + verticalScrollBarPolicy == Qt.ScrollBarAlwaysOff) { + flickableItem.ScrollBar.vertical.destroy(); + } + + //create or destroy the horizontal scrollbar + if ((!flickableItem.ScrollBar.horizontal) && + horizontalScrollBarPolicy != Qt.ScrollBarAlwaysOff) { + flickableItem.ScrollBar.horizontal = horizontalScrollComponent.createObject(root); + } else if (flickableItem.ScrollBar.horizontal && + horizontalScrollBarPolicy == Qt.ScrollBarAlwaysOff) { + flickableItem.ScrollBar.horizontal.destroy(); + } + } + } + MultiPointTouchArea { + id: flickableParent + anchors { + fill: parent + } + //clip: true + mouseEnabled: false + maximumTouchPoints: 1 + property bool touchPressed: false + onPressed: { + touchPressed = true; + flickableItem.interactive = true; + } + onReleased: touchPressed = false; + onCanceled: touchPressed = false; + } + Component { + id: flickableComponent + Flickable { + anchors { + fill: parent + } + contentWidth: root.contentItem ? root.contentItem.width : 0 + contentHeight: root.contentItem ? root.contentItem.height : 0 + } + } + Component { + id: verticalScrollComponent + ScrollBar { + z: flickableParent.z + 1 + visible: root.contentItem.visible && size < 1 + interactive: !Settings.tabletMode + + //NOTE: use this instead of anchors as crashes on some Qt 5.8 checkouts + height: parent.height - anchors.topMargin + anchors { + topMargin: parent.flickableItem.headerItem ? parent.flickableItem.headerItem.height : 0 + right: parent.right + top: parent.top + } + } + } + Component { + id: horizontalScrollComponent + ScrollBar { + z: flickableParent.z + 1 + visible: root.contentItem.visible && size < 1 + interactive: !Settings.tabletMode + + //NOTE: use this instead of anchors as crashes on some Qt 5.8 checkouts + height: parent.height - anchors.topMargin + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + } + } +} diff --git a/src/controls/templates/qmldir b/src/controls/templates/qmldir new file mode 100644 index 0000000..295c78c --- /dev/null +++ b/src/controls/templates/qmldir @@ -0,0 +1,10 @@ +module org.kde.kirigami.templates + +OverlaySheet 2.2 OverlaySheet.qml +FormLayout 2.2 FormLayout.qml +SwipeListItem 2.2 SwipeListItem.qml +AbstractListItem 2.2 AbstractListItem.qml +ApplicationHeader 2.2 ApplicationHeader.qml +AbstractApplicationHeader 2.2 AbstractApplicationHeader.qml +OverlayDrawer 2.2 OverlayDrawer.qml + diff --git a/src/delegaterecycler.cpp b/src/delegaterecycler.cpp new file mode 100644 index 0000000..d0c622a --- /dev/null +++ b/src/delegaterecycler.cpp @@ -0,0 +1,334 @@ +/* + * Copyright 2011 Marco Martin + * Copyright 2014 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "delegaterecycler.h" + +#include +#include +#include +#include + +class DelegateCache +{ +public: + DelegateCache(); + ~DelegateCache(); + + void ref(QQmlComponent *); + void deref(QQmlComponent *); + + void insert(QQmlComponent *, QQuickItem *); + QQuickItem *take(QQmlComponent *); + +private: + static const int s_cacheSize = 40; + QHash m_refs; + QHash > m_unusedItems; +}; + +Q_GLOBAL_STATIC(DelegateCache, s_delegateCache) + +DelegateCache::DelegateCache() +{ +} + +DelegateCache::~DelegateCache() +{ + for (auto& item : qAsConst(m_unusedItems)) { + qDeleteAll(item); + } +} + +void DelegateCache::ref(QQmlComponent *component) +{ + m_refs[component]++; +} + +void DelegateCache::deref(QQmlComponent *component) +{ + auto itRef = m_refs.find(component); + if (itRef == m_refs.end()) { + return; + } + + (*itRef)--; + if (*itRef <= 0) { + m_refs.erase(itRef); + + qDeleteAll(m_unusedItems.take(component)); + } +} + +void DelegateCache::insert(QQmlComponent *component, QQuickItem *item) +{ + auto& items = m_unusedItems[component]; + if (items.length() >= s_cacheSize) { + item->deleteLater(); + return; + } + + item->setParentItem(nullptr); + items.append(item); +} + +QQuickItem *DelegateCache::take(QQmlComponent *component) +{ + auto it = m_unusedItems.find(component); + if (it != m_unusedItems.end() && !it->isEmpty()) { + return it->takeFirst(); + } + return nullptr; +} + + + + + +DelegateRecycler::DelegateRecycler(QQuickItem *parent) + : QQuickItem(parent) +{ +} + +DelegateRecycler::~DelegateRecycler() +{ + if (m_sourceComponent) { + s_delegateCache->insert(m_sourceComponent, m_item); + s_delegateCache->deref(m_sourceComponent); + } +} + +void DelegateRecycler::syncIndex() +{ + const QVariant newIndex = m_propertiesTracker->property("trackedIndex"); + if (!newIndex.isValid()) { + return; + } + QQmlContext *ctx = QQmlEngine::contextForObject(m_item)->parentContext(); + ctx->setContextProperty(QStringLiteral("index"), newIndex); +} + +void DelegateRecycler::syncModel() +{ + const QVariant newModel = m_propertiesTracker->property("trackedModel"); + if (!newModel.isValid()) { + return; + } + QQmlContext *ctx = QQmlEngine::contextForObject(m_item)->parentContext(); + ctx->setContextProperty(QStringLiteral("model"), newModel); + + //try to bind all properties + QObject *modelObj = newModel.value(); + if (modelObj) { + const QMetaObject *metaObj = modelObj->metaObject(); + for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) { + ctx->setContextProperty(QString::fromUtf8(metaObj->property(i).name()), metaObj->property(i).read(modelObj)); + } + } +} + +void DelegateRecycler::syncModelData() +{ + const QVariant newModelData = m_propertiesTracker->property("trackedModelData"); + if (!newModelData.isValid()) { + return; + } + QQmlContext *ctx = QQmlEngine::contextForObject(m_item)->parentContext(); + ctx->setContextProperty(QStringLiteral("modelData"), newModelData); +} + +QQmlComponent *DelegateRecycler::sourceComponent() const +{ + return m_sourceComponent; +} + +void DelegateRecycler::setSourceComponent(QQmlComponent *component) +{ + if (component && component->parent() == this) { + qWarning() << "Error: source components cannot be declared inside DelegateRecycler"; + return; + } + if (m_sourceComponent == component) { + return; + } + + if (!m_propertiesTracker) { + static QMap propertiesTrackerComponent; + auto engine = qmlEngine(this); + auto it = propertiesTrackerComponent.find(engine); + if (it == propertiesTrackerComponent.end()) { + connect(engine, &QObject::destroyed, engine, [engine] { propertiesTrackerComponent.remove(engine); }); + it = propertiesTrackerComponent.insert(engine, new QQmlComponent(engine, engine)); + + (*it)->setData(QByteArrayLiteral("import QtQuick 2.3\nQtObject{property int trackedIndex: index; property var trackedModel: typeof model != 'undefined' ? model : null; property var trackedModelData: typeof modelData != 'undefined' ? modelData : null}"), QUrl()); + } + m_propertiesTracker = (*it)->create(QQmlEngine::contextForObject(this)); + + connect(m_propertiesTracker, SIGNAL(trackedIndexChanged()), this, SLOT(syncIndex())); + connect(m_propertiesTracker, SIGNAL(trackedModelChanged()), this, SLOT(syncModel())); + connect(m_propertiesTracker, SIGNAL(trackedModelDataChanged()), this, SLOT(syncModelData())); + } + + if (m_sourceComponent) { + if (m_item) { + disconnect(m_item.data(), &QQuickItem::implicitWidthChanged, this, &DelegateRecycler::updateHints); + disconnect(m_item.data(), &QQuickItem::implicitHeightChanged, this, &DelegateRecycler::updateHints); + s_delegateCache->insert(component, m_item); + } + s_delegateCache->deref(component); + } + + m_sourceComponent = component; + s_delegateCache->ref(component); + + m_item = s_delegateCache->take(component); + + if (!m_item) { + QQuickItem *candidate = parentItem(); + QQmlContext *ctx = nullptr; + while (candidate) { + QQmlContext *parentCtx = QQmlEngine::contextForObject(candidate); + if (parentCtx) { + ctx = new QQmlContext(parentCtx, candidate); + break; + } else { + candidate = candidate->parentItem(); + } + } + + Q_ASSERT(ctx); + + if (QQmlEngine *eng = qmlEngine(this)) { + //share context object in order to never lose track of global i18n() + ctx->setContextObject(eng->rootContext()->contextObject()); + } + + QObject *modelObj = m_propertiesTracker->property("trackedModel").value(); + if (modelObj) { + const QMetaObject *metaObj = modelObj->metaObject(); + for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) { + ctx->setContextProperty(QString::fromUtf8(metaObj->property(i).name()), metaObj->property(i).read(modelObj)); + } + } + ctx->setContextProperty(QStringLiteral("model"), m_propertiesTracker->property("trackedModel")); + ctx->setContextProperty(QStringLiteral("modelData"), m_propertiesTracker->property("trackedModelData")); + ctx->setContextProperty(QStringLiteral("index"), m_propertiesTracker->property("trackedIndex")); + ctx->setContextProperty(QStringLiteral("delegateRecycler"), this); + + QObject * obj = component->create(ctx); + m_item = qobject_cast(obj); + if (!m_item) { + obj->deleteLater(); + } else { + connect(m_item.data(), &QObject::destroyed, ctx, &QObject::deleteLater); + //if the user binded an explicit width, consider it, otherwise base upon implicit + m_widthFromItem = m_item->width() > 0 && m_item->width() != m_item->implicitWidth(); + m_heightFromItem = m_item->height() > 0 && m_item->height() != m_item->implicitHeight(); + + if (m_widthFromItem && m_heightFromItem) { + connect(m_item.data(), &QQuickItem::heightChanged, this, [this]() { + updateSize(false); + }); + } + } + } else { + syncModel(); + + QQmlContext *ctx = QQmlEngine::contextForObject(m_item)->parentContext(); +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + ctx->setContextProperty(QStringLiteral("modelData"), m_propertiesTracker->property("trackedModelData")); + ctx->setContextProperty(QStringLiteral("index"), m_propertiesTracker->property("trackedIndex")); + ctx->setContextProperty(QStringLiteral("delegateRecycler"), QVariant::fromValue(this)); +#else + ctx->setContextProperties({ QQmlContext::PropertyPair{ QStringLiteral("modelData"), m_propertiesTracker->property("trackedModelData") }, + QQmlContext::PropertyPair{ QStringLiteral("index"), m_propertiesTracker->property("trackedIndex")}, + QQmlContext::PropertyPair{ QStringLiteral("delegateRecycler"), QVariant::fromValue(this) } + }); +#endif + } + + if (m_item) { + m_item->setParentItem(this); + connect(m_item.data(), &QQuickItem::implicitWidthChanged, this, &DelegateRecycler::updateHints); + connect(m_item.data(), &QQuickItem::implicitHeightChanged, this, &DelegateRecycler::updateHints); + + updateSize(true); + } + + emit sourceComponentChanged(); +} + +void DelegateRecycler::resetSourceComponent() +{ + s_delegateCache->deref(m_sourceComponent); + m_sourceComponent = nullptr; +} + +void DelegateRecycler::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (m_item && newGeometry.size() != oldGeometry.size()) { + updateSize(true); + } + QQuickItem::geometryChanged(newGeometry, oldGeometry); +} + +void DelegateRecycler::updateHints() +{ + updateSize(false); +} + +void DelegateRecycler::updateSize(bool parentResized) +{ + if (!m_item) { + return; + } + + const bool needToUpdateWidth = !m_widthFromItem && parentResized && widthValid(); + const bool needToUpdateHeight = !m_heightFromItem && parentResized && heightValid(); + + if (parentResized) { + m_item->setPosition(QPoint(0,0)); + } + if (needToUpdateWidth && needToUpdateHeight) { + m_item->setSize(QSizeF(width(), height())); + } else if (needToUpdateWidth) { + m_item->setWidth(width()); + } else if (needToUpdateHeight) { + m_item->setHeight(height()); + } + + if (m_updatingSize) { + return; + } + + m_updatingSize = true; + + if (m_heightFromItem) { + setHeight(m_item->height()); + } + if (m_widthFromItem) { + setWidth(m_item->width()); + } + + setImplicitSize(m_item->implicitWidth() >= 0 ? m_item->implicitWidth() : m_item->width(), + m_item->implicitHeight() >= 0 ? m_item->implicitHeight() : m_item->height()); + + + m_updatingSize = false; +} diff --git a/src/delegaterecycler.h b/src/delegaterecycler.h new file mode 100644 index 0000000..5c8a456 --- /dev/null +++ b/src/delegaterecycler.h @@ -0,0 +1,89 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DELEGATERECYCLER_H +#define DELEGATERECYCLER_H + +#include +#include +#include + + +class DelegateCache; + +/** + * This class may be used as a delegate of a ListView or a GridView in the case + * the intended delegate is a bit heavy, with many objects inside. + * This will ensure the delegate instances will be put back in a common pool after + * destruction, so when scrolling a big list, the delegates from old delete items will + * be taken from the pool and reused, minimizing the need of instantiating new objects + * and deleting old ones. It ensures scrolling of lists with heavy delegates is + * smoother and helps with memory fragmentations as well. + * + * NOTE: CardListView and CardGridView are already using this recycler, so do NOT use it + * as a delegate for those 2 views. + * Also, do NOT use this with a Repeater. + * @since 2.4 + */ +class DelegateRecycler : public QQuickItem +{ + Q_OBJECT + + /** + * The Component the actual delegates will be built from. + * Note: the component may not be a child of this object, therefore it can't be + * declared inside the DelegateRecycler declaration. + * The DelegateRecycler will not take ownership of the delegate Component, so it's up + * to the caller to delete it (usually with the normal child/parent relationship) + */ + Q_PROPERTY(QQmlComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged) + +public: + DelegateRecycler(QQuickItem *parent = nullptr); + ~DelegateRecycler(); + + + QQmlComponent *sourceComponent() const; + void setSourceComponent(QQmlComponent *component); + void resetSourceComponent(); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + void updateHints(); + void updateSize(bool parentResized); + +Q_SIGNALS: + void sourceComponentChanged(); + +private Q_SLOTS: + void syncIndex(); + void syncModel(); + void syncModelData(); + +private: + QPointer m_sourceComponent; + QPointer m_item; + QObject *m_propertiesTracker = nullptr; + bool m_updatingSize = false; + bool m_widthFromItem = false; + bool m_heightFromItem = false; +}; + +#endif diff --git a/src/desktopicon.cpp b/src/desktopicon.cpp new file mode 100644 index 0000000..88c9779 --- /dev/null +++ b/src/desktopicon.cpp @@ -0,0 +1,540 @@ +/* + * Copyright 2011 Marco Martin + * Copyright 2014 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "desktopicon.h" +#include "libkirigami/platformtheme.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ManagedTextureNode : public QSGSimpleTextureNode +{ +Q_DISABLE_COPY(ManagedTextureNode) +public: + ManagedTextureNode(); + + void setTexture(QSharedPointer texture); + +private: + QSharedPointer m_texture; +}; + +ManagedTextureNode::ManagedTextureNode() +{} + +void ManagedTextureNode::setTexture(QSharedPointer texture) +{ + m_texture = texture; + QSGSimpleTextureNode::setTexture(texture.data()); +} + +typedef QHash > > TexturesCache; + +struct ImageTexturesCachePrivate +{ + TexturesCache cache; +}; + +class ImageTexturesCache +{ +public: + ImageTexturesCache(); + ~ImageTexturesCache(); + + /** + * @returns the texture for a given @p window and @p image. + * + * If an @p image id is the same as one already provided before, we won't create + * a new texture and return a shared pointer to the existing texture. + */ + QSharedPointer loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options); + + QSharedPointer loadTexture(QQuickWindow *window, const QImage &image); + + +private: + QScopedPointer d; +}; + + +ImageTexturesCache::ImageTexturesCache() + : d(new ImageTexturesCachePrivate) +{ +} + +ImageTexturesCache::~ImageTexturesCache() +{ +} + +QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options) +{ + qint64 id = image.cacheKey(); + QSharedPointer texture = d->cache.value(id).value(window).toStrongRef(); + + if (!texture) { + auto cleanAndDelete = [this, window, id](QSGTexture* texture) { + QHash >& textures = (d->cache)[id]; + textures.remove(window); + if (textures.isEmpty()) + d->cache.remove(id); + delete texture; + }; + texture = QSharedPointer(window->createTextureFromImage(image, options), cleanAndDelete); + (d->cache)[id][window] = texture.toWeakRef(); + } + + //if we have a cache in an atlas but our request cannot use an atlassed texture + //create a new texture and use that + //don't use removedFromAtlas() as that requires keeping a reference to the non atlased version + if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) { + texture = QSharedPointer(window->createTextureFromImage(image, options)); + } + + return texture; +} + +QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image) +{ + return loadTexture(window, image, nullptr); +} + +Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache) + +DesktopIcon::DesktopIcon(QQuickItem *parent) + : QQuickItem(parent), + m_smooth(false), + m_changed(false), + m_active(false), + m_selected(false), + m_isMask(false) +{ + setFlag(ItemHasContents, true); + //FIXME: not necessary anymore + connect(qApp, &QGuiApplication::paletteChanged, this, [this]() { + m_changed = true; + update(); + }); +} + + +DesktopIcon::~DesktopIcon() +{ +} + +void DesktopIcon::setSource(const QVariant &icon) +{ + if (m_source == icon) { + return; + } + m_source = icon; + m_changed = true; + + if (!m_theme) { + m_theme = static_cast(qmlAttachedPropertiesObject(this, true)); + Q_ASSERT(m_theme); + + connect(m_theme, &Kirigami::PlatformTheme::colorsChanged, this, [this]() { + m_changed = true; + update(); + }); + } + + if (m_networkReply) { + //if there was a network query going on, interrupt it + m_networkReply->close(); + } + m_loadedImage = QImage(); + update(); + emit sourceChanged(); +} + +QVariant DesktopIcon::source() const +{ + return m_source; +} + +void DesktopIcon::setEnabled(const bool enabled) +{ + if (enabled == QQuickItem::isEnabled()) { + return; + } + QQuickItem::setEnabled(enabled); + m_changed = true; + update(); + emit enabledChanged(); +} + + +void DesktopIcon::setActive(const bool active) +{ + if (active == m_active) { + return; + } + m_active = active; + m_changed = true; + update(); + emit activeChanged(); +} + +bool DesktopIcon::active() const +{ + return m_active; +} + +bool DesktopIcon::valid() const +{ + return !m_source.isNull(); +} + +void DesktopIcon::setSelected(const bool selected) +{ + if (selected == m_selected) { + return; + } + m_selected = selected; + m_changed = true; + update(); + emit selectedChanged(); +} + +bool DesktopIcon::selected() const +{ + return m_selected; +} + +void DesktopIcon::setIsMask(bool mask) +{ + if (m_isMask == mask) { + return; + } + + m_isMask = mask; + m_changed = true; + update(); + emit isMaskChanged(); +} + +bool DesktopIcon::isMask() const +{ + return m_isMask; +} + +void DesktopIcon::setColor(const QColor &color) +{ + if (m_color == color) { + return; + } + + m_color = color; + m_changed = true; + update(); + emit colorChanged(); +} + +QColor DesktopIcon::color() const +{ + return m_color; +} + + +int DesktopIcon::implicitWidth() const +{ + return 32; +} + +int DesktopIcon::implicitHeight() const +{ + return 32; +} + +void DesktopIcon::setSmooth(const bool smooth) +{ + if (smooth == m_smooth) { + return; + } + m_smooth = smooth; + m_changed = true; + update(); + emit smoothChanged(); +} + +bool DesktopIcon::smooth() const +{ + return m_smooth; +} + +QSGNode* DesktopIcon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/) +{ + if (m_source.isNull()) { + delete node; + return Q_NULLPTR; + } + + if (m_changed || node == nullptr) { + QImage img; + const QSize itemSize(width(), height()); + QRect nodeRect(QPoint(0,0), itemSize); + + if (itemSize.width() != 0 && itemSize.height() != 0) { + const auto multiplier = QCoreApplication::instance()->testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1 : (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()); + const QSize size = itemSize * multiplier; + + switch(m_source.type()){ + case QVariant::Pixmap: + img = m_source.value().toImage(); + break; + case QVariant::Image: + img = m_source.value(); + break; + case QVariant::Bitmap: + img = m_source.value().toImage(); + break; + case QVariant::Icon: + img = m_source.value().pixmap(size, iconMode(), QIcon::On).toImage(); + break; + case QVariant::Url: + case QVariant::String: + img = findIcon(size); + break; + case QVariant::Brush: + //todo: fill here too? + case QVariant::Color: + img = QImage(size, QImage::Format_Alpha8); + img.fill(m_source.value()); + break; + default: + break; + } + + if (img.isNull()){ + img = QImage(size, QImage::Format_Alpha8); + img.fill(Qt::transparent); + } + if (img.size() != size){ + // At this point, the image will already be scaled, but we need to output it in + // the correct aspect ratio, painted centered in the viewport. So: + QRect destination(QPoint(0, 0), img.size().scaled(itemSize, Qt::KeepAspectRatio)); + destination.moveCenter(nodeRect.center()); + nodeRect = destination; + } + } + m_changed = false; + + ManagedTextureNode* mNode = dynamic_cast(node); + if (!mNode) { + delete node; + mNode = new ManagedTextureNode; + } + mNode->setTexture(s_iconImageCache->loadTexture(window(), img)); + mNode->setRect(nodeRect); + node = mNode; + if (m_smooth) { + mNode->setFiltering(QSGTexture::Linear); + } + } + + return node; +} + +void DesktopIcon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (newGeometry.size() != oldGeometry.size()) { + m_changed = true; + update(); + } + QQuickItem::geometryChanged(newGeometry, oldGeometry); +} + +void DesktopIcon::handleFinished(QNetworkAccessManager* qnam, QNetworkReply* reply) { + if (reply && reply->error() == QNetworkReply::NoError) { + const QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (!possibleRedirectUrl.isEmpty()) { + const QUrl redirectUrl = reply->url().resolved(possibleRedirectUrl); + if (redirectUrl == reply->url()) { + // no infinite redirections thank you very much + reply->deleteLater(); + return; + } + reply->deleteLater(); + QNetworkRequest request(possibleRedirectUrl); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + m_networkReply = qnam->get(request); + connect(m_networkReply.data(), &QNetworkReply::readyRead, this, [this](){handleReadyRead(m_networkReply); }); + connect(m_networkReply.data(), &QNetworkReply::finished, this, [this, qnam](){handleFinished(qnam, m_networkReply); }); + return; + } + } +} + +void DesktopIcon::handleReadyRead(QNetworkReply* reply) +{ + if (reply && reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) { + // We're handing the event loop back while doing network work, and it turns out + // this fairly regularly results in things being deleted under us. So, just + // handle that and crash less :) + QPointer me(this); + QPointer guardedReply(reply); + QByteArray data; + do { + data.append(guardedReply->read(32768)); + // Because we are in the main thread, this could be potentially very expensive, so let's not block + qApp->processEvents(); + if(!me || !guardedReply) { + return; + } + } while(!guardedReply->atEnd()); + m_loadedImage = QImage::fromData(data); + if (m_loadedImage.isNull()) { + // broken image from data, inform the user of this with some useful broken-image thing... + const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()); + m_loadedImage = QIcon::fromTheme(m_fallback).pixmap(size, iconMode(), QIcon::On).toImage(); + } + m_changed = true; + update(); + } +} + +QImage DesktopIcon::findIcon(const QSize &size) +{ + QImage img; + QString iconSource = m_source.toString(); + + if (iconSource.startsWith(QLatin1String("image://"))) { + QUrl iconUrl(iconSource); + QString iconProviderId = iconUrl.host(); + QString iconId = iconUrl.path(); + + // QRC paths are not correctly handled by .path() + if (iconId.size() >=2 && iconId.startsWith(QLatin1String("/:"))) { + iconId = iconId.remove(0, 1); + } + + QSize actualSize; + QQuickImageProvider* imageProvider = dynamic_cast( + qmlEngine(this)->imageProvider(iconProviderId)); + if (!imageProvider) + return img; + switch(imageProvider->imageType()){ + case QQmlImageProviderBase::Image: + img = imageProvider->requestImage(iconId, &actualSize, size); + break; + case QQmlImageProviderBase::Pixmap: + img = imageProvider->requestPixmap(iconId, &actualSize, size).toImage(); + break; + case QQmlImageProviderBase::Texture: + case QQmlImageProviderBase::Invalid: + case QQmlImageProviderBase::ImageResponse: + //will have to investigate this more + break; + } + } else if(iconSource.startsWith(QLatin1String("http://")) || iconSource.startsWith(QLatin1String("https://"))) { + if(!m_loadedImage.isNull()) { + return m_loadedImage.scaled(size, Qt::KeepAspectRatio, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation ); + } + const auto url = m_source.toUrl(); + QQmlEngine* engine = qmlEngine(this); + QNetworkAccessManager* qnam; + if (engine && (qnam = engine->networkAccessManager()) && (!m_networkReply || m_networkReply->url() != url)) { + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + m_networkReply = qnam->get(request); + connect(m_networkReply.data(), &QNetworkReply::readyRead, this, [this](){ handleReadyRead(m_networkReply); }); + connect(m_networkReply.data(), &QNetworkReply::finished, this, [this, qnam](){ handleFinished(qnam, m_networkReply); }); + } + // Temporary icon while we wait for the real image to load... + img = QIcon::fromTheme(QStringLiteral("image-x-icon")).pixmap(size, iconMode(), QIcon::On).toImage(); + } else { + if (iconSource.startsWith(QLatin1String("qrc:/"))) { + iconSource = iconSource.mid(3); + } else if (iconSource.startsWith(QLatin1String("file:/"))) { + iconSource = QUrl(iconSource).path(); + } + + QIcon icon; + const bool isPath = iconSource.contains(QLatin1String("/")); + if (isPath) { + icon = QIcon(iconSource); + } else { + if (icon.isNull()) { + icon = m_theme->iconFromTheme(iconSource, m_color); + } + } + if (!icon.isNull()) { + img = icon.pixmap(size, iconMode(), QIcon::On).toImage(); + qreal ratio = 1; + if (window() && window()->screen()) { + ratio = window()->screen()->devicePixelRatio(); + } + + const QColor tintColor = !m_color.isValid() || m_color == Qt::transparent ? (m_selected ? m_theme->highlightedTextColor() : m_theme->textColor()) : m_color; + + if (m_isMask || + //this is an heuristic to decide when to tint and when to just draw + //(fullcolor icons) in reality on basic styles the only colored icons should be -symbolic, this heuristic is the most compatible middle ground + icon.isMask() || + //if symbolic color based on tintColor + (iconSource.endsWith(QLatin1String("-symbolic")) && tintColor.isValid() && tintColor != Qt::transparent) || + //if path color based on m_color + (isPath && m_color.isValid() && m_color != Qt::transparent)) { + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(img.rect(), tintColor); + p.end(); + } + } + } + return img; +} + +QIcon::Mode DesktopIcon::iconMode() const +{ + if (!isEnabled()) { + return QIcon::Disabled; + } else if (m_selected) { + return QIcon::Selected; + } else if (m_active) { + return QIcon::Active; + } + return QIcon::Normal; +} + +QString DesktopIcon::fallback() const +{ + return m_fallback; +} + +void DesktopIcon::setFallback(const QString& fallback) +{ + if (m_fallback != fallback) { + m_fallback = fallback; + Q_EMIT fallbackChanged(fallback); + } +} diff --git a/src/desktopicon.h b/src/desktopicon.h new file mode 100644 index 0000000..8f2d71b --- /dev/null +++ b/src/desktopicon.h @@ -0,0 +1,118 @@ +/* + * Copyright 2011 Marco Martin + * Copyright 2014 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DESKTOPICON_H +#define DESKTOPICON_H + +#include +#include +#include +#include + +class QNetworkAccessManager; +class QNetworkReply; + +namespace Kirigami { + class PlatformTheme; +} + +class DesktopIcon : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged) + Q_PROPERTY(int implicitWidth READ implicitWidth CONSTANT) + Q_PROPERTY(int implicitHeight READ implicitHeight CONSTANT) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(bool valid READ valid NOTIFY validChanged) + Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged) + Q_PROPERTY(bool isMask READ isMask WRITE setIsMask NOTIFY isMaskChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_PROPERTY(QString fallback READ fallback WRITE setFallback NOTIFY fallbackChanged) + +public: + DesktopIcon(QQuickItem *parent = nullptr); + ~DesktopIcon(); + + void setSource(const QVariant &source); + QVariant source() const; + + int implicitWidth() const; + int implicitHeight() const; + + void setSmooth(const bool smooth); + bool smooth() const; + + void setEnabled(bool enabled = true); + + void setActive(bool active = true); + bool active() const; + + bool valid() const; + + void setSelected(bool selected = true); + bool selected() const; + + void setIsMask(bool mask); + bool isMask() const; + + void setColor(const QColor &color); + QColor color() const; + + QString fallback() const; + void setFallback(const QString &fallback); + + QSGNode* updatePaintNode(QSGNode* node, UpdatePaintNodeData* data) override; + +Q_SIGNALS: + void sourceChanged(); + void smoothChanged(); + void enabledChanged(); + void activeChanged(); + void validChanged(); + void selectedChanged(); + void isMaskChanged(); + void colorChanged(); + void fallbackChanged(const QString &fallback); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + QImage findIcon(const QSize& size); + void handleFinished(QNetworkAccessManager* qnam, QNetworkReply* reply); + void handleReadyRead(QNetworkReply* reply); + QIcon::Mode iconMode() const; + +private: + Kirigami::PlatformTheme *m_theme = nullptr; + QPointer m_networkReply; + QVariant m_source; + bool m_smooth; + bool m_changed; + bool m_active; + bool m_selected; + bool m_isMask; + QImage m_loadedImage; + QColor m_color = Qt::transparent; + QString m_fallback = QStringLiteral("unknown"); +}; + +#endif diff --git a/src/enums.cpp b/src/enums.cpp new file mode 100644 index 0000000..5c10162 --- /dev/null +++ b/src/enums.cpp @@ -0,0 +1,22 @@ +/* +* Copyright (C) 2016 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "enums.h" + +#include "moc_enums.cpp" diff --git a/src/enums.h b/src/enums.h new file mode 100644 index 0000000..2c1e2b5 --- /dev/null +++ b/src/enums.h @@ -0,0 +1,55 @@ +/* +* Copyright (C) 2016 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef ENUMS_H +#define ENUMS_H + +#include + +class ApplicationHeaderStyle : public QObject +{ + Q_OBJECT + Q_ENUMS(Status) + +public: + enum Status { + Auto = 0, + Breadcrumb, + Titles, + TabBar, + ToolBar, ///@since 5.48 + None ///@since 5.48 + }; +}; + +class MessageType : public QObject +{ + Q_OBJECT + Q_ENUMS(Type) + +public: + enum Type { + Information = 0, + Positive, + Warning, + Error + }; +}; + +#endif // ENUMS_H diff --git a/src/formlayoutattached.cpp b/src/formlayoutattached.cpp new file mode 100644 index 0000000..13754a4 --- /dev/null +++ b/src/formlayoutattached.cpp @@ -0,0 +1,129 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "formlayoutattached.h" +#include +#include + +FormLayoutAttached::FormLayoutAttached(QObject *parent) + : QObject(parent) +{ + m_buddyFor = qobject_cast(parent); +} + +FormLayoutAttached::~FormLayoutAttached() +{ +} + +void FormLayoutAttached::setLabel(const QString &text) +{ + if (m_label == text) { + return; + } + + m_label = text; + emit labelChanged(); +} + +QString FormLayoutAttached::label() const +{ + return m_label; +} + +void FormLayoutAttached::setIsSection(bool section) +{ + if (m_isSection == section) { + return; + } + + m_isSection = section; + emit isSectionChanged(); +} + +bool FormLayoutAttached::isSection() const +{ + return m_isSection; +} + +void FormLayoutAttached::setCheckable(bool checkable) +{ + if (checkable == m_checkable) { + return; + } + + m_checkable = checkable; + emit checkableChanged(); +} + +bool FormLayoutAttached::checkable() const +{ + return m_checkable; +} + +void FormLayoutAttached::setChecked(bool checked) +{ + if (checked == m_checked) { + return; + } + + m_checked = checked; + emit checkedChanged(); +} + +bool FormLayoutAttached::checked() const +{ + return m_checked; +} + +void FormLayoutAttached::setEnabled(bool enabled) +{ + if (enabled == m_enabled) { + return; + } + + m_enabled = enabled; + emit enabledChanged(); +} + +bool FormLayoutAttached::enabled() const +{ + return m_enabled; +} + +QQuickItem *FormLayoutAttached::buddyFor() const +{ + return m_buddyFor; +} + +void FormLayoutAttached::setBuddyFor(QQuickItem *buddyfor) +{ + if (m_buddyFor == buddyfor || !m_buddyFor->isAncestorOf(buddyfor)) { + return; + } + + m_buddyFor = buddyfor; + emit buddyForChanged(); +} + +FormLayoutAttached *FormLayoutAttached::qmlAttachedProperties(QObject *object) +{ + return new FormLayoutAttached(object); +} + +#include "moc_formlayoutattached.cpp" diff --git a/src/formlayoutattached.h b/src/formlayoutattached.h new file mode 100644 index 0000000..8061d24 --- /dev/null +++ b/src/formlayoutattached.h @@ -0,0 +1,169 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef FORMLAYOUTATTACHED_H +#define FORMLAYOUTATTACHED_H + +#include +#include + +class QQuickItem; + +/** + * This attached property contains the information for decorating a FormLayout: + * It contains the text labels of fields and information about sections. + * @code + * import org.kde.kirigami 2.3 as Kirigami + * Kirigami.FormLayout { + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * } + * @endcode + * @since 2.3 + */ +class FormLayoutAttached : public QObject +{ + Q_OBJECT + /** + * The label for a form layout field + */ + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + /** + * If true the FormLayout item is a section separator, a section separator + * may have different looks: + * * To make it just a space between two fields, just put an empty item with isSection: + * @code + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * Item { + * Kirigami.FormData.isSection: true + * } + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * @endcode + * + * * To make it a space with a section title: + * @code + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * Item { + * Kirigami.FormData.label: "Section Title" + * Kirigami.FormData.isSection: true + * } + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * @endcode + * + * * To make it a space with a section title and a separator line: + * @code + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * Kirigami.Separator { + * Kirigami.FormData.label: "Section Title" + * Kirigami.FormData.isSection: true + * } + * TextField { + * Kirigami.FormData.label: "Label:" + * } + * @endcode + */ + Q_PROPERTY(bool isSection READ isSection WRITE setIsSection NOTIFY isSectionChanged) + + /** + * If true a checkbox is prepended to the FormLayout item. + */ + Q_PROPERTY(bool checkable READ checkable WRITE setCheckable NOTIFY checkableChanged) + + /** + * This property is true when the checkbox of the FormLayout item is checked, @see checkable. + */ + Q_PROPERTY(bool checked READ checked WRITE setChecked NOTIFY checkedChanged) + + /** + * This property holds whether the label and the checkbox of the FormLayout item receive mouse and keyboard events. + */ + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + + /** + * The Item the label will be considered a "Buddy" for, + * which will be the parent item the attached property is in. + * A buddy item is useful for instance when the label has a keyboard accelerator, + * which on triggered will be given active keyboard focus to. + */ + Q_PROPERTY(QQuickItem *buddyFor READ buddyFor WRITE setBuddyFor NOTIFY buddyForChanged) + +public: + + explicit FormLayoutAttached(QObject *parent = nullptr); + ~FormLayoutAttached() override; + + void setLabel(const QString &text); + QString label() const; + + QString decoratedLabel() const; + + void setIsSection(bool section); + bool isSection() const; + + void setCheckable(bool checkable); + bool checkable() const; + + void setChecked(bool checked); + bool checked() const; + + void setEnabled(bool enabled); + bool enabled() const; + + QQuickItem *buddyFor() const; + void setBuddyFor(QQuickItem *buddyfor); + + //QML attached property + static FormLayoutAttached *qmlAttachedProperties(QObject *object); + +Q_SIGNALS: + void labelChanged(); + void isSectionChanged(); + void checkableChanged(); + void checkedChanged(); + void enabledChanged(); + void buddyForChanged(); + +private: + QString m_label; + QString m_actualDecoratedLabel; + QString m_decoratedLabel; + QPointer m_buddyFor; + bool m_isSection = false; + bool m_checkable = false; + bool m_checked = false; + bool m_enabled = true; +}; + +QML_DECLARE_TYPEINFO(FormLayoutAttached, QML_HAS_ATTACHED_PROPERTIES) + +#endif // FORMLAYOUTATTACHED_H diff --git a/src/kirigamiplugin.cpp b/src/kirigamiplugin.cpp new file mode 100644 index 0000000..868141c --- /dev/null +++ b/src/kirigamiplugin.cpp @@ -0,0 +1,184 @@ +/* + * Copyright 2009 by Alan Alpert + * Copyright 2010 by Ménard Alexis + * Copyright 2010 by Marco Martin + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kirigamiplugin.h" +#include "enums.h" +#include "desktopicon.h" +#include "settings.h" +#include "formlayoutattached.h" +#include "mnemonicattached.h" +#include "delegaterecycler.h" +#include "scenepositionattached.h" + +#include +#include +#include +#include + +#include "libkirigami/platformtheme.h" + +static QString s_selectedStyle; + +//Q_INIT_RESOURCE(kirigami); +#ifdef KIRIGAMI_BUILD_TYPE_STATIC +#include +#endif + +QUrl KirigamiPlugin::componentUrl(const QString &fileName) const +{ + foreach (const QString &style, m_stylesFallbackChain) { + const QString candidate = QStringLiteral("styles/") + style + QLatin1Char('/') + fileName; + if (QFile::exists(resolveFilePath(candidate))) { +#ifdef KIRIGAMI_BUILD_TYPE_STATIC + return QUrl(QStringLiteral("qrc:/org/kde/kirigami/styles/") + style + QLatin1Char('/') + fileName); +#else + return QUrl(resolveFileUrl(candidate)); +#endif + } + } + +#ifdef KIRIGAMI_BUILD_TYPE_STATIC + return QUrl(QStringLiteral("qrc:/org/kde/kirigami/") + fileName); +#else + return QUrl(resolveFileUrl(fileName)); +#endif +} + +void KirigamiPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.kirigami")); + const QString style = QQuickStyle::name(); + + if (!qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP")) { + QIcon::setThemeSearchPaths({resolveFilePath(QStringLiteral(".")), QStringLiteral(":/icons")}); + QIcon::setThemeName(QStringLiteral("breeze-internal")); + } + +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + //org.kde.desktop.plasma is a couple of files that fall back to desktop by purpose + if ((style.isEmpty() || style == QStringLiteral("org.kde.desktop.plasma")) && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop")))) { + m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop")); + } +#elif defined(Q_OS_ANDROID) + if (!m_stylesFallbackChain.contains(QStringLiteral("Material"))) { + m_stylesFallbackChain.prepend(QStringLiteral("Material")); + } +#else // do we have an iOS specific style? + if (!m_stylesFallbackChain.contains(QStringLiteral("Material"))) { + m_stylesFallbackChain.prepend(QStringLiteral("Material")); + } +#endif + + if (!style.isEmpty() && QFile::exists(resolveFilePath(QStringLiteral("/styles/") + style)) && !m_stylesFallbackChain.contains(style)) { + m_stylesFallbackChain.prepend(style); + //if we have plasma deps installed, use them for extra integration + if (style == QStringLiteral("org.kde.desktop") && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop.plasma")))) { + m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop.plasma")); + } + } else { +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop")); +#endif + } + //At this point the fallback chain will be selected->org.kde.desktop->Fallback + s_selectedStyle = m_stylesFallbackChain.first(); + + qmlRegisterSingletonType(uri, 2, 0, "Settings", + [](QQmlEngine*, QJSEngine*) -> QObject* { + Settings *settings = new Settings; + settings->setStyle(s_selectedStyle); + return settings; + } + ); + + qmlRegisterUncreatableType(uri, 2, 0, "ApplicationHeaderStyle", QStringLiteral("Cannot create objects of type ApplicationHeaderStyle")); + + //old legacy retrocompatible Theme + qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 2, 0, "Theme"); + + qmlRegisterSingletonType(componentUrl(QStringLiteral("Units.qml")), uri, 2, 0, "Units"); + + qmlRegisterType(componentUrl(QStringLiteral("Action.qml")), uri, 2, 0, "Action"); + qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationHeader.qml")), uri, 2, 0, "AbstractApplicationHeader"); + qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationWindow.qml")), uri, 2, 0, "AbstractApplicationWindow"); + qmlRegisterType(componentUrl(QStringLiteral("AbstractListItem.qml")), uri, 2, 0, "AbstractListItem"); + qmlRegisterType(componentUrl(QStringLiteral("ApplicationHeader.qml")), uri, 2, 0, "ApplicationHeader"); + qmlRegisterType(componentUrl(QStringLiteral("ToolBarApplicationHeader.qml")), uri, 2, 0, "ToolBarApplicationHeader"); + qmlRegisterType(componentUrl(QStringLiteral("ApplicationWindow.qml")), uri, 2, 0, "ApplicationWindow"); + qmlRegisterType(componentUrl(QStringLiteral("BasicListItem.qml")), uri, 2, 0, "BasicListItem"); + qmlRegisterType(componentUrl(QStringLiteral("OverlayDrawer.qml")), uri, 2, 0, "OverlayDrawer"); + qmlRegisterType(componentUrl(QStringLiteral("ContextDrawer.qml")), uri, 2, 0, "ContextDrawer"); + qmlRegisterType(componentUrl(QStringLiteral("GlobalDrawer.qml")), uri, 2, 0, "GlobalDrawer"); + qmlRegisterType(componentUrl(QStringLiteral("Heading.qml")), uri, 2, 0, "Heading"); + qmlRegisterType(componentUrl(QStringLiteral("Separator.qml")), uri, 2, 0, "Separator"); + qmlRegisterType(componentUrl(QStringLiteral("PageRow.qml")), uri, 2, 0, "PageRow"); + + qmlRegisterType(uri, 2, 0, "Icon"); + + qmlRegisterType(componentUrl(QStringLiteral("Label.qml")), uri, 2, 0, "Label"); + //TODO: uncomment for 2.3 release + //qmlRegisterTypeNotAvailable(uri, 2, 3, "Label", "Label type not supported anymore, use QtQuick.Controls.Label 2.0 instead"); + qmlRegisterType(componentUrl(QStringLiteral("OverlaySheet.qml")), uri, 2, 0, "OverlaySheet"); + qmlRegisterType(componentUrl(QStringLiteral("Page.qml")), uri, 2, 0, "Page"); + qmlRegisterType(componentUrl(QStringLiteral("ScrollablePage.qml")), uri, 2, 0, "ScrollablePage"); + qmlRegisterType(componentUrl(QStringLiteral("SplitDrawer.qml")), uri, 2, 0, "SplitDrawer"); + qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem.qml")), uri, 2, 0, "SwipeListItem"); + + //2.1 + qmlRegisterType(componentUrl(QStringLiteral("AbstractItemViewHeader.qml")), uri, 2, 1, "AbstractItemViewHeader"); + qmlRegisterType(componentUrl(QStringLiteral("ItemViewHeader.qml")), uri, 2, 1, "ItemViewHeader"); + qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationItem.qml")), uri, 2, 1, "AbstractApplicationItem"); + qmlRegisterType(componentUrl(QStringLiteral("ApplicationItem.qml")), uri, 2, 1, "ApplicationItem"); + + //2.2 + //Theme changed from a singleton to an attached property + qmlRegisterUncreatableType(uri, 2, 2, "Theme", QStringLiteral("Cannot create objects of type Theme, use it as an attached property")); + + //2.3 + qmlRegisterType(componentUrl(QStringLiteral("FormLayout.qml")), uri, 2, 3, "FormLayout"); + qmlRegisterUncreatableType(uri, 2, 3, "FormData", QStringLiteral("Cannot create objects of type FormData, use it as an attached property")); + qmlRegisterUncreatableType(uri, 2, 3, "MnemonicData", QStringLiteral("Cannot create objects of type MnemonicData, use it as an attached property")); + + //2.4 + qmlRegisterType(componentUrl(QStringLiteral("AbstractCard.qml")), uri, 2, 4, "AbstractCard"); + qmlRegisterType(componentUrl(QStringLiteral("Card.qml")), uri, 2, 4, "Card"); + qmlRegisterType(componentUrl(QStringLiteral("CardsListView.qml")), uri, 2, 4, "CardsListView"); + qmlRegisterType(componentUrl(QStringLiteral("CardsGridView.qml")), uri, 2, 4, "CardsGridView"); + qmlRegisterType(componentUrl(QStringLiteral("CardsLayout.qml")), uri, 2, 4, "CardsLayout"); + qmlRegisterType(componentUrl(QStringLiteral("InlineMessage.qml")), uri, 2, 4, "InlineMessage"); + qmlRegisterUncreatableType(uri, 2, 4, "MessageType", QStringLiteral("Cannot create objects of type MessageType")); + qmlRegisterType(uri, 2, 4, "DelegateRecycler"); + + //2.5 + qmlRegisterType(componentUrl(QStringLiteral("ListItemDragHandle.qml")), uri, 2, 5, "ListItemDragHandle"); + qmlRegisterType(componentUrl(QStringLiteral("ActionToolBar.qml")), uri, 2, 5, "ActionToolBar"); + qmlRegisterUncreatableType(uri, 2, 5, "ScenePosition", QStringLiteral("Cannot create objects of type ScenePosition, use it as an attached property")); + + //2.6 + qmlRegisterType(componentUrl(QStringLiteral("AboutPage.qml")), uri, 2, 6, "AboutPage"); + qmlRegisterType(componentUrl(QStringLiteral("LinkButton.qml")), uri, 2, 6, "LinkButton"); + qmlRegisterType(componentUrl(QStringLiteral("UrlButton.qml")), uri, 2, 6, "UrlButton"); + + qmlProtectModule(uri, 2); +} + +#include "moc_kirigamiplugin.cpp" + diff --git a/src/kirigamiplugin.h b/src/kirigamiplugin.h new file mode 100644 index 0000000..7ae31ec --- /dev/null +++ b/src/kirigamiplugin.h @@ -0,0 +1,73 @@ +/* + * Copyright 2009 by Alan Alpert + * Copyright 2010 by Ménard Alexis + * Copyright 2010 by Marco Martin + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIRIGAMIPLUGIN_H +#define KIRIGAMIPLUGIN_H + +#include + +#include +#include + +class KirigamiPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) override; + +#ifdef KIRIGAMI_BUILD_TYPE_STATIC + static KirigamiPlugin& getInstance() + { + static KirigamiPlugin instance; + return instance; + } + + static void registerTypes() + { + static KirigamiPlugin instance; + instance.registerTypes("org.kde.kirigami"); + } +#endif + +private: + QUrl componentUrl(const QString &fileName) const; + QString resolveFilePath(const QString &path) const + { +#ifdef KIRIGAMI_BUILD_TYPE_STATIC + return QStringLiteral(":/org/kde/kirigami/") + path; +#else + return baseUrl().toLocalFile() + QLatin1Char('/') + path; +#endif + } + QString resolveFileUrl(const QString &filePath) const + { +#ifdef KIRIGAMI_BUILD_TYPE_STATIC + return filePath; +#else + return baseUrl().toString() + QLatin1Char('/') + filePath; +#endif + } + QStringList m_stylesFallbackChain; +}; + +#endif diff --git a/src/libkirigami/CMakeLists.txt b/src/libkirigami/CMakeLists.txt new file mode 100644 index 0000000..88d1158 --- /dev/null +++ b/src/libkirigami/CMakeLists.txt @@ -0,0 +1,94 @@ + + +set(libkirigami_SRCS + platformtheme.cpp + basictheme.cpp + kirigamipluginfactory.cpp + tabletmodewatcher.cpp +) + +#use dbus on linux, bsd etc, but not andoid and apple stuff +if (UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT(APPLE) AND NOT(DISABLE_DBUS)) + qt5_add_dbus_interface(libkirigami_SRCS org.kde.KWin.TabletModeManager.xml tabletmodemanager_interface) + set(LIBKIRIGAMKI_EXTRA_LIBS Qt5::DBus) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +ecm_qt_declare_logging_category(libkirigami_SRCS + HEADER loggingcategory.h + IDENTIFIER KirigamiLog + CATEGORY_NAME kf5.kirigami + DEFAULT_SEVERITY Warning +) + +add_library(KF5Kirigami2 ${libkirigami_SRCS}) +generate_export_header(KF5Kirigami2 BASE_NAME Kirigami2) +add_library(KF5::Kirigami2 ALIAS KF5Kirigami2) + +target_include_directories(KF5Kirigami2 + INTERFACE "$" +) + +target_link_libraries(KF5Kirigami2 + PUBLIC + Qt5::Core + PRIVATE + Qt5::Qml + Qt5::Quick + Qt5::QuickControls2 + ${LIBKIRIGAMKI_EXTRA_LIBS} +) + +set_target_properties(KF5Kirigami2 PROPERTIES + VERSION ${KIRIGAMI2_VERSION_STRING} + SOVERSION ${KIRIGAMI2_SOVERSION} + EXPORT_NAME "Kirigami2" +) + +ecm_generate_headers(Kirigami2_HEADERS + HEADER_NAMES + PlatformTheme + KirigamiPluginFactory + TabletModeWatcher + + REQUIRED_HEADERS Kirigami2_HEADERS +) + +install(TARGETS KF5Kirigami2 + EXPORT KF5Kirigami2Targets + ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/kirigami2_export.h + ${Kirigami2_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/Kirigami2 + COMPONENT Devel) + +if(BUILD_QCH) + ecm_add_qch( + KF5Kirigami2_QCH + NAME Kirigami2 + BASE_NAME KF5Kirigami2 + VERSION ${KF5_VERSION} + ORG_DOMAIN org.kde + SOURCES # using only public headers, to cover only public API + ${Kirigami2_HEADERS} + MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" + LINK_QCHS + Qt5Core_QCH + BLANK_MACROS + KIRIGAMI_EXPORT + KIRIGAMI_DEPRECATED + TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + COMPONENT Devel + ) +endif() + +include(ECMGeneratePriFile) +ecm_generate_pri_file(BASE_NAME Kirigami2 LIB_NAME KF5Kirigami2 DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/Kirigami2) +install(FILES ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) + diff --git a/src/libkirigami/basictheme.cpp b/src/libkirigami/basictheme.cpp new file mode 100644 index 0000000..56ab388 --- /dev/null +++ b/src/libkirigami/basictheme.cpp @@ -0,0 +1,325 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "basictheme_p.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Kirigami { + +class BasicThemeDeclarativeSingleton +{ +public: + BasicThemeDeclarativeSingleton() + {} + + BasicThemeDeclarative self; +}; + +Q_GLOBAL_STATIC(BasicThemeDeclarativeSingleton, privateBasicThemeDeclarativeSelf) + +BasicThemeDeclarative::BasicThemeDeclarative() +{ + m_colorSyncTimer = new QTimer; + m_colorSyncTimer->setInterval(0); + m_colorSyncTimer->setSingleShot(true); +} + +BasicThemeDeclarative::~BasicThemeDeclarative() +{ + delete m_colorSyncTimer; +} + +QObject *BasicThemeDeclarative::instance(const BasicTheme *theme) +{ + if (m_declarativeBasicTheme) { + return m_declarativeBasicTheme; + } + + QQmlEngine *engine = qmlEngine(theme->parent()); + Q_ASSERT(engine); + + QQmlComponent c(engine); + //NOTE: for now is important this import stays at 2.0 + c.setData("import QtQuick 2.6\n\ + import org.kde.kirigami 2.0 as Kirigami\n\ + QtObject {\n\ + property QtObject theme: Kirigami.Theme\n\ + }", QUrl()); + + QObject *obj = c.create(); + m_declarativeBasicTheme = obj->property("theme").value(); + + return m_declarativeBasicTheme; +} + + +BasicTheme::BasicTheme(QObject *parent) + : PlatformTheme(parent) +{ + //TODO: correct? + connect(qApp, &QGuiApplication::fontDatabaseChanged, this, [this]() {setDefaultFont(qApp->font());}); + + //connect all the declarative object signals to the timer start to compress, use the old syntax as they are all signals defined in QML + connect(basicThemeDeclarative()->instance(this), SIGNAL(textColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(disabledTextColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(highlightColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(highlightedTextColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(backgroundColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(linkColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(visitedLinkColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + + connect(basicThemeDeclarative()->instance(this), SIGNAL(buttonTextColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(buttonBackgroundColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(buttonHoverColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(buttonFocusColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + + connect(basicThemeDeclarative()->instance(this), SIGNAL(viewTextColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(viewBackgroundColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(viewHoverColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(viewFocusColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + + connect(basicThemeDeclarative()->instance(this), SIGNAL(complementaryTextColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(complementaryBackgroundColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(complementaryHoverColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + connect(basicThemeDeclarative()->instance(this), SIGNAL(complementaryFocusColorChanged()), + basicThemeDeclarative()->m_colorSyncTimer, SLOT(start())); + + //finally connect the timer to the sync + connect(basicThemeDeclarative()->m_colorSyncTimer, &QTimer::timeout, + this, &BasicTheme::syncColors); + connect(this, &BasicTheme::colorSetChanged, + this, &BasicTheme::syncColors); + connect(this, &BasicTheme::colorGroupChanged, + this, &BasicTheme::syncColors); + + connect(this, &PlatformTheme::colorSetChanged, + this, &BasicTheme::syncCustomColorsToQML); + connect(this, &PlatformTheme::colorsChanged, + this, &BasicTheme::syncCustomColorsToQML); + syncColors(); +} + +BasicTheme::~BasicTheme() +{ +} + +static inline QColor colorGroupTint(const QColor &color, PlatformTheme::ColorGroup group) +{ + switch (group) { + case PlatformTheme::Inactive: + return QColor::fromHsvF(color.hueF(), color.saturationF() * 0.5, color.valueF()); + case PlatformTheme::Disabled: + return QColor::fromHsvF(color.hueF(), color.saturationF() * 0.5, color.valueF()*0.8); + default: + return color; + } +} + +//TODO: tint for which we need to chain to m_parentBasicTheme's color +#define RESOLVECOLOR(colorName, upperCaseColor) \ + QColor color;\ + switch (colorSet()) {\ + case BasicTheme::Button:\ + color = basicThemeDeclarative()->instance(this)->property("button"#upperCaseColor).value();\ + break;\ + case BasicTheme::View:\ + color = basicThemeDeclarative()->instance(this)->property("view"#upperCaseColor).value();\ + break;\ + case BasicTheme::Selection:\ + color = basicThemeDeclarative()->instance(this)->property("selection"#upperCaseColor).value();\ + break;\ + case BasicTheme::Tooltip:\ + color = basicThemeDeclarative()->instance(this)->property("tooltip"#upperCaseColor).value();\ + break;\ + case BasicTheme::Complementary:\ + color = basicThemeDeclarative()->instance(this)->property("complementary"#upperCaseColor).value();\ + break;\ + case BasicTheme::Window:\ + default:\ + color = basicThemeDeclarative()->instance(this)->property(#colorName).value();\ + }\ + color = colorGroupTint(color, colorGroup()); + + +#define PROXYCOLOR(colorName, upperCaseColor) \ + colorGroupTint(basicThemeDeclarative()->instance(this)->property(#colorName).value(), colorGroup()) + + + +void BasicTheme::syncColors() +{ + { + RESOLVECOLOR(textColor, TextColor); + setTextColor(color); + }{ + setDisabledTextColor(PROXYCOLOR(disabledTextColor, DisabledTextColor)); + }{ + RESOLVECOLOR(backgroundColor, BackgroundColor) + setBackgroundColor(color); + }{ + setHighlightColor(PROXYCOLOR(highlightColor, HighlightColor)); + }{ + setHighlightedTextColor(PROXYCOLOR(highlightedTextColor, HighlightedTextColor)); + }{ + setActiveTextColor(PROXYCOLOR(activeTextColor, ActiveTextColor)); + }{ + setLinkColor(PROXYCOLOR(linkColor, LinkColor)); + }{ + setVisitedLinkColor(PROXYCOLOR(visitedLinkColor, VisitedLinkColor)); + }{ + setNegativeTextColor(PROXYCOLOR(negativeTextColor, NegativeTextColor)); + }{ + setNeutralTextColor(PROXYCOLOR(neutralTextColor, NeutralTextColor)); + }{ + setPositiveTextColor(PROXYCOLOR(positiveTextColor, PositiveTextColor)); + }{ + RESOLVECOLOR(hoverColor, HoverColor); + setHoverColor(color); + }{ + RESOLVECOLOR(focusColor, FocusColor); + setFocusColor(color); + } + + //legacy + { + m_buttonTextColor = PROXYCOLOR(buttonTextColor, ButtonTextColor); + m_buttonBackgroundColor = PROXYCOLOR(buttonBackgroundColor, ButtonBackgroundColor); + m_buttonHoverColor = PROXYCOLOR(buttonHoverColor, ButtonHoverColor); + m_buttonFocusColor = PROXYCOLOR(buttonFocusColor, ButtonFocusColor); + m_viewTextColor = PROXYCOLOR(viewTextColor, ViewTextColor); + m_viewBackgroundColor = PROXYCOLOR(viewBackgroundColor, ViewBackgroundColor); + m_viewHoverColor = PROXYCOLOR(viewHoverColor, ViewHoverColor); + m_viewFocusColor = PROXYCOLOR(viewFocusColor, ViewFocusColor); + } + + QPalette pal = qApp->palette(); + pal.setColor(QPalette::WindowText, textColor()); + pal.setColor(QPalette::Button, m_buttonBackgroundColor); + pal.setColor(QPalette::Light, m_buttonBackgroundColor.lighter(120)); + pal.setColor(QPalette::Dark, m_buttonBackgroundColor.darker(120)); + pal.setColor(QPalette::Mid, m_buttonBackgroundColor.darker(110)); + pal.setColor(QPalette::Base, m_viewBackgroundColor); + pal.setColor(QPalette::HighlightedText, highlightedTextColor()); + pal.setColor(QPalette::Text, m_viewTextColor); + pal.setColor(QPalette::Window, backgroundColor()); + setPalette(pal); + + if (this->parent()) { + //this will work on Qt 5.10+ but is a safe noop on older releases + this->parent()->setProperty("palette", QVariant::fromValue(pal)); + if (basicThemeDeclarative()->instance(this)) { + QMetaObject::invokeMethod(basicThemeDeclarative()->instance(this), "__propagateColorSet", Q_ARG(QVariant, QVariant::fromValue(this->parent())), Q_ARG(QVariant, colorSet())); + } + } + + emit colorsChanged(); +} + + +void BasicTheme::syncCustomColorsToQML() +{ + if (basicThemeDeclarative()->instance(this)) { + QMetaObject::invokeMethod(basicThemeDeclarative()->instance(this), "__propagateTextColor", Q_ARG(QVariant, QVariant::fromValue(this->parent())), Q_ARG(QVariant, textColor())); + QMetaObject::invokeMethod(basicThemeDeclarative()->instance(this), "__propagateBackgroundColor", Q_ARG(QVariant, QVariant::fromValue(this->parent())), Q_ARG(QVariant, backgroundColor())); + QMetaObject::invokeMethod(basicThemeDeclarative()->instance(this), "__propagatePrimaryColor", Q_ARG(QVariant, QVariant::fromValue(this->parent())), Q_ARG(QVariant, highlightColor())); + QMetaObject::invokeMethod(basicThemeDeclarative()->instance(this), "__propagateAccentColor", Q_ARG(QVariant, QVariant::fromValue(this->parent())), Q_ARG(QVariant, highlightColor())); + } +} + +QColor BasicTheme::buttonTextColor() const +{ + qWarning()<<"WARNING: buttonTextColor is deprecated, use textColor with colorSet: Theme.Button instead"; + return m_buttonTextColor; +} + +QColor BasicTheme::buttonBackgroundColor() const +{ + qWarning()<<"WARNING: buttonBackgroundColor is deprecated, use backgroundColor with colorSet: Theme.Button instead"; + return m_buttonBackgroundColor; +} + +QColor BasicTheme::buttonHoverColor() const +{ + qWarning()<<"WARNING: buttonHoverColor is deprecated, use backgroundColor with colorSet: Theme.Button instead"; + return m_buttonHoverColor; +} + +QColor BasicTheme::buttonFocusColor() const +{ + qWarning()<<"WARNING: buttonFocusColor is deprecated, use backgroundColor with colorSet: Theme.Button instead"; + return m_buttonFocusColor; +} + + +QColor BasicTheme::viewTextColor() const +{ + qWarning()<<"WARNING: viewTextColor is deprecated, use backgroundColor with colorSet: Theme.View instead"; + return m_viewTextColor; +} + +QColor BasicTheme::viewBackgroundColor() const +{ + qWarning()<<"WARNING: viewBackgroundColor is deprecated, use backgroundColor with colorSet: Theme.View instead"; + return m_viewBackgroundColor; +} + +QColor BasicTheme::viewHoverColor() const +{ + qWarning()<<"WARNING: viewHoverColor is deprecated, use backgroundColor with colorSet: Theme.View instead"; + return m_viewHoverColor; +} + +QColor BasicTheme::viewFocusColor() const +{ + qWarning()<<"WARNING: viewFocusColor is deprecated, use backgroundColor with colorSet: Theme.View instead"; + return m_viewFocusColor; +} + +BasicThemeDeclarative *BasicTheme::basicThemeDeclarative() +{ + return &privateBasicThemeDeclarativeSelf->self; +} + +} + +#include "moc_basictheme_p.cpp" diff --git a/src/libkirigami/basictheme_p.h b/src/libkirigami/basictheme_p.h new file mode 100644 index 0000000..c9688c9 --- /dev/null +++ b/src/libkirigami/basictheme_p.h @@ -0,0 +1,99 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef BASICTHEME_H +#define BASICTHEME_H + +#include "platformtheme.h" +#include +#include +#include +#include + +namespace Kirigami { + +class BasicTheme; + +class BasicThemeDeclarative +{ +public: + BasicThemeDeclarative(); + virtual ~BasicThemeDeclarative(); + + QObject *instance(const BasicTheme *theme); + + QTimer *m_colorSyncTimer; + +private: + QUrl m_qmlPath; + QObject *m_declarativeBasicTheme = nullptr; +}; + +class BasicTheme : public PlatformTheme +{ + Q_OBJECT + + // colors + Q_PROPERTY(QColor buttonTextColor READ buttonTextColor NOTIFY colorsChanged) + Q_PROPERTY(QColor buttonBackgroundColor READ buttonBackgroundColor NOTIFY colorsChanged) + Q_PROPERTY(QColor buttonHoverColor READ buttonHoverColor NOTIFY colorsChanged) + Q_PROPERTY(QColor buttonFocusColor READ buttonFocusColor NOTIFY colorsChanged) + + Q_PROPERTY(QColor viewTextColor READ viewTextColor NOTIFY colorsChanged) + Q_PROPERTY(QColor viewBackgroundColor READ viewBackgroundColor NOTIFY colorsChanged) + Q_PROPERTY(QColor viewHoverColor READ viewHoverColor NOTIFY colorsChanged) + Q_PROPERTY(QColor viewFocusColor READ viewFocusColor NOTIFY colorsChanged) + +public: + explicit BasicTheme(QObject *parent = nullptr); + ~BasicTheme(); + + void syncColors(); + + QColor buttonTextColor() const; + QColor buttonBackgroundColor() const; + QColor buttonHoverColor() const; + QColor buttonFocusColor() const; + + QColor viewTextColor() const; + QColor viewBackgroundColor() const; + QColor viewHoverColor() const; + QColor viewFocusColor() const; + + static BasicThemeDeclarative *basicThemeDeclarative(); + +Q_SIGNALS: + void colorsChanged(); + +private: + inline void syncCustomColorsToQML(); + //legacy colors + QColor m_buttonTextColor; + QColor m_buttonBackgroundColor; + QColor m_buttonHoverColor; + QColor m_buttonFocusColor; + QColor m_viewTextColor; + QColor m_viewBackgroundColor; + QColor m_viewHoverColor; + QColor m_viewFocusColor; +}; + +} + +#endif // BASICTHEME_H diff --git a/src/libkirigami/kirigamipluginfactory.cpp b/src/libkirigami/kirigamipluginfactory.cpp new file mode 100644 index 0000000..ae49276 --- /dev/null +++ b/src/libkirigami/kirigamipluginfactory.cpp @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kirigamipluginfactory.h" +#include "platformtheme.h" + +#include + + +namespace Kirigami { + +KirigamiPluginFactory::KirigamiPluginFactory(QObject *parent) + : QObject(parent) +{ +} + +KirigamiPluginFactory::~KirigamiPluginFactory() +{ +} + +} + +#include "moc_kirigamipluginfactory.cpp" diff --git a/src/libkirigami/kirigamipluginfactory.h b/src/libkirigami/kirigamipluginfactory.h new file mode 100644 index 0000000..9375480 --- /dev/null +++ b/src/libkirigami/kirigamipluginfactory.h @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef KIRIGAMIPLUGINFACTORY_H +#define KIRIGAMIPLUGINFACTORY_H + +#include "platformtheme.h" +#include + +#ifndef KIRIGAMI_BUILD_TYPE_STATIC +#include +#endif + +namespace Kirigami { + +/** + * @class KirigamiPluginFactory kirigamipluginfactory.h KirigamiPluginFactory + * + * This class is reimpleented by plugins to provide different implementations + * of PlatformTheme + */ +#ifdef KIRIGAMI_BUILD_TYPE_STATIC +class KirigamiPluginFactory : public QObject +#else +class KIRIGAMI2_EXPORT KirigamiPluginFactory : public QObject +#endif +{ + Q_OBJECT + +public: + explicit KirigamiPluginFactory(QObject *parent = nullptr); + ~KirigamiPluginFactory(); + + /** + * Creates an instance of PlatformTheme which can come out from + * an implementation provided by a plugin + * @param parent the parent object of the created PlatformTheme + */ + virtual PlatformTheme *createPlatformTheme(QObject *parent) = 0; +}; + +} + +QT_BEGIN_NAMESPACE +#define KirigamiPluginFactory_iid "org.kde.kirigami.KirigamiPluginFactory" +Q_DECLARE_INTERFACE(Kirigami::KirigamiPluginFactory, KirigamiPluginFactory_iid) +QT_END_NAMESPACE + +#endif //KIRIGAMIPLUGINFACTORY_H diff --git a/src/libkirigami/org.kde.KWin.TabletModeManager.xml b/src/libkirigami/org.kde.KWin.TabletModeManager.xml new file mode 100644 index 0000000..1daf5f0 --- /dev/null +++ b/src/libkirigami/org.kde.KWin.TabletModeManager.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/libkirigami/platformtheme.cpp b/src/libkirigami/platformtheme.cpp new file mode 100644 index 0000000..43fcf22 --- /dev/null +++ b/src/libkirigami/platformtheme.cpp @@ -0,0 +1,728 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "platformtheme.h" +#include "kirigamipluginfactory.h" +#include "basictheme_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kirigami { + +class PlatformThemePrivate { +public: + PlatformThemePrivate(PlatformTheme *q); + ~PlatformThemePrivate(); + + inline void syncCustomPalette(); + void findParentStyle(); + static QColor tint(const QColor &c1, const QColor &c2, qreal ratio); + + + PlatformTheme *q; + QTimer *setColorCompressTimer; + PlatformTheme::ColorSet m_colorSet = PlatformTheme::Window; + PlatformTheme::ColorGroup m_colorGroup = PlatformTheme::Active; + QSet m_childThemes; + QPointer m_parentTheme; + + //ordinary colors + QColor textColor; + QColor disabledTextColor; + QColor highlightedTextColor; + QColor activeTextColor; + QColor linkColor; + QColor visitedLinkColor; + QColor negativeTextColor; + QColor neutralTextColor; + QColor positiveTextColor; + + QColor backgroundColor; + QColor highlightColor; + + QColor focusColor; + QColor hoverColor; + + QPalette palette; + + //custom colors + QColor customTextColor; + QColor customDisabledTextColor; + QColor customHighlightedTextColor; + QColor customActiveTextColor; + QColor customLinkColor; + QColor customVisitedLinkColor; + QColor customNegativeTextColor; + QColor customNeutralTextColor; + QColor customPositiveTextColor; + + QColor customBackgroundColor; + QColor customHighlightColor; + + QColor customFocusColor; + QColor customHoverColor; + + QPalette customPalette; + + QFont font; + bool m_inherit = true; + bool m_init = true; + + static KirigamiPluginFactory *s_pluginFactory; +}; + +KirigamiPluginFactory *PlatformThemePrivate::s_pluginFactory = nullptr; + +PlatformThemePrivate::PlatformThemePrivate(PlatformTheme *q) + : q(q) +{ + setColorCompressTimer = new QTimer(q); + setColorCompressTimer->setSingleShot(true); + setColorCompressTimer->setInterval(0); +} + +PlatformThemePrivate::~PlatformThemePrivate() +{} + +void setPaletteColor(QPalette& customPalette, QPalette::ColorGroup cg, QPalette::ColorRole cr, const QColor &color) +{ + if (customPalette.color(cg, cr) != color) { + customPalette.setColor(cg, cr, color); + } +} + +void PlatformThemePrivate::syncCustomPalette() +{ + for (auto state : { QPalette::Active, QPalette::Inactive, QPalette::Disabled }) { + setPaletteColor(customPalette, state, QPalette::WindowText, q->textColor()); + setPaletteColor(customPalette, state, QPalette::Window, q->backgroundColor()); + setPaletteColor(customPalette, state, QPalette::Base, q->backgroundColor()); + setPaletteColor(customPalette, state, QPalette::Text, q->textColor()); + setPaletteColor(customPalette, state, QPalette::Button, q->backgroundColor()); + setPaletteColor(customPalette, state, QPalette::ButtonText, q->textColor()); + setPaletteColor(customPalette, state, QPalette::Highlight, q->highlightColor()); + setPaletteColor(customPalette, state, QPalette::HighlightedText, q->highlightedTextColor()); + setPaletteColor(customPalette, state, QPalette::ToolTipBase, q->backgroundColor()); + setPaletteColor(customPalette, state, QPalette::ToolTipText, q->textColor()); + setPaletteColor(customPalette, state, QPalette::Link, q->linkColor()); + setPaletteColor(customPalette, state, QPalette::LinkVisited, q->visitedLinkColor()); + } + emit q->paletteChanged(customPalette); +} + +void PlatformThemePrivate::findParentStyle() +{ + if (m_parentTheme) { + m_parentTheme->d->m_childThemes.remove(q); + } + QQuickItem *candidate = qobject_cast(q->parent()); + while (candidate) { + candidate = candidate->parentItem(); + PlatformTheme *t = static_cast(qmlAttachedPropertiesObject(candidate, false)); + if (t) { + t->d->m_childThemes.insert(q); + m_parentTheme = t; + if (m_inherit) { + q->setColorSet(t->colorSet()); + + q->setCustomTextColor(t->d->customTextColor); + q->setCustomDisabledTextColor(t->d->customDisabledTextColor); + q->setCustomHighlightedTextColor(t->d->customHighlightedTextColor); + q->setCustomActiveTextColor(t->d->customActiveTextColor); + q->setCustomLinkColor(t->d->customLinkColor); + q->setCustomVisitedLinkColor(t->d->customVisitedLinkColor); + q->setCustomNegativeTextColor(t->d->customNegativeTextColor); + q->setCustomNeutralTextColor(t->d->customNeutralTextColor); + q->setCustomPositiveTextColor(t->d->customPositiveTextColor); + q->setCustomBackgroundColor(t->d->customBackgroundColor); + q->setCustomHighlightColor(t->d->customHighlightColor); + q->setCustomFocusColor(t->d->customFocusColor); + q->setCustomHoverColor(t->d->customHoverColor); + } + break; + } + + } +} + +QColor PlatformThemePrivate::tint(const QColor &c1, const QColor &c2, qreal ratio) +{ + qreal r = c1.redF() + (c2.redF() - c1.redF()) * ratio; + qreal g = c1.greenF() + (c2.greenF() - c1.greenF()) * ratio; + qreal b = c1.blueF() + (c2.blueF() - c1.blueF()) * ratio; + + return QColor::fromRgbF(r, g, b, 1); +} + + + + +PlatformTheme::PlatformTheme(QObject *parent) + : QObject(parent), + d(new PlatformThemePrivate(this)) +{ + connect(d->setColorCompressTimer, &QTimer::timeout, + this, [this]() { + d->syncCustomPalette(); + emit colorsChanged(); + }); + d->findParentStyle(); + + if (QQuickItem *item = qobject_cast(parent)) { + connect(item, &QQuickItem::windowChanged, this, [this]() { + d->findParentStyle(); + }); + connect(item, &QQuickItem::parentChanged, this, [this]() { + d->findParentStyle(); + }); + } + d->m_init = false; + //TODO: needs https://codereview.qt-project.org/#/c/206889/ for font changes +} + +PlatformTheme::~PlatformTheme() +{ + if (d->m_parentTheme) { + d->m_parentTheme->d->m_childThemes.remove(this); + } + delete d; +} + +void PlatformTheme::setColorSet(PlatformTheme::ColorSet colorSet) +{ + if (d->m_colorSet == colorSet) { + return; + } + + d->m_colorSet = colorSet; + + for (PlatformTheme *t : qAsConst(d->m_childThemes)) { + if (t->inherit()) { + t->setColorSet(colorSet); + /* if (colorSet == Custom) { + t->setCustomTextColor(textColor()); + t->setCustomDisabledTextColor(disabledTextColor()); + t->setCustomHighlightedTextColor(highlightedTextColor()); + t->setCustomActiveTextColor(activeTextColor()); + t->setCustomLinkColor(linkColor()); + t->setCustomVisitedLinkColor(visitedLinkColor()); + t->setCustomNegativeTextColor(negativeTextColor()); + t->setCustomNeutralTextColor(neutralTextColor()); + t->setCustomPositiveTextColor(positiveTextColor()); + t->setCustomBackgroundColor(backgroundColor()); + t->setCustomHighlightColor(highlightColor()); + t->setCustomFocusColor(focusColor()); + t->setCustomHoverColor(hoverColor()); + }*/ + } + } + + if (!d->m_init) { + emit colorSetChanged(colorSet); + d->setColorCompressTimer->start(); + } +} + +PlatformTheme::ColorSet PlatformTheme::colorSet() const +{ + return d->m_colorSet; +} + +void PlatformTheme::setColorGroup(PlatformTheme::ColorGroup colorGroup) +{ + if (d->m_colorGroup == colorGroup) { + return; + } + + d->m_colorGroup = colorGroup; + + for (PlatformTheme *t : qAsConst(d->m_childThemes)) { + if (t->inherit()) { + t->setColorGroup(colorGroup); + } + } + + if (!d->m_init) { + emit colorGroupChanged(colorGroup); + d->setColorCompressTimer->start(); + } +} + +PlatformTheme::ColorGroup PlatformTheme::colorGroup() const +{ + return d->m_colorGroup; +} + +bool PlatformTheme::inherit() const +{ + return d->m_inherit; +} + +void PlatformTheme::setInherit(bool inherit) +{ + if (d->m_inherit == inherit) { + return; + } + + d->m_inherit = inherit; + if (inherit && d->m_parentTheme) { + setColorSet(d->m_parentTheme->colorSet()); + } + emit inheritChanged(inherit); +} + +QColor PlatformTheme::textColor() const +{ + return d->customTextColor.isValid() ? d->customTextColor : d->textColor; +} + +QColor PlatformTheme::disabledTextColor() const +{ + return d->customDisabledTextColor.isValid() ? d->customDisabledTextColor : d->disabledTextColor; +} + +QColor PlatformTheme::highlightColor() const +{ + return d->customHighlightColor.isValid() ? d->customHighlightColor : d->highlightColor; +} + +QColor PlatformTheme::highlightedTextColor() const +{ + return d->customHighlightedTextColor.isValid() ? d->customHighlightedTextColor : d->highlightedTextColor; +} + +QColor PlatformTheme::backgroundColor() const +{ + return d->customBackgroundColor.isValid() ? d->customBackgroundColor : d->backgroundColor; +} + +QColor PlatformTheme::activeTextColor() const +{ + return d->customActiveTextColor.isValid() ? d->customActiveTextColor : d->activeTextColor; +} + +QColor PlatformTheme::linkColor() const +{ + return d->customLinkColor.isValid() ? d->customLinkColor : d->linkColor; +} + +QColor PlatformTheme::visitedLinkColor() const +{ + return d->customVisitedLinkColor.isValid() ? d->customVisitedLinkColor : d->visitedLinkColor; +} + +QColor PlatformTheme::negativeTextColor() const +{ + return d->customNegativeTextColor.isValid() ? d->customNegativeTextColor : d->negativeTextColor; +} + +QColor PlatformTheme::neutralTextColor() const +{ + return d->customNeutralTextColor.isValid() ? d->customNeutralTextColor : d->neutralTextColor; +} + +QColor PlatformTheme::positiveTextColor() const +{ + return d->customPositiveTextColor.isValid() ? d->customPositiveTextColor : d->positiveTextColor; +} + +QColor PlatformTheme::focusColor() const +{ + return d->customFocusColor.isValid() ? d->customFocusColor : d->focusColor; +} + +QColor PlatformTheme::hoverColor() const +{ + return d->customHoverColor.isValid() ? d->customHoverColor : d->hoverColor; +} + +//setters for theme implementations +void PlatformTheme::setTextColor(const QColor &color) +{ + if (d->textColor == color) { + return; + } + + d->textColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setDisabledTextColor(const QColor &color) +{ + if (d->disabledTextColor == color) { + return; + } + + d->disabledTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setBackgroundColor(const QColor &color) +{ + if (d->backgroundColor == color) { + return; + } + + d->backgroundColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setHighlightColor(const QColor &color) +{ + if (d->highlightColor == color) { + return; + } + + d->highlightColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setHighlightedTextColor(const QColor &color) +{ + if (d->highlightedTextColor == color) { + return; + } + + d->highlightedTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setActiveTextColor(const QColor &color) +{ + if (d->activeTextColor == color) { + return; + } + + d->activeTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setLinkColor(const QColor &color) +{ + if (d->linkColor == color) { + return; + } + + d->linkColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setVisitedLinkColor(const QColor &color) +{ + if (d->visitedLinkColor == color) { + return; + } + + d->visitedLinkColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setNegativeTextColor(const QColor &color) +{ + if (d->negativeTextColor == color) { + return; + } + + d->negativeTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setNeutralTextColor(const QColor &color) +{ + if (d->neutralTextColor == color) { + return; + } + + d->neutralTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setPositiveTextColor(const QColor &color) +{ + if (d->positiveTextColor == color) { + return; + } + + d->positiveTextColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setHoverColor(const QColor &color) +{ + if (d->hoverColor == color) { + return; + } + + d->hoverColor = color; + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setFocusColor(const QColor &color) +{ + if (d->focusColor == color) { + return; + } + + d->focusColor = color; + d->setColorCompressTimer->start(); +} + +QFont PlatformTheme::defaultFont() const +{ + return d->font; +} + +void PlatformTheme::setDefaultFont(const QFont &font) +{ + if (d->font == font) { + return; + } + + d->font = font; + emit defaultFontChanged(font); +} + + +#define PROPAGATECUSTOMCOLOR(colorName, color)\ + for (PlatformTheme *t : qAsConst(d->m_childThemes)) {\ + if (t->inherit()) {\ + t->set##colorName(color);\ + }\ + } + + +//setters for QML clients +void PlatformTheme::setCustomTextColor(const QColor &color) +{ + if (d->customTextColor == color) { + return; + } + + d->customTextColor = color; + PROPAGATECUSTOMCOLOR(CustomTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomDisabledTextColor(const QColor &color) +{ + if (d->customDisabledTextColor == color) { + return; + } + + d->customDisabledTextColor = color; + PROPAGATECUSTOMCOLOR(CustomDisabledTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomBackgroundColor(const QColor &color) +{ + if (d->customBackgroundColor == color) { + return; + } + + d->customBackgroundColor = color; + PROPAGATECUSTOMCOLOR(CustomBackgroundColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomHighlightColor(const QColor &color) +{ + if (d->customHighlightColor == color) { + return; + } + + d->customHighlightColor = color; + PROPAGATECUSTOMCOLOR(CustomHighlightColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomHighlightedTextColor(const QColor &color) +{ + if (d->customHighlightedTextColor == color) { + return; + } + + d->customHighlightedTextColor = color; + PROPAGATECUSTOMCOLOR(CustomHighlightedTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomActiveTextColor(const QColor &color) +{ + if (d->customActiveTextColor == color) { + return; + } + + d->customActiveTextColor = color; + PROPAGATECUSTOMCOLOR(CustomActiveTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomLinkColor(const QColor &color) +{ + if (d->customLinkColor == color) { + return; + } + + d->customLinkColor = color; + PROPAGATECUSTOMCOLOR(CustomLinkColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomVisitedLinkColor(const QColor &color) +{ + if (d->customVisitedLinkColor == color) { + return; + } + + d->customVisitedLinkColor = color; + PROPAGATECUSTOMCOLOR(CustomVisitedLinkColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomNegativeTextColor(const QColor &color) +{ + if (d->customNegativeTextColor == color) { + return; + } + + d->customNegativeTextColor = color; + PROPAGATECUSTOMCOLOR(CustomNegativeTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomNeutralTextColor(const QColor &color) +{ + if (d->customNeutralTextColor == color) { + return; + } + + d->customNeutralTextColor = color; + PROPAGATECUSTOMCOLOR(CustomNeutralTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomPositiveTextColor(const QColor &color) +{ + if (d->customPositiveTextColor == color) { + return; + } + + d->customPositiveTextColor = color; + PROPAGATECUSTOMCOLOR(CustomPositiveTextColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomHoverColor(const QColor &color) +{ + if (d->customHoverColor == color) { + return; + } + + d->customHoverColor = color; + PROPAGATECUSTOMCOLOR(CustomHoverColor, color) + d->setColorCompressTimer->start(); +} + +void PlatformTheme::setCustomFocusColor(const QColor &color) +{ + if (d->customFocusColor == color) { + return; + } + + d->customFocusColor = color; + PROPAGATECUSTOMCOLOR(CustomFocusColor, color) + d->setColorCompressTimer->start(); +} + + +QPalette PlatformTheme::palette() const +{ + //check the most important custom colors to decide to return a custom palette + return d->customTextColor.isValid() || d->customBackgroundColor.isValid() || d->customHighlightColor.isValid() ? d->customPalette : d->palette; +} + +void PlatformTheme::setPalette(const QPalette &palette) +{ + if (d->palette == palette) { + return; + } + + d->palette = palette; + PROPAGATECUSTOMCOLOR(Palette, palette) + emit paletteChanged(palette); +} + +QIcon PlatformTheme::iconFromTheme(const QString &name, const QColor &customColor) +{ + QIcon icon = QIcon::fromTheme(name); + if (!icon.isNull() && (name.endsWith(QLatin1String("-symbolic")) || customColor != Qt::transparent)) { + icon.setIsMask(true); + } + return icon; +} + + + +PlatformTheme *PlatformTheme::qmlAttachedProperties(QObject *object) +{ + static bool s_factoryChecked = false; + + //check for the plugin only once: it's an heavy operation + if (PlatformThemePrivate::s_pluginFactory) { + return PlatformThemePrivate::s_pluginFactory->createPlatformTheme(object); + } else if (!s_factoryChecked) { + s_factoryChecked = true; +#if QT_CONFIG(library) + const auto libraryPaths = QCoreApplication::libraryPaths(); + for (const QString &path : libraryPaths) { + QDir dir(path + QStringLiteral("/kf5/kirigami")); + const auto fileNames = dir.entryList(QDir::Files); + for (const QString &fileName : fileNames) { + //TODO: env variable? + if (!QQuickStyle::name().isEmpty() && fileName.startsWith(QQuickStyle::name())) { + QPluginLoader loader(dir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + //TODO: load actually a factory as plugin + + KirigamiPluginFactory *factory = qobject_cast(plugin); + if (factory) { + PlatformThemePrivate::s_pluginFactory = factory; + return factory->createPlatformTheme(object); + } + } + } + } +#endif + } + + return new BasicTheme(object); +} + +} + +#include "moc_platformtheme.cpp" diff --git a/src/libkirigami/platformtheme.h b/src/libkirigami/platformtheme.h new file mode 100644 index 0000000..466ada4 --- /dev/null +++ b/src/libkirigami/platformtheme.h @@ -0,0 +1,270 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PLATFORMTHEME_H +#define PLATFORMTHEME_H + +#include +#include +#include +#include + +#ifndef KIRIGAMI_BUILD_TYPE_STATIC +#include +#endif + +namespace Kirigami { + +class PlatformThemePrivate; + +/** + * @class PlatformTheme platformtheme.h PlatformTheme + * + * This class is the base for color management in Kirigami, + * different platforms can reimplement this class to integrate with + * system platform colors of a given platform + */ +#ifdef KIRIGAMI_BUILD_TYPE_STATIC +class PlatformTheme : public QObject +#else +class KIRIGAMI2_EXPORT PlatformTheme : public QObject +#endif +{ + Q_OBJECT + + /** + * This enumeration describes the color set for which a color is being selected. + * + * Color sets define a color "environment", suitable for drawing all parts of a + * given region. Colors from different sets should not be combined. + */ + Q_PROPERTY(ColorSet colorSet READ colorSet WRITE setColorSet NOTIFY colorSetChanged) + + /** + * This enumeration describes the color group used to generate the colors. + * The enum value is based upon QPalette::CpolorGroup and has the same values. + * It's redefined here in order to make it work with QML + * @since 4.43 + */ + Q_PROPERTY(ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY colorGroupChanged) + + /** + * If true, the colorSet will be inherited from the colorset of a theme of one + * of the ancestor items + * default: true + */ + Q_PROPERTY(bool inherit READ inherit WRITE setInherit NOTIFY inheritChanged) + + // foreground colors + /** + * Color for normal foregrounds, usually text, but not limited to it, + * anything that should be painted with a clear contrast should use this color + */ + Q_PROPERTY(QColor textColor READ textColor WRITE setCustomTextColor RESET setCustomTextColor NOTIFY colorsChanged) + + /** + * Foreground color for disabled areas, usually a mid-gray + */ + Q_PROPERTY(QColor disabledTextColor READ disabledTextColor WRITE setCustomDisabledTextColor RESET setCustomDisabledTextColor NOTIFY colorsChanged) + + /** + * Color for text that has been highlighted, often is a light color while normal text is dark + */ + Q_PROPERTY(QColor highlightedTextColor READ highlightedTextColor WRITE setCustomHighlightedTextColor RESET setCustomHighlightedTextColor NOTIFY colorsChanged) + + /** + * Foreground for areas that are active or requesting attention + */ + Q_PROPERTY(QColor activeTextColor READ activeTextColor WRITE setCustomActiveTextColor RESET setCustomActiveTextColor NOTIFY colorsChanged) + + /** + * Color for links + */ + Q_PROPERTY(QColor linkColor READ linkColor WRITE setCustomLinkColor RESET setCustomLinkColor NOTIFY colorsChanged) + + /** + * Color for visited links, usually a bit darker than linkColor + */ + Q_PROPERTY(QColor visitedLinkColor READ visitedLinkColor WRITE setCustomVisitedLinkColor RESET setCustomVisitedLinkColor NOTIFY colorsChanged) + + /** + * Foreground color for negative areas, such as critical error text + */ + Q_PROPERTY(QColor negativeTextColor READ negativeTextColor WRITE setCustomNegativeTextColor RESET setCustomNegativeTextColor NOTIFY colorsChanged) + + /** + * Foreground color for neutral areas, such as warning texts (but not critical) + */ + Q_PROPERTY(QColor neutralTextColor READ neutralTextColor WRITE setCustomNeutralTextColor RESET setCustomNeutralTextColor NOTIFY colorsChanged) + + /** + * Success messages, trusted content + */ + Q_PROPERTY(QColor positiveTextColor READ positiveTextColor WRITE setCustomPositiveTextColor RESET setCustomPositiveTextColor NOTIFY colorsChanged) + + //background colors + /** + * The generic background color + */ + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setCustomBackgroundColor RESET setCustomBackgroundColor NOTIFY colorsChanged) + + /** + * The background color for selected areas + */ + Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setCustomHighlightColor RESET setCustomHighlightColor NOTIFY colorsChanged) + + //decoration colors + /** + * A decoration color that indicates active focus + */ + Q_PROPERTY(QColor focusColor READ focusColor WRITE setCustomFocusColor RESET setCustomFocusColor NOTIFY colorsChanged) + + /** + * A decoration color that indicates mouse hovering + */ + Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setCustomHoverColor RESET setCustomHoverColor NOTIFY colorsChanged) + + // font and palette + Q_PROPERTY(QFont defaultFont READ defaultFont NOTIFY defaultFontChanged) + //Active palette + Q_PROPERTY(QPalette palette READ palette NOTIFY paletteChanged) + +public: + + enum ColorSet { + View = 0, /** Color set for item views, usually the lightest of all */ + Window, /** Default Color set for windows and "chrome" areas */ + Button, /** Color set used by buttons */ + Selection, /** Color set used by selectged areas */ + Tooltip, /** Color set used by tooltips */ + Complementary /** Color set meant to be complementary to Window: usually is a dark theme for light themes */ + }; + Q_ENUM(ColorSet) + + enum ColorGroup { + Disabled = QPalette::Disabled, + Active = QPalette::Active, + Inactive = QPalette::Inactive, + Normal = QPalette::Normal + }; + Q_ENUM(ColorGroup) + + explicit PlatformTheme(QObject *parent = nullptr); + ~PlatformTheme(); + + void setColorSet(PlatformTheme::ColorSet); + PlatformTheme::ColorSet colorSet() const; + + void setColorGroup(PlatformTheme::ColorGroup); + PlatformTheme::ColorGroup colorGroup() const; + + bool inherit() const; + void setInherit(bool inherit); + + //foreground colors + QColor textColor() const; + QColor disabledTextColor() const; + QColor highlightedTextColor() const; + QColor activeTextColor() const; + QColor linkColor() const; + QColor visitedLinkColor() const; + QColor negativeTextColor() const; + QColor neutralTextColor() const; + QColor positiveTextColor() const; + + //background colors + QColor backgroundColor() const; + QColor highlightColor() const; + //TODO: add active/positive/neutral/negative backgrounds? + + //decoration colors + QColor focusColor() const; + QColor hoverColor() const; + + QFont defaultFont() const; + + //this may is used by the desktop QQC2 to set the styleoption palettes + QPalette palette() const; + + //this will be used by desktopicon to fetch icons with KIconLoader + virtual Q_INVOKABLE QIcon iconFromTheme(const QString &name, const QColor &customColor = Qt::transparent); + + //foreground colors + void setCustomTextColor(const QColor &color = QColor()); + void setCustomDisabledTextColor(const QColor &color = QColor()); + void setCustomHighlightedTextColor(const QColor &color = QColor()); + void setCustomActiveTextColor(const QColor &color = QColor()); + void setCustomLinkColor(const QColor &color = QColor()); + void setCustomVisitedLinkColor(const QColor &color = QColor()); + void setCustomNegativeTextColor(const QColor &color = QColor()); + void setCustomNeutralTextColor(const QColor &color = QColor()); + void setCustomPositiveTextColor(const QColor &color = QColor()); + //background colors + void setCustomBackgroundColor(const QColor &color = QColor()); + void setCustomHighlightColor(const QColor &color = QColor()); + //decoration colors + void setCustomFocusColor(const QColor &color = QColor()); + void setCustomHoverColor(const QColor &color = QColor()); + + //QML attached property + static PlatformTheme *qmlAttachedProperties(QObject *object); + +Q_SIGNALS: + //TODO: parameters to signals as this is also a c++ api + void colorsChanged(); + void defaultFontChanged(const QFont &font); + void colorSetChanged(Kirigami::PlatformTheme::ColorSet colorSet); + void colorGroupChanged(Kirigami::PlatformTheme::ColorGroup colorGroup); + void paletteChanged(const QPalette &pal); + void inheritChanged(bool inherit); + +protected: + //Setters, not accessible from QML but from implementations + + //foreground colors + void setTextColor(const QColor &color); + void setDisabledTextColor(const QColor &color); + void setHighlightedTextColor(const QColor &color); + void setActiveTextColor(const QColor &color); + void setLinkColor(const QColor &color); + void setVisitedLinkColor(const QColor &color); + void setNegativeTextColor(const QColor &color); + void setNeutralTextColor(const QColor &color); + void setPositiveTextColor(const QColor &color); + + //background colors + void setBackgroundColor(const QColor &color); + void setHighlightColor(const QColor &color); + + //decoration colors + void setFocusColor(const QColor &color); + void setHoverColor(const QColor &color); + + void setDefaultFont(const QFont &defaultFont); + void setPalette(const QPalette &palette); +private: + PlatformThemePrivate *d; + friend class PlatformThemePrivate; +}; + +} + +QML_DECLARE_TYPEINFO(Kirigami::PlatformTheme, QML_HAS_ATTACHED_PROPERTIES) + +#endif // PLATFORMTHEME_H diff --git a/src/libkirigami/tabletmodewatcher.cpp b/src/libkirigami/tabletmodewatcher.cpp new file mode 100644 index 0000000..2d228eb --- /dev/null +++ b/src/libkirigami/tabletmodewatcher.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "tabletmodewatcher.h" + +#if defined(KIRIGAMI_ENABLE_DBUS) +#include "tabletmodemanager_interface.h" +#include +#endif + +//TODO: All the dbus stuff should be conditional, optional win32 support + +namespace Kirigami { + +class TabletModeWatcherSingleton +{ +public: + TabletModeWatcher self; +}; + +Q_GLOBAL_STATIC(TabletModeWatcherSingleton, privateTabletModeWatcherSelf) + + +class TabletModeWatcherPrivate +{ +public: + TabletModeWatcherPrivate(TabletModeWatcher *watcher) + : q(watcher) + { + +#if !defined(KIRIGAMI_ENABLE_DBUS) && (defined(Q_OS_ANDROID) || defined(Q_OS_IOS)) + isTabletModeAvailable = true; + isTabletMode = true; +#elif defined(KIRIGAMI_ENABLE_DBUS) + //Mostly for debug purposes and for platforms which are always mobile, + //such as Plasma Mobile + if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE") || + qEnvironmentVariableIsSet("KDE_KIRIGAMI_TABLET_MODE")) { + isTabletMode = (QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("1") || + QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("true")) || + (QString::fromLatin1(qgetenv("KDE_KIRIGAMI_TABLET_MODE")) == QStringLiteral("1") || + QString::fromLatin1(qgetenv("KDE_KIRIGAMI_TABLET_MODE")) == QStringLiteral("true")); + isTabletModeAvailable = isTabletMode; + } else { + m_interface = new OrgKdeKWinTabletModeManagerInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/org/kde/KWin"), QDBusConnection::sessionBus(), q); + + if (m_interface->isValid()) { + //NOTE: the initial call is actually sync, because is better a tiny freeze than having the ui always recalculated and changed at the start + isTabletModeAvailable = m_interface->tabletModeAvailable(); + isTabletMode = m_interface->tabletMode(); + QObject::connect(m_interface, &OrgKdeKWinTabletModeManagerInterface::tabletModeChanged, + q, [this](bool tabletMode) { + setIsTablet(tabletMode); + }); + QObject::connect(m_interface, &OrgKdeKWinTabletModeManagerInterface::tabletModeAvailableChanged, + q, [this](bool avail) { + isTabletModeAvailable = avail; + emit q->tabletModeAvailableChanged(avail); + }); + } else { + isTabletModeAvailable = false; + isTabletMode = false; + } + } +//TODO: case for Windows +#else + isTabletModeAvailable = false; + isTabletMode = false; +#endif + } + ~TabletModeWatcherPrivate() {}; + void setIsTablet(bool tablet); + + TabletModeWatcher *q; +#if defined(KIRIGAMI_ENABLE_DBUS) + OrgKdeKWinTabletModeManagerInterface *m_interface = nullptr; +#endif + bool isTabletModeAvailable = false; + bool isTabletMode = false; +}; + +void TabletModeWatcherPrivate::setIsTablet(bool tablet) +{ + if (isTabletMode == tablet) { + return; + } + + isTabletMode = tablet; + emit q->tabletModeChanged(tablet); +} + + + +TabletModeWatcher::TabletModeWatcher(QObject *parent) + : QObject(parent), + d(new TabletModeWatcherPrivate(this)) +{ +} + +TabletModeWatcher::~TabletModeWatcher() +{ + delete d; +} + +TabletModeWatcher *TabletModeWatcher::self() +{ + return &privateTabletModeWatcherSelf()->self; +} + +bool TabletModeWatcher::isTabletModeAvailable() const +{ + return d->isTabletModeAvailable; +} + +bool TabletModeWatcher::isTabletMode() const +{ + return d->isTabletMode; +} + +} + +#include "moc_tabletmodewatcher.cpp" diff --git a/src/libkirigami/tabletmodewatcher.h b/src/libkirigami/tabletmodewatcher.h new file mode 100644 index 0000000..f8ca1fe --- /dev/null +++ b/src/libkirigami/tabletmodewatcher.h @@ -0,0 +1,88 @@ +/* + * Copyright 2018 Marco Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef KIRIGAMI_TABLETMODEWATCHER +#define KIRIGAMI_TABLETMODEWATCHER + +#include + +#ifndef KIRIGAMI_BUILD_TYPE_STATIC +#include +#endif + +namespace Kirigami { + +class TabletModeWatcherPrivate; + +/** + * This class reports on the status of certain transformable + * devices which can be both tablets and laptops at the same time, + * with a detachable keyboard. + * It reports whether the device supports a tablet mode and if + * the device is currently in such mode or not, emitting a signal + * when the user switches. + */ +#ifdef KIRIGAMI_BUILD_TYPE_STATIC +class TabletModeWatcher : public QObject +#else +class KIRIGAMI2_EXPORT TabletModeWatcher : public QObject +#endif +{ + Q_OBJECT + Q_PROPERTY(bool tabletModeAvailable READ isTabletModeAvailable NOTIFY tabletModeAvailableChanged) + Q_PROPERTY(bool tabletMode READ isTabletMode NOTIFY tabletModeChanged) + +public: + ~TabletModeWatcher(); + static TabletModeWatcher *self(); + + /** + * @returns true if the device supports a tablet mode and has a switch + * to report when the device has been transformed. + * For debug purposes, if either the environment variable QT_QUICK_CONTROLS_MOBILE + * or KDE_KIRIGAMI_TABLET_MODE are set to true, isTabletModeAvailable will be true + */ + bool isTabletModeAvailable() const; + + /** + * @returns true if the machine is now in tablet mode, such as the + * laptop keyboard flipped away or detached. + * Note that this doesn't mean exactly a tablet form factor, but + * that the preferred input mode for the device is the touch screen + * and that pointer and keyboard are either secondary or not available. + * + * For debug purposes, if either the environment variable QT_QUICK_CONTROLS_MOBILE + * or KDE_KIRIGAMI_TABLET_MODE are set to true, isTabletMode will be true + */ + bool isTabletMode() const; + +Q_SIGNALS: + void tabletModeAvailableChanged(bool tabletModeAvailable); + void tabletModeChanged(bool tabletMode); + +private: + TabletModeWatcher(QObject *parent = nullptr); + TabletModeWatcherPrivate *d; + friend class TabletModeWatcherSingleton; +}; +} + +#endif // KIRIGAMI_TABLETMODEWATCHER diff --git a/src/mnemonicattached.cpp b/src/mnemonicattached.cpp new file mode 100644 index 0000000..a2fb73d --- /dev/null +++ b/src/mnemonicattached.cpp @@ -0,0 +1,321 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "mnemonicattached.h" +#include +#include +#include +#include + +QHash MnemonicAttached::s_sequenceToObject = QHash(); + +MnemonicAttached::MnemonicAttached(QObject *parent) + : QObject(parent) +{ + QQuickItem *parentItem = qobject_cast(parent); + if (parentItem) { + if (parentItem->window()) { + m_window = parentItem->window(); + m_window->installEventFilter(this); + } + connect(parentItem, &QQuickItem::windowChanged, this, + [this](QQuickWindow *window) { + if (m_window) { + QWindow *renderWindow = QQuickRenderControl::renderWindowFor(m_window); + if (renderWindow) { + renderWindow->removeEventFilter(this); + } else { + m_window->removeEventFilter(this); + } + } + m_window = window; + if (m_window) { + QWindow *renderWindow = QQuickRenderControl::renderWindowFor(m_window); + //renderWindow means the widget is rendering somewhere else, like a QQuickWidget + if (renderWindow && renderWindow != m_window) { + renderWindow->installEventFilter(this); + } else { + m_window->installEventFilter(this); + } + } + }); + } +} + +MnemonicAttached::~MnemonicAttached() +{ + s_sequenceToObject.remove(m_sequence); +} + +bool MnemonicAttached::eventFilter(QObject *watched, QEvent *e) +{ + Q_UNUSED(watched) + + if (m_richTextLabel.isEmpty()) { + return false; + } + + if (e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(e); + if (ke->key() == Qt::Key_Alt) { + m_actualRichTextLabel = m_richTextLabel; + emit richTextLabelChanged(); + } + + } else if (e->type() == QEvent::KeyRelease) { + QKeyEvent *ke = static_cast(e); + if (ke->key() == Qt::Key_Alt) { + m_actualRichTextLabel = m_label; + m_actualRichTextLabel.replace(QRegularExpression(QStringLiteral("\\&([^\\&])")), QStringLiteral("\\1")); + emit richTextLabelChanged(); + } + } + return false; +} + +//Algorythm adapted from KAccelString +void MnemonicAttached::calculateWeights() +{ + m_weights.clear(); + + int pos = 0; + bool start_character = true; + bool wanted_character = false; + + while (pos < m_label.length()) { + QChar c = m_label[pos]; + + // skip non typeable characters + if (!c.isLetterOrNumber()) { + start_character = true; + ++pos; + continue; + } + + int weight = 1; + + // add special weight to first character + if (pos == 0) { + weight += FIRST_CHARACTER_EXTRA_WEIGHT; + } + + // add weight to word beginnings + if (start_character) { + weight += WORD_BEGINNING_EXTRA_WEIGHT; + start_character = false; + } + + // add weight to word beginnings + if (wanted_character) { + weight += WANTED_ACCEL_EXTRA_WEIGHT; + wanted_character = false; + } + + // add decreasing weight to left characters + if (pos < 50) { + weight += (50 - pos); + } + + // try to preserve the wanted accelerators + if (c == QLatin1Char('&') && (pos == m_label.length() - 1 || m_label[pos+1] != QLatin1Char('&'))) { + wanted_character = true; + ++pos; + continue; + } + + while (m_weights.contains(weight)) { + ++weight; + } + + m_weights[weight] = c; + + ++pos; + } + + //update our maximum weight + if (m_weights.isEmpty()) { + m_weight = m_baseWeight; + } else { + m_weight = m_baseWeight + m_weights.keys().last(); + } +} + +void MnemonicAttached::updateSequence() +{ + if (!m_sequence.isEmpty()) { + s_sequenceToObject.remove(m_sequence); + m_sequence = {}; + } + + calculateWeights(); + + const QString text = label(); + + if (!m_enabled) { + m_actualRichTextLabel = text; + m_actualRichTextLabel.replace(QRegularExpression(QStringLiteral("\\&([^\\&])")), QStringLiteral("\\1")); + //was the label already completely plain text? try to limit signal emission + if (m_mnemonicLabel != m_actualRichTextLabel) { + m_mnemonicLabel = m_actualRichTextLabel; + emit mnemonicLabelChanged(); + emit richTextLabelChanged(); + } + return; + } + + if (m_weights.isEmpty()) { + return; + } + + QMap::const_iterator i = m_weights.constEnd(); + do { + --i; + QChar c = i.value(); + QKeySequence ks(QStringLiteral("Alt+") % c); + MnemonicAttached *otherMa = s_sequenceToObject.value(ks); + Q_ASSERT(otherMa != this); + if (!otherMa || otherMa->m_weight < m_weight) { + //the old shortcut is less valuable than the current: remove it + if (otherMa) { + s_sequenceToObject.remove(otherMa->sequence()); + otherMa->m_sequence = {}; + } + + s_sequenceToObject[ks] = this; + m_sequence = ks; + m_richTextLabel = text; + m_richTextLabel.replace(QRegularExpression(QLatin1String("\\&([^\\&])")), QStringLiteral("\\1")); + m_actualRichTextLabel = m_richTextLabel; + m_mnemonicLabel = m_richTextLabel; + m_mnemonicLabel.replace(c, QLatin1String("&") % c); + m_richTextLabel.replace(QString(c), QLatin1String("") % c % QLatin1String("")); + + //remap the sequence of the previous shortcut + if (otherMa) { + otherMa->updateSequence(); + } + + break; + } + } while (i != m_weights.constBegin()); + + if (!m_sequence.isEmpty()) { + emit sequenceChanged(); + } else { + m_actualRichTextLabel = text; + m_actualRichTextLabel.replace(QRegularExpression(QStringLiteral("\\&([^\\&])")), QStringLiteral("\\1")); + m_mnemonicLabel = m_actualRichTextLabel; + } + + emit richTextLabelChanged(); + emit mnemonicLabelChanged(); +} + +void MnemonicAttached::setLabel(const QString &text) +{ + if (m_label == text) { + return; + } + + m_label = text; + updateSequence(); + emit labelChanged(); +} + +QString MnemonicAttached::richTextLabel() const +{ + return !m_actualRichTextLabel.isEmpty() ? m_actualRichTextLabel : m_label; +} + +QString MnemonicAttached::mnemonicLabel() const +{ + return m_mnemonicLabel; +} + +QString MnemonicAttached::label() const +{ + return m_label; +} + +void MnemonicAttached::setEnabled(bool enabled) +{ + if (m_enabled == enabled) { + return; + } + + m_enabled = enabled; + updateSequence(); + emit enabledChanged(); +} + +bool MnemonicAttached::enabled() const +{ + return m_enabled; +} + +void MnemonicAttached::setControlType(MnemonicAttached::ControlType controlType) +{ + if (m_controlType == controlType) { + return; + } + + m_controlType = controlType; + + switch (controlType) { + case ActionElement: + m_baseWeight = ACTION_ELEMENT_WEIGHT; + break; + case DialogButton: + m_baseWeight = DIALOG_BUTTON_EXTRA_WEIGHT; + break; + case MenuItem: + m_baseWeight = MENU_ITEM_WEIGHT; + break; + case FormLabel: + m_baseWeight = FORM_LABEL_WEIGHT; + break; + default: + m_baseWeight = SECONDARY_CONTROL_WEIGHT; + break; + } + //update our maximum weight + if (m_weights.isEmpty()) { + m_weight = m_baseWeight; + } else { + m_weight = m_baseWeight + (m_weights.constEnd() - 1).key(); + } + emit controlTypeChanged(); +} + +MnemonicAttached::ControlType MnemonicAttached::controlType() const +{ + return m_controlType; +} + +QKeySequence MnemonicAttached::sequence() +{ + return m_sequence; +} + +MnemonicAttached *MnemonicAttached::qmlAttachedProperties(QObject *object) +{ + return new MnemonicAttached(object); +} + +#include "moc_mnemonicattached.cpp" diff --git a/src/mnemonicattached.h b/src/mnemonicattached.h new file mode 100644 index 0000000..5b9c0e2 --- /dev/null +++ b/src/mnemonicattached.h @@ -0,0 +1,169 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef MNEMONICATTACHED_H +#define MNEMONICATTACHED_H + +#include +#include +#include + +class QQuickItem; + +/** + * This Attached property is used to calculate automated keyboard sequences + * to trigger actions based upon their text: if an "&" mnemonic is + * used (ie "&Ok"), the system will attempt to assign the desired letter giving + * it priority, otherwise a letter among the ones in the label will be used if + * possible and not conflicting. + * Different kinds of controls will have different priorities in assigning the + * shortcut: for instance the "Ok/Cancel" buttons in a dialog will have priority + * over fields of a FormLayout. + * @see ControlType + * + * Usually the developer shouldn't use this directly as base components + * already use this, but only when implementing a custom graphical Control. + * @since 2.3 + */ +class MnemonicAttached : public QObject +{ + Q_OBJECT + /** + * The label of the control we want to compute a mnemonic for, instance + * "Label:" or "&Ok" + */ + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + + /** + * The user-visible final label, which will have the shortcut letter underlined, + * such as "<u>O</u>k" + */ + Q_PROPERTY(QString richTextLabel READ richTextLabel NOTIFY richTextLabelChanged) + + /** + * The label with an "&" mnemonic in the place which will have the shortcut + * assigned, regardless the & wasassigned by the user or automatically generated. + */ + Q_PROPERTY(QString mnemonicLabel READ mnemonicLabel NOTIFY mnemonicLabelChanged) + + /** + * Only if true this mnemonic will be considered for the global assignment + * default: true + */ + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + + /** + * the type of control this mnemonic is attached: different types of controls have different importance and priority for shortcut assignment. + * @see ControlType + */ + Q_PROPERTY(MnemonicAttached::ControlType controlType READ controlType WRITE setControlType NOTIFY controlTypeChanged) + + /** + * The final key sequence assigned, if any: it will be Alt+alphanumeric char + */ + Q_PROPERTY(QKeySequence sequence READ sequence NOTIFY sequenceChanged) + +public: + enum ControlType { + ActionElement, /** pushbuttons, checkboxes etc */ + DialogButton, /** buttons for dialogs */ + MenuItem, /** Menu items */ + FormLabel, /** Buddy label in a FormLayout*/ + SecondaryControl /** Other controls that are considered not much important and low priority for shortcuts */ + }; + Q_ENUM(ControlType) + + explicit MnemonicAttached(QObject *parent = nullptr); + ~MnemonicAttached(); + + void setLabel(const QString &text); + QString label() const; + + QString richTextLabel() const; + QString mnemonicLabel() const; + + void setEnabled(bool enabled); + bool enabled() const; + + void setControlType(MnemonicAttached::ControlType controlType); + ControlType controlType() const; + + QKeySequence sequence(); + + //QML attached property + static MnemonicAttached *qmlAttachedProperties(QObject *object); + +protected: + bool eventFilter(QObject *watched, QEvent *e) override; + void updateSequence(); + +Q_SIGNALS: + void labelChanged(); + void enabledChanged(); + void sequenceChanged(); + void richTextLabelChanged(); + void mnemonicLabelChanged(); + void controlTypeChanged(); + +private: + void calculateWeights(); + + //TODO: to have support for DIALOG_BUTTON_EXTRA_WEIGHT etc, a type enum should be exported + enum { + // Additional weight for first character in string + FIRST_CHARACTER_EXTRA_WEIGHT = 50, + // Additional weight for the beginning of a word + WORD_BEGINNING_EXTRA_WEIGHT = 50, + // Additional weight for a 'wanted' accelerator ie string with '&' + WANTED_ACCEL_EXTRA_WEIGHT = 150, + // Default weight for an 'action' widget (ie, pushbuttons) + ACTION_ELEMENT_WEIGHT = 50, + // Additional weight for the dialog buttons (large, we basically never want these reassigned) + DIALOG_BUTTON_EXTRA_WEIGHT = 300, + // Weight for FormLayout labels (low) + FORM_LABEL_WEIGHT = 20, + // Weight for Secondary controls which are considered less important (low) + SECONDARY_CONTROL_WEIGHT = 10, + // Default weight for menu items + MENU_ITEM_WEIGHT = 250 + }; + + //order word letters by weight + int m_weight = 0; + int m_baseWeight = 0; + ControlType m_controlType = SecondaryControl; + QMap m_weights; + + QString m_label; + QString m_actualRichTextLabel; + QString m_richTextLabel; + QString m_mnemonicLabel; + QKeySequence m_sequence; + bool m_enabled = true; + + QPointer m_window; + + //global mapping of mnemonics + //TODO: map by QWindow + static QHash s_sequenceToObject; +}; + +QML_DECLARE_TYPEINFO(MnemonicAttached, QML_HAS_ATTACHED_PROPERTIES) + +#endif // MnemonicATTACHED_H diff --git a/src/qmldir b/src/qmldir new file mode 100644 index 0000000..20438e4 --- /dev/null +++ b/src/qmldir @@ -0,0 +1,48 @@ +module org.kde.kirigami + +classname KirigamiPlugin +depends QtQuick.Controls 2.0 +depends QtGraphicalEffects 1.0 +designersupported + +typeinfo plugins.qmltypes + +singleton Theme 2.2 Theme.qml + +OverlaySheet 2.5 OverlaySheet.qml +ApplicationItem 2.1 ApplicationItem.qml +AbstractApplicationWindow 2.5 AbstractApplicationWindow.qml +FormLayout 2.5 FormLayout.qml +GlobalDrawer 2.5 GlobalDrawer.qml +BasicListItem 2.5 BasicListItem.qml +AbstractItemViewHeader 2.1 AbstractItemViewHeader.qml +Heading 2.5 Heading.qml +Action 2.5 Action.qml +Separator 2.5 Separator.qml +ItemViewHeader 2.1 ItemViewHeader.qml +SwipeListItem 2.5 SwipeListItem.qml +AbstractListItem 2.5 AbstractListItem.qml +Icon 2.5 Icon.qml +Units 2.5 Units.qml +Page 2.5 Page.qml +Label 2.5 Label.qml +AbstractApplicationItem 2.1 AbstractApplicationItem.qml +ToolBarApplicationHeader 2.5 ToolBarApplicationHeader.qml +ScrollablePage 2.5 ScrollablePage.qml +ApplicationHeader 2.5 ApplicationHeader.qml +AbstractApplicationHeader 2.5 AbstractApplicationHeader.qml +ContextDrawer 2.5 ContextDrawer.qml +ApplicationWindow 2.5 ApplicationWindow.qml +PageRow 2.5 PageRow.qml +AbstractCard 2.5 AbstractCard.qml +Card 2.5 Card.qml +CardsLayout 2.5 CardsLayout.qml +CardsListView 2.5 CardsListView.qml +CardsGridView 2.5 CardsGridView.qml +InlineMessage 2.5 InlineMessage.qml +ListItemDragHandle 2.5 ListItemDragHandle.qml +ActionToolBar 2.5 ActionToolBar.qml +BannerImage 2.5 private/BannerImage.qml +AboutPage 2.6 AboutPage.qml +UrlButton 2.6 UrlButton.qml +LinkButton 2.6 LinkButton.qml diff --git a/src/scenepositionattached.cpp b/src/scenepositionattached.cpp new file mode 100644 index 0000000..9ebad70 --- /dev/null +++ b/src/scenepositionattached.cpp @@ -0,0 +1,79 @@ +/* +* Copyright (C) 2017 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "scenepositionattached.h" +#include +#include + +ScenePositionAttached::ScenePositionAttached(QObject *parent) + : QObject(parent) +{ + m_item = qobject_cast(parent); + connectAncestors(m_item); +} + +ScenePositionAttached::~ScenePositionAttached() +{ +} + +int ScenePositionAttached::x() const +{ + return m_item->mapToScene(QPointF()).x(); +} + +int ScenePositionAttached::y() const +{ + return m_item->mapToScene(QPointF()).y(); +} + +void ScenePositionAttached::connectAncestors(QQuickItem *item) +{ + if (!item) { + return; + } + + QQuickItem *ancestor = item; + while (ancestor) { + m_ancestors << ancestor; + + connect(ancestor, &QQuickItem::xChanged, this, &ScenePositionAttached::xChanged); + connect(ancestor, &QQuickItem::yChanged, this, &ScenePositionAttached::yChanged); + connect(ancestor, &QQuickItem::parentChanged, this, + [this, ancestor]() { + do { + disconnect(ancestor, nullptr, this, nullptr); + m_ancestors.pop_back(); + } while (!m_ancestors.isEmpty() && m_ancestors.last() != ancestor); + + connectAncestors(ancestor); + emit xChanged(); + emit yChanged(); + } + ); + + ancestor = ancestor->parentItem(); + } +} + +ScenePositionAttached *ScenePositionAttached::qmlAttachedProperties(QObject *object) +{ + return new ScenePositionAttached(object); +} + +#include "moc_scenepositionattached.cpp" diff --git a/src/scenepositionattached.h b/src/scenepositionattached.h new file mode 100644 index 0000000..d96ed00 --- /dev/null +++ b/src/scenepositionattached.h @@ -0,0 +1,76 @@ +/* +* Copyright (C) 2018 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SCENEPOSITIONATTACHED_H +#define SCENEPOSITIONATTACHED_H + +#include +#include + +class QQuickItem; + +/** + * This attached property contains the information about the scene position of the item: + * Its global x and y coordinates will update automatically and can be binded + * @code + * import org.kde.kirigami 2.5 as Kirigami + * Text { + * text: ScenePosition.x + * } + * @endcode + * @since 2.3 + */ +class ScenePositionAttached : public QObject +{ + Q_OBJECT + /** + * The global scene X position + */ + Q_PROPERTY(int x READ x NOTIFY xChanged) + + /** + * The global scene Y position + */ + Q_PROPERTY(int y READ y NOTIFY yChanged) + +public: + + explicit ScenePositionAttached(QObject *parent = nullptr); + ~ScenePositionAttached() override; + + int x() const; + int y() const; + + //QML attached property + static ScenePositionAttached *qmlAttachedProperties(QObject *object); + +Q_SIGNALS: + void xChanged(); + void yChanged(); + +private: + void connectAncestors(QQuickItem *item); + + QQuickItem *m_item = nullptr; + QList m_ancestors; +}; + +QML_DECLARE_TYPEINFO(ScenePositionAttached, QML_HAS_ATTACHED_PROPERTIES) + +#endif // SCENEPOSITIONATTACHED_H diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..eaba50b --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "settings.h" + +#include +#include +#include +#include +#include + +#include "libkirigami/tabletmodewatcher.h" +#include "../kirigami_version.h" + +Settings::Settings(QObject *parent) + : QObject(parent) +{ + m_tabletModeAvailable = Kirigami::TabletModeWatcher::self()->isTabletModeAvailable(); + connect(Kirigami::TabletModeWatcher::self(), &Kirigami::TabletModeWatcher::tabletModeAvailableChanged, + this, [this](bool tabletModeAvailable) { + setTabletModeAvailable(tabletModeAvailable); + }); + + m_tabletMode = Kirigami::TabletModeWatcher::self()->isTabletMode(); + connect(Kirigami::TabletModeWatcher::self(), &Kirigami::TabletModeWatcher::tabletModeChanged, + this, [this](bool tabletMode) { + setTabletMode(tabletMode); + }); + +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + m_mobile = true; +#else + //Mostly for debug purposes and for platforms which are always mobile, + //such as Plasma Mobile + if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE")) { + m_mobile = (QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("1") || + QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_MOBILE")) == QStringLiteral("true")); + } else { + m_mobile = false; + } +#endif + + const QString configPath = QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("kdeglobals")); + if (QFile::exists(configPath)) { + QSettings globals(configPath, QSettings::IniFormat); + globals.beginGroup(QStringLiteral("KDE")); + m_scrollLines = qMax(1, globals.value(QStringLiteral("WheelScrollLines"), 3).toInt()); + } else { + m_scrollLines = 3; + } +} + + +Settings::~Settings() +{ +} + +void Settings::setTabletModeAvailable(bool mobileAvailable) +{ + if (mobileAvailable == m_tabletModeAvailable) { + return; + } + + m_tabletModeAvailable = mobileAvailable; + emit tabletModeAvailableChanged(); +} + +bool Settings::isTabletModeAvailable() const +{ + return m_tabletModeAvailable; +} + +void Settings::setIsMobile(bool mobile) +{ + if (mobile == m_mobile) { + return; + } + + m_mobile = mobile; + emit isMobileChanged(); +} + +bool Settings::isMobile() const +{ + return m_mobile; +} + +void Settings::setTabletMode(bool tablet) +{ + if (tablet == m_tabletMode) { + return; + } + + m_tabletMode = tablet; + emit tabletModeChanged(); +} + +bool Settings::tabletMode() const +{ + return m_tabletMode; +} + +QString Settings::style() const +{ + return m_style; +} + +void Settings::setStyle(const QString &style) +{ + m_style = style; +} + +int Settings::mouseWheelScrollLines() const +{ + return m_scrollLines; +} + +QStringList Settings::information() const +{ + return { + tr("KDE Frameworks %1").arg(QStringLiteral(KIRIGAMI2_VERSION_STRING)), + tr("The %1 windowing system").arg(QGuiApplication::platformName()), + tr("Qt %2 (built against %3)").arg(QString::fromLocal8Bit(qVersion()), QStringLiteral(QT_VERSION_STR)) + }; +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..f38b194 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,107 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include + +/** + * This class contains global kirigami settings about the current device setup + * It is exposed to QML as the singleton "Settings" + */ +class Settings : public QObject +{ + Q_OBJECT + + /** + * True if the system can dynamically enter in tablet mode + * (or the device is actually a tablet). + * such as transformable laptops that support keyboard detachment + */ + Q_PROPERTY(bool tabletModeAvailable READ isTabletModeAvailable NOTIFY tabletModeAvailableChanged) + + /** + * True if we are running on a small mobile device such as a mobile phone + * This is used when we want to do specific adaptations to our UI for + * small screen form factors, such as having bigger touch areas. + */ + Q_PROPERTY(bool isMobile READ isMobile NOTIFY isMobileChanged) + + /** + * True if the device we are running on is behaving like a tablet: + * Note that this doesn't mean exactly a tablet form factor, but + * that the preferred input mode for the device is the touch screen + * and that pointer and keyboard are either secondary or not available. + */ + Q_PROPERTY(bool tabletMode READ tabletMode NOTIFY tabletModeChanged) + + /** + * name of the QtQuickControls2 style we are using, + * for instance org.kde.desktop, Plasma, Material, Universal etc + */ + Q_PROPERTY(QString style READ style CONSTANT) + + //TODO: make this adapt without file watchers? + /** + * How many lines of text the mouse wheel should scroll + */ + Q_PROPERTY(int mouseWheelScrollLines READ mouseWheelScrollLines CONSTANT) + + /** + * @returns runtime information about the libraries in use + * + * @since 5.52 + * @since org.kde.kirigami 2.6 + */ + Q_PROPERTY(QStringList information READ information CONSTANT) + +public: + Settings(QObject *parent = nullptr); + ~Settings(); + + void setTabletModeAvailable(bool mobile); + bool isTabletModeAvailable() const; + + void setIsMobile(bool mobile); + bool isMobile() const; + + void setTabletMode(bool tablet); + bool tabletMode() const; + + QString style() const; + void setStyle(const QString &style); + + int mouseWheelScrollLines() const; + + QStringList information() const; + +Q_SIGNALS: + void tabletModeAvailableChanged(); + void tabletModeChanged(); + void isMobileChanged(); + +private: + QString m_style; + int m_scrollLines = 0; + bool m_tabletModeAvailable : 1; + bool m_mobile : 1; + bool m_tabletMode : 1; +}; + +#endif diff --git a/src/styles/Material/AbstractListItem.qml b/src/styles/Material/AbstractListItem.qml new file mode 100644 index 0000000..3ca2ae6 --- /dev/null +++ b/src/styles/Material/AbstractListItem.qml @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.7 +import org.kde.kirigami 2.4 +import QtQuick.Controls.Material 2.1 as Mat +import QtQuick.Controls.Material.impl 2.1 as MatImp +import "../../private" +import "../../templates" as T + +T.AbstractListItem { + id: listItem + + background: DefaultListItemBackground { + + MatImp.Ripple { + anchors.fill: parent + clip: visible + pressed: listItem.pressed + anchor: listItem + active: listItem.down || listItem.visualFocus + color: Qt.rgba(0,0,0,0.2) + } + } + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 6 +} diff --git a/src/styles/Material/Label.qml b/src/styles/Material/Label.qml new file mode 100644 index 0000000..ae137b0 --- /dev/null +++ b/src/styles/Material/Label.qml @@ -0,0 +1,46 @@ +/* +* Copyright (C) 2011 by Marco Martin +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Library General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. +*/ + +import QtQuick 2.1 +import QtQuick.Window 2.2 +import org.kde.kirigami 2.4 +import QtQuick.Controls 2.0 as Controls + +/** + * This is a label which uses the current Theme. + * + * The characteristics of the text will be automatically set according to the + * current Theme. If you need a more customized text item use the Text component + * from QtQuick. + * + * You can use all elements of the QML Text component, in particular the "text" + * property to define the label text. + * + * @inherit QtQuick.Templates.Label + * @deprecated use QtQuick.Templates.Label directly, it will be styled appropriately + */ +Controls.Label { + verticalAlignment: lineCount > 1 ? Text.AlignTop : Text.AlignVCenter + + activeFocusOnTab: false + + Component.onCompleted: { + console.warn("Kirigami.Label is deprecated. Use QtQuickControls2.Label instead") + } +} diff --git a/src/styles/Material/SwipeListItem.qml b/src/styles/Material/SwipeListItem.qml new file mode 100644 index 0000000..5cbe626 --- /dev/null +++ b/src/styles/Material/SwipeListItem.qml @@ -0,0 +1,70 @@ +/* + * Copyright 2010 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.4 +import QtQuick.Controls.Material 2.1 as Mat +import QtQuick.Controls.Material.impl 2.1 as MatImp +import "../../private" +import "../../templates" as T + +/** + * An item delegate Intended to support extra actions obtainable + * by uncovering them by dragging away the item with the handle + * This acts as a container for normal list items. + * Any subclass of AbstractListItem can be assigned as the contentItem property. + * @code + * ListView { + * model: myModel + * delegate: SwipeListItem { + * Label { + * text: model.text + * } + * actions: [ + * Action { + * iconName: "document-decrypt" + * onTriggered: print("Action 1 clicked") + * }, + * Action { + * iconName: model.action2Icon + * onTriggered: //do something + * } + * ] + * } + * + * } + * @endcode + * + * @inherit QtQuick.Item + */ +T.SwipeListItem { + id: root + + background: DefaultListItemBackground { + MatImp.Ripple { + anchors.fill: parent + clip: visible + pressed: listItem.pressed + anchor: listItem + active: listItem.down || listItem.visualFocus + color: Qt.rgba(0,0,0,0.2) + } + } + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 6 +} diff --git a/src/styles/Material/Theme.qml b/src/styles/Material/Theme.qml new file mode 100644 index 0000000..ed35c96 --- /dev/null +++ b/src/styles/Material/Theme.qml @@ -0,0 +1,105 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls.Material 2.0 +import org.kde.kirigami 2.4 as Kirigami + +pragma Singleton + + +QtObject { + id: theme + //NOTE: this is useless per se, but it forces the Material attached property to be created + Material.elevation:2 + + property color textColor: theme.Material.foreground + onTextColorChanged: theme.Material.foreground = textColor + property color disabledTextColor: "#9931363b" + + property color highlightColor: theme.Material.accent + onHighlightColorChanged: theme.Material.accent = highlightColor + //FIXME: something better? + property color highlightedTextColor: theme.Material.background + property color backgroundColor: theme.Material.background + property color activeTextColor: theme.Material.primary + property color linkColor: "#2980B9" + property color visitedLinkColor: "#7F8C8D" + property color hoverColor: theme.Material.highlightedButtonColor + property color focusColor: theme.Material.highlightedButtonColor + property color negativeTextColor: "#DA4453" + property color neutralTextColor: "#F67400" + property color positiveTextColor: "#27AE60" + + property color buttonTextColor: theme.Material.foreground + property color buttonBackgroundColor: theme.Material.buttonColor + property color buttonHoverColor: theme.Material.highlightedButtonColor + property color buttonFocusColor: theme.Material.highlightedButtonColor + + property color viewTextColor: theme.Material.foreground + property color viewBackgroundColor: theme.Material.dialogColor + property color viewHoverColor: theme.Material.listHighlightColor + property color viewFocusColor: theme.Material.listHighlightColor + + property color selectionTextColor: theme.Material.primaryHighlightedTextColor + property color selectionBackgroundColor: theme.Material.textSelectionColor + property color selectionHoverColor: theme.Material.highlightedButtonColor + property color selectionFocusColor: theme.Material.highlightedButtonColor + + property color tooltipTextColor: fontMetrics.Material.foreground + property color tooltipBackgroundColor: fontMetrics.Material.tooltipColor + property color tooltipHoverColor: fontMetrics.Material.highlightedButtonColor + property color tooltipFocusColor: fontMetrics.Material.highlightedButtonColor + + property color complementaryTextColor: fontMetrics.Material.foreground + property color complementaryBackgroundColor: fontMetrics.Material.background + property color complementaryHoverColor: theme.Material.highlightedButtonColor + property color complementaryFocusColor: theme.Material.highlightedButtonColor + + property font defaultFont: fontMetrics.font + + property list children: [ + TextMetrics { + id: fontMetrics + //this is to get a source of dark colors + Material.theme: Material.Dark + } + ] + //for internal use + function __propagateColorSet(object, context) { + //TODO: actually check if it's a dark or light color + if (context === Kirigami.Theme.Complementary) { + object.Material.theme = Material.Dark; + } else { + object.Material.theme = Material.Light; + } + } + function __propagateTextColor(object, color) { + object.Material.foreground = color; + } + function __propagateBackgroundColor(object, color) { + object.Material.background = color; + } + function __propagatePrimaryColor(object, color) { + object.Material.primary = color; + } + function __propagateAccentColor(object, color) { + object.Material.accent = color; + } +} diff --git a/src/styles/org.kde.desktop/AbstractApplicationHeader.qml b/src/styles/org.kde.desktop/AbstractApplicationHeader.qml new file mode 100644 index 0000000..5cad71d --- /dev/null +++ b/src/styles/org.kde.desktop/AbstractApplicationHeader.qml @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.4 + +import "../../templates" as T + + +/** + * An item that can be used as a title for the application. + * Scrolling the main page will make it taller or shorter (trough the point of going away) + * It's a behavior similar to the typical mobile web browser addressbar + * the minimum, preferred and maximum heights of the item can be controlled with + * * minimumHeight: default is 0, i.e. hidden + * * preferredHeight: default is Units.gridUnit * 1.6 + * * maximumHeight: default is Units.gridUnit * 3 + * + * To achieve a titlebar that stays completely fixed just set the 3 sizes as the same + */ +T.AbstractApplicationHeader { + id: root + + Theme.inherit: false + + background: Rectangle { + color: Theme.backgroundColor + Separator { + visible: root.separatorVisible && (!root.page || !root.page.header || root.page.header.toString().indexOf("ToolBar") === -1) + anchors { + left: parent.left + right: parent.right + bottom: root.y <= 0 ? parent.bottom : undefined + top: root.y <= 0 ? undefined : parent.top + } + } + } +} + diff --git a/src/styles/org.kde.desktop/AbstractListItem.qml b/src/styles/org.kde.desktop/AbstractListItem.qml new file mode 100644 index 0000000..71de7c6 --- /dev/null +++ b/src/styles/org.kde.desktop/AbstractListItem.qml @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 +import "../../private" +import "../../templates" as T + +T.AbstractListItem { + id: listItem + + background: DefaultListItemBackground {} + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 4 +} diff --git a/src/styles/org.kde.desktop/ApplicationWindow.qml b/src/styles/org.kde.desktop/ApplicationWindow.qml new file mode 100644 index 0000000..10056ff --- /dev/null +++ b/src/styles/org.kde.desktop/ApplicationWindow.qml @@ -0,0 +1,29 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.1 +import org.kde.kirigami 2.4 +import "../../" as Base + + +Base.ApplicationWindow { + id: root + width: Units.gridUnit * 55 + height: Units.gridUnit * 40 +} diff --git a/src/styles/org.kde.desktop/SwipeListItem.qml b/src/styles/org.kde.desktop/SwipeListItem.qml new file mode 100644 index 0000000..0ca60c2 --- /dev/null +++ b/src/styles/org.kde.desktop/SwipeListItem.qml @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.5 +import org.kde.kirigami 2.4 +import "../../private" +import "../../templates" as T + +T.SwipeListItem { + id: listItem + + background: DefaultListItemBackground {} + implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 4 +} diff --git a/src/styles/org.kde.desktop/Theme.qml b/src/styles/org.kde.desktop/Theme.qml new file mode 100644 index 0000000..c7db900 --- /dev/null +++ b/src/styles/org.kde.desktop/Theme.qml @@ -0,0 +1,90 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 + +pragma Singleton + + +QtObject { + id: theme + + property color textColor: palette.windowText + property color disabledTextColor: disabledPalette.windowText + + property color highlightColor: palette.highlight + property color highlightedTextColor: palette.highlightedText + property color backgroundColor: palette.window + property color activeTextColor: palette.highlight + property color linkColor: "#2980B9" + property color visitedLinkColor: "#7F8C8D" + property color hoverColor: palette.highlight + property color focusColor: palette.highlight + property color negativeTextColor: "#DA4453" + property color neutralTextColor: "#F67400" + property color positiveTextColor: "#27AE60" + + property color buttonTextColor: palette.buttonText + property color buttonBackgroundColor: palette.button + property color buttonHoverColor: palette.highlight + property color buttonFocusColor: palette.highlight + + property color viewTextColor: palette.text + property color viewBackgroundColor: palette.base + property color viewHoverColor: palette.highlight + property color viewFocusColor: palette.highlight + + property color selectionTextColor: palette.highlightedText + property color selectionBackgroundColor: palette.highlight + property color selectionHoverColor: palette.highlight + property color selectionFocusColor: palette.highlight + + property color tooltipTextColor: palette.base + property color tooltipBackgroundColor: palette.text + property color tooltipHoverColor: palette.highlight + property color tooltipFocusColor: palette.highlight + + property color complementaryTextColor: palette.base + property color complementaryBackgroundColor: palette.text + property color complementaryHoverColor: palette.highlight + property color complementaryFocusColor: palette.highlight + + property font defaultFont: fontMetrics.font + + property list children: [ + TextMetrics { + id: fontMetrics + }, + SystemPalette { + id: palette + colorGroup: SystemPalette.Active + }, + SystemPalette { + id: disabledPalette + colorGroup: SystemPalette.Disabled + } + ] + + function __propagateColorSet(object, context) {} + + function __propagateTextColor(object, color) {} + function __propagateBackgroundColor(object, color) {} + function __propagatePrimaryColor(object, color) {} + function __propagateAccentColor(object, color) {} +} diff --git a/src/styles/org.kde.desktop/Units.qml b/src/styles/org.kde.desktop/Units.qml new file mode 100644 index 0000000..a667b03 --- /dev/null +++ b/src/styles/org.kde.desktop/Units.qml @@ -0,0 +1,126 @@ +/* + * Copyright 2015 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Window 2.2 + +pragma Singleton + + +QtObject { + id: units + + /** + * The fundamental unit of space that should be used for sizes, expressed in pixels. + * Given the screen has an accurate DPI settings, it corresponds to a width of + * the capital letter M + */ + property int gridUnit: fontMetrics.height + + /** + * units.iconSizes provides access to platform-dependent icon sizing + * + * The icon sizes provided are normalized for different DPI, so icons + * will scale depending on the DPI. + * + * Icon sizes from KIconLoader, adjusted to devicePixelRatio: + * * small + * * smallMedium + * * medium + * * large + * * huge + * * enormous + * + * Not devicePixelRation-adjusted:: + * * desktop + */ + property QtObject iconSizes: QtObject { + property int small: fontMetrics.roundedIconSize(16 * devicePixelRatio) + property int smallMedium: fontMetrics.roundedIconSize(22 * devicePixelRatio) + property int medium: fontMetrics.roundedIconSize(32 * devicePixelRatio) + property int large: fontMetrics.roundedIconSize(48 * devicePixelRatio) + property int huge: fontMetrics.roundedIconSize(64 * devicePixelRatio) + property int enormous: 128 * devicePixelRatio + } + + /** + * units.smallSpacing is the amount of spacing that should be used around smaller UI elements, + * for example as spacing in Columns. Internally, this size depends on the size of + * the default font as rendered on the screen, so it takes user-configured font size and DPI + * into account. + */ + property int smallSpacing: Math.floor(gridUnit/4) + + /** + * units.largeSpacing is the amount of spacing that should be used inside bigger UI elements, + * for example between an icon and the corresponding text. Internally, this size depends on + * the size of the default font as rendered on the screen, so it takes user-configured font + * size and DPI into account. + */ + property int largeSpacing: smallSpacing * 2 + + /** + * The ratio between physical and device-independent pixels. This value does not depend on the \ + * size of the configured font. If you want to take font sizes into account when scaling elements, + * use theme.mSize(theme.defaultFont), units.smallSpacing and units.largeSpacing. + * The devicePixelRatio follows the definition of "device independent pixel" by Microsoft. + */ + property real devicePixelRatio: Math.max(1, (fontMetrics.font.pixelSize / fontMetrics.font.pointSize)) + + /** + * units.longDuration should be used for longer, screen-covering animations, for opening and + * closing of dialogs and other "not too small" animations + */ + property int longDuration: 250 + + /** + * units.shortDuration should be used for short animations, such as accentuating a UI event, + * hover events, etc.. + */ + property int shortDuration: 150 + + property int toolTipDelay: 700 + + //readonly property QtObject __styleItem: QtQuickControlsPrivate.StyleItem {elementType: "frame" } + + /** + * How much the mouse scroll wheel scrolls, expressed in lines of text. + * Note: this is strictly for classical mouse wheels, touchpads 2 figer scrolling won't be affected + */ + readonly property int wheelScrollLines: 3//__styleItem.styleHint("wheelScrollLines") + + property variant fontMetrics: TextMetrics { + text: "M" + function roundedIconSize(size) { + if (size < 16) { + return size; + } else if (size < 22) { + return 16; + } else if (size < 32) { + return 22; + } else if (size < 48) { + return 32; + } else if (size < 64) { + return 48; + } else { + return size; + } + } + } +} diff --git a/tests/KeyboardListTest.qml b/tests/KeyboardListTest.qml new file mode 100644 index 0000000..b3732c9 --- /dev/null +++ b/tests/KeyboardListTest.qml @@ -0,0 +1,45 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow +{ + id: main + Component { + id: keyPage + Kirigami.ScrollablePage { + ListView { + model: 10 + delegate: Rectangle { + width: 100 + height: 30 + color: ListView.isCurrentItem ? "red" : "white" + } + } + } + } + + Component.onCompleted: { + main.pageStack.push(keyPage) + } +} diff --git a/tests/KeyboardTest.qml b/tests/KeyboardTest.qml new file mode 100644 index 0000000..558d6aa --- /dev/null +++ b/tests/KeyboardTest.qml @@ -0,0 +1,56 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow +{ + id: main + Component { + id: keyPage + Kirigami.Page { + readonly property alias lastKey: see.text + Text { + id: see + anchors.centerIn: parent + color: parent.focus ? "black" : "red" + } + + Keys.onPressed: { + if (event.text) + see.text = event.text + else + see.text = event.key + } + + Keys.onEnterPressed: main.showPassiveNotification("page!") + } + } + + header: Text { + text: "focus:" + activeFocusItem + " current: " + main.pageStack.currentIndex + } + + Component.onCompleted: { + main.pageStack.push(keyPage) + main.pageStack.push(keyPage) + } +} diff --git a/tests/actionsMenu.qml b/tests/actionsMenu.qml new file mode 100644 index 0000000..962a462 --- /dev/null +++ b/tests/actionsMenu.qml @@ -0,0 +1,104 @@ +/* + * Copyright 2016 Aleix Pol Gonzalez + * Copyright 2016 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.3 as QQC2 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.ApplicationWindow +{ + id: main + + header: Kirigami.ToolBarApplicationHeader {} + + pageStack.initialPage: Kirigami.Page { + QQC2.Button { + text: "button" + onClicked: menu.popup() + QQC2.Menu { + id: menu + + QQC2.MenuItem { text: "xxx" } + QQC2.MenuItem { text: "xxx" } + QQC2.Menu { + title: "yyy" + QQC2.MenuItem { text: "yyy" } + QQC2.MenuItem { text: "yyy" } + } + } + } + + title: "aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa" + actions { + main: Kirigami.Action { icon.name: "kate"; text: "BonDia" } + left : Kirigami.Action { icon.name: "kate"; text: "BonDia" } + right: Kirigami.Action { icon.name: "kate"; text: "BonDia" } + } + + QQC2.ActionGroup { + id: group + } + + contextualActions: [ + Kirigami.Action { + text: "submenus" + icon.name: "kalgebra" + + Kirigami.Action { text: "xxx"; onTriggered: console.log("xxx") } + Kirigami.Action { text: "xxx"; onTriggered: console.log("xxx") } + Kirigami.Action { text: "xxx"; onTriggered: console.log("xxx") } + Kirigami.Action { + text: "yyy" + Kirigami.Action { text: "yyy" } + Kirigami.Action { text: "yyy" } + Kirigami.Action { text: "yyy" } + Kirigami.Action { text: "yyy" } + } + }, + Kirigami.Action { + id: optionsAction + text: "Options" + icon.name: "kate" + + Kirigami.Action { + QQC2.ActionGroup.group: group + text: "A" + checkable: true + checked: true + } + Kirigami.Action { + QQC2.ActionGroup.group: group + text: "B" + checkable: true + } + Kirigami.Action { + QQC2.ActionGroup.group: group + text: "C" + checkable: true + } + }, + Kirigami.Action { text: "stuffing..." }, + Kirigami.Action { text: "stuffing..." }, + Kirigami.Action { text: "stuffing..." }, + Kirigami.Action { text: "stuffing..." }, + Kirigami.Action { text: "stuffing..." } + ] + } +} diff --git a/tests/cardsList.qml b/tests/cardsList.qml new file mode 100644 index 0000000..188ee58 --- /dev/null +++ b/tests/cardsList.qml @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import org.kde.kirigami 2.5 as Kirigami + +Kirigami.ApplicationWindow +{ + Component { + id: delegateComponent + Kirigami.Card { + contentItem: Label { text: ourlist.prefix + index } + } + } + + pageStack.initialPage: Kirigami.ScrollablePage { + + Kirigami.CardsListView { + id: ourlist + property string prefix: "ciao " + + delegate: delegateComponent + + model: 100 + } + } +} -- 2.30.2