]> Shamusworld >> Repos - architektonas/blob - src/applicationwindow.cpp
92c0547f773281dcc7e516db5f4eba1a88f8f408
[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 "drawingview.h"
33 #include "generaltab.h"
34 #include "painter.h"
35 #include "settingsdialog.h"
36
37
38 ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas")
39 {
40         drawing = new DrawingView(this);
41         drawing->setMouseTracking(true);                // We want *all* mouse events...!
42         setCentralWidget(drawing);
43
44         aboutWin = new AboutWindow(this);
45
46 //      ((TTEdit *)qApp)->charWnd = new CharWindow(this);
47
48         setWindowIcon(QIcon(":/res/atns-icon.png"));
49         setWindowTitle("Architektonas");
50
51         CreateActions();
52         CreateMenus();
53         CreateToolbars();
54
55         //      Create status bar
56         zoomIndicator = new QLabel("Zoom: 12.5%");
57         statusBar()->addPermanentWidget(zoomIndicator);
58         statusBar()->showMessage(tr("Ready"));
59
60         ReadSettings();
61
62 //      connect(textEdit->document(), SIGNAL(contentsChanged()),
63 //                      this, SLOT(documentWasModified()));
64
65 //      setCurrentFile("");
66         setUnifiedTitleAndToolBarOnMac(true);
67
68 //      ((TTEdit *)qApp)->charWnd->show();//eh?
69         Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
70 }
71
72 void ApplicationWindow::closeEvent(QCloseEvent * event)
73 {
74         WriteSettings();
75         event->accept();                                                        // Use ignore() if can't close for some reason
76         //Do we have a memory leak here if we don't delete the font in the Object???
77 }
78
79 //void ApplicationWindow::FileOpen(void)
80 //{
81 //}
82
83 void ApplicationWindow::SnapToGridTool(void)
84 {
85         Object::SetSnapMode(snapToGridAct->isChecked());
86 }
87
88 void ApplicationWindow::FixAngle(void)
89 {
90         Object::SetFixedAngle(fixAngleAct->isChecked());
91 }
92
93 void ApplicationWindow::FixLength(void)
94 {
95         Object::SetFixedLength(fixLengthAct->isChecked());
96 }
97
98 // We want certain tools to be exclusive, and this approach isn't working correctly...
99 void ApplicationWindow::DeleteTool(void)
100 {
101         
102         ClearUIToolStatesExcept(deleteAct);
103         SetInternalToolStates();
104 }
105
106 void ApplicationWindow::DimensionTool(void)
107 {
108         ClearUIToolStatesExcept(addDimensionAct);
109         SetInternalToolStates();
110 }
111
112 void ApplicationWindow::RotateTool(void)
113 {
114         ClearUIToolStatesExcept(rotateAct);
115         SetInternalToolStates();
116 }
117
118 void ApplicationWindow::AddLineTool(void)
119 {
120         ClearUIToolStatesExcept(addLineAct);
121         SetInternalToolStates();
122 }
123
124 void ApplicationWindow::AddCircleTool(void)
125 {
126         ClearUIToolStatesExcept(addCircleAct);
127         SetInternalToolStates();
128 }
129
130 void ApplicationWindow::AddArcTool(void)
131 {
132         ClearUIToolStatesExcept(addArcAct);
133         SetInternalToolStates();
134 }
135
136 void ApplicationWindow::AddPolygonTool(void)
137 {
138         ClearUIToolStatesExcept(addPolygonAct);
139         SetInternalToolStates();
140 }
141
142 void ApplicationWindow::ZoomInTool(void)
143 {
144         double zoomFactor = 2.0;
145 /*
146 We need to find the center of the screen, then figure out where the new corner
147 will be in the zoomed in window.
148
149 So we know in Qt coords, the center is found via:
150 size.width()  / 2 --> xCenter
151 size.height() / 2 --> yCenter
152
153 transform x/yCenter to Cartesian coordinates. So far, so good.
154
155 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
156 (after subtracting from center, that is...)
157 */
158         QSize size = drawing->size();
159         Vector center(size.width() / 2.0, size.height() / 2.0);
160 //printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y);
161         center = Painter::QtToCartesianCoords(center);
162 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
163         Vector newOrigin = center - ((center - Painter::origin) / zoomFactor);
164 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
165         Painter::origin = newOrigin;
166
167 //printf("Zoom in... level going from %02f to ", Painter::zoom);
168         // This just zooms leaving origin intact... should zoom in at the current center! [DONE]
169         Painter::zoom *= zoomFactor;
170         zoomIndicator->setText(QString("Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM));
171         drawing->UpdateGridBackground();
172         drawing->update();
173 }
174
175 void ApplicationWindow::ZoomOutTool(void)
176 {
177 /*
178 Ok, real example.
179 center = (436, 311)
180 origin = (223, 160.5)
181 newOrigin should be (-10, -10)
182 Why isn't it?
183
184 center - origin = (213, 150.5)
185 origin - center = (-213, -150.5)
186 x 2 = (-426, -301)
187 + center = (-10, -10)
188
189 */
190         double zoomFactor = 2.0;
191         QSize size = drawing->size();
192         Vector center(size.width() / 2.0, size.height() / 2.0);
193 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
194         center = Painter::QtToCartesianCoords(center);
195 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
196 //      Vector newOrigin = (center - Painter::origin) * zoomFactor;
197 //      Vector newOrigin = center - (Painter::origin * zoomFactor);
198         Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
199 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
200         Painter::origin = newOrigin;
201 //printf("Zoom out...\n");
202         // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
203         Painter::zoom /= zoomFactor;
204         zoomIndicator->setText(QString("Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM));
205         drawing->UpdateGridBackground();
206         drawing->update();
207 }
208
209 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
210 {
211         if (exception != addArcAct)
212                 addArcAct->setChecked(false);
213
214         if (exception != addCircleAct)
215                 addCircleAct->setChecked(false);
216
217         if (exception != addDimensionAct)
218                 addDimensionAct->setChecked(false);
219
220         if (exception != addLineAct)
221                 addLineAct->setChecked(false);
222
223         if (exception != addPolygonAct)
224                 addPolygonAct->setChecked(false);
225
226         if (exception != deleteAct)
227                 deleteAct->setChecked(false);
228
229         if (exception != rotateAct)
230                 rotateAct->setChecked(false);
231 }
232
233 void ApplicationWindow::SetInternalToolStates(void)
234 {
235         Object::SetDeleteActive(deleteAct->isChecked());
236         Object::SetDimensionActive(addDimensionAct->isChecked());
237         drawing->SetRotateToolActive(rotateAct->isChecked());
238         drawing->SetAddLineToolActive(addLineAct->isChecked());
239         drawing->SetAddCircleToolActive(addCircleAct->isChecked());
240 }
241
242 void ApplicationWindow::HelpAbout(void)
243 {
244         aboutWin->show();
245 }
246
247 void ApplicationWindow::Settings(void)
248 {
249         SettingsDialog dlg(this);
250         dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
251
252         if (dlg.exec() == false)
253                 return;
254
255         // Deal with stuff here (since user hit "OK" button...)
256         drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
257         WriteSettings();
258 }
259
260 void ApplicationWindow::CreateActions(void)
261 {
262         exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
263                 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
264         connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
265
266         snapToGridAct = CreateAction(tr("&Snap To Grid"), tr("Snap To Grid"), tr("Snaps mouse cursor to the visible grid when moving/creating objects."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("S,G")), true);
267         connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
268
269         fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
270                 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
271         connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
272
273         fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
274                 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
275         connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
276
277         deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(), true);
278         connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
279
280         addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
281         connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
282
283         addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
284         connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
285
286         addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
287         connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
288
289         addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
290         connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
291
292         addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
293         connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
294
295         aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
296         connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
297
298         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);
299         connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
300
301         zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
302         connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
303
304         zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
305         connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
306
307         fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
308
309         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")));
310
311         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")));
312
313         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")));
314
315         fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
316
317         settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
318         connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
319
320 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
321 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
322 /*      QActionGroup * group = new QActionGroup(this);
323         group->addAction(deleteAct);
324         group->addAction(addDimensionAct);
325         group->addAction(addLineAct);
326         group->addAction(addCircleAct);
327         group->addAction(addArcAct);//*/
328 }
329
330 //
331 // Consolidates action creation from a multi-step process to a single-step one.
332 //
333 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
334         QIcon icon, QKeySequence key, bool checkable/*= false*/)
335 {
336         QAction * action = new QAction(icon, name, this);
337         action->setToolTip(tooltip);
338         action->setStatusTip(statustip);
339         action->setShortcut(key);
340         action->setCheckable(checkable);
341
342         return action;
343 }
344
345 //
346 // This is essentially the same as the previous function, but this allows more
347 // than one key sequence to be added as key shortcuts.
348 //
349 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
350         QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
351 {
352         QAction * action = new QAction(icon, name, this);
353         action->setToolTip(tooltip);
354         action->setStatusTip(statustip);
355         QList<QKeySequence> keyList;
356         keyList.append(key1);
357         keyList.append(key2);
358         action->setShortcuts(keyList);
359         action->setCheckable(checkable);
360
361         return action;
362 }
363
364 void ApplicationWindow::CreateMenus(void)
365 {
366         QMenu * menu = menuBar()->addMenu(tr("&File"));
367         menu->addAction(fileNewAct);
368         menu->addAction(fileOpenAct);
369         menu->addAction(fileSaveAct);
370         menu->addAction(fileSaveAsAct);
371         menu->addAction(fileCloseAct);
372         menu->addSeparator();
373         menu->addAction(exitAct);
374
375         menu = menuBar()->addMenu(tr("&View"));
376         menu->addAction(zoomInAct);
377         menu->addAction(zoomOutAct);
378
379         menu = menuBar()->addMenu(tr("&Edit"));
380         menu->addAction(snapToGridAct);
381         menu->addAction(fixAngleAct);
382         menu->addAction(fixLengthAct);
383         menu->addAction(rotateAct);
384         menu->addSeparator();
385         menu->addAction(deleteAct);
386         menu->addSeparator();
387         menu->addAction(addLineAct);
388         menu->addAction(addCircleAct);
389         menu->addAction(addArcAct);
390         menu->addAction(addPolygonAct);
391         menu->addAction(addDimensionAct);
392         menu->addSeparator();
393         menu->addAction(settingsAct);
394
395         menu = menuBar()->addMenu(tr("&Help"));
396         menu->addAction(aboutAct);
397 }
398
399 void ApplicationWindow::CreateToolbars(void)
400 {
401         QToolBar * toolbar = addToolBar(tr("File"));
402         toolbar->addAction(exitAct);
403
404         toolbar = addToolBar(tr("View"));
405         toolbar->addAction(zoomInAct);
406         toolbar->addAction(zoomOutAct);
407
408         toolbar = addToolBar(tr("Edit"));
409         toolbar->addAction(snapToGridAct);
410         toolbar->addAction(fixAngleAct);
411         toolbar->addAction(fixLengthAct);
412         toolbar->addAction(rotateAct);
413         toolbar->addAction(deleteAct);
414         toolbar->addSeparator();
415         toolbar->addAction(addLineAct);
416         toolbar->addAction(addCircleAct);
417         toolbar->addAction(addArcAct);
418         toolbar->addAction(addPolygonAct);
419         toolbar->addAction(addDimensionAct);
420 }
421
422 void ApplicationWindow::ReadSettings(void)
423 {
424         QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
425         QSize size = settings.value("size", QSize(400, 400)).toSize();
426         drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
427         snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
428         resize(size);
429         move(pos);
430 //      pos = settings.value("charWndPos", QPoint(0, 0)).toPoint();
431 //      size = settings.value("charWndSize", QSize(200, 200)).toSize();
432 //      ((TTEdit *)qApp)->charWnd->resize(size);
433 //      ((TTEdit *)qApp)->charWnd->move(pos);
434 }
435
436 void ApplicationWindow::WriteSettings(void)
437 {
438         settings.setValue("pos", pos());
439         settings.setValue("size", size());
440         settings.setValue("useAntialiasing", drawing->useAntialiasing);
441         settings.setValue("snapToGrid", snapToGridAct->isChecked());
442 //      settings.setValue("charWndPos", ((TTEdit *)qApp)->charWnd->pos());
443 //      settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size());
444 }