diff --git a/activeshellpackage/package/contents/explorer/MenuTabBar.qml b/activeshellpackage/package/contents/explorer/MenuTabBar.qml index 98fd8b87..8c8d7f76 100644 --- a/activeshellpackage/package/contents/explorer/MenuTabBar.qml +++ b/activeshellpackage/package/contents/explorer/MenuTabBar.qml @@ -1,170 +1,166 @@ /* * 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 02110-1301, USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.mobilecomponents 0.2 as MobileComponents import org.kde.baloo 0.1 as Baloo PlasmaComponents.TabBar { id: tabBar property Component startComponent: appsComponent anchors { top: saveButton.bottom topMargin: 8 horizontalCenter: parent.horizontalCenter } width: Math.min(implicitWidth, parent.width - 100) - MobileComponents.ApplicationListModel { - id: applicationsModel - } - CategoryTab { text: i18n("Applications") component: appsComponent } CategoryTab { text: i18n("Bookmarks") component: bookmarksComponent } CategoryTab { text: i18n("Contacts") component: contactsComponent } CategoryTab { text: i18n("Documents") component: documentsComponent } CategoryTab { text: i18n("Images") component: imagesComponent } CategoryTab { text: i18n("Music") component: musicComponent } CategoryTab { text: i18n("Videos") component: videoComponent } CategoryTab { text: i18n("Widgets") component: widgetsComponent } Component { id: bookmarksComponent ResourceBrowser { resourceType: "Bookmark" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Bookmark" } } } } } Component { id: contactsComponent ResourceBrowser { resourceType: "Contact" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Contact" } } } } } Component { id: documentsComponent ResourceBrowser { resourceType: "Document" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Document" } } } } } Component { id: imagesComponent ResourceBrowser { resourceType: "Image" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Image" } } } } } Component { id: musicComponent ResourceBrowser { resourceType: "Audio" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Audio" } } } } } Component { id: videoComponent ResourceBrowser { resourceType: "Video" model: PlasmaCore.SortFilterModel { sourceModel: Baloo.BalooDataModel { query { type: "Video" } } } } } Component { id: widgetsComponent CommonBrowser {} } Component { id: appsComponent CommonBrowser { isApplicationExplorer: true } } } diff --git a/activeshellpackage/package/contents/views/ApplicationList.qml b/activeshellpackage/package/contents/views/ApplicationList.qml index 701da7ff..cf60e295 100644 --- a/activeshellpackage/package/contents/views/ApplicationList.qml +++ b/activeshellpackage/package/contents/views/ApplicationList.qml @@ -1,94 +1,98 @@ /* * Copyright 2014 Antonis Tsiapaliokas * * 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) 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 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 org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.mobilecomponents 0.2 as MobileComponents Item { id: root - MobileComponents.ApplicationListModel { + PlasmaCore.DataModel { id: applicationData + dataSource: PlasmaCore.DataSource { + engine: "apps" + connectedSources: sources + } } PlasmaCore.SortFilterModel { id: filterModel sourceModel: applicationData sortRole: "ApplicationNameRole" filterRegExp: searchApplicationField.text } Column { id: col spacing: units.largeSpacing anchors { fill: parent left: parent.left right: parent.right top: parent.top } PlasmaComponents.TextField{ id: searchApplicationField width: parent.width / 12 anchors.horizontalCenter: parent.horizontalCenter } MobileComponents.IconGrid { id: applicationsList property int currentIndex: 0 onCurrentIndexChanged: { currentPage = Math.max(0, Math.floor(currentIndex/pageSize)) } height: parent.height - searchApplicationField.height width: parent.width delegateWidth: Math.floor(applicationsList.width / Math.max(Math.floor(applicationsList.width / (units.gridUnit*12)), 3)) delegateHeight: delegateWidth / 1.6 model: filterModel delegate: MouseArea { width: applicationsList.delegateWidth height: applicationsList.delegateHeight PlasmaCore.IconItem { id: applicationIcon - source: model.ApplicationIconRole + source: model.iconName width: parent.width / 1.6 height: parent.height / 1.6 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } PlasmaComponents.Label { anchors.bottom: parent.bottom - text: model.ApplicationNameRole + text: model.name anchors.horizontalCenter: parent.horizontalCenter anchors.top: applicationIcon.bottom } onClicked: { applicationsList.currentIndex = (applicationsList.currentPage * applicationsList.pageSize) + index - applicationData.runApplication(model.ApplicationStorageIdRole) + applicationData.runApplication(model.menuId) } } } } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d8485e87..0302d339 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,5 +1,5 @@ #add_subdirectory(metadatamodel) #TODO Here exists a big part of the nepomuk support, which needs to be #ported to Baloo add_subdirectory(mobilecomponents) - +add_subdirectory(mobileshellprivate) diff --git a/components/mobilecomponents/CMakeLists.txt b/components/mobilecomponents/CMakeLists.txt index aa135c92..d856cab7 100644 --- a/components/mobilecomponents/CMakeLists.txt +++ b/components/mobilecomponents/CMakeLists.txt @@ -1,18 +1,24 @@ project(mobilecomponents) set(mobilecomponents_SRCS mobilecomponentsplugin.cpp - pagedproxymodel.cpp - package.cpp - applicationlistmodel.cpp - fullscreenpanel.cpp ) add_library(mobilecomponentsplugin SHARED ${mobilecomponents_SRCS}) -target_link_libraries(mobilecomponentsplugin Qt5::Core Qt5::Widgets Qt5::Qml Qt5::Quick KF5::Declarative KF5::Plasma KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::Activities KF5::WindowSystem KF5::WaylandClient) +target_link_libraries(mobilecomponentsplugin Qt5::Core Qt5::Qml Qt5::Quick) install(TARGETS mobilecomponentsplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/mobilecomponents) -install(DIRECTORY ${PROJECT_SOURCE_DIR} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/) +install(DIRECTORY qml/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/mobilecomponents) + + +#TODO: install the plasmaless version at build time +#TODO: use the same way qquickcontrols2 uses to select if possible +FILE(GLOB platformspecific ${PROJECT_SOURCE_DIR}/plasmatheme/*) + + +install(FILES ${platformspecific} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/mobilecomponents) + +add_subdirectory(private) diff --git a/components/mobilecomponents/GlobalDrawer.qml b/components/mobilecomponents/GlobalDrawer.qml deleted file mode 100644 index 76d5038b..00000000 --- a/components/mobilecomponents/GlobalDrawer.qml +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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 1.0 -import QtQuick.Layouts 1.3 -import org.kde.plasma.components 2.0 as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.mobilecomponents 0.2 as MobileComponents - -MobileComponents.OverlayDrawer { - id: root - inverse: true - - property alias content: mainContent.data - - property alias title: heading.text - property alias titleIcon: headingIcon.source - property list actions - - drawer: ColumnLayout { - id: mainColumn - anchors.fill: parent - implicitWidth: units.gridUnit * 12 - - RowLayout { - Layout.fillWidth: true - anchors { - left: parent.left - } - PlasmaCore.IconItem { - id: headingIcon - height: parent.height - width: height - Layout.minimumWidth: height - } - PlasmaExtras.Heading { - id: heading - level: 1 - } - Item { - height: parent.height - Layout.minimumWidth: height - } - } - - PlasmaExtras.PageRow { - id: pageRow - Layout.fillWidth: true - Layout.fillHeight: true - initialPage: menuComponent - } - - ColumnLayout { - id: mainContent - Layout.fillWidth: true - Layout.fillHeight: true - } - - Component { - id: menuComponent - ListView { - id: optionMenu - - model: actions - property int level: 0 - - footer: PlasmaComponents.ListItem { - visible: level > 0 - enabled: true - RowLayout { - anchors { - left: parent.left - } - PlasmaCore.IconItem { - Layout.maximumWidth: height - Layout.fillHeight: true - source: "go-previous" - } - PlasmaComponents.Label { - text: i18n("Back") - } - } - onClicked: pageRow.pop() - } - delegate: PlasmaComponents.ListItem { - enabled: true - RowLayout { - anchors { - left: parent.left - right: parent.right - } - PlasmaCore.IconItem { - Layout.maximumWidth: height - Layout.fillHeight: true - source: modelData.iconName - } - PlasmaComponents.Label { - Layout.fillWidth: true - text: modelData.text - } - PlasmaCore.IconItem { - Layout.maximumWidth: height - Layout.fillHeight: true - source: "go-next" - visible: modelData.children != undefined - } - } - onClicked: { - if (modelData.children) { - pageRow.push(menuComponent, {"model": modelData.children, "level": level + 1}); - } else { - modelData.trigger(); - pageRow.pop(pageRow.initialPage); - } - } - } - } - } - } -} - diff --git a/components/mobilecomponents/Page.qml b/components/mobilecomponents/Page.qml deleted file mode 100644 index 001bc3e8..00000000 --- a/components/mobilecomponents/Page.qml +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.3 -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.components 2.0 as PlasmaComponents - -Item { - id: root - - /** - * type:PageStack - * The page stack that this page is owned by. - */ - property Item pageStack - - /** - * Defines the toolbar contents for the page. If the page stack is set up - * using a toolbar instance, it automatically shows the currently active - * page's toolbar contents in the toolbar. - * - * The default value is null resulting in the page's toolbar to be - * invisible when the page is active. - */ - property Item tools: null - - /** - * Defines the actions for the page: at most 4 buttons will - * contain the actions at the bottom of the page, if the main - * item of the page is a Flickable or a ScrllArea, it will - * control the visibility of the actions. - */ - property alias actions: internalActions.data - - Item { - id: internalActions - } - - RowLayout { - id: internalButtons - z:99 - anchors.horizontalCenter: parent.horizontalCenter - Layout.fillWidth: false - height: units.iconSizes.large - property Item flickable: { - if (root.children[root.children.length-1]) { - if (root.children[root.children.length-1].contentY) { - return root.children[root.children.length-1]; - } else if (root.children[root.children.length-1].flickableItem) { - return root.children[root.children.length-1].flickableItem; - } - } - return null; - } - Connections { - target: internalButtons.flickable - property real oldContentY: internalButtons.flickable.contentY - onContentYChanged: { - if (internalButtons.flickable.atYBeginning || internalButtons.flickable.atYEnd) { - return; - } - internalButtons.y = Math.max(internalButtons.flickable.height - internalButtons.height, Math.min(internalButtons.flickable.height, internalButtons.y + internalButtons.flickable.contentY - oldContentY)); - oldContentY = internalButtons.flickable.contentY; - } - } - y: parent.height - height - Repeater { - model: { - if (root.actions.length == 0) { - return null; - } else { - return root.actions[0].text !== undefined && - root.actions[0].trigger !== undefined ? - root.actions : - root.actions[0]; - } - } - delegate: PlasmaComponents.ToolButton { - Layout.fillHeight: true - flat: false - iconSource: modelData.iconName - onClicked: { - if (modelData && modelData.trigger !== undefined) { - modelData.trigger(); - // assume the model is a list of QAction or Action - } else if (toolbar.model.length > index) { - toolbar.model[index].trigger(); - } else { - console.log("Don't know how to trigger the action") - } - } - } - } - onChildrenChanged: { - var flexibleFound = false; - for (var i = 0; i < children.length; ++i) { - if (children[i].Layout.fillWidth) { - flexibleFound = true; - break; - } - } - Layout.fillWidth = flexibleFound; - } - } -} diff --git a/components/mobilecomponents/applicationlistmodel.cpp b/components/mobilecomponents/applicationlistmodel.cpp deleted file mode 100644 index aa82d5f2..00000000 --- a/components/mobilecomponents/applicationlistmodel.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2014 Antonis Tsiapaliokas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 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. - */ - -// Self -#include "applicationlistmodel.h" - -// Qt -#include -#include - -// KDE -#include -#include -#include -#include -#include -#include -#include - -ApplicationListModel::ApplicationListModel(QObject *parent) - : QAbstractListModel(parent) -{ - loadApplications(); -} - -ApplicationListModel::~ApplicationListModel() -{ -} - -QHash ApplicationListModel::roleNames() const -{ - QHash roleNames; - roleNames[ApplicationNameRole] = "ApplicationNameRole"; - roleNames[ApplicationIconRole] = "ApplicationIconRole"; - roleNames[ApplicationStorageIdRole] = "ApplicationStorageIdRole"; - roleNames[ApplicationEntryPathRole] = "ApplicationEntryPathRole"; - - return roleNames; -} - - -void ApplicationListModel::loadApplications() -{ - beginResetModel(); - - KServiceGroup::Ptr group = KServiceGroup::root(); - if (!group || !group->isValid()) return; - KServiceGroup::List subGroupList = group->entries(true); - - // Iterate over all entries in the group - for(KServiceGroup::List::ConstIterator it = subGroupList.constBegin(); it != subGroupList.constEnd(); it++) { - const KSycocaEntry::Ptr groupEntry = (*it); - - if (groupEntry->isType(KST_KServiceGroup) && groupEntry->name() != "System") { - KServiceGroup::Ptr serviceGroup(static_cast(groupEntry.data())); - - if (!serviceGroup->noDisplay()) { - KServiceGroup::List entryGroupList = serviceGroup->entries(true); - - for(KServiceGroup::List::ConstIterator it = entryGroupList.constBegin(); it != entryGroupList.constEnd(); it++) { - KSycocaEntry::Ptr entry = (*it); - ApplicationData data; - if (entry->isType(KST_KService)) { - KService::Ptr service(static_cast(entry.data())); - if (service->isApplication()) { - KPluginInfo plugin(service); - if (!plugin.isValid()) { - continue; - } - data.name = plugin.name(); - data.icon = plugin.icon(); - data.storageId = service->storageId(); - data.entryPath = plugin.entryPath(); - m_applicationList << data; - } - } - } - } - } - } - - endResetModel(); - emit countChanged(); -} - -QVariant ApplicationListModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) { - return QVariant(); - } - - switch (role) { - case Qt::DisplayRole: - case ApplicationNameRole: - return m_applicationList.at(index.row()).name; - case ApplicationIconRole: - return m_applicationList.at(index.row()).icon; - case ApplicationStorageIdRole: - return m_applicationList.at(index.row()).storageId; - case ApplicationEntryPathRole: - return m_applicationList.at(index.row()).entryPath; - - default: - return QVariant(); - } -} - -int ApplicationListModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - return 0; - } - - return m_applicationList.count(); -} - -void ApplicationListModel::runApplication(const QString &storageId) { - if (storageId.isEmpty()) { - return; - } - - KService::Ptr service = KService::serviceByStorageId(storageId); - KRun::run(*service, QList(), 0); -} - -#include "applicationlistmodel.moc" diff --git a/components/mobilecomponents/applicationlistmodel.h b/components/mobilecomponents/applicationlistmodel.h deleted file mode 100644 index e963e9ce..00000000 --- a/components/mobilecomponents/applicationlistmodel.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2014 Antonis Tsiapaliokas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 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 APPLICATIONLISTMODEL_H -#define APPLICATIONLISTMODEL_H - -// Qt -#include -#include -#include - -class QString; - -struct ApplicationData { - QString name; - QString icon; - QString storageId; - QString entryPath; -}; - -class ApplicationListModel : public QAbstractListModel { - Q_OBJECT - - Q_PROPERTY(int count READ count NOTIFY countChanged) - -public: - ApplicationListModel(QObject *parent = 0); - virtual ~ApplicationListModel(); - - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - - int count() { return m_applicationList.count(); } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; - - QHash roleNames() const Q_DECL_OVERRIDE; - - enum Roles { - ApplicationNameRole = Qt::UserRole + 1, - ApplicationIconRole = Qt::UserRole + 2, - ApplicationStorageIdRole = Qt::UserRole + 3, - ApplicationEntryPathRole = Qt::UserRole + 4 - }; - - Q_INVOKABLE void runApplication(const QString &storageId); - -Q_SIGNALS: - void countChanged(); - -private: - QList m_applicationList; - void loadApplications(); -}; - -#endif // APPLICATIONLISTMODEL_H diff --git a/components/mobilecomponents/examples/ExampleApp.qml b/components/mobilecomponents/examples/ExampleApp.qml index f710dc55..5895caf1 100644 --- a/components/mobilecomponents/examples/ExampleApp.qml +++ b/components/mobilecomponents/examples/ExampleApp.qml @@ -1,120 +1,97 @@ /* * Copycontext 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 1.4 as Controls import QtQuick.Layouts 1.3 -import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.mobilecomponents 0.2 as MobileComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.core 2.0 as PlasmaCore MobileComponents.ApplicationWindow { id: root width: 500 height: 800 - MobileComponents.GlobalDrawer { - title: "Akregator" - titleIcon: "akregator" + actionButton.onClicked: print("Action button clicked") + + globalDrawer: MobileComponents.GlobalDrawer { + title: "Widget gallery" + titleIcon: "applications-graphics" + bannerImageSource: "banner.jpg" actions: [ MobileComponents.ActionGroup { text: "View" iconName: "view-list-icons" Controls.Action { text: "action 1" } Controls.Action { text: "action 2" } Controls.Action { text: "action 3" } }, MobileComponents.ActionGroup { text: "Sync" iconName: "folder-sync" Controls.Action { text: "action 4" } Controls.Action { text: "action 5" } }, Controls.Action { text: "Settings" iconName: "configure" } ] - content: Rectangle { - Layout.minimumHeight: 200 - Layout.minimumWidth: 200 + + 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 } + } - MobileComponents.ContextDrawer { - actions: - [ - Controls.Action { - text:"Action 1" - iconName: "document-decrypt" - onTriggered: print("Action 1 clicked") - }, - Controls.Action { - text:"Action 2" - iconName: "document-share" - }] + contextDrawer: MobileComponents.ContextDrawer { + id: contextDrawer + actions: root.pageStack.currentPage ? root.pageStack.currentPage.contextualActions : null title: "Actions" } initialPage: mainPageComponent //Main app content Component { id: mainPageComponent - MobileComponents.Page { - anchors.fill:parent - actions: [ - Controls.Action { - iconName:"konqueror" - onTriggered: print("Action triggered") - }, - Controls.Action { - iconName:"go-home" - } - ] - PlasmaExtras.ScrollArea { - anchors.fill:parent - ListView { - id: mainListView - model: 30 - delegate: PlasmaComponents.ListItem { - enabled: true - PlasmaComponents.Label { - enabled: true - text: "Item " + modelData - } - onClicked: root.pageStack.push(mainPageComponent) - } - } - } - } + MainPage {} } + } diff --git a/components/mobilecomponents/examples/MainPage.qml b/components/mobilecomponents/examples/MainPage.qml new file mode 100644 index 00000000..6ac14ae5 --- /dev/null +++ b/components/mobilecomponents/examples/MainPage.qml @@ -0,0 +1,104 @@ +/* + * Copycontext 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 1.4 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 as MobileComponents + +MobileComponents.Page { + anchors.fill:parent + color: MobileComponents.Theme.viewBackgroundColor + flickable: mainListView + + contextualActions: [ + Controls.Action { + text:"Action 1" + iconName: "document-decrypt" + onTriggered: print("Action 1 clicked") + }, + Controls.Action { + text:"Action 2" + iconName: "document-share" + } + ] + + Controls.ScrollView { + anchors.fill:parent + ListView { + id: mainListView + model: ListModel { + ListElement { + text: "Button" + component: "Button" + } + ListElement { + text: "CheckBox" + component: "CheckBox" + } + ListElement { + text: "Radio Button" + component: "RadioButton" + } + ListElement { + text: "Progress Bar" + component: "ProgressBar" + } + ListElement { + text: "Slider" + component: "Slider" + } + ListElement { + text: "Switch" + component: "Switch" + } + ListElement { + text: "Text Field" + component: "TextField" + } + ListElement { + text: "Icon Grid" + component: "IconGrid" + } + } + delegate: MobileComponents.ListItemWithActions { + enabled: true + MobileComponents.Label { + enabled: true + text: model.text + } + property Item ownPage + onClicked: { + root.pageStack.pop(root.initialPage); + ownPage = root.pageStack.push(Qt.resolvedUrl("gallery/" + model.component + "Gallery.qml")); + } + checked: root.pageStack.currentPage == ownPage + actions: [ + Controls.Action { + iconName: "document-decrypt" + onTriggered: print("Action 1 clicked") + }, + Controls.Action { + iconName: "mail-reply-sender" + }] + } + } + } +} + diff --git a/components/mobilecomponents/examples/banner.jpg b/components/mobilecomponents/examples/banner.jpg new file mode 100644 index 00000000..cf089716 Binary files /dev/null and b/components/mobilecomponents/examples/banner.jpg differ diff --git a/components/mobilecomponents/examples/gallery/ButtonGallery.qml b/components/mobilecomponents/examples/gallery/ButtonGallery.qml new file mode 100644 index 00000000..ad89a687 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/ButtonGallery.qml @@ -0,0 +1,102 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 + +Page { + Layout.fillWidth: true + contextualActions: [ + Controls.Action { + text:"Action for buttons" + iconName: "bookmarks" + onTriggered: print("Action 1 clicked") + }, + Controls.Action { + text:"Action 2" + iconName: "folder" + } + ] + MouseArea { + anchors.fill: parent + onClicked: actionButton.toggleVisibility(); + } + Heading { + text: "Buttons" + anchors { + left: parent.left + top: parent.top + leftMargin: Units.smallSpacing + } + } + ColumnLayout { + anchors.centerIn: parent + spacing: Units.smallSpacing + + Controls.Button { + text: "Button" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: print("clicked") + } + Controls.Button { + text: "Disabled Button" + enabled: false + anchors.horizontalCenter: parent.horizontalCenter + onClicked: print("clicked") + } + Controls.ToolButton { + text: "Tool Button" + anchors.horizontalCenter: parent.horizontalCenter + onClicked: print("clicked") + } + Controls.ToolButton { + text: "Tool Button non flat" + property bool flat: false + anchors.horizontalCenter: parent.horizontalCenter + onClicked: print("clicked") + } + Controls.ToolButton { + iconName: "go-previous" + property bool flat: false + anchors.horizontalCenter: parent.horizontalCenter + onClicked: print("clicked") + } + Row { + spacing: 0 + anchors.horizontalCenter: parent.horizontalCenter + Controls.ToolButton { + iconName: "edit-cut" + property bool flat: false + onClicked: print("clicked") + } + Controls.ToolButton { + iconName: "edit-copy" + property bool flat: false + onClicked: print("clicked") + } + Controls.ToolButton { + iconName: "edit-paste" + property bool flat: false + onClicked: print("clicked") + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/CheckBoxGallery.qml b/components/mobilecomponents/examples/gallery/CheckBoxGallery.qml new file mode 100644 index 00000000..28b0ed97 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/CheckBoxGallery.qml @@ -0,0 +1,153 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 +//FIXME +import org.kde.plasma.core 2.0 as PlasmaCore + +Page { + id: page + contextualActions: [ + Controls.Action { + text:"Action for checkbox page" + onTriggered: print("Action 1 clicked") + }, + Controls.Action { + text:"Action 2" + } + ] + Layout.fillWidth: true + flickable: scrollView.flickableItem + Controls.ScrollView { + id: scrollView + anchors.fill: parent + + ColumnLayout { + width: page.width + Heading { + text: "Checkboxes" + anchors { + left: parent.left + leftMargin: Units.smallSpacing + } + } + Item { + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.CheckBox { + text: "On" + checked: true + } + Controls.CheckBox { + text: "On" + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.CheckBox { + text: "Off" + checked: false + } + Controls.CheckBox { + text: "Off" + checked: false + enabled: false + } + } + } + //FIXME: possible to have this in mobileComponents? + PlasmaCore.ColorScope { + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + Rectangle { + anchors.fill: parent + color: PlasmaCore.ColorScope.backgroundColor + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.CheckBox { + text: "On" + checked: true + } + Controls.CheckBox { + text: "On" + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.CheckBox { + text: "Off" + checked: false + } + Controls.CheckBox { + text: "Off" + checked: false + enabled: false + } + } + } + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/IconGridGallery.qml b/components/mobilecomponents/examples/gallery/IconGridGallery.qml new file mode 100644 index 00000000..b29c7b23 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/IconGridGallery.qml @@ -0,0 +1,82 @@ +/* + * Copycontext 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.3 +import org.kde.plasma.mobilecomponents 0.2 +import org.kde.plasma.core 2.0 as PlasmaCore + +Page { + Layout.fillWidth: true + + Heading { + id: heading + text: "Icon Grid" + anchors { + left: parent.left + top: parent.top + leftMargin: Units.smallSpacing + } + } + IconGrid { + id: grid + anchors { + left: parent.left + right: parent.right + top: heading.bottom + bottom: parent.bottom + } + + model: PlasmaCore.DataModel { + dataSource: PlasmaCore.DataSource { + engine: "apps" + connectedSources: sources + } + } + delegate: Item { + width: grid.delegateWidth + height: grid.delegateHeight + Item { + anchors { + fill: parent + margins: units.gridUnit + } + Icon { + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + } + width: Units.iconSizes.huge + height: width + source: model.iconName + } + Label { + text: model.name + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + anchors { + left: parent.left + right: parent.right + top: parent.bottom + } + } + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/ProgressBarGallery.qml b/components/mobilecomponents/examples/gallery/ProgressBarGallery.qml new file mode 100644 index 00000000..40a329e4 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/ProgressBarGallery.qml @@ -0,0 +1,114 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 + +Page { + Layout.fillWidth: true + Timer { + id: timer + property int value: 0 + interval: 80 + repeat: true + running: true + onTriggered: { + value = (value + 1) % 100 + } + } + Heading { + text: "Progress Indicators" + anchors { + left: parent.left + top: parent.top + leftMargin: Units.smallSpacing + } + } + GridLayout { + anchors.centerIn: parent + rowSpacing: Units.largeSpacing + columns: 2 + width: parent.width - units.gridUnit*2 + + Label { + text: "Determinate:" + Layout.alignment: Qt.AlignRight + } + Controls.ProgressBar { + minimumValue: 0 + maximumValue: 100 + value: timer.value + Layout.maximumWidth: units.gridUnit * 10 + } + Label { + text: "Indeterminate:" + Layout.alignment: Qt.AlignRight + } + Controls.ProgressBar { + minimumValue: 0 + maximumValue: 100 + indeterminate: true + Layout.maximumWidth: units.gridUnit * 10 + } + Label { + text: "Busy indicator:" + Layout.alignment: Qt.AlignRight + } + Controls.BusyIndicator { + + } + Label { + text: "Inactive indicator:" + Layout.alignment: Qt.AlignRight + } + Controls.BusyIndicator { + running: false + } + Label { + text: "Custom size:" + Layout.alignment: Qt.AlignRight + } + Controls.BusyIndicator { + Layout.minimumWidth: Units.iconSizes.enormous + Layout.minimumHeight: width + } + Label { + text: "Vertical:" + Layout.alignment: Qt.AlignRight + } + RowLayout { + Controls.ProgressBar { + Layout.minimumWidth: Units.gridUnit * 2 + Layout.maximumHeight: Units.gridUnit * 8 + minimumValue: 0 + maximumValue: 100 + value: timer.value + orientation: Qt.Vertical + } + Controls.ProgressBar { + Layout.minimumWidth: Units.gridUnit * 2 + Layout.maximumHeight: Units.gridUnit * 8 + indeterminate: true + orientation: Qt.Vertical + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/RadioButtonGallery.qml b/components/mobilecomponents/examples/gallery/RadioButtonGallery.qml new file mode 100644 index 00000000..25e60dc0 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/RadioButtonGallery.qml @@ -0,0 +1,144 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 +//FIXME +import org.kde.plasma.core 2.0 as PlasmaCore + +Page { + id: page + Layout.fillWidth: true + flickable: scrollView.flickableItem + Controls.ScrollView { + id: scrollView + anchors.fill: parent + + ColumnLayout { + width: page.width + Heading { + text: "Radio buttons" + anchors { + left: parent.left + leftMargin: Units.smallSpacing + } + } + Item { + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.RadioButton { + text: "On" + checked: true + } + Controls.RadioButton { + text: "On" + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.RadioButton { + text: "Off" + checked: false + } + Controls.RadioButton { + text: "Off" + checked: false + enabled: false + } + } + } + //FIXME: possible to have this in mobileComponents? + PlasmaCore.ColorScope { + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + Rectangle { + anchors.fill: parent + color: PlasmaCore.ColorScope.backgroundColor + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.RadioButton { + text: "On" + checked: true + } + Controls.RadioButton { + text: "On" + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.RadioButton { + text: "Off" + checked: false + } + Controls.RadioButton { + text: "Off" + checked: false + enabled: false + } + } + } + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/SliderGallery.qml b/components/mobilecomponents/examples/gallery/SliderGallery.qml new file mode 100644 index 00000000..65a7e504 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/SliderGallery.qml @@ -0,0 +1,160 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 +//FIXME +import org.kde.plasma.core 2.0 as PlasmaCore + +Page { + id: page + Layout.fillWidth: true + flickable: scrollView.flickableItem + + Controls.ScrollView { + id: scrollView + anchors.fill: parent + + ColumnLayout { + width: page.width + Heading { + text: "Sliders" + anchors { + left: parent.left + leftMargin: Units.smallSpacing + } + } + Item { + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 20 + ColumnLayout { + anchors.centerIn: parent + spacing: Units.smallSpacing + + Label { + text: "Normal:" + } + Controls.Slider { + Layout.minimumWidth: units.gridUnit * 20 + value: 2 + maximumValue: 5.0 + } + Label { + text: "Disabled:" + } + Controls.Slider { + enabled: false + Layout.minimumWidth: units.gridUnit * 20 + value: 2 + maximumValue: 5.0 + } + Label { + text: "Thickmarks:" + } + Controls.Slider { + Layout.minimumWidth: units.gridUnit * 20 + tickmarksEnabled: true + maximumValue: 5.0 + stepSize: 1.0 + value: 3 + } + Label { + text: "Vertical:" + } + RowLayout { + Layout.alignment: Qt.AlignHCenter + Controls.Slider { + Layout.minimumWidth: 2 + Layout.minimumHeight: units.gridUnit * 10 + value: 2 + maximumValue: 5.0 + orientation: Qt.Vertical + } + Controls.Slider { + Layout.minimumWidth: 2 + Layout.minimumHeight: units.gridUnit * 10 + value: 3 + tickmarksEnabled: true + maximumValue: 5.0 + stepSize: 1.0 + orientation: Qt.Vertical + } + } + } + } + //FIXME: possible to have this in mobileComponents? + PlasmaCore.ColorScope { + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 20 + Rectangle { + anchors.fill: parent + color: PlasmaCore.ColorScope.backgroundColor + ColumnLayout { + anchors.centerIn: parent + spacing: Units.smallSpacing + + Label { + text: "Normal:" + } + Controls.Slider { + Layout.minimumWidth: units.gridUnit * 20 + value: 2 + maximumValue: 5.0 + } + Label { + text: "Thickmarks:" + } + Controls.Slider { + Layout.minimumWidth: units.gridUnit * 20 + tickmarksEnabled: true + maximumValue: 5.0 + stepSize: 1.0 + value: 3 + } + Label { + text: "Vertical:" + } + RowLayout { + Layout.alignment: Qt.AlignHCenter + Controls.Slider { + Layout.minimumWidth: 2 + Layout.minimumHeight: units.gridUnit * 10 + value: 2 + maximumValue: 5.0 + orientation: Qt.Vertical + } + Controls.Slider { + Layout.minimumWidth: 2 + Layout.minimumHeight: units.gridUnit * 10 + value: 3 + tickmarksEnabled: true + maximumValue: 5.0 + stepSize: 1.0 + orientation: Qt.Vertical + } + } + } + } + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/SwitchGallery.qml b/components/mobilecomponents/examples/gallery/SwitchGallery.qml new file mode 100644 index 00000000..935379c0 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/SwitchGallery.qml @@ -0,0 +1,136 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 +//FIXME +import org.kde.plasma.core 2.0 as PlasmaCore + +Page { + id: page + Layout.fillWidth: true + flickable: scrollView.flickableItem + Controls.ScrollView { + id: scrollView + anchors.fill: parent + + ColumnLayout { + width: page.width + Heading { + text: "Switches" + anchors { + left: parent.left + leftMargin: Units.smallSpacing + } + } + Item { + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.Switch { + checked: true + } + Controls.Switch { + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.Switch { + checked: false + } + Controls.Switch { + checked: false + enabled: false + } + } + } + //FIXME: possible to have this in mobileComponents? + PlasmaCore.ColorScope { + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + Layout.fillWidth: true + Layout.minimumHeight: units.gridUnit * 10 + Rectangle { + anchors.fill: parent + color: PlasmaCore.ColorScope.backgroundColor + GridLayout { + anchors.centerIn: parent + columns: 3 + rows: 3 + rowSpacing: Units.smallSpacing + + Item { + width: 1 + height: 1 + } + Label { + text: "Normal" + } + Label { + text: "Disabled" + enabled: false + } + Label { + text: "On" + } + Controls.Switch { + checked: true + } + Controls.Switch { + checked: true + enabled: false + } + Label { + text: "Off" + } + Controls.Switch { + checked: false + } + Controls.Switch { + checked: false + enabled: false + } + } + } + } + } + } +} diff --git a/components/mobilecomponents/examples/gallery/TextFieldGallery.qml b/components/mobilecomponents/examples/gallery/TextFieldGallery.qml new file mode 100644 index 00000000..05c991a5 --- /dev/null +++ b/components/mobilecomponents/examples/gallery/TextFieldGallery.qml @@ -0,0 +1,68 @@ +/* + * Copycontext 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 1.2 as Controls +import QtQuick.Layouts 1.3 +import org.kde.plasma.mobilecomponents 0.2 + +Page { + Layout.fillWidth: true + Heading { + text: "Text fields" + anchors { + left: parent.left + top: parent.top + leftMargin: Units.smallSpacing + } + } + ColumnLayout { + anchors.centerIn: parent + spacing: Units.smallSpacing + + Label { + text: "Placeholder text:" + } + Controls.TextField { + placeholderText: "Search..." + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "Disabled field:" + } + Controls.TextField { + text: "Disabled" + enabled: false + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "Password:" + } + Controls.TextField { + echoMode: TextInput.Password + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "Text area:" + } + Controls.TextArea { + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu nisl ac nibh malesuada pretium ut sit amet libero. Nulla libero arcu, pharetra a dignissim nec, iaculis sit amet metus. Suspendisse quis justo efficitur, pharetra dui maximus, aliquam dolor. Vestibulum vel imperdiet turpis. Mauris ut leo mauris. Praesent ut libero sollicitudin, tincidunt nisi a, efficitur erat. Curabitur lacinia leo et tempor aliquam." + } + } +} diff --git a/components/mobilecomponents/ActionGroup.qml b/components/mobilecomponents/fallbacktheme/Icon.qml similarity index 50% copy from components/mobilecomponents/ActionGroup.qml copy to components/mobilecomponents/fallbacktheme/Icon.qml index ba057f58..b28624db 100644 --- a/components/mobilecomponents/ActionGroup.qml +++ b/components/mobilecomponents/fallbacktheme/Icon.qml @@ -1,27 +1,43 @@ /* - * Copycontext 2015 Marco Martin + * 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 + * 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 1.3 +import QtQuick 2.0 +import QtGraphicalEffects 1.0 +import org.kde.plasma.mobilecomponents 0.2 -Action { +Item { id: root - default property alias children: root.__children - property list __children + property string source + property alias smooth: image.smooth + property bool active: false + property bool valid: image.status == Image.Ready + implicitWidth: Math.min(image.sourceSize.width, Units.iconSizes.medium) + implicitHeight: Math.min(image.sourceSize.height, Units.iconSizes.medium) + + Image { + id: image + anchors.fill: parent + source: root.source != "" ? (root.source.indexOf(".") === -1 ? "icons/" + root.source + ".svg" : root.source) : root.source + } + GammaAdjust { + anchors.fill: image + source: image + gamma: root.active ? 3.0 : 1 + } } diff --git a/components/mobilecomponents/fallbacktheme/Theme.qml b/components/mobilecomponents/fallbacktheme/Theme.qml new file mode 100644 index 00000000..402caedb --- /dev/null +++ b/components/mobilecomponents/fallbacktheme/Theme.qml @@ -0,0 +1,62 @@ +/* + * 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 + +/*! + \qmltype Theme + \inqmlmodule Material 0.1 + + \brief Provides access to standard colors that follow the Material Design specification. + + See \l {http://www.google.com/design/spec/style/color.html#color-ui-color-application} for + details about choosing a color scheme for your application. + */ +QtObject { + id: theme + + property color textColor: Qt.rgba(0,0,0, 0.54) + + property color highlightColor: "#2196F3" + property color backgroundColor: "#eff0f1" + property color linkColor: "#2196F3" + property color visitedLinkColor: "#2196F3" + + property color buttonTextColor: Qt.rgba(0,0,0, 0.54) + property color buttonBackgroundColor: "#eff0f1" + property color buttonHoverColor: "#2196F3" + property color buttonFocusColor: "#2196F3" + + property color viewTextColor: Qt.rgba(0,0,0, 0.54) + property color viewBackgroundColor: "#fcfcfc" + property color viewHoverColor: "#2196F3" + property color viewFocusColor: "#2196F3" + + property color complementaryTextColor: "#f3f3f3" + property color complementaryBackgroundColor: Qt.rgba(0,0,0, 0.54) + property color complementaryHoverColor: "#2196F3" + property color complementaryFocusColor: "#2196F3" + + property font defaultFont: fontMetrics.font + + property variant fontMetrics: TextMetrics {} + +} diff --git a/components/mobilecomponents/fallbacktheme/Units.qml b/components/mobilecomponents/fallbacktheme/Units.qml new file mode 100644 index 00000000..8b5032a7 --- /dev/null +++ b/components/mobilecomponents/fallbacktheme/Units.qml @@ -0,0 +1,101 @@ +/* + * 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: 16 * devicePixelRatio + property int smallMedium: 22 * devicePixelRatio + property int medium: 32 * devicePixelRatio + property int large: 48 * devicePixelRatio + property int huge: 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: 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: gridUnit + + /** + * 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: fontMetrics.height / 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 variant fontMetrics: TextMetrics { + text: "M" + } +} diff --git a/components/mobilecomponents/fallbacktheme/qmldir b/components/mobilecomponents/fallbacktheme/qmldir new file mode 100644 index 00000000..5e796368 --- /dev/null +++ b/components/mobilecomponents/fallbacktheme/qmldir @@ -0,0 +1,2 @@ +singleton Units Units.qml +singleton Theme Theme.qml diff --git a/components/mobilecomponents/mobilecomponentsplugin.cpp b/components/mobilecomponents/mobilecomponentsplugin.cpp index ffb6ee83..74185604 100644 --- a/components/mobilecomponents/mobilecomponentsplugin.cpp +++ b/components/mobilecomponents/mobilecomponentsplugin.cpp @@ -1,57 +1,40 @@ /* * 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 "mobilecomponentsplugin.h" #include #include #include -#include +#include -#include "pagedproxymodel.h" -#include "package.h" -#include "applicationlistmodel.h" -#include "fullscreenpanel.h" - -void MobileComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQmlExtensionPlugin::initializeEngine(engine, uri); - - if (!engine->rootContext()->contextObject()) { - KDeclarative::KDeclarative kdeclarative; - kdeclarative.setDeclarativeEngine(engine); - kdeclarative.setupBindings(); - } -} void MobileComponentsPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.plasma.mobilecomponents")); - qmlRegisterType(uri, 0, 2, "PagedProxyModel"); - qmlRegisterType(uri, 0, 2, "ApplicationListModel"); - qmlRegisterType(uri, 0, 2, "Package"); - qmlRegisterType(uri, 0, 2, "FullScreenPanel"); + //TODO: in this plugin it will end up something similar to + //PlasmaCore's ColorScope } #include "mobilecomponentsplugin.moc" diff --git a/components/mobilecomponents/mobilecomponentsplugin.h b/components/mobilecomponents/mobilecomponentsplugin.h index 5fcc2776..debdf8b2 100644 --- a/components/mobilecomponents/mobilecomponentsplugin.h +++ b/components/mobilecomponents/mobilecomponentsplugin.h @@ -1,39 +1,38 @@ /* * 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 MOBILECOMPONENTSPLUGIN_H #define MOBILECOMPONENTSPLUGIN_H #include #include class MobileComponentsPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: - void initializeEngine(QQmlEngine *engine, const char *uri); void registerTypes(const char *uri); }; #endif diff --git a/components/mobilecomponents/package.cpp b/components/mobilecomponents/package.cpp deleted file mode 100644 index 3e4846a2..00000000 --- a/components/mobilecomponents/package.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************************** - * Copyright 2011 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 of the License, 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 "package.h" - -#include - -#include -#include -#include -#include -#include - -Package::Package(QObject *parent) - : QObject(parent) -{ -} - -Package::~Package() -{ -} - - -QString Package::name() const -{ - return m_name; -} - -void Package::setName(const QString &name) -{ - if (m_name == name) { - return; - } - - m_name = name; - - m_package = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/Generic")); - m_package.setPath(name); - QString domain = QStringLiteral("plasma_package_") + name; - KLocalizedString::setApplicationDomain(domain.toLocal8Bit().data()); - - emit nameChanged(name); - emit visibleNameChanged(); -} - -QString Package::visibleName() const -{ - if (!m_package.isValid()) { - return QString(); - } - - return m_package.metadata().name(); -} - -QString Package::filePath(const QString &fileType, const QString &fileName) const -{ - if (!m_package.isValid()) { - return QString(); - } - - if (fileName.isEmpty()) { - return m_package.filePath(fileType.toLatin1()); - } else { - return m_package.filePath(fileType.toLatin1(), fileName); - } -} - -QString Package::filePath(const QString &fileType) const -{ - if (!m_package.isValid()) { - return QString(); - } - - return m_package.filePath(fileType.toLatin1()); -} - -#include "package.moc" - diff --git a/components/mobilecomponents/package.h b/components/mobilecomponents/package.h deleted file mode 100644 index 5534b09f..00000000 --- a/components/mobilecomponents/package.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright 2011 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 of the License, 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 PACKAGE_H -#define PACKAGE_H - -#include -#include -#include - -namespace Plasma { - class Package; -} - - -class QTimer; -class QGraphicsView; - -class Package : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(QString visibleName READ visibleName NOTIFY visibleNameChanged) - -public: - Package(QObject *parent = 0); - ~Package(); - - QString name() const; - void setName(const QString &name); - - Q_INVOKABLE QString filePath(const QString &fileType, const QString &filename) const; - Q_INVOKABLE QString filePath(const QString &fileType) const; - - QString visibleName() const; - -Q_SIGNALS: - void nameChanged(const QString &); - void visibleNameChanged(); - -private: - QString m_name; - Plasma::Package m_package; -}; - -#endif diff --git a/components/mobilecomponents/ActionGroup.qml b/components/mobilecomponents/plasmatheme/Icon.qml similarity index 77% copy from components/mobilecomponents/ActionGroup.qml copy to components/mobilecomponents/plasmatheme/Icon.qml index ba057f58..ee32aab3 100644 --- a/components/mobilecomponents/ActionGroup.qml +++ b/components/mobilecomponents/plasmatheme/Icon.qml @@ -1,27 +1,24 @@ /* - * Copycontext 2015 Marco Martin + * 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 + * 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 1.3 +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore -Action { - id: root - default property alias children: root.__children - property list __children -} + +PlasmaCore.IconItem {} diff --git a/components/mobilecomponents/plasmatheme/Theme.qml b/components/mobilecomponents/plasmatheme/Theme.qml new file mode 100644 index 00000000..c61d5200 --- /dev/null +++ b/components/mobilecomponents/plasmatheme/Theme.qml @@ -0,0 +1,58 @@ +/* + * 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. + */ + +pragma Singleton + +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +/*! + \qmltype Theme + \inqmlmodule Material 0.1 + + \brief Provides access to standard colors that follow the Material Design specification. + + See \l {http://www.google.com/design/spec/style/color.html#color-ui-color-application} for + details about choosing a color scheme for your application. + */ +QtObject { + + property color textColor: theme.textColor + property color highlightColor: theme.highlightColor + property color backgroundColor: theme.backgroundColor + property color linkColor: theme.linkColor + property color visitedLinkColor: theme.visitedLinkColor + + property color buttonTextColor: theme.buttonTextColor + property color buttonBackgroundColor: theme.buttonBackgroundColor + property color buttonHoverColor: theme.buttonHoverColor + property color buttonFocusColor: theme.buttonFocusColor + + property color viewTextColor: theme.viewTextColor + property color viewBackgroundColor: theme.viewBackgroundColor + property color viewHoverColor: theme.viewHoverColor + property color viewFocusColor: theme.viewFocusColor + + property color complementaryTextColor: theme.complementaryTextColor + property color complementaryBackgroundColor: theme.complementaryBackgroundColor + property color complementaryHoverColor: theme.complementaryHoverColor + property color complementaryFocusColor: theme.complementaryFocusColor + + property variant defaultFont: theme.defaultFont +} diff --git a/components/mobilecomponents/plasmatheme/Units.qml b/components/mobilecomponents/plasmatheme/Units.qml new file mode 100644 index 00000000..f8d0066b --- /dev/null +++ b/components/mobilecomponents/plasmatheme/Units.qml @@ -0,0 +1,95 @@ +/* + * 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. + */ + +pragma Singleton + +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + + +QtObject { + /** + * 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: units.gridUnit + + /** + * 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: units.iconSizes.small + property int smallMedium: units.iconSizes.smallMedium + property int medium: units.iconSizes.medium + property int large: units.iconSizes.large + property int huge: units.iconSizes.huge + property int enormous: units.iconSizes.enormous + } + + /** + * 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: units.smallSpacing + + /** + * 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: units.largeSpacing + + /** + * 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: units.devicePixelRatio + + /** + * 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: units.longDuration + + /** + * units.shortDuration should be used for short animations, such as accentuating a UI event, + * hover events, etc.. + */ + property int shortDuration: units.shortDuration +} diff --git a/components/mobilecomponents/private/CMakeLists.txt b/components/mobilecomponents/private/CMakeLists.txt new file mode 100644 index 00000000..b7771dd9 --- /dev/null +++ b/components/mobilecomponents/private/CMakeLists.txt @@ -0,0 +1,15 @@ + +set(mobilecomponentsprivate_SRCS + mobilecomponentsprivateplugin.cpp + pagedproxymodel.cpp + ) + +add_library(mobilecomponentsprivateplugin SHARED ${mobilecomponentsprivate_SRCS}) +target_link_libraries(mobilecomponentsprivateplugin Qt5::Core Qt5::Qml Qt5::Quick) + +install(TARGETS mobilecomponentsprivateplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/mobilecomponents/private) + + +install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/mobilecomponents/private/) + + diff --git a/components/mobilecomponents/mobilecomponentsplugin.h b/components/mobilecomponents/private/mobilecomponentsprivateplugin.cpp similarity index 68% copy from components/mobilecomponents/mobilecomponentsplugin.h copy to components/mobilecomponents/private/mobilecomponentsprivateplugin.cpp index 5fcc2776..79dcb281 100644 --- a/components/mobilecomponents/mobilecomponentsplugin.h +++ b/components/mobilecomponents/private/mobilecomponentsprivateplugin.cpp @@ -1,39 +1,40 @@ /* * Copyright 2009 by Alan Alpert * Copyright 2010 by Ménard Alexis - * Copyright 2010 by Marco Martin + * Copyright 2015 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 MOBILECOMPONENTSPLUGIN_H -#define MOBILECOMPONENTSPLUGIN_H +#include "mobilecomponentsprivateplugin.h" -#include #include +#include +#include +#include +#include "pagedproxymodel.h" -class MobileComponentsPlugin : public QQmlExtensionPlugin + +void MobileComponentsPrivatePlugin::registerTypes(const char *uri) { - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_ASSERT(uri == QLatin1String("org.kde.plasma.mobilecomponents.private")); + + qmlRegisterType(uri, 0, 2, "PagedProxyModel"); +} -public: - void initializeEngine(QQmlEngine *engine, const char *uri); - void registerTypes(const char *uri); -}; +#include "mobilecomponentsprivateplugin.moc" -#endif diff --git a/components/mobilecomponents/mobilecomponentsplugin.h b/components/mobilecomponents/private/mobilecomponentsprivateplugin.h similarity index 81% copy from components/mobilecomponents/mobilecomponentsplugin.h copy to components/mobilecomponents/private/mobilecomponentsprivateplugin.h index 5fcc2776..68565128 100644 --- a/components/mobilecomponents/mobilecomponentsplugin.h +++ b/components/mobilecomponents/private/mobilecomponentsprivateplugin.h @@ -1,39 +1,38 @@ /* * Copyright 2009 by Alan Alpert * Copyright 2010 by Ménard Alexis - * Copyright 2010 by Marco Martin + * Copyright 2015 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 MOBILECOMPONENTSPLUGIN_H -#define MOBILECOMPONENTSPLUGIN_H +#ifndef MOBILECOMPONENTSPRIVATEPLUGIN_H +#define MOBILECOMPONENTSPRIVATEPLUGIN_H #include #include -class MobileComponentsPlugin : public QQmlExtensionPlugin +class MobileComponentsPrivatePlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: - void initializeEngine(QQmlEngine *engine, const char *uri); void registerTypes(const char *uri); }; #endif diff --git a/components/mobilecomponents/pagedproxymodel.cpp b/components/mobilecomponents/private/pagedproxymodel.cpp similarity index 100% rename from components/mobilecomponents/pagedproxymodel.cpp rename to components/mobilecomponents/private/pagedproxymodel.cpp diff --git a/components/mobilecomponents/pagedproxymodel.h b/components/mobilecomponents/private/pagedproxymodel.h similarity index 100% rename from components/mobilecomponents/pagedproxymodel.h rename to components/mobilecomponents/private/pagedproxymodel.h diff --git a/components/mobilecomponents/private/qmldir b/components/mobilecomponents/private/qmldir new file mode 100644 index 00000000..83c06056 --- /dev/null +++ b/components/mobilecomponents/private/qmldir @@ -0,0 +1,3 @@ +module org.kde.plasma.mobilecomponents.private +plugin mobilecomponentsprivateplugin + diff --git a/components/mobilecomponents/ActionGroup.qml b/components/mobilecomponents/qml/ActionGroup.qml similarity index 100% copy from components/mobilecomponents/ActionGroup.qml copy to components/mobilecomponents/qml/ActionGroup.qml diff --git a/components/mobilecomponents/ApplicationWindow.qml b/components/mobilecomponents/qml/ApplicationWindow.qml similarity index 59% rename from components/mobilecomponents/ApplicationWindow.qml rename to components/mobilecomponents/qml/ApplicationWindow.qml index 67509dbb..c282b7c2 100644 --- a/components/mobilecomponents/ApplicationWindow.qml +++ b/components/mobilecomponents/qml/ApplicationWindow.qml @@ -1,57 +1,90 @@ /* * Copycontext 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 1.3 -import org.kde.plasma.components 2.0 as PlasmaComponents +import "private" import org.kde.plasma.mobilecomponents 0.2 -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.extras 2.0 as PlasmaExtras /** * 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. */ ApplicationWindow { id: root /** * The first page that will be loaded when the application starts */ property alias initialPage: __pageStack.initialPage /** - * The stack used to allocate the pages nd to manage the transitions + * 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'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 - PlasmaExtras.PageRow { + PageRow { id: __pageStack anchors.fill: parent + focus: true + Keys.onReleased: { + if (event.key == Qt.Key_Back && stackView.depth > 1) { + stackView.pop(); + event.accepted = true; + } + } + onLastVisiblePageChanged: { + if (lastVisiblePage != null) { + pop(lastVisiblePage) + } + } } + property AbstractDrawer globalDrawer + property AbstractDrawer contextDrawer + + onGlobalDrawerChanged: { + globalDrawer.parent = contentItem.parent; + } + onContextDrawerChanged: { + contextDrawer.parent = contentItem.parent; + } + + width: Units.gridUnit * 25 + height: Units.gridUnit * 30 + + property alias actionButton: __actionButton + ActionButton { + id: __actionButton + z: 9999 + anchors.bottom: parent.bottom + x: parent.width/2 - width/2 + iconSource: "distribute-horizontal-x" + + visible: root.globalDrawer || root.contextDrawer + } } diff --git a/components/mobilecomponents/ContextDrawer.qml b/components/mobilecomponents/qml/ContextDrawer.qml similarity index 78% rename from components/mobilecomponents/ContextDrawer.qml rename to components/mobilecomponents/qml/ContextDrawer.qml index 9488ebda..08325494 100644 --- a/components/mobilecomponents/ContextDrawer.qml +++ b/components/mobilecomponents/qml/ContextDrawer.qml @@ -1,97 +1,95 @@ /* * 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 1.0 as QtControls -import org.kde.plasma.components 2.0 as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.mobilecomponents 0.2 as MobileComponents +import org.kde.plasma.mobilecomponents 0.2 -MobileComponents.OverlayDrawer { +OverlayDrawer { id: root property string title //This can be any type of object that a ListView can accept as model. It expects items compatible with either QAction or QQC Action - property alias actions: internalActions.data - - Item { - id: internalActions - } - - drawer: QtControls.ScrollView { + property var actions + enabled: menu.count > 0 + edge: Qt.RightEdge + contentItem: QtControls.ScrollView { ListView { id: menu model: { if (root.actions.length == 0) { return null; } else { return root.actions[0].text !== undefined && root.actions[0].trigger !== undefined ? root.actions : root.actions[0]; } } - header: Item { + verticalLayoutDirection: ListView.BottomToTop + //in bottomtotop all is flipped + footer: Item { height: heading.height - PlasmaExtras.Heading { + width: menu.width + Heading { id: heading anchors { left: parent.left right: parent.right - margins: units.largeSpacing + margins: Units.largeSpacing } elide: Text.ElideRight level: 2 text: root.title } } - delegate: PlasmaComponents.ListItem { + delegate: ListItem { enabled: true - Row { + RowLayout { + height: implicitHeight + Units.smallSpacing * 2 anchors { left: parent.left - margins: units.largeSpacing + margins: Units.largeSpacing } - PlasmaCore.IconItem { + Icon { height: parent.height width: height source: modelData.iconName } - PlasmaComponents.Label { + Label { text: model ? model.text : modelData.text } } onClicked: { 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/components/mobilecomponents/qml/GlobalDrawer.qml b/components/mobilecomponents/qml/GlobalDrawer.qml new file mode 100644 index 00000000..14b38e03 --- /dev/null +++ b/components/mobilecomponents/qml/GlobalDrawer.qml @@ -0,0 +1,206 @@ +/* + * 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 1.0 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import org.kde.plasma.mobilecomponents 0.2 + +OverlayDrawer { + id: root + edge: Qt.LeftEdge + + default property alias content: mainContent.data + + property alias title: heading.text + property alias titleIcon: headingIcon.source + property alias bannerImageSource: bannerImage.source + property list actions + + contentItem: ColumnLayout { + id: mainColumn + anchors.fill: parent + spacing: 0 + implicitWidth: Units.gridUnit * 12 + + Image { + id: bannerImage + Layout.fillWidth: true + + Layout.preferredWidth: title.implicitWidth + Layout.preferredHeight: bannerImageSource != "" ? Math.max(title.implicitHeight, Math.floor(width / (sourceSize.width/sourceSize.height))) : title.implicitHeight + Layout.minimumHeight: Math.max(headingIcon.height, heading.height) + Units.smallSpacing * 2 + + fillMode: Image.PreserveAspectCrop + asynchronous: true + + anchors { + left: parent.left + right: parent.right + top: parent.top + } + + LinearGradient { + anchors { + left: parent.left + right: parent.right + top: parent.top + } + visible: bannerImageSource != "" + height: title.height * 1.3 + start: Qt.point(0, 0) + end: Qt.point(0, height) + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.rgba(0, 0, 0, 0.8) + } + GradientStop { + position: 1.0 + color: "transparent" + } + } + } + + RowLayout { + id: title + anchors { + left: parent.left + top: parent.top + margins: Units.smallSpacing * 2 + } + Icon { + id: headingIcon + Layout.minimumWidth: Units.iconSizes.large + Layout.minimumHeight: width + } + Heading { + id: heading + level: 1 + color: bannerImageSource != "" ? "white" : Theme.textColor + } + Item { + height: 1 + Layout.minimumWidth: heading.height + } + } + } + + Rectangle { + color: Theme.textColor + opacity: 0.2 + Layout.fillWidth: true + Layout.minimumHeight: 1 + } + + StackView { + id: pageRow + Layout.fillWidth: true + Layout.fillHeight: true + initialItem: menuComponent + } + + ColumnLayout { + id: mainContent + Layout.alignment: Qt.AlignHCenter + Layout.minimumWidth: parent.width - Units.smallSpacing*2 + Layout.maximumWidth: Layout.minimumWidth + Layout.fillWidth: false + Layout.fillHeight: true + visible: children.length > 0 + } + Item { + Layout.minimumWidth: Units.smallSpacing + Layout.minimumHeight: Units.smallSpacing + } + + Component { + id: menuComponent + ListView { + id: optionMenu + clip: true + + model: actions + property int level: 0 + + interactive: contentHeight > height + + footer: ListItem { + visible: level > 0 + enabled: true + RowLayout { + height: implicitHeight + Units.smallSpacing * 2 + anchors { + left: parent.left + } + Icon { + Layout.minimumWidth: height + Layout.maximumWidth: Layout.minimumWidth + Layout.fillHeight: true + source: "go-previous" + } + Label { + // Weird, this doesn't work + //text: (typeof(i18n) != undefined) ? i18n("Back") : "Back" + text: "Back" + } + } + onClicked: pageRow.pop() + } + delegate: ListItem { + enabled: true + RowLayout { + height: implicitHeight + Units.smallSpacing * 2 + anchors { + left: parent.left + right: parent.right + } + Icon { + Layout.maximumWidth: height + Layout.fillHeight: true + source: modelData.iconName + } + Label { + Layout.fillWidth: true + text: modelData.text + } + Icon { + Layout.minimumWidth: height + Layout.maximumWidth: Layout.minimumWidth + Layout.fillHeight: true + source: "go-next" + visible: modelData.children != undefined + } + } + onClicked: { + if (modelData.children) { + pageRow.push(menuComponent, {"model": modelData.children, "level": level + 1}); + } else { + modelData.trigger(); + pageRow.pop(pageRow.initialPage); + root.opened = false; + } + } + } + } + } + } +} + diff --git a/components/mobilecomponents/qml/Heading.qml b/components/mobilecomponents/qml/Heading.qml new file mode 100644 index 00000000..db69645e --- /dev/null +++ b/components/mobilecomponents/qml/Heading.qml @@ -0,0 +1,74 @@ +/* +* 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 org.kde.plasma.mobilecomponents 0.2 + +/** + * 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.plasma.mobilecomponents 0.2 as MobileComponents + * [...] + * Column { + * MobileComponents.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. + */ +Label { + id: heading + + /** + * The level determines how big the section header is display, values + * between 1 (big) and 5 (small) are accepted + */ + property int level: 1 + + property int step: 2 + + height: Math.round(paintedHeight * 1.2) + font.pointSize: headerPointSize(level) + font.weight: Font.Light + wrapMode: Text.WordWrap + opacity: 0.8 + + function headerPointSize(l) { + var n = Theme.defaultFont.pointSize; + var s; + if (l > 4) { + s = n + } else if (l < 2) { + s = n + (5*step) + } else { + s = n + ((5-level)*2) + } + return s; + } +} diff --git a/components/mobilecomponents/IconGrid.qml b/components/mobilecomponents/qml/IconGrid.qml similarity index 81% rename from components/mobilecomponents/IconGrid.qml rename to components/mobilecomponents/qml/IconGrid.qml index ff2cae91..1a6acbc1 100644 --- a/components/mobilecomponents/IconGrid.qml +++ b/components/mobilecomponents/qml/IconGrid.qml @@ -1,238 +1,238 @@ /* Copyright 2010 Marco Martin 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; see the file COPYING.LIB. 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.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.mobilecomponents 0.2 as MobileComponents +import org.kde.plasma.mobilecomponents 0.2 +import org.kde.plasma.mobilecomponents.private 0.2 Item { id: main property Component delegate property QtObject model - property int pageSize: Math.floor(iconView.width/main.delegateWidth)*Math.floor(iconView.height/main.delegateHeight) - property int delegateWidth: theme.mSize(theme.defaultFont).width * 15 - property int delegateHeight: theme.mSize(theme.defaultFont).width + units.iconSizes.medium + 8 + property int pageSize: Math.floor(iconView.width / main.delegateWidth) * Math.floor(iconView.height / main.delegateHeight) + property int delegateWidth: Units.iconSizes.huge + Units.gridUnit * 2 + property int delegateHeight: Units.iconSizes.huge + Units.gridUnit * 2 property alias currentPage: iconView.currentIndex - property int pagesCount: Math.ceil(model.count/pageSize) + property int pagesCount: Math.ceil(model.count / pageSize) property int count: model.count property alias contentX: iconView.contentX clip: true function positionViewAtIndex(index) { iconView.positionViewAtIndex(index / pageSize, ListView.Beginning) } Timer { id: resizeTimer running: true interval: 100 onTriggered: { - main.pageSize = Math.floor(iconView.width/main.delegateWidth)*Math.floor(iconView.height/main.delegateHeight) + main.pageSize = Math.floor(iconView.width / main.delegateWidth) * Math.floor(iconView.height / main.delegateHeight) if (iconView.currentItem) { iconView.currentItem.width = iconView.width iconView.currentItem.height = iconView.height } } } ListView { id: iconView objectName: "iconView" pressDelay: 200 - cacheBuffer: 100 - highlightMoveDuration: 250 + cacheBuffer: Units.gridUnit * 8 + highlightMoveDuration: Units.shortDuration anchors.fill: parent onWidthChanged: resizeTimer.restart() onHeightChanged: resizeTimer.restart() model: main.model ? Math.ceil(main.model.count/main.pageSize) : 0 highlightRangeMode: ListView.StrictlyEnforceRange orientation: ListView.Horizontal snapMode: ListView.SnapOneItem boundsBehavior: Flickable.DragOverBounds signal clicked(string url) delegate: Component { Item { id: delegatePage //Explicitly *not* bind the properties for performance reasons Component.onCompleted: { width = iconView.width height = iconView.height //iconView.cacheBuffer = iconView.width } Flow { id: iconFlow width: iconRepeater.suggestedWidth anchors { horizontalCenter: parent.horizontalCenter top: parent.top bottom: parent.bottom } property int orientation: ListView.Horizontal - MobileComponents.PagedProxyModel { + PagedProxyModel { id: pagedProxyModel sourceModel: main.model - currentPage: index + currentPage: model.index pageSize: main.pageSize } Repeater { id: iconRepeater model: pagedProxyModel - property int columns: Math.min(count, Math.floor(delegatePage.width/main.delegateWidth)) - property int suggestedWidth: main.delegateWidth*columns + property int columns: Math.min(count, Math.floor(delegatePage.width / main.delegateWidth)) + property int suggestedWidth: main.delegateWidth * columns //property int suggestedHeight: main.delegateHeight*Math.floor(count/columns) delegate: main.delegate } } } } } Loader { id: scrollArea visible: main.model && Math.ceil(main.model.count/main.pageSize) > 1 anchors { left: parent.left right: parent.right bottom: parent.bottom } - height: Math.max( 16, iconView.height - Math.floor(iconView.height/delegateHeight)*delegateHeight) + height: Math.max(16, iconView.height - Math.floor(iconView.height / delegateHeight) * delegateHeight) property int pageCount: main.model ? Math.ceil(main.model.count/main.pageSize) : 0 sourceComponent: pageCount > 1 ? ((pageCount * 20 > width) ? scrollDotComponent : dotsRow) : undefined function setViewIndex(index) { //animate only if near if (Math.abs(iconView.currentIndex - index) > 1) { iconView.positionViewAtIndex(index, ListView.Beginning) } else { iconView.currentIndex = index } } Component { id: scrollDotComponent MouseArea { anchors.fill: parent property int pendingIndex: 0 Rectangle { id: barRectangle - color: theme.textColor - opacity: 2.05 + color: Theme.textColor height: 4 radius: 2 anchors { left: parent.left right: parent.right verticalCenter: parent.verticalCenter - leftMargin: (parent.width/pageCount/2) - rightMargin: (parent.width/pageCount/2) + leftMargin: (parent.width / pageCount / 2) + rightMargin: (parent.width / pageCount / 2) } } Rectangle { - color: theme.textColor + color: Theme.textColor height: 8 width: height radius: 4 anchors.verticalCenter: parent.verticalCenter - x: parent.width/(pageCount/(iconView.currentIndex+1)) - (parent.width/pageCount/2) - 4 + x: parent.width / (pageCount / (iconView.currentIndex+1)) - (parent.width / pageCount / 2) - 4 Behavior on x { NumberAnimation { - duration: 250 + duration: Units.shortDuration easing.type: Easing.InOutQuad } } } function setViewIndexFromMouse(x) { pendingIndex = Math.min(pageCount, Math.round(pageCount / (barRectangle.width / Math.max(x - barRectangle.x, 1)))) viewPositionTimer.restart() } onPressed: setViewIndexFromMouse(mouse.x) onPositionChanged: setViewIndexFromMouse(mouse.x) Timer { id: viewPositionTimer interval: 200 onTriggered: setViewIndex(pendingIndex) } } } Component { id: dotsRow Item { Row { anchors.centerIn: parent - spacing: 20 + spacing: units.gridUnit Repeater { model: scrollArea.pageCount Rectangle { width: 6 height: 6 scale: iconView.currentIndex == index ? 1.5 : 1 radius: 5 smooth: true opacity: iconView.currentIndex == index ? 0.8: 0.4 - color: theme.textColor + color: Theme.textColor Behavior on scale { NumberAnimation { - duration: 250 + duration: units.shortDuration easing.type: Easing.InOutQuad } } Behavior on opacity { NumberAnimation { - duration: 250 + duration: units.shortDuration easing.type: Easing.InOutQuad } } MouseArea { anchors { fill: parent - margins: -10 + margins: Units.gridUnit / 2 } onClicked: { setViewIndex(index) } } } } } } } } } diff --git a/components/mobilecomponents/qml/Label.qml b/components/mobilecomponents/qml/Label.qml new file mode 100644 index 00000000..bf27078b --- /dev/null +++ b/components/mobilecomponents/qml/Label.qml @@ -0,0 +1,59 @@ +/* +* 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 org.kde.plasma.mobilecomponents 0.2 + +/** + * This is a label which uses the plasma Theme. + * + * The characteristics of the text will be automatically set according to the + * plasma 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.Text + */ +Text { + id: root + + height: Math.round(Math.max(paintedHeight, Units.gridUnit * 1.6)) + verticalAlignment: lineCount > 1 ? Text.AlignTop : Text.AlignVCenter + + activeFocusOnTab: false + renderType: Text.NativeRendering + + font.capitalization: Theme.defaultFont.capitalization + font.family: Theme.defaultFont.family + font.italic: Theme.defaultFont.italic + font.letterSpacing: Theme.defaultFont.letterSpacing + font.pointSize: Theme.defaultFont.pointSize + font.strikeout: Theme.defaultFont.strikeout + font.underline: Theme.defaultFont.underline + font.weight: Theme.defaultFont.weight + font.wordSpacing: Theme.defaultFont.wordSpacing + color: Theme.textColor + + opacity: enabled? 1 : 0.6 + + Accessible.role: Accessible.StaticText + Accessible.name: text +} diff --git a/components/mobilecomponents/qml/ListItem.qml b/components/mobilecomponents/qml/ListItem.qml new file mode 100644 index 00000000..042ba2cb --- /dev/null +++ b/components/mobilecomponents/qml/ListItem.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 org.kde.plasma.mobilecomponents 0.2 + +/** + * An item delegate for the primitive ListView component. + * + * It's intended to make all listviews look coherent. + * + * @inherit QtQuick.Item + */ +Item { + id: listItem + default property alias content: paddingItem.data + + /** + * type:bool Holds if the item emits signals related to mouse interaction. + * + * The default value is false. + */ + property alias enabled: itemMouse.enabled + //item has been clicked or pressed+hold + + /** + * This signal is emitted when there is a click. + * + * This is disabled by default, set enabled to true to use it. + * @see enabled + */ + signal clicked + + + /** + * The user pressed the item with the mouse and didn't release it for a + * certain amount of time. + * + * This is disabled by default, set enabled to true to use it. + * @see enabled + */ + signal pressAndHold + + /** + * If true makes the list item look as checked or pressed. It has to be set + * from the code, it won't change by itself. + */ + //plasma extension + //always look pressed? + property bool checked: false + + /** + * If true the item will be a delegate for a section, so will look like a + * "title" for the otems under it. + */ + //is this to be used as section delegate? + property bool sectionDelegate: false + + /** + * True if the list item contains mouse + */ + property alias containsMouse: itemMouse.containsMouse + + width: parent ? parent.width : childrenRect.width + height: paddingItem.childrenRect.height + Units.smallSpacing*2 + + property int implicitHeight: paddingItem.childrenRect.height + Units.smallSpacing*2 + + + MouseArea { + id: itemMouse + property bool changeBackgroundOnPress: !listItem.checked && !listItem.sectionDelegate + anchors.fill: parent + enabled: false + hoverEnabled: true + + onClicked: listItem.clicked() + onPressAndHold: listItem.pressAndHold() + + Rectangle { + id : background + color: listItem.checked || (itemMouse.pressed && itemMouse.changeBackgroundOnPress) ? Theme.highlightColor : Theme.viewBackgroundColor + + anchors.fill: parent + visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true + opacity: itemMouse.containsMouse && !itemMouse.pressed ? 0.5 : 1 + Behavior on color { + ColorAnimation { duration: Units.longDuration } + } + Behavior on opacity { NumberAnimation { duration: Units.longDuration } } + } + Item { + id: paddingItem + anchors { + fill: parent + margins: Units.smallSpacing + } + } + } + + Rectangle { + color: Theme.textColor + opacity: 0.2 + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + height: 1 + } + + Accessible.role: Accessible.ListItem +} diff --git a/components/mobilecomponents/qml/ListItemWithActions.qml b/components/mobilecomponents/qml/ListItemWithActions.qml new file mode 100644 index 00000000..43c62d40 --- /dev/null +++ b/components/mobilecomponents/qml/ListItemWithActions.qml @@ -0,0 +1,275 @@ +/* + * 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 1.0 +import org.kde.plasma.mobilecomponents 0.2 +import QtGraphicalEffects 1.0 + +/** + * An item delegate for the primitive ListView component. + * + * It's intended to make all listviews look coherent. + * + * @inherit QtQuick.Item + */ +Item { + id: listItem + default property alias content: paddingItem.data + + /** + * type:bool Holds if the item emits signals related to mouse interaction. + * + * The default value is false. + */ + property alias enabled: itemMouse.enabled + //item has been clicked or pressed+hold + + /** + * This signal is emitted when there is a click. + * + * This is disabled by default, set enabled to true to use it. + * @see enabled + */ + signal clicked + + /** + * The user pressed the item with the mouse and didn't release it for a + * certain amount of time. + * + * This is disabled by default, set enabled to true to use it. + * @see enabled + */ + signal pressAndHold + + /** + * If true makes the list item look as checked or pressed. It has to be set + * from the code, it won't change by itself. + */ + //plasma extension + //always look pressed? + property bool checked: false + + /** + * If true the item will be a delegate for a section, so will look like a + * "title" for the otems under it. + */ + //is this to be used as section delegate? + property bool sectionDelegate: false + + /** + * True if the list item contains mouse + */ + property alias containsMouse: itemMouse.containsMouse + + /** + * Defines the actions for the page: at most 4 buttons will + * contain the actions at the bottom of the page, if the main + * item of the page is a Flickable or a ScrllArea, it will + * control the visibility of the actions. + */ + property alias actions: internalActions.data + + Item { + id: internalActions + } + + width: parent ? parent.width : childrenRect.width + height: paddingItem.childrenRect.height + Units.smallSpacing * 2 + + property int implicitHeight: paddingItem.childrenRect.height + Units.smallSpacing * 2 + + + Rectangle { + id : background + color: Theme.backgroundColor + + width: parent.width + height: parent.height + MouseArea { + anchors.fill: parent + onClicked: itemMouse.x = 0; + } + RowLayout { + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: y + } + height: Math.min( parent.height / 1.5, Units.iconSizes.medium) + property bool exclusive: false + property Item checkedButton + spacing: 0 + 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: ToolButton { + Layout.fillHeight: true + Layout.minimumWidth: height + iconName: modelData.iconName + property bool flat: false + onClicked: { + if (modelData && modelData.trigger !== undefined) { + modelData.trigger(); + // assume the model is a list of QAction or Action + } else if (toolbar.model.length > index) { + toolbar.model[index].trigger(); + } else { + console.log("Don't know how to trigger the action") + } + itemMouse.x = 0; + } + } + } + } + } + InnerShadow { + anchors.fill: parent + radius: Units.smallSpacing * 2 + samples: 16 + horizontalOffset: 0 + verticalOffset: Units.smallSpacing / 2 + color: Qt.rgba(0, 0, 0, 0.3) + source: background + } + LinearGradient { + id: shadow + //TODO: depends from app layout + property bool inverse: true + width: Units.smallSpacing * 2 + anchors { + right: shadow.inverse ? undefined : itemMouse.left + left: shadow.inverse ? itemMouse.right : undefined + top: itemMouse.top + bottom: itemMouse.bottom + rightMargin: -1 + } + start: Qt.point(0, 0) + end: Qt.point(Units.smallSpacing*2, 0) + gradient: Gradient { + GradientStop { + position: 0.0 + color: shadow.inverse ? Qt.rgba(0, 0, 0, 0.3) : "transparent" + } + GradientStop { + position: shadow.inverse ? 0.3 : 0.7 + color: Qt.rgba(0, 0, 0, 0.15) + } + GradientStop { + position: 1.0 + color: shadow.inverse ? "transparent" : Qt.rgba(0, 0, 0, 0.3) + } + } + } + + MouseArea { + id: itemMouse + property bool changeBackgroundOnPress: !listItem.checked && !listItem.sectionDelegate + width: parent.width + height: parent.height + enabled: false + hoverEnabled: true + + onClicked: listItem.clicked() + onPressAndHold: listItem.pressAndHold() + + Behavior on x { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + + Rectangle { + id : item + color: listItem.checked || (itemMouse.pressed && itemMouse.changeBackgroundOnPress) ? Theme.highlightColor : Theme.viewBackgroundColor + anchors.fill: parent + + visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true + Behavior on color { + ColorAnimation { duration: Units.longDuration } + } + + Item { + id: paddingItem + anchors { + fill: parent + margins: Units.smallSpacing + } + } + + MouseArea { + width: Units.iconSizes.smallMedium + height: width + preventStealing: true + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: y + } + drag { + target: itemMouse + axis: Drag.XAxis + maximumX: 0 + } + onReleased: { + if (itemMouse.x > -itemMouse.width/2) { + itemMouse.x = 0; + } else { + itemMouse.x = -itemMouse.width + width * 2 + } + } + onClicked: { + if (itemMouse.x < -itemMouse.width/2) { + itemMouse.x = 0; + } else { + itemMouse.x = -itemMouse.width + width * 2 + } + } + Icon { + anchors.fill: parent + source: "application-menu" + } + } + } + } + + + Rectangle { + color: Theme.textColor + opacity: 0.2 + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + height: 1 + } + + Accessible.role: Accessible.ListItem +} diff --git a/components/mobilecomponents/OverlayDrawer.qml b/components/mobilecomponents/qml/OverlayDrawer.qml similarity index 68% rename from components/mobilecomponents/OverlayDrawer.qml rename to components/mobilecomponents/qml/OverlayDrawer.qml index c38f78cd..c6e9d4b3 100644 --- a/components/mobilecomponents/OverlayDrawer.qml +++ b/components/mobilecomponents/qml/OverlayDrawer.qml @@ -1,296 +1,323 @@ /* * 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 QtGraphicalEffects 1.0 -import org.kde.plasma.components 2.0 as PlasmaComponents -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.kquickcontrolsaddons 2.0 - +import org.kde.plasma.mobilecomponents 0.2 +import "private" /**Documented API -Inherits: - Page from org.kde.plasmacomponents Imports: - org.kde.plasma.core - org.kde.plasma.components - QtQuick 1.1 + QtQuick 2.1 Description: - 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. + 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. Properties: - bool open: - If true the drawer is open showing the contents of the "drawer" component. + bool opened: + If true the drawer is open showing the contents of the "drawer" + component. Item page: - It's the default property. it's the main content of the drawer page, the part that is always shown + It's the default property. it's the main content of the drawer page, + the part that is always shown - Item drawer: + Item contentItem: It's the part that can be pulled in and out, will act as a sidebar. **/ -Item { +AbstractDrawer { id: root anchors.fill: parent z: 9999 default property alias page: mainPage.data - property alias drawer: drawerPage.data - property alias open: browserFrame.open - property bool inverse: false + property Item contentItem + property alias opened: browserFrame.open + property int edge: Qt.LeftEdge + property real position: 0 + + onContentItemChanged: contentItem.parent = drawerPage + onPositionChanged: { + if (!enabled) { + return; + } + if (root.edge == Qt.LeftEdge) { + browserFrame.x = -browserFrame.width + position * browserFrame.width; + } else { + browserFrame.x = root.width - (position * browserFrame.width); + } + } + function open () { + mouseEventListener.startBrowserFrameX = browserFrame.x; + browserFrame.state = "Dragging"; + browserFrame.state = "Open"; + } + function close () { + mouseEventListener.startBrowserFrameX = browserFrame.x; + browserFrame.state = "Dragging"; + browserFrame.state = "Closed"; + } Item { id: mainPage anchors.fill: parent onChildrenChanged: mainPage.children[0].anchors.fill = mainPage } Rectangle { anchors.fill: parent color: "black" - opacity: 0.6 * (root.inverse + opacity: 0.6 * (root.edge == Qt.LeftEdge ? ((browserFrame.x + browserFrame.width) / browserFrame.width) : (1 - browserFrame.x / root.width)) } MouseArea { anchors { - right: root.inverse ? undefined : parent.right - left: root.inverse ? parent.left : undefined + right: root.edge == Qt.LeftEdge ? undefined : parent.right + left: root.edge == Qt.LeftEdge ? parent.left : undefined top: parent.top bottom: parent.bottom } z: 99 - width: units.smallSpacing + width: Units.smallSpacing onPressed: mouseEventListener.managePressed(mouse) onPositionChanged: mouseEventListener.positionChanged(mouse) onReleased: mouseEventListener.released(mouse) } MouseArea { id: mouseEventListener anchors.fill: parent drag.filterChildren: true property int startBrowserFrameX property int startMouseX property real oldMouseX property bool startDragging: false property string startState enabled: browserFrame.state != "Closed" onPressed: managePressed(mouse) function managePressed(mouse) { if (drawerPage.children.length == 0) { mouse.accepted = false; return; } mouse.accepted = true; startBrowserFrameX = browserFrame.x; oldMouseX = startMouseX = mouse.x; startDragging = false; startState = browserFrame.state; browserFrame.state = "Dragging"; browserFrame.x = startBrowserFrameX; } onPositionChanged: { if (drawerPage.children.length == 0) { mouse.accepted = false; return; } - if (mouse.x < units.gridUnit || + if (mouse.x < Units.gridUnit || Math.abs(mouse.x - startMouseX) > root.width / 5) { startDragging = true; } if (startDragging) { - browserFrame.x = root.inverse + browserFrame.x = root.edge == Qt.LeftEdge ? Math.min(0, browserFrame.x + mouse.x - oldMouseX) : Math.max(root.width - browserFrame.width, browserFrame.x + mouse.x - oldMouseX); } oldMouseX = mouse.x; } onReleased: { if (drawerPage.children.length == 0) { mouse.accepted = false; return; } - if (root.inverse) { - if (mouse.x < units.gridUnit) { + if (root.edge == Qt.LeftEdge) { + if (mouse.x < Units.gridUnit) { browserFrame.state = "Closed"; } else if (browserFrame.x - startBrowserFrameX > browserFrame.width / 3) { browserFrame.state = "Open"; } else if (startBrowserFrameX - browserFrame.x > browserFrame.width / 3) { browserFrame.state = "Closed"; } else { browserFrame.state = startState } } else { - if (mouse.x > width - units.gridUnit) { + if (mouse.x > width - Units.gridUnit) { browserFrame.state = "Closed"; } else if (browserFrame.x - startBrowserFrameX > browserFrame.width / 3) { browserFrame.state = "Closed"; } else if (startBrowserFrameX - browserFrame.x > browserFrame.width / 3) { browserFrame.state = "Open"; } else { browserFrame.state = startState; } } } onCanceled: { - if (oldMouseX > width - units.gridUnit) { + if (oldMouseX > width - Units.gridUnit) { browserFrame.state = "Closed"; } else if (Math.abs(browserFrame.x - startBrowserFrameX) > browserFrame.width / 3) { browserFrame.state = startState == "Open" ? "Closed" : "Open"; } else { browserFrame.state = "Open"; } } onClicked: { - if (Math.abs(startMouseX - mouse.x) > units.gridUnit) { + if (Math.abs(startMouseX - mouse.x) > Units.gridUnit) { return; } - if ((root.inverse && mouse.x > browserFrame.width) || - (!root.inverse && mouse.x < browserFrame.x)) { + if ((root.edge == Qt.LeftEdge && mouse.x > browserFrame.width) || + (root.edge != Qt.LeftEdge && mouse.x < browserFrame.x)) { browserFrame.state = startState == "Open" ? "Closed" : "Open"; + root.clicked(); } } Rectangle { id: browserFrame z: 100 - color: PlasmaCore.ColorScope.backgroundColor + color: Theme.viewBackgroundColor anchors { top: parent.top bottom: parent.bottom } width: { if (drawerPage.children.length > 0 && drawerPage.children[0].implicitWidth > 0) { - return Math.min( parent.width - units.gridUnit, drawerPage.children[0].implicitWidth) + return Math.min( parent.width - Units.gridUnit, drawerPage.children[0].implicitWidth) } else { - return parent.width - units.gridUnit * 3 + return parent.width - Units.gridUnit * 3 } } + onXChanged: { + root.position = root.edge == Qt.LeftEdge ? 1 + browserFrame.x/browserFrame.width : (root.width - browserFrame.x)/browserFrame.width; + } + state: "Closed" onStateChanged: open = (state != "Closed") property bool open: false onOpenChanged: { - if (drawerPage.children.length == 0) { + if (browserFrame.state == "Dragging" || drawerPage.children.length == 0) { return; } if (open) { browserFrame.state = "Open"; } else { browserFrame.state = "Closed"; } } LinearGradient { - width: units.gridUnit/2 + width: Units.gridUnit/2 anchors { - right: root.inverse ? undefined : parent.left - left: root.inverse ? parent.right : undefined + right: root.edge == Qt.LeftEdge ? undefined : parent.left + left: root.edge == Qt.LeftEdge ? parent.right : undefined top: parent.top bottom: parent.bottom - rightMargin: -1 } - opacity: browserFrame.state == "Closed" ? 0 : 1 + opacity: root.position == 0 ? 0 : 1 start: Qt.point(0, 0) - end: Qt.point(units.gridUnit/2, 0) + end: Qt.point(Units.gridUnit/2, 0) gradient: Gradient { GradientStop { position: 0.0 - color: root.inverse ? Qt.rgba(0, 0, 0, 0.3) : "transparent" + color: root.edge == Qt.LeftEdge ? Qt.rgba(0, 0, 0, 0.3) : "transparent" } GradientStop { - position: root.inverse ? 0.3 : 0.7 + position: root.edge == Qt.LeftEdge ? 0.3 : 0.7 color: Qt.rgba(0, 0, 0, 0.15) } GradientStop { position: 1.0 - color: root.inverse ? "transparent" : Qt.rgba(0, 0, 0, 0.3) + color: root.edge == Qt.LeftEdge ? "transparent" : Qt.rgba(0, 0, 0, 0.3) } } Behavior on opacity { NumberAnimation { - duration: units.longDuration + duration: Units.longDuration easing.type: Easing.InOutQuad } } } MouseArea { id: drawerPage anchors { fill: parent - //leftMargin: units.gridUnit + //leftMargin: Units.gridUnit } clip: true onChildrenChanged: drawerPage.children[0].anchors.fill = drawerPage } states: [ State { name: "Open" PropertyChanges { target: browserFrame - x: root.inverse ? 0 : root.width - browserFrame.width + x: root.edge == Qt.LeftEdge ? 0 : root.width - browserFrame.width } - }, State { name: "Dragging" //workaround for a quirkiness of the state machine //if no x binding gets defined in this state x will be set to whatever last x it had last time it was in this state PropertyChanges { target: browserFrame x: mouseEventListener.startBrowserFrameX } }, State { name: "Closed" PropertyChanges { target: browserFrame - x: root.inverse ? -browserFrame.width : root.width + x: root.edge == Qt.LeftEdge ? -browserFrame.width : root.width } } ] transitions: [ Transition { //Exclude Dragging - to: "Open,Closed,Hidden" + to: "Open,Closed" NumberAnimation { + id: transitionAnim properties: "x" - duration: units.longDuration + duration: Units.longDuration easing.type: Easing.InOutQuad } } ] } } } diff --git a/components/mobilecomponents/qml/Page.qml b/components/mobilecomponents/qml/Page.qml new file mode 100644 index 00000000..784ce803 --- /dev/null +++ b/components/mobilecomponents/qml/Page.qml @@ -0,0 +1,67 @@ +/* + * 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.plasma.mobilecomponents 0.2 +import "private" + +Rectangle { + id: root + + /** + * type:PageStack + * The page stack that this page is owned by. + */ + property Item pageStack + + /** + * Defines the toolbar contents for the page. If the page stack is set up + * using a toolbar instance, it automatically shows the currently active + * page's toolbar contents in the toolbar. + * + * The default value is null resulting in the page's toolbar to be + * invisible when the page is active. + */ + property Item tools: null + + /** + * Defines the contextual actions for the page: + * an easy way to assign actions in the right sliding panel + */ + property alias contextualActions: internalContextualActions.data + + property Flickable flickable + Item { + id: internalContextualActions + } + + Layout.fillWidth: true + color: "transparent" + + Connections { + target: flickable + property real oldContentY: flickable.contentY + onContentYChanged: { + actionButton.transform[0].y = Math.min(actionButton.height, Math.max(0, actionButton.transform[0].y + (flickable.contentY - oldContentY))); + + oldContentY = flickable.contentY; + } + } +} diff --git a/components/mobilecomponents/qml/PageRow.qml b/components/mobilecomponents/qml/PageRow.qml new file mode 100644 index 00000000..995bf86d --- /dev/null +++ b/components/mobilecomponents/qml/PageRow.qml @@ -0,0 +1,508 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Marco Martin +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.2 +import org.kde.plasma.mobilecomponents 0.2 + +import "private/PageStack.js" as Engine + +Item { + id: actualRoot + + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 + + + property int depth: Engine.getDepth() + property Item currentPage: null + property Item lastVisiblePage + property ToolBar toolBar + property variant initialPage + //A column is wide enough for 30 characters + property int columnWidth: Math.round(parent.width/(Units.gridUnit*30)) > 0 ? parent.width/Math.round(parent.width/(Units.gridUnit*30)) : width + property alias clip: scrollArea.clip + + // Indicates whether there is an ongoing page transition. + property bool busy: internal.ongoingTransitionCount > 0 + + // 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. + // + // 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. + // + // The properties argument is optional and allows defining a map of properties to set on the page. + // If the immediate argument is true then no transition animation is performed. + // Returns the page instance. + function push(page, properties, immediate) + { + scrollAnimation.running = false; + var item = Engine.push(page, properties, false, immediate) + scrollToLevel(depth) + return item + } + + // Pops a page off the stack. + // If page is specified then the stack is unwound to that page, to unwind to the first page specify + // page as null. If the immediate argument is true then no transition animation is performed. + // Returns the page instance that was popped off the stack. + function pop(page, immediate) + { + scrollToLevel(depth-1); + return Engine.pop(page, immediate); + } + + // Replaces a page on the stack. + // See push() for details. + function replace(page, properties, immediate) + { + scrollAnimation.running = false; + var item = Engine.push(page, properties, true, immediate); + scrollToLevel(depth) + return item + } + + // Clears the page stack. + function clear() + { + return Engine.clear(); + } + + // Iterates through all pages (top to bottom) and invokes the specified function. + // If the specified function returns true the search stops and the find function + // returns the page that the iteration stopped at. If the search doesn't result + // in any page being found then null is returned. + function find(func) + { + return Engine.find(func); + } + + // Scroll the view to have the page of the given level as first item + function scrollToLevel(level) + { + if (level < 0 || level > depth || root.width < width) { + return + } + + var firstLevel = Math.max(0, level - mainFlickable.width/columnWidth + 1); + scrollAnimation.to = Math.max(0, Math.min(Math.max(0, columnWidth * (firstLevel - 1)), mainFlickable.contentWidth)); + scrollAnimation.running = true; + } + + SequentialAnimation { + id: scrollAnimation + property alias to: actualScrollAnimation.to + NumberAnimation { + id: actualScrollAnimation + target: mainFlickable + properties: "contentX" + duration: internal.transitionDuration + easing.type: Easing.InOutQuad + } + ScriptAction { + script: { + //At startup sometimes the contentX is NaN for an instant + if (isNaN(mainFlickable.contentX)) { + return; + } + + actualRoot.lastVisiblePage = root.children[Math.floor((mainFlickable.contentX + mainFlickable.width - 1)/columnWidth)].page + } + } + } + + // Called when the page stack visibility changes. + onVisibleChanged: { + if (currentPage) { + if (visible) + currentPage.visible = currentPage.parent.visible = true; + } + } + + onInitialPageChanged: { + if (!internal.completed) { + return + } + + if (initialPage) { + if (depth == 0) { + push(initialPage, null, true) + } else if (depth == 1) { + replace(initialPage, null, true) + } else { + console.log("Cannot update PageStack.initialPage") + } + } + } + + onWidthChanged: { + var firstLevel = Math.max(0, depth - mainFlickable.width/columnWidth + 1); + mainFlickable.contentX = Math.max(0, Math.min(Math.max(0, columnWidth * (firstLevel - 1)), mainFlickable.contentWidth)); + } + Component.onCompleted: { + internal.completed = true + if (initialPage && depth == 0) + push(initialPage, null, true) + } + + QtObject { + id: internal + + // The number of ongoing transitions. + property int ongoingTransitionCount: 0 + + //FIXME: there should be a way to access to theh without storing it in an ugly way + property bool completed: false + + // Duration of transition animation (in ms) + property int transitionDuration: Units.longDuration + } + + ScrollView { + id: scrollArea + anchors.fill: parent + Flickable { + id: mainFlickable + anchors.fill: parent + interactive: root.width > width + boundsBehavior: Flickable.StopAtBounds + contentWidth: root.width + contentHeight: height + Row { + id: root + spacing: -Units.gridUnit * 8 + width: Math.max((depth-1+children[children.length-1].takenColumns) * columnWidth, childrenRect.width - Units.gridUnit * 8) + + height: parent.height + Behavior on width { + NumberAnimation { + duration: internal.transitionDuration + easing.type: Easing.InOutQuad + } + } + } + onMovementEnded: { + scrollToLevel(Math.round(contentX/columnWidth)+1) + } + onFlickEnded: { + movementEnded(); + } + } + } + + // Component for page containers. + Component { + id: containerComponent + + Item { + id: container + + implicitWidth: actualContainer.width + Units.gridUnit * 8 + width: implicitWidth + height: parent ? parent.height : 0 + + x: 0 + + // The actual parent of page: page will anchor to that + property Item pageParent: actualContainer + + property int pageDepth: 0 + Component.onCompleted: { + pageDepth = Engine.getDepth() + 1 + container.z = -Engine.getDepth() + } + + // The states correspond to the different possible positions of the container. + state: "Hidden" + + // The page held by this container. + property Item page: null + + // The owner of the page. + property Item owner: null + + // The width of the longer stack dimension + property int stackWidth: Math.max(actualRoot.width, actualRoot.height) + + + // Flag that indicates the container should be cleaned up after the transition has ended. + property bool cleanupAfterTransition: false + + // Flag that indicates if page transition animation is running + property bool transitionAnimationRunning: false + + // State to be set after previous state change animation has finished + property string pendingState: "none" + + //how many columns take the page? + property alias takenColumns: actualContainer.takenColumns + + // Ensures that transition finish actions are executed + // in case the object is destroyed before reaching the + // end state of an ongoing transition + Component.onDestruction: { + if (transitionAnimationRunning) + transitionEnded(); + } + + Item { + id: actualContainer + + anchors { + top: parent.top + bottom: parent.bottom + right: parent.right + rightMargin: Units.gridUnit * 8 + } + + property int takenColumns: { + if (container.page && container.page.Layout && container.page.Layout.fillWidth) { + return Math.max(1, Math.round(actualRoot.width/columnWidth)-(container.x > 0 ? 1: 0)); + } else { + return Math.max(1, Math.round(container.page ? container.page.implicitWidth/columnWidth : 1)); + } + } + + width: (container.pageDepth >= actualRoot.depth ? Math.min(actualRoot.width, takenColumns*columnWidth) : columnWidth) + } + + Rectangle { + anchors { + top: parent.top + bottom: parent.bottom + right: actualContainer.right + } + width: 1 + color: Theme.textColor + opacity: 0.3 + visible: container.pageDepth < actualRoot.depth + } + + // Sets pending state as current if state change is delayed + onTransitionAnimationRunningChanged: { + if (!transitionAnimationRunning && pendingState != "none") { + state = pendingState; + pendingState = "none"; + } + } + + // Handles state change depening on transition animation status + function setState(newState) + { + if (transitionAnimationRunning) + pendingState = newState; + else + state = newState; + } + + // Performs a push enter transition. + function pushEnter(immediate, orientationChanges) + { + if (!immediate) { + setState("Right"); + } + setState(""); + page.visible = true; + } + + // Performs a push exit transition. + function pushExit(replace, immediate, orientationChanges) + { + if (replace) { + setState(immediate ? "Hidden" : "Left"); + } + + if (replace) { + if (immediate) + cleanup(); + else + cleanupAfterTransition = true; + } + } + + // Performs a pop enter transition. + function popEnter(immediate, orientationChanges) + { + setState(""); + page.visible = true; + } + + // Performs a pop exit transition. + function popExit(immediate, orientationChanges) + { + setState(immediate ? "Hidden" : "Left"); + + if (immediate) + cleanup(); + else + cleanupAfterTransition = true; + } + + // Called when a transition has started. + function transitionStarted() + { + container.clip = true + transitionAnimationRunning = true; + internal.ongoingTransitionCount++; + } + + // Called when a transition has ended. + function transitionEnded() + { + container.clip = false + if (state != "") + state = "Hidden"; + + internal.ongoingTransitionCount--; + transitionAnimationRunning = false; + + if (cleanupAfterTransition) { + cleanup(); + } + } + + states: [ + // Explicit properties for default state. + State { + name: "" + PropertyChanges { target: container; visible: true; opacity: 1 } + PropertyChanges { target: container; width: container.implicitWidth} + }, + // Start state for pop entry, end state for push exit. + State { + name: "Left" + PropertyChanges { target: container; opacity: 0 } + PropertyChanges { target: container; width: Units.gridUnit * 8} + }, + // Start state for push entry, end state for pop exit. + State { + name: "Right" + PropertyChanges { target: container; opacity: 0 } + PropertyChanges { target: container; width: Units.gridUnit * 8} + }, + // Inactive state. + State { + name: "Hidden" + PropertyChanges { target: container; visible: false } + PropertyChanges { target: container; width: container.implicitWidth} + } + ] + + transitions: [ + // Push exit transition + Transition { + from: ""; to: "Left" + SequentialAnimation { + ScriptAction { script: transitionStarted() } + ParallelAnimation { + PropertyAnimation { properties: "width"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + } + ScriptAction { script: transitionEnded() } + } + }, + // Pop entry transition + Transition { + from: "Left"; to: "" + SequentialAnimation { + ScriptAction { script: transitionStarted() } + ParallelAnimation { + PropertyAnimation { properties: "width"; easing.type: Easing.OutQuad; duration: internal.transitionDuration } + PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + } + ScriptAction { script: transitionEnded() } + } + }, + // Pop exit transition + Transition { + from: ""; to: "Right" + SequentialAnimation { + ScriptAction { script: transitionStarted() } + ParallelAnimation { + PropertyAnimation { properties: "width"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + } + // Workaround for transition animation bug causing ghost view with page pop transition animation + // TODO: Root cause still unknown + PropertyAnimation {} + ScriptAction { script: transitionEnded() } + } + }, + // Push entry transition + Transition { + from: "Right"; to: "" + SequentialAnimation { + ScriptAction { script: transitionStarted() } + ParallelAnimation { + PropertyAnimation { properties: "width"; easing.type: Easing.OutQuad; duration: internal.transitionDuration } + PropertyAnimation { properties: "opacity"; easing.type: Easing.InQuad; duration: internal.transitionDuration } + } + ScriptAction { script: transitionEnded() } + } + } + ] + + // Cleans up the container and then destroys it. + function cleanup() + { + if (page != null) { + if (owner != container) { + // container is not the owner of the page - re-parent back to original owner + page.visible = false; + page.anchors.fill = undefined + page.parent = owner; + } + } + container.parent = null; + container.visible = false; + destroy(); + } + } + } +} diff --git a/components/mobilecomponents/SplitDrawer.qml b/components/mobilecomponents/qml/SplitDrawer.qml similarity index 89% rename from components/mobilecomponents/SplitDrawer.qml rename to components/mobilecomponents/qml/SplitDrawer.qml index f7378712..813eae10 100644 --- a/components/mobilecomponents/SplitDrawer.qml +++ b/components/mobilecomponents/qml/SplitDrawer.qml @@ -1,234 +1,234 @@ /* * 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 QtGraphicalEffects 1.0 -import org.kde.plasma.components 2.0 as PlasmaComponents -import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.mobilecomponents 0.2 +import "private" /**Documented API Inherits: - Page from org.kde.plasmacomponents + Item Imports: - org.kde.plasma.core - org.kde.plasma.components - QtQuick 1.1 + QtQuick 2.1 Description: Split Drawers are used to expose additional UI elements which are optional and can be used in conjunction with the main UI elements. For example the Resource Browser uses a Split Drawer to select different kinds of filters for the main view. Properties: bool open: If true the drawer is open showing the contents of the "drawer" component. Item page: It's the default property. it's the main content of the drawer page, the part that is always shown Item drawer: It's the part that can be pulled in and out, will act as a sidebar. int visibleDrawerWidth: the width of the visible portion of the drawer: it updates while dragging or animating **/ -PlasmaComponents.Page { +AbstractDrawer { id: root anchors { fill: parent } visible: true default property alias page: mainPage.data - property alias drawer: drawerPage.data - property alias open: sidebar.open + property Item contentItem + property alias opened: sidebar.open property int visibleDrawerWidth: browserFrame.x Component.onCompleted: { mainPage.width = browserFrame.width } + onContentItemChanged: contentItem.parent = drawerPage MouseArea { id: mouseEventListener z: 200 drag.filterChildren: true //drag.target: browserFrame property int startMouseX property int oldMouseX property int startBrowserFrameX property bool toggle: false property string startState anchors.fill: parent onPressed: { - if (drawerPage.children.length == 0 || (browserFrame.state == "Closed" && mouse.x > units.gridUnit) || + if (drawerPage.children.length == 0 || (browserFrame.state == "Closed" && mouse.x > Units.gridUnit) || mouse.x < browserFrame.x) { mouse.accepted = false; return; } toggle = true; startBrowserFrameX = browserFrame.x; oldMouseX = startMouseX = mouse.x; startState = browserFrame.state; browserFrame.state = "Dragging"; browserFrame.x = startBrowserFrameX; } onPositionChanged: { browserFrame.x = Math.max(0, browserFrame.x + mouse.x - oldMouseX); oldMouseX = mouse.x; - if (Math.abs(mouse.x - startMouseX) > units.gridUnit * 2) { + if (Math.abs(mouse.x - startMouseX) > Units.gridUnit * 2) { toggle = false; } } onReleased: { if (toggle) { browserFrame.state = startState == "Open" ? "Closed" : "Open" } else if (browserFrame.x < sidebar.width / 2) { browserFrame.state = "Closed"; } else { browserFrame.state = "Open"; } } + onClicked: root.clicked() } Rectangle { id: browserFrame z: 100 - color: PlasmaCore.ColorScope.backgroundColor + color: Theme.backgroundColor state: "Closed" onStateChanged: sidebar.open = (state != "Closed") anchors { top: parent.top bottom: parent.bottom } width: root.width; Item { id: mainPage onChildrenChanged: mainPage.children[0].anchors.fill = mainPage anchors.fill: parent } Rectangle { anchors.fill: parent color: "black" opacity: Math.min(0.4, 0.4 * (browserFrame.x / sidebar.width)) } LinearGradient { - width: units.gridUnit/2 + width: Units.gridUnit/2 anchors { right: parent.left top: parent.top bottom: parent.bottom rightMargin: -1 } start: Qt.point(0, 0) - end: Qt.point(units.gridUnit/2, 0) + end: Qt.point(Units.gridUnit/2, 0) gradient: Gradient { GradientStop { position: 0.0 color: "transparent" } GradientStop { position: 0.7 color: Qt.rgba(0, 0, 0, 0.15) } GradientStop { position: 1.0 color: Qt.rgba(0, 0, 0, 0.3) } } } states: [ State { name: "Open" PropertyChanges { target: browserFrame x: sidebar.width } }, State { name: "Dragging" PropertyChanges { target: browserFrame x: mouseEventListener.startBrowserFrameX } }, State { name: "Closed" PropertyChanges { target: browserFrame x: 0 } } ] transitions: [ Transition { //Exclude Dragging to: "Open,Closed,Hidden" NumberAnimation { properties: "x" - duration: units.longDuration + duration: Units.longDuration easing.type: Easing.InOutQuad } } ] } Item { id: sidebar property bool open: false onOpenChanged: { if (drawerPage.children.length == 0) { return; } if (open) { browserFrame.state = "Open"; } else { browserFrame.state = "Closed"; } } - width: parent.width/4 + width: Math.min(parent.width/4*3, Math.max(root.contentItem ? root.contentItem.implicitWidth : 0, parent.width/4)) anchors { left: parent.left top: parent.top bottom: parent.bottom } Item { id: drawerPage anchors.fill: parent clip: false onChildrenChanged: drawerPage.children[0].anchors.fill = drawerPage } } } diff --git a/components/mobilecomponents/ActionGroup.qml b/components/mobilecomponents/qml/private/AbstractDrawer.qml similarity index 55% rename from components/mobilecomponents/ActionGroup.qml rename to components/mobilecomponents/qml/private/AbstractDrawer.qml index ba057f58..db662509 100644 --- a/components/mobilecomponents/ActionGroup.qml +++ b/components/mobilecomponents/qml/private/AbstractDrawer.qml @@ -1,27 +1,47 @@ /* - * Copycontext 2015 Marco Martin + * 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 + * 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 1.3 +import QtGraphicalEffects 1.0 +import org.kde.plasma.mobilecomponents 0.2 -Action { +//TODO: This will become a QQC2 Drawer +//providing just a dummy api for now +Item { id: root - default property alias children: root.__children - property list __children + anchors.fill: parent + z: 9999 + + default property alias page: mainPage.data + property Item contentItem + property bool opened + property int edge: Qt.LeftEdge + property real position: 0 + + function open () { } + function close () { } + signal clicked + + Item { + id: mainPage + anchors.fill: parent + onChildrenChanged: mainPage.children[0].anchors.fill = mainPage + } } + diff --git a/components/mobilecomponents/qml/private/ActionButton.qml b/components/mobilecomponents/qml/private/ActionButton.qml new file mode 100644 index 00000000..9ad55ff7 --- /dev/null +++ b/components/mobilecomponents/qml/private/ActionButton.qml @@ -0,0 +1,175 @@ +/* + * 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.plasma.mobilecomponents 0.2 + +MouseArea { + id: button + property alias iconSource: icon.source + property bool checkable: false + property bool checked: false + Layout.minimumWidth: Units.iconSizes.large + Layout.maximumWidth: Layout.minimumWidth + implicitWidth: Units.iconSizes.large + implicitHeight: width + drag { + target: button + axis: Drag.XAxis + minimumX: contextDrawer ? 0 : parent.width/2 - width/2 + maximumX: globalDrawer ? parent.width : parent.width/2 - width/2 + } + function toggleVisibility() { + showAnimation.running = false; + if (translateTransform.y < button.height) { + showAnimation.to = button.height; + } else { + showAnimation.to = 0; + } + showAnimation.running = true; + } + + transform: Translate { + id: translateTransform + } + onReleased: { + if (globalDrawer && x > Math.min(parent.width/4*3, parent.width/2 + globalDrawer.contentItem.width/2)) { + globalDrawer.open(); + contextDrawer.close(); + } else if (contextDrawer && x < Math.max(parent.width/4, parent.width/2 - contextDrawer.contentItem.width/2)) { + if (contextDrawer) { + contextDrawer.open(); + } + if (globalDrawer) { + globalDrawer.close(); + } + } else { + if (globalDrawer) { + globalDrawer.close(); + } + if (contextDrawer) { + contextDrawer.close(); + } + } + } + onClicked: { + if (checkable) { + checked = !checked; + } + } + Connections { + target: globalDrawer + onPositionChanged: { + if (!button.pressed) { + button.x = globalDrawer.contentItem.width * globalDrawer.position + button.parent.width/2 - button.width/2; + } + } + } + Connections { + target: contextDrawer + onPositionChanged: { + if (!button.pressed) { + button.x = button.parent.width/2 - button.width/2 - contextDrawer.contentItem.width * contextDrawer.position; + } + } + } + Connections { + target: button.parent + onWidthChanged: button.x = button.parent.width/2 - button.width/2 + } + onXChanged: { + if (button.pressed) { + if (globalDrawer) { + globalDrawer.position = Math.min(1, Math.max(0, (x - button.parent.width/2 + button.width/2)/globalDrawer.contentItem.width)); + } + if (contextDrawer) { + contextDrawer.position = Math.min(1, Math.max(0, (button.parent.width/2 - button.width/2 - x)/contextDrawer.contentItem.width)); + } + } + } + + NumberAnimation { + id: showAnimation + target: translateTransform + properties: "y" + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + Item { + id: background + anchors { + fill: parent + leftMargin: -Units.gridUnit + rightMargin: -Units.gridUnit + } + Rectangle { + radius: width/2 + anchors.centerIn: parent + height: parent.height - Units.smallSpacing*2 + width: height + color: button.pressed || button.checked ? Theme.highlightColor : Theme.backgroundColor + Icon { + id: icon + anchors { + fill: parent + margins: Units.smallSpacing + } + } + ActionButtonArrow { + anchors { + right: parent.left + rightMargin: Units.smallSpacing + } + visible: contextDrawer && contextDrawer.enabled + inverted: true + } + ActionButtonArrow { + anchors { + left: parent.right + leftMargin: Units.smallSpacing + } + visible: globalDrawer && globalDrawer.enabled + } + Behavior on color { + ColorAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + Behavior on x { + NumberAnimation { + duration: Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } + DropShadow { + anchors.fill: background + horizontalOffset: 0 + verticalOffset: Units.smallSpacing/3 + radius: Units.gridUnit / 3.5 + samples: 16 + color: button.pressed ? "transparent" : Qt.rgba(0, 0, 0, 0.5) + source: background + } +} + diff --git a/components/mobilecomponents/qml/private/ActionButtonArrow.qml b/components/mobilecomponents/qml/private/ActionButtonArrow.qml new file mode 100644 index 00000000..7b585452 --- /dev/null +++ b/components/mobilecomponents/qml/private/ActionButtonArrow.qml @@ -0,0 +1,56 @@ +/* + * 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.plasma.mobilecomponents 0.2 + +Canvas { + id: canvas + width: Units.gridUnit + height: width + property bool inverted + property color color: parent.color + anchors.verticalCenter: parent.verticalCenter + + onColorChanged: requestPaint() + + onPaint: { + var ctx = canvas.getContext("2d"); + ctx.fillStyle = canvas.color; + ctx.beginPath(); + if (inverted) { + ctx.moveTo(canvas.width, 0); + ctx.bezierCurveTo(canvas.width-canvas.width/8, 0, + canvas.width-canvas.width/8, canvas.height, + canvas.width, canvas.height); + ctx.lineTo(0, canvas.height/2); + } else { + ctx.moveTo(0, 0); + ctx.bezierCurveTo(canvas.width/8, 0, + canvas.width/8, canvas.height, + 0, canvas.height); + ctx.lineTo(canvas.width, canvas.height/2); + //ctx.lineTo(0, canvas.height); + } + ctx.fill(); + } +} + diff --git a/components/mobilecomponents/qml/private/PageStack.js b/components/mobilecomponents/qml/private/PageStack.js new file mode 100644 index 00000000..8986956b --- /dev/null +++ b/components/mobilecomponents/qml/private/PageStack.js @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Page stack. Items are page containers. +var pageStack = []; + +// Page component cache map. Key is page url, value is page component. +var componentCache = {}; + +// Returns the page stack depth. +function getDepth() { + return pageStack.length; +} + +// Pushes a page on the stack. +function push(page, properties, replace, immediate) { + // page order sanity check + if ((!replace && page == currentPage) + || (replace && pageStack.length > 1 + && page == pageStack[pageStack.length - 2].page)) { + throw new Error("Cannot navigate so that the resulting page stack has two consecutive entries of the same page instance."); + } + + // 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; + } + } + + // get the current container + var oldContainer; + if (pageStack.length) { + oldContainer = pageStack[pageStack.length - 1]; + } + + // pop the old container off the stack if this is a replace + if (oldContainer && replace) { + pageStack.pop(); + } + + // 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") { + tProps = tPage.properties; + tPage = tPage.page; + } + pageStack.push(initPage(tPage, tProps)); + } + } + + // initialize the page + var container = initPage(page, properties); + + // push the page container onto the stack + pageStack.push(container); + + depth = pageStack.length; + currentPage = container.page; + + // perform page transition + //FIXME: this should be in for PageStack, out for PageRow? + //immediate = immediate || !oldContainer; + var orientationChange = false; + if (oldContainer) { + orientationChange = orientationChanges(oldContainer.page, container.page); + oldContainer.pushExit(replace, immediate, orientationChange); + } + + // sync tool bar + var tools = container.page.tools || null; + if (toolBar) { + toolBar.setTools(tools, immediate ? "set" : replace ? "replace" : "push"); + } + + container.pushEnter(immediate, orientationChange); + return container.page; +} + +// Initializes a page and its container. +function initPage(page, properties) { + var container = containerComponent.createObject(root); + + var pageComp; + if (page.createObject) { + // page defined as component + pageComp = page; + } else if (typeof page == "string") { + // page defined as string (a url) + pageComp = componentCache[page]; + if (!pageComp) { + pageComp = componentCache[page] = Qt.createComponent(page); + } + } + if (pageComp) { + if (pageComp.status == Component.Error) { + throw new Error("Error while loading page: " + pageComp.errorString()); + } else { + // instantiate page from component + page = pageComp.createObject(container.pageParent, properties || {}); + } + } 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 = container; + } else { + container.owner = page.parent; + } + + // the page has to be reparented if + if (page.parent != container.pageParent) { + page.parent = container.pageParent; + } + + if (page.pageStack !== undefined) { + page.pageStack = root; + } + + page.anchors.fill = container.pageParent + + return container; +} + +// Pops a page off the stack. +function pop(page, immediate) { + // make sure there are enough pages in the stack to pop + if (pageStack.length > 1) { + //unwind to itself means no pop + if (page !== undefined && page == pageStack[pageStack.length - 1].page) { + return + } + // pop the current container off the stack and get the next container + var oldContainer = pageStack.pop(); + var container = pageStack[pageStack.length - 1]; + if (page !== undefined) { + // an unwind target has been specified - pop until we find it + while (page != container.page && pageStack.length > 1) { + pageStack.pop(); + container.popExit(immediate, false); + container = pageStack[pageStack.length - 1]; + } + } + + depth = pageStack.length; + currentPage = container.page; + + // perform page transition + var orientationChange = orientationChanges(oldContainer.page, container.page); + oldContainer.popExit(immediate, orientationChange); + container.popEnter(immediate, orientationChange); + + // sync tool bar + var tools = container.page.tools || null; + if (toolBar) { + toolBar.setTools(tools, immediate ? "set" : "pop"); + } + return oldContainer.page; + } else { + return null; + } +} + +// Checks if the orientation changes between oldPage and newPage +function orientationChanges(oldPage, newPage) { + return newPage.orientationLock != 0 //PlasmaComponents.PageOrientation.Automatic + && newPage.orientationLock != 3//PlasmaComponents.PageOrientation.LockPrevious + && newPage.orientationLock != oldPage.orientationLock +} + +// Clears the page stack. +function clear() { + var container; + while (container = pageStack.pop()) { + container.cleanup(); + } + depth = 0; + currentPage = null; +} + +// Iterates through all pages in the stack (top to bottom) to find a page. +function find(func) { + for (var i = pageStack.length - 1; i >= 0; i--) { + var page = pageStack[i].page; + if (func(page)) { + return page; + } + } + return null; +} + diff --git a/components/mobilecomponents/qmldir b/components/mobilecomponents/qml/qmldir similarity index 56% rename from components/mobilecomponents/qmldir rename to components/mobilecomponents/qml/qmldir index 6c8fecbd..53daf98a 100644 --- a/components/mobilecomponents/qmldir +++ b/components/mobilecomponents/qml/qmldir @@ -1,11 +1,19 @@ module org.kde.plasma.mobilecomponents -plugin mobilecomponentsplugin +#plugin mobilecomponentsplugin + +singleton Units 0.2 Units.qml +singleton Theme 0.2 Theme.qml + IconGrid 0.2 IconGrid.qml OverlayDrawer 0.2 OverlayDrawer.qml SplitDrawer 0.2 SplitDrawer.qml ActionGroup 0.2 ActionGroup.qml ApplicationWindow 0.2 ApplicationWindow.qml ContextDrawer 0.2 ContextDrawer.qml GlobalDrawer 0.2 GlobalDrawer.qml Page 0.2 Page.qml - +Icon 0.2 Icon.qml +Label 0.2 Label.qml +Heading 0.2 Heading.qml +ListItem 0.2 ListItem.qml +ListItemWithActions 0.2 ListItemWithActions.qml diff --git a/components/mobileshellprivate/CMakeLists.txt b/components/mobileshellprivate/CMakeLists.txt new file mode 100644 index 00000000..694423ec --- /dev/null +++ b/components/mobileshellprivate/CMakeLists.txt @@ -0,0 +1,15 @@ +project(mobileshellprivate) + +set(mobileshellprivate_SRCS + mobileshellprivateplugin.cpp + fullscreenpanel.cpp + ) + +add_library(mobileshellprivateplugin SHARED ${mobileshellprivate_SRCS}) +target_link_libraries(mobileshellprivateplugin Qt5::Core Qt5::Widgets Qt5::Qml Qt5::Quick KF5::Declarative KF5::Plasma KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::Activities KF5::WindowSystem KF5::WaylandClient) + +install(TARGETS mobileshellprivateplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/mobileshell) + + + + diff --git a/components/mobileshellprivate/Messages.sh b/components/mobileshellprivate/Messages.sh new file mode 100644 index 00000000..0585074f --- /dev/null +++ b/components/mobileshellprivate/Messages.sh @@ -0,0 +1,2 @@ +#! /bin/sh +$XGETTEXT *.cpp */*.cpp -o $podir/plasmamobileshellprivateplugin.pot diff --git a/components/mobilecomponents/fullscreenpanel.cpp b/components/mobileshellprivate/fullscreenpanel.cpp similarity index 100% rename from components/mobilecomponents/fullscreenpanel.cpp rename to components/mobileshellprivate/fullscreenpanel.cpp diff --git a/components/mobilecomponents/fullscreenpanel.h b/components/mobileshellprivate/fullscreenpanel.h similarity index 100% rename from components/mobilecomponents/fullscreenpanel.h rename to components/mobileshellprivate/fullscreenpanel.h diff --git a/components/mobileshellprivate/mobileshellprivateplugin.cpp b/components/mobileshellprivate/mobileshellprivateplugin.cpp new file mode 100644 index 00000000..cf9a8a5c --- /dev/null +++ b/components/mobileshellprivate/mobileshellprivateplugin.cpp @@ -0,0 +1,34 @@ +/* + Copyright 2015 Marco Martin + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "mobileshellprivateplugin.h" +#include "fullscreenpanel.h" + +#include + + +void PlasmaMobileShellPrivatePlugin::registerTypes(const char *uri) +{ + Q_ASSERT(uri == QLatin1String("org.kde.plasma.private.mobileshell")); + + qmlRegisterType(uri, 2, 0, "FullScreenPanel"); +} diff --git a/components/mobileshellprivate/mobileshellprivateplugin.h b/components/mobileshellprivate/mobileshellprivateplugin.h new file mode 100644 index 00000000..0801fa4a --- /dev/null +++ b/components/mobileshellprivate/mobileshellprivateplugin.h @@ -0,0 +1,37 @@ +/* + Copyright 2015 Marco Martin + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef MOBILESHELLPRIVATE_H +#define MOBILESHELLPRIVATE_H + +#include + +class PlasmaMobileShellPrivatePlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri); +}; + +#endif diff --git a/components/mobileshellprivate/qmldir b/components/mobileshellprivate/qmldir new file mode 100644 index 00000000..c88ad12c --- /dev/null +++ b/components/mobileshellprivate/qmldir @@ -0,0 +1,2 @@ +module org.kde.plasma.private.mobileshell +plugin plasmamobileshellprivateplugin