2 // applicationwindow.cpp: Architektonas
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
11 // --- ---------- -------------------------------------------------------------
12 // JLH 03/22/2011 Created this file
13 // JLH 09/29/2011 Added simple zoom in/out functionality
14 // JLH 10/03/2011 Fixed zoom tool to zoom in/out from center of screen
24 // Uncomment this for debugging...
26 //#define DEBUGFOO // Various tool debugging...
27 //#define DEBUGTP // Toolpalette debugging...
29 #include "applicationwindow.h"
32 #include "blockwidget.h"
33 #include "dimension.h"
34 #include "drawingview.h"
35 #include "drawarcaction.h"
36 #include "drawcircleaction.h"
37 #include "drawdimensionaction.h"
38 #include "drawlineaction.h"
39 #include "drawsplineaction.h"
41 #include "generaltab.h"
43 #include "layerwidget.h"
45 #include "mirroraction.h"
47 #include "rotateaction.h"
48 #include "settingsdialog.h"
49 #include "trimaction.h"
53 DrawingView * ApplicationWindow::drawing;
56 ApplicationWindow::ApplicationWindow():
57 baseUnitInput(new QLineEdit),
58 dimensionSizeInput(new QLineEdit),
59 settings("Underground Software", "Architektonas")
61 drawing = new DrawingView(this);
62 drawing->setMouseTracking(true); // We want *all* mouse events...!
63 drawing->setFocusPolicy(Qt::StrongFocus);
64 setCentralWidget(drawing);
66 aboutWin = new AboutWindow(this);
68 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
70 setWindowIcon(QIcon(":/res/atns-icon.png"));
71 setWindowTitle("Architektonas");
77 // Create Dock widgets
78 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
79 LayerWidget * lw = new LayerWidget;
81 addDockWidget(Qt::RightDockWidgetArea, dock1);
82 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
83 BlockWidget * bw = new BlockWidget;
85 addDockWidget(Qt::RightDockWidgetArea, dock2);
86 // Needed for saveState()
87 dock1->setObjectName("Layers");
88 dock2->setObjectName("Blocks");
91 zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
92 statusBar()->addPermanentWidget(zoomIndicator);
93 statusBar()->showMessage(tr("Ready"));
96 setUnifiedTitleAndToolBarOnMac(true);
97 Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
99 connect(lw, SIGNAL(LayerSelected(int)), drawing, SLOT(SetCurrentLayer(int)));
103 void ApplicationWindow::closeEvent(QCloseEvent * event)
106 event->accept(); // Use ignore() if can't close for some reason
107 //Do we have a memory leak here if we don't delete the font in the Object???
111 void ApplicationWindow::FileNew(void)
113 // Should warn the user if drawing hasn't been saved...
114 drawing->document.Clear();
116 documentName.clear();
117 setWindowTitle("Architektonas - Untitled");
118 statusBar()->showMessage(tr("New drawing is ready."));
122 void ApplicationWindow::FileOpen(void)
124 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
125 "", tr("Architektonas files (*.drawing)"));
127 // User cancelled open
128 if (filename.isEmpty())
131 FILE * file = fopen(filename.toAscii().data(), "r");
136 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
137 msg.setIcon(QMessageBox::Critical);
142 Container container(Vector(0, 0));
143 bool successful = FileIO::LoadAtnsFile(file, &container);
149 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
150 msg.setIcon(QMessageBox::Critical);
155 printf("FileOpen: container size = %li\n", container.objects.size());
156 drawing->document = container;
158 documentName = filename;
159 setWindowTitle(QString("Architektonas - %1").arg(documentName));
160 statusBar()->showMessage(tr("Drawing loaded."));
164 void ApplicationWindow::FileSave(void)
166 if (documentName.isEmpty())
167 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
168 "", tr("Architektonas drawings (*.drawing)"));
170 FILE * file = fopen(documentName.toAscii().data(), "w");
175 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
176 msg.setIcon(QMessageBox::Critical);
181 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
187 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
188 msg.setIcon(QMessageBox::Critical);
190 // In this case, we should unlink the created file, since it's not right...
191 // unlink(documentName.toAscii().data());
192 QFile::remove(documentName);
196 setWindowTitle(QString("Architektonas - %1").arg(documentName));
197 statusBar()->showMessage(tr("Drawing saved."));
201 void ApplicationWindow::FileSaveAs(void)
203 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
204 documentName, tr("Architektonas drawings (*.drawing)"));
206 if (!filename.isEmpty())
208 documentName = filename;
214 void ApplicationWindow::SnapToGridTool(void)
216 Object::SetSnapMode(snapToGridAct->isChecked());
220 void ApplicationWindow::FixAngle(void)
222 Object::SetFixedAngle(fixAngleAct->isChecked());
226 void ApplicationWindow::FixLength(void)
228 Object::SetFixedLength(fixLengthAct->isChecked());
232 // We want certain tools to be exclusive, and this approach isn't working correctly...
233 void ApplicationWindow::DeleteTool(void)
235 // For this tool, we check first to see if anything is selected. If so, we
236 // delete those and *don't* select the delete tool.
237 if (drawing->document.ItemsSelected() > 0)
239 drawing->document.DeleteSelectedItems();
241 deleteAct->setChecked(false);
245 // Otherwise, toggle the state of the tool
246 ClearUIToolStatesExcept(deleteAct);
247 SetInternalToolStates();
251 void ApplicationWindow::DimensionTool(void)
253 ClearUIToolStatesExcept(addDimensionAct);
254 SetInternalToolStates();
258 void ApplicationWindow::RotateTool(void)
260 ClearUIToolStatesExcept(rotateAct);
261 SetInternalToolStates();
265 void ApplicationWindow::MirrorTool(void)
267 ClearUIToolStatesExcept(mirrorAct);
268 SetInternalToolStates();
272 void ApplicationWindow::TrimTool(void)
274 ClearUIToolStatesExcept(trimAct);
275 SetInternalToolStates();
279 void ApplicationWindow::AddLineTool(void)
281 ClearUIToolStatesExcept(addLineAct);
282 SetInternalToolStates();
286 void ApplicationWindow::AddCircleTool(void)
288 ClearUIToolStatesExcept(addCircleAct);
289 SetInternalToolStates();
293 void ApplicationWindow::AddArcTool(void)
295 ClearUIToolStatesExcept(addArcAct);
296 SetInternalToolStates();
300 void ApplicationWindow::AddPolygonTool(void)
302 ClearUIToolStatesExcept(addPolygonAct);
303 SetInternalToolStates();
307 void ApplicationWindow::AddSplineTool(void)
309 ClearUIToolStatesExcept(addSplineAct);
310 SetInternalToolStates();
314 void ApplicationWindow::ZoomInTool(void)
316 double zoomFactor = 2.0;
318 We need to find the center of the screen, then figure out where the new corner
319 will be in the zoomed in window.
321 So we know in Qt coords, the center is found via:
322 size.width() / 2 --> xCenter
323 size.height() / 2 --> yCenter
325 transform x/yCenter to Cartesian coordinates. So far, so good.
327 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
328 (after subtracting from center, that is...)
330 QSize size = drawing->size();
331 Vector center(size.width() / 2.0, size.height() / 2.0);
332 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
333 center = Painter::QtToCartesianCoords(center);
334 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
335 Vector newOrigin = center - ((center - Painter::origin) / zoomFactor);
336 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
337 Painter::origin = newOrigin;
339 //printf("Zoom in... level going from %02f to ", Painter::zoom);
340 // This just zooms leaving origin intact... should zoom in at the current
342 Painter::zoom *= zoomFactor;
343 Object::gridSpacing = drawing->gridPixels / Painter::zoom;
344 drawing->UpdateGridBackground();
347 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
348 baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
352 void ApplicationWindow::ZoomOutTool(void)
357 origin = (223, 160.5)
358 newOrigin should be (-10, -10)
361 center - origin = (213, 150.5)
362 origin - center = (-213, -150.5)
364 + center = (-10, -10)
367 double zoomFactor = 2.0;
368 QSize size = drawing->size();
369 Vector center(size.width() / 2.0, size.height() / 2.0);
370 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
371 center = Painter::QtToCartesianCoords(center);
372 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
373 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
374 // Vector newOrigin = center - (Painter::origin * zoomFactor);
375 Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
376 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
377 Painter::origin = newOrigin;
378 //printf("Zoom out...\n");
379 // This just zooms leaving origin intact... should zoom out at the current
381 Painter::zoom /= zoomFactor;
382 Object::gridSpacing = drawing->gridPixels / Painter::zoom;
383 drawing->UpdateGridBackground();
386 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
387 baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
391 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
393 if (exception != addArcAct)
394 addArcAct->setChecked(false);
396 if (exception != addCircleAct)
397 addCircleAct->setChecked(false);
399 if (exception != addDimensionAct)
400 addDimensionAct->setChecked(false);
402 if (exception != addLineAct)
403 addLineAct->setChecked(false);
405 if (exception != addPolygonAct)
406 addPolygonAct->setChecked(false);
408 if (exception != addSplineAct)
409 addSplineAct->setChecked(false);
411 if (exception != deleteAct)
412 deleteAct->setChecked(false);
414 if (exception != rotateAct)
415 rotateAct->setChecked(false);
417 if (exception != mirrorAct)
418 mirrorAct->setChecked(false);
420 if (exception != trimAct)
421 trimAct->setChecked(false);
425 void ApplicationWindow::SetInternalToolStates(void)
427 Object::SetDeleteActive(deleteAct->isChecked());
428 Object::SetDimensionActive(addDimensionAct->isChecked());
430 // We can be sure that if we've come here, then either an active tool is
431 // being deactivated, or a new tool is being created. In either case, the
432 // old tool needs to be deleted.
433 if (drawing->toolAction)
435 delete drawing->toolAction;
436 drawing->toolAction = NULL;
437 Object::ignoreClicks = false;
440 drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
441 drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
442 drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
443 drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
444 drawing->SetToolActive(addSplineAct->isChecked() ? new DrawSplineAction() : NULL);
445 drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL);
446 drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL);
447 drawing->SetToolActive(trimAct->isChecked() ? new TrimAction() : NULL);
449 if (drawing->toolAction)
450 Object::ignoreClicks = true;
456 void ApplicationWindow::HelpAbout(void)
462 void ApplicationWindow::Settings(void)
464 SettingsDialog dlg(this);
465 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
467 if (dlg.exec() == false)
470 // Deal with stuff here (since user hit "OK" button...)
471 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
477 // Group a bunch of selected objects (which can include other groups) together
478 // or ungroup a selected group.
480 void ApplicationWindow::HandleGrouping(void)
482 int itemsSelected = drawing->document.ItemsSelected();
484 // If nothing selected, do nothing
485 if (itemsSelected == 0)
487 statusBar()->showMessage(tr("No objects selected to make a group from."));
491 // If it's a group that's selected, ungroup it and leave the objects in a
493 if (itemsSelected == 1)
495 Object * object = drawing->document.SelectedItem(0);
499 printf("SelectedItem = NULL!\n");
501 printf("SelectedItem = %08X, type = %i\n", object, object->type);
504 if (object == NULL || object->type != OTContainer)
506 statusBar()->showMessage(tr("A group requires two or more selected objects."));
510 // Need the parent of the group, we're assuming here that the parent is
511 // the drawing's document. Does it matter? Maybe...
512 // Could just stipulate that grouping like this only takes place where the
513 // parent of the group is the drawing's document. Makes life much simpler.
514 ((Container *)object)->SelectAll();
515 ((Container *)object)->MoveContentsTo(&(drawing->document));
516 drawing->document.Delete(object);
517 statusBar()->showMessage(tr("Objects ungrouped."));
519 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
520 // group them and select the group
521 else if (itemsSelected > 1)
523 Container * container = new Container(Vector(), &(drawing->document));
524 drawing->document.MoveSelectedContentsTo(container);
525 drawing->document.Add(container);
526 container->DeselectAll();
527 container->state = OSSelected;
528 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
535 void ApplicationWindow::HandleConnection(void)
537 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
538 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
539 int itemsSelected = drawing->document.ItemsSelected();
541 // If nothing selected, do nothing
542 if (itemsSelected == 0)
544 statusBar()->showMessage(tr("No objects selected to connect."));
548 // If one thing selected, do nothing
549 if (itemsSelected == 1)
551 statusBar()->showMessage(tr("Nothing to connect object to."));
555 // This is O(n^2 / 2) :-P
556 for(int i=0; i<itemsSelected; i++)
558 Object * obj1 = drawing->document.SelectedItem(i);
560 for(int j=i+1; j<itemsSelected; j++)
562 Object * obj2 = drawing->document.SelectedItem(j);
565 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
568 if ((obj1->type == OTLine) && (obj2->type == OTLine))
570 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
571 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
572 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
576 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
577 obj1->Connect(obj2, u);
578 obj2->Connect(obj1, t);
581 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
582 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
584 printf("Testing Line<->Dimension intersection...\n");
585 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
586 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
588 int intersects = Geometry::Intersects(line, dim, &t, &u);
589 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
593 obj1->Connect(obj2, u);
594 obj2->Connect(obj1, t);
602 void ApplicationWindow::HandleDisconnection(void)
607 void ApplicationWindow::HandleGridSizeInPixels(int size)
609 drawing->SetGridSize(size);
614 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
618 double value = text.toDouble(&ok);
620 // Nothing parsable to a double, so quit...
621 if (!ok || value == 0)
624 // drawing->gridSpacing = value;
625 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
626 Object::gridSpacing = value;
627 Painter::zoom = drawing->gridPixels / Object::gridSpacing;
628 drawing->UpdateGridBackground();
633 void ApplicationWindow::HandleDimensionSize(QString text)
637 double value = text.toDouble(&ok);
639 // Nothing parsable to a double, so quit...
640 if (!ok || value == 0)
643 drawing->document.ResizeAllDimensions(value);
644 // drawing->gridSpacing = value;
645 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
646 // drawing->UpdateGridBackground();
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()));
734 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
735 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
736 /* QActionGroup * group = new QActionGroup(this);
737 group->addAction(deleteAct);
738 group->addAction(addDimensionAct);
739 group->addAction(addLineAct);
740 group->addAction(addCircleAct);
741 group->addAction(addArcAct);//*/
746 // Consolidates action creation from a multi-step process to a single-step one.
748 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
749 QIcon icon, QKeySequence key, bool checkable/*= false*/)
751 QAction * action = new QAction(icon, name, this);
752 action->setToolTip(tooltip);
753 action->setStatusTip(statustip);
754 action->setShortcut(key);
755 action->setCheckable(checkable);
762 // This is essentially the same as the previous function, but this allows more
763 // than one key sequence to be added as key shortcuts.
765 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
766 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
768 QAction * action = new QAction(icon, name, this);
769 action->setToolTip(tooltip);
770 action->setStatusTip(statustip);
771 QList<QKeySequence> keyList;
772 keyList.append(key1);
773 keyList.append(key2);
774 action->setShortcuts(keyList);
775 action->setCheckable(checkable);
781 void ApplicationWindow::CreateMenus(void)
783 QMenu * menu = menuBar()->addMenu(tr("&File"));
784 menu->addAction(fileNewAct);
785 menu->addAction(fileOpenAct);
786 menu->addAction(fileSaveAct);
787 menu->addAction(fileSaveAsAct);
788 menu->addAction(fileCloseAct);
789 menu->addSeparator();
790 menu->addAction(exitAct);
792 menu = menuBar()->addMenu(tr("&View"));
793 menu->addAction(zoomInAct);
794 menu->addAction(zoomOutAct);
796 menu = menuBar()->addMenu(tr("&Edit"));
797 menu->addAction(snapToGridAct);
798 menu->addAction(groupAct);
799 menu->addAction(fixAngleAct);
800 menu->addAction(fixLengthAct);
801 menu->addAction(rotateAct);
802 menu->addAction(mirrorAct);
803 menu->addAction(trimAct);
804 menu->addAction(connectAct);
805 menu->addAction(disconnectAct);
806 menu->addSeparator();
807 menu->addAction(deleteAct);
808 menu->addSeparator();
809 menu->addAction(addLineAct);
810 menu->addAction(addCircleAct);
811 menu->addAction(addArcAct);
812 menu->addAction(addPolygonAct);
813 menu->addAction(addSplineAct);
814 menu->addAction(addDimensionAct);
815 menu->addSeparator();
816 menu->addAction(settingsAct);
818 menu = menuBar()->addMenu(tr("&Help"));
819 menu->addAction(aboutAct);
823 void ApplicationWindow::CreateToolbars(void)
825 QToolBar * toolbar = addToolBar(tr("File"));
826 toolbar->setObjectName("File"); // Needed for saveState()
827 toolbar->addAction(fileNewAct);
828 toolbar->addAction(fileOpenAct);
829 toolbar->addAction(fileSaveAct);
830 toolbar->addAction(fileSaveAsAct);
831 toolbar->addAction(fileCloseAct);
832 // toolbar->addAction(exitAct);
834 toolbar = addToolBar(tr("View"));
835 toolbar->setObjectName("View");
836 toolbar->addAction(zoomInAct);
837 toolbar->addAction(zoomOutAct);
839 QSpinBox * spinbox = new QSpinBox;
840 toolbar->addWidget(spinbox);
841 // QLineEdit * lineedit = new QLineEdit;
842 toolbar->addWidget(baseUnitInput);
843 toolbar->addWidget(dimensionSizeInput);
845 toolbar = addToolBar(tr("Edit"));
846 toolbar->setObjectName("Edit");
847 toolbar->addAction(snapToGridAct);
848 toolbar->addAction(groupAct);
849 toolbar->addAction(fixAngleAct);
850 toolbar->addAction(fixLengthAct);
851 toolbar->addAction(rotateAct);
852 toolbar->addAction(mirrorAct);
853 toolbar->addAction(trimAct);
854 toolbar->addAction(deleteAct);
855 toolbar->addAction(connectAct);
856 toolbar->addAction(disconnectAct);
857 toolbar->addSeparator();
858 toolbar->addAction(addLineAct);
859 toolbar->addAction(addCircleAct);
860 toolbar->addAction(addArcAct);
861 toolbar->addAction(addPolygonAct);
862 toolbar->addAction(addSplineAct);
863 toolbar->addAction(addDimensionAct);
865 spinbox->setRange(4, 256);
866 spinbox->setValue(12);
867 baseUnitInput->setText("12");
868 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
869 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
870 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
874 void ApplicationWindow::ReadSettings(void)
876 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
877 QSize size = settings.value("size", QSize(400, 400)).toSize();
878 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
879 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
882 restoreState(settings.value("windowState").toByteArray());
886 void ApplicationWindow::WriteSettings(void)
888 settings.setValue("pos", pos());
889 settings.setValue("size", size());
890 settings.setValue("windowState", saveState());
891 settings.setValue("useAntialiasing", drawing->useAntialiasing);
892 settings.setValue("snapToGrid", snapToGridAct->isChecked());