]> Shamusworld >> Repos - architektonas/blobdiff - src/applicationwindow.cpp
Added Parallel tool + command processing.
[architektonas] / src / applicationwindow.cpp
index 9064595a5f5feba189e0139ba5e8c18026b9a92e..d3f014ff05a2ab51060838b5a0be4f665b800b4f 100644 (file)
 
 #include "applicationwindow.h"
 
+#include <QPrintPreviewDialog>
 #include "about.h"
 #include "blockwidget.h"
+#include "commandprocessor.h"
+#include "consolewidget.h"
 #include "drawingview.h"
 #include "fileio.h"
 #include "generaltab.h"
 #include "structs.h"
 #include "utils.h"
 
-
 // Class variables
 DrawingView * ApplicationWindow::drawing;
 
-
 ApplicationWindow::ApplicationWindow():
        baseUnitInput(new QLineEdit),
        dimensionSizeInput(new QLineEdit),
@@ -59,10 +60,8 @@ ApplicationWindow::ApplicationWindow():
 
        aboutWin = new AboutWindow(this);
 
-//     ((TTEdit *)qApp)->charWnd = new CharWindow(this);
-
        setWindowIcon(QIcon(":/res/atns-icon.png"));
-       setWindowTitle("Architektonas");
+//     setWindowTitle("Architektonas");
 
        CreateActions();
        CreateMenus();
@@ -81,17 +80,25 @@ ApplicationWindow::ApplicationWindow():
        ObjectWidget * ow = new ObjectWidget;
        dock3->setWidget(ow);
        addDockWidget(Qt::RightDockWidgetArea, dock3);
+       QDockWidget * dock4 = new QDockWidget(tr("Command"), this);
+       cw = new ConsoleWidget;
+       dock4->setWidget(cw);
+       addDockWidget(Qt::BottomDockWidgetArea, dock4);
+
        // Needed for saveState()
        dock1->setObjectName("Layers");
        dock2->setObjectName("Blocks");
        dock3->setObjectName("Object");
+       dock4->setObjectName("Commands");
 
        // Create status bar
-       zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
+       zoomIndicator = new QLabel("Zoom: 100% Grid: 12.0\" BU: Inch");
        statusBar()->addPermanentWidget(zoomIndicator);
        statusBar()->showMessage(tr("Ready"));
 
        ReadSettings();
+       // Make sure the bottom left corner gets owned by the right side:
+       setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
        setUnifiedTitleAndToolBarOnMac(true);
        Global::font =  new QFont("Verdana", 15, QFont::Bold);
 
@@ -101,8 +108,10 @@ ApplicationWindow::ApplicationWindow():
        connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload()));
 
        connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
-}
+       connect(drawing, SIGNAL(NeedZoomUpdate()), this, SLOT(UpdateZoom()));
 
+       connect(cw->cmdProc, SIGNAL(UpdateNeeded()), this, SLOT(UpdateFromCommand()));
+}
 
 void ApplicationWindow::closeEvent(QCloseEvent * event)
 {
@@ -111,7 +120,6 @@ void ApplicationWindow::closeEvent(QCloseEvent * event)
        //Do we have a memory leak here if we don't delete the font in the Object???
 }
 
-
 void ApplicationWindow::FileNew(void)
 {
        // Warn the user if drawing has changed and hasn't been saved...
@@ -148,11 +156,11 @@ void ApplicationWindow::FileNew(void)
        drawing->dirty = false;
        drawing->update();
        documentName.clear();
-       setWindowTitle("Architektonas - Untitled");
+//     setWindowTitle("Architektonas - Untitled");
+       setWindowFilePath(documentName);
        statusBar()->showMessage(tr("New drawing is ready."));
 }
 
-
 void ApplicationWindow::FileOpen(void)
 {
        QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
@@ -162,6 +170,21 @@ void ApplicationWindow::FileOpen(void)
        if (filename.isEmpty())
                return;
 
+       LoadFile(filename);
+}
+
+void ApplicationWindow::FileOpenRecent(void)
+{
+       QAction * action = qobject_cast<QAction *>(sender());
+
+       if (!action)
+               return;
+
+       LoadFile(action->data().toString());
+}
+
+void ApplicationWindow::LoadFile(QString filename)
+{
        FILE * file = fopen(filename.toUtf8().data(), "r");
 
        if (file == 0)
@@ -188,7 +211,6 @@ void ApplicationWindow::FileOpen(void)
                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();
@@ -199,11 +221,11 @@ void ApplicationWindow::FileOpen(void)
        drawing->dirty = false;
        drawing->update();
        documentName = filename;
-       setWindowTitle(QString("Architektonas - %1").arg(documentName));
+//     setWindowTitle(QString("Architektonas - %1").arg(documentName));
+       AdjustMRU(filename);
        statusBar()->showMessage(tr("Drawing loaded."));
 }
 
-
 void ApplicationWindow::FileSave(void)
 {
        if (documentName.isEmpty())
@@ -238,11 +260,11 @@ void ApplicationWindow::FileSave(void)
        }
 
        drawing->dirty = false;
-       setWindowTitle(QString("Architektonas - %1").arg(documentName));
+//     setWindowTitle(QString("Architektonas - %1").arg(documentName));
+       AdjustMRU(documentName);
        statusBar()->showMessage(tr("Drawing saved."));
 }
 
-
 void ApplicationWindow::FileSaveAs(void)
 {
        QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
@@ -255,40 +277,119 @@ void ApplicationWindow::FileSaveAs(void)
        }
 }
 
+void ApplicationWindow::PrintPreview(void)
+{
+       QPrintPreviewDialog * dlg = new QPrintPreviewDialog(this);
+
+       connect(dlg, SIGNAL(paintRequested(QPrinter *)), this, SLOT(HandlePrintRequest(QPrinter *)));
+
+       dlg->exec();
+}
+
+void ApplicationWindow::HandlePrintRequest(QPrinter * printer)
+{
+       QPainter qtPainter(printer);
+       Painter painter(&qtPainter);
+
+       // Save vars for screen
+       Point originSave = Global::origin;
+       double zoomSave = Global::zoom;
+       Vector screenSizeSave = Global::screenSize;
 
+       // Adjust zoom + origin to fit the paper (or NxM pages if we have 'em)
+       Rect r = drawing->GetObjectExtents((Object *)(&(drawing->document)));
+
+       QPageLayout pageLayout = printer->pageLayout();
+       QRect pageRect = pageLayout.paintRectPixels(printer->resolution());
+
+       Global::origin = r.BottomLeft();
+       Global::screenSize.x = pageRect.width();
+       Global::screenSize.y = pageRect.height();
+
+       double xScale = (double)pageRect.width() / r.Width();
+       double yScale = (double)pageRect.height() / r.Height();
+       Global::zoom = qMin(xScale, yScale);
+
+       if (xScale < yScale)
+               Global::origin.y -= (((double)pageRect.height() / Global::zoom) - r.Height()) / 2.0;
+       else
+               Global::origin.x -= (((double)pageRect.width() / Global::zoom) - r.Width()) / 2.0;
+
+       // Do object rendering...
+       for(int i=0; i<Global::numLayers; i++)
+               drawing->RenderObjects(&painter, drawing->document.objects, i);
+
+       // Restore vars
+       Global::origin = originSave;
+       Global::zoom = zoomSave;
+       Global::screenSize = screenSizeSave;
+}
+
+//
+// Right-click menu
+//
 void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
 {
+       // Proof of concept, still need to code up the real thing
        QMenu menu(this);
+
+       VPVector hovered = drawing->GetHovered();
+
+       if ((drawing->select.size() > 0) || (hovered.size() > 0))
+       {
+               QMenu * layerMenu = menu.addMenu("To layer");
+
+               layerAct.clear();
+
+               for(int i=0; i<Global::numLayers; i++)
+               {
+                       QAction * act = new QAction(QIcon(), Global::layerName[i].c_str(), this);
+                       act->setData(i);
+                       layerMenu->addAction(act);
+                       layerAct.append(act);
+                       connect(act, SIGNAL(triggered()), this, SLOT(MoveToLayer()));
+               }
+       }
+
        menu.addAction(mirrorAct);
        menu.addAction(rotateAct);
        menu.addAction(trimAct);
        menu.exec(event->globalPos());
 }
 
+void ApplicationWindow::MoveToLayer(void)
+{
+       QAction * act = qobject_cast<QAction *>(sender());
+
+       drawing->MoveSelectedToLayer(act->data().toInt());
+       drawing->update();
+}
+
+void ApplicationWindow::UpdateFromCommand(void)
+{
+       cw->SetToolPrompt();
+       drawing->update();
+}
 
 void ApplicationWindow::SnapToGridTool(void)
 {
        Global::snapToGrid = snapToGridAct->isChecked();
 }
 
-
 void ApplicationWindow::FixAngle(void)
 {
        Global::fixedAngle = fixAngleAct->isChecked();
 }
 
-
 void ApplicationWindow::FixLength(void)
 {
        Global::fixedLength = fixLengthAct->isChecked();
 }
 
-
 void ApplicationWindow::DeleteTool(void)
 {
        // 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);
@@ -300,16 +401,15 @@ void ApplicationWindow::DeleteTool(void)
        // Otherwise, toggle the state of the tool
        ClearUIToolStatesExcept(deleteAct);
        SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
 }
 
-
 void ApplicationWindow::DimensionTool(void)
 {
        ClearUIToolStatesExcept(addDimensionAct);
        SetInternalToolStates();
 }
 
-
 void ApplicationWindow::RotateTool(void)
 {
        ClearUIToolStatesExcept(rotateAct);
@@ -321,7 +421,6 @@ void ApplicationWindow::RotateTool(void)
        SetInternalToolStates();
 }
 
-
 void ApplicationWindow::MirrorTool(void)
 {
        ClearUIToolStatesExcept(mirrorAct);
@@ -333,13 +432,19 @@ void ApplicationWindow::MirrorTool(void)
        SetInternalToolStates();
 }
 
-
 void ApplicationWindow::TrimTool(void)
 {
        ClearUIToolStatesExcept(trimAct);
        SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
 }
 
+void ApplicationWindow::ParallelTool(void)
+{
+       ClearUIToolStatesExcept(parallelAct);
+       SetInternalToolStates();
+       Global::toolSuppressCrosshair = true;
+}
 
 void ApplicationWindow::TriangulateTool(void)
 {
@@ -347,124 +452,105 @@ void ApplicationWindow::TriangulateTool(void)
        SetInternalToolStates();
 }
 
-
 void ApplicationWindow::AddLineTool(void)
 {
        ClearUIToolStatesExcept(addLineAct);
        SetInternalToolStates();
 }
 
-
 void ApplicationWindow::AddCircleTool(void)
 {
        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;
-/*
-We need to find the center of the screen, then figure out where the new corner
-will be in the zoomed in window.
-
-So we know in Qt coords, the center is found via:
-size.width()  / 2 --> xCenter
-size.height() / 2 --> yCenter
-
-transform x/yCenter to Cartesian coordinates. So far, so good.
-
-when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
-(after subtracting from center, that is...)
-*/
+       double zoomFactor = 1.20;
        QSize size = drawing->size();
-       Vector center(size.width() / 2.0, size.height() / 2.0);
-//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 - Global::origin) / zoomFactor);
-//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
-       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]
+       Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
+
+       Global::origin = center - ((center - Global::origin) / zoomFactor);
        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));
+       UpdateZoom();
 }
 
-
 void ApplicationWindow::ZoomOutTool(void)
 {
-/*
-Ok, real example.
-center = (436, 311)
-origin = (223, 160.5)
-newOrigin should be (-10, -10)
-Why isn't it?
-
-center - origin = (213, 150.5)
-origin - center = (-213, -150.5)
-x 2 = (-426, -301)
-+ center = (-10, -10)
-
-*/
-       double zoomFactor = 2.0;
+       double zoomFactor = 1.20;
        QSize size = drawing->size();
-       Vector center(size.width() / 2.0, size.height() / 2.0);
-//printf("Zoom out... 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 - Painter::origin) * zoomFactor;
-//     Vector newOrigin = center - (Painter::origin * zoomFactor);
-       Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
-//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
-       Global::origin = newOrigin;
-//printf("Zoom out...\n");
-       // This just zooms leaving origin intact... should zoom out at the current
-       // center! [DONE]
+       Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
+
+       Global::origin = center + ((Global::origin - center) * zoomFactor);
        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));
+       UpdateZoom();
 }
 
+void ApplicationWindow::UpdateZoom(void)
+{
+       // And now, a bunch of heuristics to select the right grid size--autogrid!
+       // :-P
+       if (Global::zoom < 0.25)
+               Global::gridSpacing = 48.0;
+       else if (Global::zoom >= 0.25 && Global::zoom < 0.50)
+               Global::gridSpacing = 36.0;
+       else if (Global::zoom >= 0.50 && Global::zoom < 1.00)
+               Global::gridSpacing = 24.0;
+       else if (Global::zoom >= 1.00 && Global::zoom < 2.00)
+               Global::gridSpacing = 12.0;
+       else if (Global::zoom >= 2.00 && Global::zoom < 4.00)
+               Global::gridSpacing = 6.0;
+       else if (Global::zoom >= 4.00 && Global::zoom < 8.00)
+               Global::gridSpacing = 3.0;
+       else if (Global::zoom >= 8.00 && Global::zoom < 16.00)
+               Global::gridSpacing = 1.0;
+       else if (Global::zoom >= 16.00 && Global::zoom < 32.00)
+               Global::gridSpacing = 0.5;
+       else if (Global::zoom >= 32.00 && Global::zoom < 64.00)
+               Global::gridSpacing = 0.25;
+       else if (Global::zoom >= 64.00 && Global::zoom < 128.00)
+               Global::gridSpacing = 0.125;
+       else if (Global::zoom >= 128.00 && Global::zoom < 256.00)
+               Global::gridSpacing = 0.0625;
+       else if (Global::zoom >= 256.00 && Global::zoom < 512.00)
+               Global::gridSpacing = 0.03125;
+       else
+               Global::gridSpacing = 0.015625;
+
+       drawing->update();
+
+       zoomIndicator->setText(QString("Zoom: %1% Grid: %2\" BU: Inch").arg(Global::zoom * 100.0).arg(Global::gridSpacing));
+
+       // This is the problem...  Changing this causes the state to update itself again, screwing up the origin...  !!! FIX !!! (commented out for now)
+//     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
+               addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct,
+               triangulateAct, 0
        };
 
        for(int i=0; actionList[i]!=0; i++)
@@ -474,13 +560,14 @@ void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
        }
 }
 
-
 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.
+       // being deactivated, or a new tool is being activated.  In either case,
+       // the tool state needs to be reset.  Also, we reset the crosshair
+       // suppression flag.
        Global::toolState = TSNone;
+       Global::toolSuppressCrosshair = false;
 
        if (addLineAct->isChecked())
                Global::tool = TTLine;
@@ -502,21 +589,22 @@ void ApplicationWindow::SetInternalToolStates(void)
                Global::tool = TTRotate;
        else if (trimAct->isChecked())
                Global::tool = TTTrim;
+       else if (parallelAct->isChecked())
+               Global::tool = TTParallel;
        else if (triangulateAct->isChecked())
                Global::tool = TTTriangulate;
        else
                Global::tool = TTNone;
 
+       cw->SetToolPrompt();//cw->cmdline);
        drawing->update();
 }
 
-
 void ApplicationWindow::HelpAbout(void)
 {
        aboutWin->show();
 }
 
-
 void ApplicationWindow::Settings(void)
 {
        SettingsDialog dlg(this);
@@ -530,7 +618,6 @@ void ApplicationWindow::Settings(void)
        WriteSettings();
 }
 
-
 //
 // Group a bunch of selected objects (which can include other groups) together
 // or ungroup a selected group.
@@ -597,7 +684,6 @@ void ApplicationWindow::HandleGrouping(void)
        drawing->update();
 }
 
-
 void ApplicationWindow::HandleConnection(void)
 {
 #if 0
@@ -667,19 +753,16 @@ printf("   -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
 #endif
 }
 
-
 void ApplicationWindow::HandleDisconnection(void)
 {
 }
 
-
-void ApplicationWindow::HandleGridSizeInPixels(int size)
+void ApplicationWindow::HandleGridSizeInPixels(int /*size*/)
 {
-       drawing->SetGridSize(size);
+//     drawing->SetGridSize((uint32_t)size);
        drawing->update();
 }
 
-
 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
 {
        // Parse the text...
@@ -690,15 +773,11 @@ void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
        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)
 {
 /*
@@ -725,7 +804,6 @@ void ApplicationWindow::EditCopy(void)
        }
 }
 
-
 void ApplicationWindow::EditCut(void)
 {
        if (drawing->select.size() > 0)
@@ -736,7 +814,6 @@ void ApplicationWindow::EditCut(void)
        }
 }
 
-
 void ApplicationWindow::EditPaste(void)
 {
        if (clipboard.size() > 0)
@@ -749,7 +826,6 @@ void ApplicationWindow::EditPaste(void)
        }
 }
 
-
 //
 // Select all *visible* objects.  If an object is on a layer that is not
 // visible, skip it.
@@ -761,7 +837,6 @@ void ApplicationWindow::SelectAllObjects(void)
        drawing->update();
 }
 
-
 void ApplicationWindow::CreateActions(void)
 {
        exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
@@ -844,6 +919,9 @@ void ApplicationWindow::CreateActions(void)
        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()));
 
+       parallelAct = CreateAction(tr("&Parallel"), tr("Parallel"), tr("Create copies of objects parallel to the original."), QIcon(":/res/parallel-tool.png"), QKeySequence("p,l"), true);
+       connect(parallelAct, SIGNAL(triggered()), this, SLOT(ParallelTool()));
+
        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()));
 
@@ -859,6 +937,9 @@ void ApplicationWindow::CreateActions(void)
        selectAllAct = CreateAction(tr("Select &All"), tr("Select All Objects"), tr("Select all objects in the drawing."), QIcon(), QKeySequence(tr("Ctrl+a")));
        connect(selectAllAct, SIGNAL(triggered()), this, SLOT(SelectAllObjects()));
 
+       printPreviewAct = CreateAction(tr("&Print Preview"), tr("Print Preview"), tr("Shows preview of printing operation."), QIcon(":/res/print-preview.png"), QKeySequence(tr("Ctrl+p")));
+       connect(printPreviewAct, SIGNAL(triggered()), this, SLOT(PrintPreview()));
+
 //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);
@@ -867,8 +948,15 @@ void ApplicationWindow::CreateActions(void)
        group->addAction(addLineAct);
        group->addAction(addCircleAct);
        group->addAction(addArcAct);//*/
-}
 
+       for(int i=0; i<MRU_MAX; i++)
+       {
+               QAction * rfa = new QAction(this);
+               rfa->setVisible(false);
+               connect(rfa, SIGNAL(triggered()), this, SLOT(FileOpenRecent()));
+               mruAct.append(rfa);
+       }
+}
 
 //
 // Consolidates action creation from a multi-step process to a single-step one.
@@ -885,7 +973,6 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
        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.
@@ -906,16 +993,25 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
        return action;
 }
 
-
 void ApplicationWindow::CreateMenus(void)
 {
        QMenu * menu = menuBar()->addMenu(tr("&File"));
        menu->addAction(fileNewAct);
        menu->addAction(fileOpenAct);
+
+       QMenu * recentMenu = menu->addMenu(tr("Open &Recent"));
+
+       for(int i=0; i<MRU_MAX; i++)
+               recentMenu->addAction(mruAct.at(i));
+
+       UpdateMRUActionList();
+
        menu->addAction(fileSaveAct);
        menu->addAction(fileSaveAsAct);
        menu->addAction(fileCloseAct);
        menu->addSeparator();
+       menu->addAction(printPreviewAct);
+       menu->addSeparator();
        menu->addAction(exitAct);
 
        menu = menuBar()->addMenu(tr("&View"));
@@ -930,6 +1026,7 @@ void ApplicationWindow::CreateMenus(void)
        menu->addAction(rotateAct);
        menu->addAction(mirrorAct);
        menu->addAction(trimAct);
+       menu->addAction(parallelAct);
        menu->addAction(triangulateAct);
        menu->addAction(connectAct);
        menu->addAction(disconnectAct);
@@ -953,7 +1050,6 @@ void ApplicationWindow::CreateMenus(void)
        menu->addAction(aboutAct);
 }
 
-
 void ApplicationWindow::CreateToolbars(void)
 {
        QToolBar * toolbar = addToolBar(tr("File"));
@@ -963,7 +1059,6 @@ void ApplicationWindow::CreateToolbars(void)
        toolbar->addAction(fileSaveAct);
        toolbar->addAction(fileSaveAsAct);
        toolbar->addAction(fileCloseAct);
-//     toolbar->addAction(exitAct);
 
        toolbar = addToolBar(tr("View"));
        toolbar->setObjectName("View");
@@ -972,7 +1067,6 @@ void ApplicationWindow::CreateToolbars(void)
 
        QSpinBox * spinbox = new QSpinBox;
        toolbar->addWidget(spinbox);
-//     QLineEdit * lineedit = new QLineEdit;
        toolbar->addWidget(baseUnitInput);
        toolbar->addWidget(dimensionSizeInput);
 
@@ -985,6 +1079,7 @@ void ApplicationWindow::CreateToolbars(void)
        toolbar->addAction(rotateAct);
        toolbar->addAction(mirrorAct);
        toolbar->addAction(trimAct);
+       toolbar->addAction(parallelAct);
        toolbar->addAction(triangulateAct);
        toolbar->addAction(editCutAct);
        toolbar->addAction(editCopyAct);
@@ -1012,13 +1107,10 @@ void ApplicationWindow::CreateToolbars(void)
        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)));
-       connect(pw, SIGNAL(StampSelected(void)), drawing, SLOT(HandlePenStamp(void)));
+       connect(pw->tbStamp, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenStamp(QAction *)));
+       connect(pw->tbDropper, SIGNAL(triggered(QAction *)), drawing, SLOT(HandlePenDropper(QAction *)));
 }
 
-
 void ApplicationWindow::ReadSettings(void)
 {
        QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
@@ -1030,7 +1122,6 @@ void ApplicationWindow::ReadSettings(void)
        restoreState(settings.value("windowState").toByteArray());
 }
 
-
 void ApplicationWindow::WriteSettings(void)
 {
        settings.setValue("pos", pos());
@@ -1040,3 +1131,37 @@ void ApplicationWindow::WriteSettings(void)
        settings.setValue("snapToGrid", snapToGridAct->isChecked());
 }
 
+void ApplicationWindow::UpdateMRUActionList(void)
+{
+       QStringList mruFilePaths = settings.value("recentFiles").toStringList();
+
+       int mruSize = (mruFilePaths.size() <= MRU_MAX ? mruFilePaths.size() : MRU_MAX);
+
+       for(int i=0; i<mruSize; i++)
+       {
+               QString filename = QFileInfo(mruFilePaths.at(i)).fileName();
+               mruAct.at(i)->setText(filename);
+               mruAct.at(i)->setData(mruFilePaths.at(i));
+               mruAct.at(i)->setVisible(true);
+       }
+
+       for(int i=mruSize; i<MRU_MAX; i++)
+               mruAct.at(i)->setVisible(false);
+}
+
+void ApplicationWindow::AdjustMRU(const QString & filePath)
+{
+       documentName = filePath;
+       setWindowFilePath(documentName);
+
+       QStringList mruFilePaths = settings.value("recentFiles").toStringList();
+       mruFilePaths.removeAll(filePath);
+       mruFilePaths.prepend(filePath);
+
+       while (mruFilePaths.size() > MRU_MAX)
+               mruFilePaths.removeLast();
+
+       settings.setValue("recentFiles", mruFilePaths);
+
+       UpdateMRUActionList();
+}