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("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 zoomIndicator->setText(QString("Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM));
171 drawing->UpdateGridBackground();
175 void ApplicationWindow::ZoomOutTool(void)
180 origin = (223, 160.5)
181 newOrigin should be (-10, -10)
184 center - origin = (213, 150.5)
185 origin - center = (-213, -150.5)
187 + center = (-10, -10)
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();
209 void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
211 if (exception != addArcAct)
212 addArcAct->setChecked(false);
214 if (exception != addCircleAct)
215 addCircleAct->setChecked(false);
217 if (exception != addDimensionAct)
218 addDimensionAct->setChecked(false);
220 if (exception != addLineAct)
221 addLineAct->setChecked(false);
223 if (exception != addPolygonAct)
224 addPolygonAct->setChecked(false);
226 if (exception != deleteAct)
227 deleteAct->setChecked(false);
229 if (exception != rotateAct)
230 rotateAct->setChecked(false);
233 void ApplicationWindow::SetInternalToolStates(void)
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());
242 void ApplicationWindow::HelpAbout(void)
247 void ApplicationWindow::Settings(void)
249 SettingsDialog dlg(this);
250 dlg.generalTab->antialiasChk->setChecked(drawing->useAntialiasing);
252 if (dlg.exec() == false)
255 // Deal with stuff here (since user hit "OK" button...)
256 drawing->useAntialiasing = dlg.generalTab->antialiasChk->isChecked();
260 void ApplicationWindow::CreateActions(void)
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
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()));
307 fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
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")));
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")));
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")));
315 fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
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()));
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);//*/
331 // Consolidates action creation from a multi-step process to a single-step one.
333 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
334 QIcon icon, QKeySequence key, bool checkable/*= false*/)
336 QAction * action = new QAction(icon, name, this);
337 action->setToolTip(tooltip);
338 action->setStatusTip(statustip);
339 action->setShortcut(key);
340 action->setCheckable(checkable);
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.
349 QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
350 QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
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);
364 void ApplicationWindow::CreateMenus(void)
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);
375 menu = menuBar()->addMenu(tr("&View"));
376 menu->addAction(zoomInAct);
377 menu->addAction(zoomOutAct);
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);
395 menu = menuBar()->addMenu(tr("&Help"));
396 menu->addAction(aboutAct);
399 void ApplicationWindow::CreateToolbars(void)
401 QToolBar * toolbar = addToolBar(tr("File"));
402 toolbar->addAction(exitAct);
404 toolbar = addToolBar(tr("View"));
405 toolbar->addAction(zoomInAct);
406 toolbar->addAction(zoomOutAct);
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);
422 void ApplicationWindow::ReadSettings(void)
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());
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);
436 void ApplicationWindow::WriteSettings(void)
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());