Reworking the Editor dialog to be much faster and cleaner.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
By using Components and Loader instead of instantiating each type of editor for every property, the whole operation becomes much faster, cleaner, and streamlined. Visible (admittedly unmeasured) boosts in speed with it. Preparing the groundwork for new editors.
This commit is contained in:
parent
f76b601139
commit
d65f343b60
7 changed files with 427 additions and 352 deletions
|
@ -0,0 +1,256 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../../js/objects.js" as Objects
|
||||
import "../../js/objs/common.js" as ObjectsCommons
|
||||
import "../../js/historylib.js" as HistoryLib
|
||||
import "../../js/utils.js" as Utils
|
||||
import "../../js/mathlib.js" as MathLib
|
||||
|
||||
/*!
|
||||
\qmltype CustomPropertyList
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
\brief Lists all custom properties editors inside a repeater and allow for edition.
|
||||
|
||||
This class repeats all of the custom properties and loads the appropriate editor for each kind of property.
|
||||
|
||||
\sa Dialog
|
||||
*/
|
||||
Repeater {
|
||||
id: dlgCustomProperties
|
||||
|
||||
signal changed()
|
||||
|
||||
/*!
|
||||
\qmlproperty var CustomPropertyList::obj
|
||||
Object whose properties to list and edit.
|
||||
*/
|
||||
property var obj
|
||||
|
||||
readonly property var textTypes: ['Expression', 'Domain', 'string', 'number']
|
||||
readonly property var comboBoxTypes: ['ObjectType', 'Enum']
|
||||
readonly property var listTypes: ['List', 'Dict']
|
||||
|
||||
|
||||
// NOTE: All components have the declared properties 'propertyLabel', 'propertyIcon', propertyName' and 'propertyType' to access the object in question.
|
||||
Component {
|
||||
id: commentComponent
|
||||
|
||||
// Item for comments.
|
||||
// NOTE: propertyType here is the content of the comment (yes, it's a bit backwards, but it's more clear on the properties side).
|
||||
Label {
|
||||
// Translated text with object name.
|
||||
property string trText: qsTranslate('comment', propertyType).toString()
|
||||
text: (trText.includes("%1") ? trText.arg(obj.name) : trText).toString()
|
||||
//color: sysPalette.windowText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textEditorComponent
|
||||
|
||||
// Setting for text & number settings as well as domains & expressions
|
||||
Setting.TextSetting {
|
||||
height: 30
|
||||
label: propertyLabel
|
||||
icon: `settings/custom/${propertyIcon}.svg`
|
||||
isDouble: propertyType == 'number'
|
||||
defValue: {
|
||||
switch(propertyType) {
|
||||
case 'Expression':
|
||||
return Utils.simplifyExpression(obj[propertyName].toEditableString())
|
||||
break
|
||||
case 'string':
|
||||
return obj[propertyName]
|
||||
break
|
||||
case 'Domain':
|
||||
case 'number':
|
||||
default:
|
||||
return obj[propertyName].toString()
|
||||
}
|
||||
}
|
||||
onChanged: function(newValue) {
|
||||
var newValue = {
|
||||
'Expression': () => new MathLib.Expression(newValue),
|
||||
'Domain': () => MathLib.parseDomain(newValue),
|
||||
'string': () => newValue,
|
||||
'number': () => parseFloat(newValue)
|
||||
}[propertyType]()
|
||||
// Ensuring old and new values are different to prevent useless adding to history.
|
||||
if(obj[propertyName] != newValue) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], newValue
|
||||
))
|
||||
obj[propertyName] = newValue
|
||||
Objects.currentObjects[objType][objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: checkboxComponent
|
||||
|
||||
// Setting for boolean
|
||||
CheckBox {
|
||||
height: 20
|
||||
text: propertyLabel
|
||||
//icon: `settings/custom/${propertyIcon}.svg`
|
||||
|
||||
checked: obj[propertyName]
|
||||
onClicked: {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], this.checked
|
||||
))
|
||||
obj[propertyName] = this.checked
|
||||
Objects.currentObjects[objType][objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: comboBoxComponent
|
||||
|
||||
// Setting when selecting data from an enum, or an object of a certain type.
|
||||
Setting.ComboBoxSetting {
|
||||
height: 30
|
||||
label: propertyLabel
|
||||
icon: `settings/custom/${propertyIcon}.svg`
|
||||
// True to select an object of type, false for enums.
|
||||
property bool selectObjMode: paramTypeIn(propertyType, ['ObjectType'])
|
||||
property bool isRealObject: !selectObjMode || (propertyType.objType != "ExecutableObject" && propertyType.objType != "DrawableObject")
|
||||
|
||||
// Base, untranslated version of the model.
|
||||
property var baseModel: selectObjMode ?
|
||||
Objects.getObjectsName(propertyType.objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[propertyType.objType].displayType())] : [])
|
||||
: propertyType.values
|
||||
// Translated version of the model.
|
||||
model: selectObjMode ? baseModel : propertyType.translatedValues
|
||||
currentIndex: baseModel.indexOf(selectObjMode ? obj[propertyName].name : obj[propertyName])
|
||||
|
||||
onActivated: function(newIndex) {
|
||||
if(selectObjMode) {
|
||||
// This is only done when what we're selecting are Objects.
|
||||
// Setting object property.
|
||||
var selectedObj = Objects.currentObjectsByName[baseModel[newIndex]]
|
||||
if(newIndex != 0) {
|
||||
// Make sure we don't set the object to null.
|
||||
if(selectedObj == null) {
|
||||
// Creating new object.
|
||||
selectedObj = Objects.createNewRegisteredObject(propertyType.objType)
|
||||
history.addToHistory(new HistoryLib.CreateNewObject(selectedObj.name, propertyType.objType, selectedObj.export()))
|
||||
baseModel = Objects.getObjectsName(propertyType.objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[propertyType.objType].displayType())] :
|
||||
[])
|
||||
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||
}
|
||||
selectedObj.requiredBy.push(Objects.currentObjects[objType][objIndex])
|
||||
//Objects.currentObjects[objType][objIndex].requiredBy = obj[propertyName].filter((obj) => obj.name != obj.name)
|
||||
}
|
||||
obj.requiredBy = obj.requiredBy.filter((obj) => obj.name != obj.name)
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], selectedObj
|
||||
))
|
||||
obj[propertyName] = selectedObj
|
||||
} else if(baseModel[newIndex] != obj[propertyName]) {
|
||||
// Ensuring new property is different to not add useless history entries.
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], baseModel[newIndex]
|
||||
))
|
||||
obj[propertyName] = baseModel[newIndex]
|
||||
}
|
||||
// Refreshing
|
||||
Objects.currentObjects[objType][objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
// Setting to edit lists or dictionaries (e.g sequences & repartition function values)
|
||||
id: listDictEditorComponent
|
||||
|
||||
Setting.ListSetting {
|
||||
label: propertyLabel
|
||||
//icon: `settings/custom/${propertyIcon}.svg`
|
||||
dictionaryMode: paramTypeIn(propertyType, ['Dict'])
|
||||
keyType: dictionaryMode ? propertyType.keyType : 'string'
|
||||
valueType: propertyType.valueType
|
||||
preKeyLabel: (dictionaryMode ? propertyType.preKeyLabel : propertyType.label).replace(/\{name\}/g, obj.name)
|
||||
postKeyLabel: (dictionaryMode ? propertyType.postKeyLabel : '').replace(/\{name\}/g, obj.name)
|
||||
keyRegexp: dictionaryMode ? propertyType.keyFormat : /^.+$/
|
||||
valueRegexp: propertyType.format
|
||||
forbidAdding: propertyType.forbidAdding
|
||||
|
||||
onChanged: {
|
||||
var exported = exportModel()
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], exported
|
||||
))
|
||||
//Objects.currentObjects[objType][objIndex][propertyName] = exported
|
||||
obj[propertyName] = exported
|
||||
//Objects.currentObjects[objType][objIndex].update()
|
||||
obj.update()
|
||||
objectListList.update()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
importModel(obj[propertyName])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Component {
|
||||
Loader {
|
||||
//height: customPropComment.height + customPropText.height + customPropCheckBox.height + customPropCombo.height + customPropListDict.height
|
||||
width: dlgProperties.width
|
||||
property string propertyName: modelData[0]
|
||||
property var propertyType: modelData[1]
|
||||
property string propertyLabel: qsTranslate('prop',propertyName)
|
||||
property string propertyIcon: Utils.camelCase2readable(propertyName)
|
||||
|
||||
sourceComponent: {
|
||||
if(propertyName.startsWith('comment'))
|
||||
return commentComponent
|
||||
else if(propertyType == 'boolean')
|
||||
return checkboxComponent
|
||||
else if(paramTypeIn(propertyType, textTypes))
|
||||
return textEditorComponent
|
||||
else if(paramTypeIn(propertyType, comboBoxTypes))
|
||||
return comboBoxComponent
|
||||
else if(paramTypeIn(propertyType, listTypes))
|
||||
return listDictEditorComponent
|
||||
else
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../../js/objects.js" as Objects
|
||||
import "../../js/objs/common.js" as ObjectsCommons
|
||||
import "../../js/historylib.js" as HistoryLib
|
||||
import "../../js/utils.js" as Utils
|
||||
import "../../js/mathlib.js" as MathLib
|
||||
|
||||
/*!
|
||||
\qmltype Dialog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
\brief Dialog used to edit properties of objects.
|
||||
|
||||
This class contains the dialog that allows to edit all properties of objects.
|
||||
\todo In the future, this class should be optimized so that each property doesn't instanciate one instance of each setting type.
|
||||
|
||||
\sa Loader, ObjectLists
|
||||
*/
|
||||
D.Dialog {
|
||||
id: objEditor
|
||||
/*!
|
||||
\qmlproperty string EditorDialog::objType
|
||||
Type of object being edited by the dialog.
|
||||
*/
|
||||
property string objType: 'Point'
|
||||
/*!
|
||||
\qmlproperty int EditorDialog::objIndex
|
||||
Index of the objects amongst the ones of it's type.
|
||||
*/
|
||||
property int objIndex: 0
|
||||
/*!
|
||||
\qmlproperty var EditorDialog::obj
|
||||
Instance of the object being edited.
|
||||
*/
|
||||
property var obj: Objects.currentObjects[objType][objIndex]
|
||||
|
||||
title: "LogarithmPlotter"
|
||||
width: 350
|
||||
height: 400
|
||||
|
||||
Label {
|
||||
id: dlgTitle
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: qsTr("Edit properties of %1 %2").arg(Objects.types[objEditor.objType].displayType()).arg(objEditor.obj.name)
|
||||
font.pixelSize: 20
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Column {
|
||||
id: dlgProperties
|
||||
anchors.top: dlgTitle.bottom
|
||||
width: objEditor.width - 20
|
||||
spacing: 10
|
||||
|
||||
D.MessageDialog {
|
||||
id: invalidNameDialog
|
||||
title: qsTr("LogarithmPlotter - Invalid object name")
|
||||
text: ""
|
||||
function showDialog(objectName) {
|
||||
text = qsTr("An object with the name '%1' already exists.").arg(objectName)
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
Setting.TextSetting {
|
||||
id: nameProperty
|
||||
height: 30
|
||||
label: qsTr("Name")
|
||||
icon: "common/label.svg"
|
||||
width: dlgProperties.width
|
||||
value: objEditor.obj.name
|
||||
onChanged: function(newValue) {
|
||||
let newName = Utils.parseName(newValue)
|
||||
if(newName != '' && objEditor.obj.name != newName) {
|
||||
if(newName in Objects.currentObjectsByName) {
|
||||
invalidNameDialog.showDialog(newName)
|
||||
} else {
|
||||
history.addToHistory(new HistoryLib.NameChanged(
|
||||
objEditor.obj.name, objEditor.objType, newName
|
||||
))
|
||||
Objects.renameObject(obj.name, newName)
|
||||
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Setting.ComboBoxSetting {
|
||||
id: labelContentProperty
|
||||
height: 30
|
||||
width: dlgProperties.width
|
||||
label: qsTr("Label content")
|
||||
model: [qsTr("null"), qsTr("name"), qsTr("name + value")]
|
||||
property var idModel: ["null", "name", "name + value"]
|
||||
icon: "common/label.svg"
|
||||
currentIndex: idModel.indexOf(objEditor.obj.labelContent)
|
||||
onActivated: function(newIndex) {
|
||||
if(idModel[newIndex] != objEditor.obj.labelContent) {
|
||||
objEditor.obj.labelContent = idModel[newIndex]
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic properties
|
||||
CustomPropertyList {
|
||||
id: dlgCustomProperties
|
||||
obj: objEditor.obj
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void EditorDialog::show()
|
||||
Shows the editor after the object to be edited is set.
|
||||
*/
|
||||
function show() {
|
||||
dlgCustomProperties.model = [] // Reset
|
||||
let objProps = Objects.types[objEditor.objType].properties()
|
||||
dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array.
|
||||
objEditor.open()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
|
||||
Dialog 1.0 Dialog.qml
|
||||
CustomPropertyList 1.0 CustomPropertyList.qml
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../js/objects.js" as Objects
|
||||
import "../js/objs/common.js" as ObjectsCommons
|
||||
import "../js/historylib.js" as HistoryLib
|
||||
import "../js/utils.js" as Utils
|
||||
import "../js/mathlib.js" as MathLib
|
||||
|
||||
/*!
|
||||
\qmltype EditorDialog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Dialog used to edit properties of objects.
|
||||
|
||||
This class contains the dialog that allows to edit all properties of objects.
|
||||
\todo In the future, this class should be optimized so that each property doesn't instanciate one instance of each setting type.
|
||||
|
||||
\sa LogarithmPlotter, ObjectLists
|
||||
*/
|
||||
D.Dialog {
|
||||
id: objEditor
|
||||
/*!
|
||||
\qmlproperty string EditorDialog::objType
|
||||
Type of object being edited by the dialog.
|
||||
*/
|
||||
property string objType: 'Point'
|
||||
/*!
|
||||
\qmlproperty int EditorDialog::objIndex
|
||||
Index of the objects amongst the ones of it's type.
|
||||
*/
|
||||
property int objIndex: 0
|
||||
/*!
|
||||
\qmlproperty var EditorDialog::obj
|
||||
Instance of the object being edited.
|
||||
*/
|
||||
property var obj: Objects.currentObjects[objType][objIndex]
|
||||
|
||||
title: "LogarithmPlotter"
|
||||
width: 350
|
||||
height: 400
|
||||
|
||||
Label {
|
||||
id: dlgTitle
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: qsTr("Edit properties of %1 %2").arg(Objects.types[objEditor.objType].displayType()).arg(objEditor.obj.name)
|
||||
font.pixelSize: 20
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Column {
|
||||
id: dlgProperties
|
||||
anchors.top: dlgTitle.bottom
|
||||
width: objEditor.width - 20
|
||||
spacing: 10
|
||||
|
||||
D.MessageDialog {
|
||||
id: invalidNameDialog
|
||||
title: qsTr("LogarithmPlotter - Invalid object name")
|
||||
text: ""
|
||||
function showDialog(objectName) {
|
||||
text = qsTr("An object with the name '%1' already exists.").arg(objectName)
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
Setting.TextSetting {
|
||||
id: nameProperty
|
||||
height: 30
|
||||
label: qsTr("Name")
|
||||
icon: "common/label.svg"
|
||||
width: dlgProperties.width
|
||||
value: objEditor.obj.name
|
||||
onChanged: function(newValue) {
|
||||
let newName = Utils.parseName(newValue)
|
||||
if(newName != '' && objEditor.obj.name != newName) {
|
||||
if(newName in Objects.currentObjectsByName) {
|
||||
invalidNameDialog.showDialog(newName)
|
||||
} else {
|
||||
history.addToHistory(new HistoryLib.NameChanged(
|
||||
objEditor.obj.name, objEditor.objType, newName
|
||||
))
|
||||
Objects.renameObject(obj.name, newName)
|
||||
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Setting.ComboBoxSetting {
|
||||
id: labelContentProperty
|
||||
height: 30
|
||||
width: dlgProperties.width
|
||||
label: qsTr("Label content")
|
||||
model: [qsTr("null"), qsTr("name"), qsTr("name + value")]
|
||||
property var idModel: ["null", "name", "name + value"]
|
||||
icon: "common/label.svg"
|
||||
currentIndex: idModel.indexOf(objEditor.obj.labelContent)
|
||||
onActivated: function(newIndex) {
|
||||
if(idModel[newIndex] != objEditor.obj.labelContent) {
|
||||
objEditor.obj.labelContent = idModel[newIndex]
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic properties
|
||||
Repeater {
|
||||
id: dlgCustomProperties
|
||||
|
||||
Item {
|
||||
height: customPropComment.height + customPropText.height + customPropCheckBox.height + customPropCombo.height + customPropListDict.height
|
||||
width: dlgProperties.width
|
||||
property string label: qsTranslate('prop',modelData[0])
|
||||
property string icon: Utils.camelCase2readable(modelData[0])
|
||||
|
||||
// Item for comments
|
||||
Label {
|
||||
id: customPropComment
|
||||
width: parent.width
|
||||
height: visible ? implicitHeight : 0
|
||||
visible: modelData[0].startsWith('comment')
|
||||
// Translated text with object name.
|
||||
property string trText: visible ? qsTranslate('comment', modelData[1]).toString() : ''
|
||||
text: (visible && trText.includes("%1") ? trText.arg(objEditor.obj.name) : trText).toString()
|
||||
//color: sysPalette.windowText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
// Setting for text & number settings as well as domains & expressions
|
||||
Setting.TextSetting {
|
||||
id: customPropText
|
||||
height: visible ? 30 : 0
|
||||
width: parent.width
|
||||
label: parent.label
|
||||
icon: `settings/custom/${parent.icon}.svg`
|
||||
isDouble: modelData[1] == 'number'
|
||||
visible: paramTypeIn(modelData[1], ['Expression', 'Domain', 'string', 'number'])
|
||||
defValue: visible ? {
|
||||
'Expression': () => Utils.simplifyExpression(objEditor.obj[modelData[0]].toEditableString()),
|
||||
'Domain': () => objEditor.obj[modelData[0]].toString(),
|
||||
'string': () => objEditor.obj[modelData[0]],
|
||||
'number': () => objEditor.obj[modelData[0]]
|
||||
}[modelData[1]]() : ""
|
||||
onChanged: function(newValue) {
|
||||
var newValue = {
|
||||
'Expression': () => new MathLib.Expression(newValue),
|
||||
'Domain': () => MathLib.parseDomain(newValue),
|
||||
'string': () => newValue,
|
||||
'number': () => parseFloat(newValue)
|
||||
}[modelData[1]]()
|
||||
// Ensuring old and new values are different to prevent useless adding to history.
|
||||
if(objEditor.obj[modelData[0]] != newValue) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||
objEditor.obj[modelData[0]], newValue
|
||||
))
|
||||
objEditor.obj[modelData[0]] = newValue
|
||||
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setting for boolean
|
||||
CheckBox {
|
||||
id: customPropCheckBox
|
||||
visible: modelData[1] == 'boolean'
|
||||
height: visible ? 20 : 0
|
||||
width: parent.width
|
||||
text: parent.label
|
||||
//icon: visible ? `settings/custom/${parent.icon}.svg` : ''
|
||||
|
||||
checked: visible ? objEditor.obj[modelData[0]] : false
|
||||
onClicked: {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||
objEditor.obj[modelData[0]], this.checked
|
||||
))
|
||||
objEditor.obj[modelData[0]] = this.checked
|
||||
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
|
||||
// Setting when selecting data from an enum, or an object of a certain type.
|
||||
Setting.ComboBoxSetting {
|
||||
id: customPropCombo
|
||||
width: dlgProperties.width
|
||||
height: visible ? 30 : 0
|
||||
label: parent.label
|
||||
icon: visible ? `settings/custom/${parent.icon}.svg` : ''
|
||||
// True to select an object of type, false for enums.
|
||||
property bool selectObjMode: paramTypeIn(modelData[1], ['ObjectType'])
|
||||
property bool isRealObject: !selectObjMode || (modelData[1].objType != "ExecutableObject" && modelData[1].objType != "DrawableObject")
|
||||
|
||||
// Base, untranslated version of the model.
|
||||
property var baseModel: visible ?
|
||||
(selectObjMode ?
|
||||
Objects.getObjectsName(modelData[1].objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())] :
|
||||
[]) :
|
||||
modelData[1].values)
|
||||
: []
|
||||
// Translated version of the model.
|
||||
model: selectObjMode ? baseModel : modelData[1].translatedValues
|
||||
visible: paramTypeIn(modelData[1], ['ObjectType', 'Enum'])
|
||||
currentIndex: baseModel.indexOf(selectObjMode ? objEditor.obj[modelData[0]].name : objEditor.obj[modelData[0]])
|
||||
|
||||
onActivated: function(newIndex) {
|
||||
if(selectObjMode) {
|
||||
// This is only done when what we're selecting are Objects.
|
||||
// Setting object property.
|
||||
var selectedObj = Objects.currentObjectsByName[baseModel[newIndex]]
|
||||
if(newIndex != 0) {
|
||||
// Make sure we don't set the object to null.
|
||||
if(selectedObj == null) {
|
||||
// Creating new object.
|
||||
selectedObj = Objects.createNewRegisteredObject(modelData[1].objType)
|
||||
history.addToHistory(new HistoryLib.CreateNewObject(selectedObj.name, modelData[1].objType, selectedObj.export()))
|
||||
baseModel = Objects.getObjectsName(modelData[1].objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())] :
|
||||
[])
|
||||
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||
}
|
||||
selectedObj.requiredBy.push(Objects.currentObjects[objEditor.objType][objEditor.objIndex])
|
||||
//Objects.currentObjects[objEditor.objType][objEditor.objIndex].requiredBy = objEditor.obj[modelData[0]].filter((obj) => objEditor.obj.name != obj.name)
|
||||
}
|
||||
objEditor.obj.requiredBy = objEditor.obj.requiredBy.filter((obj) => objEditor.obj.name != obj.name)
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||
objEditor.obj[modelData[0]], selectedObj
|
||||
))
|
||||
objEditor.obj[modelData[0]] = selectedObj
|
||||
} else if(baseModel[newIndex] != objEditor.obj[modelData[0]]) {
|
||||
// Ensuring new property is different to not add useless history entries.
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||
objEditor.obj[modelData[0]], baseModel[newIndex]
|
||||
))
|
||||
objEditor.obj[modelData[0]] = baseModel[newIndex]
|
||||
}
|
||||
// Refreshing
|
||||
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
|
||||
// Setting to edit lists or dictionaries (e.g sequences & repartition function values)
|
||||
Setting.ListSetting {
|
||||
id: customPropListDict
|
||||
width: parent.width
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
visible: paramTypeIn(modelData[1], ['List', 'Dict'])
|
||||
label: parent.label
|
||||
//icon: `settings/custom/${parent.icon}.svg`
|
||||
dictionaryMode: paramTypeIn(modelData[1], ['Dict'])
|
||||
keyType: dictionaryMode ? modelData[1].keyType : 'string'
|
||||
valueType: visible ? modelData[1].valueType : 'string'
|
||||
preKeyLabel: visible ? (dictionaryMode ? modelData[1].preKeyLabel : modelData[1].label).replace(/\{name\}/g, objEditor.obj.name) : ''
|
||||
postKeyLabel: visible ? (dictionaryMode ? modelData[1].postKeyLabel : '').replace(/\{name\}/g, objEditor.obj.name) : ''
|
||||
keyRegexp: dictionaryMode ? modelData[1].keyFormat : /^.+$/
|
||||
valueRegexp: visible ? modelData[1].format : /^.+$/
|
||||
forbidAdding: visible ? modelData[1].forbidAdding : false
|
||||
|
||||
onChanged: {
|
||||
var exported = exportModel()
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||
objEditor.obj[modelData[0]], exported
|
||||
))
|
||||
//Objects.currentObjects[objEditor.objType][objEditor.objIndex][modelData[0]] = exported
|
||||
objEditor.obj[modelData[0]] = exported
|
||||
//Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||
objEditor.obj.update()
|
||||
objectListList.update()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if(visible) importModel(objEditor.obj[modelData[0]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void EditorDialog::show()
|
||||
Shows the editor after the object to be edited is set.
|
||||
*/
|
||||
function show() {
|
||||
dlgCustomProperties.model = [] // Reset
|
||||
let objProps = Objects.types[objEditor.objType].properties()
|
||||
dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array.
|
||||
objEditor.open()
|
||||
}
|
||||
}
|
|
@ -20,11 +20,12 @@ import QtQuick 2.12
|
|||
import QtQuick.Dialogs 1.3 as D
|
||||
import QtQuick.Controls 2.12
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import eu.ad5001.LogarithmPlotter.ObjectLists.Editor 1.0 as Editor
|
||||
import "../js/objects.js" as Objects
|
||||
|
||||
/*!
|
||||
\qmltype ObjectLists
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Tab of the drawer that allows the user to manage the objects.
|
||||
|
||||
This item allows the user to synthetically see all objects, while giving the user the ability
|
||||
|
@ -113,7 +114,7 @@ ScrollView {
|
|||
}
|
||||
|
||||
// Object editor
|
||||
EditorDialog {
|
||||
Editor.Dialog {
|
||||
id: objEditor
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,13 @@ import "../js/math/latex.js" as LatexJS
|
|||
|
||||
/*!
|
||||
\qmltype ObjectRow
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Row describing an object.
|
||||
|
||||
This item allows the user to see, control, and modify a graph object.
|
||||
It includes the visibility checkbox, the description label (optionally latex if enabled),
|
||||
the reposition and delete buttons, and the color picker.
|
||||
|
||||
|
||||
\sa LogarithmPlotter, ObjectCreationGrid, ObjectLists
|
||||
*/
|
||||
Item {
|
||||
|
@ -42,11 +41,27 @@ Item {
|
|||
|
||||
signal changed()
|
||||
|
||||
/*!
|
||||
\qmlproperty var ObjectRow::obj
|
||||
Object to show.
|
||||
*/
|
||||
property var obj
|
||||
/*!
|
||||
\qmlproperty var ObjectRow::posPicker
|
||||
Reference to the global PositionPicker QML object.
|
||||
*/
|
||||
property var posPicker
|
||||
|
||||
/*!
|
||||
\qmlproperty bool ObjectRow::objVisible
|
||||
True if the object should be visible, false otherwise.
|
||||
*/
|
||||
property alias objVisible: objVisibilityCheckBox.checked
|
||||
property int minHeight: 40
|
||||
/*!
|
||||
\qmlproperty bool ObjectRow::minHeight
|
||||
Minimum height of the row.
|
||||
*/
|
||||
readonly property int minHeight: 40
|
||||
|
||||
height: objDescription.height
|
||||
width: obj.typeList.width
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
Image {
|
||||
id: expr
|
||||
property string expression
|
||||
|
||||
src: Latex.render(expression).split(',')[0]
|
||||
}
|
Loading…
Reference in a new issue