diff --git a/images/icons/ic_content_copy.svg b/images/icons/ic_content_copy.svg deleted file mode 100644 index f23e8f28ac310d46eb191de81ab0eb4512b8f757..0000000000000000000000000000000000000000 --- a/images/icons/ic_content_copy.svg +++ /dev/null @@ -1,60 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve"> -<g id="Text-files"> - <path d="M53.9791489,9.1429005H50.010849c-0.0826988,0-0.1562004,0.0283995-0.2331009,0.0469999V5.0228 - C49.7777481,2.253,47.4731483,0,44.6398468,0h-34.422596C7.3839517,0,5.0793519,2.253,5.0793519,5.0228v46.8432999 - c0,2.7697983,2.3045998,5.0228004,5.1378999,5.0228004h6.0367002v2.2678986C16.253952,61.8274002,18.4702511,64,21.1954517,64 - h32.783699c2.7252007,0,4.9414978-2.1725998,4.9414978-4.8432007V13.9861002 - C58.9206467,11.3155003,56.7043495,9.1429005,53.9791489,9.1429005z M7.1110516,51.8661003V5.0228 - c0-1.6487999,1.3938999-2.9909999,3.1062002-2.9909999h34.422596c1.7123032,0,3.1062012,1.3422,3.1062012,2.9909999v46.8432999 - c0,1.6487999-1.393898,2.9911003-3.1062012,2.9911003h-34.422596C8.5049515,54.8572006,7.1110516,53.5149002,7.1110516,51.8661003z - M56.8888474,59.1567993c0,1.550602-1.3055,2.8115005-2.9096985,2.8115005h-32.783699 - c-1.6042004,0-2.9097996-1.2608986-2.9097996-2.8115005v-2.2678986h26.3541946 - c2.8333015,0,5.1379013-2.2530022,5.1379013-5.0228004V11.1275997c0.0769005,0.0186005,0.1504021,0.0469999,0.2331009,0.0469999 - h3.9682999c1.6041985,0,2.9096985,1.2609005,2.9096985,2.8115005V59.1567993z"/> - <path d="M38.6031494,13.2063999H16.253952c-0.5615005,0-1.0159006,0.4542999-1.0159006,1.0158005 - c0,0.5615997,0.4544001,1.0158997,1.0159006,1.0158997h22.3491974c0.5615005,0,1.0158997-0.4542999,1.0158997-1.0158997 - C39.6190491,13.6606998,39.16465,13.2063999,38.6031494,13.2063999z"/> - <path d="M38.6031494,21.3334007H16.253952c-0.5615005,0-1.0159006,0.4542999-1.0159006,1.0157986 - c0,0.5615005,0.4544001,1.0159016,1.0159006,1.0159016h22.3491974c0.5615005,0,1.0158997-0.454401,1.0158997-1.0159016 - C39.6190491,21.7877007,39.16465,21.3334007,38.6031494,21.3334007z"/> - <path d="M38.6031494,29.4603004H16.253952c-0.5615005,0-1.0159006,0.4543991-1.0159006,1.0158997 - s0.4544001,1.0158997,1.0159006,1.0158997h22.3491974c0.5615005,0,1.0158997-0.4543991,1.0158997-1.0158997 - S39.16465,29.4603004,38.6031494,29.4603004z"/> - <path d="M28.4444485,37.5872993H16.253952c-0.5615005,0-1.0159006,0.4543991-1.0159006,1.0158997 - s0.4544001,1.0158997,1.0159006,1.0158997h12.1904964c0.5615025,0,1.0158005-0.4543991,1.0158005-1.0158997 - S29.0059509,37.5872993,28.4444485,37.5872993z"/> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -</svg> diff --git a/qml.qrc b/qml.qrc index b557894c6414f726f9b8e094d7ef0cdf489fa682..12976b38175789779c2cfa0d1f17133f87dc5157 100644 --- a/qml.qrc +++ b/qml.qrc @@ -138,5 +138,6 @@ <file>src/mainview/components/ParticipantOverlayMenu.qml</file> <file>src/commoncomponents/DaemonReconnectPopup.qml</file> <file>src/DaemonReconnectWindow.qml</file> + <file>src/commoncomponents/LineEditContextMenu.qml</file> </qresource> </RCC> diff --git a/resources.qrc b/resources.qrc index 6c4b30e12760ccbe683a914118c278d1ed141a0c..07f0551f8dd5ad5467c97ca3a3bd9bc9ed0f80e7 100644 --- a/resources.qrc +++ b/resources.qrc @@ -41,7 +41,6 @@ <file>images/icons/ic_check_white_18dp_2x.png</file> <file>images/icons/ic_clear_24px.svg</file> <file>images/icons/ic_close_white_24dp.png</file> - <file>images/icons/ic_content_copy.svg</file> <file>images/icons/ic_delete_black_18dp_2x.png</file> <file>images/icons/ic_done_white_24dp.png</file> <file>images/icons/ic_keypad.svg</file> diff --git a/src/commoncomponents/GeneralMenuItem.qml b/src/commoncomponents/GeneralMenuItem.qml index 57701221410354049d6abe6b6760318c5b83ff8b..ac588ae34a2b468b3e48ccc52663bff056cd4fca 100644 --- a/src/commoncomponents/GeneralMenuItem.qml +++ b/src/commoncomponents/GeneralMenuItem.qml @@ -53,6 +53,7 @@ MenuItem { } anchors.fill: parent + ResponsiveImage { id: contextMenuItemImage @@ -72,8 +73,9 @@ MenuItem { id: contextMenuItemText anchors.left: contextMenuItemImage.right - anchors.leftMargin: 20 + anchors.leftMargin: contextMenuItemImage.visible ? 20 : 5 anchors.verticalCenter: menuItemContentRect.verticalCenter + width: contextMenuItemImage.visible ? (preferredWidth - contextMenuItemImage.width - 58) : preferredWidth - 24 diff --git a/src/commoncomponents/LineEditContextMenu.qml b/src/commoncomponents/LineEditContextMenu.qml new file mode 100644 index 0000000000000000000000000000000000000000..c4e0d780afaa956ea21502962975bfc823470601 --- /dev/null +++ b/src/commoncomponents/LineEditContextMenu.qml @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * 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 3 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, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtGraphicalEffects 1.14 + +import net.jami.Models 1.0 +import net.jami.Adapters 1.0 +import net.jami.Constants 1.0 + +import "js/contextmenugenerator.js" as ContextMenuGenerator + +Item { + id: root + + function openMenu(lineEditObj, mouseEvent) { + ContextMenuGenerator.initMenu(Qt.size(150, 25), 2) + + if (lineEditObj.selectedText.length) { + ContextMenuGenerator.addMenuItem(qsTr("Copy"), + "", + function (){ + lineEditObj.copy() + }) + + ContextMenuGenerator.addMenuItem(qsTr("Cut"), + "", + function (){ + lineEditObj.cut() + }) + } + + ContextMenuGenerator.addMenuItem(qsTr("Paste"), + "", + function (){ + lineEditObj.paste() + }) + + root.height = ContextMenuGenerator.getMenu().height + root.width = ContextMenuGenerator.getMenu().width + ContextMenuGenerator.getMenu().x = mouseEvent.x + ContextMenuGenerator.getMenu().y = mouseEvent.y + + // lineEdit (TextEdit) selection will be lost when menu is opened + var selectionStartTemp = lineEditObj.selectionStart + var selectionEndTemp = lineEditObj.selectionEnd + + ContextMenuGenerator.getMenu().open() + + lineEditObj.select(selectionStartTemp, selectionEndTemp) + } + + Component.onCompleted: { + ContextMenuGenerator.createBaseContextMenuObjects(root) + } +} diff --git a/src/commoncomponents/MaterialLineEdit.qml b/src/commoncomponents/MaterialLineEdit.qml index 5cf627ee71ef24d428ee46fe7c8cd36e92637325..0b72d683a426b7f255ab9b58d6260db927f14433 100644 --- a/src/commoncomponents/MaterialLineEdit.qml +++ b/src/commoncomponents/MaterialLineEdit.qml @@ -24,6 +24,8 @@ import QtGraphicalEffects 1.14 import net.jami.Constants 1.0 TextField { + id: root + enum BorderColorMode { NORMAL, SEARCHING, @@ -71,6 +73,7 @@ TextField { wrapMode: Text.Wrap readOnly: false selectByMouse: true + selectionColor: JamiTheme.contactSearchBarPlaceHolderTextFontColor font.pointSize: 10 padding: 16 font.kerning: true @@ -78,6 +81,10 @@ TextField { verticalAlignment: Text.AlignVCenter color: JamiTheme.textColor + LineEditContextMenu { + id: lineEditContextMenu + } + Image { id: lineEditImage @@ -127,8 +134,14 @@ TextField { background: Rectangle { anchors.fill: parent - radius: 4 + + radius: JamiTheme.lineEditRadius border.color: readOnly? "transparent" : borderColor color: readOnly? "transparent" : backgroundColor } + + onReleased: { + if (event.button == Qt.RightButton) + lineEditContextMenu.openMenu(root, event) + } } diff --git a/src/commoncomponents/js/contextmenugenerator.js b/src/commoncomponents/js/contextmenugenerator.js index ef93c309152566e0239fac9b8b162cf2a5b166cf..4f5848e7572c01f1b3dbc37485de3d026749a3c9 100644 --- a/src/commoncomponents/js/contextmenugenerator.js +++ b/src/commoncomponents/js/contextmenugenerator.js @@ -20,14 +20,14 @@ var baseContextMenuComponent var baseContextMenuObject var menuItemList = [] +var menuDefaultSeparatorHeight = 8 function createBaseContextMenuObjects(parent) { // If already created, return, since object cannot be destroyed. if (baseContextMenuObject) return - baseContextMenuComponent = Qt.createComponent( - "../BaseContextMenu.qml") + baseContextMenuComponent = Qt.createComponent("../BaseContextMenu.qml") if (baseContextMenuComponent.status === Component.Ready) finishCreation(parent) else if (baseContextMenuComponent.status === Component.Error) @@ -35,13 +35,6 @@ function createBaseContextMenuObjects(parent) { baseContextMenuComponent.errorString()) } -function initMenu() { - // Clear any existing items in the menu. - for (var i = 0; i < menuItemList.length; i++) { - baseContextMenuObject.removeItem(menuItemList[i]) - } -} - function finishCreation(parent) { baseContextMenuObject = baseContextMenuComponent.createObject(parent) if (baseContextMenuObject === null) { @@ -49,27 +42,45 @@ function finishCreation(parent) { console.log("Error creating object for base context menu") } - baseContextMenuObject.closed.connect(function (){ + baseContextMenuObject.closed.connect(function () { // Remove the menu items when hidden. for (var i = 0; i < menuItemList.length; i++) { baseContextMenuObject.removeItem(menuItemList[i]) } }) - baseContextMenuObject.aboutToShow.connect(function (){ + baseContextMenuObject.aboutToShow.connect(function () { // Add default separator at the bottom. - addMenuSeparator(8, "transparent") + addMenuSeparator(menuDefaultSeparatorHeight, "transparent") }) } +function initMenu(preferedMenuItemSize, defaultSeparatorHeight) { + // Clear any existing items in the menu. + for (var i = 0; i < menuItemList.length; i++) { + baseContextMenuObject.removeItem(menuItemList[i]) + } + + if (preferedMenuItemSize) { + baseContextMenuObject.menuItemsPreferredWidth = preferedMenuItemSize.width + baseContextMenuObject.menuItemsPreferredHeight = preferedMenuItemSize.height + } + + if (defaultSeparatorHeight) + menuDefaultSeparatorHeight = defaultSeparatorHeight +} + function addMenuSeparator(separatorHeight, separatorColor) { var menuSeparatorObject - var menuSeparatorComponent = Qt.createComponent("../GeneralMenuSeparator.qml"); + var menuSeparatorComponent = Qt.createComponent( + "../GeneralMenuSeparator.qml") if (menuSeparatorComponent.status === Component.Ready) { - baseContextMenuObject.generalMenuSeparatorCount ++ - menuSeparatorObject = menuSeparatorComponent.createObject(null, - {preferredWidth: baseContextMenuObject.menuItemsPreferredWidth, - preferredHeight: separatorHeight ? separatorHeight : 1}) + baseContextMenuObject.generalMenuSeparatorCount++ + menuSeparatorObject = menuSeparatorComponent.createObject( + null, { + "preferredWidth": baseContextMenuObject.menuItemsPreferredWidth, + "preferredHeight": separatorHeight ? separatorHeight : 1 + }) if (separatorColor) menuSeparatorObject.separatorColor = separatorColor } else if (menuSeparatorComponent.status === Component.Error) @@ -85,30 +96,30 @@ function addMenuSeparator(separatorHeight, separatorColor) { } } -function addMenuItem(itemName, - iconSource, - onClickedCallback, - iconColor="") { - if (!baseContextMenuObject.count){ +function addMenuItem(itemName, iconSource, onClickedCallback, iconColor) { + if (!baseContextMenuObject.count) { // Add default separator at the top. - addMenuSeparator(8, "transparent") + addMenuSeparator(menuDefaultSeparatorHeight, "transparent") } var menuItemObject - var menuItemComponent = Qt.createComponent("../GeneralMenuItem.qml"); + var menuItemComponent = Qt.createComponent("../GeneralMenuItem.qml") if (menuItemComponent.status === Component.Ready) { - menuItemObject = menuItemComponent.createObject(null, - {itemName: itemName, - iconSource: iconSource, - iconColor: iconColor, - leftBorderWidth: baseContextMenuObject.commonBorderWidth, - rightBorderWidth: baseContextMenuObject.commonBorderWidth}) + menuItemObject = menuItemComponent.createObject( + null, { + "itemName": itemName, + "iconSource": iconSource, + "iconColor": iconColor, + "preferredWidth": baseContextMenuObject.menuItemsPreferredWidth, + "preferredHeight": baseContextMenuObject.menuItemsPreferredHeight, + "leftBorderWidth": baseContextMenuObject.commonBorderWidth, + "rightBorderWidth": baseContextMenuObject.commonBorderWidth + }) } else if (menuItemComponent.status === Component.Error) - console.log("Error loading component:", - menuItemComponent.errorString()) + console.log("Error loading component:", menuItemComponent.errorString()) if (menuItemObject !== null) { menuItemObject.clicked.connect(function () { - var callback = function(){ + var callback = function () { onClickedCallback() baseContextMenuObject.onVisibleChanged.disconnect(callback) baseContextMenuObject.close() diff --git a/src/mainview/components/ContactSearchBar.qml b/src/mainview/components/ContactSearchBar.qml index 5e05c0421f7ca9e9388e7d6f94b9d1f401b48cf8..dce87787b6038356798f78bc3a45247f4fd985bb 100644 --- a/src/mainview/components/ContactSearchBar.qml +++ b/src/mainview/components/ContactSearchBar.qml @@ -46,6 +46,10 @@ Rectangle { id: fakeFocus } + LineEditContextMenu { + id: lineEditContextMenu + } + Image { id: searchIconImage @@ -94,6 +98,10 @@ Rectangle { } onTextChanged: root.contactSearchBarTextChanged(contactSearchBar.text) + onReleased: { + if (event.button == Qt.RightButton) + lineEditContextMenu.openMenu(contactSearchBar, event) + } } PushButton { diff --git a/src/mainview/components/WelcomePage.qml b/src/mainview/components/WelcomePage.qml index 5b6c178b1482fae4a8fe9530eea1ce4220717830..6fd63d404b0f896d9c5150430c86003ca3c5ef49 100644 --- a/src/mainview/components/WelcomePage.qml +++ b/src/mainview/components/WelcomePage.qml @@ -146,7 +146,7 @@ Rectangle { source: "qrc:/images/icons/content_copy-24px.svg" onClicked: { - UtilsAdapter.setText( + UtilsAdapter.setClipboardText( textMetricsjamiRegisteredNameText.text) } } diff --git a/src/utilsadapter.cpp b/src/utilsadapter.cpp index e09c3be282202278702dcb773c6ff94575ad4aa7..dafd36a0901a660a7258973e66a61bd7c825ef34 100644 --- a/src/utilsadapter.cpp +++ b/src/utilsadapter.cpp @@ -50,7 +50,7 @@ UtilsAdapter::getVersionStr() } void -UtilsAdapter::setText(QString text) +UtilsAdapter::setClipboardText(QString text) { clipboard_->setText(text, QClipboard::Clipboard); } diff --git a/src/utilsadapter.h b/src/utilsadapter.h index 82daf6292f177de26d417d3097e942499e603449..50909b90487bb609534ae0d0fe6124c3360583ba 100644 --- a/src/utilsadapter.h +++ b/src/utilsadapter.h @@ -41,7 +41,7 @@ public: Q_INVOKABLE const QString getProjectCredits(); Q_INVOKABLE const QString getVersionStr(); - Q_INVOKABLE void setText(QString text); + Q_INVOKABLE void setClipboardText(QString text); Q_INVOKABLE const QString qStringFromFile(const QString& filename); Q_INVOKABLE const QString getStyleSheet(const QString& name, const QString& source); Q_INVOKABLE const QString getCachePath();