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);
266 // Do tear-down if Rotate tool has been turned off
267 if (!mirrorAct->isChecked())
268 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
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 // We can be sure that if we've come here, then either an active tool is
418 // being deactivated, or a new tool is being created. In either case, the
419 // old tool needs to be deleted.
420 Global::toolState = TSNone;
422 if (addLineAct->isChecked())
423 Global::tool = TTLine;
424 else if (addCircleAct->isChecked())
425 Global::tool = TTCircle;
426 else if (addArcAct->isChecked())
427 Global::tool = TTArc;
428 else if (addDimensionAct->isChecked())
429 Global::tool = TTDimension;
430 else if (addSplineAct->isChecked())
431 Global::tool = TTSpline;
432 else if (addPolygonAct->isChecked())
433 Global::tool = TTPolygon;
434 else if (deleteAct->isChecked())
435 Global::tool = TTDelete;
436 else if (mirrorAct->isChecked())
437 Global::tool = TTMirror;
438 else if (rotateAct->isChecked())
439 Global::tool = TTRotate;
440 else if (trimAct->isChecked())
441 Global::tool = TTTrim;
442 else if (triangulateAct->isChecked())
443 Global::tool = TTTriangulate;
445 Global::tool = TTNone;
451 void ApplicationWindow::HelpAbout(void)
457 void ApplicationWindow::Settings(void)
459 SettingsDialog dlg(this);
460 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
462 if (dlg.exec() == false)
465 // Deal with stuff here (since user hit "OK" button...)
466 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
472 // Group a bunch of selected objects (which can include other groups) together
473 // or ungroup a selected group.
475 void ApplicationWindow::HandleGrouping(void)
478 int itemsSelected = drawing->document.ItemsSelected();
480 // If nothing selected, do nothing
481 if (itemsSelected == 0)
483 statusBar()->showMessage(tr("No objects selected to make a group from."));
487 // If it's a group that's selected, ungroup it and leave the objects in a
489 if (itemsSelected == 1)
491 Object * object = drawing->document.SelectedItem(0);
495 printf("SelectedItem = NULL!\n");
497 printf("SelectedItem = %08X, type = %i\n", object, object->type);
500 if (object == NULL || object->type != OTContainer)
502 statusBar()->showMessage(tr("A group requires two or more selected objects."));
506 // Need the parent of the group, we're assuming here that the parent is
507 // the drawing's document. Does it matter? Maybe...
508 // Could just stipulate that grouping like this only takes place where the
509 // parent of the group is the drawing's document. Makes life much simpler.
510 ((Container *)object)->SelectAll();
511 ((Container *)object)->MoveContentsTo(&(drawing->document));
512 drawing->document.Delete(object);
513 statusBar()->showMessage(tr("Objects ungrouped."));
515 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
516 // group them and select the group
517 else if (itemsSelected > 1)
519 Container * container = new Container(Vector(), &(drawing->document));
520 drawing->document.MoveSelectedContentsTo(container);
521 drawing->document.Add(container);
522 container->DeselectAll();
523 container->state = OSSelected;
524 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
533 void ApplicationWindow::HandleConnection(void)
536 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
537 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
538 int itemsSelected = drawing->document.ItemsSelected();
540 // If nothing selected, do nothing
541 if (itemsSelected == 0)
543 statusBar()->showMessage(tr("No objects selected to connect."));
547 // If one thing selected, do nothing
548 if (itemsSelected == 1)
550 statusBar()->showMessage(tr("Nothing to connect object to."));
554 // This is O(n^2 / 2) :-P
555 for(int i=0; i<itemsSelected; i++)
557 Object * obj1 = drawing->document.SelectedItem(i);
559 for(int j=i+1; j<itemsSelected; j++)
561 Object * obj2 = drawing->document.SelectedItem(j);
564 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
567 if ((obj1->type == OTLine) && (obj2->type == OTLine))
569 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
570 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
571 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
575 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
576 obj1->Connect(obj2, u);
577 obj2->Connect(obj1, t);
580 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
581 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
583 printf("Testing Line<->Dimension intersection...\n");
584 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
585 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
587 int intersects = Geometry::Intersects(line, dim, &t, &u);
588 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
592 obj1->Connect(obj2, u);
593 obj2->Connect(obj1, t);
603 void ApplicationWindow::HandleDisconnection(void)
608 void ApplicationWindow::HandleGridSizeInPixels(int size)
610 drawing->SetGridSize(size);
615 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
619 double value = text.toDouble(&ok);
621 // Nothing parsable to a double, so quit...
622 if (!ok || value == 0)
625 // drawing->gridSpacing = value;
626 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
627 Global::gridSpacing = value;
628 Global::zoom = drawing->gridPixels / Global::gridSpacing;
629 drawing->UpdateGridBackground();
634 void ApplicationWindow::HandleDimensionSize(QString text)
638 double value = text.toDouble(&ok);
640 // Nothing parsable to a double, so quit...
641 if (!ok || value == 0)
644 // drawing->document.ResizeAllDimensions(value);
649 void ApplicationWindow::CreateActions(void)
651 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
652 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
653 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
655 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);
656 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
658 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
659 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
660 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
662 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
663 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
664 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
666 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
667 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
669 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
670 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
672 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
673 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
675 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
676 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
678 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
679 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
681 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
682 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
684 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);
685 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
687 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
688 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
690 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);
691 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
693 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
694 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
696 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
697 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
699 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
700 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
702 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")));
703 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
705 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")));
706 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
708 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")));
709 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
711 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
713 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
714 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
716 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
717 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
719 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
720 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
722 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
723 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
725 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
726 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
728 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
729 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
731 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
732 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
735 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
736 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
737 /* QActionGroup * group = new QActionGroup(this);
738 group->addAction(deleteAct);
739 group->addAction(addDimensionAct);
740 group->addAction(addLineAct);
741 group->addAction(addCircleAct);
742 group->addAction(addArcAct);//*/
747 // Consolidates action creation from a multi-step process to a single-step one.
749 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
750 QIcon icon, QKeySequence key, bool checkable/*= false*/)
752 QAction * action = new QAction(icon, name, this);
753 action->setToolTip(tooltip);
754 action->setStatusTip(statustip);
755 action->setShortcut(key);
756 action->setCheckable(checkable);
763 // This is essentially the same as the previous function, but this allows more
764 // than one key sequence to be added as key shortcuts.
766 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
767 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
769 QAction * action = new QAction(icon, name, this);
770 action->setToolTip(tooltip);
771 action->setStatusTip(statustip);
772 QList<QKeySequence> keyList;
773 keyList.append(key1);
774 keyList.append(key2);
775 action->setShortcuts(keyList);
776 action->setCheckable(checkable);
782 void ApplicationWindow::CreateMenus(void)
784 QMenu * menu = menuBar()->addMenu(tr("&File"));
785 menu->addAction(fileNewAct);
786 menu->addAction(fileOpenAct);
787 menu->addAction(fileSaveAct);
788 menu->addAction(fileSaveAsAct);
789 menu->addAction(fileCloseAct);
790 menu->addSeparator();
791 menu->addAction(exitAct);
793 menu = menuBar()->addMenu(tr("&View"));
794 menu->addAction(zoomInAct);
795 menu->addAction(zoomOutAct);
797 menu = menuBar()->addMenu(tr("&Edit"));
798 menu->addAction(snapToGridAct);
799 menu->addAction(groupAct);
800 menu->addAction(fixAngleAct);
801 menu->addAction(fixLengthAct);
802 menu->addAction(rotateAct);
803 menu->addAction(mirrorAct);
804 menu->addAction(trimAct);
805 menu->addAction(triangulateAct);
806 menu->addAction(connectAct);
807 menu->addAction(disconnectAct);
808 menu->addSeparator();
809 menu->addAction(deleteAct);
810 menu->addSeparator();
811 menu->addAction(addLineAct);
812 menu->addAction(addCircleAct);
813 menu->addAction(addArcAct);
814 menu->addAction(addPolygonAct);
815 menu->addAction(addSplineAct);
816 menu->addAction(addDimensionAct);
817 menu->addSeparator();
818 menu->addAction(settingsAct);
820 menu = menuBar()->addMenu(tr("&Help"));
821 menu->addAction(aboutAct);
825 void ApplicationWindow::CreateToolbars(void)
827 QToolBar * toolbar = addToolBar(tr("File"));
828 toolbar->setObjectName("File"); // Needed for saveState()
829 toolbar->addAction(fileNewAct);
830 toolbar->addAction(fileOpenAct);
831 toolbar->addAction(fileSaveAct);
832 toolbar->addAction(fileSaveAsAct);
833 toolbar->addAction(fileCloseAct);
834 // toolbar->addAction(exitAct);
836 toolbar = addToolBar(tr("View"));
837 toolbar->setObjectName("View");
838 toolbar->addAction(zoomInAct);
839 toolbar->addAction(zoomOutAct);
841 QSpinBox * spinbox = new QSpinBox;
842 toolbar->addWidget(spinbox);
843 // QLineEdit * lineedit = new QLineEdit;
844 toolbar->addWidget(baseUnitInput);
845 toolbar->addWidget(dimensionSizeInput);
847 toolbar = addToolBar(tr("Edit"));
848 toolbar->setObjectName("Edit");
849 toolbar->addAction(snapToGridAct);
850 toolbar->addAction(groupAct);
851 toolbar->addAction(fixAngleAct);
852 toolbar->addAction(fixLengthAct);
853 toolbar->addAction(rotateAct);
854 toolbar->addAction(mirrorAct);
855 toolbar->addAction(trimAct);
856 toolbar->addAction(triangulateAct);
857 toolbar->addAction(deleteAct);
858 toolbar->addAction(connectAct);
859 toolbar->addAction(disconnectAct);
860 toolbar->addSeparator();
861 toolbar->addAction(addLineAct);
862 toolbar->addAction(addCircleAct);
863 toolbar->addAction(addArcAct);
864 toolbar->addAction(addPolygonAct);
865 toolbar->addAction(addSplineAct);
866 toolbar->addAction(addDimensionAct);
868 spinbox->setRange(4, 256);
869 spinbox->setValue(12);
870 baseUnitInput->setText("12");
871 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
872 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
873 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
877 void ApplicationWindow::ReadSettings(void)
879 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
880 QSize size = settings.value("size", QSize(400, 400)).toSize();
881 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
882 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
885 restoreState(settings.value("windowState").toByteArray());
889 void ApplicationWindow::WriteSettings(void)
891 settings.setValue("pos", pos());
892 settings.setValue("size", size());
893 settings.setValue("windowState", saveState());
894 settings.setValue("useAntialiasing", drawing->useAntialiasing);
895 settings.setValue("snapToGrid", snapToGridAct->isChecked());