diff --git a/src/controls/Dialog.qml b/src/controls/Dialog.qml index 0214380..fad34c9 100644 --- a/src/controls/Dialog.qml +++ b/src/controls/Dialog.qml @@ -1,280 +1,278 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.5 import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import QtGraphicalEffects 1.0 Maui.Popup { id: control property string message : "" property string title: "" property string acceptText: "Yes" property string rejectText: "No" property bool defaultButtons: true property bool confirmationDialog: false default property alias content : _pageContent.data property alias acceptButton : _acceptButton property alias rejectButton : _rejectButton property alias textEntry : _textEntry property alias entryField: _textEntry.visible property alias page : _page property alias footBar : _page.footBar property alias headBar: _page.headBar property alias closeButton: _closeButton signal accepted() signal rejected() clip: false closePolicy: Popup.NoAutoClose | Popup.CloseOnEscape maxWidth: Maui.Style.unit * 300 maxHeight: (_pageContent.implicitHeight * 1.2) + ( _page.footBar.height + _defaultButtonsLayout.implicitHeight ) + Maui.Style.space.huge + _page.margins + _page.padding widthHint: 0.9 heightHint: 0.9 Maui.Badge { id: _closeButton color: hovered || pressed ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.backgroundColor property int position : Maui.App.leftWindowControls.includes("X") ? Qt.AlignLeft : Qt.AlignRight Maui.X { height: Maui.Style.iconSizes.tiny width: height anchors.centerIn: parent color: Kirigami.Theme.textColor } border.color: Kirigami.Theme.textColor anchors { verticalCenter: parent.top horizontalCenter: _closeButton.position === Qt.AlignLeft ? parent.left : parent.right horizontalCenterOffset: control.width === control.parent.width ? _closeButton.width : 0 } z: control.z+999 onClicked: close() } ColumnLayout { anchors.fill: parent spacing: 0 Maui.Page { id: _page Layout.fillWidth: true Layout.fillHeight: true - footBar.visible: footBar.count > 1 - headBar.visible: headBar.count > 1 padding: 0 clip: true ColumnLayout { id: _pageContent anchors.fill: parent spacing: Maui.Style.space.medium Label { visible: title.length > 0 Layout.fillWidth: true Layout.alignment: Qt.AlignCenter color: Kirigami.Theme.textColor text: title font.weight: Font.Thin font.bold: true font.pointSize:Maui.Style.fontSizes.huge elide: Qt.ElideRight wrapMode: Text.Wrap } Kirigami.ScrollablePage { id: _scrollable visible: message.length > 0 Layout.preferredHeight: Math.min(_scrollable.contentHeight, 500) Layout.fillWidth: true Layout.alignment: Qt.AlignCenter Kirigami.Theme.backgroundColor: "transparent" padding: 0 leftPadding: padding rightPadding: padding topPadding: padding bottomPadding: padding Label { id: body width: parent.width padding: 0 text: message textFormat : TextEdit.AutoText color: Kirigami.Theme.textColor font.pointSize:Maui.Style.fontSizes.default wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere elide: Text.ElideLeft verticalAlignment: Qt.AlignVCenter } } Maui.TextField { id: _textEntry visible: false Layout.fillWidth: true Layout.alignment: Qt.AlignCenter focus: visible onAccepted: control.accepted() } } /* * layer.enabled: control.background.radius * layer.samples: 4 * layer.effect: OpacityMask * { * maskSource: Item * { * width: _page.width * height: _page.height * * Rectangle * { * anchors.centerIn: parent * width: _page.width * height: _page.height * radius: control.background.radius } } }*/ } Kirigami.Separator { Layout.fillWidth: true visible: control.defaultButtons } RowLayout { id: _defaultButtonsLayout spacing: 0 Layout.margins: 1 Layout.fillWidth: true Layout.preferredHeight: Maui.Style.toolBarHeightAlt - Maui.Style.space.medium Layout.maximumHeight: Maui.Style.toolBarHeightAlt - Maui.Style.space.medium visible: defaultButtons Button { Layout.fillWidth: true Layout.fillHeight: true implicitWidth: width id: _rejectButton text: control.rejectText background: Rectangle { color: _rejectButton.hovered || _rejectButton.down || _rejectButton.pressed ? "#da4453" : Kirigami.Theme.backgroundColor } contentItem: Label { text: _rejectButton.text color: _rejectButton.hovered || _rejectButton.down || _rejectButton.pressed ? "#fafafa" : Kirigami.Theme.textColor horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter } /*property color color : Kirigami.Theme.negativeBackgroundColor * property alias text : _rejectLabel.text * * Rectangle * { * anchors.fill: parent * color: _rejectButton.color * Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor * Label * { * id: _rejectLabel * anchors.fill: parent * anchors.margins: Maui.Style.space.small * text: _rejectButton.text * color: "#fafafa" } } */ onClicked: rejected() } Kirigami.Separator { Layout.fillHeight: true } Button { Layout.fillWidth: true Layout.fillHeight: true implicitWidth: width text: acceptText id: _acceptButton background: Rectangle { color: _acceptButton.hovered || _acceptButton.down || _acceptButton.pressed ? "#26c6da" : Kirigami.Theme.backgroundColor } contentItem: Label { text: _acceptButton.text color: _acceptButton.hovered || _acceptButton.down || _acceptButton.pressed ? "#fafafa" : Kirigami.Theme.textColor horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter } onClicked: accepted() } } } } diff --git a/src/controls/FileDialog.qml b/src/controls/FileDialog.qml index 03807dc..fbc28f1 100644 --- a/src/controls/FileDialog.qml +++ b/src/controls/FileDialog.qml @@ -1,426 +1,426 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.9 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import org.kde.mauikit 1.1 as MauiLab import QtQuick.Layouts 1.3 Maui.Dialog { id: control maxHeight: Kirigami.Settings.isMobile ? parent.height * 0.95 : Maui.Style.unit * 500 maxWidth: Maui.Style.unit * 700 page.padding: 0 property alias currentPath : browser.currentPath property alias browser : browser property alias selectionBar: _selectionBar property string suggestedFileName : "" property alias settings : browser.settings property bool searchBar : false onSearchBarChanged: if(!searchBar) browser.quitSearch() readonly property var modes : ({OPEN: 0, SAVE: 1}) property int mode : modes.OPEN property var callback : ({}) property alias textField: _textField rejectButton.visible: false acceptButton.text: control.mode === modes.SAVE ? qsTr("Save") : qsTr("Open") footBar.visible: control.mode === modes.SAVE footBar.middleContent: Maui.TextField { id: _textField Layout.fillWidth: true placeholderText: qsTr("File name...") text: suggestedFileName } onAccepted: { console.log("CURRENT PATHb", browser.currentPath+"/"+textField.text) if(control.mode === modes.SAVE && Maui.FM.fileExists(browser.currentPath+"/"+textField.text)) { _confirmationDialog.open() }else { done() } } Component { id: _pathBarComponent Maui.PathBar { onPathChanged: browser.openFolder(path) url: browser.currentPath onHomeClicked: browser.openFolder(Maui.FM.homePath()) onPlaceClicked: browser.openFolder(path) } } Component { id: _searchFieldComponent Maui.TextField { placeholderText: qsTr("Search for files... ") onAccepted: browser.search(text) onCleared: browser.quitSearch() onGoBackTriggered: { searchBar = false clear() } background: Rectangle { border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) radius: Maui.Style.radiusV color: Kirigami.Theme.backgroundColor } } } - + headBar.visible: true headBar.leftContent: ToolButton { icon.name: "application-menu" checked: pageRow.currentIndex === 0 onClicked: pageRow.currentIndex = !pageRow.currentIndex } headBar.middleContent: Loader { Layout.fillWidth: true Layout.preferredHeight: Maui.Style.iconSizes.big sourceComponent: searchBar ? _searchFieldComponent : _pathBarComponent } headBar.rightContent: ToolButton { id: searchButton icon.name: "edit-find" onClicked: searchBar = !searchBar checked: searchBar } Maui.Dialog { id: _confirmationDialog acceptButton.text: qsTr("Yes") rejectButton.text: qsTr("No") title: qsTr("A file named %1 already exists!").arg(textField.text) message: qsTr("This action will overwrite %1. Are you sure you want to do this?").arg(textField.text) onAccepted: control.done() onRejected: close() } Kirigami.PageRow { id: pageRow Layout.fillHeight: true Layout.fillWidth: true clip: true separatorVisible: wideMode initialPage: [sidebar, _browserLayout] defaultColumnWidth: Kirigami.Units.gridUnit * (Kirigami.Settings.isMobile? 15 : 8) Maui.PlacesListBrowser { id: sidebar onPlaceClicked: { pageRow.currentIndex = 1 browser.openFolder(path) } list.groups: control.mode === modes.OPEN ? [ Maui.FMList.PLACES_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] : [Maui.FMList.PLACES_PATH, Maui.FMList.REMOTE_PATH, Maui.FMList.CLOUD_PATH, Maui.FMList.DRIVES_PATH] } ColumnLayout { id: _browserLayout spacing: Maui.Style.space.small Maui.Page { Layout.fillWidth: true Layout.fillHeight: true headBar.visible: true headBar.rightContent:[ Maui.ToolButtonMenu { icon.name: "view-sort" MenuItem { text: qsTr("Show Folders First") checked: browser.currentFMList.foldersFirst checkable: true onTriggered: browser.currentFMList.foldersFirst = !browser.currentFMList.foldersFirst } MenuSeparator {} MenuItem { text: qsTr("Type") checked: browser.currentFMList.sortBy === Maui.FMList.MIME checkable: true onTriggered: browser.currentFMList.sortBy = Maui.FMList.MIME autoExclusive: true } MenuItem { text: qsTr("Date") checked: browser.currentFMList.sortBy === Maui.FMList.DATE checkable: true onTriggered: browser.currentFMList.sortBy = Maui.FMList.DATE autoExclusive: true } MenuItem { text: qsTr("Modified") checkable: true checked: browser.currentFMList.sortBy === Maui.FMList.MODIFIED onTriggered: browser.currentFMList.sortBy = Maui.FMList.MODIFIED autoExclusive: true } MenuItem { text: qsTr("Size") checkable: true checked: browser.currentFMList.sortBy === Maui.FMList.SIZE onTriggered: browser.currentFMList.sortBy = Maui.FMList.SIZE autoExclusive: true } MenuItem { text: qsTr("Name") checkable: true checked: browser.currentFMList.sortBy === Maui.FMList.LABEL onTriggered: browser.currentFMList.sortBy = Maui.FMList.LABEL autoExclusive: true } MenuSeparator{} MenuItem { id: groupAction text: qsTr("Group") checkable: true checked: browser.settings.group onTriggered: { browser.settings.group = !browser.settings.group } } }, ToolButton { id: _optionsButton icon.name: "overflow-menu" enabled: currentFMList.pathType !== Maui.FMList.TAGS_PATH && currentFMList.pathType !== Maui.FMList.TRASH_PATH && currentFMList.pathType !== Maui.FMList.APPS_PATH onClicked: { if(browser.browserMenu.visible) browser.browserMenu.close() else browser.browserMenu.show(_optionsButton, 0, height) } checked: browser.browserMenu.visible checkable: false } ] headBar.leftContent: [ Maui.ToolActions { expanded: true autoExclusive: false checkable: false Action { icon.name: "go-previous" onTriggered : browser.goBack() } Action { icon.name: "go-next" onTriggered: browser.goNext() } }, Maui.ToolActions { id: _viewTypeGroup expanded: false currentIndex: browser.settings.viewType onCurrentIndexChanged: { if(browser) browser.settings.viewType = currentIndex Maui.FM.saveSettings("VIEW_TYPE", currentIndex, "BROWSER") } Action { icon.name: "view-list-icons" text: qsTr("Grid") shortcut: "Ctrl+G" } Action { icon.name: "view-list-details" text: qsTr("List") shortcut: "Ctrl+L" } Action { icon.name: "view-file-columns" text: qsTr("Columns") shortcut: "Ctrl+M" } } ] Maui.FileBrowser { id: browser anchors.fill: parent selectionBar: _selectionBar currentPath: Maui.FM.homePath() selectionMode: control.mode === modes.OPEN onItemClicked: { if(currentFMList.get(index).isdir == "true") { openItem(index) } switch(control.mode) { case modes.OPEN : { addToSelection(currentFMList.get(index)) break } case modes.SAVE: { textField.text = currentFMList.get(index).label break } } } onCurrentPathChanged: { sidebar.currentIndex = -1 for(var i = 0; i < sidebar.count; i++) { if(String(browser.currentPath) === sidebar.list.get(i).path) { sidebar.currentIndex = i return; } } } } } MauiLab.SelectionBar { id: _selectionBar Layout.alignment: Qt.AlignCenter onExitClicked: { _selectionBar.clear() } } } } function show(cb) { if(cb) callback = cb open() } function closeIt() { browser.clearSelection() close() } function done() { var paths = browser.selectionBar && browser.selectionBar.visible ? browser.selectionBar.uris : [browser.currentPath] if(control.mode === modes.SAVE) { for(var i in paths) paths[i] = paths[i] + "/" + textField.text } if(callback) callback(paths) control.closeIt() } } diff --git a/src/controls/FilePreviewer.qml b/src/controls/FilePreviewer.qml index 8d52711..1fda397 100644 --- a/src/controls/FilePreviewer.qml +++ b/src/controls/FilePreviewer.qml @@ -1,276 +1,277 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.Dialog { id: control property url currentUrl: "" property alias model : _listView.model property bool isFav : false property bool isDir : false property bool showInfo: true property alias tagBar : _tagsBar property Maui.TagsDialog tagsDialog : null signal shareButtonClicked(url url) signal openButtonClicked(url url) maxHeight: Maui.Style.unit * 800 maxWidth: Maui.Style.unit * 500 defaultButtons: false page.padding: 0 + footBar.visible: true footBar.leftContent: ToolButton { icon.name: "document-open" onClicked: { openButtonClicked(control.currentUrl) control.close() } } footBar.middleContent: [ ToolButton { visible: !isDir icon.name: "document-share" onClicked: { shareButtonClicked(control.currentUrl) control.close() } }, ToolButton { icon.name: "love" checkable: true checked: control.isFav onClicked: { if(control.isFav) _tagsBar.list.removeFromUrls("fav") else _tagsBar.list.insertToUrls("fav") control.isFav = !control.isFav } } ] footBar.rightContent: ToolButton { icon.name: "documentinfo" checkable: true checked: control.showInfo onClicked: control.showInfo = !control.showInfo } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true spacing: 0 ListView { id: _listView Layout.fillWidth: true Layout.fillHeight: true orientation: ListView.Horizontal clip: true focus: true interactive: true highlightFollowsCurrentItem: true highlightMoveDuration: 0 highlightResizeDuration : 0 snapMode: ListView.SnapOneItem cacheBuffer: 0 keyNavigationEnabled : true keyNavigationWraps : true onMovementEnded: currentIndex = indexAt(contentX, contentY) delegate: Maui.Page { id: _delegate property bool isCurrentItem : ListView.isCurrentItem property url currentUrl: model.path property var iteminfo : model property alias infoModel : _infoModel height: _listView.height width: _listView.width title: model.label headBar.visible: true autoHideHeader: true floatingHeader: false //TODO needs some upstream fixes to work properly Loader { id: previewLoader active: _delegate.isCurrentItem && control.visible visible: !control.showInfo anchors.fill: parent clip: false onActiveChanged: if(active) show(currentUrl) } Kirigami.ScrollablePage { id: _infoContent visible: control.showInfo anchors.fill: parent Kirigami.Theme.backgroundColor: "transparent" padding: Maui.Style.space.big leftPadding: padding rightPadding: padding topPadding: padding bottomPadding: padding ColumnLayout { width: parent.width spacing: Maui.Style.space.large Repeater { model: ListModel { id: _infoModel } Column { spacing: Maui.Style.space.small width: parent.width Label { width: parent.width visible: _valueLabel.visible text: model.key color: Kirigami.Theme.textColor elide: Text.ElideRight wrapMode: Text.NoWrap horizontalAlignment: Qt.AlignLeft font.weight: Font.Bold font.bold: true } Label { id: _valueLabel width: parent.width visible: text.length text: model.value color: Kirigami.Theme.textColor elide: Qt.ElideMiddle wrapMode: Text.Wrap horizontalAlignment: Qt.AlignLeft font.weight: Font.Light } } } } } function show(path) { initModel() control.isDir = model.isdir == "true" control.currentUrl = path control.isFav = _tagsBar.list.contains("fav") var source = "private/DefaultPreview.qml" if(Maui.FM.checkFileType(Maui.FMList.AUDIO, iteminfo.mime)) { source = "private/AudioPreview.qml" } if(Maui.FM.checkFileType(Maui.FMList.VIDEO, iteminfo.mime)) { source = "private/VideoPreview.qml" } if(Maui.FM.checkFileType(Maui.FMList.TEXT, iteminfo.mime)) { source = "private/TextPreview.qml" } if(Maui.FM.checkFileType(Maui.FMList.IMAGE, iteminfo.mime)) { source = "private/ImagePreview.qml" } if(Maui.FM.checkFileType(Maui.FMList.DOCUMENT, iteminfo.mime) && !isAndroid) { source = "private/DocumentPreview.qml" } console.log("previe mime", iteminfo.mime) previewLoader.source = source control.showInfo = source === "private/DefaultPreview.qml" } function initModel() { infoModel.clear() infoModel.append({key: "Type", value: iteminfo.mime}) infoModel.append({key: "Date", value: iteminfo.date}) infoModel.append({key: "Modified", value: iteminfo.modified}) infoModel.append({key: "Last Read", value: iteminfo.lastread}) infoModel.append({key: "Owner", value: iteminfo.owner}) infoModel.append({key: "Group", value: iteminfo.group}) infoModel.append({key: "Size", value: Maui.FM.formatSize(iteminfo.size)}) infoModel.append({key: "Symbolic Link", value: iteminfo.symlink}) infoModel.append({key: "Path", value: iteminfo.path}) infoModel.append({key: "Icon Name", value: iteminfo.icon}) } } } Maui.TagsBar { id: _tagsBar position: ToolBar.Footer Layout.fillWidth: true Layout.margins: 0 list.urls: [control.currentUrl] list.strict: false allowEditMode: true onTagRemovedClicked: list.removeFromUrls(index) onTagsEdited: list.updateToUrls(tags) Kirigami.Theme.textColor: control.Kirigami.Theme.textColor Kirigami.Theme.backgroundColor: control.Kirigami.Theme.backgroundColor } } function show(model, index) { control.model = model _listView.currentIndex = index _listView.positionViewAtIndex(index,ListView.Center ) open() _listView.forceActiveFocus() } } diff --git a/src/controls/TagsDialog.qml b/src/controls/TagsDialog.qml index 40da7ce..72ef528 100644 --- a/src/controls/TagsDialog.qml +++ b/src/controls/TagsDialog.qml @@ -1,174 +1,176 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import TagsModel 1.0 import TagsList 1.0 Maui.Dialog { id: control property alias taglist :_tagsList property alias listView: _listView property alias composerList: tagListComposer.list acceptText: "OK" rejectText: "Cancel" signal tagsReady(var tags) defaultButtons: true maxHeight: Maui.Style.unit * 500 page.margins: Maui.Style.space.medium acceptButton.text: qsTr("Add") rejectButton.text: qsTr("Cancel") onAccepted: setTags() onRejected: close() + + headBar.visible: true headBar.leftContent: ToolButton { icon.name: "view-sort" onClicked: sortMenu.popup() Menu { id: sortMenu MenuItem { text: qsTr("Sort by name") checkable: true autoExclusive: true checked: _tagsList.sortBy === TagsList.TAG onTriggered: _tagsList.sortBy = TagsList.TAG } MenuItem { text: qsTr("Sort by date") checkable: true autoExclusive: true checked: _tagsList.sortBy === TagsList.ADD_DATE onTriggered: _tagsList.sortBy = TagsList.ADD_DATE } } } headBar.middleContent: Maui.TextField { id: tagText Layout.fillWidth: true placeholderText: qsTr("Add a new tag...") onAccepted: { const tags = tagText.text.split(",") for(var i in tags) { const myTag = tags[i].trim() _tagsList.insert(myTag) tagListComposer.list.append(myTag) } clear() } } headBar.rightContent: ToolButton { icon.name: "view-refresh" onClicked: taglist.refresh() } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Item { Layout.fillHeight: true Layout.fillWidth: true ListView { id: _listView anchors.fill: parent spacing: Maui.Style.space.tiny clip: true focus: true interactive: true highlightFollowsCurrentItem: true highlightMoveDuration: 0 TagsModel { id: _tagsModel list: _tagsList } TagsList { id: _tagsList } Maui.Holder { id: holder emoji: "qrc:/img/assets/Electricity.png" visible: _listView.count === 0 isMask: false title : qsTr("No tags!") body: qsTr("Start by creating tags") emojiSize: Maui.Style.iconSizes.huge } model: _tagsModel delegate: Maui.ListDelegate { id: delegate label: tag radius: Maui.Style.radiusV Connections { target: delegate onClicked: { _listView.currentIndex = index tagListComposer.list.append(_tagsList.get(_listView.currentIndex ).tag) } } } } } Maui.TagList { id: tagListComposer Layout.fillWidth: true Layout.leftMargin: Maui.Style.contentMargins Layout.rightMargin: Maui.Style.contentMargins height: Maui.Style.rowHeight width: parent.width onTagRemoved: list.remove(index) placeholderText: "" } } onClosed: { composerList.urls = [] } function setTags() { var tags = [] for(var i = 0; i < tagListComposer.count; i++) tags.push(tagListComposer.list.get(i).tag) control.tagsReady(tags) close() } } diff --git a/src/controls/ToolBar.qml b/src/controls/ToolBar.qml index 6cb1ef2..e913b4a 100644 --- a/src/controls/ToolBar.qml +++ b/src/controls/ToolBar.qml @@ -1,358 +1,358 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Controls 2.2 import org.kde.kirigami 2.9 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import "private" ToolBar { id: control property int preferredHeight: Maui.Style.toolBarHeight implicitHeight: preferredHeight implicitWidth: mainFlickable.contentWidth spacing: Maui.Style.space.small padding: 0 default property alias content : leftRowContent.data - - // property alias stickyRightContent : rightRowContent.sticky - // property alias stickyLeftContent : leftRowContent.sticky - // property alias stickyMiddleContent : middleRowContent.sticky - - property bool forceCenterMiddleContent : true - - property alias leftContent : leftRowContent.data - property alias middleContent : middleRowContent.data - property alias rightContent : rightRowContent.data - - property alias farLeftContent : farLeftRowContent.data - property alias farRightContent : farRightRowContent.data - - property alias middleLayout : middleRowContent - property alias leftLayout : leftRowContent - property alias rightLayout : rightRowContent - - property alias layout : layout - - readonly property alias fits : _scrollView.fits - - property int margins: Maui.Style.space.medium - readonly property int count : leftContent.length + middleContent.length + rightContent.length + farLeftContent.length + farRightContent.length - readonly property int visibleCount : leftRowContent.visibleChildren.length + middleRowContent.visibleChildren.length + rightRowContent.visibleChildren.length + farLeftRowContent.visibleChildren.length + farRightRowContent.visibleChildren.length - - property bool flickable: true - property bool strech : true - property bool leftSretch: strech - property bool rightSretch: strech - property bool middleStrech: strech - - MouseArea - { - id: _rightFlickRec - width: Maui.Style.iconSizes.medium - height: parent.height - visible: !mainFlickable.atXEnd && !control.fits && control.flickable - hoverEnabled: true - anchors - { - top: parent.top - bottom: parent.bottom - right: parent.right - } - z: 999 + // property alias stickyRightContent : rightRowContent.sticky + // property alias stickyLeftContent : leftRowContent.sticky + // property alias stickyMiddleContent : middleRowContent.sticky + + property bool forceCenterMiddleContent : true + + property alias leftContent : leftRowContent.data + property alias middleContent : middleRowContent.data + property alias rightContent : rightRowContent.data + + property alias farLeftContent : farLeftRowContent.data + property alias farRightContent : farRightRowContent.data + + property alias middleLayout : middleRowContent + property alias leftLayout : leftRowContent + property alias rightLayout : rightRowContent + + property alias layout : layout - EdgeShadow + readonly property alias fits : _scrollView.fits + + property int margins: Maui.Style.space.medium + readonly property int count : leftContent.length + middleContent.length + rightContent.length + farLeftContent.length + farRightContent.length + readonly property int visibleCount : leftRowContent.visibleChildren.length + middleRowContent.visibleChildren.length + rightRowContent.visibleChildren.length + farLeftRowContent.visibleChildren.length + farRightRowContent.visibleChildren.length + + property bool flickable: true + property bool strech : true + property bool leftSretch: strech + property bool rightSretch: strech + property bool middleStrech: strech + + MouseArea { - visible: true - parent: parent - edge: Qt.RightEdge + id: _rightFlickRec + width: Maui.Style.iconSizes.medium + height: parent.height + visible: !mainFlickable.atXEnd && !control.fits && control.flickable + hoverEnabled: true anchors { - right: parent.right top: parent.top bottom: parent.bottom + right: parent.right } - opacity: 1 + z: 999 - Behavior on opacity + EdgeShadow { - NumberAnimation + visible: true + parent: parent + edge: Qt.RightEdge + anchors { - duration: Kirigami.Units.longDuration - easing.type: Easing.InOutQuad + right: parent.right + top: parent.top + bottom: parent.bottom + } + + opacity: 1 + + Behavior on opacity + { + NumberAnimation + { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } } } - } - - Maui.Triangle - { - visible: !Kirigami.Settings.isMobile - anchors.centerIn: parent - rotation: -135 - color: _rightFlickRec.hovered ? control.Kirigami.Theme.highlightColor : control.Kirigami.Theme.textColor - width: Maui.Style.iconSizes.tiny - height: width - } - - enabled: !mainFlickable.atXEnd - opacity: enabled ? 1 : 0.4 - onClicked: - { - if(!mainFlickable.atXEnd) + + Maui.Triangle { - mainFlickable.contentX += Math.min( mainFlickable.contentWidth - mainFlickable.contentX, mainFlickable.contentWidth) + visible: !Kirigami.Settings.isMobile + anchors.centerIn: parent + rotation: -135 + color: _rightFlickRec.hovered ? control.Kirigami.Theme.highlightColor : control.Kirigami.Theme.textColor + width: Maui.Style.iconSizes.tiny + height: width } - if(mainFlickable.atXEnd) + enabled: !mainFlickable.atXEnd + opacity: enabled ? 1 : 0.4 + onClicked: { - mainFlickable.returnToBounds() + if(!mainFlickable.atXEnd) + { + mainFlickable.contentX += Math.min( mainFlickable.contentWidth - mainFlickable.contentX, mainFlickable.contentWidth) + } + + if(mainFlickable.atXEnd) + { + mainFlickable.returnToBounds() + } } + } - } - - MouseArea - { - id: _leftFlickRec - width: Maui.Style.iconSizes.medium - height: parent.height - visible: !mainFlickable.atXBeginning && !control.fits && control.flickable - hoverEnabled: true - anchors - { - top: parent.top - bottom: parent.bottom - left: parent.left - } - z: 999 - - EdgeShadow + MouseArea { - visible: true - parent: parent - edge: Qt.LeftEdge + id: _leftFlickRec + width: Maui.Style.iconSizes.medium + height: parent.height + visible: !mainFlickable.atXBeginning && !control.fits && control.flickable + hoverEnabled: true anchors { - left: parent.left top: parent.top bottom: parent.bottom + left: parent.left } + z: 999 - opacity: 1 - - Behavior on opacity + EdgeShadow { - NumberAnimation + visible: true + parent: parent + edge: Qt.LeftEdge + anchors { - duration: Kirigami.Units.longDuration - easing.type: Easing.InOutQuad + left: parent.left + top: parent.top + bottom: parent.bottom } - } - } - - Maui.Triangle - { - visible: !Kirigami.Settings.isMobile - anchors.centerIn: parent - rotation: 45 - color: _leftFlickRec.hovered ? control.Kirigami.Theme.highlightColor : control.Kirigami.Theme.textColor - width: Maui.Style.iconSizes.tiny - height: width - } - - enabled: !mainFlickable.atXBeginning - opacity: enabled ? 1 : 0.4 - onClicked: - { - if(!mainFlickable.atXBeginning) - mainFlickable.contentX -= control.height - if(mainFlickable.atXBeginning) - mainFlickable.returnToBounds() - } - } - - Kirigami.WheelHandler - { - id: wheelHandler - target: mainFlickable - } - - ScrollView - { - id: _scrollView - property bool fits : mainFlickable.contentWidth < control.width - onFitsChanged: mainFlickable.returnToBounds() - - height: control.implicitHeight - width: control.width - - contentWidth: mainFlickable.contentWidth - contentHeight: height - - states: [State - { - when: control.position === ToolBar.Header + opacity: 1 + + Behavior on opacity + { + NumberAnimation + { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } - AnchorChanges + Maui.Triangle { - target: _scrollView - anchors.top: undefined - anchors.bottom: parent.bottom + visible: !Kirigami.Settings.isMobile + anchors.centerIn: parent + rotation: 45 + color: _leftFlickRec.hovered ? control.Kirigami.Theme.highlightColor : control.Kirigami.Theme.textColor + width: Maui.Style.iconSizes.tiny + height: width } - }, - - State - { - when: control.position === ToolBar.Footer - AnchorChanges + enabled: !mainFlickable.atXBeginning + opacity: enabled ? 1 : 0.4 + onClicked: { - target: _scrollView - anchors.top: parent.top - anchors.bottom: undefined + if(!mainFlickable.atXBeginning) + mainFlickable.contentX -= control.height + + if(mainFlickable.atXBeginning) + mainFlickable.returnToBounds() } } - ] - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - ScrollBar.vertical.policy: ScrollBar.AlwaysOff - /* ScrollBar.horizontal: ScrollBar {parent: _scrollView; visible: false;} - * ScrollBar.vertical: ScrollBar {parent: _scrollView; visible: false} */ + Kirigami.WheelHandler + { + id: wheelHandler + target: mainFlickable + } - Flickable + ScrollView { - id: mainFlickable + id: _scrollView + property bool fits : mainFlickable.contentWidth < control.width + onFitsChanged: mainFlickable.returnToBounds() + + height: control.implicitHeight + width: control.width - anchors.fill: parent + contentWidth: mainFlickable.contentWidth + contentHeight: height - anchors.leftMargin: control.margins - anchors.rightMargin: control.margins + states: [State + { + when: control.position === ToolBar.Header + + AnchorChanges + { + target: _scrollView + anchors.top: undefined + anchors.bottom: parent.bottom + } + }, - flickableDirection: Flickable.HorizontalFlick - interactive: !fits && Maui.Handy.isTouch - contentWidth: layout.implicitWidth + State + { + when: control.position === ToolBar.Footer + + AnchorChanges + { + target: _scrollView + anchors.top: parent.top + anchors.bottom: undefined + } + } + ] - boundsBehavior: Kirigami.Settings.isMobile ? Flickable.DragOverBounds : Flickable.StopAtBounds - clip: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AlwaysOff + /* ScrollBar.horizontal: ScrollBar {parent: _scrollView; visible: false;} + * ScrollBar.vertical: ScrollBar {parent: _scrollView; visible: false} */ - RowLayout + Flickable { - id: layout - width: mainFlickable.width - height: mainFlickable.height - spacing: control.spacing + id: mainFlickable + + anchors.fill: parent + + anchors.leftMargin: control.margins + anchors.rightMargin: control.margins + + flickableDirection: Flickable.HorizontalFlick + interactive: !fits && Maui.Handy.isTouch + contentWidth: layout.implicitWidth + + boundsBehavior: Kirigami.Settings.isMobile ? Flickable.DragOverBounds : Flickable.StopAtBounds + clip: true RowLayout { - id: _leftContent - Layout.fillHeight: true - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - spacing: farLeftRowContent.visibleChildren.length > 0 ? control.spacing : 0 + id: layout + width: mainFlickable.width + height: mainFlickable.height + spacing: control.spacing RowLayout { - id: farLeftRowContent - spacing: control.spacing + id: _leftContent Layout.fillHeight: true - Layout.fillWidth: visibleChildren.length > 0 - Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + spacing: farLeftRowContent.visibleChildren.length > 0 ? control.spacing : 0 + + RowLayout + { + id: farLeftRowContent + spacing: control.spacing + Layout.fillHeight: true + Layout.fillWidth: visibleChildren.length > 0 + Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + } + + RowLayout + { + id: leftRowContent + spacing: control.spacing + Layout.fillHeight: true + Layout.fillWidth: visibleChildren.length > 0 + Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + + } + } + + Item //helper to force center middle content + { + visible: control.forceCenterMiddleContent && control.leftSretch + Layout.minimumWidth: 0 + Layout.fillWidth: visible + Layout.maximumWidth: visible ? Math.max(_rightContent.implicitWidth - _leftContent.implicitWidth, 0) : 0 } RowLayout { - id: leftRowContent - spacing: control.spacing + id: middleRowContent + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + spacing: visibleChildren.length > 1 ? control.spacing : 0 Layout.fillHeight: true - Layout.fillWidth: visibleChildren.length > 0 - Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - - } - } - - Item //helper to force center middle content - { - visible: control.forceCenterMiddleContent && control.leftSretch - Layout.minimumWidth: 0 - Layout.fillWidth: visible - Layout.maximumWidth: visible ? Math.max(_rightContent.implicitWidth - _leftContent.implicitWidth, 0) : 0 - } - - RowLayout - { - id: middleRowContent - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - spacing: visibleChildren.length > 1 ? control.spacing : 0 - Layout.fillHeight: true - Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 - Layout.fillWidth: visibleChildren.length > 0 - } - - Item //helper to force center middle content - { - visible: control.forceCenterMiddleContent && control.rightSretch - Layout.minimumWidth: 0 - Layout.fillWidth: visible - Layout.maximumWidth: visible ? Math.max(_leftContent.implicitWidth-_rightContent.implicitWidth, 0) : 0 - } - - RowLayout - { - id: _rightContent - Layout.fillHeight: true - Layout.fillWidth: true - spacing: farRightRowContent.visibleChildren.length > 0 ? control.spacing : 0 - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.fillWidth: visibleChildren.length > 0 + } - RowLayout + Item //helper to force center middle content { - id: rightRowContent - spacing: visibleChildren.length > 1 ? control.spacing : 0 - Layout.fillHeight: true - Layout.fillWidth: visibleChildren.length > 0 - Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + visible: control.forceCenterMiddleContent && control.rightSretch + Layout.minimumWidth: 0 + Layout.fillWidth: visible + Layout.maximumWidth: visible ? Math.max(_leftContent.implicitWidth-_rightContent.implicitWidth, 0) : 0 } RowLayout { - id: farRightRowContent - spacing: visibleChildren.length > 1 ? control.spacing : 0 + id: _rightContent Layout.fillHeight: true - Layout.fillWidth: visibleChildren.length > 0 - Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.fillWidth: true + spacing: farRightRowContent.visibleChildren.length > 0 ? control.spacing : 0 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - } - } - - } + RowLayout + { + id: rightRowContent + spacing: visibleChildren.length > 1 ? control.spacing : 0 + Layout.fillHeight: true + Layout.fillWidth: visibleChildren.length > 0 + Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + RowLayout + { + id: farRightRowContent + spacing: visibleChildren.length > 1 ? control.spacing : 0 + Layout.fillHeight: true + Layout.fillWidth: visibleChildren.length > 0 + Layout.minimumWidth: visibleChildren.length > 0 ? implicitWidth : 0 + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + + } + } + + } + } } - } - + } diff --git a/src/controls/labs/Doodle.qml b/src/controls/labs/Doodle.qml index df78715..1d6066b 100644 --- a/src/controls/labs/Doodle.qml +++ b/src/controls/labs/Doodle.qml @@ -1,416 +1,416 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Maui.Dialog { id: control readonly property color bgColor : "#333" Kirigami.Theme.backgroundColor: Qt.rgba(bgColor.r, bgColor.g, bgColor.b, 0.85) Kirigami.Theme.textColor:"#fefefe" -// deafultButtons: false + // deafultButtons: false + + maxHeight: img.height + maxWidth: img.width - maxHeight: img.height - maxWidth: img.width - property Item sourceItem : null property alias source : img.source property int brushSize :20 property real brushOpacity : 1 property int brushShape : 1 //0 -Circular, 1 - rectangular. property int maxBrushSize: 100 property color paintColor: "red" - + onOpened: { if(control.visible) { if(control.sourceItem) { control.sourceItem.grabToImage(function(result) { - img.source = result.url; - }) + img.source = result.url; + }) } }else { buffer.clear() } } onSourceItemChanged: { - if(control.visible) + if(control.visible) { if(control.sourceItem) { control.sourceItem.grabToImage(function(result) { - img.source = result.url; - }) + img.source = result.url; + }) } } } - + footBar.visible: true footBar.rightContent: ToolButton { icon.name: "document-share" onClicked: {} } footBar.middleContent:[ Maui.ToolActions { autoExclusive: true expanded: true Action { icon.name: "draw-highlight" text: qsTr("Highlighter") onTriggered: { control.paintColor = "yellow" control.brushOpacity = 0.7 control.brushShape = 1 control.brushSize = 30 } } Action { icon.name: "draw-brush" text: qsTr("Marker") onTriggered: { control.paintColor = "blue" control.brushOpacity = 0.9 control.brushShape = 0 control.brushSize = 20 } } Action { icon.name: "draw-calligraphic" text: qsTr("Highlighter") onTriggered: { control.paintColor = "#333" control.brushOpacity = 0.95 control.brushShape = 1 control.brushSize = 10 } } }, Maui.ToolActions { autoExclusive: true expanded: true Action { icon.name: "draw-rectangle" } Action { icon.name: "draw-circle" } Action { icon.name: "draw-circle" } }, ToolButton { icon.name: "draw-watercolor" }, ToolButton { icon.name: "draw-eraser" }, ToolButton { icon.name: "edit-opacity" } ] headBar.visible: false ScrollView { Layout.fillHeight: true Layout.fillWidth: true - contentHeight: img.height - contentWidth: img.width + contentHeight: img.height + contentWidth: img.width Image { id: img height: sourceSize.height width: sourceSize.width fillMode: Image.PreserveAspectFit autoTransform: true asynchronous: true anchors.centerIn: parent Canvas { id: pickCanvas width: 1 height: 1 visible: false } - -// Label -// { -// color: "yellow" -// text: parent.height + "-" + parent.width + " / " + control.height + "-" + control.width + " / " + buffer.width + "-"+ buffer.height -// } - + + // Label + // { + // color: "yellow" + // text: parent.height + "-" + parent.width + " / " + control.height + "-" + control.width + " / " + buffer.width + "-"+ buffer.height + // } + Canvas { id: buffer anchors.fill: parent property real lastX property real lastY property color paintColor: control.paintColor smooth: false opacity: control.brushOpacity // Stroke Opacity while drawing function clear() { var bufferCtx = buffer.getContext("2d") bufferCtx.clearRect(0, 0, width, height) buffer.requestPaint() } MouseArea { id: mouseArea anchors.fill: parent propagateComposedEvents: false preventStealing: true property int spacing: 32 property real deltaDab: Math.max(spacing / 100 * control.brushSize, 1) property var points: [] property point lastDrawPoint property point startPos property point finalPos property real brushAngle: 0 onPressed: { var point = Qt.point(mouseX, mouseY) points = [] startPos = Qt.point(point.x, point.y) finalPos = Qt.point(point.x, point.y) lastDrawPoint = point if (control.brushShape != 1) {//if brush is not square drawDab(point) } points = [] points.push(point) //Hide Color Picker later move it to the whole screen. // colorPicker.visible = false } onPositionChanged: { drawDab(Qt.point(mouseX, mouseY)) // **************** Fancy and intense bezier I don't quite understand yet: var currentPoint = Qt.point(mouseX, mouseY) var startPoint = lastDrawPoint //Rotating the dab if brush is recangular. if (control.brushShape == 1) { spacing = 16 if ( (currentPoint.x > startPoint.x)) { // dab.brushAngle = find_angle(Qt.point(startPoint.x, startPoint.y-10), // startPoint, currentPoint) // dab.requestPaint() brushAngle = find_angle(Qt.point(startPoint.x, startPoint.y-10),startPoint, currentPoint) } else { // dab.brushAngle = - find_angle(Qt.point(startPoint.x, startPoint.y-10), // startPoint, currentPoint) // dab.requestPaint() brushAngle = - find_angle(Qt.point(startPoint.x, startPoint.y-10),startPoint, currentPoint) } } else { spacing = 32 } // ## var currentSpacing = Math.sqrt(Math.pow(currentPoint.x - startPoint.x, 2) + Math.pow(currentPoint.y - startPoint.y, 2)) var numDabs = Math.floor(currentSpacing / deltaDab) if (points.length == 1 || numDabs < 3) { var endPoint = currentPoint } else { var controlPoint = points[points.length - 1] endPoint = Qt.point((controlPoint.x + currentPoint.x) / 2, (controlPoint.y + currentPoint.y) / 2) } var deltaT = 1 / numDabs var betweenPoint = startPoint var t = deltaT var diff while (t > 0 && t <= 1) { var point = bezierCurve(startPoint, controlPoint, endPoint, t) var deltaPoint = Math.sqrt(Math.pow(point.x - betweenPoint.x, 2) + Math.pow(point.y - betweenPoint.y, 2)) // check on bezier loop if (diff && Math.abs(deltaPoint - deltaDab) > Math.abs(diff)) { break; } diff = deltaPoint - deltaDab if (Math.abs(diff <= 0.5)) { drawDab(point) diff = undefined betweenPoint = point t += deltaT } else { t -= diff / deltaDab * deltaT } } points.push(currentPoint) lastDrawPoint = betweenPoint } onReleased: { var bufferCtx = buffer.getContext("2d") //saving image // Grab Buffer image var bufferImage = bufferCtx.getImageData(0, 0, width, height) // Auto save painting // saveDrawing() // Clear the buffer buffer.requestPaint() } function drawDab(point) { var ctx = buffer.getContext("2d") //Bezier Dab // ctx.save() // var size = toolbar.maxBrushSize //toolbar.brushSize // var x = point.x - size / 2 // var y = point.y - size / 2 // if (x < startPos.x) { startPos.x = Math.min(0, x) } // if (y < startPos.y) { startPos.y = Math.min(0, y) } // if (x > finalPos.x) { finalPos.x = Math.max(x, buffer.width) } // if (y > finalPos.y) { finalPos.y = Math.max(y, buffer.height) } // ctx.drawImage(dab, x, y) // ctx.restore() // buffer.requestPaint() //Raster Circle: //ctx.drawImage("brushes/circle.png", x, y, size, size) //Simple dab var size = control.brushSize ctx.fillStyle = control.paintColor var x = point.x - size / 2 var y = point.y - size / 2 if (control.brushShape == 0) { ctx.beginPath(); x = point.x - size/8 y = point.y - size/8 ctx.arc(x, y, size/2 ,0,Math.PI*2,true); } else { ctx.save() ctx.translate(x+size/2,y+size/2) ctx.beginPath() ctx.rotate(brushAngle) ctx.roundedRect(-size/4, -size/8, size/2, size/4, 2, 2) ctx.restore() } ctx.fill() buffer.requestPaint() } } } } } // Bezier Curve function bezierCurve(start, control, end, t) { var x, y // linear bezier curve if (!control) { x = (1 - t) * start.x + t * end.x y = (1 - t) * start.y + t * end.y } // quad bezier curve else { x = Math.pow((1 - t), 2) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x y = Math.pow((1 - t), 2) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y } return Qt.point(x, y) } // Convert RGB to HEX function rgbToHex(r, g, b) { if (r > 255 || g > 255 || b > 255) throw "Invalid color component"; return ((r << 16) | (g << 8) | b).toString(16); } function find_angle(A,B,C) { var AB = Math.sqrt(Math.pow(B.x-A.x,2)+ Math.pow(B.y-A.y,2)); var BC = Math.sqrt(Math.pow(B.x-C.x,2)+ Math.pow(B.y-C.y,2)); var AC = Math.sqrt(Math.pow(C.x-A.x,2)+ Math.pow(C.y-A.y,2)); return Math.acos((BC*BC+AB*AB-AC*AC)/(2*BC*AB)); } } diff --git a/src/controls/labs/Page.qml b/src/controls/labs/Page.qml index d89fd56..80017c6 100644 --- a/src/controls/labs/Page.qml +++ b/src/controls/labs/Page.qml @@ -1,605 +1,611 @@ /* * Copyright 2019 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 Pane { id: control focus: true padding: 0 leftPadding: control.padding rightPadding: control.padding topPadding: control.padding bottomPadding: control.padding default property alias content: _content.data property alias headerBackground : _headerBackground readonly property alias internalHeight : _content.height property Flickable flickable : null property int footerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineFooter property int headerPositioning : Kirigami.Settings.isMobile && flickable ? ListView.PullBackHeader : ListView.InlineHeader property string title property int margins: 0 property int leftMargin : margins property int rightMargin: margins property int topMargin: margins property int bottomMargin: margins property bool altHeader : false property bool autoHideHeader : false property bool floatingHeader : control.flickable && control.headerPositioning === ListView.InlineHeader ? !control.flickable.atYBeginning && control.flickable.contentHeight > control.height : false property bool floatingFooter : control.flickable && control.footerPositioning === ListView.InlineFooter ? !control.flickable.atYEnd : false property bool showTitle : true property alias headBar : _headBar property alias footBar: _footBar Kirigami.Theme.colorSet: Kirigami.Theme.View signal goBackTriggered() signal goForwardTriggered() background: Rectangle { color: Kirigami.Theme.backgroundColor } onFlickableChanged: returnToBounds() Connections { target: control.flickable ? control.flickable : null enabled: control.flickable && ((control.header && control.headerPositioning === ListView.PullBackHeader) || (control.footer && control.footerPositioning === ListView.PullBackFooter)) property int oldContentY property bool updatingContentY: false onContentYChanged: { _headerAnimation.enabled = false if(!control.flickable.dragging && control.flickable.atYBeginning) { control.returnToBounds() } if (updatingContentY || !control.flickable || !control.flickable.dragging) { oldContentY = control.flickable.contentY; return; //TODO: merge //if moves but not dragging, just update oldContentY } if(control.flickable.contentHeight < control.height) { return } var oldFHeight var oldHHeight if (control.footer && control.footerPositioning === ListView.PullBackFooter && control.footer.visible) { oldFHeight = control.footer.height control.footer.height = Math.max(0, Math.min(control.footer.implicitHeight, control.footer.height + oldContentY - control.flickable.contentY)); } if (control.header && control.headerPositioning === ListView.PullBackHeader && control.header.visible) { oldHHeight = control.header.height control.header.height = Math.max(0, Math.min(control.header.implicitHeight, control.header.height + oldContentY - control.flickable.contentY)); } //if the implicitHeight is changed, use that to simulate scroll if (control.header && oldHHeight !== control.header.height && control.header.visible) { updatingContentY = true control.flickable.contentY -= (oldHHeight - control.header.height) updatingContentY = false } else { oldContentY = control.flickable.contentY } } onMovementEnded: { if (control.header && control.header.visible && control.headerPositioning === ListView.PullBackHeader ) { _headerAnimation.enabled = true if (control.header.height >= (control.header.implicitHeight/2) || control.flickable.atYBeginning ) { control.header.height = control.header.implicitHeight } else { control.header.height = 0 } } if (control.footer && control.footer.visible && control.footerPositioning === ListView.PullBackFooter) { if (control.footer.height >= (control.footer.implicitHeight/2) || control.flickable.atYEnd) { if(control.flickable.atYEnd) { control.footer.height = control.footer.implicitHeight control.flickable.contentY = control.flickable.contentHeight - control.flickable.height oldContentY = control.flickable.contentY }else { control.footer.height = control.footer.implicitHeight } } else { control.footer.height = 0 } } } } /* Component.onCompleted: { if(control.header && control.header instanceof Maui.ToolBar) { control.header.visible = header.visibleCount > 0 } }*/ property Item header : Maui.ToolBar { id: _headBar visible: visibleCount > 0 width: visible ? parent.width : 0 height: visible ? implicitHeight : 0 Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Window /** to not break the visible binding just check the count state of the header and act upon it **/ // readonly property bool hide : visibleCount === 0 // onHideChanged: // { // if(!header.visible) // { // return // } // // if(hide) // { // pullBackHeader() // }else // { // pullDownHeader() // } // } // Label // { // visible: false // color: "yellow" // text: _headBar.visibleCount + " / " + _headBar.count + " - " + _headBar.height + " / " + header.height + " - " + _headBar.visible + " / " + header.visible // } Behavior on height { id: _headerAnimation enabled: false NumberAnimation { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad } } Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad } } Component { id: _titleComponent Label { text: control.title elide : Text.ElideRight font.bold : false font.weight: Font.Bold color : Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.big horizontalAlignment : Text.AlignHCenter verticalAlignment : Text.AlignVCenter } } middleContent: Loader { visible: item Layout.fillWidth: sourceComponent === _titleComponent Layout.fillHeight: sourceComponent === _titleComponent sourceComponent: control.title && control.showTitle ? _titleComponent : null } background: Rectangle { id: _headerBackground color: _headBar.Kirigami.Theme.backgroundColor Kirigami.Separator { id: _border opacity: 0.6 color: Qt.darker(parent.color, 2) anchors.left: parent.left anchors.right: parent.right } Kirigami.Separator { id: _border2 opacity: 0.4 color: Qt.lighter(parent.color, 2.5) anchors.left: parent.left anchors.right: parent.right anchors.bottomMargin: 1 } FastBlur { anchors.fill: parent visible: control.floatingHeader && !altHeader opacity: 0.25 transparentBorder: false source: ShaderEffectSource { - // cullMode: ShaderEffect.FrontFaceCulling - // hideSource: true samples : 0 recursive: true sourceItem: _content sourceRect: Qt.rect(0, 0-control.topMargin, headBar.width, headBar.height) - // textureSize: Qt.size(headBar.width,headBar.height) } radius: 64 } } } +// Label +// { +// // visible: false +// z: 999999999999 +// color: "yellow" +// text: _footBar.visibleCount + " / " + _footBar.count + " - " + _footBar.height + " / " + footer.height + " - " + _footBar.visible + " / " + footer.visible +// } + property Item footer : Maui.ToolBar { id: _footBar - visible: _footBar.visibleCount > 0 - position: ToolBar.Footer + visible: visibleCount > 0 width: visible ? parent.width : 0 height: visible ? implicitHeight : 0 + position: ToolBar.Footer + background: Rectangle { color: _footBar.Kirigami.Theme.backgroundColor Kirigami.Separator { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right } FastBlur { anchors.fill: parent visible: control.floatingFooter opacity: 0.4 transparentBorder: false source: ShaderEffectSource { samples : 0 recursive: true sourceItem: _content sourceRect: Qt.rect(0, control.height - (footBar.height), footBar.width, footBar.height) } radius: 64 } } } states: [ State { when: !altHeader && header.visible AnchorChanges { target: _headerContent anchors.top: parent.top anchors.bottom: undefined } AnchorChanges { target: _border anchors.top: undefined anchors.bottom: parent.bottom } AnchorChanges { target: _border2 anchors.top: undefined anchors.bottom: parent.bottom } PropertyChanges { target: _layout anchors.topMargin: control.floatingHeader ? 0 : _headerContent.height anchors.bottomMargin: 0 } PropertyChanges { target: _headBar position: ToolBar.Header } }, State { when: altHeader && header.visible AnchorChanges { target: _headerContent anchors.top: undefined anchors.bottom: parent.bottom } AnchorChanges { target: _border anchors.top: parent.top anchors.bottom: undefined } AnchorChanges { target: _border2 anchors.top: parent.top anchors.bottom: undefined } PropertyChanges { target: _layout anchors.topMargin: 0 anchors.bottomMargin: header.height } PropertyChanges { target: header height: header.implicitHeight } PropertyChanges { target: _headBar position: ToolBar.Footer } } ] // transitions: Transition { // // smoothly reanchor myRect and move into new position // AnchorAnimation { duration: 1000 } // } Column { id: _headerContent anchors.left: parent.left anchors.right: parent.right children: header z: _content.z+9999 } // Label // { // anchors.centerIn: _headerContent // text: header.height + "/" + _headerContent.height + " - " + _layout.anchors.topMargin // color: "orange" // z: _headerContent.z + 1 // visible: header.visible // } Item { id: _layout anchors.fill: parent Item { id: _content anchors.fill: parent anchors.margins: control.margins anchors.leftMargin: control.leftMargin anchors.rightMargin: control.rightMargin anchors.topMargin: control.topMargin anchors.bottomMargin: control.bottomMargin + (control.floatingFooter ? 0 : _footerContent.height) } Column { id: _footerContent anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom children: footer } } Timer { id: _timer interval: 1000 onTriggered: { if(control.autoHideHeader) { pullBackHeader() } stop() } } Item { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: _headerContent.height + Maui.Style.toolBarHeight z: _content.z + 9999 visible: control.autoHideHeader && !control.altHeader && !Kirigami.Settings.isMobile HoverHandler { target: parent acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus onHoveredChanged: { if(!control.autoHideHeader) { return } if(!hovered) { _timer.start() }else { pullDownHeader() _timer.stop() } } } } // Item // { // anchors.fill: parent // anchors.topMargin: header.height // anchors.bottomMargin: footer.height // z: _content.z + 9999 // // TapHandler // { // target: parent // enabled: control.autoHideHeader && !control.altHeader // // grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.ApprovesTakeOverByHandlersOfSameType | PointerHandler.CanTakeOverFromAnything // // onSingleTapped: // { // if(!control.autoHideHeader) // { // return // } // console.log("Pgae tapped") // header.visible = !header.visible // } // } // } Keys.onBackPressed: { control.goBackTriggered(); } Shortcut { sequence: "Forward" onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Forward onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Back onActivated: control.goBackTriggered(); } function returnToBounds() { if(control.header) { control.header.height = control.header.implicitHeight } if(control.footer) { control.footer.height = control.footer.implicitHeight } } function pullBackHeader() { _headerAnimation.enabled = true header.height= 0 } function pullDownHeader() { _headerAnimation.enabled = true header.height = header.implicitHeight } } diff --git a/src/controls/private/AboutDialog.qml b/src/controls/private/AboutDialog.qml index 8cdf8ae..5b6284b 100644 --- a/src/controls/private/AboutDialog.qml +++ b/src/controls/private/AboutDialog.qml @@ -1,246 +1,247 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.10 import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.12 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Dialog { id: control defaultButtons: false widthHint: 0.9 heightHint: 0.8 maxWidth: Maui.Style.unit * 400 maxHeight: Maui.Style.unit * 250 page.padding: 0 - + footBar.visible: true footBar.middleContent: ToolButton { icon.name: "link" + visible: true onClicked: Qt.openUrlExternally(Maui.App.webPage) } footBar.rightContent: ToolButton { icon.name: "love" onClicked: Qt.openUrlExternally(Maui.App.donationPage) } footBar.leftContent: ToolButton { icon.name: "documentinfo" onClicked: Qt.openUrlExternally(Maui.App.reportPage) } RowLayout { id: layout Layout.fillWidth: true Layout.fillHeight: true spacing: Maui.Style.space.medium Item { visible: parent.width > control.maxWidth * 0.7 Layout.fillHeight: true Layout.margins: Maui.Style.space.medium Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: Maui.Style.iconSizes.huge + Maui.Style.space.big Image { id: _imgIcon anchors.centerIn: parent source: Maui.App.iconName width: Math.min(Maui.Style.iconSizes.huge, parent.width) height: width sourceSize.width: width sourceSize.height: height asynchronous: true fillMode: Image.PreserveAspectFit } DropShadow { anchors.fill: _imgIcon horizontalOffset: 0 verticalOffset: 0 radius: 8.0 samples: 17 color: "#80000000" source: _imgIcon } } Kirigami.ScrollablePage { id: _descriptionItem Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignLeft | Qt.AlignTop Kirigami.Theme.backgroundColor: "transparent" padding: Maui.Style.space.medium leftPadding: padding rightPadding: padding topPadding: padding*3 bottomPadding: padding ColumnLayout { id: _columnInfo width: parent.width spacing: Maui.Style.space.medium Label { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft color: Kirigami.Theme.textColor text: Maui.App.displayName font.weight: Font.Bold font.bold: true font.pointSize: Maui.Style.fontSizes.enormous elide: Text.ElideRight wrapMode: Text.NoWrap } Label { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft color: Qt.lighter(Kirigami.Theme.textColor, 1.2) text: Maui.App.version font.weight: Font.Light font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Label { id: body Layout.fillWidth: true text: Maui.App.description color: Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Label { color: Kirigami.Theme.textColor Layout.fillWidth: true text: qsTr("By ") + Maui.App.org font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Kirigami.Separator { Layout.fillWidth: true Layout.margins: Maui.Style.space.tiny opacity: 0.4 } Label { visible: _creditsRepeater.count > 0 color: Kirigami.Theme.textColor Layout.fillWidth: true text: qsTr("Credits") font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Repeater { id: _creditsRepeater model: Maui.App.credits Column { Label { color: Kirigami.Theme.textColor Layout.fillWidth: true text: modelData.name font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Label { color: Kirigami.Theme.textColor Layout.fillWidth: true text: modelData.email font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Label { color: Kirigami.Theme.textColor Layout.fillWidth: true text: modelData.year font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } } } Kirigami.Separator { Layout.fillWidth: true Layout.margins: Maui.Style.space.tiny opacity: 0.4 } Label { color: Kirigami.Theme.textColor Layout.fillWidth: true text: qsTr("Powered by") + " MauiKit " + Maui.App.mauikitVersion + " and Kirigami" font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere onLinkActivated: Qt.openUrlExternally(link) } } } } }