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(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
92 connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
93 connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
97 void ApplicationWindow::closeEvent(QCloseEvent * event)
100 event->accept(); // Use ignore() if can't close for some reason
101 //Do we have a memory leak here if we don't delete the font in the Object???
105 void ApplicationWindow::FileNew(void)
107 // Should warn the user if drawing hasn't been saved...
108 drawing->document.objects.empty();
110 documentName.clear();
111 setWindowTitle("Architektonas - Untitled");
112 statusBar()->showMessage(tr("New drawing is ready."));
116 void ApplicationWindow::FileOpen(void)
118 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
119 "", tr("Architektonas files (*.drawing)"));
121 // User cancelled open
122 if (filename.isEmpty())
125 FILE * file = fopen(filename.toUtf8().data(), "r");
130 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
131 msg.setIcon(QMessageBox::Critical);
136 Container container;//(Vector(0, 0));
137 bool successful = FileIO::LoadAtnsFile(file, &container);
143 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
144 msg.setIcon(QMessageBox::Critical);
149 printf("FileOpen: container size = %li\n", container.objects.size());
150 drawing->document = container;
152 documentName = filename;
153 setWindowTitle(QString("Architektonas - %1").arg(documentName));
154 statusBar()->showMessage(tr("Drawing loaded."));
158 void ApplicationWindow::FileSave(void)
160 if (documentName.isEmpty())
161 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
162 "", tr("Architektonas drawings (*.drawing)"));
164 FILE * file = fopen(documentName.toUtf8().data(), "w");
169 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
170 msg.setIcon(QMessageBox::Critical);
175 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
181 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
182 msg.setIcon(QMessageBox::Critical);
184 // In this case, we should unlink the created file, since it's not right...
185 // unlink(documentName.toUtf8().data());
186 QFile::remove(documentName);
190 setWindowTitle(QString("Architektonas - %1").arg(documentName));
191 statusBar()->showMessage(tr("Drawing saved."));
195 void ApplicationWindow::FileSaveAs(void)
197 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
198 documentName, tr("Architektonas drawings (*.drawing)"));
200 if (!filename.isEmpty())
202 documentName = filename;
208 void ApplicationWindow::SnapToGridTool(void)
210 Global::snapToGrid = snapToGridAct->isChecked();
214 void ApplicationWindow::FixAngle(void)
216 Global::fixedAngle = fixAngleAct->isChecked();
220 void ApplicationWindow::FixLength(void)
222 Global::fixedLength = fixLengthAct->isChecked();
226 void ApplicationWindow::DeleteTool(void)
228 // For this tool, we check first to see if anything is selected. If so, we
229 // delete those and *don't* select the delete tool.
230 if (drawing->numSelected > 0)
232 // drawing->DeleteSelectedItems();
233 DeleteSelectedObjects(drawing->document.objects);
235 deleteAct->setChecked(false);
239 // Otherwise, toggle the state of the tool
240 ClearUIToolStatesExcept(deleteAct);
241 SetInternalToolStates();
245 void ApplicationWindow::DimensionTool(void)
247 ClearUIToolStatesExcept(addDimensionAct);
248 SetInternalToolStates();
252 void ApplicationWindow::RotateTool(void)
254 ClearUIToolStatesExcept(rotateAct);
256 // Do tear-down if Rotate tool has been turned off
257 if (!rotateAct->isChecked())
258 drawing->RotateHandler(ToolCleanup, Point(0, 0));
260 SetInternalToolStates();
264 void ApplicationWindow::MirrorTool(void)
266 ClearUIToolStatesExcept(mirrorAct);
268 // Do tear-down if Rotate tool has been turned off
269 if (!mirrorAct->isChecked())
270 drawing->MirrorHandler(ToolCleanup, Point(0, 0));
272 SetInternalToolStates();
276 void ApplicationWindow::TrimTool(void)
278 ClearUIToolStatesExcept(trimAct);
279 SetInternalToolStates();
283 void ApplicationWindow::TriangulateTool(void)
285 ClearUIToolStatesExcept(triangulateAct);
286 SetInternalToolStates();
290 void ApplicationWindow::AddLineTool(void)
292 ClearUIToolStatesExcept(addLineAct);
293 SetInternalToolStates();
297 void ApplicationWindow::AddCircleTool(void)
299 ClearUIToolStatesExcept(addCircleAct);
300 SetInternalToolStates();
304 void ApplicationWindow::AddArcTool(void)
306 ClearUIToolStatesExcept(addArcAct);
307 SetInternalToolStates();
311 void ApplicationWindow::AddPolygonTool(void)
313 ClearUIToolStatesExcept(addPolygonAct);
314 SetInternalToolStates();
318 void ApplicationWindow::AddSplineTool(void)
320 ClearUIToolStatesExcept(addSplineAct);
321 SetInternalToolStates();
325 void ApplicationWindow::ZoomInTool(void)
327 double zoomFactor = 2.0;
329 We need to find the center of the screen, then figure out where the new corner
330 will be in the zoomed in window.
332 So we know in Qt coords, the center is found via:
333 size.width() / 2 --> xCenter
334 size.height() / 2 --> yCenter
336 transform x/yCenter to Cartesian coordinates. So far, so good.
338 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
339 (after subtracting from center, that is...)
341 QSize size = drawing->size();
342 Vector center(size.width() / 2.0, size.height() / 2.0);
343 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
344 center = Painter::QtToCartesianCoords(center);
345 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
346 Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
347 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
348 Global::origin = newOrigin;
350 //printf("Zoom in... level going from %02f to ", Painter::zoom);
351 // This just zooms leaving origin intact... should zoom in at the current
353 Global::zoom *= zoomFactor;
354 Global::gridSpacing = drawing->gridPixels / Global::zoom;
355 drawing->UpdateGridBackground();
358 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
359 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
363 void ApplicationWindow::ZoomOutTool(void)
368 origin = (223, 160.5)
369 newOrigin should be (-10, -10)
372 center - origin = (213, 150.5)
373 origin - center = (-213, -150.5)
375 + center = (-10, -10)
378 double zoomFactor = 2.0;
379 QSize size = drawing->size();
380 Vector center(size.width() / 2.0, size.height() / 2.0);
381 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
382 center = Painter::QtToCartesianCoords(center);
383 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
384 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
385 // Vector newOrigin = center - (Painter::origin * zoomFactor);
386 Vector newOrigin = center + ((Global::origin - center) * zoomFactor);
387 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
388 Global::origin = newOrigin;
389 //printf("Zoom out...\n");
390 // This just zooms leaving origin intact... should zoom out at the current
392 Global::zoom /= zoomFactor;
393 Global::gridSpacing = drawing->gridPixels / Global::zoom;
394 drawing->UpdateGridBackground();
397 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
398 baseUnitInput->setText(QString("%1").arg(Global::gridSpacing));
402 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
404 QAction * actionList[] = {
405 addArcAct, addLineAct, addCircleAct, addDimensionAct, addPolygonAct,
406 addSplineAct, deleteAct, rotateAct, mirrorAct, trimAct, triangulateAct, 0
409 for(int i=0; actionList[i]!=0; i++)
411 if (actionList[i] != exception)
412 actionList[i]->setChecked(false);
417 void ApplicationWindow::SetInternalToolStates(void)
419 // We can be sure that if we've come here, then either an active tool is
420 // being deactivated, or a new tool is being created. In either case, the
421 // old tool needs to be deleted.
422 Global::toolState = TSNone;
424 if (addLineAct->isChecked())
425 Global::tool = TTLine;
426 else if (addCircleAct->isChecked())
427 Global::tool = TTCircle;
428 else if (addArcAct->isChecked())
429 Global::tool = TTArc;
430 else if (addDimensionAct->isChecked())
431 Global::tool = TTDimension;
432 else if (addSplineAct->isChecked())
433 Global::tool = TTSpline;
434 else if (addPolygonAct->isChecked())
435 Global::tool = TTPolygon;
436 else if (deleteAct->isChecked())
437 Global::tool = TTDelete;
438 else if (mirrorAct->isChecked())
439 Global::tool = TTMirror;
440 else if (rotateAct->isChecked())
441 Global::tool = TTRotate;
442 else if (trimAct->isChecked())
443 Global::tool = TTTrim;
444 else if (triangulateAct->isChecked())
445 Global::tool = TTTriangulate;
447 Global::tool = TTNone;
453 void ApplicationWindow::HelpAbout(void)
459 void ApplicationWindow::Settings(void)
461 SettingsDialog dlg(this);
462 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
464 if (dlg.exec() == false)
467 // Deal with stuff here (since user hit "OK" button...)
468 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
474 // Group a bunch of selected objects (which can include other groups) together
475 // or ungroup a selected group.
477 void ApplicationWindow::HandleGrouping(void)
480 int itemsSelected = drawing->document.ItemsSelected();
482 // If nothing selected, do nothing
483 if (itemsSelected == 0)
485 statusBar()->showMessage(tr("No objects selected to make a group from."));
489 // If it's a group that's selected, ungroup it and leave the objects in a
491 if (itemsSelected == 1)
493 Object * object = drawing->document.SelectedItem(0);
497 printf("SelectedItem = NULL!\n");
499 printf("SelectedItem = %08X, type = %i\n", object, object->type);
502 if (object == NULL || object->type != OTContainer)
504 statusBar()->showMessage(tr("A group requires two or more selected objects."));
508 // Need the parent of the group, we're assuming here that the parent is
509 // the drawing's document. Does it matter? Maybe...
510 // Could just stipulate that grouping like this only takes place where the
511 // parent of the group is the drawing's document. Makes life much simpler.
512 ((Container *)object)->SelectAll();
513 ((Container *)object)->MoveContentsTo(&(drawing->document));
514 drawing->document.Delete(object);
515 statusBar()->showMessage(tr("Objects ungrouped."));
517 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
518 // group them and select the group
519 else if (itemsSelected > 1)
521 Container * container = new Container(Vector(), &(drawing->document));
522 drawing->document.MoveSelectedContentsTo(container);
523 drawing->document.Add(container);
524 container->DeselectAll();
525 container->state = OSSelected;
526 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
535 void ApplicationWindow::HandleConnection(void)
538 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
539 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
540 int itemsSelected = drawing->document.ItemsSelected();
542 // If nothing selected, do nothing
543 if (itemsSelected == 0)
545 statusBar()->showMessage(tr("No objects selected to connect."));
549 // If one thing selected, do nothing
550 if (itemsSelected == 1)
552 statusBar()->showMessage(tr("Nothing to connect object to."));
556 // This is O(n^2 / 2) :-P
557 for(int i=0; i<itemsSelected; i++)
559 Object * obj1 = drawing->document.SelectedItem(i);
561 for(int j=i+1; j<itemsSelected; j++)
563 Object * obj2 = drawing->document.SelectedItem(j);
566 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
569 if ((obj1->type == OTLine) && (obj2->type == OTLine))
571 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
572 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
573 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
577 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
578 obj1->Connect(obj2, u);
579 obj2->Connect(obj1, t);
582 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
583 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
585 printf("Testing Line<->Dimension intersection...\n");
586 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
587 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
589 int intersects = Geometry::Intersects(line, dim, &t, &u);
590 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
594 obj1->Connect(obj2, u);
595 obj2->Connect(obj1, t);
605 void ApplicationWindow::HandleDisconnection(void)
610 void ApplicationWindow::HandleGridSizeInPixels(int size)
612 drawing->SetGridSize(size);
617 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
621 double value = text.toDouble(&ok);
623 // Nothing parsable to a double, so quit...
624 if (!ok || value == 0)
627 // drawing->gridSpacing = value;
628 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
629 Global::gridSpacing = value;
630 Global::zoom = drawing->gridPixels / Global::gridSpacing;
631 drawing->UpdateGridBackground();
636 void ApplicationWindow::HandleDimensionSize(QString text)
640 double value = text.toDouble(&ok);
642 // Nothing parsable to a double, so quit...
643 if (!ok || value == 0)
646 // drawing->document.ResizeAllDimensions(value);
651 void ApplicationWindow::CreateActions(void)
653 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
654 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
655 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
657 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);
658 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
660 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
661 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
662 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
664 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
665 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
666 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
668 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
669 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
671 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
672 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
674 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
675 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
677 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
678 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
680 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
681 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
683 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
684 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
686 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);
687 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
689 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
690 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
692 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);
693 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
695 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
696 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
698 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
699 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
701 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
702 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
704 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")));
705 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
707 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")));
708 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
710 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")));
711 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
713 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
715 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
716 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
718 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
719 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
721 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
722 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
724 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
725 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
727 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
728 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
730 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
731 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
733 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
734 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
737 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
738 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
739 /* QActionGroup * group = new QActionGroup(this);
740 group->addAction(deleteAct);
741 group->addAction(addDimensionAct);
742 group->addAction(addLineAct);
743 group->addAction(addCircleAct);
744 group->addAction(addArcAct);//*/
749 // Consolidates action creation from a multi-step process to a single-step one.
751 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
752 QIcon icon, QKeySequence key, bool checkable/*= false*/)
754 QAction * action = new QAction(icon, name, this);
755 action->setToolTip(tooltip);
756 action->setStatusTip(statustip);
757 action->setShortcut(key);
758 action->setCheckable(checkable);
765 // This is essentially the same as the previous function, but this allows more
766 // than one key sequence to be added as key shortcuts.
768 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
769 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
771 QAction * action = new QAction(icon, name, this);
772 action->setToolTip(tooltip);
773 action->setStatusTip(statustip);
774 QList<QKeySequence> keyList;
775 keyList.append(key1);
776 keyList.append(key2);
777 action->setShortcuts(keyList);
778 action->setCheckable(checkable);
784 void ApplicationWindow::CreateMenus(void)
786 QMenu * menu = menuBar()->addMenu(tr("&File"));
787 menu->addAction(fileNewAct);
788 menu->addAction(fileOpenAct);
789 menu->addAction(fileSaveAct);
790 menu->addAction(fileSaveAsAct);
791 menu->addAction(fileCloseAct);
792 menu->addSeparator();
793 menu->addAction(exitAct);
795 menu = menuBar()->addMenu(tr("&View"));
796 menu->addAction(zoomInAct);
797 menu->addAction(zoomOutAct);
799 menu = menuBar()->addMenu(tr("&Edit"));
800 menu->addAction(snapToGridAct);
801 menu->addAction(groupAct);
802 menu->addAction(fixAngleAct);
803 menu->addAction(fixLengthAct);
804 menu->addAction(rotateAct);
805 menu->addAction(mirrorAct);
806 menu->addAction(trimAct);
807 menu->addAction(triangulateAct);
808 menu->addAction(connectAct);
809 menu->addAction(disconnectAct);
810 menu->addSeparator();
811 menu->addAction(deleteAct);
812 menu->addSeparator();
813 menu->addAction(addLineAct);
814 menu->addAction(addCircleAct);
815 menu->addAction(addArcAct);
816 menu->addAction(addPolygonAct);
817 menu->addAction(addSplineAct);
818 menu->addAction(addDimensionAct);
819 menu->addSeparator();
820 menu->addAction(settingsAct);
822 menu = menuBar()->addMenu(tr("&Help"));
823 menu->addAction(aboutAct);
827 void ApplicationWindow::CreateToolbars(void)
829 QToolBar * toolbar = addToolBar(tr("File"));
830 toolbar->setObjectName("File"); // Needed for saveState()
831 toolbar->addAction(fileNewAct);
832 toolbar->addAction(fileOpenAct);
833 toolbar->addAction(fileSaveAct);
834 toolbar->addAction(fileSaveAsAct);
835 toolbar->addAction(fileCloseAct);
836 // toolbar->addAction(exitAct);
838 toolbar = addToolBar(tr("View"));
839 toolbar->setObjectName("View");
840 toolbar->addAction(zoomInAct);
841 toolbar->addAction(zoomOutAct);
843 QSpinBox * spinbox = new QSpinBox;
844 toolbar->addWidget(spinbox);
845 // QLineEdit * lineedit = new QLineEdit;
846 toolbar->addWidget(baseUnitInput);
847 toolbar->addWidget(dimensionSizeInput);
849 toolbar = addToolBar(tr("Edit"));
850 toolbar->setObjectName("Edit");
851 toolbar->addAction(snapToGridAct);
852 toolbar->addAction(groupAct);
853 toolbar->addAction(fixAngleAct);
854 toolbar->addAction(fixLengthAct);
855 toolbar->addAction(rotateAct);
856 toolbar->addAction(mirrorAct);
857 toolbar->addAction(trimAct);
858 toolbar->addAction(triangulateAct);
859 toolbar->addAction(deleteAct);
860 toolbar->addAction(connectAct);
861 toolbar->addAction(disconnectAct);
862 toolbar->addSeparator();
863 toolbar->addAction(addLineAct);
864 toolbar->addAction(addCircleAct);
865 toolbar->addAction(addArcAct);
866 toolbar->addAction(addPolygonAct);
867 toolbar->addAction(addSplineAct);
868 toolbar->addAction(addDimensionAct);
870 spinbox->setRange(4, 256);
871 spinbox->setValue(12);
872 baseUnitInput->setText("12");
873 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
874 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
875 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
879 void ApplicationWindow::ReadSettings(void)
881 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
882 QSize size = settings.value("size", QSize(400, 400)).toSize();
883 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
884 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
887 restoreState(settings.value("windowState").toByteArray());
891 void ApplicationWindow::WriteSettings(void)
893 settings.setValue("pos", pos());
894 settings.setValue("size", size());
895 settings.setValue("windowState", saveState());
896 settings.setValue("useAntialiasing", drawing->useAntialiasing);
897 settings.setValue("snapToGrid", snapToGridAct->isChecked());