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 "penwidget.h"
41 #include "settingsdialog.h"
47 DrawingView * ApplicationWindow::drawing;
50 ApplicationWindow::ApplicationWindow():
51 baseUnitInput(new QLineEdit),
52 dimensionSizeInput(new QLineEdit),
53 settings("Underground Software", "Architektonas")
55 drawing = new DrawingView(this);
56 drawing->setMouseTracking(true); // We want *all* mouse events...!
57 drawing->setFocusPolicy(Qt::StrongFocus);
58 setCentralWidget(drawing);
60 aboutWin = new AboutWindow(this);
62 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
64 setWindowIcon(QIcon(":/res/atns-icon.png"));
65 setWindowTitle("Architektonas");
71 // Create Dock widgets
72 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
73 LayerWidget * lw = new LayerWidget;
75 addDockWidget(Qt::RightDockWidgetArea, dock1);
76 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
77 BlockWidget * bw = new BlockWidget;
79 addDockWidget(Qt::RightDockWidgetArea, dock2);
80 QDockWidget * dock3 = new QDockWidget(tr("Object"), this);
81 ObjectWidget * ow = new ObjectWidget;
83 addDockWidget(Qt::RightDockWidgetArea, dock3);
84 // Needed for saveState()
85 dock1->setObjectName("Layers");
86 dock2->setObjectName("Blocks");
87 dock3->setObjectName("Object");
90 zoomIndicator = new QLabel("Zoom: 100% Grid: 12.0\" BU: Inch");
91 statusBar()->addPermanentWidget(zoomIndicator);
92 statusBar()->showMessage(tr("Ready"));
95 setUnifiedTitleAndToolBarOnMac(true);
96 Global::font = new QFont("Verdana", 15, QFont::Bold);
98 connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
99 connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
100 connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
101 connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload()));
103 connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
104 connect(drawing, SIGNAL(NeedZoomUpdate()), this, SLOT(UpdateZoom()));
108 void ApplicationWindow::closeEvent(QCloseEvent * event)
111 event->accept(); // Use ignore() if can't close for some reason
112 //Do we have a memory leak here if we don't delete the font in the Object???
116 void ApplicationWindow::FileNew(void)
118 // Warn the user if drawing has changed and hasn't been saved...
123 msg.setText("The document has been modified.");
124 msg.setInformativeText("Do you want to save your changes?");
125 msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
126 msg.setDefaultButton(QMessageBox::Save);
127 int response = msg.exec();
131 case QMessageBox::Save:
135 case QMessageBox::Discard:
136 // Don't Save was clicked
138 case QMessageBox::Cancel:
139 // Cancel was clicked
145 FileIO::ResetLayerVectors();
147 DeleteContents(drawing->document.objects);
148 drawing->document.objects.clear();
149 drawing->dirty = false;
151 documentName.clear();
152 setWindowTitle("Architektonas - Untitled");
153 statusBar()->showMessage(tr("New drawing is ready."));
157 void ApplicationWindow::FileOpen(void)
159 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
160 "", tr("Architektonas files (*.drawing)"));
162 // User cancelled open
163 if (filename.isEmpty())
166 FILE * file = fopen(filename.toUtf8().data(), "r");
171 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
172 msg.setIcon(QMessageBox::Critical);
177 Container container(true); // Make sure it's a top level container...
178 bool successful = FileIO::LoadAtnsFile(file, &container);
184 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
185 msg.setIcon(QMessageBox::Critical);
187 // Make sure to delete any hanging objects in the container...
188 DeleteContents(container.objects);
192 //printf("FileOpen: container size = %li\n", container.objects.size());
193 // Keep memory leaks from happening by getting rid of the old document
194 DeleteContents(drawing->document.objects);
196 // We can do this because the vector is just a bunch of pointers to our
197 // Objects, and the Containers (non-empty) can be moved this way with no
199 drawing->document = container;
200 drawing->dirty = false;
202 documentName = filename;
203 setWindowTitle(QString("Architektonas - %1").arg(documentName));
204 statusBar()->showMessage(tr("Drawing loaded."));
208 void ApplicationWindow::FileSave(void)
210 if (documentName.isEmpty())
211 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
212 "", tr("Architektonas drawings (*.drawing)"));
214 FILE * file = fopen(documentName.toUtf8().data(), "w");
219 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
220 msg.setIcon(QMessageBox::Critical);
225 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
231 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
232 msg.setIcon(QMessageBox::Critical);
234 // In this case, we should unlink the created file, since it's not
236 // unlink(documentName.toUtf8().data());
237 QFile::remove(documentName);
241 drawing->dirty = false;
242 setWindowTitle(QString("Architektonas - %1").arg(documentName));
243 statusBar()->showMessage(tr("Drawing saved."));
247 void ApplicationWindow::FileSaveAs(void)
249 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
250 documentName, tr("Architektonas drawings (*.drawing)"));
252 if (!filename.isEmpty())
254 documentName = filename;
260 void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
263 menu.addAction(mirrorAct);
264 menu.addAction(rotateAct);
265 menu.addAction(trimAct);
266 menu.exec(event->globalPos());
270 void ApplicationWindow::SnapToGridTool(void)
272 Global::snapToGrid = snapToGridAct->isChecked();
276 void ApplicationWindow::FixAngle(void)
278 Global::fixedAngle = fixAngleAct->isChecked();
282 void ApplicationWindow::FixLength(void)
284 Global::fixedLength = fixLengthAct->isChecked();
288 void ApplicationWindow::DeleteTool(void)
290 // For this tool, we check first to see if anything is selected. If so, we
291 // delete those and *don't* select the delete tool.
292 // if (drawing->numSelected > 0)
293 if (drawing->select.size() > 0)
295 DeleteSelectedObjects(drawing->document.objects);
297 deleteAct->setChecked(false);
301 // Otherwise, toggle the state of the tool
302 ClearUIToolStatesExcept(deleteAct);
303 SetInternalToolStates();
307 void ApplicationWindow::DimensionTool(void)
309 ClearUIToolStatesExcept(addDimensionAct);
310 SetInternalToolStates();
314 void ApplicationWindow::RotateTool(void)
316 ClearUIToolStatesExcept(rotateAct);
318 // Do tear-down if Rotate tool has been turned off
319 if (!rotateAct->isChecked())
320 drawing->RotateHandler(ToolCleanup, Point(0, 0));
322 SetInternalToolStates();
326 void ApplicationWindow::MirrorTool(void)
328 ClearUIToolStatesExcept(mirrorAct);
330 // Do tear-down if Rotate tool has been turned off
331 if (!mirrorAct->isChecked())
332 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
334 SetInternalToolStates();
338 void ApplicationWindow::TrimTool(void)
340 ClearUIToolStatesExcept(trimAct);
341 SetInternalToolStates();
345 void ApplicationWindow::TriangulateTool(void)
347 ClearUIToolStatesExcept(triangulateAct);
348 SetInternalToolStates();
352 void ApplicationWindow::AddLineTool(void)
354 ClearUIToolStatesExcept(addLineAct);
355 SetInternalToolStates();
359 void ApplicationWindow::AddCircleTool(void)
361 ClearUIToolStatesExcept(addCircleAct);
362 SetInternalToolStates();
366 void ApplicationWindow::AddArcTool(void)
368 ClearUIToolStatesExcept(addArcAct);
369 SetInternalToolStates();
373 void ApplicationWindow::AddPolygonTool(void)
375 ClearUIToolStatesExcept(addPolygonAct);
376 SetInternalToolStates();
380 void ApplicationWindow::AddSplineTool(void)
382 ClearUIToolStatesExcept(addSplineAct);
383 SetInternalToolStates();
387 void ApplicationWindow::ZoomInTool(void)
389 double zoomFactor = 1.20;
390 QSize size = drawing->size();
391 Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
393 Global::origin = center - ((center - Global::origin) / zoomFactor);
394 Global::zoom *= zoomFactor;
400 void ApplicationWindow::ZoomOutTool(void)
402 double zoomFactor = 1.20;
403 QSize size = drawing->size();
404 Vector center = Painter::QtToCartesianCoords(Vector(size.width() / 2.0, size.height() / 2.0));
406 Global::origin = center + ((Global::origin - center) * zoomFactor);
407 Global::zoom /= zoomFactor;
413 void ApplicationWindow::UpdateZoom(void)
415 // And now, a bunch of heuristics to select the right grid size--autogrid!
417 if (Global::zoom < 0.25)
418 Global::gridSpacing = 48.0;
419 else if (Global::zoom >= 0.25 && Global::zoom < 0.50)
420 Global::gridSpacing = 36.0;
421 else if (Global::zoom >= 0.50 && Global::zoom < 1.00)
422 Global::gridSpacing = 24.0;
423 else if (Global::zoom >= 1.00 && Global::zoom < 2.00)
424 Global::gridSpacing = 12.0;
425 else if (Global::zoom >= 2.00 && Global::zoom < 4.00)
426 Global::gridSpacing = 6.0;
427 else if (Global::zoom >= 4.00 && Global::zoom < 8.00)
428 Global::gridSpacing = 3.0;
429 else if (Global::zoom >= 8.00 && Global::zoom < 16.00)
430 Global::gridSpacing = 1.0;
431 else if (Global::zoom >= 16.00 && Global::zoom < 32.00)
432 Global::gridSpacing = 0.5;
433 else if (Global::zoom >= 32.00 && Global::zoom < 64.00)
434 Global::gridSpacing = 0.25;
435 else if (Global::zoom >= 64.00 && Global::zoom < 128.00)
436 Global::gridSpacing = 0.125;
437 else if (Global::zoom >= 128.00 && Global::zoom < 256.00)
438 Global::gridSpacing = 0.0625;
439 else if (Global::zoom >= 256.00 && Global::zoom < 512.00)
440 Global::gridSpacing = 0.03125;
442 Global::gridSpacing = 0.015625;
444 drawing->SetGridSize((double)(Global::gridSpacing * Global::zoom));
447 zoomIndicator->setText(QString("Zoom: %1% Grid: %2\" BU: Inch").arg(Global::zoom * 100.0).arg(Global::gridSpacing));
449 // This is the problem... Changing this causes the state to update itself again, screwing up the origin... !!! FIX !!! (commented out for now)
450 // baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
454 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
456 QAction * actionList[] = {
457 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
458 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct,
462 for(int i=0; actionList[i]!=0; i++)
464 if (actionList[i] != exception)
465 actionList[i]->setChecked(false);
470 void ApplicationWindow::SetInternalToolStates(void)
472 // We can be sure that if we've come here, then either an active tool is
473 // being deactivated, or a new tool is being created. In either case, the
474 // old tool needs to be deleted.
475 Global::toolState = TSNone;
477 if (addLineAct->isChecked())
478 Global::tool = TTLine;
479 else if (addCircleAct->isChecked())
480 Global::tool = TTCircle;
481 else if (addArcAct->isChecked())
482 Global::tool = TTArc;
483 else if (addDimensionAct->isChecked())
484 Global::tool = TTDimension;
485 else if (addSplineAct->isChecked())
486 Global::tool = TTSpline;
487 else if (addPolygonAct->isChecked())
488 Global::tool = TTPolygon;
489 else if (deleteAct->isChecked())
490 Global::tool = TTDelete;
491 else if (mirrorAct->isChecked())
492 Global::tool = TTMirror;
493 else if (rotateAct->isChecked())
494 Global::tool = TTRotate;
495 else if (trimAct->isChecked())
496 Global::tool = TTTrim;
497 else if (triangulateAct->isChecked())
498 Global::tool = TTTriangulate;
500 Global::tool = TTNone;
506 void ApplicationWindow::HelpAbout(void)
512 void ApplicationWindow::Settings(void)
514 SettingsDialog dlg(this);
515 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
517 if (dlg.exec() == false)
520 // Deal with stuff here (since user hit "OK" button...)
521 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
527 // Group a bunch of selected objects (which can include other groups) together
528 // or ungroup a selected group.
530 void ApplicationWindow::HandleGrouping(void)
532 int numSelected = drawing->select.size();
534 // If nothing selected, do nothing
535 if (numSelected == 0)
537 statusBar()->showMessage(tr("No objects selected to make a group from."));
541 // If it's a group that's selected, ungroup it and leave the objects in a
543 if (numSelected == 1)
545 Object * obj = (Object *)drawing->select[0];
547 if (obj->type != OTContainer)
549 statusBar()->showMessage(tr("A group requires two or more selected objects."));
553 // Need the parent of the group, we're assuming here that the parent is
554 // the drawing's document. Does it matter? Maybe...
555 // Could just stipulate that grouping like this only takes place where
556 // the parent of the group is the drawing's document. Makes life much
558 Container * c = (Container *)obj;
559 SelectAll(c->objects);
560 RemoveSelectedObjects(drawing->document.objects);
561 AddObjectsTo(drawing->document.objects, c->objects);
562 drawing->select.clear();
563 AddObjectsTo(drawing->select, c->objects);
565 statusBar()->showMessage(tr("Objects ungrouped."));
566 //printf("Ungroup: document size = %li\n", drawing->document.objects.size());
568 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
569 // group them and select the group
570 else if (numSelected > 1)
572 Container * c = new Container();
573 MoveSelectedObjectsTo(c->objects, drawing->document.objects);
574 drawing->document.objects.push_back(c);
575 ClearSelected(c->objects);
577 c->layer = Global::activeLayer;
579 Rect r = drawing->GetObjectExtents((Object *)c);
580 c->p[0] = r.TopLeft();
581 c->p[1] = r.BottomRight();
583 drawing->select.clear();
584 drawing->select.push_back(c);
585 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected));
586 //printf("Group: document size = %li\n", drawing->document.objects.size());
593 void ApplicationWindow::HandleConnection(void)
596 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
597 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
598 int itemsSelected = drawing->document.ItemsSelected();
600 // If nothing selected, do nothing
601 if (itemsSelected == 0)
603 statusBar()->showMessage(tr("No objects selected to connect."));
607 // If one thing selected, do nothing
608 if (itemsSelected == 1)
610 statusBar()->showMessage(tr("Nothing to connect object to."));
614 // This is O(n^2 / 2) :-P
615 for(int i=0; i<itemsSelected; i++)
617 Object * obj1 = drawing->document.SelectedItem(i);
619 for(int j=i+1; j<itemsSelected; j++)
621 Object * obj2 = drawing->document.SelectedItem(j);
624 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
627 if ((obj1->type == OTLine) && (obj2->type == OTLine))
629 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
630 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
631 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
635 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
636 obj1->Connect(obj2, u);
637 obj2->Connect(obj1, t);
640 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
641 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
643 printf("Testing Line<->Dimension intersection...\n");
644 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
645 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
647 int intersects = Geometry::Intersects(line, dim, &t, &u);
648 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
652 obj1->Connect(obj2, u);
653 obj2->Connect(obj1, t);
663 void ApplicationWindow::HandleDisconnection(void)
668 void ApplicationWindow::HandleGridSizeInPixels(int size)
670 drawing->SetGridSize((uint32_t)size);
675 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
679 double value = text.toDouble(&ok);
681 // Nothing parsable to a double, so quit...
682 if (!ok || value == 0)
685 // drawing->gridSpacing = value;
686 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
687 Global::gridSpacing = value;
688 Global::zoom = drawing->gridPixels / Global::gridSpacing;
689 drawing->UpdateGridBackground();
694 void ApplicationWindow::HandleDimensionSize(QString text)
697 This is the third input on the view toolbar; not sure what it was supposed to do... (resize all dimensions in the drawing?)
701 double value = text.toDouble(&ok);
703 // Nothing parsable to a double, so quit...
704 if (!ok || value == 0)
707 // drawing->document.ResizeAllDimensions(value);
711 void ApplicationWindow::EditCopy(void)
713 if (drawing->select.size() > 0)
715 DeleteContents(clipboard);
716 clipboard = CopySelectedObjects(drawing->document.objects);
721 void ApplicationWindow::EditCut(void)
723 if (drawing->select.size() > 0)
725 DeleteContents(clipboard);
726 clipboard = MoveSelectedObjectsFrom(drawing->document.objects);
732 void ApplicationWindow::EditPaste(void)
734 if (clipboard.size() > 0)
736 // We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state...
737 ClearSelected(drawing->document.objects);
738 SelectAll(clipboard);
739 drawing->document.Add(CopyObjects(clipboard));
746 // Select all *visible* objects. If an object is on a layer that is not
749 void ApplicationWindow::SelectAllObjects(void)
751 // Set object's state & update the drawing
752 SelectAll(drawing->document.objects);
757 void ApplicationWindow::CreateActions(void)
759 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
760 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
761 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
763 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);
764 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
766 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
767 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
768 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
770 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
771 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
772 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
774 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
775 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
777 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
778 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
780 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
781 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
783 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
784 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
786 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
787 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
789 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
790 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
792 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);
793 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
795 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
796 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
798 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);
799 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
801 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
802 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
804 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
805 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
807 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
808 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
810 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")));
811 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
813 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")));
814 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
816 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")));
817 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
819 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
821 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
822 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
824 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
825 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
827 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
828 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
830 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
831 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
833 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
834 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
836 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
837 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
839 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
840 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
842 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")));
843 connect(editCutAct, SIGNAL(triggered()), this, SLOT(EditCut()));
845 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")));
846 connect(editCopyAct, SIGNAL(triggered()), this, SLOT(EditCopy()));
848 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")));
849 connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste()));
851 selectAllAct = CreateAction(tr("Select &All"), tr("Select All Objects"), tr("Select all objects in the drawing."), QIcon(), QKeySequence(tr("Ctrl+a")));
852 connect(selectAllAct, SIGNAL(triggered()), this, SLOT(SelectAllObjects()));
854 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
855 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
856 /* QActionGroup * group = new QActionGroup(this);
857 group->addAction(deleteAct);
858 group->addAction(addDimensionAct);
859 group->addAction(addLineAct);
860 group->addAction(addCircleAct);
861 group->addAction(addArcAct);//*/
866 // Consolidates action creation from a multi-step process to a single-step one.
868 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
869 QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/)
871 QAction * action = new QAction(icon, name, this);
872 action->setToolTip(tooltip);
873 action->setStatusTip(statustip);
874 action->setShortcut(key);
875 action->setCheckable(checkable);
882 // This is essentially the same as the previous function, but this allows more
883 // than one key sequence to be added as key shortcuts.
885 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
886 QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2,
887 bool checkable/*= false*/)
889 QAction * action = new QAction(icon, name, this);
890 action->setToolTip(tooltip);
891 action->setStatusTip(statustip);
892 QList<QKeySequence> keyList;
893 keyList.append(key1);
894 keyList.append(key2);
895 action->setShortcuts(keyList);
896 action->setCheckable(checkable);
902 void ApplicationWindow::CreateMenus(void)
904 QMenu * menu = menuBar()->addMenu(tr("&File"));
905 menu->addAction(fileNewAct);
906 menu->addAction(fileOpenAct);
907 menu->addAction(fileSaveAct);
908 menu->addAction(fileSaveAsAct);
909 menu->addAction(fileCloseAct);
910 menu->addSeparator();
911 menu->addAction(exitAct);
913 menu = menuBar()->addMenu(tr("&View"));
914 menu->addAction(zoomInAct);
915 menu->addAction(zoomOutAct);
917 menu = menuBar()->addMenu(tr("&Edit"));
918 menu->addAction(snapToGridAct);
919 menu->addAction(groupAct);
920 menu->addAction(fixAngleAct);
921 menu->addAction(fixLengthAct);
922 menu->addAction(rotateAct);
923 menu->addAction(mirrorAct);
924 menu->addAction(trimAct);
925 menu->addAction(triangulateAct);
926 menu->addAction(connectAct);
927 menu->addAction(disconnectAct);
928 menu->addSeparator();
929 menu->addAction(selectAllAct);
930 menu->addAction(editCutAct);
931 menu->addAction(editCopyAct);
932 menu->addAction(editPasteAct);
933 menu->addAction(deleteAct);
934 menu->addSeparator();
935 menu->addAction(addLineAct);
936 menu->addAction(addCircleAct);
937 menu->addAction(addArcAct);
938 menu->addAction(addPolygonAct);
939 menu->addAction(addSplineAct);
940 menu->addAction(addDimensionAct);
941 menu->addSeparator();
942 menu->addAction(settingsAct);
944 menu = menuBar()->addMenu(tr("&Help"));
945 menu->addAction(aboutAct);
949 void ApplicationWindow::CreateToolbars(void)
951 QToolBar * toolbar = addToolBar(tr("File"));
952 toolbar->setObjectName("File"); // Needed for saveState()
953 toolbar->addAction(fileNewAct);
954 toolbar->addAction(fileOpenAct);
955 toolbar->addAction(fileSaveAct);
956 toolbar->addAction(fileSaveAsAct);
957 toolbar->addAction(fileCloseAct);
958 // toolbar->addAction(exitAct);
960 toolbar = addToolBar(tr("View"));
961 toolbar->setObjectName("View");
962 toolbar->addAction(zoomInAct);
963 toolbar->addAction(zoomOutAct);
965 QSpinBox * spinbox = new QSpinBox;
966 toolbar->addWidget(spinbox);
967 // QLineEdit * lineedit = new QLineEdit;
968 toolbar->addWidget(baseUnitInput);
969 toolbar->addWidget(dimensionSizeInput);
971 toolbar = addToolBar(tr("Edit"));
972 toolbar->setObjectName("Edit");
973 toolbar->addAction(snapToGridAct);
974 toolbar->addAction(groupAct);
975 toolbar->addAction(fixAngleAct);
976 toolbar->addAction(fixLengthAct);
977 toolbar->addAction(rotateAct);
978 toolbar->addAction(mirrorAct);
979 toolbar->addAction(trimAct);
980 toolbar->addAction(triangulateAct);
981 toolbar->addAction(editCutAct);
982 toolbar->addAction(editCopyAct);
983 toolbar->addAction(editPasteAct);
984 toolbar->addAction(deleteAct);
985 toolbar->addAction(connectAct);
986 toolbar->addAction(disconnectAct);
987 toolbar->addSeparator();
988 toolbar->addAction(addLineAct);
989 toolbar->addAction(addCircleAct);
990 toolbar->addAction(addArcAct);
991 toolbar->addAction(addPolygonAct);
992 toolbar->addAction(addSplineAct);
993 toolbar->addAction(addDimensionAct);
995 spinbox->setRange(4, 256);
996 spinbox->setValue(12);
997 baseUnitInput->setText("12");
998 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
999 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
1000 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
1002 PenWidget * pw = new PenWidget();
1003 toolbar = addToolBar(tr("Pen"));
1004 toolbar->setObjectName(tr("Pen"));
1005 toolbar->addWidget(pw);
1006 connect(drawing, SIGNAL(ObjectSelected(Object *)), pw, SLOT(SetFields(Object *)));
1007 connect(pw, SIGNAL(WidthSelected(float)), drawing, SLOT(HandlePenWidth(float)));
1008 connect(pw, SIGNAL(StyleSelected(int)), drawing, SLOT(HandlePenStyle(int)));
1009 connect(pw, SIGNAL(ColorSelected(uint32_t)), drawing, SLOT(HandlePenColor(uint32_t)));
1010 connect(pw, SIGNAL(StampSelected(void)), drawing, SLOT(HandlePenStamp(void)));
1014 void ApplicationWindow::ReadSettings(void)
1016 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
1017 QSize size = settings.value("size", QSize(400, 400)).toSize();
1018 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
1019 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
1022 restoreState(settings.value("windowState").toByteArray());
1026 void ApplicationWindow::WriteSettings(void)
1028 settings.setValue("pos", pos());
1029 settings.setValue("size", size());
1030 settings.setValue("windowState", saveState());
1031 settings.setValue("useAntialiasing", drawing->useAntialiasing);
1032 settings.setValue("snapToGrid", snapToGridAct->isChecked());