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)));
92 connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
93 connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
94 connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
98 void ApplicationWindow::closeEvent(QCloseEvent * event)
101 event->accept(); // Use ignore() if can't close for some reason
102 //Do we have a memory leak here if we don't delete the font in the Object???
106 void ApplicationWindow::FileNew(void)
108 // Should warn the user if drawing hasn't been saved...
109 drawing->document.objects.empty();
111 documentName.clear();
112 setWindowTitle("Architektonas - Untitled");
113 statusBar()->showMessage(tr("New drawing is ready."));
117 void ApplicationWindow::FileOpen(void)
119 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
120 "", tr("Architektonas files (*.drawing)"));
122 // User cancelled open
123 if (filename.isEmpty())
126 FILE * file = fopen(filename.toUtf8().data(), "r");
131 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
132 msg.setIcon(QMessageBox::Critical);
137 Container container;//(Vector(0, 0));
138 bool successful = FileIO::LoadAtnsFile(file, &container);
144 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
145 msg.setIcon(QMessageBox::Critical);
150 printf("FileOpen: container size = %li\n", container.objects.size());
151 drawing->document = container;
153 documentName = filename;
154 setWindowTitle(QString("Architektonas - %1").arg(documentName));
155 statusBar()->showMessage(tr("Drawing loaded."));
159 void ApplicationWindow::FileSave(void)
161 if (documentName.isEmpty())
162 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
163 "", tr("Architektonas drawings (*.drawing)"));
165 FILE * file = fopen(documentName.toUtf8().data(), "w");
170 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
171 msg.setIcon(QMessageBox::Critical);
176 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
182 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
183 msg.setIcon(QMessageBox::Critical);
185 // In this case, we should unlink the created file, since it's not right...
186 // unlink(documentName.toUtf8().data());
187 QFile::remove(documentName);
191 setWindowTitle(QString("Architektonas - %1").arg(documentName));
192 statusBar()->showMessage(tr("Drawing saved."));
196 void ApplicationWindow::FileSaveAs(void)
198 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
199 documentName, tr("Architektonas drawings (*.drawing)"));
201 if (!filename.isEmpty())
203 documentName = filename;
209 void ApplicationWindow::SnapToGridTool(void)
211 Global::snapToGrid = snapToGridAct->isChecked();
215 void ApplicationWindow::FixAngle(void)
217 Global::fixedAngle = fixAngleAct->isChecked();
221 void ApplicationWindow::FixLength(void)
223 Global::fixedLength = fixLengthAct->isChecked();
227 void ApplicationWindow::DeleteTool(void)
229 // For this tool, we check first to see if anything is selected. If so, we
230 // delete those and *don't* select the delete tool.
231 if (drawing->numSelected > 0)
233 // drawing->DeleteSelectedItems();
234 DeleteSelectedObjects(drawing->document.objects);
236 deleteAct->setChecked(false);
240 // Otherwise, toggle the state of the tool
241 ClearUIToolStatesExcept(deleteAct);
242 SetInternalToolStates();
246 void ApplicationWindow::DimensionTool(void)
248 ClearUIToolStatesExcept(addDimensionAct);
249 SetInternalToolStates();
253 void ApplicationWindow::RotateTool(void)
255 ClearUIToolStatesExcept(rotateAct);
257 // Do tear-down if Rotate tool has been turned off
258 if (!rotateAct->isChecked())
259 drawing->RotateHandler(ToolCleanup, Point(0, 0));
261 SetInternalToolStates();
265 void ApplicationWindow::MirrorTool(void)
267 ClearUIToolStatesExcept(mirrorAct);
269 // Do tear-down if Rotate tool has been turned off
270 if (!mirrorAct->isChecked())
271 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
273 SetInternalToolStates();
277 void ApplicationWindow::TrimTool(void)
279 ClearUIToolStatesExcept(trimAct);
280 SetInternalToolStates();
284 void ApplicationWindow::TriangulateTool(void)
286 ClearUIToolStatesExcept(triangulateAct);
287 SetInternalToolStates();
291 void ApplicationWindow::AddLineTool(void)
293 ClearUIToolStatesExcept(addLineAct);
294 SetInternalToolStates();
298 void ApplicationWindow::AddCircleTool(void)
300 ClearUIToolStatesExcept(addCircleAct);
301 SetInternalToolStates();
305 void ApplicationWindow::AddArcTool(void)
307 ClearUIToolStatesExcept(addArcAct);
308 SetInternalToolStates();
312 void ApplicationWindow::AddPolygonTool(void)
314 ClearUIToolStatesExcept(addPolygonAct);
315 SetInternalToolStates();
319 void ApplicationWindow::AddSplineTool(void)
321 ClearUIToolStatesExcept(addSplineAct);
322 SetInternalToolStates();
326 void ApplicationWindow::ZoomInTool(void)
328 double zoomFactor = 2.0;
330 We need to find the center of the screen, then figure out where the new corner
331 will be in the zoomed in window.
333 So we know in Qt coords, the center is found via:
334 size.width() / 2 --> xCenter
335 size.height() / 2 --> yCenter
337 transform x/yCenter to Cartesian coordinates. So far, so good.
339 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
340 (after subtracting from center, that is...)
342 QSize size = drawing->size();
343 Vector center(size.width() / 2.0, size.height() / 2.0);
344 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
345 center = Painter::QtToCartesianCoords(center);
346 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
347 Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
348 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
349 Global::origin = newOrigin;
351 //printf("Zoom in... level going from %02f to ", Painter::zoom);
352 // This just zooms leaving origin intact... should zoom in at the current
354 Global::zoom *= zoomFactor;
355 Global::gridSpacing = drawing->gridPixels / Global::zoom;
356 drawing->UpdateGridBackground();
359 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
360 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
364 void ApplicationWindow::ZoomOutTool(void)
369 origin = (223, 160.5)
370 newOrigin should be (-10, -10)
373 center - origin = (213, 150.5)
374 origin - center = (-213, -150.5)
376 + center = (-10, -10)
379 double zoomFactor = 2.0;
380 QSize size = drawing->size();
381 Vector center(size.width() / 2.0, size.height() / 2.0);
382 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
383 center = Painter::QtToCartesianCoords(center);
384 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
385 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
386 // Vector newOrigin = center - (Painter::origin * zoomFactor);
387 Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
388 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
389 Global::origin = newOrigin;
390 //printf("Zoom out...\n");
391 // This just zooms leaving origin intact... should zoom out at the current
393 Global::zoom /= zoomFactor;
394 Global::gridSpacing = drawing->gridPixels / Global::zoom;
395 drawing->UpdateGridBackground();
398 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
399 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
403 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
405 QAction * actionList[] = {
406 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
407 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0
410 for(int i=0; actionList[i]!=0; i++)
412 if (actionList[i] != exception)
413 actionList[i]->setChecked(false);
418 void ApplicationWindow::SetInternalToolStates(void)
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 (addLineAct->isChecked())
426 Global::tool = TTLine;
427 else if (addCircleAct->isChecked())
428 Global::tool = TTCircle;
429 else if (addArcAct->isChecked())
430 Global::tool = TTArc;
431 else if (addDimensionAct->isChecked())
432 Global::tool = TTDimension;
433 else if (addSplineAct->isChecked())
434 Global::tool = TTSpline;
435 else if (addPolygonAct->isChecked())
436 Global::tool = TTPolygon;
437 else if (deleteAct->isChecked())
438 Global::tool = TTDelete;
439 else if (mirrorAct->isChecked())
440 Global::tool = TTMirror;
441 else if (rotateAct->isChecked())
442 Global::tool = TTRotate;
443 else if (trimAct->isChecked())
444 Global::tool = TTTrim;
445 else if (triangulateAct->isChecked())
446 Global::tool = TTTriangulate;
448 Global::tool = TTNone;
454 void ApplicationWindow::HelpAbout(void)
460 void ApplicationWindow::Settings(void)
462 SettingsDialog dlg(this);
463 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
465 if (dlg.exec() == false)
468 // Deal with stuff here (since user hit "OK" button...)
469 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
475 // Group a bunch of selected objects (which can include other groups) together
476 // or ungroup a selected group.
478 void ApplicationWindow::HandleGrouping(void)
481 int itemsSelected = drawing->document.ItemsSelected();
483 // If nothing selected, do nothing
484 if (itemsSelected == 0)
486 statusBar()->showMessage(tr("No objects selected to make a group from."));
490 // If it's a group that's selected, ungroup it and leave the objects in a
492 if (itemsSelected == 1)
494 Object * object = drawing->document.SelectedItem(0);
498 printf("SelectedItem = NULL!\n");
500 printf("SelectedItem = %08X, type = %i\n", object, object->type);
503 if (object == NULL || object->type != OTContainer)
505 statusBar()->showMessage(tr("A group requires two or more selected objects."));
509 // Need the parent of the group, we're assuming here that the parent is
510 // the drawing's document. Does it matter? Maybe...
511 // Could just stipulate that grouping like this only takes place where the
512 // parent of the group is the drawing's document. Makes life much simpler.
513 ((Container *)object)->SelectAll();
514 ((Container *)object)->MoveContentsTo(&(drawing->document));
515 drawing->document.Delete(object);
516 statusBar()->showMessage(tr("Objects ungrouped."));
518 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
519 // group them and select the group
520 else if (itemsSelected > 1)
522 Container * container = new Container(Vector(), &(drawing->document));
523 drawing->document.MoveSelectedContentsTo(container);
524 drawing->document.Add(container);
525 container->DeselectAll();
526 container->state = OSSelected;
527 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
536 void ApplicationWindow::HandleConnection(void)
539 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
540 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
541 int itemsSelected = drawing->document.ItemsSelected();
543 // If nothing selected, do nothing
544 if (itemsSelected == 0)
546 statusBar()->showMessage(tr("No objects selected to connect."));
550 // If one thing selected, do nothing
551 if (itemsSelected == 1)
553 statusBar()->showMessage(tr("Nothing to connect object to."));
557 // This is O(n^2 / 2) :-P
558 for(int i=0; i<itemsSelected; i++)
560 Object * obj1 = drawing->document.SelectedItem(i);
562 for(int j=i+1; j<itemsSelected; j++)
564 Object * obj2 = drawing->document.SelectedItem(j);
567 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
570 if ((obj1->type == OTLine) && (obj2->type == OTLine))
572 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
573 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
574 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
578 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
579 obj1->Connect(obj2, u);
580 obj2->Connect(obj1, t);
583 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
584 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
586 printf("Testing Line<->Dimension intersection...\n");
587 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
588 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
590 int intersects = Geometry::Intersects(line, dim, &t, &u);
591 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
595 obj1->Connect(obj2, u);
596 obj2->Connect(obj1, t);
606 void ApplicationWindow::HandleDisconnection(void)
611 void ApplicationWindow::HandleGridSizeInPixels(int size)
613 drawing->SetGridSize(size);
618 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
622 double value = text.toDouble(&ok);
624 // Nothing parsable to a double, so quit...
625 if (!ok || value == 0)
628 // drawing->gridSpacing = value;
629 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
630 Global::gridSpacing = value;
631 Global::zoom = drawing->gridPixels / Global::gridSpacing;
632 drawing->UpdateGridBackground();
637 void ApplicationWindow::HandleDimensionSize(QString text)
641 double value = text.toDouble(&ok);
643 // Nothing parsable to a double, so quit...
644 if (!ok || value == 0)
647 // drawing->document.ResizeAllDimensions(value);
652 void ApplicationWindow::CreateActions(void)
654 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
655 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
656 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
658 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);
659 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
661 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
662 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
663 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
665 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
666 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
667 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
669 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
670 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
672 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
673 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
675 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
676 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
678 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
679 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
681 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
682 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
684 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
685 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
687 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);
688 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
690 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
691 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
693 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);
694 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
696 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
697 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
699 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
700 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
702 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
703 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
705 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")));
706 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
708 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")));
709 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
711 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")));
712 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
714 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
716 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
717 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
719 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
720 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
722 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
723 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
725 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
726 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
728 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
729 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
731 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
732 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
734 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
735 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
738 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
739 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
740 /* QActionGroup * group = new QActionGroup(this);
741 group->addAction(deleteAct);
742 group->addAction(addDimensionAct);
743 group->addAction(addLineAct);
744 group->addAction(addCircleAct);
745 group->addAction(addArcAct);//*/
750 // Consolidates action creation from a multi-step process to a single-step one.
752 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
753 QIcon icon, QKeySequence key, bool checkable/*= false*/)
755 QAction * action = new QAction(icon, name, this);
756 action->setToolTip(tooltip);
757 action->setStatusTip(statustip);
758 action->setShortcut(key);
759 action->setCheckable(checkable);
766 // This is essentially the same as the previous function, but this allows more
767 // than one key sequence to be added as key shortcuts.
769 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
770 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
772 QAction * action = new QAction(icon, name, this);
773 action->setToolTip(tooltip);
774 action->setStatusTip(statustip);
775 QList<QKeySequence> keyList;
776 keyList.append(key1);
777 keyList.append(key2);
778 action->setShortcuts(keyList);
779 action->setCheckable(checkable);
785 void ApplicationWindow::CreateMenus(void)
787 QMenu * menu = menuBar()->addMenu(tr("&File"));
788 menu->addAction(fileNewAct);
789 menu->addAction(fileOpenAct);
790 menu->addAction(fileSaveAct);
791 menu->addAction(fileSaveAsAct);
792 menu->addAction(fileCloseAct);
793 menu->addSeparator();
794 menu->addAction(exitAct);
796 menu = menuBar()->addMenu(tr("&View"));
797 menu->addAction(zoomInAct);
798 menu->addAction(zoomOutAct);
800 menu = menuBar()->addMenu(tr("&Edit"));
801 menu->addAction(snapToGridAct);
802 menu->addAction(groupAct);
803 menu->addAction(fixAngleAct);
804 menu->addAction(fixLengthAct);
805 menu->addAction(rotateAct);
806 menu->addAction(mirrorAct);
807 menu->addAction(trimAct);
808 menu->addAction(triangulateAct);
809 menu->addAction(connectAct);
810 menu->addAction(disconnectAct);
811 menu->addSeparator();
812 menu->addAction(deleteAct);
813 menu->addSeparator();
814 menu->addAction(addLineAct);
815 menu->addAction(addCircleAct);
816 menu->addAction(addArcAct);
817 menu->addAction(addPolygonAct);
818 menu->addAction(addSplineAct);
819 menu->addAction(addDimensionAct);
820 menu->addSeparator();
821 menu->addAction(settingsAct);
823 menu = menuBar()->addMenu(tr("&Help"));
824 menu->addAction(aboutAct);
828 void ApplicationWindow::CreateToolbars(void)
830 QToolBar * toolbar = addToolBar(tr("File"));
831 toolbar->setObjectName("File"); // Needed for saveState()
832 toolbar->addAction(fileNewAct);
833 toolbar->addAction(fileOpenAct);
834 toolbar->addAction(fileSaveAct);
835 toolbar->addAction(fileSaveAsAct);
836 toolbar->addAction(fileCloseAct);
837 // toolbar->addAction(exitAct);
839 toolbar = addToolBar(tr("View"));
840 toolbar->setObjectName("View");
841 toolbar->addAction(zoomInAct);
842 toolbar->addAction(zoomOutAct);
844 QSpinBox * spinbox = new QSpinBox;
845 toolbar->addWidget(spinbox);
846 // QLineEdit * lineedit = new QLineEdit;
847 toolbar->addWidget(baseUnitInput);
848 toolbar->addWidget(dimensionSizeInput);
850 toolbar = addToolBar(tr("Edit"));
851 toolbar->setObjectName("Edit");
852 toolbar->addAction(snapToGridAct);
853 toolbar->addAction(groupAct);
854 toolbar->addAction(fixAngleAct);
855 toolbar->addAction(fixLengthAct);
856 toolbar->addAction(rotateAct);
857 toolbar->addAction(mirrorAct);
858 toolbar->addAction(trimAct);
859 toolbar->addAction(triangulateAct);
860 toolbar->addAction(deleteAct);
861 toolbar->addAction(connectAct);
862 toolbar->addAction(disconnectAct);
863 toolbar->addSeparator();
864 toolbar->addAction(addLineAct);
865 toolbar->addAction(addCircleAct);
866 toolbar->addAction(addArcAct);
867 toolbar->addAction(addPolygonAct);
868 toolbar->addAction(addSplineAct);
869 toolbar->addAction(addDimensionAct);
871 spinbox->setRange(4, 256);
872 spinbox->setValue(12);
873 baseUnitInput->setText("12");
874 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
875 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
876 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
880 void ApplicationWindow::ReadSettings(void)
882 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
883 QSize size = settings.value("size", QSize(400, 400)).toSize();
884 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
885 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
888 restoreState(settings.value("windowState").toByteArray());
892 void ApplicationWindow::WriteSettings(void)
894 settings.setValue("pos", pos());
895 settings.setValue("size", size());
896 settings.setValue("windowState", saveState());
897 settings.setValue("useAntialiasing", drawing->useAntialiasing);
898 settings.setValue("snapToGrid", snapToGridAct->isChecked());