diff --git a/widgets/DapComboBox.qml b/widgets/DapComboBox.qml index 3698dd704e05b57b625c5be5dd3762211e12358a..6d1111970cda1a8c6db99bff5e3d80137769ad7a 100644 --- a/widgets/DapComboBox.qml +++ b/widgets/DapComboBox.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.0 DapComboBoxForm { + delegate: ItemDelegate { @@ -29,64 +30,119 @@ DapComboBoxForm //Text item contentItem: - Text + Rectangle { - id:textDelegateComboBox + id: rectTextComboBox + anchors.fill: parent anchors.topMargin: paddingTopItemDelegate anchors.leftMargin: popup.visible ? sidePaddingActive : sidePaddingNormal anchors.rightMargin: popup.visible ? sidePaddingActive : sidePaddingNormal - font: fontComboBox + color: "transparent" + width: (index !== currentIndex) ? + widthPopupComboBoxNormal - 2*sidePaddingActive - endRowPadding : + widthPopupComboBoxNormal - indicatorWidth - indicatorLeftInterval - 2 * sidePaddingActive - //Calculates various properties of a given string of text for a particular font - TextMetrics - { - id: tm - font: fontComboBox - elide: Text.ElideRight - text: modelData - elideWidth: - { - if(index != currentIndex) - return widthPopupComboBoxActive - 2*sidePaddingActive; - else - return widthPopupComboBoxNormal - indicatorWidth - indicatorLeftInterval; - } - } FontMetrics { - id: fm + id: comboBoxFontMetric font: fontComboBox } - text: + property int comboBoxIndex: index + property int comboBoxCurrentIndex: currentIndex + Row + { + spacing: roleInterval + Repeater { - if(index != currentIndex) - { - if(tm.elidedText.length < tm.text.length) - return tm.elidedText.substring(0, tm.elidedText.length-1) + - ((fm.tightBoundingRect(tm.elidedText.substring(0, tm.elidedText.length-1)).width + - fm.tightBoundingRect(tm.text.charAt(tm.elidedText.length-1) + '..').width) < tm.elideWidth ? - (tm.text.charAt(tm.elidedText.length-1) + '..') - : '..'); - return tm.elidedText.replace('…', '..'); - } - else + model: comboBoxTextRole.length + Text { - if(tm.elidedText.length < tm.text.length) - mainLineText = tm.elidedText.substring(0, tm.elidedText.length-1) + - ((fm.tightBoundingRect(tm.elidedText.substring(0, tm.elidedText.length-1)).width + - fm.tightBoundingRect(tm.text.charAt(tm.elidedText.length-1) + '..').width) < tm.elideWidth ? - (tm.text.charAt(tm.elidedText.length-1) + '..') - : '..'); - else - mainLineText = tm.elidedText.replace('…', '..'); - return ""; + id: textDelegateComboBox + font: fontComboBox + color: hovered ? hilightColorText : normalColorText + horizontalAlignment: + { + if(index === 0) + return Text.AlignLeft; + if(index === comboBoxTextRole.length - 1) + return Text.AlignRight; + return Text.AlignHCenter; + } + width: (rectTextComboBox.width - roleInterval * (comboBoxTextRole.length - 1)) / comboBoxTextRole.length + /*{ + if(index === 0) + setModelDataWidth(rectTextComboBox.comboBoxIndex, comboBoxFontMetric, rectTextComboBox.width); + console.log("comboBoxIndex", rectTextComboBox.comboBoxIndex, "index", index, "comboBoxTextRole", comboBoxTextRole[index]) + return comboBoxTextRoleWidth[index]; + }*/ + TextMetrics + { + id: comboBoxTextMetric + font: fontComboBox + elide: Text.ElideRight + text: getModelData(rectTextComboBox.comboBoxIndex, comboBoxTextRole[index]) + elideWidth: textDelegateComboBox.width + } + /*Component.onCompleted: + { + setModelDataWidth(rectTextComboBox.comboBoxIndex, comboBoxFontMetric, rectTextComboBox.width); + textDelegateComboBox.width = comboBoxTextRoleWidth[index]; + }*/ + text: + { + if(rectTextComboBox.comboBoxIndex != rectTextComboBox.comboBoxCurrentIndex) + { + if(comboBoxTextMetric.elideWidth < comboBoxFontMetric.tightBoundingRect(comboBoxTextMetric.text).width) + return checkElidedText(comboBoxFontMetric, comboBoxTextMetric); + else if(comboBoxTextMetric.elideWidth === comboBoxFontMetric.tightBoundingRect(comboBoxTextMetric.text).width) + return comboBoxTextMetric.text; + else + return comboBoxTextMetric.elidedText.replace('…', '..'); + } + else + { + if(popup.visible) + { + if(comboBoxTextMetric.elideWidth < comboBoxFontMetric.tightBoundingRect(comboBoxTextMetric.text).width) + mainLineText[index] = checkElidedText(comboBoxFontMetric, comboBoxTextMetric); + else + { + if(comboBoxTextMetric.elideWidth === comboBoxFontMetric.tightBoundingRect(comboBoxTextMetric.text).width) + mainLineText[index] = comboBoxTextMetric.text; + else + mainLineText[index] = comboBoxTextMetric.elidedText.replace('…', '..'); + } + + } + else + { + if(index === 0) + mainLineText[index] = comboBoxFontMetric.elidedText(getModelData(rectTextComboBox.comboBoxIndex, comboBoxTextRole[index]), + Text.ElideRight, + (widthPopupComboBoxNormal - indicatorWidth - indicatorLeftInterval), + Qt.TextShowMnemonic).replace('…', '..'); + } + console.log("mainLineText[index]", "index", mainLineText[index], index) + return ""; + + } + } } + } - color: hovered ? hilightColorText : normalColorText + Rectangle + { + id: endRowRectangle + height: parent.height + width: endRowPadding + color: "transparent" + } + } } + //Indent from the bottom edge or the next line that will not stand out when you hover over the mouse background: Rectangle @@ -108,4 +164,90 @@ DapComboBoxForm } highlighted: parent.highlightedIndex === index } + + function checkElidedText(fontMetric, textMetric) + { + return textMetric.elidedText.substring(0, textMetric.elidedText.length-1) + + ((fontMetric.tightBoundingRect(textMetric.elidedText.substring(0, textMetric.elidedText.length-1)).width + + fontMetric.tightBoundingRect(textMetric.text.charAt(textMetric.elidedText.length-1) + '..').width) < textMetric.elideWidth ? + (textMetric.text.charAt(textMetric.elidedText.length-1) + '..') + : '..'); + } + + function getModelData(rowIndex, modelRole) + { + return model.get(rowIndex)[modelRole]; + } + + function setModelDataWidth(rowIndex, fontMetric, rowWidth) + { + comboBoxTextRoleWidth = [0]; + mainLineText = [""]; + var neededWidth = 0; + for(var i = 0; i < comboBoxTextRole.length; i++) + { + mainLineText[i] = ""; + comboBoxTextRoleWidth[i] = fontMetric.tightBoundingRect(getModelData(rowIndex, comboBoxTextRole[i])).width; + neededWidth += comboBoxTextRoleWidth[i]; + } + neededWidth += roleInterval * (comboBoxTextRole.length - 1); + console.log("neededWidth", neededWidth, "rowWidth", rowWidth); + var oneIndex = 0; + if (neededWidth > rowWidth) + { + oneIndex = comboBoxTextRole.indexOf(mainLineRole); + if(oneIndex === -1) + { + oneIndex = comboBoxTextRole.indexOf("text"); + if(oneIndex === -1) + { + oneIndex = comboBoxTextRole.indexOf("name"); + if(oneIndex === -1) + oneIndex = 0; + } + } + if(comboBoxTextRoleWidth[oneIndex] < neededWidth - rowWidth) + { + comboBoxTextRoleWidth[oneIndex] = rowWidth / (comboBoxTextRole.length); + var maxWidth = 0; + var maxIndex = 0; + while(neededWidth > rowWidth) + { + maxWidth = comboBoxTextRoleWidth[0]; + maxIndex = 0; + for(i = 0; i < comboBoxTextRoleWidth.length; i++) + { + if(maxWidth < comboBoxTextRoleWidth[i]) + { + maxWidth = comboBoxTextRoleWidth[i]; + maxIndex = i; + } + } + comboBoxTextRoleWidth[maxIndex] -= 10 * pt; + neededWidth = 0; + for(i = 0; i < comboBoxTextRoleWidth.length; i++) + neededWidth += comboBoxTextRoleWidth[i]; + } + } + return true; + } + if(neededWidth < rowWidth) + { + oneIndex = comboBoxTextRole.indexOf(mainLineRole); + if(oneIndex === -1) + { + oneIndex = comboBoxTextRole.indexOf("text"); + if(oneIndex === -1) + { + oneIndex = comboBoxTextRole.indexOf("name"); + if(oneIndex === -1) + oneIndex = 0; + } + } + comboBoxTextRoleWidth[oneIndex] += rowWidth - neededWidth; + return true; + } + return false; + } + } diff --git a/widgets/DapComboBoxForm.ui.qml b/widgets/DapComboBoxForm.ui.qml index 829ec783aadbcec199399c89974d4f81776d9fee..448ea087c467a907d180ee7a558b486b053afb84 100644 --- a/widgets/DapComboBoxForm.ui.qml +++ b/widgets/DapComboBoxForm.ui.qml @@ -61,8 +61,22 @@ ComboBox property string colorDropShadow ///@detalis fontComboBox Font setting combobox. property alias fontComboBox: dapComboBox.font - ///@detalis mainLineText Text without unneccesary part. - property string mainLineText + //@detalis mainLineText Text without unneccesary part. + property var mainLineText: [""] + + ///@detalis comboBoxTextRole The model roles used for the ComboBox. + property var comboBoxTextRole: ["name"] + ///@detalis comboBoxTextRoleWidth The model roles width used for the ComboBox. + property var comboBoxTextRoleWidth: [100] + ///@detalis roleInterval The width between text of model roles used for the ComboBox. + property int roleInterval: 5 + ///@detalis endRowPadding The width of padding at the end of one row at ComboBox where it is need. + property int endRowPadding: 0 + + ///@detalis mainLineRole The model role for the main line of cloded ComboBox. + property string mainLineRole: "name" + + width: popup.visible ? widthPopupComboBoxActive : widthPopupComboBoxNormal height: popup.visible ? heightComboBoxActive : heightComboBoxNormal @@ -91,16 +105,38 @@ ComboBox //Main line text settings contentItem: - Text + Rectangle { anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: popup.visible ? sidePaddingActive : sidePaddingNormal - text: mainLineText - font: parent.font - color: popup.visible ? hilightColorTopText : normalColorTopText - verticalAlignment: Text.AlignVCenter + width: widthPopupComboBoxNormal - indicatorWidth - indicatorLeftInterval + color: "transparent" + Row + { + spacing: roleInterval + Repeater + { + id: mainLineRepeater + model: popup.visible ? comboBoxTextRole.length : 1 + Text + { + id: mainLineComboBoxText + height: dapComboBox.height + text: index >= mainLineText.length ? "" : mainLineText[index] + horizontalAlignment: (index === 0) ? + Text.AlignLeft : + ((index === comboBoxTextRole.length - 1) ? Text.AlignRight : Text.AlignHCenter) + + font: fontComboBox + color: popup.visible ? hilightColorTopText : normalColorTopText + verticalAlignment: Text.AlignVCenter + } + } + } } + //Customize drop-down list with shadow effect popup: Popup diff --git a/widgets/DapText.qml b/widgets/DapText.qml index 3ca718a4455e20c0a2660b515989f20561105e7f..468f588c67addbc0240e23a46202c2acbf9e106a 100644 --- a/widgets/DapText.qml +++ b/widgets/DapText.qml @@ -2,60 +2,69 @@ import QtQuick 2.4 DapTextForm { - onTextChanged: - { - elidedText = (width > 2) ? elideByWidth(width) : (maxSymbolCapacity > 2) ? elideByCapacity(maxSymbolCapacity) : text - width = _metrics.boundingRect(elidedText).width - height = _metrics.boundingRect(elidedText).height - } + width: parent.width - // "Copy Button" handler - function copy() + //Text eliding is available only after full item boot + //with all metrics - to delete binding loop + Component.onCompleted: { - _fullText.selectAll() - _fullText.copy() + checkTextElide(); } + //If it needed the dynamic width change + onWidthChanged: checkTextElide() - // Elides text by number of symbols - function elideByCapacity(maxSymbols) + //Function to elide text and check result + function checkTextElide() { - var res = "" - if (text.length > maxSymbols) + if(textMetric.elideWidth < fontMetric.tightBoundingRect(textMetric.text).width) { - switch (elide) + switch(textElide) { - case Qt.ElideLeft: - res = ".." + text.slice(-maxSymbols, text.length-1) - break - case Qt.ElideMiddle: - res = text.slice(0, Math.floor(maxSymbols/2)) + ".." + text.slice(Math.floor(maxSymbols/2) + 1, text.length-1) - break - case Qt.ElideRight: - res = text.slice(0, maxSymbols) + ".." - break - default: - res = text - break + case Text.ElideRight: + elText = textMetric.elidedText.substring(0, textMetric.elidedText.length - 1) + + ((fontMetric.tightBoundingRect(textMetric.elidedText.substring(0, textMetric.elidedText.length - 1)).width + + fontMetric.tightBoundingRect(textMetric.text.charAt(textMetric.elidedText.length - 1) + '..').width) < textMetric.elideWidth ? + (textMetric.text.charAt(textMetric.elidedText.length - 1) + '..'): + '..'); + break; + + case Text.ElideLeft: + elText = '..' + ((fontMetric.tightBoundingRect(textMetric.elidedText.substring(1, textMetric.elidedText.length - 1)).width + + fontMetric.tightBoundingRect('..' + textMetric.text.charAt(textMetric.text.length - textMetric.elidedText.length)).width) < textMetric.elideWidth ? + (textMetric.text.charAt(textMetric.text.length - textMetric.elidedText.length)): + '') + textMetric.elidedText.substring(1, textMetric.elidedText.length - 1); + + break; + + case Text.ElideMiddle: + elText = textMetric.elidedText.substring(0, textMetric.elidedText.indexOf('…')) + + ((fontMetric.tightBoundingRect(textMetric.elidedText.substring(0, textMetric.elidedText.indexOf('…'))).width + + fontMetric.tightBoundingRect(textMetric.text.charAt(textMetric.elidedText.indexOf('…')) + '..').width + + fontMetric.tightBoundingRect(textMetric.elidedText.substring(textMetric.elidedText.indexOf('…') + 1, textMetric.elidedText.length)).width) < textMetric.elideWidth ? + (textMetric.text.charAt(textMetric.elidedText.indexOf('…')) + '..'): + '..') + + textMetric.elidedText.substring(textMetric.elidedText.indexOf('…') + 1, textMetric.elidedText.length); + break; + + case Text.ElideNone: + elText = fullText; } + } else - { - res = text - } - return res + elText = textMetric.elidedText.replace('…', '..'); } - // Elides text by width - function elideByWidth(maxWidth) + //Function to copy full text to the clipboard + function copyFullText() { - if (_metrics.advanceWidth(text) > maxWidth) - { - var symbolsNum = (maxWidth / _metrics.averageCharacterWidth) - return elideByCapacity(Math.floor(symbolsNum)) - } - else - { - return text - } + //Replace elide text by full text and select it + text = fullText; + selectAll(); + //Because this method can copy only selected text + copy(); + // User should not see it! + deselect(); + text = elText; } } diff --git a/widgets/DapTextForm.ui.qml b/widgets/DapTextForm.ui.qml index ea18b880fe65f5aa5e653b224fab502804a531fe..ca740809cdf086983ef580aea9751acdfac088bf 100644 --- a/widgets/DapTextForm.ui.qml +++ b/widgets/DapTextForm.ui.qml @@ -1,43 +1,42 @@ import QtQuick 2.4 import QtQuick.Controls 2.2 -Item +TextInput { id: dapText - ///@details Text. - property alias text: fullText.text - ///@details Text color. - property alias color: elidedText.color - ///@details Font. - property alias font: elidedText.font - ///@details Elide style. - property int elide: Qt.ElideRight - ///@details The number of symbols to display. - property int maxSymbolCapacity: 0 - ///@details Text to display. - property alias elidedText: elidedText.text + ///@detalis fullText Full text string + property string fullText + ///@detalis elText Elided text string + property string elText + ////@detalis fontDapText Font setting combobox. + property alias fontDapText: dapText.font + ///@details elide Elide style. + property int textElide: Text.ElideRight + ///@detalis textMetric Text Metric to elide text + property alias textMetric: dapTextInputTextMetric + ///@detalis fontMetric Font Metric to check elided text + property alias fontMetric: dapTextInputFontMetric + ///@detalis textColor Color of text + property color textColor - property alias _fullText: fullText - property alias _metrics: metrics - - // Displays the text - Text + font: fontDapText + color: textColor + //To do elide + TextMetrics { - id: elidedText - } - - // Calculates elide - FontMetrics - { - id: metrics + id: dapTextInputTextMetric font: parent.font + elide: textElide + elideWidth: parent.width + text: fullText } - // Stores full string to copy - TextInput + // To check elide + FontMetrics { - id: fullText - visible: false + id: dapTextInputFontMetric + font: parent.font } + text: elText }