]> Shamusworld >> Repos - architektonas/blobdiff - src/applicationwindow.cpp
Fix object selection to work while in snap mode.
[architektonas] / src / applicationwindow.cpp
index b156d15fa90ab926f2ea92098b380b9beef57fa1..f9362ca5967071d34a0202608d9759249c32b759 100644 (file)
@@ -5,11 +5,13 @@
 // (C) 2011 Underground Software
 // See the README and GPLv3 files for licensing and warranty information
 //
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
 //
 // 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
 //
 
 // FIXED:
 
 #include "applicationwindow.h"
 
+#include "about.h"
+#include "blockwidget.h"
 #include "drawingview.h"
-
-
-ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas")
+#include "drawarcaction.h"
+#include "drawcircleaction.h"
+#include "drawdimensionaction.h"
+#include "drawlineaction.h"
+#include "fileio.h"
+#include "generaltab.h"
+#include "layerwidget.h"
+#include "painter.h"
+#include "settingsdialog.h"
+
+
+ApplicationWindow::ApplicationWindow():
+       baseUnitInput(new QLineEdit),
+       dimensionSizeInput(new QLineEdit),
+       settings("Underground Software", "Architektonas")
 {
        drawing = new DrawingView(this);
+       drawing->setMouseTracking(true);                // We want *all* mouse events...!
        setCentralWidget(drawing);
 
+       aboutWin = new AboutWindow(this);
+
 //     ((TTEdit *)qApp)->charWnd = new CharWindow(this);
 
        setWindowIcon(QIcon(":/res/atns-icon.png"));
@@ -43,21 +62,30 @@ ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Archit
        CreateMenus();
        CreateToolbars();
 
+       // 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);
+       // Needed for saveState()
+       dock1->setObjectName("Layers");
+       dock2->setObjectName("Blocks");
+
        //      Create status bar
+       zoomIndicator = new QLabel("Grid: 12.0\" Zoom: 12.5%");
+       statusBar()->addPermanentWidget(zoomIndicator);
        statusBar()->showMessage(tr("Ready"));
 
        ReadSettings();
-
-//     connect(textEdit->document(), SIGNAL(contentsChanged()),
-//                     this, SLOT(documentWasModified()));
-
-//     setCurrentFile("");
        setUnifiedTitleAndToolBarOnMac(true);
-
-//     ((TTEdit *)qApp)->charWnd->show();//eh?
        Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
 }
 
+
 void ApplicationWindow::closeEvent(QCloseEvent * event)
 {
        WriteSettings();
@@ -65,31 +93,455 @@ void ApplicationWindow::closeEvent(QCloseEvent * event)
        //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)
+{
+       // Should warn the user if drawing hasn't been saved...
+       drawing->document.Clear();
+       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)"));
+       FILE * file = fopen(filename.toAscii().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(Vector(0, 0));
+       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();
+               return;
+       }
+
+printf("FileOpen: container size = %li\n", container.objects.size());
+       drawing->document = container;
+       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.toAscii().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.toAscii().data());
+               return;
+       }
+
+       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::SnapToGridTool(void)
+{
+       Object::SetSnapMode(snapToGridAct->isChecked());
+}
+
 
 void ApplicationWindow::FixAngle(void)
 {
        Object::SetFixedAngle(fixAngleAct->isChecked());
 }
 
+
 void ApplicationWindow::FixLength(void)
 {
        Object::SetFixedLength(fixLengthAct->isChecked());
 }
 
+
+// We want certain tools to be exclusive, and this approach isn't working correctly...
 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->document.ItemsSelected() > 0)
+       {
+               drawing->document.DeleteSelectedItems();
+               drawing->update();
+               deleteAct->setChecked(false);
+               return;
+       }
+
+       // Otherwise, toggle the state of the tool
+       ClearUIToolStatesExcept(deleteAct);
+       SetInternalToolStates();
+}
+
+
+void ApplicationWindow::DimensionTool(void)
+{
+       ClearUIToolStatesExcept(addDimensionAct);
+       SetInternalToolStates();
+}
+
+
+void ApplicationWindow::RotateTool(void)
+{
+       ClearUIToolStatesExcept(rotateAct);
+       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::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...)
+*/
+       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 - Painter::origin) / zoomFactor);
+//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
+       Painter::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]
+       // This should actually be calculated by drawing->gridPixels / grid size.
+       Painter::zoom *= zoomFactor;
+//     drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
+       Object::gridSpacing = drawing->gridPixels / Painter::zoom;
+//     zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
+//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
+       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
+       drawing->UpdateGridBackground();
+       drawing->update();
+
+//     baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
+       baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
+}
+
+
+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;
+       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 + ((Painter::origin - center) * zoomFactor);
+//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
+       Painter::origin = newOrigin;
+//printf("Zoom out...\n");
+       // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
+       Painter::zoom /= zoomFactor;
+//     drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
+       Object::gridSpacing = drawing->gridPixels / Painter::zoom;
+//     zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
+//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
+       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
+       drawing->UpdateGridBackground();
+       drawing->update();
+
+//     baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
+       baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
+}
+
+
+void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
+{
+       if (exception != addArcAct)
+               addArcAct->setChecked(false);
+
+       if (exception != addCircleAct)
+               addCircleAct->setChecked(false);
+
+       if (exception != addDimensionAct)
+               addDimensionAct->setChecked(false);
+
+       if (exception != addLineAct)
+               addLineAct->setChecked(false);
+
+       if (exception != addPolygonAct)
+               addPolygonAct->setChecked(false);
+
+       if (exception != deleteAct)
+               deleteAct->setChecked(false);
+
+       if (exception != rotateAct)
+               rotateAct->setChecked(false);
+}
+
+
+void ApplicationWindow::SetInternalToolStates(void)
 {
        Object::SetDeleteActive(deleteAct->isChecked());
+       Object::SetDimensionActive(addDimensionAct->isChecked());
+       drawing->SetRotateToolActive(rotateAct->isChecked());
+
+       // 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.
+       if (drawing->toolAction)
+       {
+               delete drawing->toolAction;
+               drawing->toolAction = NULL;
+       }
+
+#if 0
+       drawing->SetAddLineToolActive(addLineAct->isChecked());
+       drawing->SetAddCircleToolActive(addCircleAct->isChecked());
+       drawing->SetAddArcToolActive(addArcAct->isChecked());
+       drawing->SetAddDimensionToolActive(addDimensionAct->isChecked());
+#else
+       drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
+       drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
+       drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
+       drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
+#endif
+
+       update();
+}
+
+
+void ApplicationWindow::HelpAbout(void)
+{
+       aboutWin->show();
+}
+
+
+void ApplicationWindow::Settings(void)
+{
+       SettingsDialog dlg(this);
+       dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
+
+       if (dlg.exec() == false)
+               return;
+
+       // Deal with stuff here (since user hit "OK" button...)
+       drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
+       WriteSettings();
 }
 
+
+//
+// Group a bunch of selected objects (which can include other groups) together
+// or ungroup a selected group.
+//
+void ApplicationWindow::HandleGrouping(void)
+{
+       int itemsSelected = drawing->document.ItemsSelected();
+
+       // If nothing selected, do nothing
+       if (itemsSelected == 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 (itemsSelected == 1)
+       {
+               Object * object = drawing->document.SelectedItem(0);
+
+#if 0
+if (object == NULL)
+       printf("SelectedItem = NULL!\n");
+else
+       printf("SelectedItem = %08X, type = %i\n", object, object->type);
+#endif
+
+               if (object == NULL || object->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 *)object)->SelectAll();
+               ((Container *)object)->MoveContentsTo(&(drawing->document));
+               drawing->document.Delete(object);
+               statusBar()->showMessage(tr("Objects ungrouped."));
+       }
+       // Otherwise, if it's a group of 2 or more objects (which can be groups too)
+       // group them and select the group
+       else if (itemsSelected > 1)
+       {
+               Container * container = new Container(Vector(), &(drawing->document));
+               drawing->document.MoveSelectedContentsTo(container);
+               drawing->document.Add(container);
+               container->DeselectAll();
+               container->state = OSSelected;
+               statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
+       }
+
+       drawing->update();
+}
+
+
+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;
+       Object::gridSpacing = value;
+       Painter::zoom = drawing->gridPixels / Object::gridSpacing;
+       drawing->UpdateGridBackground();
+       drawing->update();
+}
+
+
+void ApplicationWindow::HandleDimensionSize(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->document.ResizeAllDimensions(value);
+//     drawing->gridSpacing = value;
+//     Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
+//     drawing->UpdateGridBackground();
+       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()));
@@ -98,18 +550,71 @@ 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/generic-tool.png"), QKeySequence());
+       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/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/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/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()));
+
+       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/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("=")));
+       connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
+
+       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")));
+       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")));
+       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")));
+       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")));
+       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")));
+
+       settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
 
-       addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds a line to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       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()));
 
-       addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds a circle to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
 
-       addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds an arc to the drawing."), QIcon(":/res/generic-tool.png"), QKeySequence());
+       disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
+
+//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);
+       group->addAction(addLineAct);
+       group->addAction(addCircleAct);
+       group->addAction(addArcAct);//*/
 }
 
+
 //
 // Consolidates action creation from a multi-step process to a single-step one.
 //
@@ -125,11 +630,12 @@ 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::CreateAction2(QString name, QString tooltip, QString statustip,
+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);
@@ -144,70 +650,107 @@ QAction * ApplicationWindow::CreateAction2(QString name, QString tooltip, QStrin
        return action;
 }
 
+
 void ApplicationWindow::CreateMenus(void)
 {
        QMenu * menu = menuBar()->addMenu(tr("&File"));
-//     fileMenu->addAction(newAct);
-//     fileMenu->addAction(openAct);
-//     fileMenu->addAction(saveAct);
-//     fileMenu->addAction(saveAsAct);
-//     fileMenu->addSeparator();
+       menu->addAction(fileNewAct);
+       menu->addAction(fileOpenAct);
+       menu->addAction(fileSaveAct);
+       menu->addAction(fileSaveAsAct);
+       menu->addAction(fileCloseAct);
+       menu->addSeparator();
        menu->addAction(exitAct);
 
+       menu = menuBar()->addMenu(tr("&View"));
+       menu->addAction(zoomInAct);
+       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(connectAct);
+       menu->addAction(disconnectAct);
        menu->addSeparator();
        menu->addAction(deleteAct);
        menu->addSeparator();
        menu->addAction(addLineAct);
        menu->addAction(addCircleAct);
        menu->addAction(addArcAct);
+       menu->addAction(addPolygonAct);
        menu->addAction(addDimensionAct);
+       menu->addSeparator();
+       menu->addAction(settingsAct);
 
-//     editMenu = menuBar()->addMenu(tr("&Edit"));
-//     editMenu->addAction(cutAct);
-//     editMenu->addAction(copyAct);
-//     editMenu->addAction(pasteAct);
-
-//     menuBar()->addSeparator();
-
-//     helpMenu = menuBar()->addMenu(tr("&Help"));
-//     helpMenu->addAction(aboutAct);
-//     helpMenu->addAction(aboutQtAct);
+       menu = menuBar()->addMenu(tr("&Help"));
+       menu->addAction(aboutAct);
 }
 
+
 void ApplicationWindow::CreateToolbars(void)
 {
        QToolBar * toolbar = addToolBar(tr("File"));
+       toolbar->setObjectName("File"); // Needed for saveState()
        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(deleteAct);
+       toolbar->addAction(connectAct);
+       toolbar->addAction(disconnectAct);
+       toolbar->addSeparator();
        toolbar->addAction(addLineAct);
        toolbar->addAction(addCircleAct);
        toolbar->addAction(addArcAct);
+       toolbar->addAction(addPolygonAct);
        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)));
 }
 
+
 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("charWndPos", ((TTEdit *)qApp)->charWnd->pos());
-//     settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size());
+       settings.setValue("windowState", saveState());
+       settings.setValue("useAntialiasing", drawing->useAntialiasing);
+       settings.setValue("snapToGrid", snapToGridAct->isChecked());
 }
+