import QtGraphicalEffects 1.0 import QtQuick 2.13 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.0 import QtQuick.Layouts 1.3 import Qt.labs.folderlistmodel 2.13 import QtQml.Models 2.13 import "fonts/MutantStandard.js" as Mutant import "controls" import "theme" Item { id: root implicitHeight: 0 height: implicitHeight property int size: 32 property int requestedHeight: size * 8 property string morph: "clw" property string color: "v1" // can't bind to the width of the category bar when narrow=true, so we have to calculate it ourselves // narrowMode when (width of emoji drawer) < (category icon size + padding) // * (number of categories, minus one which is a VLine) // - padding (no spacing at the end) // + 2 * (left/right margin size) property bool narrowMode: width < (root.size + categoryRow.spacing) * (categoryRow.children.length - 1) - categoryRow.spacing + categoryContainer.anchors.margins * 2 property bool searchMode: false property string catimgpath: gcd.assetPath + "emojidrawer/" + (gcd.theme != "dark" ? "lightmode_" : "darkmode_") signal picked(string shortcode) signal slideopen() signal slideclosed() visible: height != 0 Rectangle { color: Theme.backgroundPaneColor border.color: Theme.dividerColor anchors.fill: parent } PropertyAnimation { id: animClose; target: root; properties: "implicitHeight"; to: 0; duration: 400; } PropertyAnimation { id: animOpen; target: root; properties: "implicitHeight"; to: requestedHeight; duration: 400; } ColumnLayout { id: categoryContainer anchors.fill: parent anchors.margins: 10 RowLayout { id: categoryRow spacing: 10 Row { ImageButton { tooltip: qsTr("search") source: gcd.assetPath + "core/search-24px.webp" size: root.size color: root.searchMode ? Theme.dividerColor : "transparent" onClicked: { root.searchMode = !root.searchMode if (!root.searchMode) txtSearch.text = "" else txtSearch.focus = true } imgSrc.visible: false ColorOverlay { color: root.searchMode ? Theme.backgroundMainColor : Theme.dividerColor anchors.fill: parent.imgSrc source: parent.imgSrc antialiasing: true smooth: true } } TextField { id: txtSearch visible: root.searchMode implicitWidth: 200 implicitHeight: root.size //: Search... placeholderText: qsTr("search") onTextChanged: { if (text == "") emojiModel.model = folder_expressions else emojiModel.model = folder_search emojiModel.updatefilters() } font.pixelSize: root.size * 0.5 background: Rectangle { color: Theme.dividerColor } } } ImageButton { id: btnEmojiExpressionsGroup visible: !root.narrowMode && !root.searchMode //: Expressions tooltip: qsTr("emojicat-expressions") source: catimgpath + "big_smile.webp" size: root.size onClicked: emojiModel.model = folder_expressions } ImageButton { visible: !root.narrowMode && !root.searchMode //: Activities tooltip: qsTr("emojicat-activities") source: catimgpath + "volleyball.webp" size: root.size onClicked: emojiModel.model = folder_activities_clothing } ImageButton { visible: !root.narrowMode && !root.searchMode //: Food, drink & herbs tooltip: qsTr("emojicat-food") source: catimgpath + "red_apple.webp" size: root.size onClicked: emojiModel.model = folder_food_drink_herbs } ImageButton { visible: !root.narrowMode && !root.searchMode //: Gender, relationships & sexuality tooltip: qsTr("emojicat-gender") size: root.size source: catimgpath + "transgender_symbol.webp" onClicked: emojiModel.model = folder_gsr } ImageButton { visible: !root.narrowMode && !root.searchMode //: Nature and effects tooltip: qsTr("emojicat-nature") source: catimgpath + "crescent.webp" size: root.size onClicked: emojiModel.model = folder_nature } ImageButton { visible: !root.narrowMode && !root.searchMode //: Objects tooltip: qsTr("emojicat-objects") source: catimgpath + "light_bulb.webp" size: root.size onClicked: emojiModel.model = folder_objects } ImageButton { visible: !root.narrowMode && !root.searchMode //: People and animals tooltip: qsTr("emojicat-people") source: catimgpath + "bear.webp" size: root.size onClicked: emojiModel.model = folder_people } ImageButton { visible: !root.narrowMode && !root.searchMode //: Symbols tooltip: qsTr("emojicat-symbols") source: catimgpath + "pentacle.webp" size: root.size onClicked: emojiModel.model = folder_symbols } ImageButton { visible: !root.narrowMode && !root.searchMode //: Travel & places tooltip: qsTr("emojicat-travel") source: catimgpath + "airplane.webp" size: root.size onClicked: emojiModel.model = folder_travel_places } ImageButton { visible: !root.narrowMode && !root.searchMode //: Miscellaneous tooltip: qsTr("emojicat-misc") source: catimgpath + "hash.webp" size: root.size onClicked: emojiModel.model = folder_utils } Rectangle { width: 2 height: root.size * 0.8 color: Theme.dividerColor visible: !root.narrowMode && !root.searchMode } Item { visible: root.narrowMode && !root.searchMode height: root.size width: root.size Image { id: imgCatRot anchors.centerIn: parent source: cats[index].source property int index: 0 property var cats: [ {source: catimgpath + "big_smile.webp", model: folder_expressions}, {source: catimgpath + "volleyball.webp", model: folder_activities_clothing}, {source: catimgpath + "red_apple.webp", model: folder_food_drink_herbs}, {source: catimgpath + "transgender_symbol.webp", model: folder_gsr}, {source: catimgpath + "crescent.webp", model: folder_nature}, {source: catimgpath + "light_bulb.webp", model: folder_objects}, {source: catimgpath + "bear.webp", model: folder_people}, {source: catimgpath + "pentacle.webp", model: folder_symbols}, {source: catimgpath + "airplane.webp", model: folder_travel_places}, {source: catimgpath + "hash.webp", model: folder_utils} ] height: root.size * (maCatRot.pressed ? 0.8 : 1.0) width: root.size * (maCatRot.pressed ? 0.8 : 1.0) ToolTip.visible: maCatRot.containsMouse ToolTip.text: gcd.os == "android" ? qsTr("cycle-cats-android") : qsTr("cycle-cats-desktop") MouseArea { id: maCatRot hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton anchors.fill: parent; onClicked: { if (mouse.button == Qt.RightButton) {//todo: long press on android imgCatRot.index = 0 } else { imgCatRot.index = (imgCatRot.index + 1) % imgCatRot.cats.length } emojiModel.model = imgCatRot.cats[imgCatRot.index].model //root.morph = Mutant.standard.morphs[imgMorph.index] //emojiModel.updatefilters() } } } } Item { height: root.size width: root.size Image { id: imgMorph anchors.centerIn: parent source: gcd.assetPath + "mutstd/hand_"+Mutant.standard.morphs[index]+"_"+root.color+".webp" property int index: 0 height: root.size width: root.size ToolTip.visible: maMorph.containsMouse ToolTip.text: gcd.os == "android" ? qsTr("cycle-morphs-android") : qsTr("cycle-morphs-desktop") MouseArea { id: maMorph hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton anchors.fill: parent; onClicked: { if (mouse.button == Qt.RightButton) {//todo: long press on android imgMorph.index = 0//TODO: saved morph } else { imgMorph.index = (imgMorph.index + 1) % Mutant.standard.morphs.length } root.morph = Mutant.standard.morphs[imgMorph.index] emojiModel.updatefilters() } } } } Item { height: root.size width: root.size Image { id: imgColor anchors.centerIn: parent source: gcd.assetPath + "mutstd/color_modifier_"+Mutant.standard.colorByIndex(index, root.morph)+".webp" property int index: 0 height: root.size width: root.size ToolTip.visible: ma.containsMouse ToolTip.text: gcd.os == "android" ? qsTr("cycle-colours-android") : qsTr("cycle-colours-desktop") MouseArea { id: ma anchors.fill: parent; hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: function(mouse){ if (mouse.button == Qt.RightButton) {//todo: long press on android imgColor.index = 0//todo: saved color } else { imgColor.index = (imgColor.index + 1) % Mutant.standard.numColors(root.morph) } root.color = Mutant.standard.colorByIndex(imgColor.index, root.morph) emojiModel.updatefilters() } } } } } GridView { Layout.fillWidth: true Layout.fillHeight: true height: root.size * 3 cellWidth: root.size * 1.2 cellHeight: root.size * 1.2 clip: true ScrollBar.vertical: ScrollBar {} maximumFlickVelocity: 1250 boundsBehavior: GridView.StopAtBounds model: emojiModel } } ListModel { id: folder_activities_clothing } ListModel { id: folder_expressions } ListModel { id: folder_food_drink_herbs } ListModel { id: folder_gsr } ListModel { id: folder_nature } ListModel { id: folder_objects } ListModel { id: folder_people } ListModel { id: folder_symbols } ListModel { id: folder_travel_places } ListModel { id: folder_utils } ListModel { id: folder_search } DelegateModel { id: emojiModel model: folder_expressions delegate: Item { width: root.size * 1.2 height: root.size * 1.2 Image { id: img //source: "file://" + gcd.binaryPath + "/assets/mutstd/" + code + ".webp" source: gcd.assetPath + "mutstd/" + code + ".webp" width: root.size * (mouseArea.pressed ? 0.9 : 1) height: width anchors.centerIn: parent property string shortcode: code ToolTip.visible: mouseArea.containsMouse ToolTip.text: desc + "\n:" + shortcode + ":" MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true onClicked: root.picked(img.shortcode) } } } Component.onCompleted: updatefilters() function clearall() { folder_activities_clothing.clear() folder_expressions.clear() folder_food_drink_herbs.clear() folder_gsr.clear() folder_nature.clear() folder_objects.clear() folder_people.clear() folder_symbols.clear() folder_travel_places.clear() folder_utils.clear() folder_search.clear() } function updatefilters() { clearall() for (var i in Mutant.standard.manifest) { if (typeof Mutant.standard.manifest[i].morph !== "undefined" && Mutant.standard.manifest[i].morph != root.morph) continue; if (typeof Mutant.standard.manifest[i].color !== "undefined" && Mutant.standard.manifest[i].color != root.color) continue; if (txtSearch.text != "" && !(Mutant.standard.manifest[i].code.includes(txtSearch.text) || Mutant.standard.manifest[i].desc.includes(txtSearch.text))) { continue; } var model = folder_expressions if (txtSearch.text == "") { switch(Mutant.standard.manifest[i].cat) { case "activities_clothing": model = folder_activities_clothing; break; case "expressions": model = folder_expressions; break; case "symbols": model = folder_symbols; break; case "food_drink_herbs": model = folder_food_drink_herbs; break; case "gsr": model = folder_gsr; break; case "nature": model = folder_nature; break; case "objects": model = folder_objects; break; case "people": model = folder_people; break; case "travel_places": model = folder_travel_places; break; case "utils": model = folder_utils; break; } } else { model = folder_search } model.append({ cat: Mutant.standard.manifest[i].cat, code: Mutant.standard.manifest[i].code, color: Mutant.standard.manifest[i].color, morph: Mutant.standard.manifest[i].morph, desc: Mutant.standard.manifest[i].desc }) } } } onSlideopen: animOpen.start() onSlideclosed: animClose.start() }