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 } |
|