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