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.
424 if (drawing->toolAction)
426 delete drawing->toolAction;
427 drawing->toolAction = NULL;
428 Global::ignoreClicks = false;
431 drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
432 drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
433 drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
434 drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
435 drawing->SetToolActive(addSplineAct->isChecked() ? new DrawSplineAction() : NULL);
436 drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL);
437 drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL);
438 drawing->SetToolActive(trimAct->isChecked() ? new TrimAction() : NULL);
439 drawing->SetToolActive(triangulateAct->isChecked() ? new TriangulateAction() : NULL);
441 if (drawing->toolAction)
442 Global::ignoreClicks = true;
444 if (addLineAct->isChecked())
445 Global::tool = TTLine;
446 else if (addCircleAct->isChecked())
447 Global::tool = TTCircle;
448 else if (addArcAct->isChecked())
449 Global::tool = TTArc;
450 else if (addDimensionAct->isChecked())
451 Global::tool = TTDimension;
452 else if (addSplineAct->isChecked())
453 Global::tool = TTSpline;
454 else if (addPolygonAct->isChecked())
455 Global::tool = TTPolygon;
456 else if (deleteAct->isChecked())
457 Global::tool = TTDelete;
458 else if (mirrorAct->isChecked())
459 Global::tool = TTMirror;
460 else if (rotateAct->isChecked())
461 Global::tool = TTRotate;
462 else if (trimAct->isChecked())
463 Global::tool = TTTrim;
464 else if (triangulateAct->isChecked())
465 Global::tool = TTTriangulate;
467 Global::tool = TTNone;
474 void ApplicationWindow::HelpAbout(void)
480 void ApplicationWindow::Settings(void)
482 SettingsDialog dlg(this);
483 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
485 if (dlg.exec() == false)
488 // Deal with stuff here (since user hit "OK" button...)
489 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
495 // Group a bunch of selected objects (which can include other groups) together
496 // or ungroup a selected group.
498 void ApplicationWindow::HandleGrouping(void)
501 int itemsSelected = drawing->document.ItemsSelected();
503 // If nothing selected, do nothing
504 if (itemsSelected == 0)
506 statusBar()->showMessage(tr("No objects selected to make a group from."));
510 // If it's a group that's selected, ungroup it and leave the objects in a
512 if (itemsSelected == 1)
514 Object * object = drawing->document.SelectedItem(0);
518 printf("SelectedItem = NULL!\n");
520 printf("SelectedItem = %08X, type = %i\n", object, object->type);
523 if (object == NULL || object->type != OTContainer)
525 statusBar()->showMessage(tr("A group requires two or more selected objects."));
529 // Need the parent of the group, we're assuming here that the parent is
530 // the drawing's document. Does it matter? Maybe...
531 // Could just stipulate that grouping like this only takes place where the
532 // parent of the group is the drawing's document. Makes life much simpler.
533 ((Container *)object)->SelectAll();
534 ((Container *)object)->MoveContentsTo(&(drawing->document));
535 drawing->document.Delete(object);
536 statusBar()->showMessage(tr("Objects ungrouped."));
538 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
539 // group them and select the group
540 else if (itemsSelected > 1)
542 Container * container = new Container(Vector(), &(drawing->document));
543 drawing->document.MoveSelectedContentsTo(container);
544 drawing->document.Add(container);
545 container->DeselectAll();
546 container->state = OSSelected;
547 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
556 void ApplicationWindow::HandleConnection(void)
559 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
560 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
561 int itemsSelected = drawing->document.ItemsSelected();
563 // If nothing selected, do nothing
564 if (itemsSelected == 0)
566 statusBar()->showMessage(tr("No objects selected to connect."));
570 // If one thing selected, do nothing
571 if (itemsSelected == 1)
573 statusBar()->showMessage(tr("Nothing to connect object to."));
577 // This is O(n^2 / 2) :-P
578 for(int i=0; i<itemsSelected; i++)
580 Object * obj1 = drawing->document.SelectedItem(i);
582 for(int j=i+1; j<itemsSelected; j++)
584 Object * obj2 = drawing->document.SelectedItem(j);
587 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
590 if ((obj1->type == OTLine) && (obj2->type == OTLine))
592 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
593 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
594 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
598 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
599 obj1->Connect(obj2, u);
600 obj2->Connect(obj1, t);
603 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
604 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
606 printf("Testing Line<->Dimension intersection...\n");
607 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
608 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
610 int intersects = Geometry::Intersects(line, dim, &t, &u);
611 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
615 obj1->Connect(obj2, u);
616 obj2->Connect(obj1, t);
626 void ApplicationWindow::HandleDisconnection(void)
631 void ApplicationWindow::HandleGridSizeInPixels(int size)
633 drawing->SetGridSize(size);
638 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
642 double value = text.toDouble(&ok);
644 // Nothing parsable to a double, so quit...
645 if (!ok || value == 0)
648 // drawing->gridSpacing = value;
649 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
650 Global::gridSpacing = value;
651 Global::zoom = drawing->gridPixels / Global::gridSpacing;
652 drawing->UpdateGridBackground();
657 void ApplicationWindow::HandleDimensionSize(QString text)
661 double value = text.toDouble(&ok);
663 // Nothing parsable to a double, so quit...
664 if (!ok || value == 0)
667 // drawing->document.ResizeAllDimensions(value);
672 void ApplicationWindow::CreateActions(void)
674 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
675 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
676 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
678 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);
679 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
681 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
682 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
683 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
685 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
686 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
687 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
689 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
690 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
692 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
693 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
695 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
696 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
698 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
699 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
701 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
702 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
704 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
705 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
707 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);
708 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
710 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
711 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
713 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);
714 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
716 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
717 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
719 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
720 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
722 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
723 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
725 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")));
726 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
728 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")));
729 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
731 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")));
732 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
734 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
736 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
737 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
739 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
740 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
742 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
743 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
745 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
746 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
748 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
749 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
751 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
752 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
754 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
755 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
758 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
759 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
760 /* QActionGroup * group = new QActionGroup(this);
761 group->addAction(deleteAct);
762 group->addAction(addDimensionAct);
763 group->addAction(addLineAct);
764 group->addAction(addCircleAct);
765 group->addAction(addArcAct);//*/
770 // Consolidates action creation from a multi-step process to a single-step one.
772 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
773 QIcon icon, QKeySequence key, bool checkable/*= false*/)
775 QAction * action = new QAction(icon, name, this);
776 action->setToolTip(tooltip);
777 action->setStatusTip(statustip);
778 action->setShortcut(key);
779 action->setCheckable(checkable);
786 // This is essentially the same as the previous function, but this allows more
787 // than one key sequence to be added as key shortcuts.
789 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
790 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
792 QAction * action = new QAction(icon, name, this);
793 action->setToolTip(tooltip);
794 action->setStatusTip(statustip);
795 QList<QKeySequence> keyList;
796 keyList.append(key1);
797 keyList.append(key2);
798 action->setShortcuts(keyList);
799 action->setCheckable(checkable);
805 void ApplicationWindow::CreateMenus(void)
807 QMenu * menu = menuBar()->addMenu(tr("&File"));
808 menu->addAction(fileNewAct);
809 menu->addAction(fileOpenAct);
810 menu->addAction(fileSaveAct);
811 menu->addAction(fileSaveAsAct);
812 menu->addAction(fileCloseAct);
813 menu->addSeparator();
814 menu->addAction(exitAct);
816 menu = menuBar()->addMenu(tr("&View"));
817 menu->addAction(zoomInAct);
818 menu->addAction(zoomOutAct);
820 menu = menuBar()->addMenu(tr("&Edit"));
821 menu->addAction(snapToGridAct);
822 menu->addAction(groupAct);
823 menu->addAction(fixAngleAct);
824 menu->addAction(fixLengthAct);
825 menu->addAction(rotateAct);
826 menu->addAction(mirrorAct);
827 menu->addAction(trimAct);
828 menu->addAction(triangulateAct);
829 menu->addAction(connectAct);
830 menu->addAction(disconnectAct);
831 menu->addSeparator();
832 menu->addAction(deleteAct);
833 menu->addSeparator();
834 menu->addAction(addLineAct);
835 menu->addAction(addCircleAct);
836 menu->addAction(addArcAct);
837 menu->addAction(addPolygonAct);
838 menu->addAction(addSplineAct);
839 menu->addAction(addDimensionAct);
840 menu->addSeparator();
841 menu->addAction(settingsAct);
843 menu = menuBar()->addMenu(tr("&Help"));
844 menu->addAction(aboutAct);
848 void ApplicationWindow::CreateToolbars(void)
850 QToolBar * toolbar = addToolBar(tr("File"));
851 toolbar->setObjectName("File"); // Needed for saveState()
852 toolbar->addAction(fileNewAct);
853 toolbar->addAction(fileOpenAct);
854 toolbar->addAction(fileSaveAct);
855 toolbar->addAction(fileSaveAsAct);
856 toolbar->addAction(fileCloseAct);
857 // toolbar->addAction(exitAct);
859 toolbar = addToolBar(tr("View"));
860 toolbar->setObjectName("View");
861 toolbar->addAction(zoomInAct);
862 toolbar->addAction(zoomOutAct);
864 QSpinBox * spinbox = new QSpinBox;
865 toolbar->addWidget(spinbox);
866 // QLineEdit * lineedit = new QLineEdit;
867 toolbar->addWidget(baseUnitInput);
868 toolbar->addWidget(dimensionSizeInput);
870 toolbar = addToolBar(tr("Edit"));
871 toolbar->setObjectName("Edit");
872 toolbar->addAction(snapToGridAct);
873 toolbar->addAction(groupAct);
874 toolbar->addAction(fixAngleAct);
875 toolbar->addAction(fixLengthAct);
876 toolbar->addAction(rotateAct);
877 toolbar->addAction(mirrorAct);
878 toolbar->addAction(trimAct);
879 toolbar->addAction(triangulateAct);
880 toolbar->addAction(deleteAct);
881 toolbar->addAction(connectAct);
882 toolbar->addAction(disconnectAct);
883 toolbar->addSeparator();
884 toolbar->addAction(addLineAct);
885 toolbar->addAction(addCircleAct);
886 toolbar->addAction(addArcAct);
887 toolbar->addAction(addPolygonAct);
888 toolbar->addAction(addSplineAct);
889 toolbar->addAction(addDimensionAct);
891 spinbox->setRange(4, 256);
892 spinbox->setValue(12);
893 baseUnitInput->setText("12");
894 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
895 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
896 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
900 void ApplicationWindow::ReadSettings(void)
902 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
903 QSize size = settings.value("size", QSize(400, 400)).toSize();
904 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
905 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
908 restoreState(settings.value("windowState").toByteArray());
912 void ApplicationWindow::WriteSettings(void)
914 settings.setValue("pos", pos());
915 settings.setValue("size", size());
916 settings.setValue("windowState", saveState());
917 settings.setValue("useAntialiasing", drawing->useAntialiasing);
918 settings.setValue("snapToGrid", snapToGridAct->isChecked());