| 1 #include <QCheckBox> |
1 #include <QCheckBox> |
| 2 #include <QLineEdit> |
2 #include <QLineEdit> |
| 3 #include <QFormLayout> |
3 #include <QFormLayout> |
| 4 #include "objecteditor.h" |
4 #include "objecteditor.h" |
| 5 #include "document.h" |
5 #include "document.h" |
| 6 #include "modeleditor.h" |
|
| 7 #include "widgets/colorbutton.h" |
6 #include "widgets/colorbutton.h" |
| 8 #include "widgets/colorindexinput.h" |
7 #include "widgets/colorindexinput.h" |
| 9 #include "widgets/vec3editor.h" |
8 #include "widgets/vec3editor.h" |
| 10 #include "ui_objecteditor.h" |
9 #include "ui_objecteditor.h" |
| 11 |
10 |
| 12 ObjectEditor::ObjectEditor(Document* document, const ldraw::id_t id) : |
11 using PropertyValue = std::variant< |
| 13 QWidget{document}, |
12 const glm::vec3*, |
| 14 ui{*new Ui_ObjectEditor}, |
13 const glm::mat4*, |
| 15 document{document} |
14 const QString*, |
| |
15 ldraw::Color>; |
| |
16 |
| |
17 enum PropertyKey |
| 16 { |
18 { |
| 17 this->ui.setupUi(this); |
19 Point1, |
| 18 this->setObjectId(id); |
20 Point2, |
| 19 QFormLayout* formLayout = new QFormLayout{ui.properties}; |
21 Point3, |
| 20 this->ui.properties->setLayout(formLayout); |
22 Point4, |
| 21 for (const ldraw::Property property : ldraw::ALL_PROPERTIES) |
23 Control1, |
| 22 { |
24 Control2, |
| 23 QWidget* editorWidget = this->makeEditorWidgetForProperty(property); |
25 Color, |
| 24 if (editorWidget != nullptr) |
26 Transformation, |
| 25 { |
27 Name, |
| 26 editorWidget->setProperty("_property_id", static_cast<int>(property)); |
28 Text, |
| 27 QLabel* propertyLabel = new QLabel{ldraw::traits(property).name.data()}; |
29 Code, |
| 28 formLayout->addRow(propertyLabel, editorWidget); |
30 }; |
| 29 this->propertyWidgets[property] = {propertyLabel, editorWidget}; |
31 |
| 30 } |
32 std::map<PropertyKey, PropertyValue> getProperties(const ModelElement& element) |
| 31 } |
33 { |
| 32 this->setObjectId(ldraw::NULL_ID); |
34 std::map<PropertyKey, PropertyValue> result; |
| |
35 std::visit<void>(overloaded{ |
| |
36 [&](const Colored<LineSegment>& edge) { |
| |
37 result[Point1] = &edge.p1; |
| |
38 result[Point2] = &edge.p2; |
| |
39 result[Color] = edge.color; |
| |
40 }, |
| |
41 [&](const Colored<Triangle>& tri) { |
| |
42 result[Point1] = &tri.p1; |
| |
43 result[Point2] = &tri.p2; |
| |
44 result[Point3] = &tri.p3; |
| |
45 result[Color] = tri.color; |
| |
46 }, |
| |
47 [&](const Colored<Quadrilateral>& quad) { |
| |
48 result[Point1] = &quad.p1; |
| |
49 result[Point2] = &quad.p2; |
| |
50 result[Point3] = &quad.p3; |
| |
51 result[Point4] = &quad.p4; |
| |
52 result[Color] = quad.color; |
| |
53 }, |
| |
54 [&](const Colored<ConditionalEdge>& cedge) { |
| |
55 result[Point1] = &cedge.p1; |
| |
56 result[Point2] = &cedge.p2; |
| |
57 result[Control1] = &cedge.c1; |
| |
58 result[Control2] = &cedge.c2; |
| |
59 result[Color] = cedge.color; |
| |
60 }, |
| |
61 [&](const Colored<SubfileReference>& ref) { |
| |
62 result[Transformation] = &ref.transformation; |
| |
63 result[Name] = &ref.name; |
| |
64 result[Color] = ref.color; |
| |
65 }, |
| |
66 [&](Empty) {}, |
| |
67 [&](const Comment& comment) { |
| |
68 result[Text] = &comment.text; |
| |
69 }, |
| |
70 [&](const ParseError& parseError) { |
| |
71 result[Code] = &parseError.code; |
| |
72 }, |
| |
73 }, element); |
| |
74 return result; |
| 33 } |
75 } |
| 34 |
|
| 35 ObjectEditor::~ObjectEditor() |
|
| 36 { |
|
| 37 delete &this->ui; |
|
| 38 } |
|
| 39 |
|
| 40 QString titleCase(const QString& string) |
|
| 41 { |
|
| 42 return string.left(1).toUpper() + string.mid(1); |
|
| 43 } |
|
| 44 |
|
| 45 void setValueToWidget(QWidget* widget, const QVariant& value) |
|
| 46 { |
|
| 47 ColorIndexInput* colorIndexInput = qobject_cast<ColorIndexInput*>(widget); |
|
| 48 if (colorIndexInput != nullptr) |
|
| 49 { |
|
| 50 colorIndexInput->setSelectedColor(value.value<ldraw::Color>()); |
|
| 51 } |
|
| 52 else |
|
| 53 { |
|
| 54 Vec3Editor* vec3Editor = qobject_cast<Vec3Editor*>(widget); |
|
| 55 if (vec3Editor != nullptr) |
|
| 56 { |
|
| 57 vec3Editor->setValue(value.value<glm::vec3>()); |
|
| 58 } |
|
| 59 else |
|
| 60 { |
|
| 61 QCheckBox* checkBox = qobject_cast<QCheckBox*>(widget); |
|
| 62 if (checkBox != nullptr) |
|
| 63 { |
|
| 64 checkBox->setChecked(value.toBool()); |
|
| 65 } |
|
| 66 else |
|
| 67 { |
|
| 68 QLineEdit* lineEdit = qobject_cast<QLineEdit*>(widget); |
|
| 69 if (lineEdit != nullptr) |
|
| 70 { |
|
| 71 lineEdit->setText(value.toString()); |
|
| 72 } |
|
| 73 } |
|
| 74 } |
|
| 75 } |
|
| 76 } |
|
| 77 |
|
| 78 void ObjectEditor::setObjectId(const ldraw::id_t id) |
|
| 79 { |
|
| 80 this->objectId = id; |
|
| 81 const ldraw::Object* object = this->document->getModel().get(id); |
|
| 82 this->ui.properties->setEnabled(object != nullptr); |
|
| 83 if (object != nullptr) |
|
| 84 { |
|
| 85 this->ui.typeNameLabel->setText("<b>" + titleCase(object->typeName()) + "</b>"); |
|
| 86 this->ui.typeIconLabel->setPixmap(QPixmap{object->iconName()}.scaledToWidth(24)); |
|
| 87 for (const ldraw::Property property : ldraw::ALL_PROPERTIES) |
|
| 88 { |
|
| 89 const QVariant value = object->getProperty(property); |
|
| 90 const auto it = this->propertyWidgets.find(property); |
|
| 91 if (it != this->propertyWidgets.end()) |
|
| 92 { |
|
| 93 it->first->setEnabled(not value.isNull()); |
|
| 94 it->second->setEnabled(not value.isNull()); |
|
| 95 if (not value.isNull()) |
|
| 96 { |
|
| 97 setValueToWidget(it->second, value); |
|
| 98 } |
|
| 99 } |
|
| 100 } |
|
| 101 } |
|
| 102 else |
|
| 103 { |
|
| 104 this->ui.typeNameLabel->setText(tr("No object selected")); |
|
| 105 this->ui.typeIconLabel->clear(); |
|
| 106 } |
|
| 107 } |
|
| 108 |
|
| 109 void ObjectEditor::handleColorChange(ldraw::Color value) |
|
| 110 { |
|
| 111 this->handlePropertyChange(this->sender(), QVariant::fromValue(value)); |
|
| 112 } |
|
| 113 |
|
| 114 void ObjectEditor::handleVec3Change(const glm::vec3 &value) |
|
| 115 { |
|
| 116 this->handlePropertyChange(this->sender(), QVariant::fromValue(value)); |
|
| 117 } |
|
| 118 |
|
| 119 void ObjectEditor::handleBoolChange(bool value) |
|
| 120 { |
|
| 121 this->handlePropertyChange(this->sender(), QVariant::fromValue(value)); |
|
| 122 } |
|
| 123 |
|
| 124 void ObjectEditor::handleStringChange(const QString &value) |
|
| 125 { |
|
| 126 this->handlePropertyChange(this->sender(), QVariant::fromValue(value)); |
|
| 127 } |
|
| 128 |
|
| 129 QWidget* ObjectEditor::makeEditorWidgetForProperty(ldraw::Property property) |
|
| 130 { |
|
| 131 QWidget* const parent = qobject_cast<QWidget*>(this->parent()); |
|
| 132 if (ldraw::traits(property).type == qMetaTypeId<ldraw::Color>()) |
|
| 133 { |
|
| 134 ColorIndexInput* colorWidget = new ColorIndexInput{this->document, {0}, parent}; |
|
| 135 connect(colorWidget, &ColorIndexInput::colorChanged, this, &ObjectEditor::handleColorChange); |
|
| 136 return colorWidget; |
|
| 137 } |
|
| 138 else if (ldraw::traits(property).type == qMetaTypeId<glm::vec3>()) |
|
| 139 { |
|
| 140 Vec3Editor* editor = new Vec3Editor{{}, parent}; |
|
| 141 connect(editor, &Vec3Editor::valueChanged, this, &ObjectEditor::handleVec3Change); |
|
| 142 return editor; |
|
| 143 } |
|
| 144 else if (ldraw::traits(property).type == qMetaTypeId<bool>()) |
|
| 145 { |
|
| 146 QCheckBox* editor = new QCheckBox{{}, parent}; |
|
| 147 connect(editor, &QCheckBox::clicked, this, &ObjectEditor::handleBoolChange); |
|
| 148 return editor; |
|
| 149 } |
|
| 150 else if (ldraw::traits(property).type == qMetaTypeId<QString>()) |
|
| 151 { |
|
| 152 QLineEdit* editor = new QLineEdit{{}, parent}; |
|
| 153 connect(editor, &QLineEdit::textChanged, this, &ObjectEditor::handleStringChange); |
|
| 154 return editor; |
|
| 155 } |
|
| 156 else |
|
| 157 { |
|
| 158 return nullptr; |
|
| 159 } |
|
| 160 } |
|
| 161 |
|
| 162 void ObjectEditor::handlePropertyChange(QObject *caller, const QVariant &value) |
|
| 163 { |
|
| 164 QVariant propertyVariant = caller->property("_property_id"); |
|
| 165 if (not propertyVariant.isNull()) |
|
| 166 { |
|
| 167 ldraw::Property const property = static_cast<ldraw::Property>(propertyVariant.toInt()); |
|
| 168 this->document->editModel()->setObjectProperty(this->objectId, property, value); |
|
| 169 } |
|
| 170 } |
|