# HG changeset patch # User Santeri Piippo # Date 1404514951 -10800 # Node ID a741a0b9df49998f17f3fd3991408c00ec9ee42d # Parent bb903e89e23c2ef7da135d7a4006625340d2acc8 - updated filenames diff -r bb903e89e23c -r a741a0b9df49 CMakeLists.txt --- a/CMakeLists.txt Sat Jul 05 01:45:32 2014 +0300 +++ b/CMakeLists.txt Sat Jul 05 02:02:31 2014 +0300 @@ -47,11 +47,11 @@ src/primitives.cc src/radioGroup.cc src/version.cc - src/editmodes/abstracteditmode.cc - src/editmodes/circlemode.cc - src/editmodes/drawmode.cc - src/editmodes/magicwandmode.cc - src/editmodes/selectmode.cc + src/editmodes/abstractEditMode.cc + src/editmodes/circleMode.cc + src/editmodes/drawMode.cc + src/editmodes/magicWandMode.cc + src/editmodes/selectMode.cc ) set (LDFORGE_HEADERS @@ -80,11 +80,11 @@ src/mainWindow.h src/editHistory.h src/format.h - src/editmodes/abstracteditmode.h - src/editmodes/circlemode.h - src/editmodes/drawmode.h - src/editmodes/magicwandmode.h - src/editmodes/selectmode.h + src/editmodes/abstractEditMode.h + src/editmodes/circleMode.h + src/editmodes/drawMode.h + src/editmodes/magicWandMode.h + src/editmodes/selectMode.h ) set (LDFORGE_FORMS diff -r bb903e89e23c -r a741a0b9df49 src/actions.cc --- a/src/actions.cc Sat Jul 05 01:45:32 2014 +0300 +++ b/src/actions.cc Sat Jul 05 02:02:31 2014 +0300 @@ -37,7 +37,7 @@ #include "colors.h" #include "glCompiler.h" #include "ui_newpart.h" -#include "editmodes/abstracteditmode.h" +#include "editmodes/abstractEditMode.h" EXTERN_CFGENTRY (Bool, drawWireframe); EXTERN_CFGENTRY (Bool, bfcRedGreenView); diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/abstractEditMode.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/abstractEditMode.cc Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,177 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#include +#include +#include "abstractEditMode.h" +#include "selectMode.h" +#include "drawMode.h" +#include "circleMode.h" +#include "magicWandMode.h" +#include "../mainWindow.h" +#include "../glRenderer.h" + +AbstractEditMode::AbstractEditMode (GLRenderer* renderer) : + _renderer (renderer) {} + +AbstractEditMode::~AbstractEditMode() {} + +AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type) +{ + switch (type) + { + case EditModeType::Select: return new SelectMode (renderer); + case EditModeType::Draw: return new DrawMode (renderer); + case EditModeType::Circle: return new CircleMode (renderer); + case EditModeType::MagicWand: return new MagicWandMode (renderer); + } + + throw std::logic_error ("bad type given to AbstractEditMode::createByType"); +} + +GLRenderer* AbstractEditMode::renderer() const +{ + return _renderer; +} + +AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) : + AbstractEditMode (renderer), + _polybrush (QBrush (QColor (64, 192, 0, 128))) +{ + // Disable the context menu - we need the right mouse button + // for removing vertices. + renderer->setContextMenuPolicy (Qt::NoContextMenu); + + // Use the crosshair cursor when drawing. + renderer->setCursor (Qt::CrossCursor); + + // Clear the selection when beginning to draw. + getCurrentDocument()->clearSelection(); + + g_win->updateSelection(); + _drawedVerts.clear(); +} + +AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) : + AbstractEditMode (renderer) +{ + renderer->unsetCursor(); + renderer->setContextMenuPolicy (Qt::DefaultContextMenu); +} + +// ============================================================================= +// +void AbstractDrawMode::addDrawnVertex (Vertex const& pos) +{ + if (preAddVertex (pos)) + return; + + _drawedVerts << pos; +} + +bool AbstractDrawMode::mouseReleased (MouseEventData const& data) +{ + if (Super::mouseReleased (data)) + return true; + + if ((data.releasedButtons & Qt::MidButton) && (_drawedVerts.size() < 4) && (not data.mouseMoved)) + { + // Find the closest vertex to our cursor + double minimumDistance = 1024.0; + const Vertex* closest = null; + Vertex cursorPosition = renderer()->coordconv2_3 (data.ev->pos(), false); + QPoint cursorPosition2D (data.ev->pos()); + const Axis relZ = renderer()->getRelativeZ(); + QVector vertices; + + for (auto it = renderer()->document()->vertices().begin(); + it != renderer()->document()->vertices().end(); + ++it) + { + vertices << it.key(); + } + + // Sort the vertices in order of distance to camera + std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool + { + if (renderer()->getFixedCamera (renderer()->camera()).negatedDepth) + return a[relZ] > b[relZ]; + + return a[relZ] < b[relZ]; + }); + + for (const Vertex& vrt : vertices) + { + // If the vertex in 2d space is very close to the cursor then we use + // it regardless of depth. + QPoint vect2d = renderer()->coordconv3_2 (vrt) - cursorPosition2D; + const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2); + if (distance2DSquared < 16.0 * 16.0) + { + closest = &vrt; + break; + } + + // Check if too far away from the cursor. + if (distance2DSquared > 64.0 * 64.0) + continue; + + // Not very close to the cursor. Compare using true distance, + // including depth. + const double distanceSquared = (vrt - cursorPosition).lengthSquared(); + + if (distanceSquared < minimumDistance) + { + minimumDistance = distanceSquared; + closest = &vrt; + } + } + + if (closest != null) + addDrawnVertex (*closest); + + return true; + } + + if ((data.releasedButtons & Qt::RightButton) && (not _drawedVerts.isEmpty())) + { + // Remove the last vertex + _drawedVerts.removeLast(); + + return true; + } + + return false; +} + +void AbstractDrawMode::finishDraw (LDObjectList& objs) +{ + if (objs.size() > 0) + { + for (LDObjectPtr obj : objs) + { + renderer()->document()->addObject (obj); + renderer()->compileObject (obj); + } + + g_win->refresh(); + g_win->endAction(); + } + + _drawedVerts.clear(); +} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/abstractEditMode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/abstractEditMode.h Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,106 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#pragma once +#include "../main.h" + +class QPainter; +class GLRenderer; +class QMouseEvent; + +enum class EditModeType +{ + Select, + Draw, + Circle, + MagicWand, +}; + +class AbstractEditMode +{ + GLRenderer* _renderer; + +public: + struct MouseEventData + { + QMouseEvent* ev; + Qt::KeyboardModifiers keymods; + bool mouseMoved; + Qt::MouseButtons releasedButtons; + }; + + AbstractEditMode (GLRenderer* renderer); + virtual ~AbstractEditMode(); + + virtual bool allowFreeCamera() const = 0; + virtual void render (QPainter&) const {}; + GLRenderer* renderer() const; + virtual EditModeType type() const = 0; + virtual bool mousePressed (QMouseEvent*) { return false; } + virtual bool mouseReleased (MouseEventData const&) { return false; } + virtual bool mouseDoubleClicked (QMouseEvent*) { return false; } + virtual bool mouseMoved (QMouseEvent*) { return false; } + + static AbstractEditMode* createByType (GLRenderer* renderer, EditModeType type); +}; + +// +// Base class for draw-like edit modes +// +class AbstractDrawMode : public AbstractEditMode +{ + DEFINE_CLASS (AbstractDrawMode, AbstractEditMode) + +protected: + QList _drawedVerts; + Vertex _rectverts[4]; + QBrush _polybrush; + +public: + AbstractDrawMode (GLRenderer* renderer); + + virtual bool allowFreeCamera() const override + { + return false; + } + + bool mouseReleased (const AbstractEditMode::MouseEventData& data) override; + void addDrawnVertex (const Vertex& pos); + void finishDraw (LDObjectList& objs); + + virtual bool preAddVertex (Vertex const&) + { + return false; + } +}; + +// +// Base class for select-like edit modes +// +class AbstractSelectMode : public AbstractEditMode +{ + DEFINE_CLASS (AbstractSelectMode, AbstractEditMode) + +public: + AbstractSelectMode (GLRenderer* renderer); + + virtual bool allowFreeCamera() const override + { + return true; + } +}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/abstracteditmode.cc --- a/src/editmodes/abstracteditmode.cc Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include -#include -#include "abstracteditmode.h" -#include "selectmode.h" -#include "drawmode.h" -#include "circlemode.h" -#include "magicwandmode.h" -#include "../mainWindow.h" -#include "../glRenderer.h" - -AbstractEditMode::AbstractEditMode (GLRenderer* renderer) : - _renderer (renderer) {} - -AbstractEditMode::~AbstractEditMode() {} - -AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type) -{ - switch (type) - { - case EditModeType::Select: return new SelectMode (renderer); - case EditModeType::Draw: return new DrawMode (renderer); - case EditModeType::Circle: return new CircleMode (renderer); - case EditModeType::MagicWand: return new MagicWandMode (renderer); - } - - throw std::logic_error ("bad type given to AbstractEditMode::createByType"); -} - -GLRenderer* AbstractEditMode::renderer() const -{ - return _renderer; -} - -AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) : - AbstractEditMode (renderer), - _polybrush (QBrush (QColor (64, 192, 0, 128))) -{ - // Disable the context menu - we need the right mouse button - // for removing vertices. - renderer->setContextMenuPolicy (Qt::NoContextMenu); - - // Use the crosshair cursor when drawing. - renderer->setCursor (Qt::CrossCursor); - - // Clear the selection when beginning to draw. - getCurrentDocument()->clearSelection(); - - g_win->updateSelection(); - _drawedVerts.clear(); -} - -AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) : - AbstractEditMode (renderer) -{ - renderer->unsetCursor(); - renderer->setContextMenuPolicy (Qt::DefaultContextMenu); -} - -// ============================================================================= -// -void AbstractDrawMode::addDrawnVertex (Vertex const& pos) -{ - if (preAddVertex (pos)) - return; - - _drawedVerts << pos; -} - -bool AbstractDrawMode::mouseReleased (MouseEventData const& data) -{ - if (Super::mouseReleased (data)) - return true; - - if ((data.releasedButtons & Qt::MidButton) && (_drawedVerts.size() < 4) && (not data.mouseMoved)) - { - // Find the closest vertex to our cursor - double minimumDistance = 1024.0; - const Vertex* closest = null; - Vertex cursorPosition = renderer()->coordconv2_3 (data.ev->pos(), false); - QPoint cursorPosition2D (data.ev->pos()); - const Axis relZ = renderer()->getRelativeZ(); - QVector vertices; - - for (auto it = renderer()->document()->vertices().begin(); - it != renderer()->document()->vertices().end(); - ++it) - { - vertices << it.key(); - } - - // Sort the vertices in order of distance to camera - std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool - { - if (renderer()->getFixedCamera (renderer()->camera()).negatedDepth) - return a[relZ] > b[relZ]; - - return a[relZ] < b[relZ]; - }); - - for (const Vertex& vrt : vertices) - { - // If the vertex in 2d space is very close to the cursor then we use - // it regardless of depth. - QPoint vect2d = renderer()->coordconv3_2 (vrt) - cursorPosition2D; - const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2); - if (distance2DSquared < 16.0 * 16.0) - { - closest = &vrt; - break; - } - - // Check if too far away from the cursor. - if (distance2DSquared > 64.0 * 64.0) - continue; - - // Not very close to the cursor. Compare using true distance, - // including depth. - const double distanceSquared = (vrt - cursorPosition).lengthSquared(); - - if (distanceSquared < minimumDistance) - { - minimumDistance = distanceSquared; - closest = &vrt; - } - } - - if (closest != null) - addDrawnVertex (*closest); - - return true; - } - - if ((data.releasedButtons & Qt::RightButton) && (not _drawedVerts.isEmpty())) - { - // Remove the last vertex - _drawedVerts.removeLast(); - - return true; - } - - return false; -} - -void AbstractDrawMode::finishDraw (LDObjectList& objs) -{ - if (objs.size() > 0) - { - for (LDObjectPtr obj : objs) - { - renderer()->document()->addObject (obj); - renderer()->compileObject (obj); - } - - g_win->refresh(); - g_win->endAction(); - } - - _drawedVerts.clear(); -} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/abstracteditmode.h --- a/src/editmodes/abstracteditmode.h Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#pragma once -#include "../main.h" - -class QPainter; -class GLRenderer; -class QMouseEvent; - -enum class EditModeType -{ - Select, - Draw, - Circle, - MagicWand, -}; - -class AbstractEditMode -{ - GLRenderer* _renderer; - -public: - struct MouseEventData - { - QMouseEvent* ev; - Qt::KeyboardModifiers keymods; - bool mouseMoved; - Qt::MouseButtons releasedButtons; - }; - - AbstractEditMode (GLRenderer* renderer); - virtual ~AbstractEditMode(); - - virtual bool allowFreeCamera() const = 0; - virtual void render (QPainter&) const {}; - GLRenderer* renderer() const; - virtual EditModeType type() const = 0; - virtual bool mousePressed (QMouseEvent*) { return false; } - virtual bool mouseReleased (MouseEventData const&) { return false; } - virtual bool mouseDoubleClicked (QMouseEvent*) { return false; } - virtual bool mouseMoved (QMouseEvent*) { return false; } - - static AbstractEditMode* createByType (GLRenderer* renderer, EditModeType type); -}; - -// -// Base class for draw-like edit modes -// -class AbstractDrawMode : public AbstractEditMode -{ - DEFINE_CLASS (AbstractDrawMode, AbstractEditMode) - -protected: - QList _drawedVerts; - Vertex _rectverts[4]; - QBrush _polybrush; - -public: - AbstractDrawMode (GLRenderer* renderer); - - virtual bool allowFreeCamera() const override - { - return false; - } - - bool mouseReleased (const AbstractEditMode::MouseEventData& data) override; - void addDrawnVertex (const Vertex& pos); - void finishDraw (LDObjectList& objs); - - virtual bool preAddVertex (Vertex const&) - { - return false; - } -}; - -// -// Base class for select-like edit modes -// -class AbstractSelectMode : public AbstractEditMode -{ - DEFINE_CLASS (AbstractSelectMode, AbstractEditMode) - -public: - AbstractSelectMode (GLRenderer* renderer); - - virtual bool allowFreeCamera() const override - { - return true; - } -}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/circleMode.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/circleMode.cc Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,284 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#include +#include "circleMode.h" +#include "../miscallenous.h" +#include "../ldObject.h" +#include "../ldDocument.h" +#include "../misc/ringFinder.h" +#include "../primitives.h" +#include "../glRenderer.h" + +CircleMode::CircleMode (GLRenderer* renderer) : + Super (renderer) {} + +EditModeType CircleMode::type() const +{ + return EditModeType::Circle; +} + +double CircleMode::getCircleDrawDist (int pos) const +{ + assert (_drawedVerts.size() >= pos + 1); + Vertex v1 = (_drawedVerts.size() >= pos + 2) ? _drawedVerts[pos + 1] : + renderer()->coordconv2_3 (renderer()->mousePosition(), false); + Axis localx, localy; + renderer()->getRelativeAxes (localx, localy); + double dx = _drawedVerts[0][localx] - v1[localx]; + double dy = _drawedVerts[0][localy] - v1[localy]; + return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate); +} + +Matrix CircleMode::getCircleDrawMatrix (double scale) +{ + // Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed. + static const Matrix templates[3] = + { + { 2, 0, 0, 0, 1, 0, 0, 0, 2 }, + { 2, 0, 0, 0, 0, 2, 0, 1, 0 }, + { 0, 1, 0, 2, 0, 0, 0, 0, 2 }, + }; + + Matrix transform = templates[renderer()->camera() % 3]; + + for (int i = 0; i < 9; ++i) + { + if (transform[i] == 2) + transform[i] = scale; + elif (transform[i] == 1 && renderer()->camera() >= 3) + transform[i] = -1; + } + + return transform; +} + +void CircleMode::buildCircle() +{ + LDObjectList objs; + const int segs = g_lores, divs = g_lores; // TODO: make customizable + double dist0 = getCircleDrawDist (0), + dist1 = getCircleDrawDist (1); + LDDocumentPtr refFile; + Matrix transform; + bool circleOrDisc = false; + + if (dist1 < dist0) + std::swap (dist0, dist1); + + if (dist0 == dist1) + { + // If the radii are the same, there's no ring space to fill. Use a circle. + refFile = getDocument ("4-4edge.dat"); + transform = getCircleDrawMatrix (dist0); + circleOrDisc = true; + } + elif (dist0 == 0 || dist1 == 0) + { + // If either radii is 0, use a disc. + refFile = getDocument ("4-4disc.dat"); + transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); + circleOrDisc = true; + } + elif (g_RingFinder.findRings (dist0, dist1)) + { + // The ring finder found a solution, use that. Add the component rings to the file. + for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents()) + { + // Get a ref file for this primitive. If we cannot find it in the + // LDraw library, generate it. + if ((refFile = ::getDocument (radialFileName (::Ring, g_lores, g_lores, cmp.num))) == null) + { + refFile = generatePrimitive (::Ring, g_lores, g_lores, cmp.num); + refFile->setImplicit (false); + } + + LDSubfilePtr ref = spawn(); + ref->setFileInfo (refFile); + ref->setTransform (getCircleDrawMatrix (cmp.scale)); + ref->setPosition (_drawedVerts[0]); + ref->setColor (maincolor()); + objs << ref; + } + } + else + { + // Ring finder failed, last resort: draw the ring with quads + QList c0, c1; + Axis localx, localy, localz; + renderer()->getRelativeAxes (localx, localy); + localz = (Axis) (3 - localx - localy); + double x0 = _drawedVerts[0][localx], + y0 = _drawedVerts[0][localy]; + + Vertex templ; + templ.setCoordinate (localx, x0); + templ.setCoordinate (localy, y0); + templ.setCoordinate (localz, renderer()->getDepthValue()); + + // Calculate circle coords + makeCircle (segs, divs, dist0, c0); + makeCircle (segs, divs, dist1, c1); + + for (int i = 0; i < segs; ++i) + { + Vertex v0, v1, v2, v3; + v0 = v1 = v2 = v3 = templ; + v0.setCoordinate (localx, v0[localx] + c0[i].x1()); + v0.setCoordinate (localy, v0[localy] + c0[i].y1()); + v1.setCoordinate (localx, v1[localx] + c0[i].x2()); + v1.setCoordinate (localy, v1[localy] + c0[i].y2()); + v2.setCoordinate (localx, v2[localx] + c1[i].x2()); + v2.setCoordinate (localy, v2[localy] + c1[i].y2()); + v3.setCoordinate (localx, v3[localx] + c1[i].x1()); + v3.setCoordinate (localy, v3[localy] + c1[i].y1()); + + LDQuadPtr quad (spawn (v0, v1, v2, v3)); + quad->setColor (maincolor()); + + // Ensure the quads always are BFC-front towards the camera + if (renderer()->camera() % 3 <= 0) + quad->invert(); + + objs << quad; + } + } + + if (circleOrDisc && refFile != null) + { + LDSubfilePtr ref = spawn(); + ref->setFileInfo (refFile); + ref->setTransform (transform); + ref->setPosition (_drawedVerts[0]); + ref->setColor (maincolor()); + objs << ref; + } + + finishDraw (objs); +} + +void CircleMode::render (QPainter& painter) const +{ + QFontMetrics metrics = QFontMetrics (QFont()); + + // If we have not specified the center point of the circle yet, preview it on the screen. + if (_drawedVerts.isEmpty()) + { + renderer()->drawBlip (painter, renderer()->coordconv3_2 (renderer()->position3D())); + } + else + { + QVector verts, verts2; + const double dist0 = getCircleDrawDist (0), + dist1 = (_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1; + const int segs = g_lores; + const double angleUnit = (2 * pi) / segs; + Axis relX, relY; + QVector ringpoints, circlepoints, circle2points; + + renderer()->getRelativeAxes (relX, relY); + + // Calculate the preview positions of vertices + for (int i = 0; i < segs; ++i) + { + Vertex v = g_origin; + v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist0)); + v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist0)); + verts << v; + + if (dist1 != -1) + { + v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist1)); + v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist1)); + verts2 << v; + } + } + + int i = 0; + for (const Vertex& v : verts + verts2) + { + // Calculate the 2D point of the vertex + QPoint point = renderer()->coordconv3_2 (v); + + // Draw a green blip at where it is + renderer()->drawBlip (painter, point); + + // Add it to the list of points for the green ring fill. + ringpoints << point; + + // Also add the circle points to separate lists + if (i < verts.size()) + circlepoints << point; + else + circle2points << point; + + ++i; + } + + // Insert the first point as the seventeenth one so that + // the ring polygon is closed properly. + if (ringpoints.size() >= 16) + ringpoints.insert (16, ringpoints[0]); + + // Same for the outer ring. Note that the indices are offset by 1 + // because of the insertion done above bumps the values. + if (ringpoints.size() >= 33) + ringpoints.insert (33, ringpoints[17]); + + // Draw the ring + painter.setBrush ((_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush); + painter.setPen (Qt::NoPen); + painter.drawPolygon (QPolygon (ringpoints)); + + // Draw the circles + painter.setBrush (Qt::NoBrush); + painter.setPen (renderer()->linePen()); + painter.drawPolygon (QPolygon (circlepoints)); + painter.drawPolygon (QPolygon (circle2points)); + + // Draw the current radius in the middle of the circle. + QPoint origin = renderer()->coordconv3_2 (_drawedVerts[0]); + QString label = QString::number (dist0); + painter.setPen (renderer()->textPen()); + painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); + + if (_drawedVerts.size() >= 2) + { + painter.drawText (origin.x() - (metrics.width (label) / 2), + origin.y() + metrics.height(), QString::number (dist1)); + } + } +} + +bool CircleMode::mouseReleased (MouseEventData const& data) +{ + if (Super::mouseReleased (data)) + return true; + + if (data.releasedButtons & Qt::LeftButton) + { + if (_drawedVerts.size() < 3) + addDrawnVertex (renderer()->position3D()); + else + buildCircle(); + + return true; + } + + return false; +} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/circleMode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/circleMode.h Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,38 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#pragma once +#include "abstractEditMode.h" + +class CircleMode : public AbstractDrawMode +{ + DEFINE_CLASS (CircleMode, AbstractDrawMode) + +public: + CircleMode (GLRenderer* renderer); + + virtual void render (QPainter& painter) const override; + virtual EditModeType type() const override; + + double getCircleDrawDist (int pos) const; + Matrix getCircleDrawMatrix (double scale); + bool mouseReleased (const AbstractEditMode::MouseEventData& data) override; + +private: + void buildCircle(); +}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/circlemode.cc --- a/src/editmodes/circlemode.cc Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include -#include "circlemode.h" -#include "../miscallenous.h" -#include "../ldObject.h" -#include "../ldDocument.h" -#include "../misc/ringFinder.h" -#include "../primitives.h" -#include "../glRenderer.h" - -CircleMode::CircleMode (GLRenderer* renderer) : - Super (renderer) {} - -EditModeType CircleMode::type() const -{ - return EditModeType::Circle; -} - -double CircleMode::getCircleDrawDist (int pos) const -{ - assert (_drawedVerts.size() >= pos + 1); - Vertex v1 = (_drawedVerts.size() >= pos + 2) ? _drawedVerts[pos + 1] : - renderer()->coordconv2_3 (renderer()->mousePosition(), false); - Axis localx, localy; - renderer()->getRelativeAxes (localx, localy); - double dx = _drawedVerts[0][localx] - v1[localx]; - double dy = _drawedVerts[0][localy] - v1[localy]; - return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate); -} - -Matrix CircleMode::getCircleDrawMatrix (double scale) -{ - // Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed. - static const Matrix templates[3] = - { - { 2, 0, 0, 0, 1, 0, 0, 0, 2 }, - { 2, 0, 0, 0, 0, 2, 0, 1, 0 }, - { 0, 1, 0, 2, 0, 0, 0, 0, 2 }, - }; - - Matrix transform = templates[renderer()->camera() % 3]; - - for (int i = 0; i < 9; ++i) - { - if (transform[i] == 2) - transform[i] = scale; - elif (transform[i] == 1 && renderer()->camera() >= 3) - transform[i] = -1; - } - - return transform; -} - -void CircleMode::buildCircle() -{ - LDObjectList objs; - const int segs = g_lores, divs = g_lores; // TODO: make customizable - double dist0 = getCircleDrawDist (0), - dist1 = getCircleDrawDist (1); - LDDocumentPtr refFile; - Matrix transform; - bool circleOrDisc = false; - - if (dist1 < dist0) - std::swap (dist0, dist1); - - if (dist0 == dist1) - { - // If the radii are the same, there's no ring space to fill. Use a circle. - refFile = getDocument ("4-4edge.dat"); - transform = getCircleDrawMatrix (dist0); - circleOrDisc = true; - } - elif (dist0 == 0 || dist1 == 0) - { - // If either radii is 0, use a disc. - refFile = getDocument ("4-4disc.dat"); - transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); - circleOrDisc = true; - } - elif (g_RingFinder.findRings (dist0, dist1)) - { - // The ring finder found a solution, use that. Add the component rings to the file. - for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents()) - { - // Get a ref file for this primitive. If we cannot find it in the - // LDraw library, generate it. - if ((refFile = ::getDocument (radialFileName (::Ring, g_lores, g_lores, cmp.num))) == null) - { - refFile = generatePrimitive (::Ring, g_lores, g_lores, cmp.num); - refFile->setImplicit (false); - } - - LDSubfilePtr ref = spawn(); - ref->setFileInfo (refFile); - ref->setTransform (getCircleDrawMatrix (cmp.scale)); - ref->setPosition (_drawedVerts[0]); - ref->setColor (maincolor()); - objs << ref; - } - } - else - { - // Ring finder failed, last resort: draw the ring with quads - QList c0, c1; - Axis localx, localy, localz; - renderer()->getRelativeAxes (localx, localy); - localz = (Axis) (3 - localx - localy); - double x0 = _drawedVerts[0][localx], - y0 = _drawedVerts[0][localy]; - - Vertex templ; - templ.setCoordinate (localx, x0); - templ.setCoordinate (localy, y0); - templ.setCoordinate (localz, renderer()->getDepthValue()); - - // Calculate circle coords - makeCircle (segs, divs, dist0, c0); - makeCircle (segs, divs, dist1, c1); - - for (int i = 0; i < segs; ++i) - { - Vertex v0, v1, v2, v3; - v0 = v1 = v2 = v3 = templ; - v0.setCoordinate (localx, v0[localx] + c0[i].x1()); - v0.setCoordinate (localy, v0[localy] + c0[i].y1()); - v1.setCoordinate (localx, v1[localx] + c0[i].x2()); - v1.setCoordinate (localy, v1[localy] + c0[i].y2()); - v2.setCoordinate (localx, v2[localx] + c1[i].x2()); - v2.setCoordinate (localy, v2[localy] + c1[i].y2()); - v3.setCoordinate (localx, v3[localx] + c1[i].x1()); - v3.setCoordinate (localy, v3[localy] + c1[i].y1()); - - LDQuadPtr quad (spawn (v0, v1, v2, v3)); - quad->setColor (maincolor()); - - // Ensure the quads always are BFC-front towards the camera - if (renderer()->camera() % 3 <= 0) - quad->invert(); - - objs << quad; - } - } - - if (circleOrDisc && refFile != null) - { - LDSubfilePtr ref = spawn(); - ref->setFileInfo (refFile); - ref->setTransform (transform); - ref->setPosition (_drawedVerts[0]); - ref->setColor (maincolor()); - objs << ref; - } - - finishDraw (objs); -} - -void CircleMode::render (QPainter& painter) const -{ - QFontMetrics metrics = QFontMetrics (QFont()); - - // If we have not specified the center point of the circle yet, preview it on the screen. - if (_drawedVerts.isEmpty()) - { - renderer()->drawBlip (painter, renderer()->coordconv3_2 (renderer()->position3D())); - } - else - { - QVector verts, verts2; - const double dist0 = getCircleDrawDist (0), - dist1 = (_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1; - const int segs = g_lores; - const double angleUnit = (2 * pi) / segs; - Axis relX, relY; - QVector ringpoints, circlepoints, circle2points; - - renderer()->getRelativeAxes (relX, relY); - - // Calculate the preview positions of vertices - for (int i = 0; i < segs; ++i) - { - Vertex v = g_origin; - v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist0)); - v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist0)); - verts << v; - - if (dist1 != -1) - { - v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist1)); - v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist1)); - verts2 << v; - } - } - - int i = 0; - for (const Vertex& v : verts + verts2) - { - // Calculate the 2D point of the vertex - QPoint point = renderer()->coordconv3_2 (v); - - // Draw a green blip at where it is - renderer()->drawBlip (painter, point); - - // Add it to the list of points for the green ring fill. - ringpoints << point; - - // Also add the circle points to separate lists - if (i < verts.size()) - circlepoints << point; - else - circle2points << point; - - ++i; - } - - // Insert the first point as the seventeenth one so that - // the ring polygon is closed properly. - if (ringpoints.size() >= 16) - ringpoints.insert (16, ringpoints[0]); - - // Same for the outer ring. Note that the indices are offset by 1 - // because of the insertion done above bumps the values. - if (ringpoints.size() >= 33) - ringpoints.insert (33, ringpoints[17]); - - // Draw the ring - painter.setBrush ((_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush); - painter.setPen (Qt::NoPen); - painter.drawPolygon (QPolygon (ringpoints)); - - // Draw the circles - painter.setBrush (Qt::NoBrush); - painter.setPen (renderer()->linePen()); - painter.drawPolygon (QPolygon (circlepoints)); - painter.drawPolygon (QPolygon (circle2points)); - - // Draw the current radius in the middle of the circle. - QPoint origin = renderer()->coordconv3_2 (_drawedVerts[0]); - QString label = QString::number (dist0); - painter.setPen (renderer()->textPen()); - painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); - - if (_drawedVerts.size() >= 2) - { - painter.drawText (origin.x() - (metrics.width (label) / 2), - origin.y() + metrics.height(), QString::number (dist1)); - } - } -} - -bool CircleMode::mouseReleased (MouseEventData const& data) -{ - if (Super::mouseReleased (data)) - return true; - - if (data.releasedButtons & Qt::LeftButton) - { - if (_drawedVerts.size() < 3) - addDrawnVertex (renderer()->position3D()); - else - buildCircle(); - - return true; - } - - return false; -} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/circlemode.h --- a/src/editmodes/circlemode.h Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include "abstracteditmode.h" - -class CircleMode : public AbstractDrawMode -{ - DEFINE_CLASS (CircleMode, AbstractDrawMode) - -public: - CircleMode (GLRenderer* renderer); - - virtual void render (QPainter& painter) const override; - virtual EditModeType type() const override; - - double getCircleDrawDist (int pos) const; - Matrix getCircleDrawMatrix (double scale); - bool mouseReleased (const AbstractEditMode::MouseEventData& data) override; - -private: - void buildCircle(); -}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/drawMode.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/drawMode.cc Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,286 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#include +#include +#include "drawMode.h" +#include "../ldObject.h" +#include "../glRenderer.h" + +CFGENTRY (Bool, drawLineLengths, true) +CFGENTRY (Bool, drawAngles, false) + +DrawMode::DrawMode (GLRenderer* renderer) : + Super (renderer), + _rectdraw (false) {} + +EditModeType DrawMode::type() const +{ + return EditModeType::Draw; +} + +void DrawMode::render (QPainter& painter) const +{ + QPoint poly[4]; + Vertex poly3d[4]; + int numverts = 4; + QFontMetrics metrics = QFontMetrics (QFont()); + + // Calculate polygon data + if (not _rectdraw) + { + numverts = _drawedVerts.size() + 1; + int i = 0; + + for (Vertex const& vert : _drawedVerts) + poly3d[i++] = vert; + + // Draw the cursor vertex as the last one in the list. + if (numverts <= 4) + poly3d[i] = renderer()->position3D(); + else + numverts = 4; + } + else + { + // Get vertex information from m_rectverts + if (_drawedVerts.size() > 0) + for (int i = 0; i < numverts; ++i) + poly3d[i] = _rectverts[i]; + else + poly3d[0] = renderer()->position3D(); + } + + // Convert to 2D + for (int i = 0; i < numverts; ++i) + poly[i] = renderer()->coordconv3_2 (poly3d[i]); + + if (numverts > 0) + { + // Draw the polygon-to-be + painter.setBrush (_polybrush); + painter.drawPolygon (poly, numverts); + + // Draw vertex blips + for (int i = 0; i < numverts; ++i) + { + QPoint& blip = poly[i]; + painter.setPen (renderer()->linePen()); + renderer()->drawBlip (painter, blip); + + // Draw their coordinates + painter.setPen (renderer()->textPen()); + painter.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true)); + } + + // Draw line lenghts and angle info if appropriate + if (numverts >= 2) + { + int numlines = (_drawedVerts.size() == 1) ? 1 : _drawedVerts.size() + 1; + painter.setPen (renderer()->textPen()); + + for (int i = 0; i < numlines; ++i) + { + const int j = (i + 1 < numverts) ? i + 1 : 0; + const int h = (i - 1 >= 0) ? i - 1 : numverts - 1; + + if (cfg::drawLineLengths) + { + const QString label = QString::number ((poly3d[j] - poly3d[i]).length()); + QPoint origin = QLineF (poly[i], poly[j]).pointAt (0.5).toPoint(); + painter.drawText (origin, label); + } + + if (cfg::drawAngles) + { + QLineF l0 (poly[h], poly[i]), + l1 (poly[i], poly[j]); + + double angle = 180 - l0.angleTo (l1); + + if (angle < 0) + angle = 180 - l1.angleTo (l0); + + QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260")); + QPoint pos = poly[i]; + pos.setY (pos.y() + metrics.height()); + + painter.drawText (pos, label); + } + } + } + } +} + +bool DrawMode::preAddVertex (Vertex const& pos) +{ + // If we picked an already-existing vertex, stop drawing + for (Vertex& vert : _drawedVerts) + { + if (vert == pos) + { + endDraw(); + return true; + } + } + + return false; +} + +bool DrawMode::mouseReleased (MouseEventData const& data) +{ + if (Super::mouseReleased (data)) + return true; + + if (data.releasedButtons & Qt::LeftButton) + { + if (_rectdraw) + { + if (_drawedVerts.size() == 2) + { + endDraw(); + return true; + } + } + else + { + // If we have 4 verts, stop drawing. + if (_drawedVerts.size() >= 4) + { + endDraw(); + return true; + } + + if (_drawedVerts.isEmpty()) + { + _rectdraw = (data.ev->modifiers() & Qt::ShiftModifier); + updateRectVerts(); + } + } + + addDrawnVertex (renderer()->position3D()); + return true; + } + + return false; +} + +// +// Update rect vertices when the mouse moves since the 3d position likely has changed +// +bool DrawMode::mouseMoved (QMouseEvent*) +{ + updateRectVerts(); + return false; +} + +void DrawMode::updateRectVerts() +{ + if (not _rectdraw) + return; + + if (_drawedVerts.isEmpty()) + { + for (int i = 0; i < 4; ++i) + _rectverts[i] = renderer()->position3D(); + + return; + } + + Vertex v0 = _drawedVerts[0], + v1 = (_drawedVerts.size() >= 2) ? _drawedVerts[1] : renderer()->position3D(); + + const Axis localx = renderer()->getCameraAxis (false), + localy = renderer()->getCameraAxis (true), + localz = (Axis) (3 - localx - localy); + + for (int i = 0; i < 4; ++i) + _rectverts[i].setCoordinate (localz, renderer()->getDepthValue()); + + _rectverts[0].setCoordinate (localx, v0[localx]); + _rectverts[0].setCoordinate (localy, v0[localy]); + _rectverts[1].setCoordinate (localx, v1[localx]); + _rectverts[1].setCoordinate (localy, v0[localy]); + _rectverts[2].setCoordinate (localx, v1[localx]); + _rectverts[2].setCoordinate (localy, v1[localy]); + _rectverts[3].setCoordinate (localx, v0[localx]); + _rectverts[3].setCoordinate (localy, v1[localy]); +} + +void DrawMode::endDraw() +{ + // Clean the selection and create the object + QList& verts = _drawedVerts; + LDObjectList objs; + + if (_rectdraw) + { + LDQuadPtr quad (spawn()); + + updateRectVerts(); + + for (int i = 0; i < quad->numVertices(); ++i) + quad->setVertex (i, _rectverts[i]); + + quad->setColor (maincolor()); + objs << quad; + } + else + { + switch (verts.size()) + { + case 1: + { + // 1 vertex - add a vertex object + LDVertexPtr obj = spawn(); + obj->pos = verts[0]; + obj->setColor (maincolor()); + objs << obj; + break; + } + + case 2: + { + // 2 verts - make a line + LDLinePtr obj = spawn (verts[0], verts[1]); + obj->setColor (edgecolor()); + objs << obj; + break; + } + + case 3: + case 4: + { + LDObjectPtr obj = (verts.size() == 3) ? + static_cast (spawn()) : + static_cast (spawn()); + + obj->setColor (maincolor()); + + for (int i = 0; i < verts.size(); ++i) + obj->setVertex (i, verts[i]); + + objs << obj; + break; + } + } + } + + finishDraw (objs); + _rectdraw = false; +} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/drawMode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/drawMode.h Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,39 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#pragma once +#include "abstractEditMode.h" + +class DrawMode : public AbstractDrawMode +{ + DEFINE_CLASS (DrawMode, AbstractDrawMode) + bool _rectdraw; + +public: + DrawMode (GLRenderer* renderer); + + virtual void render (QPainter& painter) const override; + virtual EditModeType type() const override; + virtual bool preAddVertex (Vertex const& pos) override; + virtual bool mouseReleased (MouseEventData const& data) override; + virtual bool mouseMoved (QMouseEvent*) override; + +private: + void endDraw(); + void updateRectVerts(); +}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/drawmode.cc --- a/src/editmodes/drawmode.cc Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include -#include -#include "drawmode.h" -#include "../ldObject.h" -#include "../glRenderer.h" - -CFGENTRY (Bool, drawLineLengths, true) -CFGENTRY (Bool, drawAngles, false) - -DrawMode::DrawMode (GLRenderer* renderer) : - Super (renderer), - _rectdraw (false) {} - -EditModeType DrawMode::type() const -{ - return EditModeType::Draw; -} - -void DrawMode::render (QPainter& painter) const -{ - QPoint poly[4]; - Vertex poly3d[4]; - int numverts = 4; - QFontMetrics metrics = QFontMetrics (QFont()); - - // Calculate polygon data - if (not _rectdraw) - { - numverts = _drawedVerts.size() + 1; - int i = 0; - - for (Vertex const& vert : _drawedVerts) - poly3d[i++] = vert; - - // Draw the cursor vertex as the last one in the list. - if (numverts <= 4) - poly3d[i] = renderer()->position3D(); - else - numverts = 4; - } - else - { - // Get vertex information from m_rectverts - if (_drawedVerts.size() > 0) - for (int i = 0; i < numverts; ++i) - poly3d[i] = _rectverts[i]; - else - poly3d[0] = renderer()->position3D(); - } - - // Convert to 2D - for (int i = 0; i < numverts; ++i) - poly[i] = renderer()->coordconv3_2 (poly3d[i]); - - if (numverts > 0) - { - // Draw the polygon-to-be - painter.setBrush (_polybrush); - painter.drawPolygon (poly, numverts); - - // Draw vertex blips - for (int i = 0; i < numverts; ++i) - { - QPoint& blip = poly[i]; - painter.setPen (renderer()->linePen()); - renderer()->drawBlip (painter, blip); - - // Draw their coordinates - painter.setPen (renderer()->textPen()); - painter.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true)); - } - - // Draw line lenghts and angle info if appropriate - if (numverts >= 2) - { - int numlines = (_drawedVerts.size() == 1) ? 1 : _drawedVerts.size() + 1; - painter.setPen (renderer()->textPen()); - - for (int i = 0; i < numlines; ++i) - { - const int j = (i + 1 < numverts) ? i + 1 : 0; - const int h = (i - 1 >= 0) ? i - 1 : numverts - 1; - - if (cfg::drawLineLengths) - { - const QString label = QString::number ((poly3d[j] - poly3d[i]).length()); - QPoint origin = QLineF (poly[i], poly[j]).pointAt (0.5).toPoint(); - painter.drawText (origin, label); - } - - if (cfg::drawAngles) - { - QLineF l0 (poly[h], poly[i]), - l1 (poly[i], poly[j]); - - double angle = 180 - l0.angleTo (l1); - - if (angle < 0) - angle = 180 - l1.angleTo (l0); - - QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260")); - QPoint pos = poly[i]; - pos.setY (pos.y() + metrics.height()); - - painter.drawText (pos, label); - } - } - } - } -} - -bool DrawMode::preAddVertex (Vertex const& pos) -{ - // If we picked an already-existing vertex, stop drawing - for (Vertex& vert : _drawedVerts) - { - if (vert == pos) - { - endDraw(); - return true; - } - } - - return false; -} - -bool DrawMode::mouseReleased (MouseEventData const& data) -{ - if (Super::mouseReleased (data)) - return true; - - if (data.releasedButtons & Qt::LeftButton) - { - if (_rectdraw) - { - if (_drawedVerts.size() == 2) - { - endDraw(); - return true; - } - } - else - { - // If we have 4 verts, stop drawing. - if (_drawedVerts.size() >= 4) - { - endDraw(); - return true; - } - - if (_drawedVerts.isEmpty()) - { - _rectdraw = (data.ev->modifiers() & Qt::ShiftModifier); - updateRectVerts(); - } - } - - addDrawnVertex (renderer()->position3D()); - return true; - } - - return false; -} - -// -// Update rect vertices when the mouse moves since the 3d position likely has changed -// -bool DrawMode::mouseMoved (QMouseEvent*) -{ - updateRectVerts(); - return false; -} - -void DrawMode::updateRectVerts() -{ - if (not _rectdraw) - return; - - if (_drawedVerts.isEmpty()) - { - for (int i = 0; i < 4; ++i) - _rectverts[i] = renderer()->position3D(); - - return; - } - - Vertex v0 = _drawedVerts[0], - v1 = (_drawedVerts.size() >= 2) ? _drawedVerts[1] : renderer()->position3D(); - - const Axis localx = renderer()->getCameraAxis (false), - localy = renderer()->getCameraAxis (true), - localz = (Axis) (3 - localx - localy); - - for (int i = 0; i < 4; ++i) - _rectverts[i].setCoordinate (localz, renderer()->getDepthValue()); - - _rectverts[0].setCoordinate (localx, v0[localx]); - _rectverts[0].setCoordinate (localy, v0[localy]); - _rectverts[1].setCoordinate (localx, v1[localx]); - _rectverts[1].setCoordinate (localy, v0[localy]); - _rectverts[2].setCoordinate (localx, v1[localx]); - _rectverts[2].setCoordinate (localy, v1[localy]); - _rectverts[3].setCoordinate (localx, v0[localx]); - _rectverts[3].setCoordinate (localy, v1[localy]); -} - -void DrawMode::endDraw() -{ - // Clean the selection and create the object - QList& verts = _drawedVerts; - LDObjectList objs; - - if (_rectdraw) - { - LDQuadPtr quad (spawn()); - - updateRectVerts(); - - for (int i = 0; i < quad->numVertices(); ++i) - quad->setVertex (i, _rectverts[i]); - - quad->setColor (maincolor()); - objs << quad; - } - else - { - switch (verts.size()) - { - case 1: - { - // 1 vertex - add a vertex object - LDVertexPtr obj = spawn(); - obj->pos = verts[0]; - obj->setColor (maincolor()); - objs << obj; - break; - } - - case 2: - { - // 2 verts - make a line - LDLinePtr obj = spawn (verts[0], verts[1]); - obj->setColor (edgecolor()); - objs << obj; - break; - } - - case 3: - case 4: - { - LDObjectPtr obj = (verts.size() == 3) ? - static_cast (spawn()) : - static_cast (spawn()); - - obj->setColor (maincolor()); - - for (int i = 0; i < verts.size(); ++i) - obj->setVertex (i, verts[i]); - - objs << obj; - break; - } - } - } - - finishDraw (objs); - _rectdraw = false; -} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/drawmode.h --- a/src/editmodes/drawmode.h Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include "abstracteditmode.h" - -class DrawMode : public AbstractDrawMode -{ - DEFINE_CLASS (DrawMode, AbstractDrawMode) - bool _rectdraw; - -public: - DrawMode (GLRenderer* renderer); - - virtual void render (QPainter& painter) const override; - virtual EditModeType type() const override; - virtual bool preAddVertex (Vertex const& pos) override; - virtual bool mouseReleased (MouseEventData const& data) override; - virtual bool mouseMoved (QMouseEvent*) override; - -private: - void endDraw(); - void updateRectVerts(); -}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/magicWandMode.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/magicWandMode.cc Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,215 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#include +#include "magicWandMode.h" +#include "../ldDocument.h" +#include "../mainWindow.h" +#include "../glRenderer.h" + +MagicWandMode::MagicWandMode (GLRenderer* renderer) : + Super (renderer) +{ + // Get vertex<->object data + for (LDObjectPtr obj : getCurrentDocument()->objects()) + { + // Note: this deliberately only takes vertex-objects into account. + // The magic wand does not process subparts. + for (int i = 0; i < obj->numVertices(); ++i) + _vertices[obj->vertex (i)] << obj; + } +} + +EditModeType MagicWandMode::type() const +{ + return EditModeType::MagicWand; +} + +void MagicWandMode::fillBoundaries (LDObjectPtr obj, QVector& boundaries, QVector& candidates) +{ + // All boundaries obviously share vertices with the object, therefore they're all in the list + // of candidates. + for (auto it = candidates.begin(); it != candidates.end(); ++it) + { + if ((*it)->type() != OBJ_Line || (*it)->vertex (0) == (*it)->vertex (1)) + continue; + + int matches = 0; + + for (int i = 0; i < obj->numVertices(); ++i) + { + if (not eq (obj->vertex (i), (*it)->vertex (0), (*it)->vertex (1))) + continue; + + if (++matches == 2) + { + // Boundary found. Add to boundaries list and get it off the candidates list. + boundaries.append (std::make_tuple ((*it)->vertex (0), (*it)->vertex (1))); + break; + } + } + } +} + +void MagicWandMode::doMagic (LDObjectPtr obj, MagicWandMode::MagicType type) +{ + if (obj == null) + { + if (type == Set) + { + getCurrentDocument()->clearSelection(); + g_win->buildObjList(); + } + + return; + } + + int matchesneeded = 0; + QVector boundaries; + LDObjectType objtype = obj->type(); + + if (type != InternalRecursion) + { + _selection.clear(); + _selection.append (obj); + } + + switch (obj->type()) + { + case OBJ_Line: + case OBJ_CondLine: + matchesneeded = 1; + break; + + case OBJ_Triangle: + case OBJ_Quad: + matchesneeded = 2; + break; + + default: + return; + } + + QVector candidates; + + // Get the list of objects that touch this object, i.e. share a vertex + // with this. + for (int i = 0; i < obj->numVertices(); ++i) + candidates += _vertices[obj->vertex (i)]; + + removeDuplicates (candidates); + + // If we're dealing with surfaces, get a list of boundaries. + if (matchesneeded > 1) + fillBoundaries (obj, boundaries, candidates); + + for (LDObjectPtr candidate : candidates) + { + try + { + // If we're doing this on lines, we need exact type match. Surface types (quads and + // triangles) can be mixed. Also don't consider self a candidate, and don't consider + // objects we have already processed. + if ((candidate == obj) || + (candidate->color() != obj->color()) || + (_selection.contains (candidate)) || + (matchesneeded == 1 && (candidate->type() != objtype)) || + ((candidate->numVertices() > 2) ^ (matchesneeded == 2))) + { + throw 0; + } + + // Now ensure the two objects share enough vertices. + QVector matches; + + for (int i = 0; i < obj->numVertices(); ++i) + { + for (int j = 0; j < candidate->numVertices(); ++j) + { + if (obj->vertex(i) == candidate->vertex(j)) + { + matches << obj->vertex(i); + break; + } + } + } + + if (matches.size() < matchesneeded) + throw 0; // Not enough matches. + + // Check if a boundary gets in between the objects. + for (auto boundary : boundaries) + { + if (eq (matches[0], std::get<0> (boundary), std::get<1> (boundary)) && + eq (matches[1], std::get<0> (boundary), std::get<1> (boundary))) + { + throw 0; + } + } + + _selection.append (candidate); + doMagic (candidate, InternalRecursion); + } + catch (int&) + { + continue; + } + } + + switch (type) + { + case Set: + getCurrentDocument()->clearSelection(); + case Additive: + for (LDObjectPtr obj : _selection) + obj->select(); + break; + + case Subtractive: + for (LDObjectPtr obj : _selection) + obj->deselect(); + break; + + case InternalRecursion: + break; + } + + if (type != InternalRecursion) + g_win->buildObjList(); +} + +bool MagicWandMode::mouseReleased (MouseEventData const& data) +{ + if (Super::mouseReleased (data)) + return true; + + if (data.releasedButtons & Qt::LeftButton && not data.mouseMoved) + { + MagicType wandtype = MagicWandMode::Set; + + if (data.keymods & Qt::ShiftModifier) + wandtype = MagicWandMode::Additive; + elif (data.keymods & Qt::ControlModifier) + wandtype = MagicWandMode::Subtractive; + + doMagic (renderer()->pickOneObject (data.ev->x(), data.ev->y()), wandtype); + return true; + } + + return false; +} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/magicWandMode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/magicWandMode.h Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,49 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#pragma once +#include "abstractEditMode.h" +#include "../basics.h" +#include +#include + +class MagicWandMode : public AbstractSelectMode +{ + QMap> _vertices; + QVector _selection; + + DEFINE_CLASS (MagicWandMode, AbstractSelectMode) + +public: + using BoundaryType = std::tuple; + enum MagicType + { + Set, + Additive, + Subtractive, + InternalRecursion + }; + + MagicWandMode (GLRenderer* renderer); + void doMagic (LDObjectPtr obj, MagicType type); + virtual EditModeType type() const override; + virtual bool mouseReleased (MouseEventData const& data) override; + +private: + void fillBoundaries (LDObjectPtr obj, QVector& boundaries, QVector& candidates); +}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/magicwandmode.cc --- a/src/editmodes/magicwandmode.cc Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include -#include "magicwandmode.h" -#include "../ldDocument.h" -#include "../mainWindow.h" -#include "../glRenderer.h" - -MagicWandMode::MagicWandMode (GLRenderer* renderer) : - Super (renderer) -{ - // Get vertex<->object data - for (LDObjectPtr obj : getCurrentDocument()->objects()) - { - // Note: this deliberately only takes vertex-objects into account. - // The magic wand does not process subparts. - for (int i = 0; i < obj->numVertices(); ++i) - _vertices[obj->vertex (i)] << obj; - } -} - -EditModeType MagicWandMode::type() const -{ - return EditModeType::MagicWand; -} - -void MagicWandMode::fillBoundaries (LDObjectPtr obj, QVector& boundaries, QVector& candidates) -{ - // All boundaries obviously share vertices with the object, therefore they're all in the list - // of candidates. - for (auto it = candidates.begin(); it != candidates.end(); ++it) - { - if ((*it)->type() != OBJ_Line || (*it)->vertex (0) == (*it)->vertex (1)) - continue; - - int matches = 0; - - for (int i = 0; i < obj->numVertices(); ++i) - { - if (not eq (obj->vertex (i), (*it)->vertex (0), (*it)->vertex (1))) - continue; - - if (++matches == 2) - { - // Boundary found. Add to boundaries list and get it off the candidates list. - boundaries.append (std::make_tuple ((*it)->vertex (0), (*it)->vertex (1))); - break; - } - } - } -} - -void MagicWandMode::doMagic (LDObjectPtr obj, MagicWandMode::MagicType type) -{ - if (obj == null) - { - if (type == Set) - { - getCurrentDocument()->clearSelection(); - g_win->buildObjList(); - } - - return; - } - - int matchesneeded = 0; - QVector boundaries; - LDObjectType objtype = obj->type(); - - if (type != InternalRecursion) - { - _selection.clear(); - _selection.append (obj); - } - - switch (obj->type()) - { - case OBJ_Line: - case OBJ_CondLine: - matchesneeded = 1; - break; - - case OBJ_Triangle: - case OBJ_Quad: - matchesneeded = 2; - break; - - default: - return; - } - - QVector candidates; - - // Get the list of objects that touch this object, i.e. share a vertex - // with this. - for (int i = 0; i < obj->numVertices(); ++i) - candidates += _vertices[obj->vertex (i)]; - - removeDuplicates (candidates); - - // If we're dealing with surfaces, get a list of boundaries. - if (matchesneeded > 1) - fillBoundaries (obj, boundaries, candidates); - - for (LDObjectPtr candidate : candidates) - { - try - { - // If we're doing this on lines, we need exact type match. Surface types (quads and - // triangles) can be mixed. Also don't consider self a candidate, and don't consider - // objects we have already processed. - if ((candidate == obj) || - (candidate->color() != obj->color()) || - (_selection.contains (candidate)) || - (matchesneeded == 1 && (candidate->type() != objtype)) || - ((candidate->numVertices() > 2) ^ (matchesneeded == 2))) - { - throw 0; - } - - // Now ensure the two objects share enough vertices. - QVector matches; - - for (int i = 0; i < obj->numVertices(); ++i) - { - for (int j = 0; j < candidate->numVertices(); ++j) - { - if (obj->vertex(i) == candidate->vertex(j)) - { - matches << obj->vertex(i); - break; - } - } - } - - if (matches.size() < matchesneeded) - throw 0; // Not enough matches. - - // Check if a boundary gets in between the objects. - for (auto boundary : boundaries) - { - if (eq (matches[0], std::get<0> (boundary), std::get<1> (boundary)) && - eq (matches[1], std::get<0> (boundary), std::get<1> (boundary))) - { - throw 0; - } - } - - _selection.append (candidate); - doMagic (candidate, InternalRecursion); - } - catch (int&) - { - continue; - } - } - - switch (type) - { - case Set: - getCurrentDocument()->clearSelection(); - case Additive: - for (LDObjectPtr obj : _selection) - obj->select(); - break; - - case Subtractive: - for (LDObjectPtr obj : _selection) - obj->deselect(); - break; - - case InternalRecursion: - break; - } - - if (type != InternalRecursion) - g_win->buildObjList(); -} - -bool MagicWandMode::mouseReleased (MouseEventData const& data) -{ - if (Super::mouseReleased (data)) - return true; - - if (data.releasedButtons & Qt::LeftButton && not data.mouseMoved) - { - MagicType wandtype = MagicWandMode::Set; - - if (data.keymods & Qt::ShiftModifier) - wandtype = MagicWandMode::Additive; - elif (data.keymods & Qt::ControlModifier) - wandtype = MagicWandMode::Subtractive; - - doMagic (renderer()->pickOneObject (data.ev->x(), data.ev->y()), wandtype); - return true; - } - - return false; -} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/magicwandmode.h --- a/src/editmodes/magicwandmode.h Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#pragma once -#include "abstracteditmode.h" -#include "../basics.h" -#include -#include - -class MagicWandMode : public AbstractSelectMode -{ - QMap> _vertices; - QVector _selection; - - DEFINE_CLASS (MagicWandMode, AbstractSelectMode) - -public: - using BoundaryType = std::tuple; - enum MagicType - { - Set, - Additive, - Subtractive, - InternalRecursion - }; - - MagicWandMode (GLRenderer* renderer); - void doMagic (LDObjectPtr obj, MagicType type); - virtual EditModeType type() const override; - virtual bool mouseReleased (MouseEventData const& data) override; - -private: - void fillBoundaries (LDObjectPtr obj, QVector& boundaries, QVector& candidates); -}; diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/selectMode.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/selectMode.cc Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,137 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#include +#include "selectMode.h" +#include "../glRenderer.h" +#include "../addObjectDialog.h" +#include "../mainWindow.h" +#include "../glRenderer.h" + +SelectMode::SelectMode (GLRenderer* renderer) : + Super (renderer), + _rangepick (false) {} + +EditModeType SelectMode::type() const +{ + return EditModeType::Select; +} + +void SelectMode::render (QPainter& painter) const +{ + // If we're range-picking, draw a rectangle encompassing the selection area. + if (_rangepick) + { + int x0 = _rangeStart.x(), + y0 = _rangeStart.y(), + x1 = renderer()->mousePosition().x(), + y1 = renderer()->mousePosition().y(); + + QRect rect (x0, y0, x1 - x0, y1 - y0); + QColor fillColor = (_addpick ? "#40FF00" : "#00CCFF"); + fillColor.setAlphaF (0.2f); + painter.setPen (QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter.setBrush (QBrush (fillColor)); + painter.drawRect (rect); + } +} + +bool SelectMode::mouseReleased (MouseEventData const& data) +{ + if (Super::mouseReleased (data)) + return true; + + if (data.releasedButtons & Qt::LeftButton) + { + if (not data.mouseMoved) + _rangepick = false; + + if (not _rangepick) + _addpick = (data.keymods & Qt::ControlModifier); + + if (not data.mouseMoved || _rangepick) + { + QRect area; + int const mx = data.ev->x(); + int const my = data.ev->y(); + + if (not _rangepick) + { + area = QRect (mx, my, 1, 1); + } + else + { + int const x = min (_rangeStart.x(), mx); + int const y = min (_rangeStart.y(), my); + int const width = abs (_rangeStart.x() - mx); + int const height = abs (_rangeStart.y() - my); + area = QRect (x, y, width, height); + } + + renderer()->pick (area, _addpick); + } + + _rangepick = false; + return true; + } + + return false; +} + +bool SelectMode::mousePressed (QMouseEvent* ev) +{ + if (Super::mousePressed (ev)) + return true; + + if (ev->modifiers() & Qt::ControlModifier) + { + _rangepick = true; + _rangeStart.setX (ev->x()); + _rangeStart.setY (ev->y()); + _addpick = (ev->modifiers() & Qt::AltModifier); + return true; + } + + return false; +} + +bool SelectMode::mouseDoubleClicked (QMouseEvent* ev) +{ + if (Super::mouseDoubleClicked (ev)) + return true; + + if (ev->buttons() & Qt::LeftButton) + { + renderer()->document()->clearSelection(); + LDObjectPtr obj = renderer()->pickOneObject (ev->x(), ev->y()); + + if (obj != null) + { + AddObjectDialog::staticDialog (obj->type(), obj); + g_win->endAction(); + return true; + } + } + + return false; +} + +bool SelectMode::mouseMoved (QMouseEvent*) +{ + return _rangepick; +} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/selectMode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/editmodes/selectMode.h Sat Jul 05 02:02:31 2014 +0300 @@ -0,0 +1,39 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * 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 . + */ + +#pragma once +#include "abstractEditMode.h" + +class SelectMode : public AbstractSelectMode +{ + QPoint _rangeStart; + bool _rangepick; + bool _addpick; + + DEFINE_CLASS (SelectMode, AbstractSelectMode) + +public: + SelectMode (GLRenderer* renderer); + + virtual void render (QPainter& painter) const override; + virtual bool mousePressed (QMouseEvent* ev); + virtual bool mouseReleased (MouseEventData const& data) override; + virtual bool mouseDoubleClicked (QMouseEvent* ev); + virtual bool mouseMoved (QMouseEvent*) override; + virtual EditModeType type() const override; +}; \ No newline at end of file diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/selectmode.cc --- a/src/editmodes/selectmode.cc Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include -#include "selectmode.h" -#include "../glRenderer.h" -#include "../addObjectDialog.h" -#include "../mainWindow.h" -#include "../glRenderer.h" - -SelectMode::SelectMode (GLRenderer* renderer) : - Super (renderer), - _rangepick (false) {} - -EditModeType SelectMode::type() const -{ - return EditModeType::Select; -} - -void SelectMode::render (QPainter& painter) const -{ - // If we're range-picking, draw a rectangle encompassing the selection area. - if (_rangepick) - { - int x0 = _rangeStart.x(), - y0 = _rangeStart.y(), - x1 = renderer()->mousePosition().x(), - y1 = renderer()->mousePosition().y(); - - QRect rect (x0, y0, x1 - x0, y1 - y0); - QColor fillColor = (_addpick ? "#40FF00" : "#00CCFF"); - fillColor.setAlphaF (0.2f); - painter.setPen (QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - painter.setBrush (QBrush (fillColor)); - painter.drawRect (rect); - } -} - -bool SelectMode::mouseReleased (MouseEventData const& data) -{ - if (Super::mouseReleased (data)) - return true; - - if (data.releasedButtons & Qt::LeftButton) - { - if (not data.mouseMoved) - _rangepick = false; - - if (not _rangepick) - _addpick = (data.keymods & Qt::ControlModifier); - - if (not data.mouseMoved || _rangepick) - { - QRect area; - int const mx = data.ev->x(); - int const my = data.ev->y(); - - if (not _rangepick) - { - area = QRect (mx, my, 1, 1); - } - else - { - int const x = min (_rangeStart.x(), mx); - int const y = min (_rangeStart.y(), my); - int const width = abs (_rangeStart.x() - mx); - int const height = abs (_rangeStart.y() - my); - area = QRect (x, y, width, height); - } - - renderer()->pick (area, _addpick); - } - - _rangepick = false; - return true; - } - - return false; -} - -bool SelectMode::mousePressed (QMouseEvent* ev) -{ - if (Super::mousePressed (ev)) - return true; - - if (ev->modifiers() & Qt::ControlModifier) - { - _rangepick = true; - _rangeStart.setX (ev->x()); - _rangeStart.setY (ev->y()); - _addpick = (ev->modifiers() & Qt::AltModifier); - return true; - } - - return false; -} - -bool SelectMode::mouseDoubleClicked (QMouseEvent* ev) -{ - if (Super::mouseDoubleClicked (ev)) - return true; - - if (ev->buttons() & Qt::LeftButton) - { - renderer()->document()->clearSelection(); - LDObjectPtr obj = renderer()->pickOneObject (ev->x(), ev->y()); - - if (obj != null) - { - AddObjectDialog::staticDialog (obj->type(), obj); - g_win->endAction(); - return true; - } - } - - return false; -} - -bool SelectMode::mouseMoved (QMouseEvent* ev) -{ - return _rangepick; -} diff -r bb903e89e23c -r a741a0b9df49 src/editmodes/selectmode.h --- a/src/editmodes/selectmode.h Sat Jul 05 01:45:32 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013, 2014 Santeri Piippo - * - * 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 . - */ - -#include "abstracteditmode.h" - -class SelectMode : public AbstractSelectMode -{ - QPoint _rangeStart; - bool _rangepick; - bool _addpick; - - DEFINE_CLASS (SelectMode, AbstractSelectMode) - -public: - SelectMode (GLRenderer* renderer); - - virtual void render (QPainter& painter) const override; - virtual bool mousePressed (QMouseEvent* ev); - virtual bool mouseReleased (MouseEventData const& data) override; - virtual bool mouseDoubleClicked (QMouseEvent* ev); - virtual bool mouseMoved (QMouseEvent*) override; - virtual EditModeType type() const override; -}; \ No newline at end of file diff -r bb903e89e23c -r a741a0b9df49 src/glRenderer.h --- a/src/glRenderer.h Sat Jul 05 01:45:32 2014 +0300 +++ b/src/glRenderer.h Sat Jul 05 02:02:31 2014 +0300 @@ -23,7 +23,7 @@ #include "ldObject.h" #include "ldDocument.h" #include "glShared.h" -#include "editmodes/abstracteditmode.h" +#include "editmodes/abstractEditMode.h" class GLCompiler; class MessageManager; diff -r bb903e89e23c -r a741a0b9df49 src/mainWindow.cc --- a/src/mainWindow.cc Sat Jul 05 01:45:32 2014 +0300 +++ b/src/mainWindow.cc Sat Jul 05 02:02:31 2014 +0300 @@ -50,7 +50,7 @@ #include "configuration.h" #include "ui_ldforge.h" #include "primitives.h" -#include "editmodes/abstracteditmode.h" +#include "editmodes/abstractEditMode.h" static bool g_isSelectionLocked = false; static QMap g_defaultShortcuts;