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 "dimension.h"
34 #include "drawingview.h"
35 //#include "drawarcaction.h"
36 //#include "drawcircleaction.h"
37 //#include "drawdimensionaction.h"
38 //#include "drawlineaction.h"
39 //#include "drawsplineaction.h"
41 #include "generaltab.h"
42 //#include "geometry.h"
44 #include "layerwidget.h"
46 //#include "mirroraction.h"
48 //#include "rotateaction.h"
49 #include "settingsdialog.h"
51 //#include "triangulateaction.h"
52 //#include "trimaction.h"
56 DrawingView * ApplicationWindow::drawing;
59 ApplicationWindow::ApplicationWindow():
60 baseUnitInput(new QLineEdit),
61 dimensionSizeInput(new QLineEdit),
62 settings("Underground Software", "Architektonas")
64 drawing = new DrawingView(this);
65 drawing->setMouseTracking(true); // We want *all* mouse events...!
66 drawing->setFocusPolicy(Qt::StrongFocus);
67 setCentralWidget(drawing);
69 aboutWin = new AboutWindow(this);
71 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
73 setWindowIcon(QIcon(":/res/atns-icon.png"));
74 setWindowTitle("Architektonas");
80 // Create Dock widgets
81 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
82 LayerWidget * lw = new LayerWidget;
84 addDockWidget(Qt::RightDockWidgetArea, dock1);
85 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
86 BlockWidget * bw = new BlockWidget;
88 addDockWidget(Qt::RightDockWidgetArea, dock2);
89 // Needed for saveState()
90 dock1->setObjectName("Layers");
91 dock2->setObjectName("Blocks");
94 zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
95 statusBar()->addPermanentWidget(zoomIndicator);
96 statusBar()->showMessage(tr("Ready"));
99 setUnifiedTitleAndToolBarOnMac(true);
100 Global::font = new QFont("Verdana", 15, QFont::Bold);
102 connect(lw, SIGNAL(LayerSelected(int)), drawing, SLOT(SetCurrentLayer(int)));
106 void ApplicationWindow::closeEvent(QCloseEvent * event)
109 event->accept(); // Use ignore() if can't close for some reason
110 //Do we have a memory leak here if we don't delete the font in the Object???
114 void ApplicationWindow::FileNew(void)
116 // Should warn the user if drawing hasn't been saved...
117 drawing->document.objects.empty();
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;//(Vector(0, 0));
146 bool successful = FileIO::LoadAtnsFile(file, &container);
152 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
153 msg.setIcon(QMessageBox::Critical);
158 printf("FileOpen: container size = %li\n", container.objects.size());
159 drawing->document = container;
161 documentName = filename;
162 setWindowTitle(QString("Architektonas - %1").arg(documentName));
163 statusBar()->showMessage(tr("Drawing loaded."));
167 void ApplicationWindow::FileSave(void)
169 if (documentName.isEmpty())
170 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
171 "", tr("Architektonas drawings (*.drawing)"));
173 FILE * file = fopen(documentName.toUtf8().data(), "w");
178 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
179 msg.setIcon(QMessageBox::Critical);
184 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
190 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
191 msg.setIcon(QMessageBox::Critical);
193 // In this case, we should unlink the created file, since it's not right...
194 // unlink(documentName.toUtf8().data());
195 QFile::remove(documentName);
199 setWindowTitle(QString("Architektonas - %1").arg(documentName));
200 statusBar()->showMessage(tr("Drawing saved."));
204 void ApplicationWindow::FileSaveAs(void)
206 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
207 documentName, tr("Architektonas drawings (*.drawing)"));
209 if (!filename.isEmpty())
211 documentName = filename;
217 void ApplicationWindow::SnapToGridTool(void)
219 Global::snapToGrid = snapToGridAct->isChecked();
223 void ApplicationWindow::FixAngle(void)
225 Global::fixedAngle = fixAngleAct->isChecked();
229 void ApplicationWindow::FixLength(void)
231 Global::fixedLength = fixLengthAct->isChecked();
235 void ApplicationWindow::DeleteTool(void)
237 // For this tool, we check first to see if anything is selected. If so, we
238 // delete those and *don't* select the delete tool.
239 if (drawing->numSelected > 0)
241 drawing->DeleteSelectedItems();
243 deleteAct->setChecked(false);
247 // Otherwise, toggle the state of the tool
248 ClearUIToolStatesExcept(deleteAct);
249 SetInternalToolStates();
253 void ApplicationWindow::DimensionTool(void)
255 ClearUIToolStatesExcept(addDimensionAct);
256 SetInternalToolStates();
260 void ApplicationWindow::RotateTool(void)
262 ClearUIToolStatesExcept(rotateAct);
263 SetInternalToolStates();
267 void ApplicationWindow::MirrorTool(void)
269 ClearUIToolStatesExcept(mirrorAct);
270 SetInternalToolStates();
274 void ApplicationWindow::TrimTool(void)
276 ClearUIToolStatesExcept(trimAct);
277 SetInternalToolStates();
281 void ApplicationWindow::TriangulateTool(void)
283 ClearUIToolStatesExcept(triangulateAct);
284 SetInternalToolStates();
288 void ApplicationWindow::AddLineTool(void)
290 ClearUIToolStatesExcept(addLineAct);
291 SetInternalToolStates();
295 void ApplicationWindow::AddCircleTool(void)
297 ClearUIToolStatesExcept(addCircleAct);
298 SetInternalToolStates();
302 void ApplicationWindow::AddArcTool(void)
304 ClearUIToolStatesExcept(addArcAct);
305 SetInternalToolStates();
309 void ApplicationWindow::AddPolygonTool(void)
311 ClearUIToolStatesExcept(addPolygonAct);
312 SetInternalToolStates();
316 void ApplicationWindow::AddSplineTool(void)
318 ClearUIToolStatesExcept(addSplineAct);
319 SetInternalToolStates();
323 void ApplicationWindow::ZoomInTool(void)
325 double zoomFactor = 2.0;
327 We need to find the center of the screen, then figure out where the new corner
328 will be in the zoomed in window.
330 So we know in Qt coords, the center is found via:
331 size.width() / 2 --> xCenter
332 size.height() / 2 --> yCenter
334 transform x/yCenter to Cartesian coordinates. So far, so good.
336 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
337 (after subtracting from center, that is...)
339 QSize size = drawing->size();
340 Vector center(size.width() / 2.0, size.height() / 2.0);
341 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
342 center = Painter::QtToCartesianCoords(center);
343 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
344 Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
345 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
346 Global::origin = newOrigin;
348 //printf("Zoom in... level going from %02f to ", Painter::zoom);
349 // This just zooms leaving origin intact... should zoom in at the current
351 Global::zoom *= zoomFactor;
352 Global::gridSpacing = drawing->gridPixels / Global::zoom;
353 drawing->UpdateGridBackground();
356 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
357 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
361 void ApplicationWindow::ZoomOutTool(void)
366 origin = (223, 160.5)
367 newOrigin should be (-10, -10)
370 center - origin = (213, 150.5)
371 origin - center = (-213, -150.5)
373 + center = (-10, -10)
376 double zoomFactor = 2.0;
377 QSize size = drawing->size();
378 Vector center(size.width() / 2.0, size.height() / 2.0);
379 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
380 center = Painter::QtToCartesianCoords(center);
381 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
382 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
383 // Vector newOrigin = center - (Painter::origin * zoomFactor);
384 Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
385 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
386 Global::origin = newOrigin;
387 //printf("Zoom out...\n");
388 // This just zooms leaving origin intact... should zoom out at the current
390 Global::zoom /= zoomFactor;
391 Global::gridSpacing = drawing->gridPixels / Global::zoom;
392 drawing->UpdateGridBackground();
395 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
396 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
400 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
402 QAction * actionList[] = {
403 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
404 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0
407 for(int i=0; actionList[i]!=0; i++)
409 if (actionList[i] != exception)
410 actionList[i]->setChecked(false);
415 void ApplicationWindow::SetInternalToolStates(void)
417 // Global::deleteActive = deleteAct->isChecked();
418 // Global::dimensionActive = addDimensionAct->isChecked();
420 // We can be sure that if we've come here, then either an active tool is
421 // being deactivated, or a new tool is being created. In either case, the
422 // old tool needs to be deleted.
423 Global::toolState = TSNone;
425 if (drawing->toolAction)
427 delete drawing->toolAction;
428 drawing->toolAction = NULL;
429 Global::ignoreClicks = false;
432 drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
433 drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
434 drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
435 drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
436 drawing->SetToolActive(addSplineAct->isChecked() ? new DrawSplineAction() : NULL);
437 drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL);
438 drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL);
439 drawing->SetToolActive(trimAct->isChecked() ? new TrimAction() : NULL);
440 drawing->SetToolActive(triangulateAct->isChecked() ? new TriangulateAction() : NULL);
442 if (drawing->toolAction)
443 Global::ignoreClicks = true;
445 if (addLineAct->isChecked())
446 Global::tool = TTLine;
447 else if (addCircleAct->isChecked())
448 Global::tool = TTCircle;
449 else if (addArcAct->isChecked())
450 Global::tool = TTArc;
451 else if (addDimensionAct->isChecked())
452 Global::tool = TTDimension;
453 else if (addSplineAct->isChecked())
454 Global::tool = TTSpline;
455 else if (addPolygonAct->isChecked())
456 Global::tool = TTPolygon;
457 else if (deleteAct->isChecked())
458 Global::tool = TTDelete;
459 else if (mirrorAct->isChecked())
460 Global::tool = TTMirror;
461 else if (rotateAct->isChecked())
462 Global::tool = TTRotate;
463 else if (trimAct->isChecked())
464 Global::tool = TTTrim;
465 else if (triangulateAct->isChecked())
466 Global::tool = TTTriangulate;
468 Global::tool = TTNone;
475 void ApplicationWindow::HelpAbout(void)
481 void ApplicationWindow::Settings(void)
483 SettingsDialog dlg(this);
484 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
486 if (dlg.exec() == false)
489 // Deal with stuff here (since user hit "OK" button...)
490 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
496 // Group a bunch of selected objects (which can include other groups) together
497 // or ungroup a selected group.
499 void ApplicationWindow::HandleGrouping(void)
502 int itemsSelected = drawing->document.ItemsSelected();
504 // If nothing selected, do nothing
505 if (itemsSelected == 0)
507 statusBar()->showMessage(tr("No objects selected to make a group from."));
511 // If it's a group that's selected, ungroup it and leave the objects in a
513 if (itemsSelected == 1)
515 Object * object = drawing->document.SelectedItem(0);
519 printf("SelectedItem = NULL!\n");
521 printf("SelectedItem = %08X, type = %i\n", object, object->type);
524 if (object == NULL || object->type != OTContainer)
526 statusBar()->showMessage(tr("A group requires two or more selected objects."));
530 // Need the parent of the group, we're assuming here that the parent is
531 // the drawing's document. Does it matter? Maybe...
532 // Could just stipulate that grouping like this only takes place where the
533 // parent of the group is the drawing's document. Makes life much simpler.
534 ((Container *)object)->SelectAll();
535 ((Container *)object)->MoveContentsTo(&(drawing->document));
536 drawing->document.Delete(object);
537 statusBar()->showMessage(tr("Objects ungrouped."));
539 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
540 // group them and select the group
541 else if (itemsSelected > 1)
543 Container * container = new Container(Vector(), &(drawing->document));
544 drawing->document.MoveSelectedContentsTo(container);
545 drawing->document.Add(container);
546 container->DeselectAll();
547 container->state = OSSelected;
548 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
557 void ApplicationWindow::HandleConnection(void)
560 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
561 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
562 int itemsSelected = drawing->document.ItemsSelected();
564 // If nothing selected, do nothing
565 if (itemsSelected == 0)
567 statusBar()->showMessage(tr("No objects selected to connect."));
571 // If one thing selected, do nothing
572 if (itemsSelected == 1)
574 statusBar()->showMessage(tr("Nothing to connect object to."));
578 // This is O(n^2 / 2) :-P
579 for(int i=0; i<itemsSelected; i++)
581 Object * obj1 = drawing->document.SelectedItem(i);
583 for(int j=i+1; j<itemsSelected; j++)
585 Object * obj2 = drawing->document.SelectedItem(j);
588 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
591 if ((obj1->type == OTLine) && (obj2->type == OTLine))
593 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
594 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
595 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
599 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
600 obj1->Connect(obj2, u);
601 obj2->Connect(obj1, t);
604 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
605 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
607 printf("Testing Line<->Dimension intersection...\n");
608 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
609 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
611 int intersects = Geometry::Intersects(line, dim, &t, &u);
612 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
616 obj1->Connect(obj2, u);
617 obj2->Connect(obj1, t);
627 void ApplicationWindow::HandleDisconnection(void)
632 void ApplicationWindow::HandleGridSizeInPixels(int size)
634 drawing->SetGridSize(size);
639 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
643 double value = text.toDouble(&ok);
645 // Nothing parsable to a double, so quit...
646 if (!ok || value == 0)
649 // drawing->gridSpacing = value;
650 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
651 Global::gridSpacing = value;
652 Global::zoom = drawing->gridPixels / Global::gridSpacing;
653 drawing->UpdateGridBackground();
658 void ApplicationWindow::HandleDimensionSize(QString text)
662 double value = text.toDouble(&ok);
664 // Nothing parsable to a double, so quit...
665 if (!ok || value == 0)
668 // drawing->document.ResizeAllDimensions(value);
673 void ApplicationWindow::CreateActions(void)
675 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
676 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
677 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
679 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);
680 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
682 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
683 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
684 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
686 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
687 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
688 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
690 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
691 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
693 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
694 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
696 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
697 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
699 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
700 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
702 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
703 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
705 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
706 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
708 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);
709 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
711 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
712 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
714 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);
715 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
717 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
718 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
720 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
721 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
723 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
724 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
726 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")));
727 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
729 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")));
730 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
732 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")));
733 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
735 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
737 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
738 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
740 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
741 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
743 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
744 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
746 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
747 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
749 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
750 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
752 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
753 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
755 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
756 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
759 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
760 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
761 /* QActionGroup * group = new QActionGroup(this);
762 group->addAction(deleteAct);
763 group->addAction(addDimensionAct);
764 group->addAction(addLineAct);
765 group->addAction(addCircleAct);
766 group->addAction(addArcAct);//*/
771 // Consolidates action creation from a multi-step process to a single-step one.
773 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
774 QIcon icon, QKeySequence key, bool checkable/*= false*/)
776 QAction * action = new QAction(icon, name, this);
777 action->setToolTip(tooltip);
778 action->setStatusTip(statustip);
779 action->setShortcut(key);
780 action->setCheckable(checkable);
787 // This is essentially the same as the previous function, but this allows more
788 // than one key sequence to be added as key shortcuts.
790 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
791 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
793 QAction * action = new QAction(icon, name, this);
794 action->setToolTip(tooltip);
795 action->setStatusTip(statustip);
796 QList<QKeySequence> keyList;
797 keyList.append(key1);
798 keyList.append(key2);
799 action->setShortcuts(keyList);
800 action->setCheckable(checkable);
806 void ApplicationWindow::CreateMenus(void)
808 QMenu * menu = menuBar()->addMenu(tr("&File"));
809 menu->addAction(fileNewAct);
810 menu->addAction(fileOpenAct);
811 menu->addAction(fileSaveAct);
812 menu->addAction(fileSaveAsAct);
813 menu->addAction(fileCloseAct);
814 menu->addSeparator();
815 menu->addAction(exitAct);
817 menu = menuBar()->addMenu(tr("&View"));
818 menu->addAction(zoomInAct);
819 menu->addAction(zoomOutAct);
821 menu = menuBar()->addMenu(tr("&Edit"));
822 menu->addAction(snapToGridAct);
823 menu->addAction(groupAct);
824 menu->addAction(fixAngleAct);
825 menu->addAction(fixLengthAct);
826 menu->addAction(rotateAct);
827 menu->addAction(mirrorAct);
828 menu->addAction(trimAct);
829 menu->addAction(triangulateAct);
830 menu->addAction(connectAct);
831 menu->addAction(disconnectAct);
832 menu->addSeparator();
833 menu->addAction(deleteAct);
834 menu->addSeparator();
835 menu->addAction(addLineAct);
836 menu->addAction(addCircleAct);
837 menu->addAction(addArcAct);
838 menu->addAction(addPolygonAct);
839 menu->addAction(addSplineAct);
840 menu->addAction(addDimensionAct);
841 menu->addSeparator();
842 menu->addAction(settingsAct);
844 menu = menuBar()->addMenu(tr("&Help"));
845 menu->addAction(aboutAct);
849 void ApplicationWindow::CreateToolbars(void)
851 QToolBar * toolbar = addToolBar(tr("File"));
852 toolbar->setObjectName("File"); // Needed for saveState()
853 toolbar->addAction(fileNewAct);
854 toolbar->addAction(fileOpenAct);
855 toolbar->addAction(fileSaveAct);
856 toolbar->addAction(fileSaveAsAct);
857 toolbar->addAction(fileCloseAct);
858 // toolbar->addAction(exitAct);
860 toolbar = addToolBar(tr("View"));
861 toolbar->setObjectName("View");
862 toolbar->addAction(zoomInAct);
863 toolbar->addAction(zoomOutAct);
865 QSpinBox * spinbox = new QSpinBox;
866 toolbar->addWidget(spinbox);
867 // QLineEdit * lineedit = new QLineEdit;
868 toolbar->addWidget(baseUnitInput);
869 toolbar->addWidget(dimensionSizeInput);
871 toolbar = addToolBar(tr("Edit"));
872 toolbar->setObjectName("Edit");
873 toolbar->addAction(snapToGridAct);
874 toolbar->addAction(groupAct);
875 toolbar->addAction(fixAngleAct);
876 toolbar->addAction(fixLengthAct);
877 toolbar->addAction(rotateAct);
878 toolbar->addAction(mirrorAct);
879 toolbar->addAction(trimAct);
880 toolbar->addAction(triangulateAct);
881 toolbar->addAction(deleteAct);
882 toolbar->addAction(connectAct);
883 toolbar->addAction(disconnectAct);
884 toolbar->addSeparator();
885 toolbar->addAction(addLineAct);
886 toolbar->addAction(addCircleAct);
887 toolbar->addAction(addArcAct);
888 toolbar->addAction(addPolygonAct);
889 toolbar->addAction(addSplineAct);
890 toolbar->addAction(addDimensionAct);
892 spinbox->setRange(4, 256);
893 spinbox->setValue(12);
894 baseUnitInput->setText("12");
895 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
896 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
897 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
901 void ApplicationWindow::ReadSettings(void)
903 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
904 QSize size = settings.value("size", QSize(400, 400)).toSize();
905 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
906 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
909 restoreState(settings.value("windowState").toByteArray());
913 void ApplicationWindow::WriteSettings(void)
915 settings.setValue("pos", pos());
916 settings.setValue("size", size());
917 settings.setValue("windowState", saveState());
918 settings.setValue("useAntialiasing", drawing->useAntialiasing);
919 settings.setValue("snapToGrid", snapToGridAct->isChecked());