- Dimension offsets work well now.
- Add pen stamp button, to stamp pen attributes on selected items.
- Fix std::vector references to use a typedef (VPVector for
std::vector<void *>, etc.) in order to make the code easier to read &
understand; vector iterators too.
- Add ability to select all objects.
- Adding to selection while holding down CTRL with selection rectangle
works, deselect objects with single clicks as well.
+
Stuff To Be Implemented/Fixed
-----------------------------
- Add Spline
- Add Text
- Object connections (two types: flexible and rigid)
- - Group selection (kinda done, needs more work though)
- - Take movement code out of Objects and put it into top level Container
- (actually I think this should be more of the state code handling. Have to
- see.)
- Add OSD to Object creation
- Add blocks
- Add page layout
Stuff That's Done
-----------------
+ - Group selection (kinda done, needs more work though) [Shamus 2020]
+ - Take movement code out of Objects and put it into top level Container
+ (actually I think this should be more of the state code handling. Have to
+ see.) [Shamus 2015ish, whenever C++ OO was ditched]
- Add layers [Shamus 2015ish]
- Add pen color/style/width to Objects [Shamus 2017ish]
- Fix loading and saving code [Shamus 2016ish]
- Mirror tool (started, needs actual mirroring implementation) (Rotate tool is
also done :-D) [Shamus 2013-09-01]
-
<file>editcut2.png</file>
<file>editcopy2.png</file>
<file>editpaste2.png</file>
+ <file>pen-stamp.png</file>
</qresource>
</RCC>
void ApplicationWindow::HandleDimensionSize(QString text)
{
/*
-This is the third input on the view toolbar; not sure what it was supposed to do...
+This is the third input on the view toolbar; not sure what it was supposed to do... (resize all dimensions in the drawing?)
*/
// Parse the text...
bool ok;
if (drawing->select.size() > 0)
{
DeleteContents(clipboard);
- CopySelectedObjectsTo(clipboard, drawing->document.objects);
+ clipboard = CopySelectedObjects(drawing->document.objects);
}
}
if (drawing->select.size() > 0)
{
DeleteContents(clipboard);
- MoveSelectedObjectsTo(clipboard, drawing->document.objects);
+ clipboard = MoveSelectedObjectsFrom(drawing->document.objects);
drawing->update();
}
}
if (clipboard.size() > 0)
{
// We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state...
- // This only moves the cut/copied from the clipboard to the drawing.
-// AddObjectsTo(drawing->document.objects, clipboard);
- CopyObjects(clipboard, drawing->document.objects);
+ ClearSelected(drawing->document.objects);
+ SelectAll(clipboard);
+ drawing->document.Add(CopyObjects(clipboard));
drawing->update();
}
}
+//
+// Select all *visible* objects. If an object is on a layer that is not
+// visible, skip it.
+//
+void ApplicationWindow::SelectAllObjects(void)
+{
+ // Set object's state & update the drawing
+ SelectAll(drawing->document.objects);
+ drawing->update();
+}
+
+
void ApplicationWindow::CreateActions(void)
{
exitAct = CreateAction(tr("&Quit"), tr("Quit"), tr("Exits the application."),
editPasteAct = CreateAction(tr("&Paste Objects"), tr("Paste Objects"), tr("Paste objects from the clipboard to the drawing."), QIcon(":/res/editpaste2.png"), QKeySequence(tr("Ctrl+v")));
connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste()));
+ selectAllAct = CreateAction(tr("Select &All"), tr("Select All Objects"), tr("Select all objects in the drawing."), QIcon(), QKeySequence(tr("Ctrl+a")));
+ connect(selectAllAct, SIGNAL(triggered()), this, SLOT(SelectAllObjects()));
+
//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);
menu->addAction(connectAct);
menu->addAction(disconnectAct);
menu->addSeparator();
+ menu->addAction(selectAllAct);
menu->addAction(editCutAct);
menu->addAction(editCopyAct);
menu->addAction(editPasteAct);
connect(pw, SIGNAL(WidthSelected(float)), drawing, SLOT(HandlePenWidth(float)));
connect(pw, SIGNAL(StyleSelected(int)), drawing, SLOT(HandlePenStyle(int)));
connect(pw, SIGNAL(ColorSelected(uint32_t)), drawing, SLOT(HandlePenColor(uint32_t)));
+ connect(pw, SIGNAL(StampSelected(void)), drawing, SLOT(HandlePenStamp(void)));
}
void EditCut(void);
void EditCopy(void);
void EditPaste(void);
+ void SelectAllObjects(void);
signals:
void ReloadLayers(void);
QAction * editCutAct;
QAction * editCopyAct;
QAction * editPasteAct;
+ QAction * selectAllAct;
std::vector<void *> clipboard;
DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
// The value in the settings file will override this.
- useAntialiasing(true), /*numSelected(0),*/ numHovered(0), shiftDown(false),
+ useAntialiasing(true), numHovered(0), shiftDown(false),
ctrlDown(false), altDown(false),
gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
scale(1.0), offsetX(-10), offsetY(-10), document(true),
void DrawingView::DeleteCurrentLayer(int layer)
{
//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
- std::vector<void *>::iterator i = document.objects.begin();
+ VPVectorIter i = document.objects.begin();
while (i != document.objects.end())
{
//
void DrawingView::HandleLayerSwap(int layer1, int layer2)
{
+// !!! FIX !!! This doesn't properly handle container contents...
//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2);
- std::vector<void *>::iterator i;
-
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
Object * obj = (Object *)(*i);
void DrawingView::HandlePenWidth(float width)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->thickness = width;
void DrawingView::HandlePenStyle(int style)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->style = style;
void DrawingView::HandlePenColor(uint32_t color)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->color = color;
}
+void DrawingView::HandlePenStamp(void)
+{
+ VPVector flat = Flatten(select);
+
+ for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
+ {
+ Object * obj = (Object *)(*i);
+
+ if (obj->type != OTText)
+ obj->thickness = Global::penWidth;
+
+ obj->style = Global::penStyle;
+ obj->color = Global::penColor;
+ }
+
+ update();
+}
+
+
QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
{
// This is undoing the transform, e.g. going from client coords to local
!!! FIX !!!
[Well, it seems to work OK *except* when you move one of the points, then you get to see nothing. Is it worth fixing there to get rid of problems here? Have to investigate...]
*/
-void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int layer, bool ignoreLayer/*= false*/)
+void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool ignoreLayer/*= false*/)
{
- std::vector<void *>::iterator i;
-
- for(i=v.begin(); i!=v.end(); i++)
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
{
Object * obj = (Object *)(*i);
float scaledThickness = Global::scale * obj->thickness;
unit = Vector(d->lp[0], d->lp[1]).Unit();
- Point p1 = d->lp[0] + (ortho * (10.0 + d->offset) * scaledThickness);
- Point p2 = d->lp[1] + (ortho * (10.0 + d->offset) * scaledThickness);
- Point p3 = d->lp[0] + (ortho * (16.0 + d->offset) * scaledThickness);
- Point p4 = d->lp[1] + (ortho * (16.0 + d->offset) * scaledThickness);
+ Point p1 = d->lp[0] + (ortho * (d->offset + (10.0 * scaledThickness)));
+ Point p2 = d->lp[1] + (ortho * (d->offset + (10.0 * scaledThickness)));
+ Point p3 = d->lp[0] + (ortho * (d->offset + (16.0 * scaledThickness)));
+ Point p4 = d->lp[1] + (ortho * (d->offset + (16.0 * scaledThickness)));
Point p5 = d->p[0] + (ortho * 4.0 * scaledThickness);
Point p6 = d->p[1] + (ortho * 4.0 * scaledThickness);
dimText = QString("%1' %2\"").arg(feet).arg(inches);
}
+/*
+Where is the text offset? It looks like it's drawing in the center, but obviously it isn't. It isn't here, it's in Painter::DrawAngledText().
+*/
painter->DrawAngledText(ctr, angle, dimText, scaledThickness);
if (d->hitObject)
}
+//
+// This toggles the selection being hovered (typically, only 1 object)
+//
void DrawingView::AddHoveredToSelection(void)
{
- std::vector<void *>::iterator i;
-
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->hovered)
- ((Object *)(*i))->selected = true;
+// ((Object *)(*i))->selected = true;
+ ((Object *)(*i))->selected = !((Object *)(*i))->selected;
}
}
-void DrawingView::GetSelection(std::vector<void *> & v)
+void DrawingView::GetSelection(VPVector & v)
{
v.clear();
- std::vector<void *>::iterator i;
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->selected)
v.push_back(*i);
}
-#if 0
-void DrawingView::GetHovered(std::vector<void *> & v)
+VPVector DrawingView::GetSelection(void)
{
- v.clear();
- std::vector<void *>::iterator i;
+ VPVector v;
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
- if (((Object *)(*i))->hovered)
-// {
-//printf("GetHovered: adding object (%X) to hover... hp1=%s, hp2=%s, hl=%s\n", (*i), (((Line *)(*i))->hitPoint[0] ? "true" : "false"), (((Line *)(*i))->hitPoint[1] ? "true" : "false"), (((Line *)(*i))->hitObject ? "true" : "false"));
+ if (((Object *)(*i))->selected)
v.push_back(*i);
-// }
}
+
+ return v;
}
-#endif
-std::vector<void *> DrawingView::GetHovered(void)
+VPVector DrawingView::GetHovered(void)
{
- std::vector<void *> v;
- std::vector<void *>::iterator i;
+ VPVector v;
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->hovered)
-// {
-//printf("GetHovered: adding object (%X) to hover... hp1=%s, hp2=%s, hl=%s\n", (*i), (((Line *)(*i))->hitPoint[0] ? "true" : "false"), (((Line *)(*i))->hitPoint[1] ? "true" : "false"), (((Line *)(*i))->hitObject ? "true" : "false"));
v.push_back(*i);
-// }
}
return v;
angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
- std::vector<void *>::iterator j = select.begin();
+ VPVectorIter j = select.begin();
// std::vector<Object>::iterator i = toolScratch.begin();
- std::vector<void *>::iterator i = toolScratch2.begin();
+ VPVectorIter i = toolScratch2.begin();
// for(; i!=toolScratch.end(); i++, j++)
for(; i!=toolScratch2.end(); i++, j++)
// Container * c = (Container *)&objT;
Container * c = (Container *)objT;
Container * c2 = (Container *)objS;
- std::vector<void *>::iterator l = c->objects.begin();
+ VPVectorIter l = c->objects.begin();
// TODO: Rotate items in the container
// TODO: Make this recursive
- for(std::vector<void *>::iterator k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
+ for(VPVectorIter k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
{
Object * obj3 = (Object *)(*k);
Object * obj4 = (Object *)(*l);
if (ctrlDown)
{
// Stamp a copy of the selection at the current rotation & bail
- std::vector<void *> temp;
+ VPVector temp;
CopyObjects(select, temp);
ClearSelected(temp);
AddObjectsTo(document.objects, temp);
angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
- std::vector<void *>::iterator j = select.begin();
+ VPVectorIter j = select.begin();
std::vector<Object>::iterator i = toolScratch.begin();
for(; i!=toolScratch.end(); i++, j++)
if (ctrlDown)
{
// Stamp a copy of the selection at the current rotation & bail
- std::vector<void *> temp;
+ VPVector temp;
CopyObjects(select, temp);
ClearSelected(temp);
AddObjectsTo(document.objects, temp);
if (numHovered != 1)
break;
- std::vector<void *> hover = GetHovered();
+ VPVector hover = GetHovered();
Object * obj = (Object *)hover[0];
// Skip if it's not a line...
return;
}
- std::vector<void *> hover = GetHovered();
+ VPVector hover = GetHovered();
Object * obj = (Object *)hover[0];
// Skip if it's not a line...
// Currently only deal with line against line trimming, can expand to
// others as well (line/circle, circle/circle, line/arc, etc)
- std::vector<void *>::iterator i;
+ VPVectorIter i;
for(i=document.objects.begin(); i!=document.objects.end(); i++)
{
obj = (Object *)(*i);
{
if (event->button() == Qt::LeftButton)
{
-printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
+//printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
// Handle tool processing, if any
AddHoveredToSelection();
update(); // needed??
// GetHovered(hover); // prolly needed
- std::vector<void *> hover2 = GetHovered();
+ VPVector hover2 = GetHovered();
dragged = (Object *)hover2[0];
draggingObject = true;
-printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
+//printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
// Alert the pen widget
emit ObjectSelected(dragged);
return;
}
- // Didn't hit any object and not using a tool, so do a selection rectangle
+ // Didn't hit any object and not using a tool, so do a selection
+ // rectangle
Global::selectionInProgress = true;
Global::selection.setTopLeft(QPointF(point.x, point.y));
Global::selection.setBottomRight(QPointF(point.x, point.y));
+ select = GetSelection();
}
else if (event->button() == Qt::MiddleButton)
{
if (Global::selectionInProgress)
{
CheckObjectBounds();
+
+ // Make sure previously selected objects stay selected (CTRL held)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
+ ((Object *)(*i))->selected = true;
+
update();
return;
}
// Do object hit testing...
bool needUpdate = HitTestObjects(point);
-// GetHovered(hover);
- std::vector<void *> hover2 = GetHovered();
+ VPVector hover2 = GetHovered();
+#if 0
{
if (needUpdate)
{
printf(" (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]);
}
}
+#endif
// Check for multi-hover...
if (numHovered > 1)
return;
}
- if (Global::selectionInProgress)
+// if (Global::selectionInProgress)
Global::selectionInProgress = false;
informativeText.clear();
// Should we be doing this automagically? Hmm...
// Clear our vectors
- select.clear();
-// hover.clear();
-
- // Scoop 'em up
- std::vector<void *>::iterator i;
+// select.clear();
+//// hover.clear();
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
- {
- if (((Object *)(*i))->selected)
- select.push_back(*i);
- }
+ // Scoop 'em up (do we need to??? Seems we do, because keyboard movement uses it. Also, tools use it too. But we can move it out of here)
+ select = GetSelection();
draggingObject = false;
}
// This is not centering for some reason. Need to figure out why. :-/
if (event->delta() > 0)
{
+ if (Global::zoom > 20.0)
+ return;
+
Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
Global::origin = newOrigin;
Global::zoom *= zoomFactor;
}
else
{
+ if (Global::zoom < 0.25)
+ return;
+
Vector newOrigin = center + ((-center + Global::origin) * zoomFactor);
Global::origin = newOrigin;
Global::zoom /= zoomFactor;
else if (event->key() == Qt::Key_Alt)
altDown = true;
+ // If there's a change in any of the modifier key states, pass it on to
+ // the current tool's handler
if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
{
if (Global::tool)
case OTContainer:
{
Container * c = (Container *)obj;
- std::vector<void *>::iterator i = c->objects.begin();
+ VPVectorIter i = c->objects.begin();
rect = GetObjectExtents((Object *)*i);
i++;
void DrawingView::CheckObjectBounds(void)
{
- std::vector<void *>::iterator i;
+ VPVectorIter i;
for(i=document.objects.begin(); i!=document.objects.end(); i++)
{
bool DrawingView::HitTestObjects(Point point)
{
- std::vector<void *>::iterator i;
+ VPVectorIter i;
numHovered = 0;
bool needUpdate = false;
hoverPointValid = false;
Vector orthogonal = Vector::Normal(d->lp[0], d->lp[1]);
// Get our line parallel to our points
float scaledThickness = Global::scale * obj->thickness;
+#if 1
+ Point p1 = d->lp[0] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+ Point p2 = d->lp[1] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+#else
Point p1 = d->lp[0] + (orthogonal * (10.0 + d->offset) * scaledThickness);
Point p2 = d->lp[1] + (orthogonal * (10.0 + d->offset) * scaledThickness);
+#endif
Point p3(p1, point);
Vector v1(d->p[0], point);
likely we can just rely on the object itself and steal its state like we have in the commented out portion below; can prolly rewrite the HitTest() portion to be one line: needUpdate = HitTest(cObj, point);
Well, you could if there was only one object in the Container. But since there isn't, we have to keep the if HitTest() == true then needUpdate = true bit. Because otherwise, a false result anywhere will kill the needed update elsewhere.
*/
-
Container * c = (Container *)obj;
c->hitObject = false;
c->hovered = false;
c->clicked = NULL;
- std::vector<void *> flat = Flatten(c);
+ VPVector flat = Flatten(c);
//printf("HitTest::OTContainer (size=%li)\n", flat.size());
- for(std::vector<void *>::iterator i=flat.begin(); i!=flat.end(); i++)
+ for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
{
Object * cObj = (Object *)(*i);
c->clicked = cObj;
}//*/
+ if (cObj->hitPoint[2] == true)
+ {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
+ c->hitPoint[2] = true;
+ c->clicked = cObj;
+ }//*/
+
if (cObj->hovered == true)
c->hovered = true;//*/
}
obj->p[1] = point;
else if (obj->hitObject)
{
- obj->p[0] += delta;
- obj->p[1] += delta;
+ // Move measurement lines in/out
+ if (shiftDown)
+ {
+ Dimension * d = (Dimension *)obj;
+ double dist = Geometry::DistanceToLineFromPoint(d->lp[0], d->lp[1], point);
+ float scaledThickness = Global::scale * obj->thickness;
+ // Looks like offset is 0 to +MAX, but line is at 10.0. So
+ // anything less than 10.0 should set the offset to 0.
+ d->offset = 0;
+
+ if (dist > (10.0 * scaledThickness))
+ d->offset = dist - (10.0 * scaledThickness);
+ }
+ else
+ {
+ obj->p[0] += delta;
+ obj->p[1] += delta;
+ }
}
break;
void UpdateGridBackground(void);
Point SnapPointToGrid(Point);
Point SnapPointToAngle(Point);
- void RenderObjects(Painter *, std::vector<void *> &, int, bool ignoreLayer = false);
+ void RenderObjects(Painter *, VPVector &, int, bool ignoreLayer = false);
void AddHoveredToSelection(void);
- void GetSelection(std::vector<void *> &);
-// void GetHovered(std::vector<void *> &);
- std::vector<void *> GetHovered(void);
+ void GetSelection(VPVector &);
+ VPVector GetSelection(void);
+ VPVector GetHovered(void);
void ToolHandler(int, Point);
void ToolDraw(Painter *);
void LineHandler(int, Point);
void HandlePenWidth(float);
void HandlePenStyle(int);
void HandlePenColor(uint32_t);
+ void HandlePenStamp(void);
signals:
void ObjectHovered(Object *);
QString informativeText;
public:
- std::vector<void *> select;
-// std::vector<void *> hover;
- std::vector<void *> toolObjects;
+ VPVector select;
+ VPVector toolObjects;
std::vector<Object> toolScratch;
- std::vector<void *> toolScratch2;
+ VPVector toolScratch2;
Point toolPoint[32];
Object * toolObj[32];
Point intersectionPoint;
}
+double Geometry::DistanceToLineFromPoint(Point tail, Point head, Point point)
+{
+ // Interpretation: given a line in the form x = a + tu, where u is the
+ // unit vector of the line, a is the tail and t is a parameter which
+ // describes the line, the distance of a point p to the line is given by:
+ // || (a - p) - ((a - p) . u) u ||
+ // We go an extra step: we set the sign to reflect which side of the line
+ // it's on (+ == to the left if head points away from you, - == to the
+ // right)
+ Vector line(tail, head);
+ Vector u = line.Unit();
+ Vector a_p = tail - point;
+ Vector dist = a_p - (u * (a_p).Dot(u));
+
+ double angle = Vector::Angle(tail, point) - line.Angle();
+
+ if (angle < 0)
+ angle += TAU;
+
+ return dist.Magnitude() * (angle < HALF_TAU ? +1.0 : -1.0);
+}
+
+
Point Geometry::MirrorPointAroundLine(Point point, Point tail, Point head)
{
// Get the vector of the intersection of the line and the normal on the
public:
// All methods are class methods for this class
static double ParameterOfLineAndPoint(Point, Point, Point);
+ static double DistanceToLineFromPoint(Point, Point, Point);
static Point MirrorPointAroundLine(Point, Point, Point);
static Point RotatePointAroundPoint(Point, Point, double);
static double Determinant(Point, Point);
int Global::activeLayer = 0;
int Global::numLayers = 1;
-std::vector<bool> Global::layerHidden;
-std::vector<bool> Global::layerLocked;
-std::vector<std::string> Global::layerName;
+BVector Global::layerHidden;
+BVector Global::layerLocked;
+SVector Global::layerName;
enum LineStyle { LSNone, LSSolid, LSDash, LSDot, LSDashDot, LSDashDotDot };
+typedef std::vector<void *> VPVector;
+typedef std::vector<void *>::iterator VPVectorIter;
+typedef std::vector<bool> BVector;
+typedef std::vector<std::string> SVector;
class Global
{
static int activeLayer;
static int numLayers;
- static std::vector<bool> layerHidden;
- static std::vector<bool> layerLocked;
- static std::vector<std::string> layerName;
+ static BVector layerHidden;
+ static BVector layerLocked;
+ static SVector layerName;
};
#endif // __GLOBALS_H__
// Need to figure out if dimensions are always rendered at one size
// regardless of zoom, or if they have a definite size, and are thus
// zoomable.
- float yOffset = -12.0 * Global::zoom * size;
+// float yOffset = -12.0 * Global::zoom * size;
+ float yOffset = -8.0 * Global::zoom * size;
// Fix text so it isn't upside down...
if ((angle > QTR_TAU) && (angle < THREE_QTR_TAU))
{
angle += HALF_TAU;
- yOffset = 12.0 * Global::zoom * size;
+// yOffset = 12.0 * Global::zoom * size;
+ yOffset = 8.0 * Global::zoom * size;
}
textBox.translate(0, yOffset);
QLabel * l1 = new QLabel(tr("Width:"));
QLabel * l2 = new QLabel(tr("RGB:"));
QLabel * l3 = new QLabel(tr("Style:"));
+ QToolButton * qtb = new QToolButton(this);
+
+ QAction * action = new QAction(QIcon(":/res/pen-stamp.png"), tr(""), this);
+ action->setToolTip(tr("Stamp Selected"));
+ action->setStatusTip(tr("Stamp selected objects with pen attributes."));
+ action->setShortcut(QKeySequence(tr("p,p")));
+// action->setCheckable(checkable);
+ qtb->setDefaultAction(action);
style->insertItem(1, tr("Solid"));
style->insertItem(2, tr("Dash"));
hbox1->addWidget(blue, 0, Qt::AlignLeft);
hbox1->addWidget(l3, 0, Qt::AlignLeft);
hbox1->addWidget(style, 0, Qt::AlignLeft);
+ hbox1->addWidget(qtb, 0, Qt::AlignLeft);
hbox1->addStretch(1);
setLayout(hbox1);
connect(green, SIGNAL(textEdited(QString)), this, SLOT(HandleGreenSelected(QString)));
connect(blue, SIGNAL(textEdited(QString)), this, SLOT(HandleBlueSelected(QString)));
connect(style, SIGNAL(currentIndexChanged(int)), this, SLOT(HandleStyleSelected(int)));
+ connect(qtb, SIGNAL(triggered(QAction *)), this, SLOT(HandleStamp(QAction *)));
}
emit ColorSelected(Global::penColor);
}
+
+void PenWidget::HandleStamp(QAction * /* action */)
+{
+ emit StampSelected();
+}
+
void HandleRedSelected(QString);
void HandleGreenSelected(QString);
void HandleBlueSelected(QString);
+ void HandleStamp(QAction *);
signals:
void WidthSelected(float);
void StyleSelected(int);
void ColorSelected(uint32_t);
+ void StampSelected(void);
private:
QLineEdit * width;
struct Container {
OBJECT_COMMON;
- std::vector<void *> objects;
+ VPVector objects;
double scale;
bool topLevel;
Object * clicked;
Container(bool tl = false): type(OTContainer), id(Global::objectID++), selected(false), hovered(false), hitObject(false), topLevel(tl), clicked(NULL) {}
void Add(void * obj) { objects.push_back(obj); }
+ void Add(VPVector objs) { objects.insert(objects.end(), objs.begin(), objs.end()); }
// void DeleteContents(void) {}
/* void DeleteContents(Container * c)
{
//
#include "utils.h"
+#include <math.h>
#include <string.h> // For memcpy()
#include "geometry.h"
// Copy objects in one vector to another, creating copies and placing them in
// the other vector. Clearing & etc. of vectors is responsibility of the caller!
//
-void CopyObjects(std::vector<void *> & from, std::vector<void *> & to)
+void CopyObjects(VPVector & from, VPVector & to)
{
- for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
+ for(VPVectorIter i=from.begin(); i!=from.end(); i++)
{
Object * obj = (Object *)(*i);
Object * newObject = CopyObject(obj);
}
+VPVector CopyObjects(VPVector & src)
+{
+ VPVector copy;
+
+ for(VPVectorIter i=src.begin(); i!=src.end(); i++)
+ {
+ Object * newObject = CopyObject2((Object *)(*i));
+ copy.push_back(newObject);
+ }
+
+ return copy;
+}
+
+
//
// Create a copy of the passed in object.
//
newObject = new Dimension();
memcpy(newObject, obj, sizeof(Dimension));
break;
-#if 0
case OTSpline:
newObject = new Spline();
memcpy(newObject, obj, sizeof(Spline));
break;
-#endif
case OTText:
newObject = new Text();
memcpy(newObject, obj, sizeof(Text));
// memcpy(newObject, obj, sizeof(Line));
((Container *)newObject)->p[0] = obj->p[0];
((Container *)newObject)->p[1] = obj->p[1];
+ ((Container *)newObject)->layer = obj->layer;
CopyObjects(((Container *)obj)->objects, ((Container *)newObject)->objects);
break;
default:
}
-void MoveSelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+//
+// Create a copy of the passed in object. This version calls the second
+// version of CopyObjects() (with one parameter and a vector return value).
+//
+Object * CopyObject2(Object * obj)
+{
+ void * newObject = NULL;
+
+ switch (obj->type)
+ {
+ case OTLine:
+ newObject = new Line();
+ memcpy(newObject, obj, sizeof(Line));
+ break;
+
+ case OTCircle:
+ newObject = new Circle();
+ memcpy(newObject, obj, sizeof(Circle));
+ break;
+
+ case OTEllipse:
+ newObject = new Ellipse();
+ memcpy(newObject, obj, sizeof(Ellipse));
+ break;
+
+ case OTArc:
+ newObject = new Arc();
+ memcpy(newObject, obj, sizeof(Arc));
+ break;
+
+ case OTDimension:
+ newObject = new Dimension();
+ memcpy(newObject, obj, sizeof(Dimension));
+ break;
+
+ case OTSpline:
+ newObject = new Spline();
+ memcpy(newObject, obj, sizeof(Spline));
+ break;
+
+ case OTText:
+ newObject = new Text();
+ memcpy(newObject, obj, sizeof(Text));
+ ((Text *)newObject)->s = ((Text *)obj)->s;
+ break;
+
+ case OTContainer:
+ newObject = new Container();
+ ((Container *)newObject)->p[0] = obj->p[0];
+ ((Container *)newObject)->p[1] = obj->p[1];
+ ((Container *)newObject)->layer = obj->layer;
+ ((Container *)newObject)->objects = CopyObjects(((Container *)obj)->objects);
+ break;
+ }
+
+ // Fix objectID
+ if (newObject && (((Object *)newObject)->type != OTContainer))
+ ((Object *)newObject)->id = Global::objectID++;
+
+ return (Object *)newObject;
+}
+
+
+void MoveSelectedObjectsTo(VPVector & dest, VPVector & from)
{
- std::vector<void *>::iterator i = from.begin();
+ VPVectorIter i = from.begin();
while (i != from.end())
{
}
+VPVector MoveSelectedObjectsFrom(VPVector & from)
+{
+ VPVector objects;
+ VPVectorIter i = from.begin();
+
+ while (i != from.end())
+ {
+ Object * obj = (Object *)(*i);
+
+ if (obj->selected)
+ {
+ objects.push_back(*i);
+ from.erase(i);
+ }
+ else
+ i++;
+ }
+
+ return objects;
+}
+
+
//hmm, this won't work, as these are just pointers...
//[should work now]
-void CopySelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+void CopySelectedObjectsTo(VPVector & dest, VPVector & from)
{
- for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
+ for(VPVectorIter i=from.begin(); i!=from.end(); i++)
{
Object * obj = (Object *)(*i);
if (obj->selected)
-// {
-// Object * newObject = CopyObject(obj);
- dest.push_back(CopyObject(obj));
-// }
+ dest.push_back(CopyObject2(obj));
}
}
-void AddObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+VPVector CopySelectedObjects(VPVector & src)
{
- for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
- dest.push_back(*i);
+ VPVector copy;
+
+ for(VPVectorIter i=src.begin(); i!=src.end(); i++)
+ {
+ Object * obj = (Object *)(*i);
+
+ if (obj->selected)
+ copy.push_back(CopyObject2(obj));
+ }
+
+ return copy;
}
-void ClearSelected(std::vector<void *> & v)
+void AddObjectsTo(VPVector & dest, VPVector & from)
{
- std::vector<void *>::iterator i;
+ for(VPVectorIter i=from.begin(); i!=from.end(); i++)
+ dest.push_back(*i);
+}
- for(i=v.begin(); i!=v.end(); i++)
+
+void ClearSelected(VPVector & v)
+{
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
((Object *)(*i))->selected = false;
}
-void SelectAll(std::vector<void *> & v)
+//
+// Select all *visible* objects. If an object's layer is invisible, skip it.
+//
+void SelectAll(VPVector & v)
{
- std::vector<void *>::iterator i;
-
- for(i=v.begin(); i!=v.end(); i++)
- ((Object *)(*i))->selected = true;
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
+ {
+ Object * obj = (Object *)(*i);
+ bool visible = !Global::layerHidden[obj->layer];
+ obj->selected = visible;
+ }
}
// have to keep track of that stuff ourselves. :-P Believe it or not, this is
// a Good Thing(TM). ;-)
//
-void DeleteContents(std::vector<void *> & v)
+void DeleteContents(VPVector & v)
{
- std::vector<void *>::iterator i;
-
- for(i=v.begin(); i!=v.end(); i++)
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
{
Object * obj = (Object *)(*i);
}
-void DeleteSelectedObjects(std::vector<void *> & v)
+void DeleteSelectedObjects(VPVector & v)
{
- std::vector<void *>::iterator i = v.begin();
+ VPVectorIter i = v.begin();
while (i != v.end())
{
// This is used to remove selected objects from one container in order to move
// them to a different container.
//
-void RemoveSelectedObjects(std::vector<void *> & v)
+void RemoveSelectedObjects(VPVector & v)
{
- std::vector<void *>::iterator i = v.begin();
+ VPVectorIter i = v.begin();
while (i != v.end())
{
}
-void SavePointsFrom(std::vector<void *> & v, std::vector<Object> & save)
+void SavePointsFrom(VPVector & v, std::vector<Object> & save)
{
save.clear();
Object o;
- for(std::vector<void *>::iterator i=v.begin(); i!=v.end(); i++)
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
{
memcpy(&o, (Object *)(*i), sizeof(Object));
save.push_back(o);
}
-void RestorePointsTo(std::vector<void *> & v, std::vector<Object> & s)
+void RestorePointsTo(VPVector & v, std::vector<Object> & s)
{
- std::vector<Object>::iterator i = s.begin();
- std::vector<void *>::iterator j = v.begin();
+ std::vector<Object>::iterator i;
+ VPVectorIter j;
- for(; i!=s.end(); i++, j++)
+ for(i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
{
Object * obj2 = (Object *)(*j);
obj2->p[0] = (*i).p[0];
}
-void RestorePointsTo(std::vector<void *> & v, std::vector<void *> & s)
+void RestorePointsTo(VPVector & v, VPVector & s)
{
- std::vector<void *>::iterator i = s.begin();
- std::vector<void *>::iterator j = v.begin();
-
- for(; i!=s.end(); i++, j++)
+ for(VPVectorIter i=s.begin(), j=v.begin(); i!=s.end(); i++, j++)
{
Object * objS = (Object *)(*i);
Object * objV = (Object *)(*j);
}
+//
+// Translate a single object; it it's a Container, translate all its contents,
+// including subcontainers.
+//
void TranslateObject(Object * obj, Point delta)
{
if (obj->type == OTContainer)
{
Container * c = (Container *)obj;
- std::vector<void *>::iterator i;
- for(i=c->objects.begin(); i!=c->objects.end(); i++)
+ for(VPVectorIter i=c->objects.begin(); i!=c->objects.end(); i++)
TranslateObject((Object *)*i, delta);
}
-// else
-// {
- obj->p[0] += delta;
- obj->p[1] += delta;
-// }
+
+ obj->p[0] += delta;
+ obj->p[1] += delta;
}
void TranslateContainer(Container * c, Point point, Point delta)
{
if (c->clicked == NULL)
- {
+// {
// TranslateObject((Object *)c, delta);
return;
- }
+// }
-static int i=0;
-printf("TranslateContainer: boop (%i)\n", i++);
- Point clickedPoint;
+//static int i=0;
+//printf("TranslateContainer: boop (%i)\n", i++);
+//we can set this to "point" and it won't move...
+//do it *this* way, and non-enumerated clicks will do the right thing
+ Point clickedPoint = point - delta;
switch (c->clicked->type)
{
else if (c->clicked->hitPoint[1])
clickedPoint = c->clicked->p[1];
else if (c->clicked->hitObject)
+//Weirdness: some lines get a midpoint, some don't...
clickedPoint = Geometry::Midpoint((Line *)(c->clicked));
break;
case OTCircle:
if (c->clicked->hitPoint[0])
clickedPoint = c->clicked->p[0];
- else if (c->clicked->hitObject)
- clickedPoint = point;
+// else if (c->clicked->hitObject)
+// clickedPoint = point - delta;
break;
case OTArc:
+ if (c->clicked->hitPoint[0])
+ clickedPoint = c->clicked->p[0];
+ else if (c->clicked->hitPoint[1])
+ clickedPoint = c->clicked->p[0] + (Vector(cos(c->clicked->angle[0]), sin(c->clicked->angle[0])) * c->clicked->radius[0]);
+ else if (c->clicked->hitPoint[2])
+ clickedPoint = c->clicked->p[0] + (Vector(cos(c->clicked->angle[0] + c->clicked->angle[1]), sin(c->clicked->angle[0] + c->clicked->angle[1])) * c->clicked->radius[0]);
+// else if (c->clicked->hitObject)
+// clickedPoint = point - delta;
+
break;
case OTDimension:
}
-void TranslateObjects(std::vector<void *> & v, Point delta)
+//
+// Translate all objects in the passed in vector, including Containers and all
+// the objects they contain.
+//
+void TranslateObjects(VPVector & v, Point delta)
{
-#if 0
- if (obj->type == OTContainer)
- {
- Container * c = (Container *)obj;
- std::vector<void *>::iterator i;
-
- for(i=c->objects.begin(); i!=c->objects.end(); i++)
- TranslateObject((Object *)*i, delta);
- }
- else
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
{
+ Object * obj = (Object *)(*i);
obj->p[0] += delta;
obj->p[1] += delta;
+
+ if (obj->type == OTContainer)
+ {
+ Container * c = (Container *)obj;
+ TranslateObjects(c->objects, delta);
+ }
}
-#endif
- // Handle containters too???
- std::vector<void *>::iterator i;
+}
- for(i=v.begin(); i!=v.end(); i++)
+
+//
+// This does not *copy* the objects, it simply flattens out the pointers in the
+// Container and all sub-Containers.
+//
+VPVector Flatten(Container * src)
+{
+ VPVector flat;
+
+ for(VPVectorIter i=src->objects.begin(); i!=src->objects.end(); i++)
{
+ flat.push_back(*i);
Object * obj = (Object *)(*i);
- obj->p[0] += delta;
- obj->p[1] += delta;
+
+ // Recursively add objects to the flat vector, if necessary
+ if (obj->type == OTContainer)
+ {
+ VPVector sub = Flatten((Container *)obj);
+ flat.insert(flat.end(), sub.begin(), sub.end());
+ }
}
+
+ return flat;
}
-std::vector<void *> Flatten(Container * src)
+//
+// This does not *copy* the objects, it simply flattens out the pointers in the
+// vector and all sub-Containers in the vector.
+//
+VPVector Flatten(VPVector src)
{
- std::vector<void *> flat;
- std::vector<void *>::iterator i;
+ VPVector flat;
- for(i=src->objects.begin(); i!=src->objects.end(); i++)
+ for(VPVectorIter i=src.begin(); i!=src.end(); i++)
{
flat.push_back(*i);
Object * obj = (Object *)(*i);
// Recursively add objects to the flat vector, if necessary
if (obj->type == OTContainer)
{
- std::vector<void *> sub = Flatten((Container *)obj);
+ VPVector sub = Flatten(((Container *)obj)->objects);
flat.insert(flat.end(), sub.begin(), sub.end());
}
}
#include <vector>
#include "structs.h"
-void CopyObjects(std::vector<void *> & from, std::vector<void *> & to);
+void CopyObjects(VPVector & from, VPVector & to);
+VPVector CopyObjects(VPVector & from);
Object * CopyObject(Object * obj);
-void MoveSelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
-void CopySelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
-void AddObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
-void ClearSelected(std::vector<void *> & v);
-void SelectAll(std::vector<void *> & v);
-void DeleteContents(std::vector<void *> & v);
-void DeleteSelectedObjects(std::vector<void *> & v);
-void RemoveSelectedObjects(std::vector<void *> & v);
-void SavePointsFrom(std::vector<void *> & v, std::vector<Object> & s);
-void RestorePointsTo(std::vector<void *> & v, std::vector<Object> & s);
-void RestorePointsTo(std::vector<void *> & v, std::vector<void *> & s);
+Object * CopyObject2(Object * obj);
+void MoveSelectedObjectsTo(VPVector & dest, VPVector & from);
+VPVector MoveSelectedObjectsFrom(VPVector & from);
+void CopySelectedObjectsTo(VPVector & dest, VPVector & from);
+VPVector CopySelectedObjects(VPVector & from);
+void AddObjectsTo(VPVector & dest, VPVector & from);
+void ClearSelected(VPVector & v);
+void SelectAll(VPVector & v);
+void DeleteContents(VPVector & v);
+void DeleteSelectedObjects(VPVector & v);
+void RemoveSelectedObjects(VPVector & v);
+void SavePointsFrom(VPVector & v, std::vector<Object> & s);
+void RestorePointsTo(VPVector & v, std::vector<Object> & s);
+void RestorePointsTo(VPVector & v, VPVector & s);
void TranslateObject(Object * obj, Point delta);
void TranslateContainer(Container * c, Point point, Point delta);
-void TranslateObjects(std::vector<void *> & v, Point delta);
-std::vector<void *> Flatten(Container * src);
+void TranslateObjects(VPVector & v, Point delta);
+VPVector Flatten(Container * src);
+VPVector Flatten(VPVector src);
#endif // __UTILS_H__
double Vector::Magnitude(void)
{
- return sqrt(x * x + y * y + z * z);
+ return sqrt((x * x) + (y * y) + (z * z));
}