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