2 // applicationwindow.cpp: Architektonas
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
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
24 // Uncomment this for debugging...
26 //#define DEBUGFOO // Various tool debugging...
27 //#define DEBUGTP // Toolpalette debugging...
29 #include "applicationwindow.h"
32 #include "drawingview.h"
33 #include "generaltab.h"
35 #include "settingsdialog.h"
38 ApplicationWindow::ApplicationWindow(): settings("Underground Software", "Architektonas")
40 drawing = new DrawingView(this);
41 drawing->setMouseTracking(true); // We want *all* mouse events...!
42 setCentralWidget(drawing);
44 aboutWin = new AboutWindow(this);
46 // ((TTEdit *)qApp)->charWnd = new CharWindow(this);
48 setWindowIcon(QIcon(":/res/atns-icon.png"));
49 setWindowTitle("Architektonas");
56 zoomIndicator = new QLabel("Grid: 12.0\" Zoom: 12.5%");
57 statusBar()->addPermanentWidget(zoomIndicator);
58 statusBar()->showMessage(tr("Ready"));
62 // connect(textEdit->document(), SIGNAL(contentsChanged()),
63 // this, SLOT(documentWasModified()));
65 // setCurrentFile("");
66 setUnifiedTitleAndToolBarOnMac(true);
68 // ((TTEdit *)qApp)->charWnd->show();//eh?
69 Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
72 void ApplicationWindow::closeEvent(QCloseEvent * event)
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???
79 //void ApplicationWindow::FileOpen(void)
83 void ApplicationWindow::SnapToGridTool(void)
85 Object::SetSnapMode(snapToGridAct->isChecked());
88 void ApplicationWindow::FixAngle(void)
90 Object::SetFixedAngle(fixAngleAct->isChecked());
93 void ApplicationWindow::FixLength(void)
95 Object::SetFixedLength(fixLengthAct->isChecked());
98 // We want certain tools to be exclusive, and this approach isn't working correctly...
99 void ApplicationWindow::DeleteTool(void)
102 ClearUIToolStatesExcept(deleteAct);
103 SetInternalToolStates();
106 void ApplicationWindow::DimensionTool(void)
108 ClearUIToolStatesExcept(addDimensionAct);
109 SetInternalToolStates();
112 void ApplicationWindow::RotateTool(void)
114 ClearUIToolStatesExcept(rotateAct);
115 SetInternalToolStates();
118 void ApplicationWindow::AddLineTool(void)
120 ClearUIToolStatesExcept(addLineAct);
121 SetInternalToolStates();
124 void ApplicationWindow::AddCircleTool(void)
126 ClearUIToolStatesExcept(addCircleAct);
127 SetInternalToolStates();
130 void ApplicationWindow::AddArcTool(void)
132 ClearUIToolStatesExcept(addArcAct);
133 SetInternalToolStates();
136 void ApplicationWindow::AddPolygonTool(void)
138 ClearUIToolStatesExcept(addPolygonAct);
139 SetInternalToolStates();
142 void ApplicationWindow::ZoomInTool(void)
144 double zoomFactor = 2.0;
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.
149 So we know in Qt coords, the center is found via:
150 size.width() / 2 --> xCenter
151 size.height() / 2 --> yCenter
153 transform x/yCenter to Cartesian coordinates. So far, so good.
155 when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2
156 (after subtracting from center, that is...)
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;
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 drawing->gridSpacing = 12.0 / Painter::zoom;
171 zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
172 drawing->UpdateGridBackground();
176 void ApplicationWindow::ZoomOutTool(void)
181 origin = (223, 160.5)
182 newOrigin should be (-10, -10)
185 center - origin = (213, 150.5)
186 origin - center = (-213, -150.5)
188 + center = (-10, -10)
191 double zoomFactor = 2.0;
192 QSize size = drawing->size();
193 Vector center(size.width() / 2.0, size.height() / 2.0);
194 //printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y);
195 center = Painter::QtToCartesianCoords(center);
196 //printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y);
197 // Vector newOrigin = (center - Painter::origin) * zoomFactor;
198 // Vector newOrigin = center - (Painter::origin * zoomFactor);
199 Vector newOrigin = center + ((Painter::origin - center) * zoomFactor);
200 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
201 Painter::origin = newOrigin;
202 //printf("Zoom out...\n");
203 // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
204 Painter::zoom /= zoomFactor;
205 drawing->gridSpacing = 12.0 / Painter::zoom;
206 zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
207 drawing->UpdateGridBackground();
211 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
213 if (exception != addArcAct)
214 addArcAct->setChecked(false);
216 if (exception != addCircleAct)
217 addCircleAct->setChecked(false);
219 if (exception != addDimensionAct)
220 addDimensionAct->setChecked(false);
222 if (exception != addLineAct)
223 addLineAct->setChecked(false);
225 if (exception != addPolygonAct)
226 addPolygonAct->setChecked(false);
228 if (exception != deleteAct)
229 deleteAct->setChecked(false);
231 if (exception != rotateAct)
232 rotateAct->setChecked(false);
235 void ApplicationWindow::SetInternalToolStates(void)
237 Object::SetDeleteActive(deleteAct->isChecked());
238 Object::SetDimensionActive(addDimensionAct->isChecked());
239 drawing->SetRotateToolActive(rotateAct->isChecked());
240 drawing->SetAddLineToolActive(addLineAct->isChecked());
241 drawing->SetAddCircleToolActive(addCircleAct->isChecked());
244 void ApplicationWindow::HelpAbout(void)
249 void ApplicationWindow::Settings(void)
251 SettingsDialog dlg(this);
252 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
254 if (dlg.exec() == false)
257 // Deal with stuff here (since user hit "OK" button...)
258 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
262 void ApplicationWindow::CreateActions(void)
264 exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
265 QIcon(":/res/quit.png"), QKeySequence(tr("Ctrl+q")));
266 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
268 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")), true);
269 connect(snapToGridAct, SIGNAL(triggered()), this, SLOT(SnapToGridTool()));
271 fixAngleAct = CreateAction(tr("Fix &Angle"), tr("Fix Angle"), tr("Fixes the angle of an object."),
272 QIcon(":/res/fix-angle.png"), QKeySequence(tr("F,A")), true);
273 connect(fixAngleAct, SIGNAL(triggered()), this, SLOT(FixAngle()));
275 fixLengthAct = CreateAction(tr("Fix &Length"), tr("Fix Length"), tr("Fixes the length of an object."),
276 QIcon(":/res/fix-length.png"), QKeySequence(tr("F,L")), true);
277 connect(fixLengthAct, SIGNAL(triggered()), this, SLOT(FixLength()));
279 deleteAct = CreateAction(tr("&Delete"), tr("Delete Object"), tr("Deletes selected objects."), QIcon(":/res/delete-tool.png"), QKeySequence(), true);
280 connect(deleteAct, SIGNAL(triggered()), this, SLOT(DeleteTool()));
282 addDimensionAct = CreateAction(tr("Add &Dimension"), tr("Add Dimension"), tr("Adds a dimension to the drawing."), QIcon(":/res/dimension-tool.png"), QKeySequence("D,I"), true);
283 connect(addDimensionAct, SIGNAL(triggered()), this, SLOT(DimensionTool()));
285 addLineAct = CreateAction(tr("Add &Line"), tr("Add Line"), tr("Adds lines to the drawing."), QIcon(":/res/add-line-tool.png"), QKeySequence("A,L"), true);
286 connect(addLineAct, SIGNAL(triggered()), this, SLOT(AddLineTool()));
288 addCircleAct = CreateAction(tr("Add &Circle"), tr("Add Circle"), tr("Adds circles to the drawing."), QIcon(":/res/add-circle-tool.png"), QKeySequence("A,C"), true);
289 connect(addCircleAct, SIGNAL(triggered()), this, SLOT(AddCircleTool()));
291 addArcAct = CreateAction(tr("Add &Arc"), tr("Add Arc"), tr("Adds arcs to the drawing."), QIcon(":/res/add-arc-tool.png"), QKeySequence("A,A"), true);
292 connect(addArcAct, SIGNAL(triggered()), this, SLOT(AddArcTool()));
294 addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
295 connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
297 aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
298 connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
300 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);
301 connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool()));
303 zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("=")));
304 connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool()));
306 zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-")));
307 connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
309 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
311 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")));
313 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")));
315 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")));
317 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
319 settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
320 connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
322 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
323 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
324 /* QActionGroup * group = new QActionGroup(this);
325 group->addAction(deleteAct);
326 group->addAction(addDimensionAct);
327 group->addAction(addLineAct);
328 group->addAction(addCircleAct);
329 group->addAction(addArcAct);//*/
333 // Consolidates action creation from a multi-step process to a single-step one.
335 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
336 QIcon icon, QKeySequence key, bool checkable/*= false*/)
338 QAction * action = new QAction(icon, name, this);
339 action->setToolTip(tooltip);
340 action->setStatusTip(statustip);
341 action->setShortcut(key);
342 action->setCheckable(checkable);
348 // This is essentially the same as the previous function, but this allows more
349 // than one key sequence to be added as key shortcuts.
351 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
352 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
354 QAction * action = new QAction(icon, name, this);
355 action->setToolTip(tooltip);
356 action->setStatusTip(statustip);
357 QList<QKeySequence> keyList;
358 keyList.append(key1);
359 keyList.append(key2);
360 action->setShortcuts(keyList);
361 action->setCheckable(checkable);
366 void ApplicationWindow::CreateMenus(void)
368 QMenu * menu = menuBar()->addMenu(tr("&File"));
369 menu->addAction(fileNewAct);
370 menu->addAction(fileOpenAct);
371 menu->addAction(fileSaveAct);
372 menu->addAction(fileSaveAsAct);
373 menu->addAction(fileCloseAct);
374 menu->addSeparator();
375 menu->addAction(exitAct);
377 menu = menuBar()->addMenu(tr("&View"));
378 menu->addAction(zoomInAct);
379 menu->addAction(zoomOutAct);
381 menu = menuBar()->addMenu(tr("&Edit"));
382 menu->addAction(snapToGridAct);
383 menu->addAction(fixAngleAct);
384 menu->addAction(fixLengthAct);
385 menu->addAction(rotateAct);
386 menu->addSeparator();
387 menu->addAction(deleteAct);
388 menu->addSeparator();
389 menu->addAction(addLineAct);
390 menu->addAction(addCircleAct);
391 menu->addAction(addArcAct);
392 menu->addAction(addPolygonAct);
393 menu->addAction(addDimensionAct);
394 menu->addSeparator();
395 menu->addAction(settingsAct);
397 menu = menuBar()->addMenu(tr("&Help"));
398 menu->addAction(aboutAct);
401 void ApplicationWindow::CreateToolbars(void)
403 QToolBar * toolbar = addToolBar(tr("File"));
404 toolbar->addAction(exitAct);
406 toolbar = addToolBar(tr("View"));
407 toolbar->addAction(zoomInAct);
408 toolbar->addAction(zoomOutAct);
410 toolbar = addToolBar(tr("Edit"));
411 toolbar->addAction(snapToGridAct);
412 toolbar->addAction(fixAngleAct);
413 toolbar->addAction(fixLengthAct);
414 toolbar->addAction(rotateAct);
415 toolbar->addAction(deleteAct);
416 toolbar->addSeparator();
417 toolbar->addAction(addLineAct);
418 toolbar->addAction(addCircleAct);
419 toolbar->addAction(addArcAct);
420 toolbar->addAction(addPolygonAct);
421 toolbar->addAction(addDimensionAct);
424 void ApplicationWindow::ReadSettings(void)
426 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
427 QSize size = settings.value("size", QSize(400, 400)).toSize();
428 drawing->useAntialiasing = settings.value("useAntialiasing", true).toBool();
429 snapToGridAct->setChecked(settings.value("snapToGrid", true).toBool());
432 // pos = settings.value("charWndPos", QPoint(0, 0)).toPoint();
433 // size = settings.value("charWndSize", QSize(200, 200)).toSize();
434 // ((TTEdit *)qApp)->charWnd->resize(size);
435 // ((TTEdit *)qApp)->charWnd->move(pos);
438 void ApplicationWindow::WriteSettings(void)
440 settings.setValue("pos", pos());
441 settings.setValue("size", size());
442 settings.setValue("useAntialiasing", drawing->useAntialiasing);
443 settings.setValue("snapToGrid", snapToGridAct->isChecked());
444 // settings.setValue("charWndPos", ((TTEdit *)qApp)->charWnd->pos());
445 // settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size());