X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fapplicationwindow.cpp;h=cbb96362521aff7e37a2da3851551026eedde5a7;hb=97cfdecd62ced6cb1237a9ac6c7cbce2092fde99;hp=8e7891c613ed8e7691fde9e30d905358f5a1040f;hpb=043ecf4d074909ba2f7f53237962f9eaa72f19c2;p=architektonas diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index 8e7891c..cbb9636 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -8,7 +8,7 @@ // JLH = James Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ------------------------------------------------------------ // JLH 03/22/2011 Created this file // JLH 09/29/2011 Added simple zoom in/out functionality // JLH 10/03/2011 Fixed zoom tool to zoom in/out from center of screen @@ -29,16 +29,32 @@ #include "applicationwindow.h" #include "about.h" +#include "blockwidget.h" #include "drawingview.h" +#include "fileio.h" #include "generaltab.h" +#include "global.h" +#include "layerwidget.h" +#include "objectwidget.h" #include "painter.h" +#include "penwidget.h" #include "settingsdialog.h" +#include "structs.h" +#include "utils.h" -ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas") +// Class variables +DrawingView * ApplicationWindow::drawing; + + +ApplicationWindow::ApplicationWindow(): + baseUnitInput(new QLineEdit), + dimensionSizeInput(new QLineEdit), + settings("Underground Software", "Architektonas") { drawing = new DrawingView(this); drawing->setMouseTracking(true); // We want *all* mouse events...! + drawing->setFocusPolicy(Qt::StrongFocus); setCentralWidget(drawing); aboutWin = new AboutWindow(this); @@ -52,75 +68,321 @@ ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Archit CreateMenus(); CreateToolbars(); - // Create status bar + // Create Dock widgets + QDockWidget * dock1 = new QDockWidget(tr("Layers"), this); + LayerWidget * lw = new LayerWidget; + dock1->setWidget(lw); + addDockWidget(Qt::RightDockWidgetArea, dock1); + QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this); + BlockWidget * bw = new BlockWidget; + dock2->setWidget(bw); + addDockWidget(Qt::RightDockWidgetArea, dock2); + QDockWidget * dock3 = new QDockWidget(tr("Object"), this); + ObjectWidget * ow = new ObjectWidget; + dock3->setWidget(ow); + addDockWidget(Qt::RightDockWidgetArea, dock3); + // Needed for saveState() + dock1->setObjectName("Layers"); + dock2->setObjectName("Blocks"); + dock3->setObjectName("Object"); + + // Create status bar + zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch"); + statusBar()->addPermanentWidget(zoomIndicator); statusBar()->showMessage(tr("Ready")); ReadSettings(); - -// connect(textEdit->document(), SIGNAL(contentsChanged()), -// this, SLOT(documentWasModified())); - -// setCurrentFile(""); setUnifiedTitleAndToolBarOnMac(true); + Global::font = new QFont("Verdana", 15, QFont::Bold); + + connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int))); + connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle())); + connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int))); + connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload())); -// ((TTEdit *)qApp)->charWnd->show();//eh? - Object::SetFont(new QFont("Verdana", 15, QFont::Bold)); + connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *))); } + void ApplicationWindow::closeEvent(QCloseEvent * event) { WriteSettings(); - event->accept(); // Use ignore() if can't close for some reason + event->accept(); // Use ignore() if can't close for some reason //Do we have a memory leak here if we don't delete the font in the Object??? } -//void ApplicationWindow::FileOpen(void) -//{ -//} + +void ApplicationWindow::FileNew(void) +{ + // Warn the user if drawing has changed and hasn't been saved... + if (drawing->dirty) + { + QMessageBox msg; + + msg.setText("The document has been modified."); + msg.setInformativeText("Do you want to save your changes?"); + msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msg.setDefaultButton(QMessageBox::Save); + int response = msg.exec(); + + switch (response) + { + case QMessageBox::Save: + // Save was clicked + FileSave(); + break; + case QMessageBox::Discard: + // Don't Save was clicked + break; + case QMessageBox::Cancel: + // Cancel was clicked + return; +// break; + } + } + + FileIO::ResetLayerVectors(); + emit ReloadLayers(); + DeleteContents(drawing->document.objects); + drawing->document.objects.clear(); + drawing->dirty = false; + drawing->update(); + documentName.clear(); + setWindowTitle("Architektonas - Untitled"); + statusBar()->showMessage(tr("New drawing is ready.")); +} + + +void ApplicationWindow::FileOpen(void) +{ + QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"), + "", tr("Architektonas files (*.drawing)")); + + // User cancelled open + if (filename.isEmpty()) + return; + + FILE * file = fopen(filename.toUtf8().data(), "r"); + + if (file == 0) + { + QMessageBox msg; + msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename)); + msg.setIcon(QMessageBox::Critical); + msg.exec(); + return; + } + + Container container(true); // Make sure it's a top level container... + bool successful = FileIO::LoadAtnsFile(file, &container); + fclose(file); + + if (!successful) + { + QMessageBox msg; + msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename)); + msg.setIcon(QMessageBox::Critical); + msg.exec(); + // Make sure to delete any hanging objects in the container... + DeleteContents(container.objects); + return; + } + +//printf("FileOpen: container size = %li\n", container.objects.size()); + // Keep memory leaks from happening by getting rid of the old document + DeleteContents(drawing->document.objects); + emit ReloadLayers(); + // We can do this because the vector is just a bunch of pointers to our + // Objects, and the Containers (non-empty) can be moved this way with no + // problem. + drawing->document = container; + drawing->dirty = false; + drawing->update(); + documentName = filename; + setWindowTitle(QString("Architektonas - %1").arg(documentName)); + statusBar()->showMessage(tr("Drawing loaded.")); +} + + +void ApplicationWindow::FileSave(void) +{ + if (documentName.isEmpty()) + documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"), + "", tr("Architektonas drawings (*.drawing)")); + + FILE * file = fopen(documentName.toUtf8().data(), "w"); + + if (file == 0) + { + QMessageBox msg; + msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName)); + msg.setIcon(QMessageBox::Critical); + msg.exec(); + return; + } + + bool successful = FileIO::SaveAtnsFile(file, &drawing->document); + fclose(file); + + if (!successful) + { + QMessageBox msg; + msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName)); + msg.setIcon(QMessageBox::Critical); + msg.exec(); + // In this case, we should unlink the created file, since it's not + // right... +// unlink(documentName.toUtf8().data()); + QFile::remove(documentName); + return; + } + + drawing->dirty = false; + setWindowTitle(QString("Architektonas - %1").arg(documentName)); + statusBar()->showMessage(tr("Drawing saved.")); +} + + +void ApplicationWindow::FileSaveAs(void) +{ + QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"), + documentName, tr("Architektonas drawings (*.drawing)")); + + if (!filename.isEmpty()) + { + documentName = filename; + FileSave(); + } +} + + +void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event) +{ + QMenu menu(this); + menu.addAction(mirrorAct); + menu.addAction(rotateAct); + menu.addAction(trimAct); + menu.exec(event->globalPos()); +} + + +void ApplicationWindow::SnapToGridTool(void) +{ + Global::snapToGrid = snapToGridAct->isChecked(); +} + void ApplicationWindow::FixAngle(void) { - Object::SetFixedAngle(fixAngleAct->isChecked()); + Global::fixedAngle = fixAngleAct->isChecked(); } + void ApplicationWindow::FixLength(void) { - Object::SetFixedLength(fixLengthAct->isChecked()); + Global::fixedLength = fixLengthAct->isChecked(); } + void ApplicationWindow::DeleteTool(void) { - Object::SetDeleteActive(deleteAct->isChecked()); + // For this tool, we check first to see if anything is selected. If so, we + // delete those and *don't* select the delete tool. +// if (drawing->numSelected > 0) + if (drawing->select.size() > 0) + { + DeleteSelectedObjects(drawing->document.objects); + drawing->update(); + deleteAct->setChecked(false); + return; + } + + // Otherwise, toggle the state of the tool + ClearUIToolStatesExcept(deleteAct); + SetInternalToolStates(); } + void ApplicationWindow::DimensionTool(void) { - Object::SetDimensionActive(addDimensionAct->isChecked()); + ClearUIToolStatesExcept(addDimensionAct); + SetInternalToolStates(); } + void ApplicationWindow::RotateTool(void) { - drawing->SetRotateToolActive(rotateAct->isChecked()); + ClearUIToolStatesExcept(rotateAct); + + // Do tear-down if Rotate tool has been turned off + if (!rotateAct->isChecked()) + drawing->RotateHandler(ToolCleanup, Point(0, 0)); + + SetInternalToolStates(); } + +void ApplicationWindow::MirrorTool(void) +{ + ClearUIToolStatesExcept(mirrorAct); + + // Do tear-down if Rotate tool has been turned off + if (!mirrorAct->isChecked()) + drawing->MirrorHandler(ToolCleanup, Point(0, 0)); + + SetInternalToolStates(); +} + + +void ApplicationWindow::TrimTool(void) +{ + ClearUIToolStatesExcept(trimAct); + SetInternalToolStates(); +} + + +void ApplicationWindow::TriangulateTool(void) +{ + ClearUIToolStatesExcept(triangulateAct); + SetInternalToolStates(); +} + + void ApplicationWindow::AddLineTool(void) { - addCircleAct->setChecked(false); - addArcAct->setChecked(false); - rotateAct->setChecked(false); - RotateTool(); - drawing->SetAddLineToolActive(addLineAct->isChecked()); + ClearUIToolStatesExcept(addLineAct); + SetInternalToolStates(); } + void ApplicationWindow::AddCircleTool(void) { - addLineAct->setChecked(false); - addArcAct->setChecked(false); - rotateAct->setChecked(false); - RotateTool(); - drawing->SetAddCircleToolActive(addCircleAct->isChecked()); + ClearUIToolStatesExcept(addCircleAct); + SetInternalToolStates(); +} + + +void ApplicationWindow::AddArcTool(void) +{ + ClearUIToolStatesExcept(addArcAct); + SetInternalToolStates(); } + +void ApplicationWindow::AddPolygonTool(void) +{ + ClearUIToolStatesExcept(addPolygonAct); + SetInternalToolStates(); +} + + +void ApplicationWindow::AddSplineTool(void) +{ + ClearUIToolStatesExcept(addSplineAct); + SetInternalToolStates(); +} + + void ApplicationWindow::ZoomInTool(void) { double zoomFactor = 2.0; @@ -142,16 +404,23 @@ when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin. //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y); center = Painter::QtToCartesianCoords(center); //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y); - Vector newOrigin = center - ((center - Painter::origin) / zoomFactor); + Vector newOrigin = center - ((center - Global::origin) / zoomFactor); //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y); - Painter::origin = newOrigin; + Global::origin = newOrigin; //printf("Zoom in... level going from %02f to ", Painter::zoom); - // This just zooms leaving origin intact... should zoom in at the current center! [DONE] - Painter::zoom *= zoomFactor; + // This just zooms leaving origin intact... should zoom in at the current + // center! [DONE] + Global::zoom *= zoomFactor; + Global::gridSpacing = drawing->gridPixels / Global::zoom; + drawing->UpdateGridBackground(); drawing->update(); + + zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing)); + baseUnitInput->setText(QString("%1").arg(Global::gridSpacing)); } + void ApplicationWindow::ZoomOutTool(void) { /* @@ -175,20 +444,79 @@ x 2 = (-426, -301) //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y); // Vector newOrigin = (center - Painter::origin) * zoomFactor; // Vector newOrigin = center - (Painter::origin * zoomFactor); - Vector newOrigin = center + ((Painter::origin - center) * zoomFactor); + Vector newOrigin = center + ((Global::origin - center) * zoomFactor); //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y); - Painter::origin = newOrigin; + Global::origin = newOrigin; //printf("Zoom out...\n"); - // This just zooms leaving origin intact... should zoom out at the current center! [DONE] - Painter::zoom /= zoomFactor; + // This just zooms leaving origin intact... should zoom out at the current + // center! [DONE] + Global::zoom /= zoomFactor; + Global::gridSpacing = drawing->gridPixels / Global::zoom; + drawing->UpdateGridBackground(); + drawing->update(); + + zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing)); + baseUnitInput->setText(QString("%1").arg(Global::gridSpacing)); +} + + +void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception) +{ + QAction * actionList[] = { + addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct, + addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0 + }; + + for(int i=0; actionList[i]!=0; i++) + { + if (actionList[i] != exception) + actionList[i]->setChecked(false); + } +} + + +void ApplicationWindow::SetInternalToolStates(void) +{ + // We can be sure that if we've come here, then either an active tool is + // being deactivated, or a new tool is being created. In either case, the + // old tool needs to be deleted. + Global::toolState = TSNone; + + if (addLineAct->isChecked()) + Global::tool = TTLine; + else if (addCircleAct->isChecked()) + Global::tool = TTCircle; + else if (addArcAct->isChecked()) + Global::tool = TTArc; + else if (addDimensionAct->isChecked()) + Global::tool = TTDimension; + else if (addSplineAct->isChecked()) + Global::tool = TTSpline; + else if (addPolygonAct->isChecked()) + Global::tool = TTPolygon; + else if (deleteAct->isChecked()) + Global::tool = TTDelete; + else if (mirrorAct->isChecked()) + Global::tool = TTMirror; + else if (rotateAct->isChecked()) + Global::tool = TTRotate; + else if (trimAct->isChecked()) + Global::tool = TTTrim; + else if (triangulateAct->isChecked()) + Global::tool = TTTriangulate; + else + Global::tool = TTNone; + drawing->update(); } + void ApplicationWindow::HelpAbout(void) { aboutWin->show(); } + void ApplicationWindow::Settings(void) { SettingsDialog dlg(this); @@ -202,12 +530,235 @@ void ApplicationWindow::Settings(void) WriteSettings(); } + +// +// Group a bunch of selected objects (which can include other groups) together +// or ungroup a selected group. +// +void ApplicationWindow::HandleGrouping(void) +{ + int numSelected = drawing->select.size(); + + // If nothing selected, do nothing + if (numSelected == 0) + { + statusBar()->showMessage(tr("No objects selected to make a group from.")); + return; + } + + // If it's a group that's selected, ungroup it and leave the objects in a + // selected state + if (numSelected == 1) + { + Object * obj = (Object *)drawing->select[0]; + + if (obj->type != OTContainer) + { + statusBar()->showMessage(tr("A group requires two or more selected objects.")); + return; + } + + // Need the parent of the group, we're assuming here that the parent is + // the drawing's document. Does it matter? Maybe... + // Could just stipulate that grouping like this only takes place where + // the parent of the group is the drawing's document. Makes life much + // simpler. + Container * c = (Container *)obj; + SelectAll(c->objects); + RemoveSelectedObjects(drawing->document.objects); + AddObjectsTo(drawing->document.objects, c->objects); + drawing->select.clear(); + AddObjectsTo(drawing->select, c->objects); + delete c; + statusBar()->showMessage(tr("Objects ungrouped.")); +//printf("Ungroup: document size = %li\n", drawing->document.objects.size()); + } + // Otherwise, if it's a group of 2 or more objects (which can be groups too) + // group them and select the group + else if (numSelected > 1) + { + Container * c = new Container(); + MoveSelectedObjectsTo(c->objects, drawing->document.objects); + drawing->document.objects.push_back(c); + ClearSelected(c->objects); + c->selected = true; + c->layer = Global::activeLayer; + + Rect r = drawing->GetObjectExtents((Object *)c); + c->p[0] = r.TopLeft(); + c->p[1] = r.BottomRight(); + + drawing->select.clear(); + drawing->select.push_back(c); + statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected)); +//printf("Group: document size = %li\n", drawing->document.objects.size()); + } + + drawing->update(); +} + + +void ApplicationWindow::HandleConnection(void) +{ +#if 0 +//double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2)); +//printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt); + int itemsSelected = drawing->document.ItemsSelected(); + + // If nothing selected, do nothing + if (itemsSelected == 0) + { + statusBar()->showMessage(tr("No objects selected to connect.")); + return; + } + + // If one thing selected, do nothing + if (itemsSelected == 1) + { + statusBar()->showMessage(tr("Nothing to connect object to.")); + return; + } + + // This is O(n^2 / 2) :-P + for(int i=0; idocument.SelectedItem(i); + + for(int j=i+1; jdocument.SelectedItem(j); + double t, u, v, w; + +// if ((obj1->type != OTLine) || (obj2->type != OTLine)) +// continue; + + if ((obj1->type == OTLine) && (obj2->type == OTLine)) + { +//printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2); + int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u); +//printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u); + + if (intersects) + { + //printf("Connecting objects (%X, %X)...\n", obj1, obj2); + obj1->Connect(obj2, u); + obj2->Connect(obj1, t); + } + } + else if (((obj1->type == OTLine) && (obj2->type == OTDimension)) + || ((obj2->type == OTLine) && (obj1->type == OTDimension))) + { +printf("Testing Line<->Dimension intersection...\n"); + Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2); + Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2); + + int intersects = Geometry::Intersects(line, dim, &t, &u); +printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u); + + if (intersects) + { + obj1->Connect(obj2, u); + obj2->Connect(obj1, t); + } + } + } + } +#else +#endif +} + + +void ApplicationWindow::HandleDisconnection(void) +{ +} + + +void ApplicationWindow::HandleGridSizeInPixels(int size) +{ + drawing->SetGridSize(size); + drawing->update(); +} + + +void ApplicationWindow::HandleGridSizeInBaseUnits(QString text) +{ + // Parse the text... + bool ok; + double value = text.toDouble(&ok); + + // Nothing parsable to a double, so quit... + if (!ok || value == 0) + return; + +// drawing->gridSpacing = value; +// Painter::zoom = drawing->gridPixels / drawing->gridSpacing; + Global::gridSpacing = value; + Global::zoom = drawing->gridPixels / Global::gridSpacing; + drawing->UpdateGridBackground(); + drawing->update(); +} + + +void ApplicationWindow::HandleDimensionSize(QString text) +{ +/* +This is the third input on the view toolbar; not sure what it was supposed to do... +*/ + // Parse the text... + bool ok; + double value = text.toDouble(&ok); + + // Nothing parsable to a double, so quit... + if (!ok || value == 0) + return; + +// drawing->document.ResizeAllDimensions(value); + drawing->update(); +} + +void ApplicationWindow::EditCopy(void) +{ + if (drawing->select.size() > 0) + { + DeleteContents(clipboard); + CopySelectedObjectsTo(clipboard, drawing->document.objects); + } +} + + +void ApplicationWindow::EditCut(void) +{ + if (drawing->select.size() > 0) + { + DeleteContents(clipboard); + MoveSelectedObjectsTo(clipboard, drawing->document.objects); + drawing->update(); + } +} + + +void ApplicationWindow::EditPaste(void) +{ + if (clipboard.size() > 0) + { + // We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state... + // This only moves the cut/copied from the clipboard to the drawing. +// AddObjectsTo(drawing->document.objects, clipboard); + CopyObjects(clipboard, drawing->document.objects); + drawing->update(); + } +} + + void ApplicationWindow::CreateActions(void) { exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."), QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q"))); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); + snapToGridAct = CreateAction(tr("Snap To &Grid"), tr("Snap To Grid"), tr("Snaps mouse cursor to the visible grid when moving/creating objects."), QIcon(":/res/snap-to-grid-tool.png"), QKeySequence(tr("S")), true); + connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool())); + fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."), QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true); connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle())); @@ -216,24 +767,31 @@ void ApplicationWindow::CreateActions(void) QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true); connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength())); - deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/generic-tool.png"), QKeySequence(), true); + deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true); connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool())); addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true); connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool())); - addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence("A,L"), true); + addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true); connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool())); - addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence("A,C"), true); + addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true); connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool())); - addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence("A,A"), true); + addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true); + connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool())); + + addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true); + connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool())); + + addSplineAct = CreateAction(tr("Add &Spline"), tr("Add Spline"), tr("Add a NURB spline to the drawing."), QIcon(":/res/add-spline-tool.png"), QKeySequence("A,S"), true); + connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool())); aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence()); connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout())); - rotateAct = CreateAction(tr("&Rotate Objects"), tr("Rotate"), tr("Rotate object(s) around an arbitrary center."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("R,O")), true); + rotateAct = CreateAction(tr("&Rotate Objects"), tr("Rotate"), tr("Rotate object(s) around an arbitrary center."), QIcon(":/res/rotate-tool.png"), QKeySequence(tr("R,O")), true); connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool())); zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("="))); @@ -242,20 +800,52 @@ void ApplicationWindow::CreateActions(void) zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-"))); connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool())); - fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n"))); + fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n"))); + connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew())); - fileOpenAct = CreateAction(tr("&Open Drawing"), tr("Open Drawing"), tr("Opens an existing drawing from a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+o"))); + fileOpenAct = CreateAction(tr("&Open Drawing"), tr("Open Drawing"), tr("Opens an existing drawing from a file."), QIcon(":/res/file-open.png"), QKeySequence(tr("Ctrl+o"))); + connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen())); - fileSaveAct = CreateAction(tr("&Save Drawing"), tr("Save Drawing"), tr("Saves the current drawing to a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+s"))); + fileSaveAct = CreateAction(tr("&Save Drawing"), tr("Save Drawing"), tr("Saves the current drawing to a file."), QIcon(":/res/file-save.png"), QKeySequence(tr("Ctrl+s"))); + connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave())); - fileSaveAsAct = CreateAction(tr("Save Drawing &As"), tr("Save As"), tr("Saves the current drawing to a file with a different name."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+Shift+s"))); + fileSaveAsAct = CreateAction(tr("Save Drawing &As"), tr("Save As"), tr("Saves the current drawing to a file with a different name."), QIcon(":/res/file-save-as.png"), QKeySequence(tr("Ctrl+Shift+s"))); + connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs())); - fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w"))); + fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w"))); - settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence()); + settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence()); connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings())); + groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g")); + connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping())); + + connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c")); + connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection())); + + disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d")); + connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection())); + + mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true); + connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool())); + + trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true); + connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool())); + + triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true); + connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool())); + + editCutAct = CreateAction(tr("&Cut Objects"), tr("Cut Objects"), tr("Cut objects from the drawing to the clipboard."), QIcon(":/res/editcut2.png"), QKeySequence(tr("Ctrl+x"))); + connect(editCutAct, SIGNAL(triggered()), this, SLOT(EditCut())); + + editCopyAct = CreateAction(tr("&Copy Objects"), tr("Copy Objects"), tr("Copy objects from the drawing to the clipboard."), QIcon(":/res/editcopy2.png"), QKeySequence(tr("Ctrl+c"))); + connect(editCopyAct, SIGNAL(triggered()), this, SLOT(EditCopy())); + + editPasteAct = CreateAction(tr("&Paste Objects"), tr("Paste Objects"), tr("Paste objects from the clipboard to the drawing."), QIcon(":/res/editpaste2.png"), QKeySequence(tr("Ctrl+v"))); + connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste())); + //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing... +// Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick. /* QActionGroup * group = new QActionGroup(this); group->addAction(deleteAct); group->addAction(addDimensionAct); @@ -264,11 +854,12 @@ void ApplicationWindow::CreateActions(void) group->addAction(addArcAct);//*/ } + // // Consolidates action creation from a multi-step process to a single-step one. // -QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip, - QIcon icon, QKeySequence key, bool checkable/*= false*/) +QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, + QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/) { QAction * action = new QAction(icon, name, this); action->setToolTip(tooltip); @@ -279,12 +870,14 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString return action; } + // // This is essentially the same as the previous function, but this allows more // than one key sequence to be added as key shortcuts. // -QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip, - QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/) +QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, + QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2, + bool checkable/*= false*/) { QAction * action = new QAction(icon, name, this); action->setToolTip(tooltip); @@ -298,6 +891,7 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString return action; } + void ApplicationWindow::CreateMenus(void) { QMenu * menu = menuBar()->addMenu(tr("&File")); @@ -314,15 +908,27 @@ void ApplicationWindow::CreateMenus(void) menu->addAction(zoomOutAct); menu = menuBar()->addMenu(tr("&Edit")); + menu->addAction(snapToGridAct); + menu->addAction(groupAct); menu->addAction(fixAngleAct); menu->addAction(fixLengthAct); menu->addAction(rotateAct); + menu->addAction(mirrorAct); + menu->addAction(trimAct); + menu->addAction(triangulateAct); + menu->addAction(connectAct); + menu->addAction(disconnectAct); menu->addSeparator(); + menu->addAction(editCutAct); + menu->addAction(editCopyAct); + menu->addAction(editPasteAct); menu->addAction(deleteAct); menu->addSeparator(); menu->addAction(addLineAct); menu->addAction(addCircleAct); menu->addAction(addArcAct); + menu->addAction(addPolygonAct); + menu->addAction(addSplineAct); menu->addAction(addDimensionAct); menu->addSeparator(); menu->addAction(settingsAct); @@ -331,44 +937,89 @@ void ApplicationWindow::CreateMenus(void) menu->addAction(aboutAct); } + void ApplicationWindow::CreateToolbars(void) { QToolBar * toolbar = addToolBar(tr("File")); - toolbar->addAction(exitAct); + toolbar->setObjectName("File"); // Needed for saveState() + toolbar->addAction(fileNewAct); + toolbar->addAction(fileOpenAct); + toolbar->addAction(fileSaveAct); + toolbar->addAction(fileSaveAsAct); + toolbar->addAction(fileCloseAct); +// toolbar->addAction(exitAct); toolbar = addToolBar(tr("View")); + toolbar->setObjectName("View"); toolbar->addAction(zoomInAct); toolbar->addAction(zoomOutAct); + QSpinBox * spinbox = new QSpinBox; + toolbar->addWidget(spinbox); +// QLineEdit * lineedit = new QLineEdit; + toolbar->addWidget(baseUnitInput); + toolbar->addWidget(dimensionSizeInput); + toolbar = addToolBar(tr("Edit")); + toolbar->setObjectName("Edit"); + toolbar->addAction(snapToGridAct); + toolbar->addAction(groupAct); toolbar->addAction(fixAngleAct); toolbar->addAction(fixLengthAct); toolbar->addAction(rotateAct); + toolbar->addAction(mirrorAct); + toolbar->addAction(trimAct); + toolbar->addAction(triangulateAct); + toolbar->addAction(editCutAct); + toolbar->addAction(editCopyAct); + toolbar->addAction(editPasteAct); toolbar->addAction(deleteAct); + toolbar->addAction(connectAct); + toolbar->addAction(disconnectAct); + toolbar->addSeparator(); toolbar->addAction(addLineAct); toolbar->addAction(addCircleAct); toolbar->addAction(addArcAct); + toolbar->addAction(addPolygonAct); + toolbar->addAction(addSplineAct); toolbar->addAction(addDimensionAct); + + spinbox->setRange(4, 256); + spinbox->setValue(12); + baseUnitInput->setText("12"); + connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int))); + connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString))); + connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString))); + + PenWidget * pw = new PenWidget(); + toolbar = addToolBar(tr("Pen")); + toolbar->setObjectName(tr("Pen")); + toolbar->addWidget(pw); + connect(drawing, SIGNAL(ObjectSelected(Object *)), pw, SLOT(SetFields(Object *))); + connect(pw, SIGNAL(WidthSelected(float)), drawing, SLOT(HandlePenWidth(float))); + connect(pw, SIGNAL(StyleSelected(int)), drawing, SLOT(HandlePenStyle(int))); + connect(pw, SIGNAL(ColorSelected(uint32_t)), drawing, SLOT(HandlePenColor(uint32_t))); } + void ApplicationWindow::ReadSettings(void) { QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint(); QSize size = settings.value("size", QSize(400, 400)).toSize(); drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool(); + snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool()); resize(size); move(pos); -// pos = settings.value("charWndPos", QPoint(0, 0)).toPoint(); -// size = settings.value("charWndSize", QSize(200, 200)).toSize(); -// ((TTEdit *)qApp)->charWnd->resize(size); -// ((TTEdit *)qApp)->charWnd->move(pos); + restoreState(settings.value("windowState").toByteArray()); } + void ApplicationWindow::WriteSettings(void) { settings.setValue("pos", pos()); settings.setValue("size", size()); + settings.setValue("windowState", saveState()); settings.setValue("useAntialiasing", drawing->useAntialiasing); -// settings.setValue("charWndPos", ((TTEdit *)qApp)->charWnd->pos()); -// settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size()); + settings.setValue("snapToGrid", snapToGridAct->isChecked()); } +