]> Shamusworld >> Repos - architektonas/blob - src/applicationwindow.cpp
Various fixes to Container/Group handling, added DrawArcAction.
[architektonas] / src / applicationwindow.cpp
1 //
2 // applicationwindow.cpp: Architektonas
3 //
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
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
15 //
16
17 // FIXED:
18 //
19 //
20 // STILL TO BE DONE:
21 //
22 //
23
24 // Uncomment this for debugging...
25 //#define DEBUG
26 //#define DEBUGFOO                      // Various tool debugging...
27 //#define DEBUGTP                               // Toolpalette debugging...
28
29 #include "applicationwindow.h"
30
31 #include "about.h"
32 #include "blockwidget.h"
33 #include "drawingview.h"
34 #include "fileio.h"
35 #include "generaltab.h"
36 #include "layerwidget.h"
37 #include "painter.h"
38 #include "settingsdialog.h"
39
40
41 ApplicationWindow::ApplicationWindow():
42         baseUnitInput(new QLineEdit),
43         dimensionSizeInput(new QLineEdit),
44         settings("Underground Software", "Architektonas")
45 {
46         drawing = new DrawingView(this);
47         drawing->setMouseTracking(true);                // We want *all* mouse events...!
48         setCentralWidget(drawing);
49
50         aboutWin = new AboutWindow(this);
51
52 //      ((TTEdit *)qApp)->charWnd = new CharWindow(this);
53
54         setWindowIcon(QIcon(":/res/atns-icon.png"));
55         setWindowTitle("Architektonas");
56
57         CreateActions();
58         CreateMenus();
59         CreateToolbars();
60
61         // Create Dock widgets
62         QDockWidget * dock1 = new QDockWidget(tr("Layers"), this);
63         LayerWidget * lw = new LayerWidget;
64         dock1->setWidget(lw);
65         addDockWidget(Qt::RightDockWidgetArea, dock1);
66         QDockWidget * dock2 = new QDockWidget(tr("Blocks"), this);
67         BlockWidget * bw = new BlockWidget;
68         dock2->setWidget(bw);
69         addDockWidget(Qt::RightDockWidgetArea, dock2);
70         // Needed for saveState()
71         dock1->setObjectName("Layers");
72         dock2->setObjectName("Blocks");
73
74         //      Create status bar
75         zoomIndicator = new QLabel("Grid: 12.0\" Zoom: 12.5%");
76         statusBar()->addPermanentWidget(zoomIndicator);
77         statusBar()->showMessage(tr("Ready"));
78
79         ReadSettings();
80         setUnifiedTitleAndToolBarOnMac(true);
81         Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
82 }
83
84
85 void ApplicationWindow::closeEvent(QCloseEvent * event)
86 {
87         WriteSettings();
88         event->accept();                                                        // Use ignore() if can't close for some reason
89         //Do we have a memory leak here if we don't delete the font in the Object???
90 }
91
92
93 void ApplicationWindow::FileNew(void)
94 {
95         // Should warn the user if drawing hasn't been saved...
96         drawing->document.Clear();
97         drawing->update();
98         documentName.clear();
99         setWindowTitle("Architektonas - Untitled");
100         statusBar()->showMessage(tr("New drawing is ready."));
101 }
102
103
104 void ApplicationWindow::FileOpen(void)
105 {
106         QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
107                 "", tr("Architektonas files (*.drawing)"));
108         FILE * file = fopen(filename.toAscii().data(), "r");
109
110         if (file == 0)
111         {
112                 QMessageBox msg;
113                 msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
114                 msg.setIcon(QMessageBox::Critical);
115                 msg.exec();
116                 return;
117         }
118
119         Container container(Vector(0, 0));
120         bool successful = FileIO::LoadAtnsFile(file, &container);
121         fclose(file);
122
123         if (!successful)
124         {
125                 QMessageBox msg;
126                 msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
127                 msg.setIcon(QMessageBox::Critical);
128                 msg.exec();
129                 return;
130         }
131
132 printf("FileOpen: container size = %li\n", container.objects.size());
133         drawing->document = container;
134         drawing->update();
135         documentName = filename;
136         setWindowTitle(QString("Architektonas - %1").arg(documentName));
137         statusBar()->showMessage(tr("Drawing loaded."));
138 }
139
140
141 void ApplicationWindow::FileSave(void)
142 {
143         if (documentName.isEmpty())
144                 documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
145                         "", tr("Architektonas drawings (*.drawing)"));
146
147         FILE * file = fopen(documentName.toAscii().data(), "w");
148
149         if (file == 0)
150         {
151                 QMessageBox msg;
152                 msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
153                 msg.setIcon(QMessageBox::Critical);
154                 msg.exec();
155                 return;
156         }
157
158         bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
159         fclose(file);
160
161         if (!successful)
162         {
163                 QMessageBox msg;
164                 msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
165                 msg.setIcon(QMessageBox::Critical);
166                 msg.exec();
167                 // In this case, we should unlink the created file, since it's not right...
168                 unlink(documentName.toAscii().data());
169                 return;
170         }
171
172         setWindowTitle(QString("Architektonas - %1").arg(documentName));
173         statusBar()->showMessage(tr("Drawing saved."));
174 }
175
176
177 void ApplicationWindow::FileSaveAs(void)
178 {
179         QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
180                 documentName, tr("Architektonas drawings (*.drawing)"));
181
182         if (!filename.isEmpty())
183         {
184                 documentName = filename;
185                 FileSave();
186         }
187 }
188
189
190 void ApplicationWindow::SnapToGridTool(void)
191 {
192         Object::SetSnapMode(snapToGridAct->isChecked());
193 }
194
195
196 void ApplicationWindow::FixAngle(void)
197 {
198         Object::SetFixedAngle(fixAngleAct->isChecked());
199 }
200
201
202 void ApplicationWindow::FixLength(void)
203 {
204         Object::SetFixedLength(fixLengthAct->isChecked());
205 }
206
207
208 // We want certain tools to be exclusive, and this approach isn't working correctly...
209 void ApplicationWindow::DeleteTool(void)
210 {
211         // For this tool, we check first to see if anything is selected. If so, we
212         // delete those and *don't* select the delete tool.
213         if (drawing->document.ItemsSelected() > 0)
214         {
215                 drawing->document.DeleteSelectedItems();
216                 drawing->update();
217                 deleteAct->setChecked(false);
218                 return;
219         }
220
221         // Otherwise, toggle the state of the tool
222         ClearUIToolStatesExcept(deleteAct);
223         SetInternalToolStates();
224 }
225
226
227 void ApplicationWindow::DimensionTool(void)
228 {
229         ClearUIToolStatesExcept(addDimensionAct);
230         SetInternalToolStates();
231 }
232
233
234 void ApplicationWindow::RotateTool(void)
235 {
236         ClearUIToolStatesExcept(rotateAct);
237         SetInternalToolStates();
238 }
239
240
241 void ApplicationWindow::AddLineTool(void)
242 {
243         ClearUIToolStatesExcept(addLineAct);
244         SetInternalToolStates();
245 }
246
247
248 void ApplicationWindow::AddCircleTool(void)
249 {
250         ClearUIToolStatesExcept(addCircleAct);
251         SetInternalToolStates();
252 }
253
254
255 void ApplicationWindow::AddArcTool(void)
256 {
257         ClearUIToolStatesExcept(addArcAct);
258         SetInternalToolStates();
259 }
260
261
262 void ApplicationWindow::AddPolygonTool(void)
263 {
264         ClearUIToolStatesExcept(addPolygonAct);
265         SetInternalToolStates();
266 }
267
268
269 void ApplicationWindow::ZoomInTool(void)
270 {
271         double zoomFactor = 2.0;
272 /*
273 We need to find the center of the screen, then figure out where the new corner
274 will be in the zoomed in window.
275
276 So we know in Qt coords, the center is found via:
277 size.width()  / 2 --> xCenter
278 size.height() / 2 --> yCenter
279
280 transform x/yCenter to Cartesian coordinates. So far, so good.
281
282 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
283 (after subtracting from center, that is...)
284 */
285         QSize size = drawing->size();
286         Vector center(size.width() / 2.0, size.height() / 2.0);
287 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
288         center = Painter::QtToCartesianCoords(center);
289 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
290         Vector newOrigin = center - ((center - Painter::origin) / zoomFactor);
291 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
292         Painter::origin = newOrigin;
293
294 //printf("Zoom in... level going from %02f to ", Painter::zoom);
295         // This just zooms leaving origin intact... should zoom in at the current center! [DONE]
296         // This should actually be calculated by drawing->gridPixels / grid size.
297         Painter::zoom *= zoomFactor;
298         drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
299 //      zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
300         zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
301         drawing->UpdateGridBackground();
302         drawing->update();
303
304         baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
305 }
306
307
308 void ApplicationWindow::ZoomOutTool(void)
309 {
310 /*
311 Ok, real example.
312 center = (436, 311)
313 origin = (223, 160.5)
314 newOrigin should be (-10, -10)
315 Why isn't it?
316
317 center - origin = (213, 150.5)
318 origin - center = (-213, -150.5)
319 x 2 = (-426, -301)
320 + center = (-10, -10)
321
322 */
323         double zoomFactor = 2.0;
324         QSize size = drawing->size();
325         Vector center(size.width() / 2.0, size.height() / 2.0);
326 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
327         center = Painter::QtToCartesianCoords(center);
328 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
329 //      Vector newOrigin = (center - Painter::origin) * zoomFactor;
330 //      Vector newOrigin = center - (Painter::origin * zoomFactor);
331         Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
332 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
333         Painter::origin = newOrigin;
334 //printf("Zoom out...\n");
335         // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
336         Painter::zoom /= zoomFactor;
337         drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
338 //      zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
339         zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
340         drawing->UpdateGridBackground();
341         drawing->update();
342
343         baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
344 }
345
346
347 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
348 {
349         if (exception != addArcAct)
350                 addArcAct->setChecked(false);
351
352         if (exception != addCircleAct)
353                 addCircleAct->setChecked(false);
354
355         if (exception != addDimensionAct)
356                 addDimensionAct->setChecked(false);
357
358         if (exception != addLineAct)
359                 addLineAct->setChecked(false);
360
361         if (exception != addPolygonAct)
362                 addPolygonAct->setChecked(false);
363
364         if (exception != deleteAct)
365                 deleteAct->setChecked(false);
366
367         if (exception != rotateAct)
368                 rotateAct->setChecked(false);
369 }
370
371
372 void ApplicationWindow::SetInternalToolStates(void)
373 {
374         Object::SetDeleteActive(deleteAct->isChecked());
375         Object::SetDimensionActive(addDimensionAct->isChecked());
376         drawing->SetRotateToolActive(rotateAct->isChecked());
377
378         // We can be sure that if we've come here, then either an active tool is
379         // being deactivated, or a new tool is being created. In either case, the
380         // old tool needs to be deleted.
381         if (drawing->toolAction)
382         {
383                 delete drawing->toolAction;
384                 drawing->toolAction = NULL;
385         }
386
387         drawing->SetAddLineToolActive(addLineAct->isChecked());
388         drawing->SetAddCircleToolActive(addCircleAct->isChecked());
389         drawing->SetAddArcToolActive(addArcAct->isChecked());
390         drawing->SetAddDimensionToolActive(addDimensionAct->isChecked());
391 }
392
393
394 void ApplicationWindow::HelpAbout(void)
395 {
396         aboutWin->show();
397 }
398
399
400 void ApplicationWindow::Settings(void)
401 {
402         SettingsDialog dlg(this);
403         dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
404
405         if (dlg.exec() == false)
406                 return;
407
408         // Deal with stuff here (since user hit "OK" button...)
409         drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
410         WriteSettings();
411 }
412
413
414 //
415 // Group a bunch of selected objects (which can include other groups) together
416 // or ungroup a selected group.
417 //
418 void ApplicationWindow::HandleGrouping(void)
419 {
420         int itemsSelected = drawing->document.ItemsSelected();
421
422         // If nothing selected, do nothing
423         if (itemsSelected == 0)
424         {
425                 statusBar()->showMessage(tr("No objects selected to make a group from."));
426                 return;
427         }
428
429         // If it's a group that's selected, ungroup it and leave the objects in a
430         // selected state
431         if (itemsSelected == 1)
432         {
433                 Object * object = drawing->document.SelectedItem(0);
434
435 #if 0
436 if (object == NULL)
437         printf("SelectedItem = NULL!\n");
438 else
439         printf("SelectedItem = %08X, type = %i\n", object, object->type);
440 #endif
441
442                 if (object == NULL || object->type != OTContainer)
443                 {
444                         statusBar()->showMessage(tr("A group requires two or more selected objects."));
445                         return;
446                 }
447
448                 // Need the parent of the group, we're assuming here that the parent is
449                 // the drawing's document. Does it matter? Maybe...
450                 // Could just stipulate that grouping like this only takes place where the
451                 // parent of the group is the drawing's document. Makes life much simpler.
452                 ((Container *)object)->SelectAll();
453                 ((Container *)object)->MoveContentsTo(&(drawing->document));
454                 drawing->document.Delete(object);
455                 statusBar()->showMessage(tr("Objects ungrouped."));
456         }
457         // Otherwise, if it's a group of 2 or more objects (which can be groups too)
458         // group them and select the group
459         else if (itemsSelected > 1)
460         {
461                 Container * container = new Container(Vector(), &(drawing->document));
462                 drawing->document.MoveSelectedContentsTo(container);
463                 drawing->document.Add(container);
464                 container->DeselectAll();
465                 container->state = OSSelected;
466                 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
467         }
468
469         drawing->update();
470 }
471
472
473 void ApplicationWindow::HandleGridSizeInPixels(int size)
474 {
475         drawing->SetGridSize(size);
476         drawing->update();
477 }
478
479
480 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
481 {
482         // Parse the text...
483         bool ok;
484         double value = text.toDouble(&ok);
485
486         // Nothing parsable to a double, so quit...
487         if (!ok || value == 0)
488                 return;
489
490         drawing->gridSpacing = value;
491         Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
492         drawing->UpdateGridBackground();
493         drawing->update();
494 }
495
496
497 void ApplicationWindow::HandleDimensionSize(QString text)
498 {
499         // Parse the text...
500         bool ok;
501         double value = text.toDouble(&ok);
502
503         // Nothing parsable to a double, so quit...
504         if (!ok || value == 0)
505                 return;
506
507         drawing->document.ResizeAllDimensions(value);
508 //      drawing->gridSpacing = value;
509 //      Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
510 //      drawing->UpdateGridBackground();
511         drawing->update();
512 }
513
514
515 void ApplicationWindow::CreateActions(void)
516 {
517         exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
518                 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
519         connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
520
521         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);
522         connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
523
524         fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
525                 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
526         connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
527
528         fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
529                 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
530         connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
531
532         deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
533         connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
534
535         addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
536         connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
537
538         addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
539         connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
540
541         addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
542         connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
543
544         addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
545         connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
546
547         addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
548         connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
549
550         aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
551         connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
552
553         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);
554         connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
555
556         zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
557         connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
558
559         zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
560         connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
561
562         fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
563         connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
564
565         fileOpenAct = CreateAction(tr("&Open Drawing"), tr("Open Drawing"), tr("Opens an existing drawing from a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+o")));
566         connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
567
568         fileSaveAct = CreateAction(tr("&Save Drawing"), tr("Save Drawing"), tr("Saves the current drawing to a file."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+s")));
569         connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
570
571         fileSaveAsAct = CreateAction(tr("Save Drawing &As"), tr("Save As"), tr("Saves the current drawing to a file with a different name."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+Shift+s")));
572         connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
573
574         fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
575
576         settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
577         connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
578
579         groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
580         connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
581
582         connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
583
584         disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
585
586 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
587 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
588 /*      QActionGroup * group = new QActionGroup(this);
589         group->addAction(deleteAct);
590         group->addAction(addDimensionAct);
591         group->addAction(addLineAct);
592         group->addAction(addCircleAct);
593         group->addAction(addArcAct);//*/
594 }
595
596
597 //
598 // Consolidates action creation from a multi-step process to a single-step one.
599 //
600 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
601         QIcon icon, QKeySequence key, bool checkable/*= false*/)
602 {
603         QAction * action = new QAction(icon, name, this);
604         action->setToolTip(tooltip);
605         action->setStatusTip(statustip);
606         action->setShortcut(key);
607         action->setCheckable(checkable);
608
609         return action;
610 }
611
612
613 //
614 // This is essentially the same as the previous function, but this allows more
615 // than one key sequence to be added as key shortcuts.
616 //
617 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
618         QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
619 {
620         QAction * action = new QAction(icon, name, this);
621         action->setToolTip(tooltip);
622         action->setStatusTip(statustip);
623         QList<QKeySequence> keyList;
624         keyList.append(key1);
625         keyList.append(key2);
626         action->setShortcuts(keyList);
627         action->setCheckable(checkable);
628
629         return action;
630 }
631
632
633 void ApplicationWindow::CreateMenus(void)
634 {
635         QMenu * menu = menuBar()->addMenu(tr("&File"));
636         menu->addAction(fileNewAct);
637         menu->addAction(fileOpenAct);
638         menu->addAction(fileSaveAct);
639         menu->addAction(fileSaveAsAct);
640         menu->addAction(fileCloseAct);
641         menu->addSeparator();
642         menu->addAction(exitAct);
643
644         menu = menuBar()->addMenu(tr("&View"));
645         menu->addAction(zoomInAct);
646         menu->addAction(zoomOutAct);
647
648         menu = menuBar()->addMenu(tr("&Edit"));
649         menu->addAction(snapToGridAct);
650         menu->addAction(groupAct);
651         menu->addAction(fixAngleAct);
652         menu->addAction(fixLengthAct);
653         menu->addAction(rotateAct);
654         menu->addAction(connectAct);
655         menu->addAction(disconnectAct);
656         menu->addSeparator();
657         menu->addAction(deleteAct);
658         menu->addSeparator();
659         menu->addAction(addLineAct);
660         menu->addAction(addCircleAct);
661         menu->addAction(addArcAct);
662         menu->addAction(addPolygonAct);
663         menu->addAction(addDimensionAct);
664         menu->addSeparator();
665         menu->addAction(settingsAct);
666
667         menu = menuBar()->addMenu(tr("&Help"));
668         menu->addAction(aboutAct);
669 }
670
671
672 void ApplicationWindow::CreateToolbars(void)
673 {
674         QToolBar * toolbar = addToolBar(tr("File"));
675         toolbar->setObjectName("File"); // Needed for saveState()
676         toolbar->addAction(exitAct);
677
678         toolbar = addToolBar(tr("View"));
679         toolbar->setObjectName("View");
680         toolbar->addAction(zoomInAct);
681         toolbar->addAction(zoomOutAct);
682
683         QSpinBox * spinbox = new QSpinBox;
684         toolbar->addWidget(spinbox);
685 //      QLineEdit * lineedit = new QLineEdit;
686         toolbar->addWidget(baseUnitInput);
687         toolbar->addWidget(dimensionSizeInput);
688
689         toolbar = addToolBar(tr("Edit"));
690         toolbar->setObjectName("Edit");
691         toolbar->addAction(snapToGridAct);
692         toolbar->addAction(groupAct);
693         toolbar->addAction(fixAngleAct);
694         toolbar->addAction(fixLengthAct);
695         toolbar->addAction(rotateAct);
696         toolbar->addAction(deleteAct);
697         toolbar->addAction(connectAct);
698         toolbar->addAction(disconnectAct);
699         toolbar->addSeparator();
700         toolbar->addAction(addLineAct);
701         toolbar->addAction(addCircleAct);
702         toolbar->addAction(addArcAct);
703         toolbar->addAction(addPolygonAct);
704         toolbar->addAction(addDimensionAct);
705
706         spinbox->setRange(4, 256);
707         spinbox->setValue(12);
708         baseUnitInput->setText("12");
709         connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
710         connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
711         connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
712 }
713
714
715 void ApplicationWindow::ReadSettings(void)
716 {
717         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
718         QSize size = settings.value("size", QSize(400, 400)).toSize();
719         drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
720         snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
721         resize(size);
722         move(pos);
723         restoreState(settings.value("windowState").toByteArray());
724 }
725
726
727 void ApplicationWindow::WriteSettings(void)
728 {
729         settings.setValue("pos", pos());
730         settings.setValue("size", size());
731         settings.setValue("windowState", saveState());
732         settings.setValue("useAntialiasing", drawing->useAntialiasing);
733         settings.setValue("snapToGrid", snapToGridAct->isChecked());
734 }
735