X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdrawingview.cpp;h=60f941e94c37a3e63d738d15369b7b69c8cd1bfe;hb=790c1a6d97f73f7457c7fad7e82fa29e5b6accd5;hp=f50fca562d11ce438a51c61d70ef16e689ba92e1;hpb=a6e76b6a748a350bda067a99672f9dcca626d872;p=architektonas diff --git a/src/drawingview.cpp b/src/drawingview.cpp index f50fca5..60f941e 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -1,3 +1,4 @@ +// // drawingview.cpp // // Part of the Architektonas Project @@ -16,11 +17,14 @@ // // - Redo rendering code to *not* use Qt's transform functions, as they are tied // to a left-handed system and we need a right-handed one. [DONE] +// - Fixed length tool doesn't work on lines [DONE] // // STILL TO BE DONE: // // - Lots of stuff // - Layer locking (hiding works) +// - Fixed angle tool doesn't work on lines +// - Make it so "dirty" flag reflects drawing state // // Uncomment this for debugging... @@ -48,50 +52,27 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), ctrlDown(false), altDown(false), gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE), scale(1.0), offsetX(-10), offsetY(-10), document(true), - gridPixels(0), collided(false), hoveringIntersection(false), - dragged(NULL), draggingObject(false), angleSnap(false) + gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false), + hoveringIntersection(false), dragged(NULL), draggingObject(false), + angleSnap(false), dirty(false) { //wtf? doesn't work except in c++11??? document = { 0 }; setBackgroundRole(QPalette::Base); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); Global::gridSpacing = 12.0; // In base units (inch is default) -#if 0 - Line * line = new Line(Vector(5, 5), Vector(50, 40), &document); + + Line * line = new Line(Vector(5, 5), Vector(50, 40), 2.0, 0xFF7F00, LSDash); document.Add(line); - document.Add(new Line(Vector(50, 40), Vector(10, 83), &document)); - document.Add(new Line(Vector(10, 83), Vector(17, 2), &document)); - document.Add(new Circle(Vector(100, 100), 36, &document)); - document.Add(new Circle(Vector(50, 150), 49, &document)); - 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), DTLinear, &document); - line->SetDimensionOnLine(dimension); - document.Add(dimension); -#else - // Alternate way to do the above... - line->SetDimensionOnLine(); -#endif -#else - Line * line = new Line;//(Vector(5, 5), Vector(50, 40), &document); - line->p[0] = Vector(5, 5); - line->p[1] = Vector(50, 40); - line->type = OTLine; - line->thickness = 2.0; - line->style = LSDash; - line->color = 0xFF7F00; - line->layer = 0; - document.objects.push_back(line); - document.objects.push_back(new Line(Vector(50, 40), Vector(10, 83))); - document.objects.push_back(new Line(Vector(10, 83), Vector(17, 2))); - document.objects.push_back(new Circle(Vector(100, 100), 36)); - document.objects.push_back(new Circle(Vector(50, 150), 49)); - document.objects.push_back(new Arc(Vector(300, 300), 32, TAU / 8.0, TAU * 0.65)), - document.objects.push_back(new Arc(Vector(200, 200), 60, TAU / 4.0, TAU * 0.75)); - document.objects.push_back(new Dimension(Vector(50, 40), Vector(5, 5))); - document.objects.push_back(new Text(Vector(10, 83), "Here is some awesome text!")); -#endif + document.Add(new Line(Vector(50, 40), Vector(10, 83))); + document.Add(new Line(Vector(10, 83), Vector(17, 2))); + document.Add(new Circle(Vector(100, 100), 36)); + document.Add(new Circle(Vector(50, 150), 49)); + document.Add(new Arc(Vector(300, 300), 32, TAU / 8.0, TAU * 0.65)), + document.Add(new Arc(Vector(200, 200), 60, TAU / 4.0, TAU * 0.75)); + document.Add(new Text(Vector(10, 83), "Here is some awesome text!")); + + AddDimensionTo(line); /* Here we set the grid size in pixels--12 in this case. Initially, we have our @@ -365,6 +346,18 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y) } +void DrawingView::focusOutEvent(QFocusEvent * /*event*/) +{ +// printf("DrawingView::focusOutEvent()...\n"); + // Make sure all modkeys being held are marked as released when the app + // loses focus (N.B.: This only works because the app sets the focus policy + // of this object to something other than Qt::NoFocus) + shiftDown = ctrlDown = altDown = false; + scrollDrag = false; + setCursor(Qt::ArrowCursor); +} + + void DrawingView::paintEvent(QPaintEvent * /*event*/) { QPainter qtPainter(this); @@ -406,6 +399,9 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) if (hoveringIntersection) painter.DrawHandle(intersectionPoint); + if (hoverPointValid) + painter.DrawHandle(hoverPoint); + if (!informativeText.isEmpty()) painter.DrawInformativeText(informativeText); } @@ -414,6 +410,12 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) // // Renders objects in the passed in vector // +/* +N.B.: Since we have "hoverPointValid" drawing regular object handles above, + we can probably do away with a lot of them that are being done down below. + !!! 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 & v, int layer, bool ignoreLayer/*= false*/) { std::vector::iterator i; @@ -451,7 +453,11 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int if (obj->hitPoint[1]) painter->DrawHandle(obj->p[1]); + if (obj->hitObject) + painter->DrawSmallHandle(Geometry::Midpoint((Line *)obj)); + break; + case OTCircle: painter->SetBrush(QBrush(Qt::NoBrush)); painter->DrawEllipse(obj->p[0], obj->radius[0], obj->radius[0]); @@ -460,6 +466,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int painter->DrawHandle(obj->p[0]); break; + case OTArc: painter->DrawArc(obj->p[0], obj->radius[0], obj->angle[0], obj->angle[1]); @@ -473,6 +480,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int painter->DrawHandle(obj->p[0] + (Vector(cos(obj->angle[0] + obj->angle[1]), sin(obj->angle[0] + obj->angle[1])) * obj->radius[0])); break; + case OTDimension: { Dimension * d = (Dimension *)obj; @@ -640,6 +648,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int break; } + case OTText: { Text * t = (Text *)obj; @@ -653,30 +662,36 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness, t->angle[0]); break; } + case OTSpline: { break; } + case OTPolygon: { break; } + case OTContainer: { // Containers require recursive rendering... Container * c = (Container *)obj; - RenderObjects(painter, (*c).objects, layer); +printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), layer); + RenderObjects(painter, (*c).objects, layer, ignoreLayer); //printf("Container extents: <%lf, %lf>, <%lf, %lf>\nsize: %i\n", r.l, r.t, r.r, r.b, c->objects.size()); // Containers also have special indicators showing they are selected if (c->selected || c->hitObject) { - Rect r = GetObjectExtents(obj); - painter->DrawRectCorners(r); +// Rect r = GetObjectExtents(obj); +// painter->DrawRectCorners(r); + painter->DrawRectCorners(Rect(c->p[0], c->p[1])); } break; } + default: break; } @@ -709,6 +724,7 @@ void DrawingView::GetSelection(std::vector & v) } +#if 0 void DrawingView::GetHovered(std::vector & v) { v.clear(); @@ -723,6 +739,25 @@ void DrawingView::GetHovered(std::vector & v) // } } } +#endif + + +std::vector DrawingView::GetHovered(void) +{ + std::vector v; + std::vector::iterator i; + + for(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; +} void DrawingView::resizeEvent(QResizeEvent * /*event*/) @@ -749,6 +784,12 @@ void DrawingView::ToolHandler(int mode, Point p) MirrorHandler(mode, p); else if (Global::tool == TTDimension) DimensionHandler(mode, p); + else if (Global::tool == TTTriangulate) + TriangulateHandler(mode, p); + else if (Global::tool == TTTrim) + TrimHandler(mode, p); + else if (Global::tool == TTParallel) + ParallelHandler(mode, p); } @@ -923,6 +964,7 @@ void DrawingView::LineHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseMove: if (Global::toolState == TSNone) toolPoint[0] = p; @@ -930,6 +972,7 @@ void DrawingView::LineHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseUp: if (Global::toolState == TSNone) { @@ -965,6 +1008,7 @@ void DrawingView::CircleHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseMove: if (Global::toolState == TSNone) toolPoint[0] = p; @@ -972,6 +1016,7 @@ void DrawingView::CircleHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseUp: if (Global::toolState == TSNone) { @@ -1013,6 +1058,7 @@ void DrawingView::ArcHandler(int mode, Point p) toolPoint[3] = p; break; + case ToolMouseMove: if (Global::toolState == TSNone) toolPoint[0] = p; @@ -1030,6 +1076,7 @@ void DrawingView::ArcHandler(int mode, Point p) } break; + case ToolMouseUp: if (Global::toolState == TSNone) { @@ -1082,7 +1129,8 @@ void DrawingView::RotateHandler(int mode, Point p) if (Global::toolState == TSNone) { toolPoint[0] = p; - SavePointsFrom(select, toolScratch); +// SavePointsFrom(select, toolScratch); + CopyObjects(select, toolScratch2); Global::toolState = TSPoint1; } else if (Global::toolState == TSPoint1) @@ -1091,6 +1139,7 @@ void DrawingView::RotateHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseMove: if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone)) toolPoint[0] = p; @@ -1104,28 +1153,69 @@ void DrawingView::RotateHandler(int mode, Point p) angleSnap = true; double angle = Vector(toolPoint[0], toolPoint[1]).Angle(); std::vector::iterator j = select.begin(); - std::vector::iterator i = toolScratch.begin(); +// std::vector::iterator i = toolScratch.begin(); + std::vector::iterator i = toolScratch2.begin(); - for(; i!=toolScratch.end(); i++, j++) +// for(; i!=toolScratch.end(); i++, j++) + for(; i!=toolScratch2.end(); i++, j++) { - Object obj = *i; - Point p1 = Geometry::RotatePointAroundPoint(obj.p[0], toolPoint[0], angle); - Point p2 = Geometry::RotatePointAroundPoint(obj.p[1], toolPoint[0], angle); - Object * obj2 = (Object *)(*j); - obj2->p[0] = p1; - obj2->p[1] = p2; +// Object objT = *i; +// Point p1 = Geometry::RotatePointAroundPoint(objT.p[0], toolPoint[0], angle); +// Point p2 = Geometry::RotatePointAroundPoint(objT.p[1], toolPoint[0], angle); + Object * objT = (Object *)(*i); + Object * objS = (Object *)(*j); - if (obj.type == OTArc) + Point p1 = Geometry::RotatePointAroundPoint(objT->p[0], toolPoint[0], angle); + Point p2 = Geometry::RotatePointAroundPoint(objT->p[1], toolPoint[0], angle); + + objS->p[0] = p1; + objS->p[1] = p2; + +// if (objT.type == OTArc || objT.type == OTText) + if (objT->type == OTArc || objT->type == OTText) { - obj2->angle[0] = obj.angle[0] + angle; +// objS->angle[0] = objT.angle[0] + angle; + objS->angle[0] = objT->angle[0] + angle; - if (obj2->angle[0] > TAU) - obj2->angle[0] -= TAU; + if (objS->angle[0] > TAU) + objS->angle[0] -= TAU; + } +// else if (objT.type == OTContainer) + else if (objT->type == OTContainer) + { + // OK, this doesn't work because toolScratch only has points and nothing in the containers... [ACTUALLY... toolScratch is is a vector of type Object... which DOESN'T have an objects vector in it...] +// Container * c = (Container *)&objT; + Container * c = (Container *)objT; + Container * c2 = (Container *)objS; + std::vector::iterator l = c->objects.begin(); + // TODO: Rotate items in the container + // TODO: Make this recursive + for(std::vector::iterator k=c2->objects.begin(); k!=c2->objects.end(); k++, l++) + { + Object * obj3 = (Object *)(*k); + Object * obj4 = (Object *)(*l); + + p1 = Geometry::RotatePointAroundPoint(obj4->p[0], toolPoint[0], angle); + p2 = Geometry::RotatePointAroundPoint(obj4->p[1], toolPoint[0], angle); + + obj3->p[0] = p1; + obj3->p[1] = p2; +// obj3->angle[0] = objT.angle[0] + angle; + obj3->angle[0] = obj4->angle[0] + angle; + + if (obj3->angle[0] > TAU) + obj3->angle[0] -= TAU; + } + + Rect r = GetObjectExtents(objS); + c2->p[0] = r.TopLeft(); + c2->p[1] = r.BottomRight(); } } } break; + case ToolMouseUp: if (Global::toolState == TSPoint1) { @@ -1149,30 +1239,39 @@ void DrawingView::RotateHandler(int mode, Point p) CopyObjects(select, temp); ClearSelected(temp); AddObjectsTo(document.objects, temp); - RestorePointsTo(select, toolScratch); +// RestorePointsTo(select, toolScratch); + RestorePointsTo(select, toolScratch2); return; } toolPoint[0] = p; Global::toolState = TSPoint1; - SavePointsFrom(select, toolScratch); +// SavePointsFrom(select, toolScratch); + DeleteContents(toolScratch2); + CopyObjects(select, toolScratch2); } break; + case ToolKeyDown: // Reset the selection if shift held down... if (shiftDown) - RestorePointsTo(select, toolScratch); +// RestorePointsTo(select, toolScratch); + RestorePointsTo(select, toolScratch2); break; + case ToolKeyUp: // Reset selection when key is let up if (!shiftDown) RotateHandler(ToolMouseMove, toolPoint[1]); break; + case ToolCleanup: - RestorePointsTo(select, toolScratch); +// RestorePointsTo(select, toolScratch); + RestorePointsTo(select, toolScratch2); + DeleteContents(toolScratch2); } } @@ -1194,6 +1293,7 @@ void DrawingView::MirrorHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseMove: if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone)) toolPoint[0] = p; @@ -1218,6 +1318,11 @@ void DrawingView::MirrorHandler(int mode, Point p) obj2->p[0] = p1; obj2->p[1] = p2; +/* +N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have + a negative start angle which makes it impossible to interact with. + !!! FIX !!! +*/ if (obj.type == OTArc) { // This is 2*mirror angle - obj angle - obj span @@ -1230,6 +1335,7 @@ void DrawingView::MirrorHandler(int mode, Point p) } break; + case ToolMouseUp: if (Global::toolState == TSPoint1) { @@ -1263,18 +1369,21 @@ void DrawingView::MirrorHandler(int mode, Point p) } break; + case ToolKeyDown: // Reset the selection if shift held down... if (shiftDown) RestorePointsTo(select, toolScratch); break; + case ToolKeyUp: // Reset selection when key is let up if (!shiftDown) MirrorHandler(ToolMouseMove, toolPoint[1]); break; + case ToolCleanup: RestorePointsTo(select, toolScratch); } @@ -1292,6 +1401,7 @@ void DrawingView::DimensionHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseMove: if (Global::toolState == TSNone) toolPoint[0] = p; @@ -1299,6 +1409,7 @@ void DrawingView::DimensionHandler(int mode, Point p) toolPoint[1] = p; break; + case ToolMouseUp: if (Global::toolState == TSNone) { @@ -1323,10 +1434,265 @@ void DrawingView::DimensionHandler(int mode, Point p) } +void DrawingView::TriangulateHandler(int mode, Point/*p*/) +{ + switch (mode) + { + case ToolMouseDown: + { + // Skip if nothing hovered... + if (numHovered != 1) + break; + + std::vector hover = GetHovered(); + Object * obj = (Object *)hover[0]; + + // Skip if it's not a line... + if (obj->type != OTLine) + break; + + if (Global::toolState == TSNone) + toolObj[0] = obj; + else if (Global::toolState == TSPoint2) + toolObj[1] = obj; + else + toolObj[2] = obj; + + break; + } +#if 0 + case ToolMouseMove: + if (Global::toolState == TSNone) + toolPoint[0] = p; + else if (Global::toolState == TSPoint2) + toolPoint[1] = p; + else if (Global::toolState == TSPoint3) + { + toolPoint[2] = p; + angleSnap = true; + } + else + { + toolPoint[3] = p; + angleSnap = true; + } + + break; +#endif + case ToolMouseUp: + if (Global::toolState == TSNone) + { + Global::toolState = TSPoint2; + } + else if (Global::toolState == TSPoint2) + { +/* if (shiftDown) + { + // Key override is telling us to start arc at new center, not + // continue the current one. + toolPoint[0] = toolPoint[1]; + return; + }*/ + + Global::toolState = TSPoint3; + } + else + { + double len2 = Vector::Magnitude(toolObj[1]->p[0], toolObj[1]->p[1]); + double len3 = Vector::Magnitude(toolObj[2]->p[0], toolObj[2]->p[1]); + + Circle c1(toolObj[0]->p[0], len2); + Circle c2(toolObj[0]->p[1], len3); + + Geometry::CheckCircleToCircleIntersection((Object *)&c1, (Object *)&c2); + + // Only move lines if the triangle formed by them is not degenerate + if (Global::numIntersectPoints > 0) + { + toolObj[1]->p[0] = toolObj[0]->p[0]; + toolObj[1]->p[1] = Global::intersectPoint[0]; + + toolObj[2]->p[0] = Global::intersectPoint[0]; + toolObj[2]->p[1] = toolObj[0]->p[1]; + } + + Global::toolState = TSNone; + } + } +} + + +void DrawingView::TrimHandler(int mode, Point p) +{ +/* +n.b.: this code is lifted straight out of the old oo code. needs to be updated. +*/ + switch (mode) + { + case ToolMouseDown: + { +#if 0 + Object * toTrim = doc->lastObjectHovered; + + if (toTrim == NULL) + return; + + Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint); + + // Check to see which case we have... + // We're trimming point #1... + if (t == 0) + { + ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u); + } + else if (u == 1.0) + { + ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t); + } + else + { + Point p1 = ((Line *)toTrim)->position + (v * t); + Point p2 = ((Line *)toTrim)->position + (v * u); + Point p3 = ((Line *)toTrim)->endpoint; + ((Line *)toTrim)->endpoint = p1; + Line * line = new Line(p2, p3); + emit ObjectReady(line); + } + + doc->lastObjectHovered = NULL; +#endif + } + break; + + case ToolMouseMove: + { +#if 0 + Object * toTrim = doc->lastObjectHovered; + t = 0, u = 1.0; + + if (toTrim == NULL) + return; + + if (toTrim->type != OTLine) + return; + + double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point); + + std::vector::iterator i; + + for(i=doc->objects.begin(); i!=doc->objects.end(); i++) + { + // Can't trim against yourself... :-P + if (*i == toTrim) + continue; + + Object * trimAgainst = *i; + double t1;//, u1; + + if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine)) + continue; + + int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1); + + if (intersects) + { + // Now what? We don't know which side to trim! + // ... now we do, we know which side of the Line we're on! + if ((t1 > t) && (t1 < pointHoveredT)) + t = t1; + + if ((t1 < u) && (t1 > pointHoveredT)) + u = t1; + } + } +#endif + // Bail out if nothing hovered... + if (numHovered != 1) + { + toolObj[0] = NULL; + return; + } + + std::vector hover = GetHovered(); + Object * obj = (Object *)hover[0]; + + // Skip if it's not a line... + if (obj->type != OTLine) + { + toolObj[0] = NULL; + return; + } + + toolObj[0] = obj; + double hoveredParam = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], p); + + // Currently only deal with line against line trimming, can expand to + // others as well (line/circle, circle/circle, line/arc, etc) + std::vector::iterator i; + for(i=document.objects.begin(); i!=document.objects.end(); i++) + { + obj = (Object *)(*i); + + if (obj == toolObj[0]) + continue; + else if (obj->type != OTLine) + continue; + + Geometry::CheckLineToLineIntersection(toolObj[0], obj); + + if (Global::numIntersectParams > 0) + { + // Mark the line segment somehow (the side the mouse is on) so that it can be drawn & trimmed when we hit ToolMouseDown. + } + } + } + break; + + case ToolMouseUp: + break; + + case ToolKeyDown: + break; + + case ToolKeyUp: + break; + + case ToolCleanup: + break; + } +} + + +void DrawingView::ParallelHandler(int mode, Point /*p*/) +{ + switch (mode) + { + case ToolMouseDown: + break; + + case ToolMouseMove: + break; + + case ToolMouseUp: + break; + + case ToolKeyDown: + break; + + case ToolKeyUp: + break; + + case ToolCleanup: + break; + } +} + + void DrawingView::mousePressEvent(QMouseEvent * event) { if (event->button() == Qt::LeftButton) { +printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered); Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); // Handle tool processing, if any @@ -1334,6 +1700,8 @@ void DrawingView::mousePressEvent(QMouseEvent * event) { if (hoveringIntersection) point = intersectionPoint; + else if (hoverPointValid) + point = hoverPoint; else if (Global::snapToGrid) point = SnapPointToGrid(point); @@ -1358,12 +1726,14 @@ void DrawingView::mousePressEvent(QMouseEvent * event) { AddHoveredToSelection(); update(); // needed?? - GetHovered(hover); // prolly needed - dragged = (Object *)hover[0]; +// GetHovered(hover); // prolly needed + std::vector hover2 = GetHovered(); + dragged = (Object *)hover2[0]; draggingObject = true; +printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]); // Alert the pen widget - emit(ObjectSelected(dragged)); + emit ObjectSelected(dragged); // See if anything is using just a straight click on a handle if (HandleObjectClicked()) @@ -1377,9 +1747,26 @@ void DrawingView::mousePressEvent(QMouseEvent * event) // We do it *after*... why? (doesn't seem to confer any advantage...) if (hoveringIntersection) oldPoint = intersectionPoint; + else if (hoverPointValid) + oldPoint = hoverPoint; else if (Global::snapToGrid) oldPoint = SnapPointToGrid(point); + // Needed for fixed length handling + if (Global::fixedLength) + { + if (dragged->type == OTLine) + { + dragged->length = Vector::Magnitude(dragged->p[0], dragged->p[1]); + } + } + + if (dragged->type == OTCircle) + { + // Save for informative text, uh, er, informing + dragged->length = dragged->radius[0]; + } + return; } @@ -1436,13 +1823,23 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) // Do object hit testing... bool needUpdate = HitTestObjects(point); - GetHovered(hover); +// GetHovered(hover); + std::vector hover2 = GetHovered(); +{ +if (needUpdate) +{ + printf("mouseMoveEvent:: numHovered=%li, hover2.size()=%li\n", numHovered, hover2.size()); + + if (hover2.size() > 0) + printf(" (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]); +} +} // Check for multi-hover... if (numHovered > 1) { //need to check for case where hover is over 2 circles and a 3rd's center... - Object * obj1 = (Object *)hover[0], * obj2 = (Object *)hover[1]; + Object * obj1 = (Object *)hover2[0], * obj2 = (Object *)hover2[1]; Geometry::Intersects(obj1, obj2); int numIntersecting = Global::numIntersectParams; @@ -1480,6 +1877,29 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) intersectionPoint = v1; } } + else if (numHovered == 1) + { + Object * obj = (Object *)hover2[0]; + + if (obj->type == OTLine) + { +/* +Not sure that this is the best way to handle this, but it works(TM)... +Except when lines are overlapping, then it doesn't work... !!! FIX !!! +*/ + Point midpoint = Geometry::Midpoint((Line *)obj); + Vector v1 = Vector::Magnitude(midpoint, point); + + if ((v1.Magnitude() * Global::zoom) < 8.0) + { + QString text = tr("Midpoint <%1, %2>"); + informativeText = text.arg(midpoint.x).arg(midpoint.y); + hoverPointValid = true; + hoverPoint = midpoint; + needUpdate = true; + } + } + } // Handle object movement (left button down & over an object) if ((event->buttons() & Qt::LeftButton) && draggingObject && !Global::tool) @@ -1549,7 +1969,7 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event) // Should we be doing this automagically? Hmm... // Clear our vectors select.clear(); - hover.clear(); +// hover.clear(); // Scoop 'em up std::vector::iterator i; @@ -1624,7 +2044,6 @@ void DrawingView::keyPressEvent(QKeyEvent * event) { scrollDrag = true; setCursor(Qt::SizeAllCursor); -// oldPoint = Vector(); oldPoint = oldScrollPoint; } @@ -1869,7 +2288,8 @@ void DrawingView::CheckObjectBounds(void) bounds = bounds.normalized(); #endif - // If the end of the arc is before the beginning, add 360 degrees to it + // If the end of the arc is before the beginning, add 360 degrees + // to it if (end < start) end += TAU; @@ -1916,9 +2336,19 @@ void DrawingView::CheckObjectBounds(void) break; } - default: + case OTContainer: + { + Container * c = (Container *)obj; + + if (Global::selection.contains(c->p[0].x, c->p[0].y) && Global::selection.contains(c->p[1].x, c->p[1].y)) + c->selected = true; + break; } + +// default: +// break; + } } } @@ -1938,14 +2368,14 @@ bool DrawingView::HitTestObjects(Point point) if (draggingObject && (obj == dragged)) continue; - if (HitTest(obj, point)) + if (HitTest(obj, point) == true) needUpdate = true; if (obj->hovered) { numHovered++; //printf("MouseMove: OBJECT HOVERED (numHovered = %i)\n", numHovered); - emit(ObjectHovered(obj)); + emit ObjectHovered(obj); } } @@ -2121,7 +2551,6 @@ bool DrawingView::HitTest(Object * obj, Point point) else if ((hCS2Point.Magnitude() * Global::zoom) < 8.0) obj->hitPoint[4] = true; -// return (hitPoint1 || hitPoint2 || hitLine || hitFlipSwitch || hitChangeSwitch1 || hitChangeSwitch2 ? true : false); obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject ? true : false); if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHP3 != obj->hitPoint[3]) || (oldHP4 != obj->hitPoint[4]) || (oldHO != obj->hitObject)) @@ -2152,24 +2581,70 @@ bool DrawingView::HitTest(Object * obj, Point point) case OTContainer: { - // Containers must be recursively tested... + // Containers must be recursively tested... Or do they??? +/* +So the idea here is to flatten the structure, *then* test the objects within. Flattening includes the Containers as well; we can do this because it's pointers all the way down. +*/ +// bool oldHitObj = c->hitObject, oldHovered = c->hovered; +// Object * oldClicked = c->clicked; +/* +still need to compare old state to new state, and set things up based upon that... +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; - std::vector::iterator i; + c->clicked = NULL; - for(i=c->objects.begin(); i!=c->objects.end(); i++) + std::vector flat = Flatten(c); + +//printf("HitTest::OTContainer (size=%li)\n", flat.size()); + for(std::vector::iterator i=flat.begin(); i!=flat.end(); i++) { - Object * cObj = (Object *)*i; + Object * cObj = (Object *)(*i); + + // Skip the flattened containers (if any)... + if (cObj->type == OTContainer) + continue; - if (HitTest(cObj, point)) + // We do it this way instead of needUpdate = HitTest() because we + // are checking more than one object, and that way of doing will + // not return consistent results. + if (HitTest(cObj, point) == true) +// { +//printf("HitTest::OTContainer, subobj ($%llX) hit!\n", cObj); needUpdate = true; +// c->hitObject = true; +// c->clicked = cObj; +// c->hovered = true; +// } + // Same reasons for doing it this way here apply. if (cObj->hitObject == true) + { +//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj); c->hitObject = true; + c->clicked = cObj; + }//*/ + + if (cObj->hitPoint[0] == true) + { +//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj); + c->hitPoint[0] = true; + c->clicked = cObj; + }//*/ + + if (cObj->hitPoint[1] == true) + { +//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj); + c->hitPoint[1] = true; + c->clicked = cObj; + }//*/ if (cObj->hovered == true) - c->hovered = true; + c->hovered = true;//*/ } break; @@ -2240,9 +2715,27 @@ void DrawingView::HandleObjectMovement(Point point) { case OTLine: if (obj->hitPoint[0]) + { + if (Global::fixedLength) + { + Vector line = point - obj->p[1]; + Vector unit = line.Unit(); + point = obj->p[1] + (unit * obj->length); + } + obj->p[0] = point; + } else if (obj->hitPoint[1]) + { + if (Global::fixedLength) + { + Vector line = point - obj->p[0]; + Vector unit = line.Unit(); + point = obj->p[0] + (unit * obj->length); + } + obj->p[1] = point; + } else if (obj->hitObject) { obj->p[0] += delta; @@ -2256,12 +2749,11 @@ void DrawingView::HandleObjectMovement(Point point) obj->p[0] = point; else if (obj->hitObject) { -//this doesn't work. we need to save this on mouse down for this to work correctly! -// double oldRadius = obj->radius[0]; + double oldRadius = obj->length; obj->radius[0] = Vector::Magnitude(obj->p[0], point); - QString text = QObject::tr("Radius: %1");//\nScale: %2%"); - informativeText = text.arg(obj->radius[0], 0, 'd', 4);//.arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0); + QString text = QObject::tr("Radius: %1\nScale: %2%"); + informativeText = text.arg(obj->radius[0], 0, 'd', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0); } break; @@ -2357,7 +2849,11 @@ void DrawingView::HandleObjectMovement(Point point) case OTContainer: // This is shitty, but works for now until I can code up something // nicer :-) - TranslateObject(obj, delta); +/* +The idea is to make it so whichever point on the object in question is being dragged becomes the snap point for the container; shouldn't be too difficult to figure out how to do this. +*/ +// TranslateObject(obj, delta); + TranslateContainer((Container *)obj, point, delta); break; default: @@ -2365,3 +2861,24 @@ void DrawingView::HandleObjectMovement(Point point) } } + +void DrawingView::AddDimensionTo(void * o) +{ + Object * obj = (Object *)o; + + switch (obj->type) + { + case OTLine: + document.Add(new Dimension(obj->p[0], obj->p[1])); + break; + case OTCircle: + break; + case OTEllipse: + break; + case OTArc: + break; + case OTSpline: + break; + } +} +