Sun, 30 Aug 2015 17:20:55 +0300
Split actions.cpp and actionsEdit.cpp into toolsets.
--- a/CMakeLists.txt Sun Aug 30 15:18:41 2015 +0300 +++ b/CMakeLists.txt Sun Aug 30 17:20:55 2015 +0300 @@ -33,8 +33,6 @@ include_directories (${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) set (LDFORGE_SOURCES - src/actions.cpp - src/actionsEdit.cpp src/addObjectDialog.cpp src/basics.cpp src/colors.cpp @@ -44,7 +42,6 @@ src/dialogs.cpp src/documentation.cpp src/editHistory.cpp - src/extPrograms.cpp src/glRenderer.cpp src/glCompiler.cpp src/ldDocument.cpp @@ -71,6 +68,13 @@ src/editmodes/magicWandMode.cpp src/editmodes/rectangleMode.cpp src/editmodes/selectMode.cpp + src/toolsets/algorithmtoolset.cpp + src/toolsets/basictoolset.cpp + src/toolsets/extprogramtoolset.cpp + src/toolsets/filetoolset.cpp + src/toolsets/movetoolset.cpp + src/toolsets/toolset.cpp + src/toolsets/viewtoolset.cpp ) set (LDFORGE_HEADERS @@ -110,6 +114,13 @@ src/editmodes/magicWandMode.h src/editmodes/rectangleMode.h src/editmodes/selectMode.h + src/toolsets/algorithmtoolset.h + src/toolsets/basictoolset.h + src/toolsets/extprogramtoolset.h + src/toolsets/filetoolset.h + src/toolsets/movetoolset.h + src/toolsets/toolset.h + src/toolsets/viewtoolset.h ) set (LDFORGE_FORMS
--- a/src/actions.cpp Sun Aug 30 15:18:41 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,883 +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 <http://www.gnu.org/licenses/>. - */ - -#include <QFileDialog> -#include <QMessageBox> -#include <QTextEdit> -#include <QBoxLayout> -#include <QDialogButtonBox> -#include <QPushButton> -#include <QInputDialog> - -#include "mainwindow.h" -#include "ldDocument.h" -#include "editHistory.h" -#include "configDialog.h" -#include "addObjectDialog.h" -#include "miscallenous.h" -#include "glRenderer.h" -#include "dialogs.h" -#include "primitives.h" -#include "radioGroup.h" -#include "colors.h" -#include "glCompiler.h" -#include "ldobjectiterator.h" -#include "dialogs/ldrawpathdialog.h" -#include "dialogs/newpartdialog.h" -#include "editmodes/abstractEditMode.h" - -EXTERN_CFGENTRY (Bool, DrawWireframe) -EXTERN_CFGENTRY (Bool, BFCRedGreenView) -EXTERN_CFGENTRY (Bool, DrawAngles) -EXTERN_CFGENTRY (Bool, RandomColors) -EXTERN_CFGENTRY (Bool, DrawSurfaces) -EXTERN_CFGENTRY (Bool, DrawEdgeLines) -EXTERN_CFGENTRY (Bool, DrawConditionalLines) -EXTERN_CFGENTRY (Bool, DrawAxes) -EXTERN_CFGENTRY (String, LDrawPath) -EXTERN_CFGENTRY (String, DefaultName) -EXTERN_CFGENTRY (String, DefaultUser) -EXTERN_CFGENTRY (Bool, UseCALicense) - -// ============================================================================= -// -void MainWindow::slot_actionNew() -{ - NewPartDialog* dlg = new NewPartDialog (this); - - if (dlg->exec() == QDialog::Accepted) - { - newFile(); - dlg->fillHeader (CurrentDocument()); - doFullRefresh(); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionNewFile() -{ - newFile(); -} - -// ============================================================================= -// -void MainWindow::slot_actionOpen() -{ - QString name = QFileDialog::getOpenFileName (this, "Open File", "", "LDraw files (*.dat *.ldr)"); - - if (name.isEmpty()) - return; - - OpenMainModel (name); -} - -// ============================================================================= -// -void MainWindow::slot_actionSave() -{ - save (CurrentDocument(), false); -} - -// ============================================================================= -// -void MainWindow::slot_actionSaveAs() -{ - save (CurrentDocument(), true); -} - -// ============================================================================= -// -void MainWindow::slot_actionSaveAll() -{ - for (LDDocument* file : LDDocument::explicitDocuments()) - save (file, false); -} - -// ============================================================================= -// -void MainWindow::slot_actionClose() -{ - if (not CurrentDocument()->isSafeToClose()) - return; - - CurrentDocument()->dismiss(); -} - -// ============================================================================= -// -void MainWindow::slot_actionCloseAll() -{ - if (not IsSafeToCloseAll()) - return; - - CloseAllDocuments(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSettings() -{ - (new ConfigDialog)->exec(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSetLDrawPath() -{ - (new LDrawPathDialog (cfg::LDrawPath, true))->exec(); -} - -// ============================================================================= -// -void MainWindow::slot_actionExit() -{ - Exit(); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewSubfile() -{ - AddObjectDialog::staticDialog (OBJ_Subfile, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewLine() -{ - AddObjectDialog::staticDialog (OBJ_Line, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewTriangle() -{ - AddObjectDialog::staticDialog (OBJ_Triangle, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewQuad() -{ - AddObjectDialog::staticDialog (OBJ_Quad, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewCLine() -{ - AddObjectDialog::staticDialog (OBJ_CondLine, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewComment() -{ - AddObjectDialog::staticDialog (OBJ_Comment, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionNewBFC() -{ - AddObjectDialog::staticDialog (OBJ_BFC, nullptr); -} - -// ============================================================================= -// -void MainWindow::slot_actionEdit() -{ - if (Selection().size() != 1) - return; - - LDObject* obj = Selection().first(); - AddObjectDialog::staticDialog (obj->type(), obj); -} - -// ============================================================================= -// -void MainWindow::slot_actionHelp() -{ -} - -// ============================================================================= -// -void MainWindow::slot_actionAbout() -{ - AboutDialog().exec(); -} - -// ============================================================================= -// -void MainWindow::slot_actionAboutQt() -{ - QMessageBox::aboutQt (this); -} - -// ============================================================================= -// -void MainWindow::slot_actionSelectAll() -{ - for (LDObject* obj : CurrentDocument()->objects()) - obj->select(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSelectByColor() -{ - if (Selection().isEmpty()) - return; - - QList<LDColor> colors; - - for (LDObject* obj : Selection()) - { - if (obj->isColored()) - colors << obj->color(); - } - - removeDuplicates (colors); - CurrentDocument()->clearSelection(); - - for (LDObject* obj : CurrentDocument()->objects()) - { - if (colors.contains (obj->color())) - obj->select(); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionSelectByType() -{ - if (Selection().isEmpty()) - return; - - QList<LDObjectType> types; - QStringList subfilenames; - - for (LDObject* obj : Selection()) - { - types << obj->type(); - - if (types.last() == OBJ_Subfile) - subfilenames << static_cast<LDSubfile*> (obj)->fileInfo()->name(); - } - - removeDuplicates (types); - removeDuplicates (subfilenames); - CurrentDocument()->clearSelection(); - - for (LDObject* obj : CurrentDocument()->objects()) - { - LDObjectType type = obj->type(); - - if (not types.contains (type)) - continue; - - // For subfiles, type check is not enough, we check the name of the document as well. - if (type == OBJ_Subfile and not subfilenames.contains (static_cast<LDSubfile*> (obj)->fileInfo()->name())) - continue; - - obj->select(); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionGridCoarse() -{ - cfg::Grid = Grid::Coarse; - updateGridToolBar(); -} - -void MainWindow::slot_actionGridMedium() -{ - cfg::Grid = Grid::Medium; - updateGridToolBar(); -} - -void MainWindow::slot_actionGridFine() -{ - cfg::Grid = Grid::Fine; - updateGridToolBar(); -} - -// ============================================================================= -// -void MainWindow::slot_actionResetView() -{ - R()->resetAngles(); - R()->update(); -} - -// ============================================================================= -// -void MainWindow::slot_actionInsertFrom() -{ - QString fname = QFileDialog::getOpenFileName(); - int idx = getInsertionPoint(); - - if (not fname.length()) - return; - - QFile f (fname); - - if (not f.open (QIODevice::ReadOnly)) - { - Critical (format ("Couldn't open %1 (%2)", fname, f.errorString())); - return; - } - - LDObjectList objs = LoadFileContents (&f, null); - - CurrentDocument()->clearSelection(); - - for (LDObject* obj : objs) - { - CurrentDocument()->insertObj (idx, obj); - obj->select(); - R()->compileObject (obj); - - idx++; - } - - refresh(); - scrollToSelection(); -} - -// ============================================================================= -// -void MainWindow::slot_actionExportTo() -{ - if (Selection().isEmpty()) - return; - - QString fname = QFileDialog::getSaveFileName(); - - if (fname.length() == 0) - return; - - QFile file (fname); - - if (not file.open (QIODevice::WriteOnly | QIODevice::Text)) - { - Critical (format ("Unable to open %1 for writing (%2)", fname, file.errorString())); - return; - } - - for (LDObject* obj : Selection()) - { - QString contents = obj->asText(); - QByteArray data = contents.toUtf8(); - file.write (data, data.size()); - file.write ("\r\n", 2); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionInsertRaw() -{ - int idx = getInsertionPoint(); - - QDialog* const dlg = new QDialog; - QVBoxLayout* const layout = new QVBoxLayout; - QTextEdit* const te_edit = new QTextEdit; - QDialogButtonBox* const bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - - layout->addWidget (te_edit); - layout->addWidget (bbx_buttons); - dlg->setLayout (layout); - dlg->setWindowTitle (APPNAME " - Insert Raw"); - dlg->connect (bbx_buttons, SIGNAL (accepted()), dlg, SLOT (accept())); - dlg->connect (bbx_buttons, SIGNAL (rejected()), dlg, SLOT (reject())); - - if (dlg->exec() == QDialog::Rejected) - return; - - CurrentDocument()->clearSelection(); - - for (QString line : QString (te_edit->toPlainText()).split ("\n")) - { - LDObject* obj = ParseLine (line); - - CurrentDocument()->insertObj (idx, obj); - obj->select(); - idx++; - } - - refresh(); - scrollToSelection(); -} - -// ============================================================================= -// -void MainWindow::slot_actionScreenshot() -{ - setlocale (LC_ALL, "C"); - - int w, h; - uchar* imgdata = R()->getScreencap (w, h); - QImage img = GetImageFromScreencap (imgdata, w, h); - - QString root = Basename (CurrentDocument()->name()); - - if (root.right (4) == ".dat") - root.chop (4); - - QString defaultname = (root.length() > 0) ? format ("%1.png", root) : ""; - QString fname = QFileDialog::getSaveFileName (this, "Save Screencap", defaultname, - "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)"); - - if (not fname.isEmpty() and not img.save (fname)) - Critical (format ("Couldn't open %1 for writing to save screencap: %2", fname, strerror (errno))); - - delete[] imgdata; -} - -// ============================================================================= -// -void MainWindow::slot_actionAxes() -{ - cfg::DrawAxes = not cfg::DrawAxes; - updateActions(); - R()->update(); -} - -// ============================================================================= -// -void MainWindow::slot_actionVisibilityToggle() -{ - for (LDObject* obj : Selection()) - obj->setHidden (not obj->isHidden()); - - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionVisibilityHide() -{ - for (LDObject* obj : Selection()) - obj->setHidden (true); - - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionVisibilityReveal() -{ - for (LDObject* obj : Selection()) - obj->setHidden (false); - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionWireframe() -{ - cfg::DrawWireframe = not cfg::DrawWireframe; - R()->refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSetOverlay() -{ - OverlayDialog dlg; - - if (not dlg.exec()) - return; - - R()->setupOverlay ((ECamera) dlg.camera(), dlg.fpath(), dlg.ofsx(), - dlg.ofsy(), dlg.lwidth(), dlg.lheight()); -} - -// ============================================================================= -// -void MainWindow::slot_actionClearOverlay() -{ - R()->clearOverlay(); -} - -// ============================================================================= -// -void MainWindow::slot_actionModeSelect() -{ - R()->setEditMode (EditModeType::Select); -} - -// ============================================================================= -// -void MainWindow::slot_actionModeDraw() -{ - R()->setEditMode (EditModeType::Draw); -} - -// ============================================================================= -// -void MainWindow::slot_actionModeRectangle() -{ - R()->setEditMode (EditModeType::Rectangle); -} - -// ============================================================================= -// -void MainWindow::slot_actionModeCircle() -{ - R()->setEditMode (EditModeType::Circle); -} - -// ============================================================================= -// -void MainWindow::slot_actionModeMagicWand() -{ - R()->setEditMode (EditModeType::MagicWand); -} - -void MainWindow::slot_actionModeLinePath() -{ - R()->setEditMode (EditModeType::LinePath); -} - -// ============================================================================= -// -void MainWindow::slot_actionDrawAngles() -{ - cfg::DrawAngles = not cfg::DrawAngles; - R()->refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSetDrawDepth() -{ - if (R()->camera() == EFreeCamera) - return; - - bool ok; - double depth = QInputDialog::getDouble (this, "Set Draw Depth", - format ("Depth value for %1 Camera:", R()->getCameraName()), - R()->getDepthValue(), -10000.0f, 10000.0f, 3, &ok); - - if (ok) - R()->setDepthValue (depth); -} - -#if 0 -// This is a test to draw a dummy axle. Meant to be used as a primitive gallery, -// but I can't figure how to generate these pictures properly. Multi-threading -// these is an immense pain. -void MainWindow::slot_actiontestpic() -{ - LDDocument* file = getFile ("axle.dat"); - setlocale (LC_ALL, "C"); - - if (not file) - { - critical ("couldn't load axle.dat"); - return; - } - - int w, h; - - GLRenderer* rend = new GLRenderer; - rend->resize (64, 64); - rend->setAttribute (Qt::WA_DontShowOnScreen); - rend->show(); - rend->setFile (file); - rend->setDrawOnly (true); - rend->compileAllObjects(); - rend->initGLData(); - rend->drawGLScene(); - - uchar* imgdata = rend->screencap (w, h); - QImage img = imageFromScreencap (imgdata, w, h); - - if (img.isNull()) - { - critical ("Failed to create the image!\n"); - } - else - { - QLabel* label = new QLabel; - QDialog* dlg = new QDialog; - label->setPixmap (QPixmap::fromImage (img)); - QVBoxLayout* layout = new QVBoxLayout (dlg); - layout->addWidget (label); - dlg->exec(); - } - - delete[] imgdata; - rend->deleteLater(); -} -#endif - -// ============================================================================= -// -void MainWindow::slot_actionScanPrimitives() -{ - PrimitiveScanner::start(); -} - -// ============================================================================= -// -void MainWindow::slot_actionBFCView() -{ - cfg::BFCRedGreenView = not cfg::BFCRedGreenView; - - if (cfg::BFCRedGreenView) - cfg::RandomColors = false; - - updateActions(); - R()->refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionJumpTo() -{ - bool ok; - int defval = 0; - LDObject* obj; - - if (Selection().size() == 1) - defval = Selection()[0]->lineNumber(); - - int idx = QInputDialog::getInt (null, "Go to line", "Go to line:", defval, - 1, CurrentDocument()->getObjectCount(), 1, &ok); - - if (not ok or (obj = CurrentDocument()->getObject (idx - 1)) == null) - return; - - CurrentDocument()->clearSelection(); - obj->select(); - updateSelection(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSubfileSelection() -{ - if (Selection().size() == 0) - return; - - QString parentpath (CurrentDocument()->fullPath()); - - // BFC type of the new subfile - it shall inherit the BFC type of the parent document - BFCStatement bfctype (BFCStatement::NoCertify); - - // Dirname of the new subfile - QString subdirname (Dirname (parentpath)); - - // Title of the new subfile - QString subtitle; - - // Comment containing the title of the parent document - LDComment* titleobj = dynamic_cast<LDComment*> (CurrentDocument()->getObject (0)); - - // License text for the subfile - QString license (PreferredLicenseText()); - - // LDraw code body of the new subfile (i.e. code of the selection) - QStringList code; - - // Full path of the subfile to be - QString fullsubname; - - // Where to insert the subfile reference? - int refidx (Selection()[0]->lineNumber()); - - // Determine title of subfile - if (titleobj != null) - subtitle = "~" + titleobj->text(); - else - subtitle = "~subfile"; - - // Remove duplicate tildes - while (subtitle.startsWith ("~~")) - subtitle.remove (0, 1); - - // If this the parent document isn't already in s/, we need to stuff it into - // a subdirectory named s/. Ensure it exists! - QString topdirname = Basename (Dirname (CurrentDocument()->fullPath())); - - if (topdirname != "s") - { - QString desiredPath = subdirname + "/s"; - QString title = tr ("Create subfile directory?"); - QString text = format (tr ("The directory <b>%1</b> is suggested for " - "subfiles. This directory does not exist, create it?"), desiredPath); - - if (QDir (desiredPath).exists() or Confirm (title, text)) - { - subdirname = desiredPath; - QDir().mkpath (subdirname); - } - else - return; - } - - // Determine the body of the name of the subfile - if (not parentpath.isEmpty()) - { - // Chop existing '.dat' suffix - if (parentpath.endsWith (".dat")) - parentpath.chop (4); - - // Remove the s?? suffix if it's there, otherwise we'll get filenames - // like s01s01.dat when subfiling subfiles. - QRegExp subfilesuffix ("s[0-9][0-9]$"); - if (subfilesuffix.indexIn (parentpath) != -1) - parentpath.chop (subfilesuffix.matchedLength()); - - int subidx = 1; - QString digits; - - // Now find the appropriate filename. Increase the number of the subfile - // until we find a name which isn't already taken. - do - { - digits.setNum (subidx++); - - // pad it with a zero - if (digits.length() == 1) - digits.prepend ("0"); - - fullsubname = subdirname + "/" + Basename (parentpath) + "s" + digits + ".dat"; - } while (FindDocument ("s\\" + Basename (fullsubname)) != null or QFile (fullsubname).exists()); - } - - // Determine the BFC winding type used in the main document - it is to - // be carried over to the subfile. - for (LDObjectIterator<LDBFC> it (CurrentDocument()); it.isValid(); ++it) - { - if (isOneOf (it->statement(), BFCStatement::CertifyCCW, BFCStatement::CertifyCW, BFCStatement::NoCertify)) - { - bfctype = it->statement(); - break; - } - } - - // Get the body of the document in LDraw code - for (LDObject* obj : Selection()) - code << obj->asText(); - - // Create the new subfile document - LDDocument* doc = LDDocument::createNew(); - doc->setImplicit (false); - doc->setFullPath (fullsubname); - doc->setName (LDDocument::shortenName (fullsubname)); - - LDObjectList objs; - objs << LDSpawn<LDComment> (subtitle); - objs << LDSpawn<LDComment> ("Name: "); // This gets filled in when the subfile is saved - objs << LDSpawn<LDComment> (format ("Author: %1 [%2]", cfg::DefaultName, cfg::DefaultUser)); - objs << LDSpawn<LDComment> ("!LDRAW_ORG Unofficial_Subpart"); - - if (not license.isEmpty()) - objs << LDSpawn<LDComment> (license); - - objs << LDSpawn<LDEmpty>(); - objs << LDSpawn<LDBFC> (bfctype); - objs << LDSpawn<LDEmpty>(); - - doc->addObjects (objs); - - // Add the actual subfile code to the new document - for (QString line : code) - { - LDObject* obj = ParseLine (line); - doc->addObject (obj); - } - - // Try save it - if (save (doc, true)) - { - // Save was successful. Delete the original selection now from the - // main document. - for (LDObject* obj : Selection()) - obj->destroy(); - - // Add a reference to the new subfile to where the selection was - LDSubfile* ref (LDSpawn<LDSubfile>()); - ref->setColor (MainColor); - ref->setFileInfo (doc); - ref->setPosition (Origin); - ref->setTransform (IdentityMatrix); - CurrentDocument()->insertObj (refidx, ref); - - // Refresh stuff - updateDocumentList(); - doFullRefresh(); - } - else - { - // Failed to save. - doc->dismiss(); - } -} - -void MainWindow::slot_actionRandomColors() -{ - cfg::RandomColors = not cfg::RandomColors; - - if (cfg::RandomColors) - cfg::BFCRedGreenView = false; - - updateActions(); - R()->refresh(); -} - -void MainWindow::slot_actionOpenSubfiles() -{ - for (LDObject* obj : Selection()) - { - LDSubfile* ref = dynamic_cast<LDSubfile*> (obj); - - if (ref == null or not ref->fileInfo()->isImplicit()) - continue; - - ref->fileInfo()->setImplicit (false); - } -} - -void MainWindow::slot_actionDrawSurfaces() -{ - cfg::DrawSurfaces = not cfg::DrawSurfaces; - updateActions(); - update(); -} - -void MainWindow::slot_actionDrawEdgeLines() -{ - cfg::DrawEdgeLines = not cfg::DrawEdgeLines; - updateActions(); - update(); -} - -void MainWindow::slot_actionDrawConditionalLines() -{ - cfg::DrawConditionalLines = not cfg::DrawConditionalLines; - updateActions(); - update(); -}
--- a/src/actionsEdit.cpp Sun Aug 30 15:18:41 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,730 +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 <http://www.gnu.org/licenses/>. - */ - -#include <limits> -#include <QSpinBox> -#include <QCheckBox> -#include <QBoxLayout> -#include <QClipboard> -#include <QInputDialog> -#include "mainwindow.h" -#include "main.h" -#include "ldDocument.h" -#include "dialogs/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" -#include "ldobjectiterator.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 (LDObject* obj : objs) - { - if (not data.isEmpty()) - data += "\n"; - - data += obj->asText(); - ++num; - } - - qApp->clipboard()->setText (data); - return num; -} - -// ============================================================================= -// -void MainWindow::slot_actionCut() -{ - int num = CopyToClipboard(); - deleteSelection(); - print (tr ("%1 objects cut"), num); -} - -// ============================================================================= -// -void MainWindow::slot_actionCopy() -{ - int num = CopyToClipboard(); - print (tr ("%1 objects copied"), num); -} - -// ============================================================================= -// -void MainWindow::slot_actionPaste() -{ - const QString clipboardText = qApp->clipboard()->text(); - int idx = getInsertionPoint(); - CurrentDocument()->clearSelection(); - int num = 0; - - for (QString line : clipboardText.split ("\n")) - { - LDObject* pasted = ParseLine (line); - CurrentDocument()->insertObj (idx++, pasted); - pasted->select(); - ++num; - } - - print (tr ("%1 objects pasted"), num); - refresh(); - scrollToSelection(); -} - -// ============================================================================= -// -void MainWindow::slot_actionDelete() -{ - int num = deleteSelection(); - print (tr ("%1 objects deleted"), num); -} - -// ============================================================================= -// -static void DoInline (bool deep) -{ - for (LDObjectIterator<LDSubfile> it (Selection()); it.isValid(); ++it) - { - // Get the index of the subfile so we know where to insert the - // inlined contents. - int idx = it->lineNumber(); - - if (idx != -1) - { - LDObjectList objs = it->inlineContents (deep, false); - - // Merge in the inlined objects - for (LDObject* inlineobj : objs) - { - QString line = inlineobj->asText(); - inlineobj->destroy(); - LDObject* newobj = ParseLine (line); - CurrentDocument()->insertObj (idx++, newobj); - newobj->select(); - } - - // Delete the subfile now as it's been inlined. - it->destroy(); - } - } -} - -void MainWindow::slot_actionInline() -{ - DoInline (false); - refresh(); -} - -void MainWindow::slot_actionInlineDeep() -{ - DoInline (true); - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionSplitQuads() -{ - int num = 0; - - for (LDObjectIterator<LDQuad> it (Selection()); it.isValid(); ++it) - { - // Find the index of this quad - long index = it->lineNumber(); - - if (index == -1) - return; - - QList<LDTriangle*> triangles = it->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::slot_actionEditRaw() -{ - if (Selection().size() != 1) - return; - - LDObject* 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 (static_cast<LDError*> (obj)->reason()); - else - { - ui.errorDescription->hide(); - ui.errorIcon->hide(); - } - - if (dlg->exec() == QDialog::Rejected) - return; - - // Reinterpret it from the text of the input field - LDObject* newobj = ParseLine (ui.code->text()); - obj->replace (newobj); - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_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, this)) - { - for (LDObject* obj : objs) - { - if (obj->isColored()) - obj->setColor (color); - } - - refresh(); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionBorders() -{ - LDObjectList objs = Selection(); - int num = 0; - - for (LDObject* obj : objs) - { - const LDObjectType type = obj->type(); - - if (type != OBJ_Quad and type != OBJ_Triangle) - continue; - - LDLine* lines[4]; - - if (type == OBJ_Quad) - { - LDQuad* quad = static_cast<LDQuad*> (obj); - lines[0] = LDSpawn<LDLine> (quad->vertex (0), quad->vertex (1)); - lines[1] = LDSpawn<LDLine> (quad->vertex (1), quad->vertex (2)); - lines[2] = LDSpawn<LDLine> (quad->vertex (2), quad->vertex (3)); - lines[3] = LDSpawn<LDLine> (quad->vertex (3), quad->vertex (0)); - } - else - { - LDTriangle* tri = static_cast<LDTriangle*> (obj); - lines[0] = LDSpawn<LDLine> (tri->vertex (0), tri->vertex (1)); - lines[1] = LDSpawn<LDLine> (tri->vertex (1), tri->vertex (2)); - lines[2] = LDSpawn<LDLine> (tri->vertex (2), tri->vertex (0)); - lines[3] = nullptr; - } - - 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; - } - } - - print (tr ("Added %1 border lines"), num); - refresh(); -} - -// ============================================================================= -// -static void MoveSelection (MainWindow* win, bool up) -{ - LDObjectList objs = Selection(); - LDObject::moveObjects (objs, up); - win->buildObjList(); -} - -// ============================================================================= -// -void MainWindow::slot_actionMoveUp() -{ - MoveSelection (this, true); -} - -void MainWindow::slot_actionMoveDown() -{ - MoveSelection (this, false); -} - -// ============================================================================= -// -void MainWindow::slot_actionUndo() -{ - CurrentDocument()->undo(); -} - -void MainWindow::slot_actionRedo() -{ - CurrentDocument()->redo(); -} - -// ============================================================================= -// -static void MoveObjects (Vertex vect) -{ - // Apply the grid values - vect *= *CurrentGrid().coordinateSnap; - - for (LDObject* obj : Selection()) - obj->move (vect); -} - -// ============================================================================= -// -void MainWindow::slot_actionMoveXNeg() -{ - MoveObjects ({-1, 0, 0}); -} - -void MainWindow::slot_actionMoveYNeg() -{ - MoveObjects ({0, -1, 0}); -} - -void MainWindow::slot_actionMoveZNeg() -{ - MoveObjects ({0, 0, -1}); -} - -void MainWindow::slot_actionMoveXPos() -{ - MoveObjects ({1, 0, 0}); -} - -void MainWindow::slot_actionMoveYPos() -{ - MoveObjects ({0, 1, 0}); -} - -void MainWindow::slot_actionMoveZPos() -{ - MoveObjects ({0, 0, 1}); -} - -// ============================================================================= -// -void MainWindow::slot_actionInvert() -{ - for (LDObject* obj : Selection()) - obj->invert(); - - refresh(); -} - -// ============================================================================= -// -static double GetRotateActionAngle() -{ - return (Pi * *CurrentGrid().angleSnap) / 180; -} - -void MainWindow::slot_actionRotateXPos() -{ - RotateObjects (1, 0, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::slot_actionRotateYPos() -{ - RotateObjects (0, 1, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::slot_actionRotateZPos() -{ - RotateObjects (0, 0, 1, GetRotateActionAngle(), Selection()); -} -void MainWindow::slot_actionRotateXNeg() -{ - RotateObjects (-1, 0, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::slot_actionRotateYNeg() -{ - RotateObjects (0, -1, 0, GetRotateActionAngle(), Selection()); -} -void MainWindow::slot_actionRotateZNeg() -{ - RotateObjects (0, 0, -1, GetRotateActionAngle(), Selection()); -} - -void MainWindow::slot_actionRotationPoint() -{ - ConfigureRotationPoint(); -} - -// ============================================================================= -// -void MainWindow::slot_actionRoundCoordinates() -{ - setlocale (LC_ALL, "C"); - int num = 0; - - for (LDObject* obj : Selection()) - { - LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj); - - 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::slot_actionUncolor() -{ - int num = 0; - - for (LDObject* obj : Selection()) - { - if (not obj->isColored()) - continue; - - obj->setColor (obj->defaultColor()); - num++; - } - - print (tr ("%1 objects uncolored"), num); - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionReplaceCoords() -{ - QDialog* dlg = new QDialog (this); - 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<Axis> sel; - int num = 0; - - if (ui.x->isChecked()) sel << X; - if (ui.y->isChecked()) sel << Y; - if (ui.z->isChecked()) sel << Z; - - for (LDObject* 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::slot_actionFlip() -{ - QDialog* dlg = new QDialog; - Ui::FlipUI ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - QList<Axis> sel; - - if (ui.x->isChecked()) sel << X; - if (ui.y->isChecked()) sel << Y; - if (ui.z->isChecked()) sel << Z; - - for (LDObject* 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::slot_actionDemote() -{ - int num = 0; - - for (LDObjectIterator<LDCondLine> it (Selection()); it.isValid(); ++it) - { - it->toEdgeLine(); - ++num; - } - - print (tr ("Converted %1 conditional lines"), num); - refresh(); -} - -// ============================================================================= -// -static bool IsColorUsed (LDColor color) -{ - for (LDObject* obj : CurrentDocument()->objects()) - { - if (obj->isColored() and obj->color() == color) - return true; - } - - return false; -} - -// ============================================================================= -// -void MainWindow::slot_actionAutocolor() -{ - LDColor color; - - for (color = 0; color.isLDConfigColor(); ++color) - { - if (color.isValid() and not IsColorUsed (color)) - break; - } - - if (not color.isLDConfigColor()) - { - print (tr ("Cannot auto-color: all colors are in use!")); - return; - } - - for (LDObject* obj : Selection()) - { - if (not obj->isColored()) - continue; - - obj->setColor (color); - } - - print (tr ("Auto-colored: new color is [%1] %2"), color.index(), color.name()); - refresh(); -} - -// ============================================================================= -// -void MainWindow::slot_actionAddHistoryLine() -{ - LDObject* obj; - bool ishistory = false; - bool 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 - LDComment* comment = new LDComment (format ("!HISTORY %1 [%2] %3", - ui->m_date->date().toString ("yyyy-MM-dd"), - ui->m_username->text(), - ui->m_comment->text())); - - // Find a spot to place the new comment - for (obj = CurrentDocument()->getObject (0); - obj and obj->next() and not obj->next()->isScemantic(); - obj = obj->next()) - { - LDComment* comment = dynamic_cast<LDComment*> (obj); - - if (comment and comment->text().startsWith ("!HISTORY ")) - ishistory = true; - - if (prevIsHistory and not ishistory) - break; // Last line was history, this isn't, thus insert the new history line here. - - prevIsHistory = ishistory; - } - - int idx = obj ? obj->lineNumber() : 0; - CurrentDocument()->insertObj (idx++, comment); - - // 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, new LDEmpty); - - buildObjList(); - delete ui; -} - -void MainWindow::slot_actionSplitLines() -{ - bool ok; - int segments = QInputDialog::getInt (this, APPNAME, "Amount of segments:", cfg::SplitLinesSegments, 0, - std::numeric_limits<int>::max(), 1, &ok); - - if (not ok) - return; - - cfg::SplitLinesSegments = segments; - - for (LDObject* obj : Selection()) - { - if (not isOneOf (obj->type(), OBJ_Line, OBJ_CondLine)) - continue; - - QVector<LDObject*> newsegs; - - for (int i = 0; i < segments; ++i) - { - LDObject* 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<LDLine> (v0, v1); - else - segment = LDSpawn<LDCondLine> (v0, v1, obj->vertex (2), obj->vertex (3)); - - newsegs << segment; - } - - int ln = obj->lineNumber(); - - for (LDObject* seg : newsegs) - CurrentDocument()->insertObj (ln++, seg); - - obj->destroy(); - } - - buildObjList(); - refresh(); -}
--- a/src/extPrograms.cpp Sun Aug 30 15:18:41 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,721 +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 <http://www.gnu.org/licenses/>. - */ - -#include <QProcess> -#include <QTemporaryFile> -#include <QDialog> -#include <QDialogButtonBox> -#include <QSpinBox> -#include <QCheckBox> -#include <QComboBox> -#include <QGridLayout> -#include <QFileInfo> -#include "main.h" -#include "configuration.h" -#include "miscallenous.h" -#include "mainwindow.h" -#include "ldDocument.h" -#include "radioGroup.h" -#include "editHistory.h" -#include "ui_ytruder.h" -#include "ui_intersector.h" -#include "ui_rectifier.h" -#include "ui_coverer.h" -#include "ui_isecalc.h" -#include "ui_edger2.h" -#include "dialogs.h" - -enum extprog -{ - Isecalc, - Intersector, - Coverer, - Ytruder, - Rectifier, - Edger2, -}; - -// ============================================================================= -// -CFGENTRY (String, IsecalcPath, "") -CFGENTRY (String, IntersectorPath, "") -CFGENTRY (String, CovererPath, "") -CFGENTRY (String, YtruderPath, "") -CFGENTRY (String, RectifierPath, "") -CFGENTRY (String, Edger2Path, "") - -QString* const g_extProgPaths[] = -{ - &cfg::IsecalcPath, - &cfg::IntersectorPath, - &cfg::CovererPath, - &cfg::YtruderPath, - &cfg::RectifierPath, - &cfg::Edger2Path, -}; - -CFGENTRY (Bool, IsecalcUsesWine, false) -CFGENTRY (Bool, IntersectorUsesWine, false) -CFGENTRY (Bool, CovererUsesWine, false) -CFGENTRY (Bool, YtruderUsesWine, false) -CFGENTRY (Bool, RectifierUsesWine, false) -CFGENTRY (Bool, Edger2UsesWine, false) - -bool* const g_extProgWine[] = -{ - &cfg::IsecalcUsesWine, - &cfg::IntersectorUsesWine, - &cfg::CovererUsesWine, - &cfg::YtruderUsesWine, - &cfg::RectifierUsesWine, - &cfg::Edger2UsesWine, -}; - -const char* g_extProgNames[] = -{ - "Isecalc", - "Intersector", - "Coverer", - "Ytruder", - "Rectifier", - "Edger2" -}; - -// ============================================================================= -// -static bool MakeTempFile (QTemporaryFile& tmp, QString& fname) -{ - if (not tmp.open()) - return false; - - fname = tmp.fileName(); - tmp.close(); - return true; -} - -// ============================================================================= -// -static bool CheckExtProgramPath (const extprog prog) -{ - QString& path = *g_extProgPaths[prog]; - - if (not path.isEmpty()) - return true; - - ExtProgPathPrompt* dlg = new ExtProgPathPrompt (g_extProgNames[prog]); - - if (dlg->exec() and not dlg->getPath().isEmpty()) - { - path = dlg->getPath(); - return true; - } - - return false; -} - -// ============================================================================= -// -static QString ProcessExtProgError (extprog prog, QProcess& proc) -{ - switch (proc.error()) - { - case QProcess::FailedToStart: - { - QString wineblurb; - -#ifndef _WIN32 - if (*g_extProgWine[prog]) - wineblurb = "make sure Wine is installed and "; -#else - (void) prog; -#endif - - return format ("Program failed to start, %1check your permissions", wineblurb); - } break; - - case QProcess::Crashed: - return "Crashed."; - - case QProcess::WriteError: - case QProcess::ReadError: - return "I/O error."; - - case QProcess::UnknownError: - return "Unknown error"; - - case QProcess::Timedout: - return format ("Timed out (30 seconds)"); - } - - return ""; -} - -// ============================================================================= -// -static void WriteObjects (const LDObjectList& objects, QFile& f) -{ - for (LDObject* obj : objects) - { - if (obj->type() == OBJ_Subfile) - { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - LDObjectList objs = ref->inlineContents (true, false); - - WriteObjects (objs, f); - - for (LDObject* obj : objs) - obj->destroy(); - } - else - f.write ((obj->asText() + "\r\n").toUtf8()); - } -} - -// ============================================================================= -// -static void WriteObjects (const LDObjectList& objects, QString fname) -{ - // Write the input file - QFile f (fname); - - if (not f.open (QIODevice::WriteOnly | QIODevice::Text)) - { - Critical (format ("Couldn't open temporary file %1 for writing: %2\n", fname, f.errorString())); - return; - } - - WriteObjects (objects, f); - f.close(); - -#ifdef DEBUG - QFile::copy (fname, "debug_lastInput"); -#endif -} - -// ============================================================================= -// -void WriteSelection (QString fname) -{ - WriteObjects (Selection(), fname); -} - -// ============================================================================= -// -void WriteColorGroup (LDColor color, QString fname) -{ - LDObjectList objects; - - for (LDObject* obj : CurrentDocument()->objects()) - { - if (not obj->isColored() or obj->color() != color) - continue; - - objects << obj; - } - - WriteObjects (objects, fname); -} - -// ============================================================================= -// -bool RunExtProgram (extprog prog, QString path, QString argvstr) -{ - QTemporaryFile input; - QStringList argv = argvstr.split (" ", QString::SkipEmptyParts); - -#ifndef _WIN32 - if (*g_extProgWine[prog]) - { - argv.insert (0, path); - path = "wine"; - } -#endif // _WIN32 - - print ("Running command: %1 %2\n", path, argv.join (" ")); - - if (not input.open()) - return false; - - QProcess proc; - - // Begin! - proc.setStandardInputFile (input.fileName()); - proc.start (path, argv); - - if (not proc.waitForStarted()) - { - Critical (format ("Couldn't start %1: %2\n", g_extProgNames[prog], ProcessExtProgError (prog, proc))); - return false; - } - - // Write an enter, the utility tools all expect one - input.write ("\n"); - - // Wait while it runs - proc.waitForFinished(); - - QString err = ""; - - if (proc.exitStatus() != QProcess::NormalExit) - err = ProcessExtProgError (prog, proc); - - // Check the return code - if (proc.exitCode() != 0) - err = format ("Program exited abnormally (return code %1).", proc.exitCode()); - - if (not err.isEmpty()) - { - Critical (format ("%1 failed: %2\n", g_extProgNames[prog], err)); - QString filename ("externalProgramOutput.txt"); - QFile file (filename); - - if (file.open (QIODevice::WriteOnly | QIODevice::Text)) - { - file.write (proc.readAllStandardOutput()); - file.write (proc.readAllStandardError()); - print ("Wrote output and error logs to %1", QFileInfo (file).absoluteFilePath()); - } - else - { - print ("Couldn't open %1 for writing: %2", - QFileInfo (filename).absoluteFilePath(), file.errorString()); - } - - return false; - } - - return true; -} - -// ============================================================================= -// -static void InsertOutput (QString fname, bool replace, QList<LDColor> colorsToReplace) -{ -#ifdef DEBUG - QFile::copy (fname, "./debug_lastOutput"); -#endif // RELEASE - - // Read the output file - QFile f (fname); - - if (not f.open (QIODevice::ReadOnly)) - { - Critical (format ("Couldn't open temporary file %1 for reading.\n", fname)); - return; - } - - LDObjectList objs = LoadFileContents (&f, null); - - // If we replace the objects, delete the selection now. - if (replace) - g_win->deleteSelection(); - - for (LDColor color : colorsToReplace) - g_win->deleteByColor (color); - - // Insert the new objects - CurrentDocument()->clearSelection(); - - for (LDObject* obj : objs) - { - if (not obj->isScemantic()) - { - obj->destroy(); - continue; - } - - CurrentDocument()->addObject (obj); - obj->select(); - } - - g_win->doFullRefresh(); -} - -// ============================================================================= -// Interface for Ytruder -// ============================================================================= -void MainWindow::slot_actionYtruder() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Ytruder)) - return; - - QDialog* dlg = new QDialog; - Ui::YtruderUI ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - // Read the user's choices - const enum { Distance, Symmetry, Projection, Radial } mode = - ui.mode_distance->isChecked() ? Distance : - ui.mode_symmetry->isChecked() ? Symmetry : - ui.mode_projection->isChecked() ? Projection : Radial; - - const Axis axis = - ui.axis_x->isChecked() ? X : - ui.axis_y->isChecked() ? Y : Z; - - const double depth = ui.planeDepth->value(), - condAngle = ui.condAngle->value(); - - QTemporaryFile indat, outdat; - QString inDATName, outDATName; - - // Make temp files for the input and output files - if (not MakeTempFile (indat, inDATName) or not MakeTempFile (outdat, outDATName)) - return; - - // Compose the command-line arguments - QString argv = Join ( - { - (axis == X) ? "-x" : (axis == Y) ? "-y" : "-z", - (mode == Distance) ? "-d" : (mode == Symmetry) ? "-s" : (mode == Projection) ? "-p" : "-r", - depth, - "-a", - condAngle, - inDATName, - outDATName - }); - - WriteSelection (inDATName); - - if (not RunExtProgram (Ytruder, cfg::YtruderPath, argv)) - return; - - InsertOutput (outDATName, false, {}); -} - -// ============================================================================= -// Rectifier interface -// ============================================================================= -void MainWindow::slot_actionRectifier() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Rectifier)) - return; - - QDialog* dlg = new QDialog; - Ui::RectifierUI ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - QTemporaryFile indat, outdat; - QString inDATName, outDATName; - - // Make temp files for the input and output files - if (not MakeTempFile (indat, inDATName) or not MakeTempFile (outdat, outDATName)) - return; - - // Compose arguments - QString argv = Join ( - { - (not ui.cb_condense->isChecked()) ? "-q" : "", - (not ui.cb_subst->isChecked()) ? "-r" : "", - (ui.cb_condlineCheck->isChecked()) ? "-a" : "", - (ui.cb_colorize->isChecked()) ? "-c" : "", - "-t", - ui.dsb_coplthres->value(), - inDATName, - outDATName - }); - - WriteSelection (inDATName); - - if (not RunExtProgram (Rectifier, cfg::RectifierPath, argv)) - return; - - InsertOutput (outDATName, true, {}); -} - -// ============================================================================= -// Intersector interface -// ============================================================================= -void MainWindow::slot_actionIntersector() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Intersector)) - return; - - QDialog* dlg = new QDialog; - Ui::IntersectorUI ui; - ui.setupUi (dlg); - - MakeColorComboBox (ui.cmb_incol); - MakeColorComboBox (ui.cmb_cutcol); - ui.cb_repeat->setWhatsThis ("If this is set, " APPNAME " runs Intersector a second time with inverse files to cut the " - " cutter group with the input group. Both groups are cut by the intersection."); - ui.cb_edges->setWhatsThis ("Makes " APPNAME " try run Isecalc to create edgelines for the intersection."); - - LDColor inCol, cutCol; - const bool repeatInverse = ui.cb_repeat->isChecked(); - - forever - { - if (not dlg->exec()) - return; - - inCol = ui.cmb_incol->itemData (ui.cmb_incol->currentIndex()).toInt(); - cutCol = ui.cmb_cutcol->itemData (ui.cmb_cutcol->currentIndex()).toInt(); - - if (inCol == cutCol) - { - Critical ("Cannot use the same color group for both input and cutter!"); - continue; - } - - break; - } - - // Five temporary files! - // indat = input group file - // cutdat = cutter group file - // outdat = primary output - // outdat2 = inverse output - // edgesdat = edges output (isecalc) - QTemporaryFile indat, cutdat, outdat, outdat2, edgesdat; - QString inDATName, cutDATName, outDATName, outDAT2Name, edgesDATName; - - if (not MakeTempFile (indat, inDATName) or - not MakeTempFile (cutdat, cutDATName) or - not MakeTempFile (outdat, outDATName) or - not MakeTempFile (outdat2, outDAT2Name) or - not MakeTempFile (edgesdat, edgesDATName)) - { - return; - } - - QString parms = Join ( - { - (ui.cb_colorize->isChecked()) ? "-c" : "", - (ui.cb_nocondense->isChecked()) ? "-t" : "", - "-s", - ui.dsb_prescale->value() - }); - - QString argv_normal = Join ( - { - parms, - inDATName, - cutDATName, - outDATName - }); - - QString argv_inverse = Join ( - { - parms, - cutDATName, - inDATName, - outDAT2Name - }); - - WriteColorGroup (inCol, inDATName); - WriteColorGroup (cutCol, cutDATName); - - if (not RunExtProgram (Intersector, cfg::IntersectorPath, argv_normal)) - return; - - InsertOutput (outDATName, false, {inCol}); - - if (repeatInverse and RunExtProgram (Intersector, cfg::IntersectorPath, argv_inverse)) - InsertOutput (outDAT2Name, false, {cutCol}); - - if (ui.cb_edges->isChecked() and CheckExtProgramPath (Isecalc) and - RunExtProgram (Isecalc, cfg::IsecalcPath, Join ({inDATName, cutDATName, edgesDATName}))) - { - InsertOutput (edgesDATName, false, {}); - } -} - -// ============================================================================= -// -void MainWindow::slot_actionCoverer() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Coverer)) - return; - - QDialog* dlg = new QDialog; - Ui::CovererUI ui; - ui.setupUi (dlg); - MakeColorComboBox (ui.cmb_col1); - MakeColorComboBox (ui.cmb_col2); - - LDColor in1Col, in2Col; - - forever - { - if (not dlg->exec()) - return; - - in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(); - in2Col = ui.cmb_col2->itemData (ui.cmb_col2->currentIndex()).toInt(); - - if (in1Col == in2Col) - { - Critical ("Cannot use the same color group for both inputs!"); - continue; - } - - break; - } - - QTemporaryFile in1dat, in2dat, outdat; - QString in1DATName, in2DATName, outDATName; - - if (not MakeTempFile (in1dat, in1DATName) or - not MakeTempFile (in2dat, in2DATName) or - not MakeTempFile (outdat, outDATName)) - { - return; - } - - QString argv = Join ( - { - (ui.cb_oldsweep->isChecked() ? "-s" : ""), - (ui.cb_reverse->isChecked() ? "-r" : ""), - (ui.dsb_segsplit->value() != 0 ? format ("-l %1", ui.dsb_segsplit->value()) : ""), - (ui.sb_bias->value() != 0 ? format ("-s %1", ui.sb_bias->value()) : ""), - in1DATName, - in2DATName, - outDATName - }); - - WriteColorGroup (in1Col, in1DATName); - WriteColorGroup (in2Col, in2DATName); - - if (not RunExtProgram (Coverer, cfg::CovererPath, argv)) - return; - - InsertOutput (outDATName, false, {}); -} - -// ============================================================================= -// -void MainWindow::slot_actionIsecalc() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Isecalc)) - return; - - Ui::IsecalcUI ui; - QDialog* dlg = new QDialog; - ui.setupUi (dlg); - - MakeColorComboBox (ui.cmb_col1); - MakeColorComboBox (ui.cmb_col2); - - LDColor in1Col, in2Col; - - // Run the dialog and validate input - forever - { - if (not dlg->exec()) - return; - - in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(); - in2Col = ui.cmb_col2->itemData (ui.cmb_col2->currentIndex()).toInt(); - - if (in1Col == in2Col) - { - Critical ("Cannot use the same color group for both input and cutter!"); - continue; - } - - break; - } - - QTemporaryFile in1dat, in2dat, outdat; - QString in1DATName, in2DATName, outDATName; - - if (not MakeTempFile (in1dat, in1DATName) or - not MakeTempFile (in2dat, in2DATName) or - not MakeTempFile (outdat, outDATName)) - { - return; - } - - QString argv = Join ( - { - in1DATName, - in2DATName, - outDATName - }); - - WriteColorGroup (in1Col, in1DATName); - WriteColorGroup (in2Col, in2DATName); - RunExtProgram (Isecalc, cfg::IsecalcPath, argv); - InsertOutput (outDATName, false, {}); -} - -// ============================================================================= -// -void MainWindow::slot_actionEdger2() -{ - setlocale (LC_ALL, "C"); - - if (not CheckExtProgramPath (Edger2)) - return; - - QDialog* dlg = new QDialog; - Ui::Edger2Dialog ui; - ui.setupUi (dlg); - - if (not dlg->exec()) - return; - - QTemporaryFile in, out; - QString inName, outName; - - if (not MakeTempFile (in, inName) or not MakeTempFile (out, outName)) - return; - - int unmatched = ui.unmatched->currentIndex(); - - QString argv = Join ( - { - format ("-p %1", ui.precision->value()), - format ("-af %1", ui.flatAngle->value()), - format ("-ac %1", ui.condAngle->value()), - format ("-ae %1", ui.edgeAngle->value()), - ui.delLines->isChecked() ? "-de" : "", - ui.delCondLines->isChecked() ? "-dc" : "", - ui.colored->isChecked() ? "-c" : "", - ui.bfc->isChecked() ? "-b" : "", - ui.convex->isChecked() ? "-cx" : "", - ui.concave->isChecked() ? "-cv" : "", - unmatched == 0 ? "-u+" : (unmatched == 2 ? "-u-" : ""), - inName, - outName, - }); - - WriteSelection (inName); - - if (not RunExtProgram (Edger2, cfg::Edger2Path, argv)) - return; - - InsertOutput (outName, true, {}); -}
--- a/src/mainwindow.cpp Sun Aug 30 15:18:41 2015 +0300 +++ b/src/mainwindow.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -51,6 +51,7 @@ #include "ui_mainwindow.h" #include "primitives.h" #include "editmodes/abstractEditMode.h" +#include "toolsets/toolset.h" static bool g_isSelectionLocked = false; static QMap<QAction*, QKeySequence> g_defaultShortcuts; @@ -127,6 +128,40 @@ this, SLOT (circleToolSegmentsChanged())); circleToolSegmentsChanged(); // invoke it manually for initial label text + // Examine the toolsets and make a dictionary of tools + m_toolsets = Toolset::createToolsets (this); + + QStringList ignore; + for (int i = 0; i < Toolset::staticMetaObject.methodCount(); ++i) + { + QMetaMethod method = Toolset::staticMetaObject.method (i); + ignore.append (QString::fromUtf8 (method.name())); + } + + for (Toolset* toolset : m_toolsets) + { + const QMetaObject* meta = toolset->metaObject(); + + for (int i = 0; i < meta->methodCount(); ++i) + { + ToolInfo info; + info.method = meta->method (i); + info.object = toolset; + QString methodName = QString::fromUtf8 (info.method.name()); + + if (ignore.contains (methodName)) + continue; // The method was inherited from base classes + + QString actionName = "action" + methodName.left (1).toUpper() + methodName.mid (1); + QAction* action = findChild<QAction*> (actionName); + + if (action == nullptr) + print ("No action for %1::%2 (looked for %3)\n", meta->className(), methodName, actionName); + else + m_toolmap[action] = info; + } + } + for (QVariant const& toolbarname : cfg::HiddenToolbars) { QToolBar* toolbar = findChild<QToolBar*> (toolbarname.toString()); @@ -147,8 +182,19 @@ { // Get the name of the sender object and use it to compose the slot name, // then invoke this slot to call the action. - QMetaObject::invokeMethod (this, - qPrintable (format ("slot_%1", sender()->objectName())), Qt::DirectConnection); + QAction* action = qobject_cast<QAction*> (sender()); + + if (action) + { + if (m_toolmap.contains (action)) + { + const ToolInfo& info = m_toolmap[action]; + info.method.invoke (info.object, Qt::DirectConnection); + } + else + print ("No tool info for %1!\n", action->objectName()); + } + endAction(); } @@ -677,14 +723,14 @@ contextMenu->addAction (ui.actionCut); contextMenu->addAction (ui.actionCopy); contextMenu->addAction (ui.actionPaste); - contextMenu->addAction (ui.actionDelete); + contextMenu->addAction (ui.actionRemove); contextMenu->addSeparator(); contextMenu->addAction (ui.actionSetColor); if (single) contextMenu->addAction (ui.actionEditRaw); - contextMenu->addAction (ui.actionBorders); + contextMenu->addAction (ui.actionMakeBorders); contextMenu->addAction (ui.actionSetOverlay); contextMenu->addAction (ui.actionClearOverlay); @@ -1024,7 +1070,7 @@ ui.actionWireframe->setChecked (cfg::DrawWireframe); ui.actionAxes->setChecked (cfg::DrawAxes); - ui.actionBFCView->setChecked (cfg::BFCRedGreenView); + ui.actionBfcView->setChecked (cfg::BFCRedGreenView); ui.actionRandomColors->setChecked (cfg::RandomColors); ui.actionDrawAngles->setChecked (cfg::DrawAngles); ui.actionDrawSurfaces->setChecked (cfg::DrawSurfaces);
--- a/src/mainwindow.h Sun Aug 30 15:18:41 2015 +0300 +++ b/src/mainwindow.h Sun Aug 30 17:20:55 2015 +0300 @@ -23,6 +23,7 @@ #include <QListWidget> #include <QRadioButton> #include <QTreeWidget> +#include <QMetaMethod> #include "configuration.h" #include "ldObject.h" #include "colors.h" @@ -35,6 +36,7 @@ class QComboBox; class QProgressBar; struct Primitive; +class Toolset; class LDQuickColor { @@ -168,112 +170,13 @@ void ringToolHiResClicked (bool clicked); void circleToolSegmentsChanged(); void slot_action(); - void slot_actionNew(); - void slot_actionNewFile(); - void slot_actionOpen(); - void slot_actionDownloadFrom(); - void slot_actionSave(); - void slot_actionSaveAs(); - void slot_actionSaveAll(); - void slot_actionClose(); - void slot_actionCloseAll(); - void slot_actionInsertFrom(); - void slot_actionExportTo(); - void slot_actionSettings(); - void slot_actionSetLDrawPath(); - void slot_actionScanPrimitives(); - void slot_actionExit(); - void slot_actionResetView(); - void slot_actionAxes(); - void slot_actionWireframe(); - void slot_actionBFCView(); - void slot_actionSetOverlay(); - void slot_actionClearOverlay(); - void slot_actionScreenshot(); - void slot_actionInsertRaw(); - void slot_actionNewSubfile(); - void slot_actionNewLine(); - void slot_actionNewTriangle(); - void slot_actionNewQuad(); - void slot_actionNewCLine(); - void slot_actionNewComment(); - void slot_actionNewBFC(); - void slot_actionUndo(); - void slot_actionRedo(); - void slot_actionCut(); - void slot_actionCopy(); - void slot_actionPaste(); - void slot_actionDelete(); - void slot_actionSelectAll(); - void slot_actionSelectByColor(); - void slot_actionSelectByType(); - void slot_actionModeDraw(); - void slot_actionModeSelect(); - void slot_actionModeRectangle(); - void slot_actionModeCircle(); - void slot_actionModeMagicWand(); - void slot_actionModeLinePath(); - void slot_actionSetDrawDepth(); - void slot_actionSetColor(); - void slot_actionAutocolor(); - void slot_actionUncolor(); - void slot_actionInline(); - void slot_actionInlineDeep(); - void slot_actionInvert(); - void slot_actionMakePrimitive(); - void slot_actionSplitQuads(); - void slot_actionEditRaw(); - void slot_actionBorders(); - void slot_actionRoundCoordinates(); - void slot_actionVisibilityHide(); - void slot_actionVisibilityReveal(); - void slot_actionVisibilityToggle(); - void slot_actionReplaceCoords(); - void slot_actionFlip(); - void slot_actionDemote(); - void slot_actionYtruder(); - void slot_actionRectifier(); - void slot_actionIntersector(); - void slot_actionIsecalc(); - void slot_actionCoverer(); - void slot_actionEdger2(); - void slot_actionHelp(); - void slot_actionAbout(); - void slot_actionAboutQt(); - void slot_actionGridCoarse(); - void slot_actionGridMedium(); - void slot_actionGridFine(); - void slot_actionEdit(); - void slot_actionMoveUp(); - void slot_actionMoveDown(); - void slot_actionMoveXNeg(); - void slot_actionMoveXPos(); - void slot_actionMoveYNeg(); - void slot_actionMoveYPos(); - void slot_actionMoveZNeg(); - void slot_actionMoveZPos(); - void slot_actionRotateXNeg(); - void slot_actionRotateXPos(); - void slot_actionRotateYNeg(); - void slot_actionRotateYPos(); - void slot_actionRotateZNeg(); - void slot_actionRotateZPos(); - void slot_actionRotationPoint(); - void slot_actionAddHistoryLine(); - void slot_actionJumpTo(); - void slot_actionSubfileSelection(); - void slot_actionDrawAngles(); - void slot_actionRandomColors(); - void slot_actionOpenSubfiles(); - void slot_actionSplitLines(); - void slot_actionDrawSurfaces(); - void slot_actionDrawEdgeLines(); - void slot_actionDrawConditionalLines(); protected: void closeEvent (QCloseEvent* ev); private: + struct ToolInfo { QMetaMethod method; Toolset* object; }; + GLRenderer* m_renderer; LDObjectList m_sel; QList<LDQuickColor> m_quickColors; @@ -283,6 +186,8 @@ class Ui_MainWindow& ui; QTabBar* m_tabs; bool m_updatingTabs; + QVector<Toolset*> m_toolsets; + QMap<QAction*, ToolInfo> m_toolmap; private slots: void slot_selectionChanged();
--- a/src/mainwindow.ui Sun Aug 30 15:18:41 2015 +0300 +++ b/src/mainwindow.ui Sun Aug 30 17:20:55 2015 +0300 @@ -75,8 +75,8 @@ <rect> <x>0</x> <y>0</y> - <width>218</width> - <height>124</height> + <width>234</width> + <height>402</height> </rect> </property> <attribute name="label"> @@ -157,8 +157,8 @@ <rect> <x>0</x> <y>0</y> - <width>96</width> - <height>86</height> + <width>234</width> + <height>402</height> </rect> </property> <attribute name="label"> @@ -210,7 +210,7 @@ <normaloff>:/icons/open-recent.png</normaloff>:/icons/open-recent.png</iconset> </property> </widget> - <addaction name="actionNew"/> + <addaction name="actionNewPart"/> <addaction name="actionNewFile"/> <addaction name="actionOpen"/> <addaction name="menuOpenRecent"/> @@ -239,7 +239,7 @@ <addaction name="actionResetView"/> <addaction name="actionAxes"/> <addaction name="actionWireframe"/> - <addaction name="actionBFCView"/> + <addaction name="actionBfcView"/> <addaction name="actionDrawAngles"/> <addaction name="actionRandomColors"/> <addaction name="separator"/> @@ -261,8 +261,8 @@ <addaction name="actionNewSubfile"/> <addaction name="actionNewLine"/> <addaction name="actionNewTriangle"/> - <addaction name="actionNewQuad"/> - <addaction name="actionNewCLine"/> + <addaction name="actionNewQuadrilateral"/> + <addaction name="actionNewConditionalLine"/> <addaction name="actionNewComment"/> <addaction name="actionNewBFC"/> </widget> @@ -278,7 +278,7 @@ <addaction name="actionCut"/> <addaction name="actionCopy"/> <addaction name="actionPaste"/> - <addaction name="actionDelete"/> + <addaction name="actionRemove"/> <addaction name="separator"/> <addaction name="actionSelectAll"/> <addaction name="actionSelectByColor"/> @@ -304,7 +304,7 @@ <addaction name="actionUncolor"/> <addaction name="separator"/> <addaction name="actionInvert"/> - <addaction name="actionInline"/> + <addaction name="actionInlineShallow"/> <addaction name="actionInlineDeep"/> <addaction name="actionMakePrimitive"/> <addaction name="separator"/> @@ -312,9 +312,9 @@ <addaction name="separator"/> <addaction name="actionSplitQuads"/> <addaction name="actionEditRaw"/> - <addaction name="actionBorders"/> + <addaction name="actionMakeBorders"/> <addaction name="actionRoundCoordinates"/> - <addaction name="actionReplaceCoords"/> + <addaction name="actionReplaceCoordinates"/> <addaction name="actionFlip"/> <addaction name="actionDemote"/> <addaction name="actionOpenSubfiles"/> @@ -390,7 +390,7 @@ <addaction name="menuRotate"/> <addaction name="menuObject_List"/> <addaction name="separator"/> - <addaction name="actionRotationPoint"/> + <addaction name="actionConfigureRotationPoint"/> </widget> <addaction name="menuFile"/> <addaction name="menuView"/> @@ -412,7 +412,7 @@ <attribute name="toolBarBreak"> <bool>false</bool> </attribute> - <addaction name="actionNew"/> + <addaction name="actionNewPart"/> <addaction name="actionNewFile"/> <addaction name="actionOpen"/> <addaction name="actionSave"/> @@ -431,8 +431,8 @@ <addaction name="actionNewSubfile"/> <addaction name="actionNewLine"/> <addaction name="actionNewTriangle"/> - <addaction name="actionNewQuad"/> - <addaction name="actionNewCLine"/> + <addaction name="actionNewQuadrilateral"/> + <addaction name="actionNewConditionalLine"/> <addaction name="actionNewComment"/> <addaction name="actionNewBFC"/> </widget> @@ -451,7 +451,7 @@ <addaction name="actionCut"/> <addaction name="actionCopy"/> <addaction name="actionPaste"/> - <addaction name="actionDelete"/> + <addaction name="actionRemove"/> </widget> <widget class="QToolBar" name="toolBarSelect"> <property name="windowTitle"> @@ -493,7 +493,7 @@ </attribute> <addaction name="actionAxes"/> <addaction name="actionWireframe"/> - <addaction name="actionBFCView"/> + <addaction name="actionBfcView"/> <addaction name="actionRandomColors"/> <addaction name="actionDrawAngles"/> </widget> @@ -511,10 +511,10 @@ <addaction name="actionAutocolor"/> <addaction name="actionInvert"/> <addaction name="actionSplitQuads"/> - <addaction name="actionInline"/> + <addaction name="actionInlineShallow"/> <addaction name="actionEditRaw"/> - <addaction name="actionBorders"/> - <addaction name="actionReplaceCoords"/> + <addaction name="actionMakeBorders"/> + <addaction name="actionReplaceCoordinates"/> <addaction name="actionRoundCoordinates"/> <addaction name="actionVisibilityHide"/> <addaction name="actionVisibilityToggle"/> @@ -565,7 +565,7 @@ <addaction name="actionCoverer"/> <addaction name="actionEdger2"/> </widget> - <action name="actionNew"> + <action name="actionNewPart"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/brick.png</normaloff>:/icons/brick.png</iconset> @@ -729,7 +729,7 @@ <string>&Wireframe</string> </property> </action> - <action name="actionBFCView"> + <action name="actionBfcView"> <property name="checkable"> <bool>true</bool> </property> @@ -803,7 +803,7 @@ <string>Ne&w Triangle</string> </property> </action> - <action name="actionNewQuad"> + <action name="actionNewQuadrilateral"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-quad.png</normaloff>:/icons/add-quad.png</iconset> @@ -812,7 +812,7 @@ <string>New &Quadrilateral</string> </property> </action> - <action name="actionNewCLine"> + <action name="actionNewConditionalLine"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-condline.png</normaloff>:/icons/add-condline.png</iconset> @@ -917,7 +917,7 @@ <string>Ctrl+V</string> </property> </action> - <action name="actionDelete"> + <action name="actionRemove"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> @@ -1045,7 +1045,7 @@ <string>Reduce colors of everything selected to main and edge colors</string> </property> </action> - <action name="actionInline"> + <action name="actionInlineShallow"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/inline.png</normaloff>:/icons/inline.png</iconset> @@ -1120,7 +1120,7 @@ <string>Edit the LDraw code of this object.</string> </property> </action> - <action name="actionBorders"> + <action name="actionMakeBorders"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/make-borders.png</normaloff>:/icons/make-borders.png</iconset> @@ -1156,7 +1156,7 @@ <string>Toggles visibility/hiding on objects.</string> </property> </action> - <action name="actionReplaceCoords"> + <action name="actionReplaceCoordinates"> <property name="icon"> <iconset resource="../ldforge.qrc"> <normaloff>:/icons/replace-coords.png</normaloff>:/icons/replace-coords.png</iconset> @@ -1473,7 +1473,7 @@ <string>Ctrl+Up</string> </property> </action> - <action name="actionRotationPoint"> + <action name="actionConfigureRotationPoint"> <property name="text"> <string>&Set Rotation Point</string> </property>
--- a/src/partDownloader.cpp Sun Aug 30 15:18:41 2015 +0300 +++ b/src/partDownloader.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -582,10 +582,3 @@ { networkReply()->abort(); } - -// ============================================================================= -// -void MainWindow::slot_actionDownloadFrom() -{ - PartDownloader::staticBegin(); -}
--- a/src/primitives.cpp Sun Aug 30 15:18:41 2015 +0300 +++ b/src/primitives.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -689,27 +689,3 @@ if (on and ui->sb_segs->value() == LowResolution) ui->sb_segs->setValue (HighResolution); } - -// ============================================================================= -// -void MainWindow::slot_actionMakePrimitive() -{ - PrimitivePrompt* dlg = new PrimitivePrompt (g_win); - - if (not dlg->exec()) - return; - - int segs = dlg->ui->sb_segs->value(); - int divs = dlg->ui->cb_hires->isChecked() ? HighResolution : LowResolution; - int num = dlg->ui->sb_ringnum->value(); - PrimitiveType type = - dlg->ui->rb_circle->isChecked() ? Circle : - dlg->ui->rb_cylinder->isChecked() ? Cylinder : - dlg->ui->rb_disc->isChecked() ? Disc : - dlg->ui->rb_ndisc->isChecked() ? DiscNeg : - dlg->ui->rb_ring->isChecked() ? Ring : Cone; - - LDDocument* f = GeneratePrimitive (type, segs, divs, num); - f->setImplicit (false); - g_win->save (f, false); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/algorithmtoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,586 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <limits> +#include <QBoxLayout> +#include <QCheckBox> +#include <QDir> +#include <QInputDialog> +#include <QSpinBox> +#include "../mainwindow.h" +#include "../main.h" +#include "../ldDocument.h" +#include "../miscallenous.h" +#include "../radioGroup.h" +#include "../glRenderer.h" +#include "../dialogs.h" +#include "../colors.h" +#include "../ldObjectMath.h" +#include "../ldobjectiterator.h" +#include "ui_replcoords.h" +#include "ui_editraw.h" +#include "ui_flip.h" +#include "ui_addhistoryline.h" +#include "algorithmtoolset.h" + +EXTERN_CFGENTRY (String, DefaultUser) + +CFGENTRY (Int, RoundPosition, 3) +CFGENTRY (Int, RoundMatrix, 4) +CFGENTRY (Int, SplitLinesSegments, 5) +EXTERN_CFGENTRY (String, DefaultName) +EXTERN_CFGENTRY (String, DefaultUser) +EXTERN_CFGENTRY (Bool, UseCALicense) + +AlgorithmToolset::AlgorithmToolset (MainWindow* parent) : + Toolset (parent) +{ +} + +void AlgorithmToolset::splitQuads() +{ + int num = 0; + + for (LDObjectIterator<LDQuad> it (Selection()); it.isValid(); ++it) + { + // Find the index of this quad + int index = it->lineNumber(); + + if (index == -1) + return; + + QList<LDTriangle*> triangles = it->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); +} + +void AlgorithmToolset::editRaw() +{ + if (Selection().size() != 1) + return; + + LDObject* 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 (static_cast<LDError*> (obj)->reason()); + else + { + ui.errorDescription->hide(); + ui.errorIcon->hide(); + } + + if (dlg->exec() == QDialog::Rejected) + return; + + // Reinterpret it from the text of the input field + LDObject* newobj = ParseLine (ui.code->text()); + obj->replace (newobj); +} + +void AlgorithmToolset::makeBorders() +{ + LDObjectList objs = Selection(); + int num = 0; + + for (LDObject* obj : objs) + { + const LDObjectType type = obj->type(); + + if (type != OBJ_Quad and type != OBJ_Triangle) + continue; + + LDLine* lines[4]; + + if (type == OBJ_Quad) + { + LDQuad* quad = static_cast<LDQuad*> (obj); + lines[0] = LDSpawn<LDLine> (quad->vertex (0), quad->vertex (1)); + lines[1] = LDSpawn<LDLine> (quad->vertex (1), quad->vertex (2)); + lines[2] = LDSpawn<LDLine> (quad->vertex (2), quad->vertex (3)); + lines[3] = LDSpawn<LDLine> (quad->vertex (3), quad->vertex (0)); + } + else + { + LDTriangle* tri = static_cast<LDTriangle*> (obj); + lines[0] = LDSpawn<LDLine> (tri->vertex (0), tri->vertex (1)); + lines[1] = LDSpawn<LDLine> (tri->vertex (1), tri->vertex (2)); + lines[2] = LDSpawn<LDLine> (tri->vertex (2), tri->vertex (0)); + lines[3] = nullptr; + } + + 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; + } + } + + print (tr ("Added %1 border lines"), num); +} + +void AlgorithmToolset::roundCoordinates() +{ + setlocale (LC_ALL, "C"); + int num = 0; + + for (LDObject* obj : Selection()) + { + LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj); + + 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); + m_window->refreshObjectList(); +} + +void AlgorithmToolset::replaceCoordinates() +{ + QDialog* dlg = new QDialog (m_window); + 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<Axis> sel; + int num = 0; + + if (ui.x->isChecked()) sel << X; + if (ui.y->isChecked()) sel << Y; + if (ui.z->isChecked()) sel << Z; + + for (LDObject* 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); +} + +void AlgorithmToolset::flip() +{ + QDialog* dlg = new QDialog; + Ui::FlipUI ui; + ui.setupUi (dlg); + + if (not dlg->exec()) + return; + + QList<Axis> sel; + + if (ui.x->isChecked()) sel << X; + if (ui.y->isChecked()) sel << Y; + if (ui.z->isChecked()) sel << Z; + + for (LDObject* 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); + } + } +} + +void AlgorithmToolset::demote() +{ + int num = 0; + + for (LDObjectIterator<LDCondLine> it (Selection()); it.isValid(); ++it) + { + it->toEdgeLine(); + ++num; + } + + print (tr ("Converted %1 conditional lines"), num); +} + +bool AlgorithmToolset::isColorUsed (LDColor color) const +{ + for (LDObject* obj : CurrentDocument()->objects()) + { + if (obj->isColored() and obj->color() == color) + return true; + } + + return false; +} + +void AlgorithmToolset::autocolor() +{ + LDColor color; + + for (color = 0; color.isLDConfigColor(); ++color) + { + if (color.isValid() and not isColorUsed (color)) + break; + } + + if (not color.isLDConfigColor()) + { + print (tr ("Cannot auto-color: all colors are in use!")); + return; + } + + for (LDObject* obj : Selection()) + { + if (not obj->isColored()) + continue; + + obj->setColor (color); + } + + print (tr ("Auto-colored: new color is [%1] %2"), color.index(), color.name()); +} + +void AlgorithmToolset::addHistoryLine() +{ + LDObject* obj; + bool ishistory = false; + bool 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 + LDComment* comment = new LDComment (format ("!HISTORY %1 [%2] %3", + ui->m_date->date().toString ("yyyy-MM-dd"), + ui->m_username->text(), + ui->m_comment->text())); + + // Find a spot to place the new comment + for (obj = CurrentDocument()->getObject (0); + obj and obj->next() and not obj->next()->isScemantic(); + obj = obj->next()) + { + LDComment* comment = dynamic_cast<LDComment*> (obj); + + if (comment and comment->text().startsWith ("!HISTORY ")) + ishistory = true; + + if (prevIsHistory and not ishistory) + break; // Last line was history, this isn't, thus insert the new history line here. + + prevIsHistory = ishistory; + } + + int idx = obj ? obj->lineNumber() : 0; + CurrentDocument()->insertObj (idx++, comment); + + // 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, new LDEmpty); + + m_window->buildObjList(); + delete ui; +} + +void AlgorithmToolset::splitLines() +{ + bool ok; + int segments = QInputDialog::getInt (m_window, APPNAME, "Amount of segments:", cfg::SplitLinesSegments, 0, + std::numeric_limits<int>::max(), 1, &ok); + + if (not ok) + return; + + cfg::SplitLinesSegments = segments; + + for (LDObject* obj : Selection()) + { + if (not isOneOf (obj->type(), OBJ_Line, OBJ_CondLine)) + continue; + + QVector<LDObject*> newsegs; + + for (int i = 0; i < segments; ++i) + { + LDObject* 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<LDLine> (v0, v1); + else + segment = LDSpawn<LDCondLine> (v0, v1, obj->vertex (2), obj->vertex (3)); + + newsegs << segment; + } + + int ln = obj->lineNumber(); + + for (LDObject* seg : newsegs) + CurrentDocument()->insertObj (ln++, seg); + + obj->destroy(); + } + + m_window->buildObjList(); + m_window->refresh(); +} + +void AlgorithmToolset::subfileSelection() +{ + if (Selection().size() == 0) + return; + + QString parentpath (CurrentDocument()->fullPath()); + + // BFC type of the new subfile - it shall inherit the BFC type of the parent document + BFCStatement bfctype (BFCStatement::NoCertify); + + // Dirname of the new subfile + QString subdirname (Dirname (parentpath)); + + // Title of the new subfile + QString subtitle; + + // Comment containing the title of the parent document + LDComment* titleobj = dynamic_cast<LDComment*> (CurrentDocument()->getObject (0)); + + // License text for the subfile + QString license (PreferredLicenseText()); + + // LDraw code body of the new subfile (i.e. code of the selection) + QStringList code; + + // Full path of the subfile to be + QString fullsubname; + + // Where to insert the subfile reference? + int refidx (Selection()[0]->lineNumber()); + + // Determine title of subfile + if (titleobj != null) + subtitle = "~" + titleobj->text(); + else + subtitle = "~subfile"; + + // Remove duplicate tildes + while (subtitle.startsWith ("~~")) + subtitle.remove (0, 1); + + // If this the parent document isn't already in s/, we need to stuff it into + // a subdirectory named s/. Ensure it exists! + QString topdirname = Basename (Dirname (CurrentDocument()->fullPath())); + + if (topdirname != "s") + { + QString desiredPath = subdirname + "/s"; + QString title = tr ("Create subfile directory?"); + QString text = format (tr ("The directory <b>%1</b> is suggested for " + "subfiles. This directory does not exist, create it?"), desiredPath); + + if (QDir (desiredPath).exists() or Confirm (title, text)) + { + subdirname = desiredPath; + QDir().mkpath (subdirname); + } + else + return; + } + + // Determine the body of the name of the subfile + if (not parentpath.isEmpty()) + { + // Chop existing '.dat' suffix + if (parentpath.endsWith (".dat")) + parentpath.chop (4); + + // Remove the s?? suffix if it's there, otherwise we'll get filenames + // like s01s01.dat when subfiling subfiles. + QRegExp subfilesuffix ("s[0-9][0-9]$"); + if (subfilesuffix.indexIn (parentpath) != -1) + parentpath.chop (subfilesuffix.matchedLength()); + + int subidx = 1; + QString digits; + + // Now find the appropriate filename. Increase the number of the subfile + // until we find a name which isn't already taken. + do + { + digits.setNum (subidx++); + + // pad it with a zero + if (digits.length() == 1) + digits.prepend ("0"); + + fullsubname = subdirname + "/" + Basename (parentpath) + "s" + digits + ".dat"; + } while (FindDocument ("s\\" + Basename (fullsubname)) != null or QFile (fullsubname).exists()); + } + + // Determine the BFC winding type used in the main document - it is to + // be carried over to the subfile. + for (LDObjectIterator<LDBFC> it (CurrentDocument()); it.isValid(); ++it) + { + if (isOneOf (it->statement(), BFCStatement::CertifyCCW, BFCStatement::CertifyCW, BFCStatement::NoCertify)) + { + bfctype = it->statement(); + break; + } + } + + // Get the body of the document in LDraw code + for (LDObject* obj : Selection()) + code << obj->asText(); + + // Create the new subfile document + LDDocument* doc = LDDocument::createNew(); + doc->setImplicit (false); + doc->setFullPath (fullsubname); + doc->setName (LDDocument::shortenName (fullsubname)); + + LDObjectList objs; + objs << LDSpawn<LDComment> (subtitle); + objs << LDSpawn<LDComment> ("Name: "); // This gets filled in when the subfile is saved + objs << LDSpawn<LDComment> (format ("Author: %1 [%2]", cfg::DefaultName, cfg::DefaultUser)); + objs << LDSpawn<LDComment> ("!LDRAW_ORG Unofficial_Subpart"); + + if (not license.isEmpty()) + objs << LDSpawn<LDComment> (license); + + objs << LDSpawn<LDEmpty>(); + objs << LDSpawn<LDBFC> (bfctype); + objs << LDSpawn<LDEmpty>(); + + doc->addObjects (objs); + + // Add the actual subfile code to the new document + for (QString line : code) + { + LDObject* obj = ParseLine (line); + doc->addObject (obj); + } + + // Try save it + if (m_window->save (doc, true)) + { + // Save was successful. Delete the original selection now from the + // main document. + for (LDObject* obj : Selection()) + obj->destroy(); + + // Add a reference to the new subfile to where the selection was + LDSubfile* ref = LDSpawn<LDSubfile>(); + ref->setColor (MainColor); + ref->setFileInfo (doc); + ref->setPosition (Origin); + ref->setTransform (IdentityMatrix); + CurrentDocument()->insertObj (refidx, ref); + + // Refresh stuff + m_window->updateDocumentList(); + m_window->doFullRefresh(); + } + else + { + // Failed to save. + doc->dismiss(); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/algorithmtoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,42 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class AlgorithmToolset : public Toolset +{ + Q_OBJECT +public: + explicit AlgorithmToolset (MainWindow* parent); + + Q_INVOKABLE void addHistoryLine(); + Q_INVOKABLE void autocolor(); + Q_INVOKABLE void demote(); + Q_INVOKABLE void editRaw(); + Q_INVOKABLE void flip(); + Q_INVOKABLE void makeBorders(); + Q_INVOKABLE void replaceCoordinates(); + Q_INVOKABLE void roundCoordinates(); + Q_INVOKABLE void splitLines(); + Q_INVOKABLE void splitQuads(); + Q_INVOKABLE void subfileSelection(); + +private: + bool isColorUsed (class LDColor color) const; +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/basictoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,299 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <QApplication> +#include <QClipboard> +#include <QDialog> +#include <QDialogButtonBox> +#include <QTextEdit> +#include <QVBoxLayout> +#include "../addObjectDialog.h" +#include "../glRenderer.h" +#include "../ldDocument.h" +#include "../ldObject.h" +#include "../ldobjectiterator.h" +#include "../mainwindow.h" +#include "../dialogs/colorselector.h" +#include "basictoolset.h" + +BasicToolset::BasicToolset (MainWindow *parent) : + Toolset (parent) {} + +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 (LDObject* obj : objs) + { + if (not data.isEmpty()) + data += "\n"; + + data += obj->asText(); + ++num; + } + + qApp->clipboard()->setText (data); + return num; +} + +void BasicToolset::cut() +{ + int num = CopyToClipboard(); + m_window->deleteSelection(); + print (tr ("%1 objects cut"), num); +} + +void BasicToolset::copy() +{ + int num = CopyToClipboard(); + print (tr ("%1 objects copied"), num); +} + +void BasicToolset::paste() +{ + const QString clipboardText = qApp->clipboard()->text(); + int idx = m_window->getInsertionPoint(); + CurrentDocument()->clearSelection(); + int num = 0; + + for (QString line : clipboardText.split ("\n")) + { + LDObject* pasted = ParseLine (line); + CurrentDocument()->insertObj (idx++, pasted); + pasted->select(); + ++num; + } + + print (tr ("%1 objects pasted"), num); + m_window->refresh(); + m_window->scrollToSelection(); +} + +void BasicToolset::remove() +{ + int num = m_window->deleteSelection(); + print (tr ("%1 objects deleted"), num); +} + +void BasicToolset::doInline (bool deep) +{ + for (LDObjectIterator<LDSubfile> it (Selection()); it.isValid(); ++it) + { + // Get the index of the subfile so we know where to insert the + // inlined contents. + int idx = it->lineNumber(); + + if (idx != -1) + { + LDObjectList objs = it->inlineContents (deep, false); + + // Merge in the inlined objects + for (LDObject* inlineobj : objs) + { + QString line = inlineobj->asText(); + inlineobj->destroy(); + LDObject* newobj = ParseLine (line); + CurrentDocument()->insertObj (idx++, newobj); + newobj->select(); + } + + // Delete the subfile now as it's been inlined. + it->destroy(); + } + } +} + +void BasicToolset::inlineShallow() +{ + doInline (false); +} + +void BasicToolset::inlineDeep() +{ + doInline (true); +} + +void BasicToolset::undo() +{ + CurrentDocument()->undo(); +} + +void BasicToolset::redo() +{ + CurrentDocument()->redo(); +} + +void BasicToolset::uncolor() +{ + int num = 0; + + for (LDObject* obj : Selection()) + { + if (not obj->isColored()) + continue; + + obj->setColor (obj->defaultColor()); + num++; + } + + print (tr ("%1 objects uncolored"), num); +} + +void BasicToolset::insertRaw() +{ + int idx = m_window->getInsertionPoint(); + + QDialog* const dlg = new QDialog; + QVBoxLayout* const layout = new QVBoxLayout; + QTextEdit* const inputbox = new QTextEdit; + QDialogButtonBox* const buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + layout->addWidget (inputbox); + layout->addWidget (buttons); + dlg->setLayout (layout); + dlg->setWindowTitle (APPNAME " - Insert Raw"); + dlg->connect (buttons, SIGNAL (accepted()), dlg, SLOT (accept())); + dlg->connect (buttons, SIGNAL (rejected()), dlg, SLOT (reject())); + + if (dlg->exec() == QDialog::Rejected) + return; + + CurrentDocument()->clearSelection(); + + for (QString line : QString (inputbox->toPlainText()).split ("\n")) + { + LDObject* obj = ParseLine (line); + + CurrentDocument()->insertObj (idx, obj); + obj->select(); + idx++; + } + + m_window->refresh(); + m_window->scrollToSelection(); +} + +void BasicToolset::setColor() +{ + 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 = m_window->getSelectedColor(); + + // Show the dialog to the user now and ask for a color. + if (ColorSelector::selectColor (color, defaultcol, m_window)) + { + for (LDObject* obj : objs) + { + if (obj->isColored()) + obj->setColor (color); + } + } +} + +void BasicToolset::invert() +{ + for (LDObject* obj : Selection()) + obj->invert(); +} + +void BasicToolset::newSubfile() +{ + AddObjectDialog::staticDialog (OBJ_Subfile, nullptr); +} + +void BasicToolset::newLine() +{ + AddObjectDialog::staticDialog (OBJ_Line, nullptr); +} + +void BasicToolset::newTriangle() +{ + AddObjectDialog::staticDialog (OBJ_Triangle, nullptr); +} + +void BasicToolset::newQuadrilateral() +{ + AddObjectDialog::staticDialog (OBJ_Quad, nullptr); +} + +void BasicToolset::newConditionalLine() +{ + AddObjectDialog::staticDialog (OBJ_CondLine, nullptr); +} + +void BasicToolset::newComment() +{ + AddObjectDialog::staticDialog (OBJ_Comment, nullptr); +} + +void BasicToolset::newBFC() +{ + AddObjectDialog::staticDialog (OBJ_BFC, nullptr); +} + +void BasicToolset::edit() +{ + if (Selection().size() != 1) + return; + + LDObject* obj = Selection().first(); + AddObjectDialog::staticDialog (obj->type(), obj); +} + +void BasicToolset::modeSelect() +{ + m_window->R()->setEditMode (EditModeType::Select); +} + +void BasicToolset::modeDraw() +{ + m_window->R()->setEditMode (EditModeType::Draw); +} + +void BasicToolset::modeRectangle() +{ + m_window->R()->setEditMode (EditModeType::Rectangle); +} + +void BasicToolset::modeCircle() +{ + m_window->R()->setEditMode (EditModeType::Circle); +} + +void BasicToolset::modeMagicWand() +{ + m_window->R()->setEditMode (EditModeType::MagicWand); +} + +void BasicToolset::modeLinePath() +{ + m_window->R()->setEditMode (EditModeType::LinePath); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/basictoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,58 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class BasicToolset : public Toolset +{ + Q_OBJECT + +public: + BasicToolset (MainWindow *parent); + + Q_INVOKABLE void copy(); + Q_INVOKABLE void cut(); + Q_INVOKABLE void edit(); + Q_INVOKABLE void inlineDeep(); + Q_INVOKABLE void inlineShallow(); + Q_INVOKABLE void insertRaw(); + Q_INVOKABLE void invert(); + Q_INVOKABLE void modeCircle(); + Q_INVOKABLE void modeDraw(); + Q_INVOKABLE void modeLinePath(); + Q_INVOKABLE void modeMagicWand(); + Q_INVOKABLE void modeRectangle(); + Q_INVOKABLE void modeSelect(); + Q_INVOKABLE void newBFC(); + Q_INVOKABLE void newComment(); + Q_INVOKABLE void newConditionalLine(); + Q_INVOKABLE void newLine(); + Q_INVOKABLE void newQuadrilateral(); + Q_INVOKABLE void newSubfile(); + Q_INVOKABLE void newTriangle(); + Q_INVOKABLE void paste(); + Q_INVOKABLE void redo(); + Q_INVOKABLE void remove(); + Q_INVOKABLE void setColor(); + Q_INVOKABLE void uncolor(); + Q_INVOKABLE void undo(); + +private: + void doInline (bool deep); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/extprogramtoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,725 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <QProcess> +#include <QTemporaryFile> +#include <QDialog> +#include <QDialogButtonBox> +#include <QSpinBox> +#include <QCheckBox> +#include <QComboBox> +#include <QGridLayout> +#include <QFileInfo> +#include "../main.h" +#include "../configuration.h" +#include "../miscallenous.h" +#include "../mainwindow.h" +#include "../ldDocument.h" +#include "../radioGroup.h" +#include "../editHistory.h" +#include "../dialogs.h" +#include "extprogramtoolset.h" +#include "ui_ytruder.h" +#include "ui_intersector.h" +#include "ui_rectifier.h" +#include "ui_coverer.h" +#include "ui_isecalc.h" +#include "ui_edger2.h" + +enum ExtProgramType +{ + Isecalc, + Intersector, + Coverer, + Ytruder, + Rectifier, + Edger2, +}; + +// ============================================================================= +// +CFGENTRY (String, IsecalcPath, "") +CFGENTRY (String, IntersectorPath, "") +CFGENTRY (String, CovererPath, "") +CFGENTRY (String, YtruderPath, "") +CFGENTRY (String, RectifierPath, "") +CFGENTRY (String, Edger2Path, "") + +QString* const g_extProgPaths[] = +{ + &cfg::IsecalcPath, + &cfg::IntersectorPath, + &cfg::CovererPath, + &cfg::YtruderPath, + &cfg::RectifierPath, + &cfg::Edger2Path, +}; + +CFGENTRY (Bool, IsecalcUsesWine, false) +CFGENTRY (Bool, IntersectorUsesWine, false) +CFGENTRY (Bool, CovererUsesWine, false) +CFGENTRY (Bool, YtruderUsesWine, false) +CFGENTRY (Bool, RectifierUsesWine, false) +CFGENTRY (Bool, Edger2UsesWine, false) + +bool* const g_extProgWine[] = +{ + &cfg::IsecalcUsesWine, + &cfg::IntersectorUsesWine, + &cfg::CovererUsesWine, + &cfg::YtruderUsesWine, + &cfg::RectifierUsesWine, + &cfg::Edger2UsesWine, +}; + +const char* g_extProgNames[] = +{ + "Isecalc", + "Intersector", + "Coverer", + "Ytruder", + "Rectifier", + "Edger2" +}; + +ExtProgramToolset::ExtProgramToolset (MainWindow* parent) : + Toolset (parent) {} + +// ============================================================================= +// +static bool MakeTempFile (QTemporaryFile& tmp, QString& fname) +{ + if (not tmp.open()) + return false; + + fname = tmp.fileName(); + tmp.close(); + return true; +} + +// ============================================================================= +// +static bool CheckExtProgramPath (ExtProgramType program) +{ + QString& path = *g_extProgPaths[program]; + + if (not path.isEmpty()) + return true; + + ExtProgPathPrompt* dlg = new ExtProgPathPrompt (g_extProgNames[program]); + + if (dlg->exec() and not dlg->getPath().isEmpty()) + { + path = dlg->getPath(); + return true; + } + + return false; +} + +// ============================================================================= +// +static QString ProcessExtProgError (ExtProgramType prog, QProcess& proc) +{ + switch (proc.error()) + { + case QProcess::FailedToStart: + { + QString winemessage; + +#ifndef _WIN32 + if (*g_extProgWine[prog]) + winemessage = "make sure Wine is installed and "; +#else + Q_UNUSED (prog); +#endif + + return format ("Program failed to start, %1check your permissions", winemessage); + } break; + + case QProcess::Crashed: + return "Crashed."; + + case QProcess::WriteError: + case QProcess::ReadError: + return "I/O error."; + + case QProcess::UnknownError: + return "Unknown error"; + + case QProcess::Timedout: + return "Timed out (30 seconds)"; + } + + return ""; +} + +// ============================================================================= +// +static void WriteObjects (const LDObjectList& objects, QFile& f) +{ + for (LDObject* obj : objects) + { + if (obj->type() == OBJ_Subfile) + { + LDSubfile* ref = static_cast<LDSubfile*> (obj); + LDObjectList objs = ref->inlineContents (true, false); + + WriteObjects (objs, f); + + for (LDObject* obj : objs) + obj->destroy(); + } + else + f.write ((obj->asText() + "\r\n").toUtf8()); + } +} + +// ============================================================================= +// +static void WriteObjects (const LDObjectList& objects, QString fname) +{ + // Write the input file + QFile f (fname); + + if (not f.open (QIODevice::WriteOnly | QIODevice::Text)) + { + Critical (format ("Couldn't open temporary file %1 for writing: %2\n", fname, f.errorString())); + return; + } + + WriteObjects (objects, f); + f.close(); + +#ifdef DEBUG + QFile::copy (fname, "debug_lastInput"); +#endif +} + +// ============================================================================= +// +void WriteSelection (QString fname) +{ + WriteObjects (Selection(), fname); +} + +// ============================================================================= +// +void WriteColorGroup (LDColor color, QString fname) +{ + LDObjectList objects; + + for (LDObject* obj : CurrentDocument()->objects()) + { + if (not obj->isColored() or obj->color() != color) + continue; + + objects << obj; + } + + WriteObjects (objects, fname); +} + +// ============================================================================= +// +bool RunExtProgram (ExtProgramType prog, QString path, QString argvstr) +{ + QTemporaryFile input; + QStringList argv = argvstr.split (" ", QString::SkipEmptyParts); + +#ifndef _WIN32 + if (*g_extProgWine[prog]) + { + argv.insert (0, path); + path = "wine"; + } +#endif // _WIN32 + + print ("Running command: %1 %2\n", path, argv.join (" ")); + + if (not input.open()) + return false; + + QProcess proc; + + // Begin! + proc.setStandardInputFile (input.fileName()); + proc.start (path, argv); + + if (not proc.waitForStarted()) + { + Critical (format ("Couldn't start %1: %2\n", g_extProgNames[prog], ProcessExtProgError (prog, proc))); + return false; + } + + // Write an enter, the utility tools all expect one + input.write ("\n"); + + // Wait while it runs + proc.waitForFinished(); + + QString err = ""; + + if (proc.exitStatus() != QProcess::NormalExit) + err = ProcessExtProgError (prog, proc); + + // Check the return code + if (proc.exitCode() != 0) + err = format ("Program exited abnormally (return code %1).", proc.exitCode()); + + if (not err.isEmpty()) + { + Critical (format ("%1 failed: %2\n", g_extProgNames[prog], err)); + QString filename ("externalProgramOutput.txt"); + QFile file (filename); + + if (file.open (QIODevice::WriteOnly | QIODevice::Text)) + { + file.write (proc.readAllStandardOutput()); + file.write (proc.readAllStandardError()); + print ("Wrote output and error logs to %1", QFileInfo (file).absoluteFilePath()); + } + else + { + print ("Couldn't open %1 for writing: %2", + QFileInfo (filename).absoluteFilePath(), file.errorString()); + } + + return false; + } + + return true; +} + +// ============================================================================= +// +static void InsertOutput (QString fname, bool replace, QList<LDColor> colorsToReplace) +{ +#ifdef DEBUG + QFile::copy (fname, "./debug_lastOutput"); +#endif // RELEASE + + // Read the output file + QFile f (fname); + + if (not f.open (QIODevice::ReadOnly)) + { + Critical (format ("Couldn't open temporary file %1 for reading.\n", fname)); + return; + } + + LDObjectList objs = LoadFileContents (&f, null); + + // If we replace the objects, delete the selection now. + if (replace) + g_win->deleteSelection(); + + for (LDColor color : colorsToReplace) + g_win->deleteByColor (color); + + // Insert the new objects + CurrentDocument()->clearSelection(); + + for (LDObject* obj : objs) + { + if (not obj->isScemantic()) + { + obj->destroy(); + continue; + } + + CurrentDocument()->addObject (obj); + obj->select(); + } + + g_win->doFullRefresh(); +} + +// ============================================================================= +// Interface for Ytruder +// ============================================================================= +void ExtProgramToolset::ytruder() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Ytruder)) + return; + + QDialog* dlg = new QDialog; + Ui::YtruderUI ui; + ui.setupUi (dlg); + + if (not dlg->exec()) + return; + + // Read the user's choices + const enum { Distance, Symmetry, Projection, Radial } mode = + ui.mode_distance->isChecked() ? Distance : + ui.mode_symmetry->isChecked() ? Symmetry : + ui.mode_projection->isChecked() ? Projection : Radial; + + const Axis axis = + ui.axis_x->isChecked() ? X : + ui.axis_y->isChecked() ? Y : Z; + + const double depth = ui.planeDepth->value(), + condAngle = ui.condAngle->value(); + + QTemporaryFile indat, outdat; + QString inDATName, outDATName; + + // Make temp files for the input and output files + if (not MakeTempFile (indat, inDATName) or not MakeTempFile (outdat, outDATName)) + return; + + // Compose the command-line arguments + QString argv = Join ( + { + (axis == X) ? "-x" : (axis == Y) ? "-y" : "-z", + (mode == Distance) ? "-d" : (mode == Symmetry) ? "-s" : (mode == Projection) ? "-p" : "-r", + depth, + "-a", + condAngle, + inDATName, + outDATName + }); + + WriteSelection (inDATName); + + if (not RunExtProgram (Ytruder, cfg::YtruderPath, argv)) + return; + + InsertOutput (outDATName, false, {}); +} + +// ============================================================================= +// Rectifier interface +// ============================================================================= +void ExtProgramToolset::rectifier() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Rectifier)) + return; + + QDialog* dlg = new QDialog; + Ui::RectifierUI ui; + ui.setupUi (dlg); + + if (not dlg->exec()) + return; + + QTemporaryFile indat, outdat; + QString inDATName, outDATName; + + // Make temp files for the input and output files + if (not MakeTempFile (indat, inDATName) or not MakeTempFile (outdat, outDATName)) + return; + + // Compose arguments + QString argv = Join ( + { + (not ui.cb_condense->isChecked()) ? "-q" : "", + (not ui.cb_subst->isChecked()) ? "-r" : "", + (ui.cb_condlineCheck->isChecked()) ? "-a" : "", + (ui.cb_colorize->isChecked()) ? "-c" : "", + "-t", + ui.dsb_coplthres->value(), + inDATName, + outDATName + }); + + WriteSelection (inDATName); + + if (not RunExtProgram (Rectifier, cfg::RectifierPath, argv)) + return; + + InsertOutput (outDATName, true, {}); +} + +// ============================================================================= +// Intersector interface +// ============================================================================= +void ExtProgramToolset::intersector() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Intersector)) + return; + + QDialog* dlg = new QDialog; + Ui::IntersectorUI ui; + ui.setupUi (dlg); + + MakeColorComboBox (ui.cmb_incol); + MakeColorComboBox (ui.cmb_cutcol); + ui.cb_repeat->setWhatsThis ("If this is set, " APPNAME " runs Intersector a second time with inverse files to cut the " + " cutter group with the input group. Both groups are cut by the intersection."); + ui.cb_edges->setWhatsThis ("Makes " APPNAME " try run Isecalc to create edgelines for the intersection."); + + LDColor inCol, cutCol; + const bool repeatInverse = ui.cb_repeat->isChecked(); + + forever + { + if (not dlg->exec()) + return; + + inCol = ui.cmb_incol->itemData (ui.cmb_incol->currentIndex()).toInt(); + cutCol = ui.cmb_cutcol->itemData (ui.cmb_cutcol->currentIndex()).toInt(); + + if (inCol == cutCol) + { + Critical ("Cannot use the same color group for both input and cutter!"); + continue; + } + + break; + } + + // Five temporary files! + // indat = input group file + // cutdat = cutter group file + // outdat = primary output + // outdat2 = inverse output + // edgesdat = edges output (isecalc) + QTemporaryFile indat, cutdat, outdat, outdat2, edgesdat; + QString inDATName, cutDATName, outDATName, outDAT2Name, edgesDATName; + + if (not MakeTempFile (indat, inDATName) or + not MakeTempFile (cutdat, cutDATName) or + not MakeTempFile (outdat, outDATName) or + not MakeTempFile (outdat2, outDAT2Name) or + not MakeTempFile (edgesdat, edgesDATName)) + { + return; + } + + QString parms = Join ( + { + (ui.cb_colorize->isChecked()) ? "-c" : "", + (ui.cb_nocondense->isChecked()) ? "-t" : "", + "-s", + ui.dsb_prescale->value() + }); + + QString argv_normal = Join ( + { + parms, + inDATName, + cutDATName, + outDATName + }); + + QString argv_inverse = Join ( + { + parms, + cutDATName, + inDATName, + outDAT2Name + }); + + WriteColorGroup (inCol, inDATName); + WriteColorGroup (cutCol, cutDATName); + + if (not RunExtProgram (Intersector, cfg::IntersectorPath, argv_normal)) + return; + + InsertOutput (outDATName, false, {inCol}); + + if (repeatInverse and RunExtProgram (Intersector, cfg::IntersectorPath, argv_inverse)) + InsertOutput (outDAT2Name, false, {cutCol}); + + if (ui.cb_edges->isChecked() and CheckExtProgramPath (Isecalc) and + RunExtProgram (Isecalc, cfg::IsecalcPath, Join ({inDATName, cutDATName, edgesDATName}))) + { + InsertOutput (edgesDATName, false, {}); + } +} + +// ============================================================================= +// +void ExtProgramToolset::coverer() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Coverer)) + return; + + QDialog* dlg = new QDialog; + Ui::CovererUI ui; + ui.setupUi (dlg); + MakeColorComboBox (ui.cmb_col1); + MakeColorComboBox (ui.cmb_col2); + + LDColor in1Col, in2Col; + + forever + { + if (not dlg->exec()) + return; + + in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(); + in2Col = ui.cmb_col2->itemData (ui.cmb_col2->currentIndex()).toInt(); + + if (in1Col == in2Col) + { + Critical ("Cannot use the same color group for both inputs!"); + continue; + } + + break; + } + + QTemporaryFile in1dat, in2dat, outdat; + QString in1DATName, in2DATName, outDATName; + + if (not MakeTempFile (in1dat, in1DATName) or + not MakeTempFile (in2dat, in2DATName) or + not MakeTempFile (outdat, outDATName)) + { + return; + } + + QString argv = Join ( + { + (ui.cb_oldsweep->isChecked() ? "-s" : ""), + (ui.cb_reverse->isChecked() ? "-r" : ""), + (ui.dsb_segsplit->value() != 0 ? format ("-l %1", ui.dsb_segsplit->value()) : ""), + (ui.sb_bias->value() != 0 ? format ("-s %1", ui.sb_bias->value()) : ""), + in1DATName, + in2DATName, + outDATName + }); + + WriteColorGroup (in1Col, in1DATName); + WriteColorGroup (in2Col, in2DATName); + + if (not RunExtProgram (Coverer, cfg::CovererPath, argv)) + return; + + InsertOutput (outDATName, false, {}); +} + +// ============================================================================= +// +void ExtProgramToolset::isecalc() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Isecalc)) + return; + + Ui::IsecalcUI ui; + QDialog* dlg = new QDialog; + ui.setupUi (dlg); + + MakeColorComboBox (ui.cmb_col1); + MakeColorComboBox (ui.cmb_col2); + + LDColor in1Col, in2Col; + + // Run the dialog and validate input + forever + { + if (not dlg->exec()) + return; + + in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(); + in2Col = ui.cmb_col2->itemData (ui.cmb_col2->currentIndex()).toInt(); + + if (in1Col == in2Col) + { + Critical ("Cannot use the same color group for both input and cutter!"); + continue; + } + + break; + } + + QTemporaryFile in1dat, in2dat, outdat; + QString in1DATName, in2DATName, outDATName; + + if (not MakeTempFile (in1dat, in1DATName) or + not MakeTempFile (in2dat, in2DATName) or + not MakeTempFile (outdat, outDATName)) + { + return; + } + + QString argv = Join ( + { + in1DATName, + in2DATName, + outDATName + }); + + WriteColorGroup (in1Col, in1DATName); + WriteColorGroup (in2Col, in2DATName); + RunExtProgram (Isecalc, cfg::IsecalcPath, argv); + InsertOutput (outDATName, false, {}); +} + +// ============================================================================= +// +void ExtProgramToolset::edger2() +{ + setlocale (LC_ALL, "C"); + + if (not CheckExtProgramPath (Edger2)) + return; + + QDialog* dlg = new QDialog; + Ui::Edger2Dialog ui; + ui.setupUi (dlg); + + if (not dlg->exec()) + return; + + QTemporaryFile in, out; + QString inName, outName; + + if (not MakeTempFile (in, inName) or not MakeTempFile (out, outName)) + return; + + int unmatched = ui.unmatched->currentIndex(); + + QString argv = Join ( + { + format ("-p %1", ui.precision->value()), + format ("-af %1", ui.flatAngle->value()), + format ("-ac %1", ui.condAngle->value()), + format ("-ae %1", ui.edgeAngle->value()), + ui.delLines->isChecked() ? "-de" : "", + ui.delCondLines->isChecked() ? "-dc" : "", + ui.colored->isChecked() ? "-c" : "", + ui.bfc->isChecked() ? "-b" : "", + ui.convex->isChecked() ? "-cx" : "", + ui.concave->isChecked() ? "-cv" : "", + unmatched == 0 ? "-u+" : (unmatched == 2 ? "-u-" : ""), + inName, + outName, + }); + + WriteSelection (inName); + + if (not RunExtProgram (Edger2, cfg::Edger2Path, argv)) + return; + + InsertOutput (outName, true, {}); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/extprogramtoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,33 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class ExtProgramToolset : public Toolset +{ +public: + ExtProgramToolset (MainWindow* parent); + + Q_INVOKABLE void coverer(); + Q_INVOKABLE void edger2(); + Q_INVOKABLE void intersector(); + Q_INVOKABLE void isecalc(); + Q_INVOKABLE void rectifier(); + Q_INVOKABLE void ytruder(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/filetoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,231 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <QFileDialog> +#include <QMessageBox> +#include "../configDialog.h" +#include "../dialogs.h" +#include "../glRenderer.h" +#include "../ldDocument.h" +#include "../mainwindow.h" +#include "../partDownloader.h" +#include "../primitives.h" +#include "../dialogs/ldrawpathdialog.h" +#include "../dialogs/newpartdialog.h" +#include "filetoolset.h" +#include "ui_makeprim.h" + +EXTERN_CFGENTRY (String, LDrawPath) + +FileToolset::FileToolset (MainWindow* parent) : + Toolset (parent) {} + +void FileToolset::newPart() +{ + NewPartDialog* dlg = new NewPartDialog (m_window); + + if (dlg->exec() == QDialog::Accepted) + { + newFile(); + dlg->fillHeader (CurrentDocument()); + m_window->doFullRefresh(); + } +} + +void FileToolset::newFile() +{ + newFile(); +} + +void FileToolset::open() +{ + QString name = QFileDialog::getOpenFileName (m_window, "Open File", "", "LDraw files (*.dat *.ldr)"); + + if (name.isEmpty()) + return; + + OpenMainModel (name); +} + +void FileToolset::save() +{ + m_window->save (CurrentDocument(), false); +} + +void FileToolset::saveAs() +{ + m_window->save (CurrentDocument(), true); +} + +void FileToolset::saveAll() +{ + for (LDDocument* file : LDDocument::explicitDocuments()) + m_window->save (file, false); +} + +void FileToolset::close() +{ + if (not CurrentDocument()->isSafeToClose()) + return; + + CurrentDocument()->dismiss(); +} + +void FileToolset::closeAll() +{ + if (not IsSafeToCloseAll()) + return; + + CloseAllDocuments(); +} + +void FileToolset::settings() +{ + (new ConfigDialog)->exec(); +} + +void FileToolset::setLDrawPath() +{ + (new LDrawPathDialog (cfg::LDrawPath, true))->exec(); +} + +void FileToolset::exit() +{ + Exit(); +} + +void FileToolset::insertFrom() +{ + QString fname = QFileDialog::getOpenFileName(); + int idx = m_window->getInsertionPoint(); + + if (not fname.length()) + return; + + QFile f (fname); + + if (not f.open (QIODevice::ReadOnly)) + { + Critical (format ("Couldn't open %1 (%2)", fname, f.errorString())); + return; + } + + LDObjectList objs = LoadFileContents (&f, null); + + CurrentDocument()->clearSelection(); + + for (LDObject* obj : objs) + { + CurrentDocument()->insertObj (idx, obj); + obj->select(); + m_window->R()->compileObject (obj); + + idx++; + } + + m_window->refresh(); + m_window->scrollToSelection(); +} + +void FileToolset::exportTo() +{ + if (Selection().isEmpty()) + return; + + QString fname = QFileDialog::getSaveFileName(); + + if (fname.length() == 0) + return; + + QFile file (fname); + + if (not file.open (QIODevice::WriteOnly | QIODevice::Text)) + { + Critical (format ("Unable to open %1 for writing (%2)", fname, file.errorString())); + return; + } + + for (LDObject* obj : Selection()) + { + QString contents = obj->asText(); + QByteArray data = contents.toUtf8(); + file.write (data, data.size()); + file.write ("\r\n", 2); + } +} + +void FileToolset::scanPrimitives() +{ + PrimitiveScanner::start(); +} + +void FileToolset::openSubfiles() +{ + for (LDObject* obj : Selection()) + { + LDSubfile* ref = dynamic_cast<LDSubfile*> (obj); + + if (ref == null or not ref->fileInfo()->isImplicit()) + continue; + + ref->fileInfo()->setImplicit (false); + } +} + +void FileToolset::downloadFrom() +{ + PartDownloader::staticBegin(); +} + +void FileToolset::makePrimitive() +{ + PrimitivePrompt* dlg = new PrimitivePrompt (g_win); + + if (not dlg->exec()) + return; + + int segs = dlg->ui->sb_segs->value(); + int divs = dlg->ui->cb_hires->isChecked() ? HighResolution : LowResolution; + int num = dlg->ui->sb_ringnum->value(); + PrimitiveType type = + dlg->ui->rb_circle->isChecked() ? Circle : + dlg->ui->rb_cylinder->isChecked() ? Cylinder : + dlg->ui->rb_disc->isChecked() ? Disc : + dlg->ui->rb_ndisc->isChecked() ? DiscNeg : + dlg->ui->rb_ring->isChecked() ? Ring : Cone; + + LDDocument* f = GeneratePrimitive (type, segs, divs, num); + f->setImplicit (false); + m_window->save (f, false); +} + +// These are not exactly file tools but I don't want to make another toolset just for 3 very small actions +void FileToolset::help() +{ + // Not yet implemented +} + +void FileToolset::about() +{ + AboutDialog().exec(); +} + +void FileToolset::aboutQt() +{ + QMessageBox::aboutQt (m_window); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/filetoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,49 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class FileToolset : public Toolset +{ + Q_OBJECT + +public: + FileToolset (class MainWindow* parent); + + Q_INVOKABLE void about(); + Q_INVOKABLE void aboutQt(); + Q_INVOKABLE void downloadFrom(); + Q_INVOKABLE void close(); + Q_INVOKABLE void closeAll(); + Q_INVOKABLE void exit(); + Q_INVOKABLE void exportTo(); + Q_INVOKABLE void help(); + Q_INVOKABLE void insertFrom(); + Q_INVOKABLE void makePrimitive(); + Q_INVOKABLE void newFile(); + Q_INVOKABLE void newPart(); + Q_INVOKABLE void open(); + Q_INVOKABLE void openSubfiles(); + Q_INVOKABLE void save(); + Q_INVOKABLE void saveAll(); + Q_INVOKABLE void saveAs(); + Q_INVOKABLE void scanPrimitives(); + Q_INVOKABLE void setLDrawPath(); + Q_INVOKABLE void settings(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/movetoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,137 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "../ldDocument.h" +#include "../ldObjectMath.h" +#include "../miscallenous.h" +#include "../mainwindow.h" +#include "movetoolset.h" + +MoveToolset::MoveToolset (MainWindow* parent) : + Toolset (parent) +{ +} + +void MoveToolset::moveSelection (bool up) +{ + LDObjectList objs = Selection(); + LDObject::moveObjects (objs, up); + m_window->buildObjList(); +} + +void MoveToolset::moveUp() +{ + moveSelection (true); +} + +void MoveToolset::moveDown() +{ + moveSelection (false); +} + +void MoveToolset::gridCoarse() +{ + cfg::Grid = Grid::Coarse; + m_window->updateGridToolBar(); +} + +void MoveToolset::gridMedium() +{ + cfg::Grid = Grid::Medium; + m_window->updateGridToolBar(); +} + +void MoveToolset::gridFine() +{ + cfg::Grid = Grid::Fine; + m_window->updateGridToolBar(); +} + +void MoveToolset::moveObjects (Vertex vect) +{ + // Apply the grid values + vect *= *CurrentGrid().coordinateSnap; + + for (LDObject* obj : Selection()) + obj->move (vect); +} + +void MoveToolset::moveXNeg() +{ + moveObjects ({-1, 0, 0}); +} + +void MoveToolset::moveYNeg() +{ + moveObjects ({0, -1, 0}); +} + +void MoveToolset::moveZNeg() +{ + moveObjects ({0, 0, -1}); +} + +void MoveToolset::moveXPos() +{ + moveObjects ({1, 0, 0}); +} + +void MoveToolset::moveYPos() +{ + moveObjects ({0, 1, 0}); +} + +void MoveToolset::moveZPos() +{ + moveObjects ({0, 0, 1}); +} + +static double GetRotateActionAngle() +{ + return (Pi * *CurrentGrid().angleSnap) / 180; +} + +void MoveToolset::rotateXPos() +{ + RotateObjects (1, 0, 0, GetRotateActionAngle(), Selection()); +} +void MoveToolset::rotateYPos() +{ + RotateObjects (0, 1, 0, GetRotateActionAngle(), Selection()); +} +void MoveToolset::rotateZPos() +{ + RotateObjects (0, 0, 1, GetRotateActionAngle(), Selection()); +} +void MoveToolset::rotateXNeg() +{ + RotateObjects (-1, 0, 0, GetRotateActionAngle(), Selection()); +} +void MoveToolset::rotateYNeg() +{ + RotateObjects (0, -1, 0, GetRotateActionAngle(), Selection()); +} +void MoveToolset::rotateZNeg() +{ + RotateObjects (0, 0, -1, GetRotateActionAngle(), Selection()); +} + +void MoveToolset::configureRotationPoint() +{ + ConfigureRotationPoint(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/movetoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,51 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class MoveToolset : public Toolset +{ + Q_OBJECT + +public: + explicit MoveToolset (MainWindow* parent); + + Q_INVOKABLE void configureRotationPoint(); + Q_INVOKABLE void gridCoarse(); + Q_INVOKABLE void gridFine(); + Q_INVOKABLE void gridMedium(); + Q_INVOKABLE void moveDown(); + Q_INVOKABLE void moveUp(); + Q_INVOKABLE void moveXNeg(); + Q_INVOKABLE void moveXPos(); + Q_INVOKABLE void moveYNeg(); + Q_INVOKABLE void moveYPos(); + Q_INVOKABLE void moveZNeg(); + Q_INVOKABLE void moveZPos(); + Q_INVOKABLE void rotateXNeg(); + Q_INVOKABLE void rotateXPos(); + Q_INVOKABLE void rotateYNeg(); + Q_INVOKABLE void rotateYPos(); + Q_INVOKABLE void rotateZNeg(); + Q_INVOKABLE void rotateZPos(); + +private: + void moveSelection (bool up); + void moveObjects (Vertex vect); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/toolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,42 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "../mainwindow.h" +#include "algorithmtoolset.h" +#include "basictoolset.h" +#include "extprogramtoolset.h" +#include "filetoolset.h" +#include "movetoolset.h" +#include "toolset.h" +#include "viewtoolset.h" + +Toolset::Toolset (MainWindow* parent) : + QObject (parent), + m_window (parent) {} + +QVector<Toolset*> Toolset::createToolsets (MainWindow* parent) +{ + QVector<Toolset*> tools; + tools << new AlgorithmToolset (parent); + tools << new BasicToolset (parent); + tools << new ExtProgramToolset (parent); + tools << new FileToolset (parent); + tools << new MoveToolset (parent); + tools << new ViewToolset (parent); + return tools; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/toolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,35 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <QObject> +#include "../main.h" + +class MainWindow; + +class Toolset : public QObject +{ + Q_OBJECT +public: + Toolset (MainWindow* parent); + + static QVector<Toolset*> createToolsets (MainWindow* parent); + +protected: + MainWindow* m_window; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/viewtoolset.cpp Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,310 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <QFileDialog> +#include <QInputDialog> +#include "../mainwindow.h" +#include "../ldDocument.h" +#include "../miscallenous.h" +#include "../glRenderer.h" +#include "../primitives.h" +#include "../colors.h" +#include "../dialogs.h" +#include "../glCompiler.h" +#include "viewtoolset.h" + +EXTERN_CFGENTRY (Bool, DrawWireframe) +EXTERN_CFGENTRY (Bool, BFCRedGreenView) +EXTERN_CFGENTRY (Bool, DrawAngles) +EXTERN_CFGENTRY (Bool, RandomColors) +EXTERN_CFGENTRY (Bool, DrawSurfaces) +EXTERN_CFGENTRY (Bool, DrawEdgeLines) +EXTERN_CFGENTRY (Bool, DrawConditionalLines) +EXTERN_CFGENTRY (Bool, DrawAxes) + +ViewToolset::ViewToolset (MainWindow *parent) : + Toolset (parent) {} + +void ViewToolset::selectAll() +{ + for (LDObject* obj : CurrentDocument()->objects()) + obj->select(); +} + +void ViewToolset::selectByColor() +{ + if (Selection().isEmpty()) + return; + + QList<LDColor> colors; + + for (LDObject* obj : Selection()) + { + if (obj->isColored()) + colors << obj->color(); + } + + removeDuplicates (colors); + CurrentDocument()->clearSelection(); + + for (LDObject* obj : CurrentDocument()->objects()) + { + if (colors.contains (obj->color())) + obj->select(); + } +} + +void ViewToolset::selectByType() +{ + if (Selection().isEmpty()) + return; + + QList<LDObjectType> types; + QStringList subfilenames; + + for (LDObject* obj : Selection()) + { + types << obj->type(); + + if (types.last() == OBJ_Subfile) + subfilenames << static_cast<LDSubfile*> (obj)->fileInfo()->name(); + } + + removeDuplicates (types); + removeDuplicates (subfilenames); + CurrentDocument()->clearSelection(); + + for (LDObject* obj : CurrentDocument()->objects()) + { + LDObjectType type = obj->type(); + + if (not types.contains (type)) + continue; + + // For subfiles, type check is not enough, we check the name of the document as well. + if (type == OBJ_Subfile and not subfilenames.contains (static_cast<LDSubfile*> (obj)->fileInfo()->name())) + continue; + + obj->select(); + } +} + +void ViewToolset::resetView() +{ + m_window->R()->resetAngles(); + m_window->R()->update(); +} + +void ViewToolset::screenshot() +{ + setlocale (LC_ALL, "C"); + + int w, h; + uchar* imgdata = m_window->R()->getScreencap (w, h); + QImage img = GetImageFromScreencap (imgdata, w, h); + + QString root = Basename (CurrentDocument()->name()); + + if (root.right (4) == ".dat") + root.chop (4); + + QString defaultname = (root.length() > 0) ? format ("%1.png", root) : ""; + QString fname = QFileDialog::getSaveFileName (m_window, "Save Screencap", defaultname, + "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)"); + + if (not fname.isEmpty() and not img.save (fname)) + Critical (format ("Couldn't open %1 for writing to save screencap: %2", fname, strerror (errno))); + + delete[] imgdata; +} + +void ViewToolset::axes() +{ + cfg::DrawAxes = not cfg::DrawAxes; + m_window->updateActions(); + m_window->R()->update(); +} + +void ViewToolset::visibilityToggle() +{ + for (LDObject* obj : Selection()) + obj->setHidden (not obj->isHidden()); +} + +void ViewToolset::visibilityHide() +{ + for (LDObject* obj : Selection()) + obj->setHidden (true); +} + +void ViewToolset::visibilityReveal() +{ + for (LDObject* obj : Selection()) + obj->setHidden (false); +} + +void ViewToolset::wireframe() +{ + cfg::DrawWireframe = not cfg::DrawWireframe; + m_window->R()->refresh(); +} + +void ViewToolset::setOverlay() +{ + OverlayDialog dlg; + + if (not dlg.exec()) + return; + + m_window->R()->setupOverlay ((ECamera) dlg.camera(), dlg.fpath(), dlg.ofsx(), + dlg.ofsy(), dlg.lwidth(), dlg.lheight()); +} + +void ViewToolset::clearOverlay() +{ + m_window->R()->clearOverlay(); +} + +void ViewToolset::drawAngles() +{ + cfg::DrawAngles = not cfg::DrawAngles; + m_window->R()->refresh(); +} + +void ViewToolset::setDrawDepth() +{ + if (m_window->R()->camera() == EFreeCamera) + return; + + bool ok; + double depth = QInputDialog::getDouble (m_window, "Set Draw Depth", + format ("Depth value for %1 Camera:", m_window->R()->getCameraName()), + m_window->R()->getDepthValue(), -10000.0f, 10000.0f, 3, &ok); + + if (ok) + m_window->R()->setDepthValue (depth); +} + +#if 0 +// This is a test to draw a dummy axle. Meant to be used as a primitive gallery, +// but I can't figure how to generate these pictures properly. Multi-threading +// these is an immense pain. +void ViewToolset::testpic() +{ + LDDocument* file = getFile ("axle.dat"); + setlocale (LC_ALL, "C"); + + if (not file) + { + critical ("couldn't load axle.dat"); + return; + } + + int w, h; + + GLRenderer* rend = new GLRenderer; + rend->resize (64, 64); + rend->setAttribute (Qt::WA_DontShowOnScreen); + rend->show(); + rend->setFile (file); + rend->setDrawOnly (true); + rend->compileAllObjects(); + rend->initGLData(); + rend->drawGLScene(); + + uchar* imgdata = rend->screencap (w, h); + QImage img = imageFromScreencap (imgdata, w, h); + + if (img.isNull()) + { + critical ("Failed to create the image!\n"); + } + else + { + QLabel* label = new QLabel; + QDialog* dlg = new QDialog; + label->setPixmap (QPixmap::fromImage (img)); + QVBoxLayout* layout = new QVBoxLayout (dlg); + layout->addWidget (label); + dlg->exec(); + } + + delete[] imgdata; + rend->deleteLater(); +} +#endif + +void ViewToolset::bfcView() +{ + cfg::BFCRedGreenView = not cfg::BFCRedGreenView; + + if (cfg::BFCRedGreenView) + cfg::RandomColors = false; + + m_window->updateActions(); + m_window->R()->refresh(); +} + +void ViewToolset::jumpTo() +{ + bool ok; + int defval = 0; + LDObject* obj; + + if (Selection().size() == 1) + defval = Selection()[0]->lineNumber(); + + int idx = QInputDialog::getInt (null, "Go to line", "Go to line:", defval, + 1, CurrentDocument()->getObjectCount(), 1, &ok); + + if (not ok or (obj = CurrentDocument()->getObject (idx - 1)) == null) + return; + + CurrentDocument()->clearSelection(); + obj->select(); + m_window->updateSelection(); +} + +void ViewToolset::randomColors() +{ + cfg::RandomColors = not cfg::RandomColors; + + if (cfg::RandomColors) + cfg::BFCRedGreenView = false; + + m_window->updateActions(); + m_window->R()->refresh(); +} + +void ViewToolset::drawSurfaces() +{ + cfg::DrawSurfaces = not cfg::DrawSurfaces; + m_window->updateActions(); +} + +void ViewToolset::drawEdgeLines() +{ + cfg::DrawEdgeLines = not cfg::DrawEdgeLines; + m_window->updateActions(); +} + +void ViewToolset::drawConditionalLines() +{ + cfg::DrawConditionalLines = not cfg::DrawConditionalLines; + m_window->updateActions(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/toolsets/viewtoolset.h Sun Aug 30 17:20:55 2015 +0300 @@ -0,0 +1,49 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "toolset.h" + +class ViewToolset : public Toolset +{ + Q_OBJECT + +public: + ViewToolset (MainWindow* parent); + + Q_INVOKABLE void axes(); + Q_INVOKABLE void bfcView(); + Q_INVOKABLE void clearOverlay(); + Q_INVOKABLE void drawAngles(); + Q_INVOKABLE void drawConditionalLines(); + Q_INVOKABLE void drawEdgeLines(); + Q_INVOKABLE void drawSurfaces(); + Q_INVOKABLE void jumpTo(); + Q_INVOKABLE void randomColors(); + Q_INVOKABLE void resetView(); + Q_INVOKABLE void screenshot(); + Q_INVOKABLE void selectAll(); + Q_INVOKABLE void selectByColor(); + Q_INVOKABLE void selectByType(); + Q_INVOKABLE void setDrawDepth(); + Q_INVOKABLE void setOverlay(); + Q_INVOKABLE void visibilityHide(); + Q_INVOKABLE void visibilityReveal(); + Q_INVOKABLE void visibilityToggle(); + Q_INVOKABLE void wireframe(); +};