48 this->ui.viewportFrame->setLayout(new QVBoxLayout{this->ui.listView}); |
51 this->ui.viewportFrame->setLayout(new QVBoxLayout{this->ui.listView}); |
49 this->ui.viewportFrame->layout()->addWidget(this->canvas); |
52 this->ui.viewportFrame->layout()->addWidget(this->canvas); |
50 this->toolsBar->setOrientation(Qt::Vertical); |
53 this->toolsBar->setOrientation(Qt::Vertical); |
51 this->setMouseTracking(true); |
54 this->setMouseTracking(true); |
52 connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); |
55 connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); |
|
56 connect(this->canvas, &Canvas::mouseClick, this, &Document::canvasMouseClick); |
|
57 connect(this->canvas, &Canvas::mouseMove, this, &Document::canvasMouseMove); |
53 connect(this->canvas, &Canvas::newStatusText, this, &Document::newStatusText); |
58 connect(this->canvas, &Canvas::newStatusText, this, &Document::newStatusText); |
54 connect(this->canvas, &Canvas::selectionChanged, [&](const QSet<ldraw::id_t>& newSelection) |
59 connect(this->canvas, &Canvas::selectionChanged, [&](const QSet<ldraw::id_t>& newSelection) |
55 { |
60 { |
56 QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); |
61 QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); |
57 QItemSelection selection; |
62 QItemSelection selection; |
151 } |
156 } |
152 this->ui.toolWidgetStack->addWidget(widget); |
157 this->ui.toolWidgetStack->addWidget(widget); |
153 this->toolActions.push_back(action); |
158 this->toolActions.push_back(action); |
154 connect(action, &QAction::triggered, this, &Document::editingModeTriggered); |
159 connect(action, &QAction::triggered, this, &Document::editingModeTriggered); |
155 } |
160 } |
|
161 this->ui.listView->selectAll(); |
156 } |
162 } |
157 |
163 |
158 void Document::editingModeTriggered() |
164 void Document::editingModeTriggered() |
159 { |
165 { |
160 QAction* triggeredAction = qobject_cast<QAction*>(this->sender()); |
166 QAction* triggeredAction = qobject_cast<QAction*>(this->sender()); |
161 if (triggeredAction != nullptr) |
167 if (triggeredAction != nullptr) |
162 { |
168 { |
163 const int index = triggeredAction->property(INDEX_PROPERTY).toInt(); |
169 const int index = triggeredAction->property(INDEX_PROPERTY).toInt(); |
164 this->canvas->mode = static_cast<EditingMode>(index); |
170 this->mode = static_cast<EditingMode>(index); |
165 this->ui.toolWidgetStack->setCurrentIndex(index); |
171 this->ui.toolWidgetStack->setCurrentIndex(index); |
166 for (QAction* action : this->toolActions) { |
172 for (QAction* action : this->toolActions) { |
167 action->setChecked(action == triggeredAction); |
173 action->setChecked(action == triggeredAction); |
168 } |
174 } |
169 } |
175 } |
170 } |
176 } |
171 |
177 |
|
178 void updatePreviewPolygon(DrawState* drawState) |
|
179 { |
|
180 drawState->previewPolygon = drawState->polygon; |
|
181 drawState->previewPolygon.resize(drawState->polygon.size() + 1); |
|
182 drawState->previewPolygon.back() = drawState->previewPoint; |
|
183 if (drawState->previewPolygon.size() > 2) |
|
184 { |
|
185 drawState->isconcave = not geom::isConvex(drawState->previewPolygon); |
|
186 } |
|
187 } |
|
188 |
|
189 void removeLastPoint(DrawState* drawState) |
|
190 { |
|
191 if (drawState->polygon.size() > 0) |
|
192 { |
|
193 drawState->polygon.erase(drawState->polygon.end() - 1); |
|
194 updatePreviewPolygon(drawState); |
|
195 } |
|
196 } |
|
197 |
|
198 bool isCloseToExistingPoints(const std::vector<glm::vec3>& points, const glm::vec3 &pos) |
|
199 { |
|
200 return any(points, std::bind(geom::isclose, std::placeholders::_1, pos)); |
|
201 } |
|
202 |
|
203 void Document::canvasMouseClick(QMouseEvent *event) |
|
204 { |
|
205 switch(this->mode) |
|
206 { |
|
207 case SelectMode: |
|
208 if (event->button() == Qt::LeftButton) |
|
209 { |
|
210 const ldraw::id_t highlighted = this->canvas->getHighlightedObject(); |
|
211 QSet<ldraw::id_t> selected; |
|
212 if (highlighted != ldraw::NULL_ID) { |
|
213 selected.insert(highlighted); |
|
214 } |
|
215 this->select(selected); |
|
216 event->accept(); |
|
217 } |
|
218 break; |
|
219 case DrawMode: |
|
220 if (event->button() == Qt::LeftButton and this->canvas->worldPosition.has_value()) |
|
221 { |
|
222 const glm::vec3& pos = this->canvas->worldPosition.value(); |
|
223 if (isCloseToExistingPoints(this->drawState.polygon, pos)) |
|
224 { |
|
225 this->closeShape(); |
|
226 } |
|
227 else |
|
228 { |
|
229 this->drawState.polygon.push_back(pos); |
|
230 updatePreviewPolygon(&this->drawState); |
|
231 } |
|
232 event->accept(); |
|
233 } |
|
234 else if (true |
|
235 and event->button() == Qt::RightButton |
|
236 and this->drawState.polygon.size() > 0 |
|
237 ) { |
|
238 this->drawState.polygon.erase(this->drawState.polygon.end() - 1); |
|
239 updatePreviewPolygon(&this->drawState); |
|
240 event->accept(); |
|
241 } |
|
242 break; |
|
243 } |
|
244 } |
|
245 |
|
246 void Document::canvasMouseMove(QMouseEvent *event) |
|
247 { |
|
248 switch(this->mode) |
|
249 { |
|
250 case SelectMode: |
|
251 break; |
|
252 case DrawMode: |
|
253 if (this->canvas->worldPosition.has_value()) |
|
254 { |
|
255 this->drawState.previewPoint = this->canvas->worldPosition.value(); |
|
256 updatePreviewPolygon(&this->drawState); |
|
257 this->update(); |
|
258 } |
|
259 event->accept(); |
|
260 break; |
|
261 } |
|
262 } |
|
263 |
|
264 void Document::select(const QSet<ldraw::id_t> &selected) |
|
265 { |
|
266 QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); |
|
267 QItemSelection itemSelection; |
|
268 for (const ldraw::id_t id : selected) |
|
269 { |
|
270 QModelIndex index = this->model->find(id); |
|
271 if (index != QModelIndex{}) |
|
272 { |
|
273 itemSelection.select(index, index); |
|
274 } |
|
275 } |
|
276 selectionModel->select(itemSelection, QItemSelectionModel::ClearAndSelect); |
|
277 } |
|
278 |
172 const Model &Document::getModel() const |
279 const Model &Document::getModel() const |
173 { |
280 { |
174 return *this->model; |
281 return *this->model; |
175 } |
282 } |
176 |
283 |
177 const QSet<ldraw::id_t> Document::selectedObjects() const |
284 const QSet<ldraw::id_t> Document::selectedObjects() const |
178 { |
285 { |
179 return this->canvas->selectedObjects(); |
286 return this->canvas->selectedObjects(); |
180 } |
287 } |
|
288 |
|
289 void Document::closeShape() |
|
290 { |
|
291 if (this->drawState.polygon.size() >= 2 and this->drawState.polygon.size() <= 4) |
|
292 { |
|
293 std::unique_ptr<ModelEditor> modelEditor = this->editModel(); |
|
294 switch (this->drawState.polygon.size()) |
|
295 { |
|
296 case 2: |
|
297 modelEditor->append<ldraw::Edge>( |
|
298 vectorToArray<2>(this->drawState.polygon), |
|
299 ldraw::EDGE_COLOR); |
|
300 break; |
|
301 case 3: |
|
302 modelEditor->append<ldraw::Triangle>( |
|
303 vectorToArray<3>(this->drawState.polygon), |
|
304 ldraw::MAIN_COLOR); |
|
305 break; |
|
306 case 4: |
|
307 modelEditor->append<ldraw::Quadrilateral>( |
|
308 vectorToArray<4>(this->drawState.polygon), |
|
309 ldraw::MAIN_COLOR); |
|
310 break; |
|
311 } |
|
312 } |
|
313 this->drawState.polygon.clear(); |
|
314 updatePreviewPolygon(&this->drawState); |
|
315 } |