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 "triangulateaction.h"
50 #include "trimaction.h"
54 DrawingView * ApplicationWindow::drawing;
57 ApplicationWindow::ApplicationWindow():
58 baseUnitInput(new QLineEdit),
59 dimensionSizeInput(new QLineEdit),
60 settings("Underground Software", "Architektonas")
62 drawing = new DrawingView(this);
63 drawing->setMouseTracking(true); // We want *all* mouse events...!
64 drawing->setFocusPolicy(Qt::StrongFocus);
65 setCentralWidget(drawing);
67 aboutWin = new AboutWindow(this);
69 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
71 setWindowIcon(QIcon(":/res/atns-icon.png"));
72 setWindowTitle("Architektonas");
78 // Create Dock widgets
79 QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
80 LayerWidget * lw = new LayerWidget;
82 addDockWidget(Qt::RightDockWidgetArea, dock1);
83 QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
84 BlockWidget * bw = new BlockWidget;
86 addDockWidget(Qt::RightDockWidgetArea, dock2);
87 // Needed for saveState()
88 dock1->setObjectName("Layers");
89 dock2->setObjectName("Blocks");
92 zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
93 statusBar()->addPermanentWidget(zoomIndicator);
94 statusBar()->showMessage(tr("Ready"));
97 setUnifiedTitleAndToolBarOnMac(true);
98 Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
100 connect(lw, SIGNAL(LayerSelected(int)), drawing, SLOT(SetCurrentLayer(int)));
104 void ApplicationWindow::closeEvent(QCloseEvent * event)
107 event->accept(); // Use ignore() if can't close for some reason
108 //Do we have a memory leak here if we don't delete the font in the Object???
112 void ApplicationWindow::FileNew(void)
114 // Should warn the user if drawing hasn't been saved...
115 drawing->document.Clear();
117 documentName.clear();
118 setWindowTitle("Architektonas - Untitled");
119 statusBar()->showMessage(tr("New drawing is ready."));
123 void ApplicationWindow::FileOpen(void)
125 QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
126 "", tr("Architektonas files (*.drawing)"));
128 // User cancelled open
129 if (filename.isEmpty())
132 FILE * file = fopen(filename.toUtf8().data(), "r");
137 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
138 msg.setIcon(QMessageBox::Critical);
143 Container container(Vector(0, 0));
144 bool successful = FileIO::LoadAtnsFile(file, &container);
150 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
151 msg.setIcon(QMessageBox::Critical);
156 printf("FileOpen: container size = %li\n", container.objects.size());
157 drawing->document = container;
159 documentName = filename;
160 setWindowTitle(QString("Architektonas - %1").arg(documentName));
161 statusBar()->showMessage(tr("Drawing loaded."));
165 void ApplicationWindow::FileSave(void)
167 if (documentName.isEmpty())
168 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
169 "", tr("Architektonas drawings (*.drawing)"));
171 FILE * file = fopen(documentName.toUtf8().data(), "w");
176 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
177 msg.setIcon(QMessageBox::Critical);
182 bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
188 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
189 msg.setIcon(QMessageBox::Critical);
191 // In this case, we should unlink the created file, since it's not right...
192 // unlink(documentName.toUtf8().data());
193 QFile::remove(documentName);
197 setWindowTitle(QString("Architektonas - %1").arg(documentName));
198 statusBar()->showMessage(tr("Drawing saved."));
202 void ApplicationWindow::FileSaveAs(void)
204 QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
205 documentName, tr("Architektonas drawings (*.drawing)"));
207 if (!filename.isEmpty())
209 documentName = filename;
215 void ApplicationWindow::SnapToGridTool(void)
217 Object::SetSnapMode(snapToGridAct->isChecked());
221 void ApplicationWindow::FixAngle(void)
223 Object::SetFixedAngle(fixAngleAct->isChecked());
227 void ApplicationWindow::FixLength(void)
229 Object::SetFixedLength(fixLengthAct->isChecked());
233 // We want certain tools to be exclusive, and this approach isn't working correctly...
234 void ApplicationWindow::DeleteTool(void)
236 // For this tool, we check first to see if anything is selected. If so, we
237 // delete those and *don't* select the delete tool.
238 if (drawing->document.ItemsSelected() > 0)
240 drawing->document.DeleteSelectedItems();
242 deleteAct->setChecked(false);
246 // Otherwise, toggle the state of the tool
247 ClearUIToolStatesExcept(deleteAct);
248 SetInternalToolStates();
252 void ApplicationWindow::DimensionTool(void)
254 ClearUIToolStatesExcept(addDimensionAct);
255 SetInternalToolStates();
259 void ApplicationWindow::RotateTool(void)
261 ClearUIToolStatesExcept(rotateAct);
262 SetInternalToolStates();
266 void ApplicationWindow::MirrorTool(void)
268 ClearUIToolStatesExcept(mirrorAct);
269 SetInternalToolStates();
273 void ApplicationWindow::TrimTool(void)
275 ClearUIToolStatesExcept(trimAct);
276 SetInternalToolStates();
280 void ApplicationWindow::TriangulateTool(void)
282 ClearUIToolStatesExcept(triangulateAct);
283 SetInternalToolStates();
287 void ApplicationWindow::AddLineTool(void)
289 ClearUIToolStatesExcept(addLineAct);
290 SetInternalToolStates();
294 void ApplicationWindow::AddCircleTool(void)
296 ClearUIToolStatesExcept(addCircleAct);
297 SetInternalToolStates();
301 void ApplicationWindow::AddArcTool(void)
303 ClearUIToolStatesExcept(addArcAct);
304 SetInternalToolStates();
308 void ApplicationWindow::AddPolygonTool(void)
310 ClearUIToolStatesExcept(addPolygonAct);
311 SetInternalToolStates();
315 void ApplicationWindow::AddSplineTool(void)
317 ClearUIToolStatesExcept(addSplineAct);
318 SetInternalToolStates();
322 void ApplicationWindow::ZoomInTool(void)
324 double zoomFactor = 2.0;
326 We need to find the center of the screen, then figure out where the new corner
327 will be in the zoomed in window.
329 So we know in Qt coords, the center is found via:
330 size.width() / 2 --> xCenter
331 size.height() / 2 --> yCenter
333 transform x/yCenter to Cartesian coordinates. So far, so good.
335 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
336 (after subtracting from center, that is...)
338 QSize size = drawing->size();
339 Vector center(size.width() / 2.0, size.height() / 2.0);
340 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
341 center = Painter::QtToCartesianCoords(center);
342 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
343 Vector newOrigin = center - ((center - Painter::origin) / zoomFactor);
344 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
345 Painter::origin = newOrigin;
347 //printf("Zoom in... level going from %02f to ", Painter::zoom);
348 // This just zooms leaving origin intact... should zoom in at the current
350 Painter::zoom *= zoomFactor;
351 Object::gridSpacing = drawing->gridPixels / Painter::zoom;
352 drawing->UpdateGridBackground();
355 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
356 baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
360 void ApplicationWindow::ZoomOutTool(void)
365 origin = (223, 160.5)
366 newOrigin should be (-10, -10)
369 center - origin = (213, 150.5)
370 origin - center = (-213, -150.5)
372 + center = (-10, -10)
375 double zoomFactor = 2.0;
376 QSize size = drawing->size();
377 Vector center(size.width() / 2.0, size.height() / 2.0);
378 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
379 center = Painter::QtToCartesianCoords(center);
380 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
381 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
382 // Vector newOrigin = center - (Painter::origin * zoomFactor);
383 Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
384 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
385 Painter::origin = newOrigin;
386 //printf("Zoom out...\n");
387 // This just zooms leaving origin intact... should zoom out at the current
389 Painter::zoom /= zoomFactor;
390 Object::gridSpacing = drawing->gridPixels / Painter::zoom;
391 drawing->UpdateGridBackground();
394 zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
395 baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
399 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
401 if (exception != addArcAct)
402 addArcAct->setChecked(false);
404 if (exception != addCircleAct)
405 addCircleAct->setChecked(false);
407 if (exception != addDimensionAct)
408 addDimensionAct->setChecked(false);
410 if (exception != addLineAct)
411 addLineAct->setChecked(false);
413 if (exception != addPolygonAct)
414 addPolygonAct->setChecked(false);
416 if (exception != addSplineAct)
417 addSplineAct->setChecked(false);
419 if (exception != deleteAct)
420 deleteAct->setChecked(false);
422 if (exception != rotateAct)
423 rotateAct->setChecked(false);
425 if (exception != mirrorAct)
426 mirrorAct->setChecked(false);
428 if (exception != trimAct)
429 trimAct->setChecked(false);
431 if (exception != triangulateAct)
432 triangulateAct->setChecked(false);
436 void ApplicationWindow::SetInternalToolStates(void)
438 Object::SetDeleteActive(deleteAct->isChecked());
439 Object::SetDimensionActive(addDimensionAct->isChecked());
441 // We can be sure that if we've come here, then either an active tool is
442 // being deactivated, or a new tool is being created. In either case, the
443 // old tool needs to be deleted.
444 if (drawing->toolAction)
446 delete drawing->toolAction;
447 drawing->toolAction = NULL;
448 Object::ignoreClicks = false;
451 drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
452 drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
453 drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
454 drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
455 drawing->SetToolActive(addSplineAct->isChecked() ? new DrawSplineAction() : NULL);
456 drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL);
457 drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL);
458 drawing->SetToolActive(trimAct->isChecked() ? new TrimAction() : NULL);
459 drawing->SetToolActive(triangulateAct->isChecked() ? new TriangulateAction() : NULL);
461 if (drawing->toolAction)
462 Object::ignoreClicks = true;
468 void ApplicationWindow::HelpAbout(void)
474 void ApplicationWindow::Settings(void)
476 SettingsDialog dlg(this);
477 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
479 if (dlg.exec() == false)
482 // Deal with stuff here (since user hit "OK" button...)
483 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
489 // Group a bunch of selected objects (which can include other groups) together
490 // or ungroup a selected group.
492 void ApplicationWindow::HandleGrouping(void)
494 int itemsSelected = drawing->document.ItemsSelected();
496 // If nothing selected, do nothing
497 if (itemsSelected == 0)
499 statusBar()->showMessage(tr("No objects selected to make a group from."));
503 // If it's a group that's selected, ungroup it and leave the objects in a
505 if (itemsSelected == 1)
507 Object * object = drawing->document.SelectedItem(0);
511 printf("SelectedItem = NULL!\n");
513 printf("SelectedItem = %08X, type = %i\n", object, object->type);
516 if (object == NULL || object->type != OTContainer)
518 statusBar()->showMessage(tr("A group requires two or more selected objects."));
522 // Need the parent of the group, we're assuming here that the parent is
523 // the drawing's document. Does it matter? Maybe...
524 // Could just stipulate that grouping like this only takes place where the
525 // parent of the group is the drawing's document. Makes life much simpler.
526 ((Container *)object)->SelectAll();
527 ((Container *)object)->MoveContentsTo(&(drawing->document));
528 drawing->document.Delete(object);
529 statusBar()->showMessage(tr("Objects ungrouped."));
531 // Otherwise, if it's a group of 2 or more objects (which can be groups too)
532 // group them and select the group
533 else if (itemsSelected > 1)
535 Container * container = new Container(Vector(), &(drawing->document));
536 drawing->document.MoveSelectedContentsTo(container);
537 drawing->document.Add(container);
538 container->DeselectAll();
539 container->state = OSSelected;
540 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
547 void ApplicationWindow::HandleConnection(void)
549 //double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
550 //printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
551 int itemsSelected = drawing->document.ItemsSelected();
553 // If nothing selected, do nothing
554 if (itemsSelected == 0)
556 statusBar()->showMessage(tr("No objects selected to connect."));
560 // If one thing selected, do nothing
561 if (itemsSelected == 1)
563 statusBar()->showMessage(tr("Nothing to connect object to."));
567 // This is O(n^2 / 2) :-P
568 for(int i=0; i<itemsSelected; i++)
570 Object * obj1 = drawing->document.SelectedItem(i);
572 for(int j=i+1; j<itemsSelected; j++)
574 Object * obj2 = drawing->document.SelectedItem(j);
577 // if ((obj1->type != OTLine) || (obj2->type != OTLine))
580 if ((obj1->type == OTLine) && (obj2->type == OTLine))
582 //printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
583 int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
584 //printf(" (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
588 //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
589 obj1->Connect(obj2, u);
590 obj2->Connect(obj1, t);
593 else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
594 || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
596 printf("Testing Line<->Dimension intersection...\n");
597 Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
598 Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
600 int intersects = Geometry::Intersects(line, dim, &t, &u);
601 printf(" -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
605 obj1->Connect(obj2, u);
606 obj2->Connect(obj1, t);
614 void ApplicationWindow::HandleDisconnection(void)
619 void ApplicationWindow::HandleGridSizeInPixels(int size)
621 drawing->SetGridSize(size);
626 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
630 double value = text.toDouble(&ok);
632 // Nothing parsable to a double, so quit...
633 if (!ok || value == 0)
636 // drawing->gridSpacing = value;
637 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
638 Object::gridSpacing = value;
639 Painter::zoom = drawing->gridPixels / Object::gridSpacing;
640 drawing->UpdateGridBackground();
645 void ApplicationWindow::HandleDimensionSize(QString text)
649 double value = text.toDouble(&ok);
651 // Nothing parsable to a double, so quit...
652 if (!ok || value == 0)
655 drawing->document.ResizeAllDimensions(value);
656 // drawing->gridSpacing = value;
657 // Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
658 // drawing->UpdateGridBackground();
663 void ApplicationWindow::CreateActions(void)
665 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
666 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
667 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
669 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);
670 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
672 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
673 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
674 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
676 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
677 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
678 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
680 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
681 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
683 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
684 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
686 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
687 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
689 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
690 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
692 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
693 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
695 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
696 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
698 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);
699 connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
701 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
702 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
704 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);
705 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
707 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
708 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
710 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
711 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
713 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/file-new.png"), QKeySequence(tr("Ctrl+n")));
714 connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
716 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")));
717 connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
719 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")));
720 connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
722 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")));
723 connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
725 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/file-close.png"), QKeySequence(tr("Ctrl+w")));
727 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/settings.png"), QKeySequence());
728 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
730 groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
731 connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
733 connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
734 connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
736 disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
737 connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
739 mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
740 connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
742 trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
743 connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
745 triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
746 connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
749 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
750 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
751 /* QActionGroup * group = new QActionGroup(this);
752 group->addAction(deleteAct);
753 group->addAction(addDimensionAct);
754 group->addAction(addLineAct);
755 group->addAction(addCircleAct);
756 group->addAction(addArcAct);//*/
761 // Consolidates action creation from a multi-step process to a single-step one.
763 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
764 QIcon icon, QKeySequence key, bool checkable/*= false*/)
766 QAction * action = new QAction(icon, name, this);
767 action->setToolTip(tooltip);
768 action->setStatusTip(statustip);
769 action->setShortcut(key);
770 action->setCheckable(checkable);
777 // This is essentially the same as the previous function, but this allows more
778 // than one key sequence to be added as key shortcuts.
780 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
781 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
783 QAction * action = new QAction(icon, name, this);
784 action->setToolTip(tooltip);
785 action->setStatusTip(statustip);
786 QList<QKeySequence> keyList;
787 keyList.append(key1);
788 keyList.append(key2);
789 action->setShortcuts(keyList);
790 action->setCheckable(checkable);
796 void ApplicationWindow::CreateMenus(void)
798 QMenu * menu = menuBar()->addMenu(tr("&File"));
799 menu->addAction(fileNewAct);
800 menu->addAction(fileOpenAct);
801 menu->addAction(fileSaveAct);
802 menu->addAction(fileSaveAsAct);
803 menu->addAction(fileCloseAct);
804 menu->addSeparator();
805 menu->addAction(exitAct);
807 menu = menuBar()->addMenu(tr("&View"));
808 menu->addAction(zoomInAct);
809 menu->addAction(zoomOutAct);
811 menu = menuBar()->addMenu(tr("&Edit"));
812 menu->addAction(snapToGridAct);
813 menu->addAction(groupAct);
814 menu->addAction(fixAngleAct);
815 menu->addAction(fixLengthAct);
816 menu->addAction(rotateAct);
817 menu->addAction(mirrorAct);
818 menu->addAction(trimAct);
819 menu->addAction(triangulateAct);
820 menu->addAction(connectAct);
821 menu->addAction(disconnectAct);
822 menu->addSeparator();
823 menu->addAction(deleteAct);
824 menu->addSeparator();
825 menu->addAction(addLineAct);
826 menu->addAction(addCircleAct);
827 menu->addAction(addArcAct);
828 menu->addAction(addPolygonAct);
829 menu->addAction(addSplineAct);
830 menu->addAction(addDimensionAct);
831 menu->addSeparator();
832 menu->addAction(settingsAct);
834 menu = menuBar()->addMenu(tr("&Help"));
835 menu->addAction(aboutAct);
839 void ApplicationWindow::CreateToolbars(void)
841 QToolBar * toolbar = addToolBar(tr("File"));
842 toolbar->setObjectName("File"); // Needed for saveState()
843 toolbar->addAction(fileNewAct);
844 toolbar->addAction(fileOpenAct);
845 toolbar->addAction(fileSaveAct);
846 toolbar->addAction(fileSaveAsAct);
847 toolbar->addAction(fileCloseAct);
848 // toolbar->addAction(exitAct);
850 toolbar = addToolBar(tr("View"));
851 toolbar->setObjectName("View");
852 toolbar->addAction(zoomInAct);
853 toolbar->addAction(zoomOutAct);
855 QSpinBox * spinbox = new QSpinBox;
856 toolbar->addWidget(spinbox);
857 // QLineEdit * lineedit = new QLineEdit;
858 toolbar->addWidget(baseUnitInput);
859 toolbar->addWidget(dimensionSizeInput);
861 toolbar = addToolBar(tr("Edit"));
862 toolbar->setObjectName("Edit");
863 toolbar->addAction(snapToGridAct);
864 toolbar->addAction(groupAct);
865 toolbar->addAction(fixAngleAct);
866 toolbar->addAction(fixLengthAct);
867 toolbar->addAction(rotateAct);
868 toolbar->addAction(mirrorAct);
869 toolbar->addAction(trimAct);
870 toolbar->addAction(triangulateAct);
871 toolbar->addAction(deleteAct);
872 toolbar->addAction(connectAct);
873 toolbar->addAction(disconnectAct);
874 toolbar->addSeparator();
875 toolbar->addAction(addLineAct);
876 toolbar->addAction(addCircleAct);
877 toolbar->addAction(addArcAct);
878 toolbar->addAction(addPolygonAct);
879 toolbar->addAction(addSplineAct);
880 toolbar->addAction(addDimensionAct);
882 spinbox->setRange(4, 256);
883 spinbox->setValue(12);
884 baseUnitInput->setText("12");
885 connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
886 connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
887 connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
891 void ApplicationWindow::ReadSettings(void)
893 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
894 QSize size = settings.value("size", QSize(400, 400)).toSize();
895 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
896 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
899 restoreState(settings.value("windowState").toByteArray());
903 void ApplicationWindow::WriteSettings(void)
905 settings.setValue("pos", pos());
906 settings.setValue("size", size());
907 settings.setValue("windowState", saveState());
908 settings.setValue("useAntialiasing", drawing->useAntialiasing);
909 settings.setValue("snapToGrid", snapToGridAct->isChecked());