diff --git a/src/chatbar/RichEditBar.qml b/src/chatbar/RichEditBar.qml index fec932c04..938f75f94 100644 --- a/src/chatbar/RichEditBar.qml +++ b/src/chatbar/RichEditBar.qml @@ -57,6 +57,7 @@ RowLayout { readonly property ChatButtonHelper chatButtonHelper: ChatButtonHelper { textItem: root.contentModel.focusedTextItem + inQuote: root.contentModel.focusType == LibNeoChat.MessageComponentType.Quote } signal clicked @@ -195,11 +196,12 @@ RowLayout { } StyleButton { id: styleButton - Layout.minimumWidth: compressed ? -1 : Kirigami.Units.gridUnit * 8 + Kirigami.Units.largeSpacing * 2 + Layout.minimumWidth: compressed ? -1 : Kirigami.Units.gridUnit * 10 + Kirigami.Units.largeSpacing * 2 icon.name: "typewriter" text: i18nc("@action:button", "Text Style") style: root.chatButtonHelper.currentStyle + inQuote: root.contentModel.focusType == LibNeoChat.MessageComponentType.Quote compressed: root.maxAvailableWidth < root.extraTextCompressedImplicitWidth enabled: root.chatButtonHelper.styleFormatEnabled display: QQC2.AbstractButton.IconOnly @@ -216,8 +218,10 @@ RowLayout { StylePicker { id: styleMenu + width: styleButton.compressed ? implicitWidth : styleButton.width chatContentModel: root.contentModel chatButtonHelper: root.chatButtonHelper + inQuote: root.contentModel.focusType == LibNeoChat.MessageComponentType.Quote onClosed: { root.clicked() diff --git a/src/chatbar/StyleButton.qml b/src/chatbar/StyleButton.qml index 517838b95..6a22f6ef5 100644 --- a/src/chatbar/StyleButton.qml +++ b/src/chatbar/StyleButton.qml @@ -16,6 +16,8 @@ QQC2.AbstractButton { required property int style + required property bool inQuote + property bool open: false property bool compressed: false @@ -37,6 +39,7 @@ QQC2.AbstractButton { visible: !root.compressed style: root.style + inQuote: root.inQuote sizeText: false onPressed: root.clicked() diff --git a/src/chatbar/StyleDelegate.qml b/src/chatbar/StyleDelegate.qml index 3635176fd..31e123f02 100644 --- a/src/chatbar/StyleDelegate.qml +++ b/src/chatbar/StyleDelegate.qml @@ -16,6 +16,8 @@ QQC2.TextArea { required property int style + required property bool inQuote + property bool highlight: false property bool sizeText: true @@ -52,11 +54,12 @@ QQC2.TextArea { StyleDelegateHelper { textItem: root + inQuote: root.inQuote } background: Rectangle { color: Kirigami.Theme.backgroundColor - Kirigami.Theme.colorSet: root.style === LibNeoChat.RichFormat.Quote ? Kirigami.Theme.Window : Kirigami.Theme.View + Kirigami.Theme.colorSet: root.style === LibNeoChat.RichFormat.Quote || (root.inQuote && !(root.style == LibNeoChat.RichFormat.Paragraph || root.style == LibNeoChat.RichFormat.Code)) ? Kirigami.Theme.Window : Kirigami.Theme.View Kirigami.Theme.inherit: false radius: Kirigami.Units.cornerRadius border { diff --git a/src/chatbar/StylePicker.qml b/src/chatbar/StylePicker.qml index 5285a665c..7f1164bc9 100644 --- a/src/chatbar/StylePicker.qml +++ b/src/chatbar/StylePicker.qml @@ -17,6 +17,7 @@ QQC2.Popup { required property MessageContent.ChatBarMessageContentModel chatContentModel required property ChatButtonHelper chatButtonHelper + required property bool inQuote y: -implicitHeight padding: Kirigami.Units.largeSpacing @@ -35,7 +36,12 @@ QQC2.Popup { Layout.minimumWidth: Kirigami.Units.gridUnit * 8 Layout.minimumHeight: Kirigami.Units.gridUnit * 2 + enabled: chatButtonHelper.richFormatEnabled || + index == LibNeoChat.RichFormat.Paragraph || + index == LibNeoChat.RichFormat.Code || + index == LibNeoChat.RichFormat.Quote style: index + inQuote: root.inQuote highlight: root.chatButtonHelper.currentStyle === index || hovered onPressed: (event) => { diff --git a/src/chatbar/chatbuttonhelper.cpp b/src/chatbar/chatbuttonhelper.cpp index e2035bb8e..5d3cc265a 100644 --- a/src/chatbar/chatbuttonhelper.cpp +++ b/src/chatbar/chatbuttonhelper.cpp @@ -41,6 +41,7 @@ void ChatButtonHelper::setTextItem(ChatTextItemHelper *textItem) } }); connect(m_textItem, &ChatTextItemHelper::textFormatChanged, this, &ChatButtonHelper::richFormatEnabledChanged); + connect(m_textItem, &ChatTextItemHelper::textFormatChanged, this, &ChatButtonHelper::styleChanged); connect(m_textItem, &ChatTextItemHelper::charFormatChanged, this, &ChatButtonHelper::charFormatChanged); connect(m_textItem, &ChatTextItemHelper::styleChanged, this, &ChatButtonHelper::styleChanged); connect(m_textItem, &ChatTextItemHelper::listChanged, this, &ChatButtonHelper::listChanged); @@ -48,6 +49,23 @@ void ChatButtonHelper::setTextItem(ChatTextItemHelper *textItem) Q_EMIT textItemChanged(); Q_EMIT richFormatEnabledChanged(); + Q_EMIT styleChanged(); +} + +bool ChatButtonHelper::inQuote() const +{ + return m_inQuote; +} + +void ChatButtonHelper::setInQuote(bool inQuote) +{ + if (inQuote == m_inQuote) { + return; + } + m_inQuote = inQuote; + Q_EMIT inQuoteChanged(); + Q_EMIT richFormatEnabledChanged(); + Q_EMIT styleChanged(); } bool ChatButtonHelper::richFormatEnabled() const @@ -158,7 +176,14 @@ RichFormat::Format ChatButtonHelper::currentStyle() const if (!m_textItem) { return RichFormat::Paragraph; } - return static_cast(m_textItem->textCursor().blockFormat().headingLevel()); + if (!richFormatEnabled()) { + return RichFormat::Code; + } + const auto currentHeadingLevel = m_textItem->textCursor().blockFormat().headingLevel(); + if (currentHeadingLevel == 0 && m_inQuote) { + return RichFormat::Quote; + } + return static_cast(currentHeadingLevel); } void ChatButtonHelper::setFormat(RichFormat::Format format) diff --git a/src/chatbar/chatbuttonhelper.h b/src/chatbar/chatbuttonhelper.h index 8231b50bf..aeace0b50 100644 --- a/src/chatbar/chatbuttonhelper.h +++ b/src/chatbar/chatbuttonhelper.h @@ -23,6 +23,11 @@ class ChatButtonHelper : public QObject */ Q_PROPERTY(ChatTextItemHelper *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged) + /** + * @brief Whether the current block is a Quote block. + */ + Q_PROPERTY(bool inQuote READ inQuote WRITE setInQuote NOTIFY inQuoteChanged) + /** * @brief Whether rich formating is enabled at the current cursor location. */ @@ -94,6 +99,9 @@ public: ChatTextItemHelper *textItem() const; void setTextItem(ChatTextItemHelper *textItem); + bool inQuote() const; + void setInQuote(bool inQuote); + bool richFormatEnabled() const; bool styleFormatEnabled() const; bool bold() const; @@ -140,6 +148,7 @@ public: Q_SIGNALS: void textItemChanged(); + void inQuoteChanged(); void richFormatEnabledChanged(); void charFormatChanged(); void styleChanged(); @@ -147,6 +156,7 @@ Q_SIGNALS: private: QPointer m_textItem; + bool m_inQuote = false; void selectLinkText(QTextCursor &cursor) const; }; diff --git a/src/chatbar/styledelegatehelper.cpp b/src/chatbar/styledelegatehelper.cpp index c6dd06e98..8338e2521 100644 --- a/src/chatbar/styledelegatehelper.cpp +++ b/src/chatbar/styledelegatehelper.cpp @@ -47,6 +47,21 @@ QTextDocument *StyleDelegateHelper::document() const return quickDocument ? quickDocument->textDocument() : nullptr; } +bool StyleDelegateHelper::inQuote() const +{ + return m_inQuote; +} + +void StyleDelegateHelper::setInQuote(bool inQuote) +{ + if (inQuote == m_inQuote) { + return; + } + m_inQuote = inQuote; + formatDocument(); + Q_EMIT inQuoteChanged(); +} + void StyleDelegateHelper::formatDocument() { if (!document()) { @@ -62,7 +77,7 @@ void StyleDelegateHelper::formatDocument() cursor.select(QTextCursor::Document); cursor.removeSelectedText(); const auto style = static_cast(m_textItem->property("style").toInt()); - const auto string = RichFormat::styleString(style); + const auto string = RichFormat::styleString(style, m_inQuote); const auto sizeText = static_cast(m_textItem->property("sizeText").toBool()); const int headingLevel = style <= 6 && sizeText ? style : 0; @@ -83,7 +98,7 @@ void StyleDelegateHelper::formatDocument() chrfmt.setFontItalic(true); } - cursor.mergeBlockCharFormat(chrfmt); + cursor.setBlockCharFormat(chrfmt); cursor.insertText(string); cursor.endEditBlock(); } diff --git a/src/chatbar/styledelegatehelper.h b/src/chatbar/styledelegatehelper.h index 87b7f545a..15b41354b 100644 --- a/src/chatbar/styledelegatehelper.h +++ b/src/chatbar/styledelegatehelper.h @@ -19,19 +19,30 @@ class StyleDelegateHelper : public QObject */ Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged) + /** + * @brief Whether the current block is a Quote block. + */ + Q_PROPERTY(bool inQuote READ inQuote WRITE setInQuote NOTIFY inQuoteChanged) + public: explicit StyleDelegateHelper(QObject *parent = nullptr); QQuickItem *textItem() const; void setTextItem(QQuickItem *textItem); + bool inQuote() const; + void setInQuote(bool inQuote); + Q_SIGNALS: void textItemChanged(); + void inQuoteChanged(); private: QPointer m_textItem; QTextDocument *document() const; + bool m_inQuote = false; + private Q_SLOTS: void formatDocument(); }; diff --git a/src/libneochat/enums/richformat.cpp b/src/libneochat/enums/richformat.cpp index f57ec1518..a30b09a6b 100644 --- a/src/libneochat/enums/richformat.cpp +++ b/src/libneochat/enums/richformat.cpp @@ -9,30 +9,45 @@ #include -QString RichFormat::styleString(Format format) +QString RichFormat::styleString(Format format, bool inQuoteBlock) { + QString formatString; switch (format) { case Paragraph: - return i18nc("As in the default paragraph text style in the chat bar", "Paragraph Style"); + formatString = i18nc("As in the default paragraph text style in the chat bar", "Paragraph Style"); + break; case Heading1: - return i18nc("As in heading level 1 text style in the chat bar", "Heading 1"); + formatString = i18nc("As in heading level 1 text style in the chat bar", "Heading 1"); + break; case Heading2: - return i18nc("As in heading level 2 text style in the chat bar", "Heading 2"); + formatString = i18nc("As in heading level 2 text style in the chat bar", "Heading 2"); + break; case Heading3: - return i18nc("As in heading level 3 text style in the chat bar", "Heading 3"); + formatString = i18nc("As in heading level 3 text style in the chat bar", "Heading 3"); + break; case Heading4: - return i18nc("As in heading level 4 text style in the chat bar", "Heading 4"); + formatString = i18nc("As in heading level 4 text style in the chat bar", "Heading 4"); + break; case Heading5: - return i18nc("As in heading level 5 text style in the chat bar", "Heading 5"); + formatString = i18nc("As in heading level 5 text style in the chat bar", "Heading 5"); + break; case Heading6: - return i18nc("As in heading level 6 text style in the chat bar", "Heading 6"); + formatString = i18nc("As in heading level 6 text style in the chat bar", "Heading 6"); + break; case Code: - return i18nc("As in code text style in the chat bar", "Code"); + formatString = i18nc("As in code text style in the chat bar", "Code"); + break; case Quote: - return i18nc("As in quote text style in the chat bar", "\"Quote\""); + if (inQuoteBlock) { + formatString = i18nc("As in the default paragraph text style inside a quote block in the chat bar", "Quote Paragraph Style"); + break; + } + formatString = i18nc("As in quote text style in the chat bar", "Quote"); + break; default: - return {}; + break; } + return u"%1%2%1"_s.arg(inQuoteBlock && !(format == Paragraph || format == Code) ? u"\""_s : u""_s, formatString); }; RichFormat::FormatType RichFormat::typeForFormat(Format format) diff --git a/src/libneochat/enums/richformat.h b/src/libneochat/enums/richformat.h index a13d621d8..271dfe784 100644 --- a/src/libneochat/enums/richformat.h +++ b/src/libneochat/enums/richformat.h @@ -67,7 +67,7 @@ public: * * @sa Format */ - static QString styleString(Format format); + static QString styleString(Format format, bool inQuoteBlock = false); /** * @brief Return the FormatType for the Format. diff --git a/src/messagecontent/models/chatbarmessagecontentmodel.cpp b/src/messagecontent/models/chatbarmessagecontentmodel.cpp index 93e2150f4..e901fc4d2 100644 --- a/src/messagecontent/models/chatbarmessagecontentmodel.cpp +++ b/src/messagecontent/models/chatbarmessagecontentmodel.cpp @@ -430,7 +430,7 @@ void ChatBarMessageContentModel::insertStyleAtCursor(RichFormat::Format style) void ChatBarMessageContentModel::insertComponentAtCursor(MessageComponentType::Type type) { if (m_components[m_currentFocusComponent.row()].type == type) { - if (type == MessageComponentType::Text && focusedTextItem()) { + if ((type == MessageComponentType::Text || type == MessageComponentType::Quote) && focusedTextItem()) { focusedTextItem()->mergeFormatOnCursor(RichFormat::Paragraph); } return;