src/drawingview.h \
src/drawcircleaction.h \
src/drawlineaction.h \
+ src/fileio.h \
src/generaltab.h \
src/line.h \
src/main.h \
src/drawingview.cpp \
src/drawcircleaction.cpp \
src/drawlineaction.cpp \
+ src/fileio.cpp \
src/generaltab.cpp \
src/line.cpp \
src/main.cpp \
src/settingsdialog.cpp \
src/vector.cpp
-# src/mainapp/commands.cpp \
-# src/mainapp/createqtactions.cpp \
-# src/mainapp/qc_dialogfactory.cpp \
-# src/mainapp/graphicview.cpp \
-# src/mainapp/mdiwindow.cpp \
-# src/mainapp/settings.cpp
// "<img src=':/res/about-logo.png' style='padding-right:15px; float:left'>"
"<table>"
- "<tr><td align='right' width='120'><b>Architektonas: </b></td><td>Free, <i>Industrial Strength</i> 2D Computer Aided Design</td></tr>"
+ "<tr><td align='right' width='130'><b>Architektonas: </b></td><td>Free, <i>Industrial Strength</i> 2D Computer Aided Design</td></tr>"
"<tr><td align='right'><b>Version: </b></td><td>1.0.0</td></tr>"
"<tr><td align='right'><b>License: </b></td><td>GPL v3 or later</td></tr>"
"<tr><td align='right'><b>Chief Architect: </b></td><td>James Hammons (shamus)</td></tr>"
#include "about.h"
#include "drawingview.h"
+#include "fileio.h"
#include "generaltab.h"
#include "painter.h"
#include "settingsdialog.h"
Object::SetFont(new QFont("Verdana", 15, QFont::Bold));
}
+
void ApplicationWindow::closeEvent(QCloseEvent * event)
{
WriteSettings();
//Do we have a memory leak here if we don't delete the font in the Object???
}
-//void ApplicationWindow::FileOpen(void)
-//{
-//}
+
+void ApplicationWindow::FileNew(void)
+{
+ // Should warn the user if drawing hasn't been saved...
+ drawing->document.Clear();
+ drawing->update();
+ documentName.clear();
+ setWindowTitle("Architektonas - Untitled");
+ statusBar()->showMessage(tr("New drawing is ready."));
+}
+
+
+void ApplicationWindow::FileOpen(void)
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
+ "", tr("Architektonas files (*.drawing)"));
+ FILE * file = fopen(filename.toAscii().data(), "r");
+
+ if (file == 0)
+ {
+ QMessageBox msg;
+ msg.setText(QString(tr("Could not open file \"%1\" for loading!")).arg(filename));
+ msg.setIcon(QMessageBox::Critical);
+ msg.exec();
+ return;
+ }
+
+ Container container(Vector(0, 0));
+ bool successful = FileIO::LoadAtnsFile(file, &container);
+ fclose(file);
+
+ if (!successful)
+ {
+ QMessageBox msg;
+ msg.setText(QString(tr("Could not load file \"%1\"!")).arg(filename));
+ msg.setIcon(QMessageBox::Critical);
+ msg.exec();
+ return;
+ }
+
+ drawing->document = container;
+ drawing->update();
+ documentName = filename;
+ setWindowTitle(QString("Architektonas - %1").arg(documentName));
+ statusBar()->showMessage(tr("Drawing loaded."));
+}
+
+
+void ApplicationWindow::FileSave(void)
+{
+ if (documentName.isEmpty())
+ documentName = QFileDialog::getSaveFileName(this, tr("Save Drawing"),
+ "", tr("Architektonas drawings (*.drawing)"));
+
+ FILE * file = fopen(documentName.toAscii().data(), "w");
+
+ if (file == 0)
+ {
+ QMessageBox msg;
+ msg.setText(QString(tr("Could not open file \"%1\" for saving!")).arg(documentName));
+ msg.setIcon(QMessageBox::Critical);
+ msg.exec();
+ return;
+ }
+
+ bool successful = FileIO::SaveAtnsFile(file, &drawing->document);
+ fclose(file);
+
+ if (!successful)
+ {
+ QMessageBox msg;
+ msg.setText(QString(tr("Could not save file \"%1\"!")).arg(documentName));
+ msg.setIcon(QMessageBox::Critical);
+ msg.exec();
+ // In this case, we should unlink the created file, since it's not right...
+ unlink(documentName.toAscii().data());
+ return;
+ }
+
+ setWindowTitle(QString("Architektonas - %1").arg(documentName));
+ statusBar()->showMessage(tr("Drawing saved."));
+}
+
+
+void ApplicationWindow::FileSaveAs(void)
+{
+ QString filename = QFileDialog::getSaveFileName(this, tr("Save Drawing As"),
+ documentName, tr("Architektonas drawings (*.drawing)"));
+
+ if (!filename.isEmpty())
+ {
+ documentName = filename;
+ FileSave();
+ }
+}
+
void ApplicationWindow::SnapToGridTool(void)
{
Object::SetSnapMode(snapToGridAct->isChecked());
}
+
void ApplicationWindow::FixAngle(void)
{
Object::SetFixedAngle(fixAngleAct->isChecked());
}
+
void ApplicationWindow::FixLength(void)
{
Object::SetFixedLength(fixLengthAct->isChecked());
}
+
// We want certain tools to be exclusive, and this approach isn't working correctly...
void ApplicationWindow::DeleteTool(void)
{
SetInternalToolStates();
}
+
void ApplicationWindow::DimensionTool(void)
{
ClearUIToolStatesExcept(addDimensionAct);
SetInternalToolStates();
}
+
void ApplicationWindow::RotateTool(void)
{
ClearUIToolStatesExcept(rotateAct);
SetInternalToolStates();
}
+
void ApplicationWindow::AddLineTool(void)
{
ClearUIToolStatesExcept(addLineAct);
SetInternalToolStates();
}
+
void ApplicationWindow::AddCircleTool(void)
{
ClearUIToolStatesExcept(addCircleAct);
SetInternalToolStates();
}
+
void ApplicationWindow::AddArcTool(void)
{
ClearUIToolStatesExcept(addArcAct);
SetInternalToolStates();
}
+
void ApplicationWindow::AddPolygonTool(void)
{
ClearUIToolStatesExcept(addPolygonAct);
SetInternalToolStates();
}
+
void ApplicationWindow::ZoomInTool(void)
{
double zoomFactor = 2.0;
drawing->update();
}
+
void ApplicationWindow::ZoomOutTool(void)
{
/*
drawing->update();
}
+
void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
{
if (exception != addArcAct)
rotateAct->setChecked(false);
}
+
void ApplicationWindow::SetInternalToolStates(void)
{
Object::SetDeleteActive(deleteAct->isChecked());
drawing->SetAddCircleToolActive(addCircleAct->isChecked());
}
+
void ApplicationWindow::HelpAbout(void)
{
aboutWin->show();
}
+
void ApplicationWindow::Settings(void)
{
SettingsDialog dlg(this);
WriteSettings();
}
+
+void ApplicationWindow::HandleGrouping(void)
+{
+ // Group a bunch of selected objects together or ungroup a selected group.
+}
+
+
void ApplicationWindow::CreateActions(void)
{
exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool()));
fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n")));
+ connect(fileNewAct, SIGNAL(triggered()), this, SLOT(FileNew()));
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")));
+ connect(fileOpenAct, SIGNAL(triggered()), this, SLOT(FileOpen()));
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")));
+ connect(fileSaveAct, SIGNAL(triggered()), this, SLOT(FileSave()));
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")));
+ connect(fileSaveAsAct, SIGNAL(triggered()), this, SLOT(FileSaveAs()));
fileCloseAct = CreateAction(tr("&Close Drawing"), tr("Close Drawing"), tr("Closes the current drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+w")));
settingsAct = CreateAction(tr("&Settings"), tr("Settings"), tr("Change certain defaults for Architektonas."), QIcon(":/res/generic-tool.png"), QKeySequence());
connect(settingsAct, SIGNAL(triggered()), this, SLOT(Settings()));
+ groupAct = CreateAction(tr("&Group"), tr("Group"), tr("Group/ungroup selected objects."), QIcon(":/res/generic-tool.png"), QKeySequence("g"));
+ connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
+
//Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
// Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
/* QActionGroup * group = new QActionGroup(this);
group->addAction(addArcAct);//*/
}
+
//
// Consolidates action creation from a multi-step process to a single-step one.
//
return action;
}
+
//
// This is essentially the same as the previous function, but this allows more
// than one key sequence to be added as key shortcuts.
return action;
}
+
void ApplicationWindow::CreateMenus(void)
{
QMenu * menu = menuBar()->addMenu(tr("&File"));
menu = menuBar()->addMenu(tr("&Edit"));
menu->addAction(snapToGridAct);
+ menu->addAction(groupAct);
menu->addAction(fixAngleAct);
menu->addAction(fixLengthAct);
menu->addAction(rotateAct);
menu->addAction(aboutAct);
}
+
void ApplicationWindow::CreateToolbars(void)
{
QToolBar * toolbar = addToolBar(tr("File"));
toolbar = addToolBar(tr("Edit"));
toolbar->addAction(snapToGridAct);
+ toolbar->addAction(groupAct);
toolbar->addAction(fixAngleAct);
toolbar->addAction(fixLengthAct);
toolbar->addAction(rotateAct);
toolbar->addAction(addDimensionAct);
}
+
void ApplicationWindow::ReadSettings(void)
{
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
// ((TTEdit *)qApp)->charWnd->move(pos);
}
+
void ApplicationWindow::WriteSettings(void)
{
settings.setValue("pos", pos());
// settings.setValue("charWndPos", ((TTEdit *)qApp)->charWnd->pos());
// settings.setValue("charWndSize", ((TTEdit *)qApp)->charWnd->size());
}
+
void closeEvent(QCloseEvent * event);
private slots:
-// void FileOpen();
+ void FileNew(void);
+ void FileOpen(void);
+ void FileSave(void);
+ void FileSaveAs(void);
void SnapToGridTool(void);
void FixAngle(void);
void FixLength(void);
void ZoomOutTool(void);
void HelpAbout(void);
void Settings(void);
+ void HandleGrouping(void);
private:
void ClearUIToolStatesExcept(QAction *);
DrawingView * drawing;
AboutWindow * aboutWin;
QLabel * zoomIndicator;
+ QString documentName;
QSettings settings;
QAction * zoomInAct;
QAction * zoomOutAct;
QAction * snapToGridAct;
+ QAction * groupAct;
};
#endif // __APPLICATIONWINDOW_H__
// Draw the center point of the arc
painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
- painter->DrawEllipse(position, 4.0, 4.0);
+ painter->DrawHandle(position);
// Draw the rotation & span setting handles
- painter->DrawEllipse(handle2, 4.0, 4.0);
- painter->DrawEllipse(handle3, 4.0, 4.0);
+ painter->DrawHandle(handle2);
+ painter->DrawHandle(handle3);
// If we're rotating or setting the span, draw an information panel
// showing both absolute and relative angles being set.
double relAngle = (startAngle >= oldAngle ? startAngle - oldAngle :
startAngle - oldAngle + (2.0 * PI)) * RADIANS_TO_DEGREES;
-// painter->save();
-//close, but no cigar. we need to "invert" our transformation to make this work properly
-// return QPoint(-offsetX + x, (size().height() - (-offsetY + y)) * +1.0);
-// painter->translate(0, viewportHeight);
-// painter->scale(1.0, -1.0);
-// Give up for now; just paint the info panel in the upper left corner of the screen
-// painter->resetTransform();
QString text;
if (hitHandle2)
pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
painter->SetPen(pen);
painter->SetBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
- QRectF textRect(10.0, 10.0, 220.0, 60.0); // x, y, w, h
+ QRectF textRect(10.0, 10.0, 260.0, 60.0); // x, y, w, h
painter->DrawRoundedRect(textRect, 7.0, 7.0);
textRect.setLeft(textRect.left() + 14);
pen = QPen(QColor(0xDF, 0x5F, 0x00), 1.0, Qt::SolidLine);
painter->SetPen(pen);
painter->DrawText(textRect, Qt::AlignVCenter, text);
-// painter->Restore();
}
-
-// painter->setPen(QPen(Qt::red, 2.0, Qt::DotLine));
}
else
{
painter->SetPen(pen);
}
-#if 0
- QRectF rectangle(QPointF(position.x - radius, position.y - radius),
- QPointF(position.x + radius, position.y + radius));
- int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
- int angle2 = (int)(angleSpan * RADIANS_TO_DEGREES * 16.0);
- painter->DrawArc(rectangle, -angle1, -angle2);
-#else
painter->DrawArc(position, radius, startAngle, angleSpan);
-#endif
}
/*virtual*/ Vector Arc::Center(void)
{
}
+
+// Copy constructor
+Container::Container(const Container & copy): Object(copy.position, copy.parent)
+{
+ // Use overloaded assignment operator
+ *this = copy;
+}
+
+
Container::~Container()
{
+#if 0
// No memory leaks!
while (objects.size() > 0)
{
delete objects[0];
objects.erase(objects.begin());
}
+#else
+ Clear();
+#endif
}
+
+// Assignment operator
+Container & Container::operator=(const Container & copy)
+{
+ // Take care of self-assignment
+ if (this == ©)
+ return *this;
+
+ Clear();
+
+ for(int i=0; i<(int)copy.objects.size(); i++)
+ objects.push_back(copy.objects[i]);
+
+ return *this;
+}
+
+
/*virtual*/ void Container::Draw(Painter * painter)
{
for(int i=0; i<(int)objects.size(); i++)
objects[i]->Draw(painter);
}
+
/*virtual*/ Vector Container::Center(void)
{
return position;
Also: should put the snap logic into the Object base class (as a static method)...
*/
+
/*virtual*/ bool Container::Collided(Vector point)
{
objectWasDragged = false;
return collision;
}
+
// The TLC is passing all mouse movement here, so we're doing the same here.
// Need to adjust all other objects to handle things correctly.
+
// One optimization that will need to be done eventually is to subdivide the screen
// into parts and keep subdividing until an acceptable number of objects lie within
// the slice. This way, the GUI will still be responsive and *not* have to test
// needUpdate = false;
}
+
/*virtual*/ void Container::PointerReleased(void)
{
dragging = false;
objects[i]->PointerReleased();
}
+
/*virtual*/ bool Container::NeedsUpdate(void)
{
needUpdate = false;
return needUpdate;
}
+
/*virtual*/ void Container::Add(Object * object)
{
objects.push_back(object);
}
+
+
+void Container::Clear(void)
+{
+ // No memory leaks!
+ while (objects.size() > 0)
+ {
+ delete objects[0];
+ objects.erase(objects.begin());
+ }
+}
class Container: public Object
{
public:
+// Container(void);
Container(Vector, Object * p = 0);
+ Container(const Container &);
~Container();
+ Container & operator=(const Container &);
virtual void Draw(Painter *);
virtual Vector Center(void);
virtual bool Collided(Vector);
virtual void PointerReleased(void);
virtual bool NeedsUpdate(void);
virtual void Add(Object *);
+ void Clear(void);
protected:
Vector oldPoint; // Used for dragging
#include "painter.h"
-Dimension::Dimension(Vector p1, Vector p2, Object * p/*= NULL*/): Object(p1, p), endpoint(p2),
+Dimension::Dimension(Vector p1, Vector p2, DimensionType dt/*= DTLinear*/ ,Object * p/*= NULL*/):
+ Object(p1, p), endpoint(p2),
dragging(false), draggingHandle1(false), draggingHandle2(false),
- length(p2.Magnitude()), point1(NULL), point2(NULL)
+ length(p2.Magnitude()), type(dt), point1(NULL), point2(NULL)
{
}
// This is bad, p1 & p2 could be NULL, causing much consternation...
-Dimension::Dimension(Vector * p1, Vector * p2, Object * p/*= NULL*/): Object(*p1, p), endpoint(*p2),
+Dimension::Dimension(Vector * p1, Vector * p2, DimensionType dt/*= DTLinear*/ , Object * p/*= NULL*/):
+ Object(*p1, p), endpoint(*p2),
dragging(false), draggingHandle1(false), draggingHandle2(false),
- length(p2->Magnitude()), point1(p1), point2(p2)
+ length(p2->Magnitude()), type(dt), point1(p1), point2(p2)
{
}
#include "object.h"
+enum DimensionType { DTLinear, DTRadial, DTDiametric, DTCircumferential, DTLeader };
+
class Dimension: public Object
{
public:
- Dimension(Vector, Vector, Object * p = 0);
- Dimension(Vector *, Vector *, Object * p = 0);
+ Dimension(Vector, Vector, DimensionType dt = DTLinear, Object * p = 0);
+ Dimension(Vector *, Vector *, DimensionType dt = DTLinear, Object * p = 0);
~Dimension();
virtual void Draw(Painter *);
bool draggingHandle2;
bool objectWasDragged;
double length;
+ DimensionType type;
Vector * point1; // These couple to external points; if there
Vector * point2; // are none then fall back to endpoint/position
document.Add(new Arc(Vector(300, 300), 32, PI / 4.0, PI * 1.3, &document)),
document.Add(new Arc(Vector(200, 200), 60, PI / 2.0, PI * 1.5, &document));
#if 1
- Dimension * dimension = new Dimension(Vector(0, 0), Vector(0, 0), &document);
+ Dimension * dimension = new Dimension(Vector(0, 0), Vector(0, 0), DTLinear, &document);
line->SetDimensionOnLine(dimension);
document.Add(dimension);
#else
painter.DrawLine(-16384, 0, 16384, 0);
// Draw supplemental (tool related) points
-
+// NOTE that this can be done as an action!
+// In that case, we would need access to the document...
if (rotateTool)
{
painter.SetPen(QPen(QColor(0, 200, 0), 2.0, Qt::SolidLine));
QPixmap gridBackground;
double scale; // Window scaling factor
int32_t offsetX, offsetY; // Window offsets
- Container document;
public:
+ Container document;
double gridSpacing;
private:
bool collided;
--- /dev/null
+//
+// fileio.cpp: Architektonas file save/load support
+//
+// Part of the Architektonas Project
+// (C) 2013 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- -------------------------------------------------------------
+// JLH 02/20/2013 Created this file
+//
+
+#include "fileio.h"
+
+//#include <stdio.h>
+#include <stdlib.h>
+#include "container.h"
+
+
+/*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * object)
+{
+// QString filename2 = QFileDialog::getSaveFileName(NULL, tr("Save Drawing"),
+// "", tr("Architektonas files (*.drawing)"));
+
+ return false;
+}
+
+
+/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * object)
+{
+// QString filename2 = QFileDialog::getOpenFileName(NULL, tr("Open Drawing"),
+// "", tr("Architektonas files (*.drawing)"));
+
+ return false;
+}
+
+
--- /dev/null
+#ifndef __FILEIO_H__
+#define __FILEIO_H__
+
+#include <stdio.h>
+
+class Container;
+
+// NB: The methods in this class are all static, so there's no need to
+// instantiate an object of this type to use its functions.
+
+class FileIO
+{
+ public:
+ static bool SaveAtnsFile(FILE *, Container *);
+ static bool LoadAtnsFile(FILE *, Container *);
+};
+
+#endif // __FILEIO_H__
+
But we can fix that by making this object call any attached object's (like
a dimension only) Draw() function... :-/
*/
- attachedDimension = new Dimension(&position, &endpoint, this);
+ attachedDimension = new Dimension(&position, &endpoint, DTLinear, this);
if (parent != NULL)
parent->Add(attachedDimension);
// If they don't pass one in, create it for the caller.
if (dimension == NULL)
{
- dimension = new Dimension(&position, &endpoint, this);
+ dimension = new Dimension(&position, &endpoint, DTLinear, this);
if (parent)
parent->Add(dimension);