Make the scroll bar of the chat bar move properly as you type.

This commit is contained in:
James Graham
2026-01-25 18:53:41 +00:00
parent b7a329c199
commit 39573c1650
3 changed files with 34 additions and 14 deletions

View File

@@ -107,6 +107,19 @@ Item {
clip: true clip: true
ColumnLayout { ColumnLayout {
readonly property real visibleTop: chatScrollView.QQC2.ScrollBar.vertical.position * chatScrollView.contentHeight
readonly property real visibleBottom: chatScrollView.QQC2.ScrollBar.vertical.position * chatScrollView.contentHeight + chatScrollView.QQC2.ScrollBar.vertical.size * chatScrollView.contentHeight
readonly property rect cursorRectInColumn: mapFromItem(contentModel.focusedTextItem.textItem, contentModel.focusedTextItem.cursorRectangle);
onCursorRectInColumnChanged: {
if (chatScrollView.QQC2.ScrollBar.vertical.visible) {
if (cursorRectInColumn.y < visibleTop) {
chatScrollView.QQC2.ScrollBar.vertical.position = cursorRectInColumn.y / chatScrollView.contentHeight
} else if (cursorRectInColumn.y + cursorRectInColumn.height > visibleBottom) {
chatScrollView.QQC2.ScrollBar.vertical.position = (cursorRectInColumn.y + cursorRectInColumn.height - (chatScrollView.QQC2.ScrollBar.vertical.size * chatScrollView.contentHeight)) / chatScrollView.contentHeight
}
}
}
width: chatScrollView.width width: chatScrollView.width
spacing: Kirigami.Units.smallSpacing spacing: Kirigami.Units.smallSpacing

View File

@@ -11,6 +11,8 @@ import org.kde.kirigami as Kirigami
import org.kde.neochat.libneochat as LibNeoChat import org.kde.neochat.libneochat as LibNeoChat
import org.kde.neochat.messagecontent as MessageContent import org.kde.neochat.messagecontent as MessageContent
pragma ComponentBehavior: Bound
RowLayout { RowLayout {
id: root id: root
@@ -54,7 +56,7 @@ RowLayout {
Kirigami.Units.gridUnit Kirigami.Units.gridUnit
readonly property ChatButtonHelper chatButtonHelper: ChatButtonHelper { readonly property ChatButtonHelper chatButtonHelper: ChatButtonHelper {
textItem: contentModel.focusedTextItem textItem: root.contentModel.focusedTextItem
} }
signal clicked signal clicked
@@ -66,7 +68,7 @@ RowLayout {
onActivated: boldButton.clicked() onActivated: boldButton.clicked()
} }
icon.name: "format-text-bold" icon.name: "format-text-bold"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Bold") text: i18nc("@action:button", "Bold")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
@@ -87,7 +89,7 @@ RowLayout {
onActivated: italicButton.clicked() onActivated: italicButton.clicked()
} }
icon.name: "format-text-italic" icon.name: "format-text-italic"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Italic") text: i18nc("@action:button", "Italic")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
@@ -111,7 +113,7 @@ RowLayout {
onActivated: underlineButton.clicked() onActivated: underlineButton.clicked()
} }
icon.name: "format-text-underline" icon.name: "format-text-underline"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Underline") text: i18nc("@action:button", "Underline")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
@@ -127,7 +129,7 @@ RowLayout {
} }
QQC2.ToolButton { QQC2.ToolButton {
icon.name: "format-text-strikethrough" icon.name: "format-text-strikethrough"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Strikethrough") text: i18nc("@action:button", "Strikethrough")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
@@ -146,12 +148,12 @@ RowLayout {
id: compressedExtraTextFormatButton id: compressedExtraTextFormatButton
visible: root.maxAvailableWidth < root.listCompressedImplicitWidth visible: root.maxAvailableWidth < root.listCompressedImplicitWidth
icon.name: "dialog-text-and-font" icon.name: "dialog-text-and-font"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Format Text") text: i18nc("@action:button", "Format Text")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
onClicked: { onClicked: {
let dialog = compressedTextFormatMenu.createObject(compressedExtraTextFormatButton) let dialog = compressedTextFormatMenu.createObject(compressedExtraTextFormatButton) as QQC2.Menu
dialog.onClosed.connect(() => { dialog.onClosed.connect(() => {
compressedExtraTextFormatButton.checked = false; compressedExtraTextFormatButton.checked = false;
}); });
@@ -235,7 +237,7 @@ RowLayout {
checkable: true checkable: true
onClicked: { onClicked: {
let dialog = emojiDialog.createObject(root).open(); let dialog = (emojiDialog.createObject(root) as EmojiDialog).open();
} }
QQC2.ToolTip.visible: hovered QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
@@ -267,7 +269,7 @@ RowLayout {
visible: root.maxAvailableWidth > root.uncompressedImplicitWidth visible: root.maxAvailableWidth > root.uncompressedImplicitWidth
QQC2.ToolButton { QQC2.ToolButton {
icon.name: "format-list-unordered" icon.name: "format-list-unordered"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Unordered List") text: i18nc("@action:button", "Unordered List")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
@@ -283,11 +285,11 @@ RowLayout {
} }
QQC2.ToolButton { QQC2.ToolButton {
icon.name: "format-list-ordered" icon.name: "format-list-ordered"
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
text: i18nc("@action:button", "Ordered List") text: i18nc("@action:button", "Ordered List")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
checkable: true checkable: true
checked: root.chatButtonHelper.orderedlist checked: root.chatButtonHelper.orderedList
onClicked: { onClicked: {
root.chatButtonHelper.setFormat(LibNeoChat.RichFormat.OrderedList); root.chatButtonHelper.setFormat(LibNeoChat.RichFormat.OrderedList);
root.clicked(); root.clicked();
@@ -300,7 +302,7 @@ RowLayout {
QQC2.ToolButton { QQC2.ToolButton {
id: indentAction id: indentAction
icon.name: "format-indent-more" icon.name: "format-indent-more"
enabled: chatButtonHelper.richFormatEnabled && root.chatButtonHelper.canIndentListMore enabled: root.chatButtonHelper.richFormatEnabled && root.chatButtonHelper.canIndentListMore
text: i18nc("@action:button", "Increase List Level") text: i18nc("@action:button", "Increase List Level")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
onClicked: { onClicked: {
@@ -315,7 +317,7 @@ RowLayout {
QQC2.ToolButton { QQC2.ToolButton {
id: dedentAction id: dedentAction
icon.name: "format-indent-less" icon.name: "format-indent-less"
enabled: chatButtonHelper.richFormatEnabled && root.chatButtonHelper.canIndentListLess enabled: root.chatButtonHelper.richFormatEnabled && root.chatButtonHelper.canIndentListLess
text: i18nc("@action:button", "Decrease List Level") text: i18nc("@action:button", "Decrease List Level")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
onClicked: { onClicked: {
@@ -330,7 +332,7 @@ RowLayout {
} }
QQC2.ToolButton { QQC2.ToolButton {
id: compressedListButton id: compressedListButton
enabled: chatButtonHelper.richFormatEnabled enabled: root.chatButtonHelper.richFormatEnabled
visible: root.maxAvailableWidth < root.uncompressedImplicitWidth visible: root.maxAvailableWidth < root.uncompressedImplicitWidth
icon.name: "format-list-unordered" icon.name: "format-list-unordered"
text: i18nc("@action:button", "List Style") text: i18nc("@action:button", "List Style")

View File

@@ -38,6 +38,11 @@ class ChatTextItemHelper : public QObject
*/ */
Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged) Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged)
/**
* @brief The QML text Item the ChatTextItemHelper is handling.
*/
Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorPositionChanged)
public: public:
enum InsertPosition { enum InsertPosition {
Cursor, Cursor,