/*************************************************************************** * Copyright (c) 2014 Joe Dowsett * * Copyright (c) 2014 Luke Parry * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ #include #endif // #ifndef _PreComp_ #include #include #include #include #include #include #include #include #include #include #include #include #include "ViewProviderProjGroup.h" #include "ViewProviderProjGroupItem.h" #include "ViewProviderPage.h" #include "TaskProjGroup.h" #include using namespace Gui; using namespace TechDrawGui; //TODO: Look into this, seems we might be able to delete it now? IR #if 0 // needed for Qt's lupdate utility qApp->translate("QObject", "Make axonometric..."); qApp->translate("QObject", "Edit axonometric settings..."); qApp->translate("QObject", "Make orthographic"); #endif TaskProjGroup::TaskProjGroup(TechDraw::DrawProjGroup* featView, bool mode) : ui(new Ui_TaskProjGroup), multiView(featView), m_createMode(mode) { ui->setupUi(this); blockUpdate = true; ui->projection->setCurrentIndex(multiView->ProjectionType.getValue()); setFractionalScale(multiView->Scale.getValue()); ui->cmbScaleType->setCurrentIndex(multiView->ScaleType.getValue()); // Initially toggle view checkboxes if needed setupViewCheckboxes(true); blockUpdate = false; // Rotation buttons // Note we don't do the custom one here, as it's handled by [a different function that's held up in customs] connect(ui->butTopRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); connect(ui->butCWRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); connect(ui->butRightRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); connect(ui->butDownRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); connect(ui->butLeftRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); connect(ui->butCCWRotate, SIGNAL(clicked()), this, SLOT(rotateButtonClicked(void))); // Slot for Scale Type connect(ui->cmbScaleType, SIGNAL(currentIndexChanged(int)), this, SLOT(scaleTypeChanged(int))); connect(ui->sbScaleNum, SIGNAL(valueChanged(int)), this, SLOT(scaleManuallyChanged(int))); connect(ui->sbScaleDen, SIGNAL(valueChanged(int)), this, SLOT(scaleManuallyChanged(int))); // Slot for Projection Type (layout) connect(ui->projection, SIGNAL(currentIndexChanged(int)), this, SLOT(projectionTypeChanged(int))); m_page = multiView->findParentPage(); Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_page->getDocument()); Gui::ViewProvider* vp = activeGui->getViewProvider(m_page); ViewProviderPage* dvp = dynamic_cast(vp); m_mdi = dvp->getMDIViewPage(); } TaskProjGroup::~TaskProjGroup() { delete ui; } void TaskProjGroup::viewToggled(bool toggle) { bool changed = false; // Obtain name of checkbox QString viewName = sender()->objectName(); int index = viewName.mid(7).toInt(); const char *viewNameCStr = viewChkIndexToCStr(index); App::DocumentObject* newObj; TechDraw::DrawView* newView; if ( toggle && !multiView->hasProjection( viewNameCStr ) ) { newObj = multiView->addProjection( viewNameCStr ); newView = static_cast(newObj); m_mdi->redraw1View(newView); changed = true; } else if ( !toggle && multiView->hasProjection( viewNameCStr ) ) { multiView->removeProjection( viewNameCStr ); changed = true; } if (changed) { multiView->recomputeFeature(); if (multiView->ScaleType.isValue("Automatic")) { double scale = multiView->Scale.getValue(); setFractionalScale(scale); } } } void TaskProjGroup::rotateButtonClicked(void) { if ( multiView && ui ) { const QObject *clicked = sender(); // Any translation/scale/etc applied here will be ignored, as // DrawProjGroup::setFrontViewOrientation() only // uses it to set Direction and XAxisDirection. Base::Matrix4D m = multiView->viewOrientationMatrix.getValue(); // TODO: Construct these directly Base::Matrix4D t; //TODO: Consider changing the vectors around depending on whether we're in First or Third angle mode - might be more intuitive? IR if ( clicked == ui->butTopRotate ) { t.rotX(M_PI / -2); } else if ( clicked == ui->butCWRotate ) { t.rotY(M_PI / -2); } else if ( clicked == ui->butRightRotate) { t.rotZ(M_PI / 2); } else if ( clicked == ui->butDownRotate) { t.rotX(M_PI / 2); } else if ( clicked == ui->butLeftRotate) { t.rotZ(M_PI / -2); } else if ( clicked == ui->butCCWRotate) { t.rotY(M_PI / 2); } m *= t; multiView->setFrontViewOrientation(m); Gui::Command::updateActive(); } } void TaskProjGroup::projectionTypeChanged(int index) { if(blockUpdate) return; if(index == 0) { //layout per Page (Document) Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ProjectionType = '%s'", multiView->getNameInDocument(), "Default"); } else if(index == 1) { // First Angle layout Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ProjectionType = '%s'", multiView->getNameInDocument(), "First Angle"); } else if(index == 2) { // Third Angle layout Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ProjectionType = '%s'", multiView->getNameInDocument(), "Third Angle"); } else { Base::Console().Log("Error - TaskProjGroup::projectionTypeChanged - unknown projection layout: %d\n", index); return; } // Update checkboxes so checked state matches the drawing setupViewCheckboxes(); } void TaskProjGroup::scaleTypeChanged(int index) { if(blockUpdate) return; if(index == 0) { // Document Scale Type Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ScaleType = '%s'", multiView->getNameInDocument() , "Page"); } else if(index == 1) { // Automatic Scale Type Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ScaleType = '%s'", multiView->getNameInDocument() , "Automatic"); } else if(index == 2) { // Custom Scale Type Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.ScaleType = '%s'", multiView->getNameInDocument() , "Custom"); int a = ui->sbScaleNum->value(); int b = ui->sbScaleDen->value(); double scale = (double) a / (double) b; Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Scale = %f", multiView->getNameInDocument() , scale); } else { Base::Console().Log("Error - TaskProjGroup::scaleTypeChanged - unknown scale type: %d\n",index); return; } multiView->recomputeFeature(); Gui::Command::updateActive(); } // ** David Eppstein / UC Irvine / 8 Aug 1993 // Reworked 2015 IR to add the power of logarithms! void TaskProjGroup::nearestFraction(double val, int &n, int &d) const { int exponent = std::floor(std::log10(val)); if (exponent > 1 || exponent < -1) { val *= std::pow(10, -exponent); } n = 1; // numerator d = 1; // denominator double fraction = n / d; //double m = fabs(fraction - val); while (fabs(fraction - val) > 0.001) { if (fraction < val) { ++n; } else { ++d; n = (int) round(val * d); } fraction = n / (double) d; } if (exponent > 1) { n *= std::pow(10, exponent); } else if (exponent < -1) { d *= std::pow(10, -exponent); } } void TaskProjGroup::updateTask() { // Update the scale type blockUpdate = true; ui->cmbScaleType->setCurrentIndex(multiView->ScaleType.getValue()); // Update the scale value setFractionalScale(multiView->Scale.getValue()); blockUpdate = false; } void TaskProjGroup::setFractionalScale(double newScale) { blockUpdate = true; int num, den; nearestFraction(newScale, num, den); ui->sbScaleNum->setValue(num); ui->sbScaleDen->setValue(den); blockUpdate = false; } void TaskProjGroup::scaleManuallyChanged(int i) { Q_UNUSED(i); if(blockUpdate) return; if (!multiView->ScaleType.isValue("Custom")) { //ignore if not custom! return; } int a = ui->sbScaleNum->value(); int b = ui->sbScaleDen->value(); double scale = (double) a / (double) b; Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Scale = %f", multiView->getNameInDocument() , scale); multiView->recomputeFeature(); Gui::Command::updateActive(); } void TaskProjGroup::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } } const char * TaskProjGroup::viewChkIndexToCStr(int index) { // Third Angle: FTL T FTRight // L F Right Rear // FBL B FBRight // // First Angle: FBRight B FBL // Right F L Rear // FTRight T FTL assert (multiView != NULL); bool thirdAngle = multiView->usedProjectionType().isValue("Third Angle"); switch(index) { case 0: return (thirdAngle ? "FrontTopLeft" : "FrontBottomRight"); case 1: return (thirdAngle ? "Top" : "Bottom"); case 2: return (thirdAngle ? "FrontTopRight" : "FrontBottomLeft"); case 3: return (thirdAngle ? "Left" : "Right"); case 4: return (thirdAngle ? "Front" : "Front"); case 5: return (thirdAngle ? "Right" : "Left"); case 6: return (thirdAngle ? "Rear" : "Rear"); case 7: return (thirdAngle ? "FrontBottomLeft" : "FrontTopRight"); case 8: return (thirdAngle ? "Bottom" : "Top"); case 9: return (thirdAngle ? "FrontBottomRight" : "FrontTopLeft"); default: return NULL; } } void TaskProjGroup::setupViewCheckboxes(bool addConnections) { if ( multiView == NULL ) { return; } // There must be a better way to construct this list... QCheckBox * viewCheckboxes[] = { ui->chkView0, ui->chkView1, ui->chkView2, ui->chkView3, ui->chkView4, ui->chkView5, ui->chkView6, ui->chkView7, ui->chkView8, ui->chkView9 }; for (int i = 0; i < 10; ++i) { QCheckBox *box = viewCheckboxes[i]; if (addConnections) { connect(box, SIGNAL(toggled(bool)), this, SLOT(viewToggled(bool))); } const char *viewStr = viewChkIndexToCStr(i); if ( viewStr != NULL && multiView->hasProjection(viewStr) ) { box->setCheckState(Qt::Checked); } else { box->setCheckState(Qt::Unchecked); } } } bool TaskProjGroup::accept() { Gui::Command::commitCommand(); Gui::Command::updateActive(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); return true; } bool TaskProjGroup::reject() { if (getCreateMode()) { std::string multiViewName = multiView->getNameInDocument(); std::string PageName = multiView->findParentPage()->getNameInDocument(); Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().%s.purgeProjections()", multiViewName.c_str()); Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().%s.removeView(App.activeDocument().%s)", PageName.c_str(),multiViewName.c_str()); Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().removeObject('%s')",multiViewName.c_str()); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); } else { if (Gui::Command::hasPendingCommand()) { std::vector undos = Gui::Application::Instance->activeDocument()->getUndoVector(); Gui::Application::Instance->activeDocument()->undo(1); multiView->rebuildViewList(); } else { Base::Console().Log("TaskProjGroup: Edit mode - NO command is active\n"); } Gui::Command::updateActive(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); } return false; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TODO: Do we really need to hang on to the TaskDlgProjGroup in this class? IR TaskDlgProjGroup::TaskDlgProjGroup(TechDraw::DrawProjGroup* featView, bool mode) : TaskDialog(), multiView(featView) { //viewProvider = dynamic_cast(featView); widget = new TaskProjGroup(featView,mode); taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-projgroup"), widget->windowTitle(), true, 0); taskbox->groupLayout()->addWidget(widget); Content.push_back(taskbox); } TaskDlgProjGroup::~TaskDlgProjGroup() { } void TaskDlgProjGroup::update() { widget->updateTask(); } void TaskDlgProjGroup::setCreateMode(bool b) { widget->setCreateMode(b); } //==== calls from the TaskView =============================================================== void TaskDlgProjGroup::open() { if (!widget->getCreateMode()) { //this is an edit session, start a transaction Gui::Command::openCommand("Edit Projection Group"); } } void TaskDlgProjGroup::clicked(int) { } bool TaskDlgProjGroup::accept() { widget->accept(); return true; } bool TaskDlgProjGroup::reject() { widget->reject(); return true; } #include