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));
555 void ApplicationWindow::HandleConnection(void)
558 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
559 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
560 int itemsSelected = drawing->document.ItemsSelected();
562 // If nothing selected, do nothing
563 if (itemsSelected == 0)
565 statusBar()->showMessage(tr("No objects selected to connect."));
569 // If one thing selected, do nothing
570 if (itemsSelected == 1)
572 statusBar()->showMessage(tr("Nothing to connect object to."));
576 // This is O(n^2 / 2) :-P
577 for(int i=0; i<itemsSelected; i++)
579 Object * obj1 = drawing->document.SelectedItem(i);
581 for(int j=i+1; j<itemsSelected; j++)
583 Object * obj2 = drawing->document.SelectedItem(j);
586 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
589 if ((obj1->type == OTLine) && (obj2->type == OTLine))
591 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
592 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
593 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
597 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
598 obj1->Connect(obj2, u);
599 obj2->Connect(obj1, t);
602 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
603 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
605 printf("Testing Line<->Dimension intersection...\n");
606 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
607 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
609 int intersects = Geometry::Intersects(line, dim, &t, &u);
610 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
614 obj1->Connect(obj2, u);
615 obj2->Connect(obj1, t);
624 void ApplicationWindow::HandleDisconnection(void)
629 void ApplicationWindow::HandleGridSizeInPixels(int size)
631 drawing->SetGridSize(size);
636 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
640 double value = text.toDouble(&ok);
642 // Nothing parsable to a double, so quit...
643 if (!ok || value == 0)
646 // drawing->gridSpacing = value;
647 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
648 Global::gridSpacing = value;
649 Global::zoom = drawing->gridPixels / Global::gridSpacing;
650 drawing->UpdateGridBackground();
655 void ApplicationWindow::HandleDimensionSize(QString text)
659 double value = text.toDouble(&ok);
661 // Nothing parsable to a double, so quit...
662 if (!ok || value == 0)
665 // drawing->document.ResizeAllDimensions(value);
670 void ApplicationWindow::CreateActions(void)
672 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
673 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
674 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
676 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);
677 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
679 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
680 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
681 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
683 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
684 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
685 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
687 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
688 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
690 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
691 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
693 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
694 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
696 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
697 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
699 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
700 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
702 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
703 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
705 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);
706 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
708 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
709 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
711 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);
712 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
714 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
715 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
717 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
718 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
720 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
721 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
723 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")));
724 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
726 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")));
727 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
729 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")));
730 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
732 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
734 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
735 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
737 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
738 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
740 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
741 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
743 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
744 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
746 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
747 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
749 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
750 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
752 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
753 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
756 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
757 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
758 /* QActionGroup * group = new QActionGroup(this);
759 group->addAction(deleteAct);
760 group->addAction(addDimensionAct);
761 group->addAction(addLineAct);
762 group->addAction(addCircleAct);
763 group->addAction(addArcAct);//*/
768 // Consolidates action creation from a multi-step process to a single-step one.
770 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
771 QIcon icon, QKeySequence key, bool checkable/*= false*/)
773 QAction * action = new QAction(icon, name, this);
774 action->setToolTip(tooltip);
775 action->setStatusTip(statustip);
776 action->setShortcut(key);
777 action->setCheckable(checkable);
784 // This is essentially the same as the previous function, but this allows more
785 // than one key sequence to be added as key shortcuts.
787 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
788 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
790 QAction * action = new QAction(icon, name, this);
791 action->setToolTip(tooltip);
792 action->setStatusTip(statustip);
793 QList<QKeySequence> keyList;
794 keyList.append(key1);
795 keyList.append(key2);
796 action->setShortcuts(keyList);
797 action->setCheckable(checkable);
803 void ApplicationWindow::CreateMenus(void)
805 QMenu * menu = menuBar()->addMenu(tr("&File"));
806 menu->addAction(fileNewAct);
807 menu->addAction(fileOpenAct);
808 menu->addAction(fileSaveAct);
809 menu->addAction(fileSaveAsAct);
810 menu->addAction(fileCloseAct);
811 menu->addSeparator();
812 menu->addAction(exitAct);
814 menu = menuBar()->addMenu(tr("&View"));
815 menu->addAction(zoomInAct);
816 menu->addAction(zoomOutAct);
818 menu = menuBar()->addMenu(tr("&Edit"));
819 menu->addAction(snapToGridAct);
820 menu->addAction(groupAct);
821 menu->addAction(fixAngleAct);
822 menu->addAction(fixLengthAct);
823 menu->addAction(rotateAct);
824 menu->addAction(mirrorAct);
825 menu->addAction(trimAct);
826 menu->addAction(triangulateAct);
827 menu->addAction(connectAct);
828 menu->addAction(disconnectAct);
829 menu->addSeparator();
830 menu->addAction(deleteAct);
831 menu->addSeparator();
832 menu->addAction(addLineAct);
833 menu->addAction(addCircleAct);
834 menu->addAction(addArcAct);
835 menu->addAction(addPolygonAct);
836 menu->addAction(addSplineAct);
837 menu->addAction(addDimensionAct);
838 menu->addSeparator();
839 menu->addAction(settingsAct);
841 menu = menuBar()->addMenu(tr("&Help"));
842 menu->addAction(aboutAct);
846 void ApplicationWindow::CreateToolbars(void)
848 QToolBar * toolbar = addToolBar(tr("File"));
849 toolbar->setObjectName("File"); // Needed for saveState()
850 toolbar->addAction(fileNewAct);
851 toolbar->addAction(fileOpenAct);
852 toolbar->addAction(fileSaveAct);
853 toolbar->addAction(fileSaveAsAct);
854 toolbar->addAction(fileCloseAct);
855 // toolbar->addAction(exitAct);
857 toolbar = addToolBar(tr("View"));
858 toolbar->setObjectName("View");
859 toolbar->addAction(zoomInAct);
860 toolbar->addAction(zoomOutAct);
862 QSpinBox * spinbox = new QSpinBox;
863 toolbar->addWidget(spinbox);
864 // QLineEdit * lineedit = new QLineEdit;
865 toolbar->addWidget(baseUnitInput);
866 toolbar->addWidget(dimensionSizeInput);
868 toolbar = addToolBar(tr("Edit"));
869 toolbar->setObjectName("Edit");
870 toolbar->addAction(snapToGridAct);
871 toolbar->addAction(groupAct);
872 toolbar->addAction(fixAngleAct);
873 toolbar->addAction(fixLengthAct);
874 toolbar->addAction(rotateAct);
875 toolbar->addAction(mirrorAct);
876 toolbar->addAction(trimAct);
877 toolbar->addAction(triangulateAct);
878 toolbar->addAction(deleteAct);
879 toolbar->addAction(connectAct);
880 toolbar->addAction(disconnectAct);
881 toolbar->addSeparator();
882 toolbar->addAction(addLineAct);
883 toolbar->addAction(addCircleAct);
884 toolbar->addAction(addArcAct);
885 toolbar->addAction(addPolygonAct);
886 toolbar->addAction(addSplineAct);
887 toolbar->addAction(addDimensionAct);
889 spinbox->setRange(4, 256);
890 spinbox->setValue(12);
891 baseUnitInput->setText("12");
892 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
893 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
894 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
898 void ApplicationWindow::ReadSettings(void)
900 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
901 QSize size = settings.value("size", QSize(400, 400)).toSize();
902 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
903 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
906 restoreState(settings.value("windowState").toByteArray());
910 void ApplicationWindow::WriteSettings(void)
912 settings.setValue("pos", pos());
913 settings.setValue("size", size());
914 settings.setValue("windowState", saveState());
915 settings.setValue("useAntialiasing", drawing->useAntialiasing);
916 settings.setValue("snapToGrid", snapToGridAct->isChecked());