diff -r ab77deb851fa -r 8d98ee0dc917 src/actionsEdit.cc --- a/src/actionsEdit.cc Tue Mar 03 16:50:39 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,738 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2015 Teemu 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 -#include -#include -#include -#include "mainWindow.h" -#include "main.h" -#include "ldDocument.h" -#include "colorSelector.h" -#include "miscallenous.h" -#include "radioGroup.h" -#include "glRenderer.h" -#include "dialogs.h" -#include "colors.h" -#include "ldObjectMath.h" -#include "ui_replcoords.h" -#include "ui_editraw.h" -#include "ui_flip.h" -#include "ui_addhistoryline.h" - -EXTERN_CFGENTRY (String, DefaultUser) - -CFGENTRY (Int, RoundPosition, 3) -CFGENTRY (Int, RoundMatrix, 4) -CFGENTRY (Int, SplitLinesSegments, 5) - -// ============================================================================= -// -static int CopyToClipboard() -{ - LDObjectList objs = Selection(); - int num = 0; - - // Clear the clipboard first. - qApp->clipboard()->clear(); - - // Now, copy the contents into the clipboard. - QString data; - - for (LDObjectPtr obj : objs) - { - if (not data.isEmpty()) - data += "\n"; - - data += obj->asText(); - ++num; - } - - qApp->clipboard()->setText (data); - return num; -} - -// ============================================================================= -// -void MainWindow::actionCut() -{ - int num = CopyToClipboard(); - deleteSelection(); - print (tr ("%1 objects cut"), num); -} - -// ============================================================================= -// -void MainWindow::actionCopy() -{ - int num = CopyToClipboard(); - print (tr ("%1 objects copied"), num); -} - -// ============================================================================= -// -void MainWindow::actionPaste() -{ - const QString clipboardText = qApp->clipboard()->text(); - int idx = getInsertionPoint(); - CurrentDocument()->clearSelection(); - int num = 0; - - for (QString line : clipboardText.split ("\n")) - { - LDObjectPtr pasted = ParseLine (line); - CurrentDocument()->insertObj (idx++, pasted); - pasted->select(); - ++num; - } - - print (tr ("%1 objects pasted"), num); - refresh(); - scrollToSelection(); -} - -// ============================================================================= -// -void MainWindow::actionDelete() -{ - int num = deleteSelection(); - print (tr ("%1 objects deleted"), num); -} - -// ============================================================================= -// -static void DoInline (bool deep) -{ - LDObjectList sel = Selection(); - - LDIterate (Selection(), [&](LDSubfilePtr const& ref) - { - // Get the index of the subfile so we know where to insert the - // inlined contents. - long idx = ref->lineNumber(); - - assert (idx != -1); - LDObjectList objs = ref->inlineContents (deep, false); - - // Merge in the inlined objects - for (LDObjectPtr inlineobj : objs) - { - QString line = inlineobj->asText(); - inlineobj->destroy(); - LDObjectPtr newobj = ParseLine (line); - CurrentDocument()->insertObj (idx++, newobj); - newobj->select(); - } - - // Delete the subfile now as it's been inlined. - ref->destroy(); - }); - - g_win->refresh(); -} - -void MainWindow::actionInline() -{ - DoInline (false); -} - -void MainWindow::actionInlineDeep() -{ - DoInline (true); -} - -// ============================================================================= -// -void MainWindow::actionSplitQuads() -{ - int num = 0; - - LDIterate (Selection(), [&](LDQuadPtr const& quad) - { - // Find the index of this quad - long index = quad->lineNumber(); - - if (index == -1) - return; - - QList triangles = quad->splitToTriangles(); - - // Replace the quad with the first triangle and add the second triangle - // after the first one. - CurrentDocument()->setObject (index, triangles[0]); - CurrentDocument()->insertObj (index + 1, triangles[1]); - num++; - }); - - print ("%1 quadrilaterals split", num); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionEditRaw() -{ - if (Selection().size() != 1) - return; - - LDObjectPtr obj = Selection()[0]; - QDialog* dlg = new QDialog; - Ui::EditRawUI ui; - - ui.setupUi (dlg); - ui.code->setText (obj->asText()); - - if (obj->type() == OBJ_Error) - ui.errorDescription->setText (obj.staticCast()->reason()); - else - { - ui.errorDescription->hide(); - ui.errorIcon->hide(); - } - - if (dlg->exec() == QDialog::Rejected) - return; - - // Reinterpret it from the text of the input field - LDObjectPtr newobj = ParseLine (ui.code->text()); - obj->replace (newobj); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionSetColor() -{ - if (Selection().isEmpty()) - return; - - LDObjectList objs = Selection(); - - // If all selected objects have the same color, said color is our default - // value to the color selection dialog. - LDColor color; - LDColor defaultcol = getSelectedColor(); - - // Show the dialog to the user now and ask for a color. - if (ColorSelector::selectColor (color, defaultcol, g_win)) - { - for (LDObjectPtr obj : objs) - { - if (obj->isColored()) - obj->setColor (color); - } - - refresh(); - } -} - -// ============================================================================= -// -void MainWindow::actionBorders() -{ - LDObjectList objs = Selection(); - int num = 0; - - for (LDObjectPtr obj : objs) - { - const LDObjectType type = obj->type(); - - if (type != OBJ_Quad and type != OBJ_Triangle) - continue; - - LDLinePtr lines[4]; - - if (type == OBJ_Quad) - { - LDQuadPtr quad = obj.staticCast(); - lines[0] = LDSpawn (quad->vertex (0), quad->vertex (1)); - lines[1] = LDSpawn (quad->vertex (1), quad->vertex (2)); - lines[2] = LDSpawn (quad->vertex (2), quad->vertex (3)); - lines[3] = LDSpawn (quad->vertex (3), quad->vertex (0)); - } - else - { - LDTrianglePtr tri = obj.staticCast(); - lines[0] = LDSpawn (tri->vertex (0), tri->vertex (1)); - lines[1] = LDSpawn (tri->vertex (1), tri->vertex (2)); - lines[2] = LDSpawn (tri->vertex (2), tri->vertex (0)); - } - - for (int i = 0; i < countof (lines); ++i) - { - if (lines[i] == null) - continue; - - long idx = obj->lineNumber() + i + 1; - CurrentDocument()->insertObj (idx, lines[i]); - } - - num += countof (lines); - } - - print (tr ("Added %1 border lines"), num); - refresh(); -} - -// ============================================================================= -// -static void MoveSelection (const bool up) -{ - LDObjectList objs = Selection(); - LDObject::moveObjects (objs, up); - g_win->buildObjList(); -} - -// ============================================================================= -// -void MainWindow::actionMoveUp() -{ - MoveSelection (true); -} - -void MainWindow::actionMoveDown() -{ - MoveSelection (false); -} - -// ============================================================================= -// -void MainWindow::actionUndo() -{ - CurrentDocument()->undo(); -} - -void MainWindow::actionRedo() -{ - CurrentDocument()->redo(); -} - -// ============================================================================= -// -static void MoveObjects (Vertex vect) -{ - // Apply the grid values - vect *= *CurrentGrid().coordinateSnap; - - for (LDObjectPtr obj : Selection()) - obj->move (vect); - - g_win->refresh(); -} - -// ============================================================================= -// -void MainWindow::actionMoveXNeg() -{ - MoveObjects ({-1, 0, 0}); -} - -void MainWindow::actionMoveYNeg() -{ - MoveObjects ({0, -1, 0}); -} - -void MainWindow::actionMoveZNeg() -{ - MoveObjects ({0, 0, -1}); -} - -void MainWindow::actionMoveXPos() -{ - MoveObjects ({1, 0, 0}); -} - -void MainWindow::actionMoveYPos() -{ - MoveObjects ({0, 1, 0}); -} - -void MainWindow::actionMoveZPos() -{ - MoveObjects ({0, 0, 1}); -} - -// ============================================================================= -// -void MainWindow::actionInvert() -{ - for (LDObjectPtr obj : Selection()) - obj->invert(); - - refresh(); -} - -// ============================================================================= -// -static double GetRotateActionAngle() -{ - return (Pi * *CurrentGrid().angleSnap) / 180; -} - -void MainWindow::actionRotateXPos() -{ - RotateObjects (1, 0, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::actionRotateYPos() -{ - RotateObjects (0, 1, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::actionRotateZPos() -{ - RotateObjects (0, 0, 1, GetRotateActionAngle(), Selection()); -} -void MainWindow::actionRotateXNeg() -{ - RotateObjects (-1, 0, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::actionRotateYNeg() -{ - RotateObjects (0, -1, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::actionRotateZNeg() -{ - RotateObjects (0, 0, -1, GetRotateActionAngle(), Selection()); -} - -void MainWindow::actionRotationPoint() -{ - ConfigureRotationPoint(); -} - -// ============================================================================= -// -void MainWindow::actionRoundCoordinates() -{ - setlocale (LC_ALL, "C"); - int num = 0; - - for (LDObjectPtr obj : Selection()) - { - LDMatrixObjectPtr mo = obj.dynamicCast(); - - if (mo != null) - { - Vertex v = mo->position(); - Matrix t = mo->transform(); - - // Note: matrix values are to be rounded to 4 decimals. - v.apply ([](Axis, double& a) { RoundToDecimals (a, cfg::RoundPosition); }); - ApplyToMatrix (t, [](int, double& a) { RoundToDecimals (a, cfg::RoundMatrix); }); - - mo->setPosition (v); - mo->setTransform (t); - num += 12; - } - else - { - for (int i = 0; i < obj->numVertices(); ++i) - { - Vertex v = obj->vertex (i); - v.apply ([](Axis, double& a) { RoundToDecimals (a, cfg::RoundPosition); }); - obj->setVertex (i, v); - num += 3; - } - } - } - - print (tr ("Rounded %1 values"), num); - refreshObjectList(); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionUncolor() -{ - int num = 0; - - for (LDObjectPtr obj : Selection()) - { - if (not obj->isColored()) - continue; - - obj->setColor (obj->defaultColor()); - num++; - } - - print (tr ("%1 objects uncolored"), num); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionReplaceCoords() -{ - QDialog* dlg = new QDialog (g_win); - Ui::ReplaceCoordsUI ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - const double search = ui.search->value(), - replacement = ui.replacement->value(); - const bool any = ui.any->isChecked(), - rel = ui.relative->isChecked(); - - QList sel; - int num = 0; - - if (ui.x->isChecked()) sel << X; - if (ui.y->isChecked()) sel << Y; - if (ui.z->isChecked()) sel << Z; - - for (LDObjectPtr obj : Selection()) - { - for (int i = 0; i < obj->numVertices(); ++i) - { - Vertex v = obj->vertex (i); - - v.apply ([&](Axis ax, double& coord) - { - if (not sel.contains (ax) or - (not any and coord != search)) - { - return; - } - - if (not rel) - coord = 0; - - coord += replacement; - num++; - }); - - obj->setVertex (i, v); - } - } - - print (tr ("Altered %1 values"), num); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionFlip() -{ - QDialog* dlg = new QDialog; - Ui::FlipUI ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - QList sel; - - if (ui.x->isChecked()) sel << X; - if (ui.y->isChecked()) sel << Y; - if (ui.z->isChecked()) sel << Z; - - for (LDObjectPtr obj : Selection()) - { - for (int i = 0; i < obj->numVertices(); ++i) - { - Vertex v = obj->vertex (i); - - v.apply ([&](Axis ax, double& a) - { - if (sel.contains (ax)) - a = -a; - }); - - obj->setVertex (i, v); - } - } - - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionDemote() -{ - int num = 0; - - LDIterate (Selection(), [&](LDCondLinePtr const& cnd) - { - cnd->toEdgeLine(); - ++num; - }); - - print (tr ("Demoted %1 conditional lines"), num); - refresh(); -} - -// ============================================================================= -// -static bool IsColorUsed (LDColor color) -{ - for (LDObjectPtr obj : CurrentDocument()->objects()) - { - if (obj->isColored() and obj->color() == color) - return true; - } - - return false; -} - -// ============================================================================= -// -void MainWindow::actionAutocolor() -{ - int colnum = 0; - LDColor color; - - for (colnum = 0; - colnum < CountLDConfigColors() and - ((color = LDColor::fromIndex (colnum)) == null or - IsColorUsed (color)); - colnum++) {} - - if (colnum >= CountLDConfigColors()) - { - print (tr ("Cannot auto-color: all colors are in use!")); - return; - } - - for (LDObjectPtr obj : Selection()) - { - if (not obj->isColored()) - continue; - - obj->setColor (color); - } - - print (tr ("Auto-colored: new color is [%1] %2"), colnum, color.name()); - refresh(); -} - -// ============================================================================= -// -void MainWindow::actionAddHistoryLine() -{ - LDObjectPtr obj; - bool ishistory = false, - prevIsHistory = false; - - QDialog* dlg = new QDialog; - Ui_AddHistoryLine* ui = new Ui_AddHistoryLine; - ui->setupUi (dlg); - ui->m_username->setText (cfg::DefaultUser); - ui->m_date->setDate (QDate::currentDate()); - ui->m_comment->setFocus(); - - if (not dlg->exec()) - return; - - // Create the comment object based on input - QString commentText = format ("!HISTORY %1 [%2] %3", - ui->m_date->date().toString ("yyyy-MM-dd"), - ui->m_username->text(), - ui->m_comment->text()); - - LDCommentPtr comm (LDSpawn (commentText)); - - // Find a spot to place the new comment - for (obj = CurrentDocument()->getObject (0); - obj != null and obj->next() != null and not obj->next()->isScemantic(); - obj = obj->next()) - { - LDCommentPtr comm = obj.dynamicCast(); - - if (comm != null and comm->text().startsWith ("!HISTORY ")) - ishistory = true; - - if (prevIsHistory and not ishistory) - { - // Last line was history, this isn't, thus insert the new history - // line here. - break; - } - - prevIsHistory = ishistory; - } - - int idx = obj ? obj->lineNumber() : 0; - CurrentDocument()->insertObj (idx++, comm); - - // If we're adding a history line right before a scemantic object, pad it - // an empty line - if (obj and obj->next() and obj->next()->isScemantic()) - CurrentDocument()->insertObj (idx, LDEmptyPtr (LDSpawn())); - - buildObjList(); - delete ui; -} - -void MainWindow::actionSplitLines() -{ - bool ok; - int segments = QInputDialog::getInt (g_win, APPNAME, "Amount of segments:", cfg::SplitLinesSegments, 0, - std::numeric_limits::max(), 1, &ok); - - if (not ok) - return; - - cfg::SplitLinesSegments = segments; - - for (LDObjectPtr obj : Selection()) - { - if (not Eq (obj->type(), OBJ_Line, OBJ_CondLine)) - continue; - - QVector newsegs; - - for (int i = 0; i < segments; ++i) - { - LDObjectPtr segment; - Vertex v0, v1; - - v0.apply ([&](Axis ax, double& a) - { - double len = obj->vertex (1)[ax] - obj->vertex (0)[ax]; - a = (obj->vertex (0)[ax] + ((len * i) / segments)); - }); - - v1.apply ([&](Axis ax, double& a) - { - double len = obj->vertex (1)[ax] - obj->vertex (0)[ax]; - a = (obj->vertex (0)[ax] + ((len * (i + 1)) / segments)); - }); - - if (obj->type() == OBJ_Line) - segment = LDSpawn (v0, v1); - else - segment = LDSpawn (v0, v1, obj->vertex (2), obj->vertex (3)); - - newsegs << segment; - } - - int ln = obj->lineNumber(); - - for (LDObjectPtr seg : newsegs) - CurrentDocument()->insertObj (ln++, seg); - - obj->destroy(); - } - - buildObjList(); - g_win->refresh(); -}