mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-09-05 02:20:28 +00:00
Chatview and combobox UI fixes (#2489)
Chatview and combobox UI fixes (#2489) Signed-off-by: Adam Treat <treat.adam@gmail.com>
This commit is contained in:
@@ -205,13 +205,12 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 20
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.leftMargin: 30
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 100
|
||||
color: "transparent"
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
MyToolButton {
|
||||
@@ -237,8 +236,15 @@ Rectangle {
|
||||
id: comboBox
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 350
|
||||
Layout.maximumWidth: 675
|
||||
Layout.preferredWidth: 550
|
||||
Layout.leftMargin: {
|
||||
// This function works in tandem with the preferredWidth and the layout to
|
||||
// provide the maximum size combobox we can have at the smallest window width
|
||||
// we allow with the largest font size we allow. It is unfortunately based
|
||||
// upon a magic number that was produced through trial and error for something
|
||||
// I don't fully understand.
|
||||
return -Math.max(0, comboBox.width / 2 + collectionsButton.width + 110 /*magic*/ - comboLayout.width / 2);
|
||||
}
|
||||
enabled: !currentChat.isServer
|
||||
&& !currentChat.trySwitchContextInProgress
|
||||
&& !currentChat.isCurrentlyLoading
|
||||
@@ -266,8 +272,8 @@ Rectangle {
|
||||
ProgressBar {
|
||||
id: modelProgress
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: contentRow.width + 20
|
||||
visible: currentChat.isCurrentlyLoading
|
||||
height: 10
|
||||
value: currentChat.modelLoadingPercentage
|
||||
@@ -286,38 +292,110 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
contentItem: Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
leftPadding: 10
|
||||
rightPadding: {
|
||||
if (ejectButton.visible && reloadButton)
|
||||
return 105;
|
||||
if (reloadButton.visible)
|
||||
return 65
|
||||
return 25
|
||||
|
||||
contentItem: Item {
|
||||
RowLayout {
|
||||
id: contentRow
|
||||
anchors.centerIn: parent
|
||||
spacing: 0
|
||||
RowLayout {
|
||||
id: miniButtonsRow
|
||||
clip: true
|
||||
Behavior on Layout.preferredWidth {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Layout.preferredWidth: {
|
||||
if (!comboBox.hovered)
|
||||
return 0
|
||||
return (reloadButton.visible ? reloadButton.width : 0) + (ejectButton.visible ? ejectButton.width : 0)
|
||||
}
|
||||
|
||||
MyMiniButton {
|
||||
id: reloadButton
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: currentChat.modelLoadingError === ""
|
||||
&& !currentChat.trySwitchContextInProgress
|
||||
&& !currentChat.isCurrentlyLoading
|
||||
&& (currentChat.isModelLoaded || currentModelName() !== "")
|
||||
source: "qrc:/gpt4all/icons/regenerate.svg"
|
||||
backgroundColor: theme.textColor
|
||||
backgroundColorHovered: theme.styledTextColor
|
||||
onClicked: {
|
||||
if (currentChat.isModelLoaded)
|
||||
currentChat.forceReloadModel();
|
||||
else
|
||||
currentChat.reloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Reload the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
|
||||
MyMiniButton {
|
||||
id: ejectButton
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: currentChat.isModelLoaded && !currentChat.isCurrentlyLoading
|
||||
source: "qrc:/gpt4all/icons/eject.svg"
|
||||
backgroundColor: theme.textColor
|
||||
backgroundColorHovered: theme.styledTextColor
|
||||
onClicked: {
|
||||
currentChat.forceUnloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Eject the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: comboBoxText
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
text: {
|
||||
if (ModelList.selectableModels.count === 0)
|
||||
return qsTr("No model installed...")
|
||||
if (currentChat.modelLoadingError !== "")
|
||||
return qsTr("Model loading error...")
|
||||
if (currentChat.trySwitchContextInProgress === 1)
|
||||
return qsTr("Waiting for model...")
|
||||
if (currentChat.trySwitchContextInProgress === 2)
|
||||
return qsTr("Switching context...")
|
||||
if (currentModelName() === "")
|
||||
return qsTr("Choose a model...")
|
||||
if (currentChat.modelLoadingPercentage === 0.0)
|
||||
return qsTr("Reload \u00B7 ") + currentModelName()
|
||||
if (currentChat.isCurrentlyLoading)
|
||||
return qsTr("Loading \u00B7 ") + currentModelName()
|
||||
return currentModelName()
|
||||
}
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
color: theme.iconBackgroundLight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Item {
|
||||
Layout.minimumWidth: updown.width
|
||||
Layout.minimumHeight: updown.height
|
||||
Image {
|
||||
id: updown
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
sourceSize.width: comboBoxText.font.pixelSize
|
||||
sourceSize.height: comboBoxText.font.pixelSize
|
||||
mipmap: true
|
||||
visible: false
|
||||
source: "qrc:/gpt4all/icons/up_down.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: updown
|
||||
source: updown
|
||||
color: comboBoxText.color
|
||||
}
|
||||
}
|
||||
}
|
||||
text: {
|
||||
if (ModelList.selectableModels.count === 0)
|
||||
return qsTr("No model installed...")
|
||||
if (currentChat.modelLoadingError !== "")
|
||||
return qsTr("Model loading error...")
|
||||
if (currentChat.trySwitchContextInProgress === 1)
|
||||
return qsTr("Waiting for model...")
|
||||
if (currentChat.trySwitchContextInProgress === 2)
|
||||
return qsTr("Switching context...")
|
||||
if (currentModelName() === "")
|
||||
return qsTr("Choose a model...")
|
||||
if (currentChat.modelLoadingPercentage === 0.0)
|
||||
return qsTr("Reload \u00B7 ") + currentModelName()
|
||||
if (currentChat.isCurrentlyLoading)
|
||||
return qsTr("Loading \u00B7 ") + currentModelName()
|
||||
return currentModelName()
|
||||
}
|
||||
font.pixelSize: theme.fontSizeLarger
|
||||
color: theme.iconBackgroundLight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
delegate: ItemDelegate {
|
||||
id: comboItemDelegate
|
||||
@@ -330,12 +408,12 @@ Rectangle {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
color: (index % 2 === 0 ? theme.darkContrast : theme.lightContrast)
|
||||
border.width: highlighted
|
||||
border.color: theme.accentColor
|
||||
color: highlighted ? theme.lightContrast : theme.darkContrast
|
||||
}
|
||||
highlighted: comboBox.highlightedIndex === index
|
||||
}
|
||||
indicator: Item {
|
||||
}
|
||||
popup: Popup {
|
||||
id: comboItemPopup
|
||||
y: comboBox.height - 1
|
||||
@@ -378,46 +456,6 @@ Rectangle {
|
||||
comboBox.changeModel(index);
|
||||
}
|
||||
}
|
||||
|
||||
MyMiniButton {
|
||||
id: ejectButton
|
||||
visible: currentChat.isModelLoaded && !currentChat.isCurrentlyLoading
|
||||
z: 500
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "qrc:/gpt4all/icons/eject.svg"
|
||||
backgroundColor: theme.mutedLightTextColor
|
||||
backgroundColorHovered: theme.iconBackgroundLight
|
||||
onClicked: {
|
||||
currentChat.forceUnloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Eject the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
|
||||
MyMiniButton {
|
||||
id: reloadButton
|
||||
visible: currentChat.modelLoadingError === ""
|
||||
&& !currentChat.trySwitchContextInProgress
|
||||
&& !currentChat.isCurrentlyLoading
|
||||
&& (currentChat.isModelLoaded || currentModelName() !== "")
|
||||
z: 500
|
||||
anchors.right: ejectButton.visible ? ejectButton.left : parent.right
|
||||
anchors.rightMargin: ejectButton.visible ? 10 : 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "qrc:/gpt4all/icons/regenerate.svg"
|
||||
backgroundColor: theme.mutedLightTextColor
|
||||
backgroundColorHovered: theme.iconBackgroundLight
|
||||
onClicked: {
|
||||
if (currentChat.isModelLoaded)
|
||||
currentChat.forceReloadModel();
|
||||
else
|
||||
currentChat.reloadModel();
|
||||
}
|
||||
ToolTip.text: qsTr("Reload the currently loaded model")
|
||||
ToolTip.visible: hovered
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -425,99 +463,97 @@ Rectangle {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 30
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
clip: true
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
MyButton {
|
||||
id: collectionsButton
|
||||
clip: true
|
||||
anchors.right: parent.right
|
||||
MyButton {
|
||||
id: collectionsButton
|
||||
borderWidth: 0
|
||||
backgroundColor: theme.collectionsButtonBackground
|
||||
backgroundColorHovered: theme.collectionsButtonBackgroundHovered
|
||||
backgroundRadius: 5
|
||||
padding: 15
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
borderWidth: 0
|
||||
backgroundColor: theme.collectionsButtonBackground
|
||||
backgroundColorHovered: theme.collectionsButtonBackgroundHovered
|
||||
backgroundRadius: 5
|
||||
padding: 15
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 10
|
||||
Item {
|
||||
visible: currentChat.collectionModel.count === 0
|
||||
Layout.minimumWidth: collectionsImage.width
|
||||
Layout.minimumHeight: collectionsImage.height
|
||||
Image {
|
||||
id: collectionsImage
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
sourceSize.width: 24
|
||||
sourceSize.height: 24
|
||||
mipmap: true
|
||||
visible: false
|
||||
source: "qrc:/gpt4all/icons/db.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: collectionsImage
|
||||
source: collectionsImage
|
||||
color: theme.collectionsButtonForeground
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
spacing: 10
|
||||
Item {
|
||||
visible: currentChat.collectionModel.count === 0
|
||||
Layout.minimumWidth: collectionsImage.width
|
||||
Layout.minimumHeight: collectionsImage.height
|
||||
Image {
|
||||
id: collectionsImage
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
sourceSize.width: 24
|
||||
sourceSize.height: 24
|
||||
mipmap: true
|
||||
visible: false
|
||||
source: "qrc:/gpt4all/icons/db.svg"
|
||||
}
|
||||
|
||||
MyBusyIndicator {
|
||||
visible: currentChat.collectionModel.updatingCount !== 0
|
||||
color: theme.collectionsButtonProgress
|
||||
size: 24
|
||||
Layout.minimumWidth: 24
|
||||
Layout.minimumHeight: 24
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: currentChat.collectionModel.updatingCount
|
||||
color: theme.collectionsButtonForeground
|
||||
font.pixelSize: 14 // fixed regardless of theme
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: currentChat.collectionModel.count !== 0
|
||||
radius: 6
|
||||
ColorOverlay {
|
||||
anchors.fill: collectionsImage
|
||||
source: collectionsImage
|
||||
color: theme.collectionsButtonForeground
|
||||
Layout.minimumWidth: collectionsImage.width
|
||||
Layout.minimumHeight: collectionsImage.height
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: currentChat.collectionModel.count
|
||||
color: theme.collectionsButtonText
|
||||
font.pixelSize: 14 // fixed regardless of theme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyBusyIndicator {
|
||||
visible: currentChat.collectionModel.updatingCount !== 0
|
||||
color: theme.collectionsButtonProgress
|
||||
size: 24
|
||||
Layout.minimumWidth: 24
|
||||
Layout.minimumHeight: 24
|
||||
Text {
|
||||
text: qsTr("LocalDocs")
|
||||
anchors.centerIn: parent
|
||||
text: currentChat.collectionModel.updatingCount
|
||||
color: theme.collectionsButtonForeground
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
font.pixelSize: 14 // fixed regardless of theme
|
||||
}
|
||||
}
|
||||
|
||||
fontPixelSize: theme.fontSizeLarge
|
||||
|
||||
background: Rectangle {
|
||||
radius: collectionsButton.backgroundRadius
|
||||
// TODO(jared): either use collectionsButton-specific theming, or don't - this is inconsistent
|
||||
color: conversation.state == "expanded" ? (
|
||||
collectionsButton.hovered ? theme.lightButtonBackgroundHovered : theme.lightButtonBackground
|
||||
) : (
|
||||
collectionsButton.hovered ? theme.lighterButtonBackground : theme.lighterButtonBackgroundHovered
|
||||
)
|
||||
Rectangle {
|
||||
visible: currentChat.collectionModel.count !== 0
|
||||
radius: 6
|
||||
color: theme.collectionsButtonForeground
|
||||
Layout.minimumWidth: collectionsImage.width
|
||||
Layout.minimumHeight: collectionsImage.height
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: currentChat.collectionModel.count
|
||||
color: theme.collectionsButtonText
|
||||
font.pixelSize: 14 // fixed regardless of theme
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.name: qsTr("Add documents")
|
||||
Accessible.description: qsTr("add collections of documents to the chat")
|
||||
|
||||
onClicked: {
|
||||
conversation.toggleRightPanel()
|
||||
Text {
|
||||
text: qsTr("LocalDocs")
|
||||
color: theme.collectionsButtonForeground
|
||||
font.pixelSize: theme.fontSizeLarge
|
||||
}
|
||||
}
|
||||
|
||||
fontPixelSize: theme.fontSizeLarge
|
||||
|
||||
background: Rectangle {
|
||||
radius: collectionsButton.backgroundRadius
|
||||
// TODO(jared): either use collectionsButton-specific theming, or don't - this is inconsistent
|
||||
color: conversation.state === "expanded" ? (
|
||||
collectionsButton.hovered ? theme.lightButtonBackgroundHovered : theme.lightButtonBackground
|
||||
) : (
|
||||
collectionsButton.hovered ? theme.lighterButtonBackground : theme.lighterButtonBackgroundHovered
|
||||
)
|
||||
}
|
||||
|
||||
Accessible.name: qsTr("Add documents")
|
||||
Accessible.description: qsTr("add collections of documents to the chat")
|
||||
|
||||
onClicked: {
|
||||
conversation.toggleRightPanel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1418,8 +1454,8 @@ Rectangle {
|
||||
MyTextArea {
|
||||
id: textInput
|
||||
color: theme.textColor
|
||||
topPadding: 30
|
||||
bottomPadding: 30
|
||||
topPadding: 15
|
||||
bottomPadding: 15
|
||||
leftPadding: 20
|
||||
rightPadding: 40
|
||||
enabled: currentChat.isModelLoaded && !currentChat.isServer
|
||||
@@ -1506,8 +1542,8 @@ Rectangle {
|
||||
anchors.right: textInputView.right
|
||||
anchors.verticalCenter: textInputView.verticalCenter
|
||||
anchors.rightMargin: 15
|
||||
width: 30
|
||||
height: 30
|
||||
imageWidth: theme.fontSizeLarger
|
||||
imageHeight: theme.fontSizeLarger
|
||||
visible: !currentChat.isServer && ModelList.selectableModels.count !== 0
|
||||
enabled: !currentChat.responseInProgress
|
||||
source: "qrc:/gpt4all/icons/send_message.svg"
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.Basic
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
@@ -8,15 +10,39 @@ ComboBox {
|
||||
spacing: 0
|
||||
padding: 10
|
||||
Accessible.role: Accessible.ComboBox
|
||||
contentItem: Text {
|
||||
id: text
|
||||
leftPadding: 10
|
||||
rightPadding: 20
|
||||
text: comboBox.displayText
|
||||
font: comboBox.font
|
||||
color: theme.textColor
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
contentItem: RowLayout {
|
||||
id: contentRow
|
||||
spacing: 0
|
||||
Text {
|
||||
id: text
|
||||
Layout.fillWidth: true
|
||||
leftPadding: 10
|
||||
rightPadding: 20
|
||||
text: comboBox.displayText
|
||||
font: comboBox.font
|
||||
color: theme.textColor
|
||||
verticalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Item {
|
||||
Layout.preferredWidth: updown.width
|
||||
Layout.preferredHeight: updown.height
|
||||
Image {
|
||||
id: updown
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
sourceSize.width: comboBox.font.pixelSize
|
||||
sourceSize.height: comboBox.font.pixelSize
|
||||
mipmap: true
|
||||
visible: false
|
||||
source: "qrc:/gpt4all/icons/up_down.svg"
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: updown
|
||||
source: updown
|
||||
color: theme.textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate: ItemDelegate {
|
||||
width: comboBox.width
|
||||
@@ -53,33 +79,7 @@ ComboBox {
|
||||
color: theme.black
|
||||
}
|
||||
}
|
||||
indicator: Canvas {
|
||||
id: canvas
|
||||
x: comboBox.width - width - comboBox.rightPadding
|
||||
y: comboBox.topPadding + (comboBox.availableHeight - height) / 2
|
||||
width: 12
|
||||
height: 18
|
||||
contextType: "2d"
|
||||
|
||||
Connections {
|
||||
target: comboBox
|
||||
function onPressedChanged() { canvas.requestPaint(); }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var context = getContext("2d");
|
||||
context.reset();
|
||||
context.lineWidth = 2;
|
||||
context.moveTo(0, height / 2 - 2);
|
||||
context.lineTo(width / 2, 0);
|
||||
context.lineTo(width, height / 2 - 2);
|
||||
context.moveTo(0, height / 2 + 2);
|
||||
context.lineTo(width / 2, height);
|
||||
context.lineTo(width, height / 2 + 2);
|
||||
context.strokeStyle = comboBox.pressed ? theme.mutedLightTextColor : theme.mutedLighterTextColor;
|
||||
context.stroke();
|
||||
|
||||
}
|
||||
indicator: Item {
|
||||
}
|
||||
background: Rectangle {
|
||||
color: theme.controlBackground
|
||||
|
@@ -33,8 +33,8 @@ Button {
|
||||
anchors.centerIn: parent
|
||||
visible: false
|
||||
mipmap: true
|
||||
sourceSize.width: 20
|
||||
sourceSize.height: 20
|
||||
sourceSize.width: 16
|
||||
sourceSize.height: 16
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: image
|
||||
|
Reference in New Issue
Block a user