src/editmodes/abstractEditMode.cc

branch
projects
changeset 935
8d98ee0dc917
parent 930
ab77deb851fa
parent 934
be8128aff739
child 936
aee883858c90
equal deleted inserted replaced
930:ab77deb851fa 935:8d98ee0dc917
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 - 2015 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <QMouseEvent>
20 #include <stdexcept>
21 #include "abstractEditMode.h"
22 #include "selectMode.h"
23 #include "drawMode.h"
24 #include "rectangleMode.h"
25 #include "circleMode.h"
26 #include "magicWandMode.h"
27 #include "linePathMode.h"
28 #include "../mainWindow.h"
29 #include "../glRenderer.h"
30
31 CFGENTRY (Bool, DrawLineLengths, true)
32 CFGENTRY (Bool, DrawAngles, false)
33
34 AbstractEditMode::AbstractEditMode (GLRenderer* renderer) :
35 m_renderer (renderer) {}
36
37 AbstractEditMode::~AbstractEditMode() {}
38
39 AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type)
40 {
41 switch (type)
42 {
43 case EditModeType::Select: return new SelectMode (renderer);
44 case EditModeType::Draw: return new DrawMode (renderer);
45 case EditModeType::Rectangle: return new RectangleMode (renderer);
46 case EditModeType::Circle: return new CircleMode (renderer);
47 case EditModeType::MagicWand: return new MagicWandMode (renderer);
48 case EditModeType::LinePath: return new LinePathMode (renderer);
49 }
50
51 throw std::logic_error ("bad type given to AbstractEditMode::createByType");
52 }
53
54 GLRenderer* AbstractEditMode::renderer() const
55 {
56 return m_renderer;
57 }
58
59 AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) :
60 AbstractEditMode (renderer),
61 m_polybrush (QBrush (QColor (64, 192, 0, 128)))
62 {
63 // Disable the context menu - we need the right mouse button
64 // for removing vertices.
65 renderer->setContextMenuPolicy (Qt::NoContextMenu);
66
67 // Use the crosshair cursor when drawing.
68 renderer->setCursor (Qt::CrossCursor);
69
70 // Clear the selection when beginning to draw.
71 CurrentDocument()->clearSelection();
72
73 g_win->updateSelection();
74 m_drawedVerts.clear();
75 }
76
77 AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) :
78 AbstractEditMode (renderer)
79 {
80 renderer->unsetCursor();
81 renderer->setContextMenuPolicy (Qt::DefaultContextMenu);
82 }
83
84 // =============================================================================
85 //
86 void AbstractDrawMode::addDrawnVertex (Vertex const& pos)
87 {
88 if (preAddVertex (pos))
89 return;
90
91 m_drawedVerts << pos;
92 }
93
94 bool AbstractDrawMode::mouseReleased (MouseEventData const& data)
95 {
96 if (Super::mouseReleased (data))
97 return true;
98
99 if ((data.releasedButtons & Qt::MidButton) and (m_drawedVerts.size() < 4) and (not data.mouseMoved))
100 {
101 // Find the closest vertex to our cursor
102 double minimumDistance = 1024.0;
103 const Vertex* closest = null;
104 Vertex cursorPosition = renderer()->coordconv2_3 (data.ev->pos(), false);
105 QPoint cursorPosition2D (data.ev->pos());
106 const Axis relZ = renderer()->getRelativeZ();
107 QVector<Vertex> vertices = renderer()->document()->inlineVertices();
108
109 // Sort the vertices in order of distance to camera
110 std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool
111 {
112 if (renderer()->getFixedCamera (renderer()->camera()).negatedDepth)
113 return a[relZ] > b[relZ];
114
115 return a[relZ] < b[relZ];
116 });
117
118 for (const Vertex& vrt : vertices)
119 {
120 // If the vertex in 2d space is very close to the cursor then we use
121 // it regardless of depth.
122 QPoint vect2d = renderer()->coordconv3_2 (vrt) - cursorPosition2D;
123 const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2);
124 if (distance2DSquared < 16.0 * 16.0)
125 {
126 closest = &vrt;
127 break;
128 }
129
130 // Check if too far away from the cursor.
131 if (distance2DSquared > 64.0 * 64.0)
132 continue;
133
134 // Not very close to the cursor. Compare using true distance,
135 // including depth.
136 const double distanceSquared = (vrt - cursorPosition).lengthSquared();
137
138 if (distanceSquared < minimumDistance)
139 {
140 minimumDistance = distanceSquared;
141 closest = &vrt;
142 }
143 }
144
145 if (closest != null)
146 addDrawnVertex (*closest);
147
148 return true;
149 }
150
151 if ((data.releasedButtons & Qt::RightButton) and (not m_drawedVerts.isEmpty()))
152 {
153 // Remove the last vertex
154 m_drawedVerts.removeLast();
155
156 return true;
157 }
158
159 return false;
160 }
161
162 void AbstractDrawMode::finishDraw (LDObjectList const& objs)
163 {
164 int pos = g_win->getInsertionPoint();
165
166 if (objs.size() > 0)
167 {
168 for (LDObjectPtr obj : objs)
169 {
170 renderer()->document()->insertObj (pos++, obj);
171 renderer()->compileObject (obj);
172 }
173
174 g_win->refresh();
175 g_win->endAction();
176 }
177
178 m_drawedVerts.clear();
179 }
180
181 void AbstractDrawMode::drawLength (QPainter &painter, const Vertex &v0, const Vertex &v1,
182 const QPointF& v0p, const QPointF& v1p) const
183 {
184 if (not cfg::DrawLineLengths)
185 return;
186
187 const QString label = QString::number ((v1 - v0).length());
188 QPoint origin = QLineF (v0p, v1p).pointAt (0.5).toPoint();
189 painter.drawText (origin, label);
190 }
191
192 void AbstractDrawMode::renderPolygon (QPainter& painter, const QVector<Vertex>& poly3d,
193 bool withlengths, bool withangles) const
194 {
195 QVector<QPoint> poly (poly3d.size());
196 QFontMetrics metrics = QFontMetrics (QFont());
197
198 // Convert to 2D
199 for (int i = 0; i < poly3d.size(); ++i)
200 poly[i] = renderer()->coordconv3_2 (poly3d[i]);
201
202 // Draw the polygon-to-be
203 painter.setBrush (m_polybrush);
204 painter.drawPolygon (QPolygonF (poly));
205
206 // Draw vertex blips
207 for (int i = 0; i < poly3d.size(); ++i)
208 {
209 QPoint& blip = poly[i];
210 painter.setPen (renderer()->linePen());
211 renderer()->drawBlip (painter, blip);
212
213 // Draw their coordinates
214 painter.setPen (renderer()->textPen());
215 painter.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true));
216 }
217
218 // Draw line lenghts and angle info if appropriate
219 if (poly3d.size() >= 2 and (withlengths or withangles))
220 {
221 painter.setPen (renderer()->textPen());
222
223 for (int i = 0; i < poly3d.size(); ++i)
224 {
225 const int j = (i + 1) % poly3d.size();
226 const int h = (i - 1 >= 0) ? (i - 1) : (poly3d.size() - 1);
227
228 if (withlengths)
229 drawLength (painter, poly3d[i], poly3d[j], poly[i], poly[j]);
230
231 if (withangles and cfg::DrawAngles)
232 {
233 QLineF l0 (poly[h], poly[i]),
234 l1 (poly[i], poly[j]);
235
236 double angle = 180 - l0.angleTo (l1);
237
238 if (angle < 0)
239 angle = 180 - l1.angleTo (l0);
240
241 QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260"));
242 QPoint pos = poly[i];
243 pos.setY (pos.y() + metrics.height());
244
245 painter.drawText (pos, label);
246 }
247 }
248 }
249 }
250
251 bool AbstractDrawMode::keyReleased (QKeyEvent *ev)
252 {
253 if (Super::keyReleased (ev))
254 return true;
255
256 if (not m_drawedVerts.isEmpty() and ev->key() == Qt::Key_Backspace)
257 {
258 m_drawedVerts.removeLast();
259 return true;
260 }
261
262 return false;
263 }

mercurial