]> Shamusworld >> Repos - architektonas/blob - src/applicationwindow.cpp
bf181a882d50629fb27c30e079a34c4ba29af86f
[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->SetAddDimensionToolActive(addDimensionAct->isChecked());
390 }
391
392
393 void ApplicationWindow::HelpAbout(void)
394 {
395         aboutWin->show();
396 }
397
398
399 void ApplicationWindow::Settings(void)
400 {
401         SettingsDialog dlg(this);
402         dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
403
404         if (dlg.exec() == false)
405                 return;
406
407         // Deal with stuff here (since user hit "OK" button...)
408         drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
409         WriteSettings();
410 }
411
412
413 //
414 // Group a bunch of selected objects (which can include other groups) together
415 // or ungroup a selected group.
416 //
417 void ApplicationWindow::HandleGrouping(void)
418 {
419         int itemsSelected = drawing->document.ItemsSelected();
420
421         // If nothing selected, do nothing
422         if (itemsSelected == 0)
423         {
424                 statusBar()->showMessage(tr("No objects selected to make a group from."));
425                 return;
426         }
427
428         // If it's a group that's selected, ungroup it and leave the objects in a
429         // selected state
430         if (itemsSelected == 1)
431         {
432                 Object * object = drawing->document.SelectedItem(0);
433
434 #if 0
435 if (object == NULL)
436         printf("SelectedItem = NULL!\n");
437 else
438         printf("SelectedItem = %08X, type = %i\n", object, object->type);
439 #endif
440
441                 if (object == NULL || object->type != OTContainer)
442                 {
443                         statusBar()->showMessage(tr("A group requires two or more selected objects."));
444                         return;
445                 }
446
447                 // Need the parent of the group, we're assuming here that the parent is
448                 // the drawing's document. Does it matter? Maybe...
449                 // Could just stipulate that grouping like this only takes place where the
450                 // parent of the group is the drawing's document. Makes life much simpler.
451                 ((Container *)object)->SelectAll();
452                 ((Container *)object)->MoveContentsTo(&(drawing->document));
453                 drawing->document.Delete(object);
454                 statusBar()->showMessage(tr("Objects ungrouped."));
455         }
456         // Otherwise, if it's a group of 2 or more objects (which can be groups too)
457         // group them and select the group
458         else if (itemsSelected > 1)
459         {
460                 Container * container = new Container(Vector(), &(drawing->document));
461                 drawing->document.MoveSelectedContentsTo(container);
462                 drawing->document.Add(container);
463                 container->DeselectAll();
464                 container->state = OSSelected;
465                 statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(itemsSelected));
466         }
467
468         drawing->update();
469 }
470
471
472 void ApplicationWindow::HandleGridSizeInPixels(int size)
473 {
474         drawing->SetGridSize(size);
475         drawing->update();
476 }
477
478
479 void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
480 {
481         // Parse the text...
482         bool ok;
483         double value = text.toDouble(&ok);
484
485         // Nothing parsable to a double, so quit...
486         if (!ok || value == 0)
487                 return;
488
489         drawing->gridSpacing = value;
490         Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
491         drawing->UpdateGridBackground();
492         drawing->update();
493 }
494
495
496 void ApplicationWindow::HandleDimensionSize(QString text)
497 {
498         // Parse the text...
499         bool ok;
500         double value = text.toDouble(&ok);
501
502         // Nothing parsable to a double, so quit...
503         if (!ok || value == 0)
504                 return;
505
506         drawing->document.ResizeAllDimensions(value);
507 //      drawing->gridSpacing = value;
508 //      Painter::zoom = drawing->gridPixels / drawing->gridSpacing;
509 //      drawing->UpdateGridBackground();
510         drawing->update();
511 }
512
513
514 void ApplicationWindow::CreateActions(void)
515 {
516         exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
517                 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
518         connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
519
520         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);
521         connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
522
523         fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
524                 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
525         connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
526
527         fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
528                 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
529         connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
530
531         deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(tr("Delete")), true);
532         connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
533
534         addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
535         connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
536
537         addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
538         connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
539
540         addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
541         connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
542
543         addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
544         connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
545
546         addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
547         connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
548
549         aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
550         connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
551
552         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);
553         connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
554
555         zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
556         connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
557
558         zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
559         connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
560
561         fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
562         connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
563
564         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")));
565         connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
566
567         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")));
568         connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
569
570         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")));
571         connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
572
573         fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
574
575         settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
576         connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
577
578         groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/group-tool.png"), QKeySequence("g"));
579         connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
580
581 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
582 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
583 /*      QActionGroup * group = new QActionGroup(this);
584         group->addAction(deleteAct);
585         group->addAction(addDimensionAct);
586         group->addAction(addLineAct);
587         group->addAction(addCircleAct);
588         group->addAction(addArcAct);//*/
589 }
590
591
592 //
593 // Consolidates action creation from a multi-step process to a single-step one.
594 //
595 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
596         QIcon icon, QKeySequence key, bool checkable/*= false*/)
597 {
598         QAction * action = new QAction(icon, name, this);
599         action->setToolTip(tooltip);
600         action->setStatusTip(statustip);
601         action->setShortcut(key);
602         action->setCheckable(checkable);
603
604         return action;
605 }
606
607
608 //
609 // This is essentially the same as the previous function, but this allows more
610 // than one key sequence to be added as key shortcuts.
611 //
612 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
613         QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
614 {
615         QAction * action = new QAction(icon, name, this);
616         action->setToolTip(tooltip);
617         action->setStatusTip(statustip);
618         QList<QKeySequence> keyList;
619         keyList.append(key1);
620         keyList.append(key2);
621         action->setShortcuts(keyList);
622         action->setCheckable(checkable);
623
624         return action;
625 }
626
627
628 void ApplicationWindow::CreateMenus(void)
629 {
630         QMenu * menu = menuBar()->addMenu(tr("&File"));
631         menu->addAction(fileNewAct);
632         menu->addAction(fileOpenAct);
633         menu->addAction(fileSaveAct);
634         menu->addAction(fileSaveAsAct);
635         menu->addAction(fileCloseAct);
636         menu->addSeparator();
637         menu->addAction(exitAct);
638
639         menu = menuBar()->addMenu(tr("&View"));
640         menu->addAction(zoomInAct);
641         menu->addAction(zoomOutAct);
642
643         menu = menuBar()->addMenu(tr("&Edit"));
644         menu->addAction(snapToGridAct);
645         menu->addAction(groupAct);
646         menu->addAction(fixAngleAct);
647         menu->addAction(fixLengthAct);
648         menu->addAction(rotateAct);
649         menu->addSeparator();
650         menu->addAction(deleteAct);
651         menu->addSeparator();
652         menu->addAction(addLineAct);
653         menu->addAction(addCircleAct);
654         menu->addAction(addArcAct);
655         menu->addAction(addPolygonAct);
656         menu->addAction(addDimensionAct);
657         menu->addSeparator();
658         menu->addAction(settingsAct);
659
660         menu = menuBar()->addMenu(tr("&Help"));
661         menu->addAction(aboutAct);
662 }
663
664
665 void ApplicationWindow::CreateToolbars(void)
666 {
667         QToolBar * toolbar = addToolBar(tr("File"));
668         toolbar->setObjectName("File"); // Needed for saveState()
669         toolbar->addAction(exitAct);
670
671         toolbar = addToolBar(tr("View"));
672         toolbar->setObjectName("View");
673         toolbar->addAction(zoomInAct);
674         toolbar->addAction(zoomOutAct);
675
676         QSpinBox * spinbox = new QSpinBox;
677         toolbar->addWidget(spinbox);
678 //      QLineEdit * lineedit = new QLineEdit;
679         toolbar->addWidget(baseUnitInput);
680         toolbar->addWidget(dimensionSizeInput);
681
682         toolbar = addToolBar(tr("Edit"));
683         toolbar->setObjectName("Edit");
684         toolbar->addAction(snapToGridAct);
685         toolbar->addAction(groupAct);
686         toolbar->addAction(fixAngleAct);
687         toolbar->addAction(fixLengthAct);
688         toolbar->addAction(rotateAct);
689         toolbar->addAction(deleteAct);
690         toolbar->addSeparator();
691         toolbar->addAction(addLineAct);
692         toolbar->addAction(addCircleAct);
693         toolbar->addAction(addArcAct);
694         toolbar->addAction(addPolygonAct);
695         toolbar->addAction(addDimensionAct);
696
697         spinbox->setRange(4, 256);
698         spinbox->setValue(12);
699         baseUnitInput->setText("12");
700         connect(spinbox, SIGNAL(valueChanged(int)), this, SLOT(HandleGridSizeInPixels(int)));
701         connect(baseUnitInput, SIGNAL(textChanged(QString)), this, SLOT(HandleGridSizeInBaseUnits(QString)));
702         connect(dimensionSizeInput, SIGNAL(textChanged(QString)), this, SLOT(HandleDimensionSize(QString)));
703 }
704
705
706 void ApplicationWindow::ReadSettings(void)
707 {
708         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
709         QSize size = settings.value("size", QSize(400, 400)).toSize();
710         drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
711         snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
712         resize(size);
713         move(pos);
714         restoreState(settings.value("windowState").toByteArray());
715 }
716
717
718 void ApplicationWindow::WriteSettings(void)
719 {
720         settings.setValue("pos", pos());
721         settings.setValue("size", size());
722         settings.setValue("windowState", saveState());
723         settings.setValue("useAntialiasing", drawing->useAntialiasing);
724         settings.setValue("snapToGrid", snapToGridAct->isChecked());
725 }
726