From ccac11461956c9c0cc9756f8963436b5d88dfbb7 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sat, 11 Feb 2017 08:33:30 -0600 Subject: [PATCH] Added ability to manipulate Text objects. It's not possible yet to edit their content or change their angle, but that's coming. :-) --- src/drawingview.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++- src/objectwidget.cpp | 17 +++++++++++ src/painter.cpp | 24 +++++++++++---- src/painter.h | 1 + src/rect.cpp | 30 +++++++++++++++++++ src/rect.h | 5 ++++ src/structs.h | 16 ++++++---- 7 files changed, 152 insertions(+), 12 deletions(-) diff --git a/src/drawingview.cpp b/src/drawingview.cpp index ca063c5..0ef95dd 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -607,7 +607,14 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int case OTText: { Text * t = (Text *)obj; - painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness); + + if (t->measured == false) + { + t->extents = painter->MeasureTextObject(t->s.c_str(), scaledThickness); + t->measured = true; + } + + painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness, t->angle[0]); break; } case OTSpline: @@ -1601,12 +1608,14 @@ Rect DrawingView::GetObjectExtents(Object * obj) rect = Rect(obj->p[0], obj->p[1]); break; } + case OTCircle: { rect = Rect(obj->p[0], obj->p[0]); rect.Expand(obj->radius[0]); break; } + case OTArc: { Arc * a = (Arc *)obj; @@ -1643,9 +1652,16 @@ Rect DrawingView::GetObjectExtents(Object * obj) rect *= a->radius[0]; rect.Translate(a->p[0]); + break; + } + case OTText: + { + Text * t = (Text *)obj; + rect = Rect(t->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height())); break; } + case OTContainer: { Container * c = (Container *)obj; @@ -1656,6 +1672,7 @@ Rect DrawingView::GetObjectExtents(Object * obj) for(; i!=c->objects.end(); i++) rect |= GetObjectExtents((Object *)*i); } + default: break; } @@ -1685,6 +1702,7 @@ void DrawingView::CheckObjectBounds(void) break; } + case OTCircle: { Circle * c = (Circle *)obj; @@ -1694,6 +1712,7 @@ void DrawingView::CheckObjectBounds(void) break; } + case OTArc: { Arc * a = (Arc *)obj; @@ -1759,6 +1778,18 @@ void DrawingView::CheckObjectBounds(void) break; } + + case OTText: + { + Text * t = (Text *)obj; + Rect r(obj->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height())); + + if (Global::selection.contains(r.l, r.t) && Global::selection.contains(r.r, r.b)) + t->selected = true; + + break; + } + default: break; } @@ -1843,6 +1874,7 @@ bool DrawingView::HitTest(Object * obj, Point point) break; } + case OTCircle: { bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject; @@ -1850,7 +1882,11 @@ bool DrawingView::HitTest(Object * obj, Point point) double length = Vector::Magnitude(obj->p[0], point); if ((length * Global::zoom) < 8.0) + { obj->hitPoint[0] = true; + hoverPoint = obj->p[0]; + hoverPointValid = true; + } else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) obj->hitObject = true; @@ -1861,6 +1897,7 @@ bool DrawingView::HitTest(Object * obj, Point point) break; } + case OTArc: { bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHO = obj->hitObject; @@ -1883,7 +1920,11 @@ bool DrawingView::HitTest(Object * obj, Point point) double length3 = Vector::Magnitude(point, handle2); if ((length * Global::zoom) < 8.0) + { obj->hitPoint[0] = true; + hoverPoint = obj->p[0]; + hoverPointValid = true; + } else if ((length2 * Global::zoom) < 8.0) { obj->hitPoint[1] = true; @@ -1906,6 +1947,7 @@ bool DrawingView::HitTest(Object * obj, Point point) break; } + case OTDimension: { bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHP3 = obj->hitPoint[3], oldHP4 = obj->hitPoint[4], oldHO = obj->hitObject; @@ -1959,9 +2001,29 @@ bool DrawingView::HitTest(Object * obj, Point point) if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHP3 != obj->hitPoint[3]) || (oldHP4 != obj->hitPoint[4]) || (oldHO != obj->hitObject)) needUpdate = true; + break; + } + + case OTText: + { + Text * t = (Text *)obj; + bool oldHO = obj->hitObject; + obj->hitObject = false; + + Rect r(obj->p[0], Point(obj->p[0].x + t->extents.Width(), obj->p[0].y - t->extents.Height())); +//printf("Text: p=<%lf, %lf>, w/h=%lf, %lf [lrtb=%lf, %lf, %lf, %lf]\n", obj->p[0].x, obj->p[0].y, t->extents.Width(), t->extents.Height(), t->extents.l, t->extents.r, t->extents.t, t->extents.b); + + if (r.Contains(point)) + obj->hitObject = true; + + obj->hovered = (obj->hitObject ? true : false); + + if (oldHO != obj->hitObject) + needUpdate = true; break; } + case OTContainer: { // Containers must be recursively tested... @@ -1986,6 +2048,7 @@ bool DrawingView::HitTest(Object * obj, Point point) break; } + default: break; } @@ -2159,6 +2222,12 @@ void DrawingView::HandleObjectMovement(Point point) break; + case OTText: + if (obj->hitObject) + obj->p[0] += delta; + + break; + case OTContainer: // This is shitty, but works for now until I can code up something // nicer :-) diff --git a/src/objectwidget.cpp b/src/objectwidget.cpp index c7e0cf6..554ce34 100644 --- a/src/objectwidget.cpp +++ b/src/objectwidget.cpp @@ -74,6 +74,10 @@ void ObjectWidget::ShowInfo(Object * obj) const char objName[OTCount][16] = { "None", "Line", "Circle", "Ellipse", "Arc", "Polygon", "Dimension", "Spline", "Text", "Container" }; + const char dimName[DTCount][32] = { + "Linear", "Vertical", "Horizontal", "Radial", "Diametric", + "Circumferential", "Angular", "Leader" + }; // Sanity check if (obj == NULL) @@ -89,25 +93,38 @@ void ObjectWidget::ShowInfo(Object * obj) s += QString("<%1, %2> to <%3, %4>
Length: %5
Angle: %6°
").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->p[1].x).arg(obj->p[1].y).arg(line.Magnitude()).arg(line.Angle() * RADIANS_TO_DEGREES); break; } + case OTCircle: s += QString("Center: <%1, %2>
Radius: %3
").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]); break; + case OTEllipse: break; + case OTArc: s += QString("Center: <%1, %2>
Radius: %3
Start: %4°
End: %5°
").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]).arg(obj->angle[0] * RADIANS_TO_DEGREES).arg(obj->angle[1] * RADIANS_TO_DEGREES); break; break; + case OTPolygon: break; + case OTDimension: break; + case OTSpline: break; + case OTText: + { + Text * t = (Text *)obj; + s += QString("<%1, %2>
Width/Height: %3/%4
Angle: %5°
").arg(t->p[0].x).arg(t->p[0].y).arg(t->extents.Width()).arg(t->extents.Height()).arg(obj->angle[0] * RADIANS_TO_DEGREES); break; + } + case OTContainer: break; + default: break; } diff --git a/src/painter.cpp b/src/painter.cpp index 0806811..df1d7d5 100644 --- a/src/painter.cpp +++ b/src/painter.cpp @@ -183,6 +183,25 @@ void Painter::DrawTextObject(Point p, QString text, double size, double angle/*= } +// +// Return the non-rotated rectangle containing the extents of the text in +// Cartesian coordiates (starting from <0, 0>, the lower left hand side) +// +Rect Painter::MeasureTextObject(QString text, double size) +{ + if (!painter) + return Rect(); + + painter->setFont(QFont("Arial", Global::zoom * size)); + int textWidth = QFontMetrics(painter->font()).width(text); + int textHeight = QFontMetrics(painter->font()).height(); + Point measured((double)textWidth / Global::zoom, (double)textHeight / Global::zoom);// = QtToCartesianCoords(Point(textWidth, textHeight)); +//printf("QFontMetrics w/h=%i/%i, measured=%lf/%lf\n", textWidth, textHeight, measured.x, measured.y); + + return Rect(Point(0, 0), measured); +} + + void Painter::DrawArc(Vector center, double radius, double startAngle, double span) { if (!painter) @@ -245,13 +264,8 @@ void Painter::DrawRectCorners(Rect rect) if (!painter) return; -// QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y)); - Vector v1 = CartesianToQtCoords(Vector(rect.l, rect.t)); Vector v2 = CartesianToQtCoords(Vector(rect.r, rect.b)); -// QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y)); -// screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom -// painter->drawRect(screenRect); v1 += Vector(-8.0, -8.0); v2 += Vector(+8.0, +8.0); painter->setPen(QPen(Qt::red, 2.0, Qt::DashLine)); diff --git a/src/painter.h b/src/painter.h index 4ff50b2..5b11e25 100644 --- a/src/painter.h +++ b/src/painter.h @@ -22,6 +22,7 @@ class Painter void SetFont(QFont); void DrawAngledText(Vector, double, QString, double); void DrawTextObject(Vector, QString, double, double angle = 0); + Rect MeasureTextObject(QString text, double size); void DrawArc(Vector, double, double, double); void DrawEllipse(Vector, double, double); void DrawHandle(Vector); diff --git a/src/rect.cpp b/src/rect.cpp index 8207f23..8c9c74e 100644 --- a/src/rect.cpp +++ b/src/rect.cpp @@ -98,3 +98,33 @@ void Rect::Expand(double amt) b -= amt; } + +double Rect::Width(void) +{ + return r - l; +} + + +double Rect::Height(void) +{ + return t - b; +} + + +bool Rect::Contains(Point p) +{ + return ((p.x >= l) && (p.x <= r) && (p.y >= b) && (p.y <= t) ? true : false); +} + + +Point Rect::TopLeft(void) +{ + return Point(t, l); +} + + +Point Rect::BottomRight(void) +{ + return Point(b, r); +} + diff --git a/src/rect.h b/src/rect.h index 0a8478a..2689bae 100644 --- a/src/rect.h +++ b/src/rect.h @@ -20,6 +20,11 @@ struct Rect void Normalize(void); void Translate(Point p); void Expand(double amt); + double Width(void); + double Height(void); + bool Contains(Point p); + Point TopLeft(void); + Point BottomRight(void); }; #endif // __RECT_H__ diff --git a/src/structs.h b/src/structs.h index 7fe1f09..cdd11ec 100644 --- a/src/structs.h +++ b/src/structs.h @@ -5,11 +5,12 @@ #include #include #include "global.h" +#include "rect.h" #include "vector.h" enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTDimension, OTSpline, OTText, OTContainer, OTCount }; -enum DimensionType { DTLinear, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader }; +enum DimensionType { DTLinear = 0, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader, DTCount }; enum ToolType { TTNone, TTLine, TTCircle, TTEllipse, TTArc, TTDimension, TTText, TTPolygon, TTSpline, TTRotate, TTMirror, TTTrim, TTTriangulate, TTDelete }; @@ -30,6 +31,10 @@ enum ToolState { TSNone, TSPoint1, TSPoint2, TSPoint3, TSPoint4, TSDone }; double angle[2]; \ double radius[2]; +struct Object { + OBJECT_COMMON; +}; + struct Line { OBJECT_COMMON; @@ -85,12 +90,15 @@ struct Dimension { struct Text { OBJECT_COMMON; + Rect extents; + bool measured; std::string s; Text(): type(OTText), id(Global::objectID++) {} Text(Vector pt1, char * str, float th = 10.0, uint32_t c = 0): type(OTText), id(Global::objectID++), layer(0), color(c), thickness(th), - style(LSSolid), selected(false), hovered(false), hitObject(false), s(str) { p[0] = pt1; } + style(LSSolid), selected(false), hovered(false), hitObject(false), + measured(false), s(str) { p[0] = pt1; angle[0] = 0; } }; struct Polygon { @@ -129,9 +137,5 @@ struct Container { }*/ }; -struct Object { - OBJECT_COMMON; -}; - #endif // __STRUCTS_H__ -- 2.37.2