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