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"
39 #include "settingsdialog.h"
45 DrawingView * ApplicationWindow::drawing;
48 ApplicationWindow::ApplicationWindow():
49 baseUnitInput(new QLineEdit),
50 dimensionSizeInput(new QLineEdit),
51 settings("Underground Software", "Architektonas")
53 drawing = new DrawingView(this);
54 drawing->setMouseTracking(true); // We want *all* mouse events...!
55 drawing->setFocusPolicy(Qt::StrongFocus);
56 setCentralWidget(drawing);
58 aboutWin = new AboutWindow(this);
60 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
62 setWindowIcon(QIcon(":/res/atns-icon.png"));
63 setWindowTitle("Architektonas");
69 // Create Dock widgets
70 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
71 LayerWidget * lw = new LayerWidget;
73 addDockWidget(Qt::RightDockWidgetArea, dock1);
74 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
75 BlockWidget * bw = new BlockWidget;
77 addDockWidget(Qt::RightDockWidgetArea, dock2);
78 // Needed for saveState()
79 dock1->setObjectName("Layers");
80 dock2->setObjectName("Blocks");
83 zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
84 statusBar()->addPermanentWidget(zoomIndicator);
85 statusBar()->showMessage(tr("Ready"));
88 setUnifiedTitleAndToolBarOnMac(true);
89 Global::font = new QFont("Verdana", 15, QFont::Bold);
91 connect(lw, SIGNAL(LayerSelected(int)), drawing, SLOT(SetCurrentLayer(int)));
95 void ApplicationWindow::closeEvent(QCloseEvent * event)
98 event->accept(); // Use ignore() if can't close for some reason
99 //Do we have a memory leak here if we don't delete the font in the Object???
103 void ApplicationWindow::FileNew(void)
105 // Should warn the user if drawing hasn't been saved...
106 drawing->document.objects.empty();
108 documentName.clear();
109 setWindowTitle("Architektonas - Untitled");
110 statusBar()->showMessage(tr("New drawing is ready."));
114 void ApplicationWindow::FileOpen(void)
116 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
117 "", tr("Architektonas files (*.drawing)"));
119 // User cancelled open
120 if (filename.isEmpty())
123 FILE * file = fopen(filename.toUtf8().data(), "r");
128 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
129 msg.setIcon(QMessageBox::Critical);
134 Container container;//(Vector(0, 0));
135 bool successful = FileIO::LoadAtnsFile(file, &container);
141 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
142 msg.setIcon(QMessageBox::Critical);
147 printf("FileOpen: container size = %li\n", container.objects.size());
148 drawing->document = container;
150 documentName = filename;
151 setWindowTitle(QString("Architektonas - %1").arg(documentName));
152 statusBar()->showMessage(tr("Drawing loaded."));
156 void ApplicationWindow::FileSave(void)
158 if (documentName.isEmpty())
159 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
160 "", tr("Architektonas drawings (*.drawing)"));
162 FILE * file = fopen(documentName.toUtf8().data(), "w");
167 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
168 msg.setIcon(QMessageBox::Critical);
173 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
179 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
180 msg.setIcon(QMessageBox::Critical);
182 // In this case, we should unlink the created file, since it's not right...
183 // unlink(documentName.toUtf8().data());
184 QFile::remove(documentName);
188 setWindowTitle(QString("Architektonas - %1").arg(documentName));
189 statusBar()->showMessage(tr("Drawing saved."));
193 void ApplicationWindow::FileSaveAs(void)
195 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
196 documentName, tr("Architektonas drawings (*.drawing)"));
198 if (!filename.isEmpty())
200 documentName = filename;
206 void ApplicationWindow::SnapToGridTool(void)
208 Global::snapToGrid = snapToGridAct->isChecked();
212 void ApplicationWindow::FixAngle(void)
214 Global::fixedAngle = fixAngleAct->isChecked();
218 void ApplicationWindow::FixLength(void)
220 Global::fixedLength = fixLengthAct->isChecked();
224 void ApplicationWindow::DeleteTool(void)
226 // For this tool, we check first to see if anything is selected. If so, we
227 // delete those and *don't* select the delete tool.
228 if (drawing->numSelected > 0)
230 // drawing->DeleteSelectedItems();
231 DeleteSelectedObjects(drawing->document.objects);
233 deleteAct->setChecked(false);
237 // Otherwise, toggle the state of the tool
238 ClearUIToolStatesExcept(deleteAct);
239 SetInternalToolStates();
243 void ApplicationWindow::DimensionTool(void)
245 ClearUIToolStatesExcept(addDimensionAct);
246 SetInternalToolStates();
250 void ApplicationWindow::RotateTool(void)
252 ClearUIToolStatesExcept(rotateAct);
254 // Do tear-down if Rotate tool has been turned off
255 if (!rotateAct->isChecked())
256 drawing->RotateHandler(ToolCleanup, Point(0, 0));
258 SetInternalToolStates();
262 void ApplicationWindow::MirrorTool(void)
264 ClearUIToolStatesExcept(mirrorAct);
265 SetInternalToolStates();
269 void ApplicationWindow::TrimTool(void)
271 ClearUIToolStatesExcept(trimAct);
272 SetInternalToolStates();
276 void ApplicationWindow::TriangulateTool(void)
278 ClearUIToolStatesExcept(triangulateAct);
279 SetInternalToolStates();
283 void ApplicationWindow::AddLineTool(void)
285 ClearUIToolStatesExcept(addLineAct);
286 SetInternalToolStates();
290 void ApplicationWindow::AddCircleTool(void)
292 ClearUIToolStatesExcept(addCircleAct);
293 SetInternalToolStates();
297 void ApplicationWindow::AddArcTool(void)
299 ClearUIToolStatesExcept(addArcAct);
300 SetInternalToolStates();
304 void ApplicationWindow::AddPolygonTool(void)
306 ClearUIToolStatesExcept(addPolygonAct);
307 SetInternalToolStates();
311 void ApplicationWindow::AddSplineTool(void)
313 ClearUIToolStatesExcept(addSplineAct);
314 SetInternalToolStates();
318 void ApplicationWindow::ZoomInTool(void)
320 double zoomFactor = 2.0;
322 We need to find the center of the screen, then figure out where the new corner
323 will be in the zoomed in window.
325 So we know in Qt coords, the center is found via:
326 size.width() / 2 --> xCenter
327 size.height() / 2 --> yCenter
329 transform x/yCenter to Cartesian coordinates. So far, so good.
331 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
332 (after subtracting from center, that is...)
334 QSize size = drawing->size();
335 Vector center(size.width() / 2.0, size.height() / 2.0);
336 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
337 center = Painter::QtToCartesianCoords(center);
338 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
339 Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
340 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
341 Global::origin = newOrigin;
343 //printf("Zoom in... level going from %02f to ", Painter::zoom);
344 // This just zooms leaving origin intact... should zoom in at the current
346 Global::zoom *= zoomFactor;
347 Global::gridSpacing = drawing->gridPixels / Global::zoom;
348 drawing->UpdateGridBackground();
351 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
352 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
356 void ApplicationWindow::ZoomOutTool(void)
361 origin = (223, 160.5)
362 newOrigin should be (-10, -10)
365 center - origin = (213, 150.5)
366 origin - center = (-213, -150.5)
368 + center = (-10, -10)
371 double zoomFactor = 2.0;
372 QSize size = drawing->size();
373 Vector center(size.width() / 2.0, size.height() / 2.0);
374 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
375 center = Painter::QtToCartesianCoords(center);
376 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
377 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
378 // Vector newOrigin = center - (Painter::origin * zoomFactor);
379 Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
380 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
381 Global::origin = newOrigin;
382 //printf("Zoom out...\n");
383 // This just zooms leaving origin intact... should zoom out at the current
385 Global::zoom /= zoomFactor;
386 Global::gridSpacing = drawing->gridPixels / Global::zoom;
387 drawing->UpdateGridBackground();
390 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
391 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
395 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
397 QAction * actionList[] = {
398 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
399 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0
402 for(int i=0; actionList[i]!=0; i++)
404 if (actionList[i] != exception)
405 actionList[i]->setChecked(false);
410 void ApplicationWindow::SetInternalToolStates(void)
412 // We can be sure that if we've come here, then either an active tool is
413 // being deactivated, or a new tool is being created. In either case, the
414 // old tool needs to be deleted.
415 Global::toolState = TSNone;
417 if (addLineAct->isChecked())
418 Global::tool = TTLine;
419 else if (addCircleAct->isChecked())
420 Global::tool = TTCircle;
421 else if (addArcAct->isChecked())
422 Global::tool = TTArc;
423 else if (addDimensionAct->isChecked())
424 Global::tool = TTDimension;
425 else if (addSplineAct->isChecked())
426 Global::tool = TTSpline;
427 else if (addPolygonAct->isChecked())
428 Global::tool = TTPolygon;
429 else if (deleteAct->isChecked())
430 Global::tool = TTDelete;
431 else if (mirrorAct->isChecked())
432 Global::tool = TTMirror;
433 else if (rotateAct->isChecked())
434 Global::tool = TTRotate;
435 else if (trimAct->isChecked())
436 Global::tool = TTTrim;
437 else if (triangulateAct->isChecked())
438 Global::tool = TTTriangulate;
440 Global::tool = TTNone;
446 void ApplicationWindow::HelpAbout(void)
452 void ApplicationWindow::Settings(void)
454 SettingsDialog dlg(this);
455 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
457 if (dlg.exec() == false)
460 // Deal with stuff here (since user hit "OK" button...)
461 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
467 // Group a bunch of selected objects (which can include other groups) together
468 // or ungroup a selected group.
470 void ApplicationWindow::HandleGrouping(void)
473 int itemsSelected = drawing->document.ItemsSelected();
475 // If nothing selected, do nothing
476 if (itemsSelected == 0)
478 statusBar()->showMessage(tr("No objects selected to make a group from."));
482 // If it's a group that's selected, ungroup it and leave the objects in a
484 if (itemsSelected == 1)
486 Object * object = drawing->document.SelectedItem(0);
490 printf("SelectedItem = NULL!\n");
492 printf("SelectedItem = %08X, type = %i\n", object, object->type);
495 if (object == NULL || object->type != OTContainer)
497 statusBar()->showMessage(tr("A group requires two or more selected objects."));
501 // Need the parent of the group, we're assuming here that the parent is
502 // the drawing's document. Does it matter? Maybe...
503 // Could just stipulate that grouping like this only takes place where the
504 // parent of the group is the drawing's document. Makes life much simpler.
505 ((Container *)object)->SelectAll();
506 ((Container *)object)->MoveContentsTo(&(drawing->document));
507 drawing->document.Delete(object);
508 statusBar()->showMessage(tr("Objects ungrouped."));
510 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
511 // group them and select the group
512 else if (itemsSelected > 1)
514 Container * container = new Container(Vector(), &(drawing->document));
515 drawing->document.MoveSelectedContentsTo(container);
516 drawing->document.Add(container);
517 container->DeselectAll();
518 container->state = OSSelected;
519 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
528 void ApplicationWindow::HandleConnection(void)
531 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
532 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
533 int itemsSelected = drawing->document.ItemsSelected();
535 // If nothing selected, do nothing
536 if (itemsSelected == 0)
538 statusBar()->showMessage(tr("No objects selected to connect."));
542 // If one thing selected, do nothing
543 if (itemsSelected == 1)
545 statusBar()->showMessage(tr("Nothing to connect object to."));
549 // This is O(n^2 / 2) :-P
550 for(int i=0; i<itemsSelected; i++)
552 Object * obj1 = drawing->document.SelectedItem(i);
554 for(int j=i+1; j<itemsSelected; j++)
556 Object * obj2 = drawing->document.SelectedItem(j);
559 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
562 if ((obj1->type == OTLine) && (obj2->type == OTLine))
564 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
565 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
566 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
570 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
571 obj1->Connect(obj2, u);
572 obj2->Connect(obj1, t);
575 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
576 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
578 printf("Testing Line<->Dimension intersection...\n");
579 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
580 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
582 int intersects = Geometry::Intersects(line, dim, &t, &u);
583 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
587 obj1->Connect(obj2, u);
588 obj2->Connect(obj1, t);
598 void ApplicationWindow::HandleDisconnection(void)
603 void ApplicationWindow::HandleGridSizeInPixels(int size)
605 drawing->SetGridSize(size);
610 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
614 double value = text.toDouble(&ok);
616 // Nothing parsable to a double, so quit...
617 if (!ok || value == 0)
620 // drawing->gridSpacing = value;
621 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
622 Global::gridSpacing = value;
623 Global::zoom = drawing->gridPixels / Global::gridSpacing;
624 drawing->UpdateGridBackground();
629 void ApplicationWindow::HandleDimensionSize(QString text)
633 double value = text.toDouble(&ok);
635 // Nothing parsable to a double, so quit...
636 if (!ok || value == 0)
639 // drawing->document.ResizeAllDimensions(value);
644 void ApplicationWindow::CreateActions(void)
646 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
647 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
648 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
650 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);
651 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
653 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
654 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
655 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
657 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
658 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
659 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
661 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
662 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
664 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
665 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
667 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
668 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
670 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
671 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
673 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
674 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
676 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
677 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
679 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);
680 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
682 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
683 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
685 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);
686 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
688 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
689 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
691 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
692 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
694 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
695 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
697 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")));
698 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
700 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")));
701 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
703 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")));
704 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
706 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
708 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
709 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
711 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
712 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
714 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
715 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
717 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
718 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
720 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
721 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
723 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
724 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
726 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
727 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
730 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
731 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
732 /* QActionGroup * group = new QActionGroup(this);
733 group->addAction(deleteAct);
734 group->addAction(addDimensionAct);
735 group->addAction(addLineAct);
736 group->addAction(addCircleAct);
737 group->addAction(addArcAct);//*/
742 // Consolidates action creation from a multi-step process to a single-step one.
744 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
745 QIcon icon, QKeySequence key, bool checkable/*= false*/)
747 QAction * action = new QAction(icon, name, this);
748 action->setToolTip(tooltip);
749 action->setStatusTip(statustip);
750 action->setShortcut(key);
751 action->setCheckable(checkable);
758 // This is essentially the same as the previous function, but this allows more
759 // than one key sequence to be added as key shortcuts.
761 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
762 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
764 QAction * action = new QAction(icon, name, this);
765 action->setToolTip(tooltip);
766 action->setStatusTip(statustip);
767 QList<QKeySequence> keyList;
768 keyList.append(key1);
769 keyList.append(key2);
770 action->setShortcuts(keyList);
771 action->setCheckable(checkable);
777 void ApplicationWindow::CreateMenus(void)
779 QMenu * menu = menuBar()->addMenu(tr("&File"));
780 menu->addAction(fileNewAct);
781 menu->addAction(fileOpenAct);
782 menu->addAction(fileSaveAct);
783 menu->addAction(fileSaveAsAct);
784 menu->addAction(fileCloseAct);
785 menu->addSeparator();
786 menu->addAction(exitAct);
788 menu = menuBar()->addMenu(tr("&View"));
789 menu->addAction(zoomInAct);
790 menu->addAction(zoomOutAct);
792 menu = menuBar()->addMenu(tr("&Edit"));
793 menu->addAction(snapToGridAct);
794 menu->addAction(groupAct);
795 menu->addAction(fixAngleAct);
796 menu->addAction(fixLengthAct);
797 menu->addAction(rotateAct);
798 menu->addAction(mirrorAct);
799 menu->addAction(trimAct);
800 menu->addAction(triangulateAct);
801 menu->addAction(connectAct);
802 menu->addAction(disconnectAct);
803 menu->addSeparator();
804 menu->addAction(deleteAct);
805 menu->addSeparator();
806 menu->addAction(addLineAct);
807 menu->addAction(addCircleAct);
808 menu->addAction(addArcAct);
809 menu->addAction(addPolygonAct);
810 menu->addAction(addSplineAct);
811 menu->addAction(addDimensionAct);
812 menu->addSeparator();
813 menu->addAction(settingsAct);
815 menu = menuBar()->addMenu(tr("&Help"));
816 menu->addAction(aboutAct);
820 void ApplicationWindow::CreateToolbars(void)
822 QToolBar * toolbar = addToolBar(tr("File"));
823 toolbar->setObjectName("File"); // Needed for saveState()
824 toolbar->addAction(fileNewAct);
825 toolbar->addAction(fileOpenAct);
826 toolbar->addAction(fileSaveAct);
827 toolbar->addAction(fileSaveAsAct);
828 toolbar->addAction(fileCloseAct);
829 // toolbar->addAction(exitAct);
831 toolbar = addToolBar(tr("View"));
832 toolbar->setObjectName("View");
833 toolbar->addAction(zoomInAct);
834 toolbar->addAction(zoomOutAct);
836 QSpinBox * spinbox = new QSpinBox;
837 toolbar->addWidget(spinbox);
838 // QLineEdit * lineedit = new QLineEdit;
839 toolbar->addWidget(baseUnitInput);
840 toolbar->addWidget(dimensionSizeInput);
842 toolbar = addToolBar(tr("Edit"));
843 toolbar->setObjectName("Edit");
844 toolbar->addAction(snapToGridAct);
845 toolbar->addAction(groupAct);
846 toolbar->addAction(fixAngleAct);
847 toolbar->addAction(fixLengthAct);
848 toolbar->addAction(rotateAct);
849 toolbar->addAction(mirrorAct);
850 toolbar->addAction(trimAct);
851 toolbar->addAction(triangulateAct);
852 toolbar->addAction(deleteAct);
853 toolbar->addAction(connectAct);
854 toolbar->addAction(disconnectAct);
855 toolbar->addSeparator();
856 toolbar->addAction(addLineAct);
857 toolbar->addAction(addCircleAct);
858 toolbar->addAction(addArcAct);
859 toolbar->addAction(addPolygonAct);
860 toolbar->addAction(addSplineAct);
861 toolbar->addAction(addDimensionAct);
863 spinbox->setRange(4, 256);
864 spinbox->setValue(12);
865 baseUnitInput->setText("12");
866 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
867 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
868 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
872 void ApplicationWindow::ReadSettings(void)
874 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
875 QSize size = settings.value("size", QSize(400, 400)).toSize();
876 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
877 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
880 restoreState(settings.value("windowState").toByteArray());
884 void ApplicationWindow::WriteSettings(void)
886 settings.setValue("pos", pos());
887 settings.setValue("size", size());
888 settings.setValue("windowState", saveState());
889 settings.setValue("useAntialiasing", drawing->useAntialiasing);
890 settings.setValue("snapToGrid", snapToGridAct->isChecked());