]> Shamusworld >> Repos - architektonas/blobdiff - src/applicationwindow.cpp
Changes to make containers behave like a first-class object.
[architektonas] / src / applicationwindow.cpp
index ac4122da777394a32d15ff908afd487ac88bb682..7dd57aca22824c70f77ff62cb782808e47814569 100644 (file)
@@ -8,7 +8,7 @@
 // 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
@@ -35,7 +35,9 @@
 #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"
@@ -75,11 +77,16 @@ ApplicationWindow::ApplicationWindow():
        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
+       // Create status bar
        zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
        statusBar()->addPermanentWidget(zoomIndicator);
        statusBar()->showMessage(tr("Ready"));
@@ -88,10 +95,12 @@ ApplicationWindow::ApplicationWindow():
        setUnifiedTitleAndToolBarOnMac(true);
        Global::font =  new QFont("Verdana", 15, QFont::Bold);
 
-       connect(lw, SIGNAL(LayerSelected(int)), drawing, SLOT(SetCurrentLayer(int)));
        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()));
+
+       connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
 }
 
 
@@ -105,8 +114,38 @@ void ApplicationWindow::closeEvent(QCloseEvent * event)
 
 void ApplicationWindow::FileNew(void)
 {
-       // Should warn the user if drawing hasn't been saved...
-       drawing->document.objects.empty();
+       // 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");
@@ -134,7 +173,7 @@ void ApplicationWindow::FileOpen(void)
                return;
        }
 
-       Container container;//(Vector(0, 0));
+       Container container(true);      // Make sure it's a top level container...
        bool successful = FileIO::LoadAtnsFile(file, &container);
        fclose(file);
 
@@ -144,11 +183,20 @@ void ApplicationWindow::FileOpen(void)
                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());
+//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));
@@ -182,12 +230,14 @@ void ApplicationWindow::FileSave(void)
                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...
+               // 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."));
 }
@@ -206,6 +256,16 @@ void ApplicationWindow::FileSaveAs(void)
 }
 
 
+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();
@@ -228,9 +288,9 @@ 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->numSelected > 0)
+       if (drawing->select.size() > 0)
        {
-//             drawing->DeleteSelectedItems();
                DeleteSelectedObjects(drawing->document.objects);
                drawing->update();
                deleteAct->setChecked(false);
@@ -508,8 +568,9 @@ else
 
                // 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.
+               // 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);
@@ -527,6 +588,75 @@ else
                statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
        }
 #else
+       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 *)object)->SelectAll();
+//             ((Container *)object)->MoveContentsTo(&(drawing->document));
+//             drawing->document.Delete(object);
+               Container * c = (Container *)obj;
+//printf("Ungroup: container size = %li\n", c->objects.size());
+               SelectAll(c->objects);
+//printf("Ungroup: document size = %li (pre-AddObjectsTo)\n", drawing->document.objects.size());
+               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 * container = new Container(Vector(), &(drawing->document));
+//             drawing->document.MoveSelectedContentsTo(container);
+//             drawing->document.Add(container);
+//             container->DeselectAll();
+//             container->state = OSSelected;
+
+               Container * c = new Container();
+//             AddObjectsTo(c->objects, drawing->select);
+//             RemoveSelectedObjects(drawing->document.objects);
+               MoveSelectedObjectsTo(c->objects, drawing->document.objects);
+               drawing->document.objects.push_back(c);
+               ClearSelected(c->objects);
+               c->selected = true;
+               c->layer = Global::currentLayer;
+
+               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());
+       }
 #endif
 
        drawing->update();
@@ -636,6 +766,9 @@ void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
 
 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);
@@ -648,6 +781,39 @@ void ApplicationWindow::HandleDimensionSize(QString text)
        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)
 {
@@ -734,6 +900,14 @@ void ApplicationWindow::CreateActions(void)
        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.
@@ -749,8 +923,8 @@ void ApplicationWindow::CreateActions(void)
 //
 // 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);
@@ -766,8 +940,9 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString
 // 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);
@@ -809,6 +984,9 @@ void ApplicationWindow::CreateMenus(void)
        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);
@@ -857,6 +1035,9 @@ void ApplicationWindow::CreateToolbars(void)
        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);
@@ -874,6 +1055,15 @@ void ApplicationWindow::CreateToolbars(void)
        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)));
 }