2 // applicationwindow.cpp: Architektonas
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
11 // --- ---------- ------------------------------------------------------------
12 // JLH 03/22/2011 Created this file
13 // JLH 09/29/2011 Added simple zoom in/out functionality
14 // JLH 10/03/2011 Fixed zoom tool to zoom in/out from center of screen
24 // Uncomment this for debugging...
26 //#define DEBUGFOO // Various tool debugging...
27 //#define DEBUGTP // Toolpalette debugging...
29 #include "applicationwindow.h"
32 #include "blockwidget.h"
33 #include "drawingview.h"
35 #include "generaltab.h"
37 #include "layerwidget.h"
38 #include "objectwidget.h"
40 #include "settingsdialog.h"
46 DrawingView * ApplicationWindow::drawing;
49 ApplicationWindow::ApplicationWindow():
50 baseUnitInput(new QLineEdit),
51 dimensionSizeInput(new QLineEdit),
52 settings("Underground Software", "Architektonas")
54 drawing = new DrawingView(this);
55 drawing->setMouseTracking(true); // We want *all* mouse events...!
56 drawing->setFocusPolicy(Qt::StrongFocus);
57 setCentralWidget(drawing);
59 aboutWin = new AboutWindow(this);
61 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
63 setWindowIcon(QIcon(":/res/atns-icon.png"));
64 setWindowTitle("Architektonas");
70 // Create Dock widgets
71 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
72 LayerWidget * lw = new LayerWidget;
74 addDockWidget(Qt::RightDockWidgetArea, dock1);
75 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
76 BlockWidget * bw = new BlockWidget;
78 addDockWidget(Qt::RightDockWidgetArea, dock2);
79 QDockWidget * dock3 = new QDockWidget(tr("Object"), this);
80 ObjectWidget * ow = new ObjectWidget;
82 addDockWidget(Qt::RightDockWidgetArea, dock3);
83 // Needed for saveState()
84 dock1->setObjectName("Layers");
85 dock2->setObjectName("Blocks");
86 dock3->setObjectName("Object");
89 zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
90 statusBar()->addPermanentWidget(zoomIndicator);
91 statusBar()->showMessage(tr("Ready"));
94 setUnifiedTitleAndToolBarOnMac(true);
95 Global::font = new QFont("Verdana", 15, QFont::Bold);
97 connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
98 connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
99 connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
101 connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
105 void ApplicationWindow::closeEvent(QCloseEvent * event)
108 event->accept(); // Use ignore() if can't close for some reason
109 //Do we have a memory leak here if we don't delete the font in the Object???
113 void ApplicationWindow::FileNew(void)
115 // Should warn the user if drawing hasn't been saved... !!! FIX !!!
116 DeleteContents(drawing->document.objects);
117 drawing->document.objects.clear();
119 documentName.clear();
120 setWindowTitle("Architektonas - Untitled");
121 statusBar()->showMessage(tr("New drawing is ready."));
125 void ApplicationWindow::FileOpen(void)
127 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
128 "", tr("Architektonas files (*.drawing)"));
130 // User cancelled open
131 if (filename.isEmpty())
134 FILE * file = fopen(filename.toUtf8().data(), "r");
139 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
140 msg.setIcon(QMessageBox::Critical);
145 Container container(true); // Make sure it's a top level container...
146 bool successful = FileIO::LoadAtnsFile(file, &container);
152 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
153 msg.setIcon(QMessageBox::Critical);
155 // Make sure to delete any hanging objects in the container...
156 DeleteContents(container.objects);
160 //printf("FileOpen: container size = %li\n", container.objects.size());
161 // Keep memory leaks from happening by getting rid of the old document
162 DeleteContents(drawing->document.objects);
163 // We can do this because the vector is just a bunch of pointers to our
164 // Objects, and the Containers (non-empty) can be moved way with no problem.
165 drawing->document = container;
167 documentName = filename;
168 setWindowTitle(QString("Architektonas - %1").arg(documentName));
169 statusBar()->showMessage(tr("Drawing loaded."));
173 void ApplicationWindow::FileSave(void)
175 if (documentName.isEmpty())
176 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
177 "", tr("Architektonas drawings (*.drawing)"));
179 FILE * file = fopen(documentName.toUtf8().data(), "w");
184 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
185 msg.setIcon(QMessageBox::Critical);
190 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
196 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
197 msg.setIcon(QMessageBox::Critical);
199 // In this case, we should unlink the created file, since it's not
201 // unlink(documentName.toUtf8().data());
202 QFile::remove(documentName);
206 setWindowTitle(QString("Architektonas - %1").arg(documentName));
207 statusBar()->showMessage(tr("Drawing saved."));
211 void ApplicationWindow::FileSaveAs(void)
213 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
214 documentName, tr("Architektonas drawings (*.drawing)"));
216 if (!filename.isEmpty())
218 documentName = filename;
224 void ApplicationWindow::SnapToGridTool(void)
226 Global::snapToGrid = snapToGridAct->isChecked();
230 void ApplicationWindow::FixAngle(void)
232 Global::fixedAngle = fixAngleAct->isChecked();
236 void ApplicationWindow::FixLength(void)
238 Global::fixedLength = fixLengthAct->isChecked();
242 void ApplicationWindow::DeleteTool(void)
244 // For this tool, we check first to see if anything is selected. If so, we
245 // delete those and *don't* select the delete tool.
246 // if (drawing->numSelected > 0)
247 if (drawing->select.size() > 0)
249 DeleteSelectedObjects(drawing->document.objects);
251 deleteAct->setChecked(false);
255 // Otherwise, toggle the state of the tool
256 ClearUIToolStatesExcept(deleteAct);
257 SetInternalToolStates();
261 void ApplicationWindow::DimensionTool(void)
263 ClearUIToolStatesExcept(addDimensionAct);
264 SetInternalToolStates();
268 void ApplicationWindow::RotateTool(void)
270 ClearUIToolStatesExcept(rotateAct);
272 // Do tear-down if Rotate tool has been turned off
273 if (!rotateAct->isChecked())
274 drawing->RotateHandler(ToolCleanup, Point(0, 0));
276 SetInternalToolStates();
280 void ApplicationWindow::MirrorTool(void)
282 ClearUIToolStatesExcept(mirrorAct);
284 // Do tear-down if Rotate tool has been turned off
285 if (!mirrorAct->isChecked())
286 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
288 SetInternalToolStates();
292 void ApplicationWindow::TrimTool(void)
294 ClearUIToolStatesExcept(trimAct);
295 SetInternalToolStates();
299 void ApplicationWindow::TriangulateTool(void)
301 ClearUIToolStatesExcept(triangulateAct);
302 SetInternalToolStates();
306 void ApplicationWindow::AddLineTool(void)
308 ClearUIToolStatesExcept(addLineAct);
309 SetInternalToolStates();
313 void ApplicationWindow::AddCircleTool(void)
315 ClearUIToolStatesExcept(addCircleAct);
316 SetInternalToolStates();
320 void ApplicationWindow::AddArcTool(void)
322 ClearUIToolStatesExcept(addArcAct);
323 SetInternalToolStates();
327 void ApplicationWindow::AddPolygonTool(void)
329 ClearUIToolStatesExcept(addPolygonAct);
330 SetInternalToolStates();
334 void ApplicationWindow::AddSplineTool(void)
336 ClearUIToolStatesExcept(addSplineAct);
337 SetInternalToolStates();
341 void ApplicationWindow::ZoomInTool(void)
343 double zoomFactor = 2.0;
345 We need to find the center of the screen, then figure out where the new corner
346 will be in the zoomed in window.
348 So we know in Qt coords, the center is found via:
349 size.width() / 2 --> xCenter
350 size.height() / 2 --> yCenter
352 transform x/yCenter to Cartesian coordinates. So far, so good.
354 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
355 (after subtracting from center, that is...)
357 QSize size = drawing->size();
358 Vector center(size.width() / 2.0, size.height() / 2.0);
359 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
360 center = Painter::QtToCartesianCoords(center);
361 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
362 Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
363 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
364 Global::origin = newOrigin;
366 //printf("Zoom in... level going from %02f to ", Painter::zoom);
367 // This just zooms leaving origin intact... should zoom in at the current
369 Global::zoom *= zoomFactor;
370 Global::gridSpacing = drawing->gridPixels / Global::zoom;
371 drawing->UpdateGridBackground();
374 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
375 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
379 void ApplicationWindow::ZoomOutTool(void)
384 origin = (223, 160.5)
385 newOrigin should be (-10, -10)
388 center - origin = (213, 150.5)
389 origin - center = (-213, -150.5)
391 + center = (-10, -10)
394 double zoomFactor = 2.0;
395 QSize size = drawing->size();
396 Vector center(size.width() / 2.0, size.height() / 2.0);
397 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
398 center = Painter::QtToCartesianCoords(center);
399 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
400 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
401 // Vector newOrigin = center - (Painter::origin * zoomFactor);
402 Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
403 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
404 Global::origin = newOrigin;
405 //printf("Zoom out...\n");
406 // This just zooms leaving origin intact... should zoom out at the current
408 Global::zoom /= zoomFactor;
409 Global::gridSpacing = drawing->gridPixels / Global::zoom;
410 drawing->UpdateGridBackground();
413 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
414 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
418 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
420 QAction * actionList[] = {
421 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
422 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0
425 for(int i=0; actionList[i]!=0; i++)
427 if (actionList[i] != exception)
428 actionList[i]->setChecked(false);
433 void ApplicationWindow::SetInternalToolStates(void)
435 // We can be sure that if we've come here, then either an active tool is
436 // being deactivated, or a new tool is being created. In either case, the
437 // old tool needs to be deleted.
438 Global::toolState = TSNone;
440 if (addLineAct->isChecked())
441 Global::tool = TTLine;
442 else if (addCircleAct->isChecked())
443 Global::tool = TTCircle;
444 else if (addArcAct->isChecked())
445 Global::tool = TTArc;
446 else if (addDimensionAct->isChecked())
447 Global::tool = TTDimension;
448 else if (addSplineAct->isChecked())
449 Global::tool = TTSpline;
450 else if (addPolygonAct->isChecked())
451 Global::tool = TTPolygon;
452 else if (deleteAct->isChecked())
453 Global::tool = TTDelete;
454 else if (mirrorAct->isChecked())
455 Global::tool = TTMirror;
456 else if (rotateAct->isChecked())
457 Global::tool = TTRotate;
458 else if (trimAct->isChecked())
459 Global::tool = TTTrim;
460 else if (triangulateAct->isChecked())
461 Global::tool = TTTriangulate;
463 Global::tool = TTNone;
469 void ApplicationWindow::HelpAbout(void)
475 void ApplicationWindow::Settings(void)
477 SettingsDialog dlg(this);
478 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
480 if (dlg.exec() == false)
483 // Deal with stuff here (since user hit "OK" button...)
484 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
490 // Group a bunch of selected objects (which can include other groups) together
491 // or ungroup a selected group.
493 void ApplicationWindow::HandleGrouping(void)
496 int itemsSelected = drawing->document.ItemsSelected();
498 // If nothing selected, do nothing
499 if (itemsSelected == 0)
501 statusBar()->showMessage(tr("No objects selected to make a group from."));
505 // If it's a group that's selected, ungroup it and leave the objects in a
507 if (itemsSelected == 1)
509 Object * object = drawing->document.SelectedItem(0);
513 printf("SelectedItem = NULL!\n");
515 printf("SelectedItem = %08X, type = %i\n", object, object->type);
518 if (object == NULL || object->type != OTContainer)
520 statusBar()->showMessage(tr("A group requires two or more selected objects."));
524 // Need the parent of the group, we're assuming here that the parent is
525 // the drawing's document. Does it matter? Maybe...
526 // Could just stipulate that grouping like this only takes place where
527 // the parent of the group is the drawing's document. Makes life much
529 ((Container *)object)->SelectAll();
530 ((Container *)object)->MoveContentsTo(&(drawing->document));
531 drawing->document.Delete(object);
532 statusBar()->showMessage(tr("Objects ungrouped."));
534 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
535 // group them and select the group
536 else if (itemsSelected > 1)
538 Container * container = new Container(Vector(), &(drawing->document));
539 drawing->document.MoveSelectedContentsTo(container);
540 drawing->document.Add(container);
541 container->DeselectAll();
542 container->state = OSSelected;
543 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
546 int numSelected = drawing->select.size();
548 // If nothing selected, do nothing
549 if (numSelected == 0)
551 statusBar()->showMessage(tr("No objects selected to make a group from."));
555 // If it's a group that's selected, ungroup it and leave the objects in a
557 if (numSelected == 1)
559 Object * obj = (Object *)drawing->select[0];
561 if (obj->type != OTContainer)
563 statusBar()->showMessage(tr("A group requires two or more selected objects."));
567 // Need the parent of the group, we're assuming here that the parent is
568 // the drawing's document. Does it matter? Maybe...
569 // Could just stipulate that grouping like this only takes place where
570 // the parent of the group is the drawing's document. Makes life much
572 // ((Container *)object)->SelectAll();
573 // ((Container *)object)->MoveContentsTo(&(drawing->document));
574 // drawing->document.Delete(object);
575 Container * c = (Container *)obj;
576 //printf("Ungroup: container size = %li\n", c->objects.size());
577 SelectAll(c->objects);
578 //printf("Ungroup: document size = %li (pre-AddObjectsTo)\n", drawing->document.objects.size());
579 RemoveSelectedObjects(drawing->document.objects);
580 AddObjectsTo(drawing->document.objects, c->objects);
581 drawing->select.clear();
582 AddObjectsTo(drawing->select, c->objects);
584 statusBar()->showMessage(tr("Objects ungrouped."));
585 //printf("Ungroup: document size = %li\n", drawing->document.objects.size());
587 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
588 // group them and select the group
589 else if (numSelected > 1)
591 // Container * container = new Container(Vector(), &(drawing->document));
592 // drawing->document.MoveSelectedContentsTo(container);
593 // drawing->document.Add(container);
594 // container->DeselectAll();
595 // container->state = OSSelected;
597 Container * c = new Container();
598 // AddObjectsTo(c->objects, drawing->select);
599 // RemoveSelectedObjects(drawing->document.objects);
600 MoveSelectedObjectsTo(c->objects, drawing->document.objects);
601 drawing->document.objects.push_back(c);
602 ClearSelected(c->objects);
604 c->layer = Global::currentLayer;
605 drawing->select.clear();
606 drawing->select.push_back(c);
607 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected));
608 //printf("Group: document size = %li\n", drawing->document.objects.size());
616 void ApplicationWindow::HandleConnection(void)
619 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
620 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
621 int itemsSelected = drawing->document.ItemsSelected();
623 // If nothing selected, do nothing
624 if (itemsSelected == 0)
626 statusBar()->showMessage(tr("No objects selected to connect."));
630 // If one thing selected, do nothing
631 if (itemsSelected == 1)
633 statusBar()->showMessage(tr("Nothing to connect object to."));
637 // This is O(n^2 / 2) :-P
638 for(int i=0; i<itemsSelected; i++)
640 Object * obj1 = drawing->document.SelectedItem(i);
642 for(int j=i+1; j<itemsSelected; j++)
644 Object * obj2 = drawing->document.SelectedItem(j);
647 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
650 if ((obj1->type == OTLine) && (obj2->type == OTLine))
652 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
653 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
654 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
658 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
659 obj1->Connect(obj2, u);
660 obj2->Connect(obj1, t);
663 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
664 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
666 printf("Testing Line<->Dimension intersection...\n");
667 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
668 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
670 int intersects = Geometry::Intersects(line, dim, &t, &u);
671 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
675 obj1->Connect(obj2, u);
676 obj2->Connect(obj1, t);
686 void ApplicationWindow::HandleDisconnection(void)
691 void ApplicationWindow::HandleGridSizeInPixels(int size)
693 drawing->SetGridSize(size);
698 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
702 double value = text.toDouble(&ok);
704 // Nothing parsable to a double, so quit...
705 if (!ok || value == 0)
708 // drawing->gridSpacing = value;
709 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
710 Global::gridSpacing = value;
711 Global::zoom = drawing->gridPixels / Global::gridSpacing;
712 drawing->UpdateGridBackground();
717 void ApplicationWindow::HandleDimensionSize(QString text)
721 double value = text.toDouble(&ok);
723 // Nothing parsable to a double, so quit...
724 if (!ok || value == 0)
727 // drawing->document.ResizeAllDimensions(value);
732 void ApplicationWindow::CreateActions(void)
734 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
735 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
736 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
738 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);
739 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
741 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
742 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
743 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
745 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
746 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
747 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
749 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
750 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
752 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
753 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
755 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
756 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
758 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
759 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
761 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
762 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
764 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
765 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
767 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);
768 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
770 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
771 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
773 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);
774 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
776 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
777 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
779 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
780 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
782 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
783 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
785 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")));
786 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
788 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")));
789 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
791 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")));
792 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
794 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
796 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
797 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
799 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
800 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
802 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
803 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
805 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
806 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
808 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
809 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
811 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
812 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
814 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
815 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
818 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
819 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
820 /* QActionGroup * group = new QActionGroup(this);
821 group->addAction(deleteAct);
822 group->addAction(addDimensionAct);
823 group->addAction(addLineAct);
824 group->addAction(addCircleAct);
825 group->addAction(addArcAct);//*/
830 // Consolidates action creation from a multi-step process to a single-step one.
832 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
833 QIcon icon, QKeySequence key, bool checkable/*= false*/)
835 QAction * action = new QAction(icon, name, this);
836 action->setToolTip(tooltip);
837 action->setStatusTip(statustip);
838 action->setShortcut(key);
839 action->setCheckable(checkable);
846 // This is essentially the same as the previous function, but this allows more
847 // than one key sequence to be added as key shortcuts.
849 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
850 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
852 QAction * action = new QAction(icon, name, this);
853 action->setToolTip(tooltip);
854 action->setStatusTip(statustip);
855 QList<QKeySequence> keyList;
856 keyList.append(key1);
857 keyList.append(key2);
858 action->setShortcuts(keyList);
859 action->setCheckable(checkable);
865 void ApplicationWindow::CreateMenus(void)
867 QMenu * menu = menuBar()->addMenu(tr("&File"));
868 menu->addAction(fileNewAct);
869 menu->addAction(fileOpenAct);
870 menu->addAction(fileSaveAct);
871 menu->addAction(fileSaveAsAct);
872 menu->addAction(fileCloseAct);
873 menu->addSeparator();
874 menu->addAction(exitAct);
876 menu = menuBar()->addMenu(tr("&View"));
877 menu->addAction(zoomInAct);
878 menu->addAction(zoomOutAct);
880 menu = menuBar()->addMenu(tr("&Edit"));
881 menu->addAction(snapToGridAct);
882 menu->addAction(groupAct);
883 menu->addAction(fixAngleAct);
884 menu->addAction(fixLengthAct);
885 menu->addAction(rotateAct);
886 menu->addAction(mirrorAct);
887 menu->addAction(trimAct);
888 menu->addAction(triangulateAct);
889 menu->addAction(connectAct);
890 menu->addAction(disconnectAct);
891 menu->addSeparator();
892 menu->addAction(deleteAct);
893 menu->addSeparator();
894 menu->addAction(addLineAct);
895 menu->addAction(addCircleAct);
896 menu->addAction(addArcAct);
897 menu->addAction(addPolygonAct);
898 menu->addAction(addSplineAct);
899 menu->addAction(addDimensionAct);
900 menu->addSeparator();
901 menu->addAction(settingsAct);
903 menu = menuBar()->addMenu(tr("&Help"));
904 menu->addAction(aboutAct);
908 void ApplicationWindow::CreateToolbars(void)
910 QToolBar * toolbar = addToolBar(tr("File"));
911 toolbar->setObjectName("File"); // Needed for saveState()
912 toolbar->addAction(fileNewAct);
913 toolbar->addAction(fileOpenAct);
914 toolbar->addAction(fileSaveAct);
915 toolbar->addAction(fileSaveAsAct);
916 toolbar->addAction(fileCloseAct);
917 // toolbar->addAction(exitAct);
919 toolbar = addToolBar(tr("View"));
920 toolbar->setObjectName("View");
921 toolbar->addAction(zoomInAct);
922 toolbar->addAction(zoomOutAct);
924 QSpinBox * spinbox = new QSpinBox;
925 toolbar->addWidget(spinbox);
926 // QLineEdit * lineedit = new QLineEdit;
927 toolbar->addWidget(baseUnitInput);
928 toolbar->addWidget(dimensionSizeInput);
930 toolbar = addToolBar(tr("Edit"));
931 toolbar->setObjectName("Edit");
932 toolbar->addAction(snapToGridAct);
933 toolbar->addAction(groupAct);
934 toolbar->addAction(fixAngleAct);
935 toolbar->addAction(fixLengthAct);
936 toolbar->addAction(rotateAct);
937 toolbar->addAction(mirrorAct);
938 toolbar->addAction(trimAct);
939 toolbar->addAction(triangulateAct);
940 toolbar->addAction(deleteAct);
941 toolbar->addAction(connectAct);
942 toolbar->addAction(disconnectAct);
943 toolbar->addSeparator();
944 toolbar->addAction(addLineAct);
945 toolbar->addAction(addCircleAct);
946 toolbar->addAction(addArcAct);
947 toolbar->addAction(addPolygonAct);
948 toolbar->addAction(addSplineAct);
949 toolbar->addAction(addDimensionAct);
951 spinbox->setRange(4, 256);
952 spinbox->setValue(12);
953 baseUnitInput->setText("12");
954 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
955 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
956 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
960 void ApplicationWindow::ReadSettings(void)
962 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
963 QSize size = settings.value("size", QSize(400, 400)).toSize();
964 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
965 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
968 restoreState(settings.value("windowState").toByteArray());
972 void ApplicationWindow::WriteSettings(void)
974 settings.setValue("pos", pos());
975 settings.setValue("size", size());
976 settings.setValue("windowState", saveState());
977 settings.setValue("useAntialiasing", drawing->useAntialiasing);
978 settings.setValue("snapToGrid", snapToGridAct->isChecked());