mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2024-09-11 13:25:35 +03:00
additional new ui changes, part 5 (#2485) Signed-off-by: Jared Van Bortel <jared@nomic.ai>
729 lines
24 KiB
QML
729 lines
24 KiB
QML
import QtCore
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Controls.Basic
|
|
import QtQuick.Layouts
|
|
import Qt5Compat.GraphicalEffects
|
|
import llm
|
|
import chatlistmodel
|
|
import download
|
|
import modellist
|
|
import network
|
|
import gpt4all
|
|
import localdocs
|
|
import mysettings
|
|
|
|
Window {
|
|
id: window
|
|
width: 1920
|
|
height: 1080
|
|
minimumWidth: 1280
|
|
minimumHeight: 720
|
|
visible: true
|
|
title: qsTr("GPT4All v") + Qt.application.version
|
|
|
|
Settings {
|
|
property alias x: window.x
|
|
property alias y: window.y
|
|
property alias width: window.width
|
|
property alias height: window.height
|
|
}
|
|
|
|
Theme {
|
|
id: theme
|
|
}
|
|
|
|
Item {
|
|
Accessible.role: Accessible.Window
|
|
Accessible.name: title
|
|
}
|
|
|
|
// Startup code
|
|
Component.onCompleted: {
|
|
startupDialogs();
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
Network.trackEvent("session_end")
|
|
}
|
|
|
|
Connections {
|
|
target: firstStartDialog
|
|
function onClosed() {
|
|
startupDialogs();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: Download
|
|
function onHasNewerReleaseChanged() {
|
|
startupDialogs();
|
|
}
|
|
}
|
|
|
|
property bool hasCheckedFirstStart: false
|
|
property bool hasShownSettingsAccess: false
|
|
property var currentChat: ChatListModel.currentChat
|
|
|
|
function startupDialogs() {
|
|
if (!LLM.compatHardware()) {
|
|
Network.trackEvent("noncompat_hardware")
|
|
errorCompatHardware.open();
|
|
return;
|
|
}
|
|
|
|
// check if we have access to settings and if not show an error
|
|
if (!hasShownSettingsAccess && !LLM.hasSettingsAccess()) {
|
|
errorSettingsAccess.open();
|
|
hasShownSettingsAccess = true;
|
|
return;
|
|
}
|
|
|
|
// check for first time start of this version
|
|
if (!hasCheckedFirstStart) {
|
|
if (Download.isFirstStart(/*writeVersion*/ true)) {
|
|
firstStartDialog.open();
|
|
return;
|
|
}
|
|
|
|
// send startup or opt-out now that the user has made their choice
|
|
Network.sendStartup()
|
|
// start localdocs
|
|
LocalDocs.requestStart()
|
|
|
|
hasCheckedFirstStart = true
|
|
}
|
|
|
|
// check for new version
|
|
if (Download.hasNewerRelease && !firstStartDialog.opened) {
|
|
newVersionDialog.open();
|
|
return;
|
|
}
|
|
}
|
|
|
|
PopupDialog {
|
|
id: errorCompatHardware
|
|
anchors.centerIn: parent
|
|
shouldTimeOut: false
|
|
shouldShowBusy: false
|
|
closePolicy: Popup.NoAutoClose
|
|
modal: true
|
|
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
|
|
+ qsTr("<i>\"Incompatible hardware detected.\"</i>")
|
|
+ qsTr("<br><br>Unfortunately, your CPU does not meet the minimal requirements to run ")
|
|
+ qsTr("this program. In particular, it does not support AVX intrinsics which this ")
|
|
+ qsTr("program requires to successfully run a modern large language model. ")
|
|
+ qsTr("The only solution at this time is to upgrade your hardware to a more modern CPU.")
|
|
+ qsTr("<br><br>See here for more information: <a href=\"https://en.wikipedia.org/wiki/Advanced_Vector_Extensions\">")
|
|
+ qsTr("https://en.wikipedia.org/wiki/Advanced_Vector_Extensions</a>")
|
|
}
|
|
|
|
PopupDialog {
|
|
id: errorSettingsAccess
|
|
anchors.centerIn: parent
|
|
shouldTimeOut: false
|
|
shouldShowBusy: false
|
|
modal: true
|
|
text: qsTr("<h3>Encountered an error starting up:</h3><br>")
|
|
+ qsTr("<i>\"Inability to access settings file.\"</i>")
|
|
+ qsTr("<br><br>Unfortunately, something is preventing the program from accessing ")
|
|
+ qsTr("the settings file. This could be caused by incorrect permissions in the local ")
|
|
+ qsTr("app config directory where the settings file is located. ")
|
|
+ qsTr("Check out our <a href=\"https://discord.gg/4M2QFmTt2k\">discord channel</a> for help.")
|
|
}
|
|
|
|
StartupDialog {
|
|
id: firstStartDialog
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
NewVersionDialog {
|
|
id: newVersionDialog
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
Connections {
|
|
target: Network
|
|
function onHealthCheckFailed(code) {
|
|
healthCheckFailed.open();
|
|
}
|
|
}
|
|
|
|
PopupDialog {
|
|
id: healthCheckFailed
|
|
anchors.centerIn: parent
|
|
text: qsTr("Connection to datalake failed.")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
}
|
|
|
|
property bool hasSaved: false
|
|
|
|
PopupDialog {
|
|
id: savingPopup
|
|
anchors.centerIn: parent
|
|
shouldTimeOut: false
|
|
shouldShowBusy: true
|
|
text: qsTr("Saving chats.")
|
|
font.pixelSize: theme.fontSizeLarge
|
|
}
|
|
|
|
NetworkDialog {
|
|
id: networkDialog
|
|
anchors.centerIn: parent
|
|
width: Math.min(1024, window.width - (window.width * .2))
|
|
height: Math.min(600, window.height - (window.height * .2))
|
|
Item {
|
|
Accessible.role: Accessible.Dialog
|
|
Accessible.name: qsTr("Network dialog")
|
|
Accessible.description: qsTr("opt-in to share feedback/conversations")
|
|
}
|
|
}
|
|
|
|
onClosing: function(close) {
|
|
if (window.hasSaved)
|
|
return;
|
|
|
|
savingPopup.open();
|
|
ChatListModel.saveChats();
|
|
close.accepted = false
|
|
}
|
|
|
|
Connections {
|
|
target: ChatListModel
|
|
function onSaveChatsFinished() {
|
|
window.hasSaved = true;
|
|
savingPopup.close();
|
|
window.close()
|
|
}
|
|
}
|
|
|
|
color: theme.viewBarBackground
|
|
|
|
Rectangle {
|
|
id: viewBar
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
width: 16 + 52 * theme.fontScale
|
|
color: theme.viewBarBackground
|
|
|
|
ColumnLayout {
|
|
id: viewsLayout
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 30
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
Layout.margins: 0
|
|
spacing: 16
|
|
|
|
MyToolButton {
|
|
id: homeButton
|
|
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
|
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
Layout.preferredHeight: 38 * theme.fontScale
|
|
Layout.alignment: Qt.AlignCenter
|
|
toggledWidth: 0
|
|
toggled: homeView.isShown()
|
|
toggledColor: theme.iconBackgroundViewBarToggled
|
|
imageWidth: 25 * theme.fontScale
|
|
imageHeight: 25 * theme.fontScale
|
|
source: "qrc:/gpt4all/icons/home.svg"
|
|
Accessible.name: qsTr("Home view")
|
|
Accessible.description: qsTr("Home view of application")
|
|
onClicked: {
|
|
homeView.show()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: -20
|
|
text: qsTr("Home")
|
|
font.pixelSize: theme.fontSizeMedium
|
|
font.bold: true
|
|
color: homeButton.hovered ? homeButton.backgroundColorHovered : homeButton.backgroundColor
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
horizontalAlignment: Text.AlignHCenter
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
homeView.show()
|
|
}
|
|
}
|
|
}
|
|
|
|
MyToolButton {
|
|
id: chatButton
|
|
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
|
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
Layout.preferredHeight: 38 * theme.fontScale
|
|
Layout.alignment: Qt.AlignCenter
|
|
toggledWidth: 0
|
|
toggled: chatView.isShown()
|
|
toggledColor: theme.iconBackgroundViewBarToggled
|
|
imageWidth: 25 * theme.fontScale
|
|
imageHeight: 25 * theme.fontScale
|
|
source: "qrc:/gpt4all/icons/chat.svg"
|
|
Accessible.name: qsTr("Chat view")
|
|
Accessible.description: qsTr("Chat view to interact with models")
|
|
onClicked: {
|
|
chatView.show()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: -20
|
|
text: qsTr("Chats")
|
|
font.pixelSize: theme.fontSizeMedium
|
|
font.bold: true
|
|
color: chatButton.hovered ? chatButton.backgroundColorHovered : chatButton.backgroundColor
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
horizontalAlignment: Text.AlignHCenter
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
chatView.show()
|
|
}
|
|
}
|
|
}
|
|
|
|
MyToolButton {
|
|
id: modelsButton
|
|
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
|
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
Layout.preferredHeight: 38 * theme.fontScale
|
|
toggledWidth: 0
|
|
toggled: modelsView.isShown()
|
|
toggledColor: theme.iconBackgroundViewBarToggled
|
|
imageWidth: 25 * theme.fontScale
|
|
imageHeight: 25 * theme.fontScale
|
|
source: "qrc:/gpt4all/icons/models.svg"
|
|
Accessible.name: qsTr("Models")
|
|
Accessible.description: qsTr("Models view for installed models")
|
|
onClicked: {
|
|
modelsView.show()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: -20
|
|
text: qsTr("Models")
|
|
font.pixelSize: theme.fontSizeMedium
|
|
font.bold: true
|
|
color: modelsButton.hovered ? modelsButton.backgroundColorHovered : modelsButton.backgroundColor
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
horizontalAlignment: Text.AlignHCenter
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
modelsView.show()
|
|
}
|
|
}
|
|
}
|
|
|
|
MyToolButton {
|
|
id: localdocsButton
|
|
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
|
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
Layout.preferredHeight: 38 * theme.fontScale
|
|
toggledWidth: 0
|
|
toggledColor: theme.iconBackgroundViewBarToggled
|
|
toggled: localDocsView.isShown()
|
|
imageWidth: 25 * theme.fontScale
|
|
imageHeight: 25 * theme.fontScale
|
|
source: "qrc:/gpt4all/icons/db.svg"
|
|
Accessible.name: qsTr("LocalDocs")
|
|
Accessible.description: qsTr("LocalDocs view to configure and use local docs")
|
|
onClicked: {
|
|
localDocsView.show()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: -20
|
|
text: qsTr("LocalDocs")
|
|
font.pixelSize: theme.fontSizeMedium
|
|
font.bold: true
|
|
color: localdocsButton.hovered ? localdocsButton.backgroundColorHovered : localdocsButton.backgroundColor
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
horizontalAlignment: Text.AlignHCenter
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
localDocsView.show()
|
|
}
|
|
}
|
|
}
|
|
|
|
MyToolButton {
|
|
id: settingsButton
|
|
backgroundColor: toggled ? theme.iconBackgroundViewBarHovered : theme.iconBackgroundViewBar
|
|
backgroundColorHovered: theme.iconBackgroundViewBarHovered
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
Layout.preferredHeight: 38 * theme.fontScale
|
|
toggledWidth: 0
|
|
toggledColor: theme.iconBackgroundViewBarToggled
|
|
toggled: settingsView.isShown()
|
|
imageWidth: 25 * theme.fontScale
|
|
imageHeight: 25 * theme.fontScale
|
|
source: "qrc:/gpt4all/icons/settings.svg"
|
|
Accessible.name: qsTr("Settings")
|
|
Accessible.description: qsTr("Settings view for application configuration")
|
|
onClicked: {
|
|
settingsView.show(0 /*pageToDisplay*/)
|
|
}
|
|
}
|
|
|
|
Text {
|
|
Layout.topMargin: -20
|
|
text: qsTr("Settings")
|
|
font.pixelSize: theme.fontSizeMedium
|
|
font.bold: true
|
|
color: settingsButton.hovered ? settingsButton.backgroundColorHovered : settingsButton.backgroundColor
|
|
Layout.preferredWidth: 38 * theme.fontScale
|
|
horizontalAlignment: Text.AlignHCenter
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
settingsView.show(0 /*pageToDisplay*/)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: buttonsLayout
|
|
anchors.bottom: parent.bottom
|
|
anchors.margins: 0
|
|
anchors.bottomMargin: 25
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
Layout.margins: 0
|
|
spacing: 22
|
|
|
|
Item {
|
|
id: antennaItem
|
|
Layout.alignment: Qt.AlignCenter
|
|
Layout.preferredWidth: antennaImage.width
|
|
Layout.preferredHeight: antennaImage.height
|
|
Image {
|
|
id: antennaImage
|
|
sourceSize.width: 32
|
|
sourceSize.height: 32
|
|
visible: false
|
|
fillMode: Image.PreserveAspectFit
|
|
source: "qrc:/gpt4all/icons/antenna_3.svg"
|
|
}
|
|
|
|
ColorOverlay {
|
|
id: antennaColored
|
|
visible: ModelList.selectableModels.count !== 0 && (currentChat.isServer || currentChat.modelInfo.isOnline || MySettings.networkIsActive)
|
|
anchors.fill: antennaImage
|
|
source: antennaImage
|
|
color: theme.styledTextColor
|
|
ToolTip.text: {
|
|
if (MySettings.networkIsActive)
|
|
return qsTr("The datalake is enabled")
|
|
else if (currentChat.modelInfo.isOnline)
|
|
return qsTr("Using a network model")
|
|
else if (currentChat.modelInfo.isOnline)
|
|
return qsTr("Server mode is enabled")
|
|
return ""
|
|
}
|
|
ToolTip.visible: maAntenna.containsMouse
|
|
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
|
MouseArea {
|
|
id: maAntenna
|
|
anchors.fill: antennaColored
|
|
hoverEnabled: true
|
|
}
|
|
}
|
|
|
|
SequentialAnimation {
|
|
running: true
|
|
loops: Animation.Infinite
|
|
|
|
PropertyAnimation {
|
|
target: antennaImage
|
|
property: "source"
|
|
duration: 500
|
|
from: "qrc:/gpt4all/icons/antenna_1.svg"
|
|
to: "qrc:/gpt4all/icons/antenna_2.svg"
|
|
}
|
|
|
|
PauseAnimation {
|
|
duration: 1500
|
|
}
|
|
|
|
PropertyAnimation {
|
|
target: antennaImage
|
|
property: "source"
|
|
duration: 500
|
|
from: "qrc:/gpt4all/icons/antenna_2.svg"
|
|
to: "qrc:/gpt4all/icons/antenna_3.svg"
|
|
}
|
|
|
|
PauseAnimation {
|
|
duration: 1500
|
|
}
|
|
|
|
PropertyAnimation {
|
|
target: antennaImage
|
|
property: "source"
|
|
duration: 500
|
|
from: "qrc:/gpt4all/icons/antenna_3.svg"
|
|
to: "qrc:/gpt4all/icons/antenna_2.svg"
|
|
}
|
|
|
|
PauseAnimation {
|
|
duration: 1500
|
|
}
|
|
|
|
PropertyAnimation {
|
|
target: antennaImage
|
|
property: "source"
|
|
duration: 1500
|
|
from: "qrc:/gpt4all/icons/antenna_2.svg"
|
|
to: "qrc:/gpt4all/icons/antenna_1.svg"
|
|
}
|
|
|
|
PauseAnimation {
|
|
duration: 500
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.alignment: Qt.AlignCenter
|
|
Layout.preferredWidth: image.width
|
|
Layout.preferredHeight: image.height
|
|
color: "transparent"
|
|
|
|
Image {
|
|
id: image
|
|
anchors.centerIn: parent
|
|
sourceSize: Qt.size(48 * theme.fontScale, 32 * theme.fontScale)
|
|
fillMode: Image.PreserveAspectFit
|
|
mipmap: true
|
|
visible: false
|
|
source: "qrc:/gpt4all/icons/nomic_logo.svg"
|
|
}
|
|
|
|
ColorOverlay {
|
|
anchors.fill: image
|
|
source: image
|
|
color: image.hovered ? theme.mutedDarkTextColorHovered : theme.mutedDarkTextColor
|
|
TapHandler {
|
|
onTapped: function(eventPoint, button) {
|
|
Qt.openUrlExternally("https://nomic.ai")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: roundedFrame
|
|
z: 299
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: viewBar.right
|
|
anchors.right: parent.right
|
|
anchors.topMargin: 15
|
|
anchors.bottomMargin: 15
|
|
anchors.rightMargin: 15
|
|
radius: 15
|
|
border.width: 1
|
|
border.color: theme.dividerColor
|
|
color: "transparent"
|
|
clip: true
|
|
}
|
|
|
|
RectangularGlow {
|
|
id: effect
|
|
anchors.fill: roundedFrame
|
|
glowRadius: 15
|
|
spread: 0
|
|
color: theme.dividerColor
|
|
cornerRadius: 10
|
|
opacity: 0.5
|
|
}
|
|
|
|
StackLayout {
|
|
id: stackLayout
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: viewBar.right
|
|
anchors.right: parent.right
|
|
anchors.topMargin: 15
|
|
anchors.bottomMargin: 15
|
|
anchors.rightMargin: 15
|
|
|
|
layer.enabled: true
|
|
layer.effect: OpacityMask {
|
|
maskSource: Rectangle {
|
|
width: roundedFrame.width
|
|
height: roundedFrame.height
|
|
radius: 15
|
|
}
|
|
}
|
|
|
|
HomeView {
|
|
id: homeView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
shouldShowFirstStart: !hasCheckedFirstStart
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 0;
|
|
}
|
|
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 0
|
|
}
|
|
|
|
Connections {
|
|
target: homeView
|
|
function onChatViewRequested() {
|
|
chatView.show();
|
|
}
|
|
function onLocalDocsViewRequested() {
|
|
localDocsView.show();
|
|
}
|
|
function onAddModelViewRequested() {
|
|
addModelView.show();
|
|
}
|
|
function onSettingsViewRequested(page) {
|
|
settingsView.show(page);
|
|
}
|
|
}
|
|
}
|
|
|
|
ChatView {
|
|
id: chatView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 1;
|
|
}
|
|
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 1
|
|
}
|
|
|
|
Connections {
|
|
target: chatView
|
|
function onAddCollectionViewRequested() {
|
|
addCollectionView.show();
|
|
}
|
|
function onAddModelViewRequested() {
|
|
addModelView.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
ModelsView {
|
|
id: modelsView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 2;
|
|
// FIXME This expanded code should be removed and we should be changing the names of
|
|
// the classes here in ModelList for the proxy/filter models
|
|
ModelList.downloadableModels.expanded = true
|
|
}
|
|
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 2
|
|
}
|
|
|
|
Item {
|
|
Accessible.name: qsTr("Installed models")
|
|
Accessible.description: qsTr("View of installed models")
|
|
}
|
|
|
|
Connections {
|
|
target: modelsView
|
|
function onAddModelViewRequested() {
|
|
addModelView.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalDocsView {
|
|
id: localDocsView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 3;
|
|
}
|
|
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 3
|
|
}
|
|
|
|
Connections {
|
|
target: localDocsView
|
|
function onAddCollectionViewRequested() {
|
|
addCollectionView.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsView {
|
|
id: settingsView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show(page) {
|
|
settingsView.pageToDisplay = page;
|
|
stackLayout.currentIndex = 4;
|
|
}
|
|
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 4
|
|
}
|
|
}
|
|
|
|
AddCollectionView {
|
|
id: addCollectionView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 5;
|
|
}
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 5
|
|
}
|
|
|
|
Connections {
|
|
target: addCollectionView
|
|
function onLocalDocsViewRequested() {
|
|
localDocsView.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
AddModelView {
|
|
id: addModelView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
function show() {
|
|
stackLayout.currentIndex = 6;
|
|
}
|
|
function isShown() {
|
|
return stackLayout.currentIndex === 6
|
|
}
|
|
|
|
Connections {
|
|
target: addModelView
|
|
function onModelsViewRequested() {
|
|
modelsView.show();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|