void GraphicsWindow::Init(void) { scale = 5; offset = Vector::From(0, 0, 0); projRight = Vector::From(1, 0, 0); projUp = Vector::From(0, 1, 0); // Make sure those are valid; could get a mouse move without a mouse // down if someone depresses the button, then drags into our window. orig.projRight = projRight; orig.projUp = projUp; // And with the last group active activeGroup = SK.groupOrder.elem[SK.groupOrder.n - 1]; SK.GetGroup(activeGroup)->Activate(); showWorkplanes = false; showNormals = true; showPoints = true; showConstraints = true; showHdnLines = false; showShaded = true; showEdges = true; showMesh = false; showOutlines = false; showTextWindow = true; ShowTextWindow(showTextWindow); showSnapGrid = false; context.active = false; // Do this last, so that all the menus get updated correctly. ClearSuper(); }
void GraphicsWindow::DeleteTaggedRequests(void) { // Rewrite any point-coincident constraints that were affected by this // deletion. Request *r; for(r = SK.request.First(); r; r = SK.request.NextAfter(r)) { if(!r->tag) continue; FixConstraintsForRequestBeingDeleted(r->h); } // and then delete the tagged requests. SK.request.RemoveTagged(); // An edit might be in progress for the just-deleted item. So // now it's not. HideGraphicsEditControl(); SS.TW.HideEditControl(); // And clear out the selection, which could contain that item. ClearSuper(); // And regenerate to get rid of what it generates, plus anything // that references it (since the regen code checks for that). SS.GenerateAll(SolveSpaceUI::GENERATE_ALL); EnsureValidActives(); SS.ScheduleShowTW(); }
void TextWindow::Init(void) { ClearSuper(); }
void GraphicsWindow::MouseLeftDown(double mx, double my) { orig.mouseDown = true; if(GraphicsEditControlIsVisible()) { orig.mouse = Point2d::From(mx, my); orig.mouseOnButtonDown = orig.mouse; HideGraphicsEditControl(); return; } SS.TW.HideEditControl(); if(SS.showToolbar) { if(ToolbarMouseDown((int)mx, (int)my)) return; } // Make sure the hover is up to date. MouseMoved(mx, my, false, false, false, false, false); orig.mouse.x = mx; orig.mouse.y = my; orig.mouseOnButtonDown = orig.mouse; // The current mouse location Vector v = offset.ScaledBy(-1); v = v.Plus(projRight.ScaledBy(mx/scale)); v = v.Plus(projUp.ScaledBy(my/scale)); hRequest hr; switch(pending.operation) { case MNU_DATUM_POINT: hr = AddRequest(Request::DATUM_POINT); SK.GetEntity(hr.entity(0))->PointForceTo(v); ConstrainPointByHovered(hr.entity(0)); ClearSuper(); break; case MNU_LINE_SEGMENT: hr = AddRequest(Request::LINE_SEGMENT); SK.GetEntity(hr.entity(1))->PointForceTo(v); ConstrainPointByHovered(hr.entity(1)); ClearSuper(); pending.operation = DRAGGING_NEW_LINE_POINT; pending.point = hr.entity(2); pending.description = "click next point of line, or press Esc"; SK.GetEntity(pending.point)->PointForceTo(v); break; case MNU_RECTANGLE: { if(!SS.GW.LockedInWorkplane()) { Error("Can't draw rectangle in 3d; select a workplane first."); ClearSuper(); break; } hRequest lns[4]; int i; SS.UndoRemember(); for(i = 0; i < 4; i++) { lns[i] = AddRequest(Request::LINE_SEGMENT, false); } for(i = 0; i < 4; i++) { Constraint::ConstrainCoincident( lns[i].entity(1), lns[(i+1)%4].entity(2)); SK.GetEntity(lns[i].entity(1))->PointForceTo(v); SK.GetEntity(lns[i].entity(2))->PointForceTo(v); } for(i = 0; i < 4; i++) { Constraint::Constrain( (i % 2) ? Constraint::HORIZONTAL : Constraint::VERTICAL, Entity::NO_ENTITY, Entity::NO_ENTITY, lns[i].entity(0)); } ConstrainPointByHovered(lns[2].entity(1)); pending.operation = DRAGGING_NEW_POINT; pending.point = lns[1].entity(2); pending.description = "click to place other corner of rectangle"; break; } case MNU_CIRCLE: hr = AddRequest(Request::CIRCLE); // Centered where we clicked SK.GetEntity(hr.entity(1))->PointForceTo(v); // Normal to the screen SK.GetEntity(hr.entity(32))->NormalForceTo( Quaternion::From(SS.GW.projRight, SS.GW.projUp)); // Initial radius zero SK.GetEntity(hr.entity(64))->DistanceForceTo(0); ConstrainPointByHovered(hr.entity(1)); ClearSuper(); pending.operation = DRAGGING_NEW_RADIUS; pending.circle = hr.entity(0); pending.description = "click to set radius"; break; case MNU_ARC: { if(!SS.GW.LockedInWorkplane()) { Error("Can't draw arc in 3d; select a workplane first."); ClearPending(); break; } hr = AddRequest(Request::ARC_OF_CIRCLE); // This fudge factor stops us from immediately failing to solve // because of the arc's implicit (equal radius) tangent. Vector adj = SS.GW.projRight.WithMagnitude(2/SS.GW.scale); SK.GetEntity(hr.entity(1))->PointForceTo(v.Minus(adj)); SK.GetEntity(hr.entity(2))->PointForceTo(v); SK.GetEntity(hr.entity(3))->PointForceTo(v); ConstrainPointByHovered(hr.entity(2)); ClearSuper(); pending.operation = DRAGGING_NEW_ARC_POINT; pending.point = hr.entity(3); pending.description = "click to place point"; break; } case MNU_CUBIC: hr = AddRequest(Request::CUBIC); SK.GetEntity(hr.entity(1))->PointForceTo(v); SK.GetEntity(hr.entity(2))->PointForceTo(v); SK.GetEntity(hr.entity(3))->PointForceTo(v); SK.GetEntity(hr.entity(4))->PointForceTo(v); ConstrainPointByHovered(hr.entity(1)); ClearSuper(); pending.operation = DRAGGING_NEW_CUBIC_POINT; pending.point = hr.entity(4); pending.description = "click next point of cubic, or press Esc"; break; case MNU_WORKPLANE: if(LockedInWorkplane()) { Error("Sketching in a workplane already; sketch in 3d before " "creating new workplane."); ClearSuper(); break; } hr = AddRequest(Request::WORKPLANE); SK.GetEntity(hr.entity(1))->PointForceTo(v); SK.GetEntity(hr.entity(32))->NormalForceTo( Quaternion::From(SS.GW.projRight, SS.GW.projUp)); ConstrainPointByHovered(hr.entity(1)); ClearSuper(); break; case MNU_TTF_TEXT: { if(!SS.GW.LockedInWorkplane()) { Error("Can't draw text in 3d; select a workplane first."); ClearSuper(); break; } hr = AddRequest(Request::TTF_TEXT); Request *r = SK.GetRequest(hr); r->str.strcpy("Abc"); r->font.strcpy("arial.ttf"); SK.GetEntity(hr.entity(1))->PointForceTo(v); SK.GetEntity(hr.entity(2))->PointForceTo(v); pending.operation = DRAGGING_NEW_POINT; pending.point = hr.entity(2); pending.description = "click to place bottom left of text"; break; } case MNU_COMMENT: { ClearSuper(); Constraint c; ZERO(&c); c.group = SS.GW.activeGroup; c.workplane = SS.GW.ActiveWorkplane(); c.type = Constraint::COMMENT; c.disp.offset = v; c.comment.strcpy("NEW COMMENT -- DOUBLE-CLICK TO EDIT"); Constraint::AddConstraint(&c); break; } case DRAGGING_RADIUS: case DRAGGING_NEW_POINT: // The MouseMoved event has already dragged it as desired. ClearPending(); break; case DRAGGING_NEW_ARC_POINT: ConstrainPointByHovered(pending.point); ClearPending(); break; case DRAGGING_NEW_CUBIC_POINT: { hRequest hr = pending.point.request(); Request *r = SK.GetRequest(hr); if(hover.entity.v == hr.entity(1).v && r->extraPoints >= 2) { // They want the endpoints coincident, which means a periodic // spline instead. r->type = Request::CUBIC_PERIODIC; // Remove the off-curve control points, which are no longer // needed here; so move [2,ep+1] down, skipping first pt. int i; for(i = 2; i <= r->extraPoints+1; i++) { SK.GetEntity(hr.entity((i-1)+1))->PointForceTo( SK.GetEntity(hr.entity(i+1))->PointGetNum()); } // and move ep+3 down by two, skipping both SK.GetEntity(hr.entity((r->extraPoints+1)+1))->PointForceTo( SK.GetEntity(hr.entity((r->extraPoints+3)+1))->PointGetNum()); r->extraPoints -= 2; // And we're done. SS.MarkGroupDirty(r->group); SS.ScheduleGenerateAll(); ClearPending(); break; } if(ConstrainPointByHovered(pending.point)) { ClearPending(); break; } Entity e; if(r->extraPoints >= (int)arraylen(e.point) - 4) { ClearPending(); break; } (SK.GetRequest(hr)->extraPoints)++; SS.GenerateAll(-1, -1); int ep = r->extraPoints; Vector last = SK.GetEntity(hr.entity(3+ep))->PointGetNum(); SK.GetEntity(hr.entity(2+ep))->PointForceTo(last); SK.GetEntity(hr.entity(3+ep))->PointForceTo(v); SK.GetEntity(hr.entity(4+ep))->PointForceTo(v); pending.point = hr.entity(4+ep); break; } case DRAGGING_NEW_LINE_POINT: { if(hover.entity.v) { Entity *e = SK.GetEntity(hover.entity); if(e->IsPoint()) { hRequest hrl = pending.point.request(); Entity *sp = SK.GetEntity(hrl.entity(1)); if(( e->PointGetNum()).Equals( (sp->PointGetNum()))) { // If we constrained by the hovered point, then we // would create a zero-length line segment. That's // not good, so just stop drawing. ClearPending(); break; } } } if(ConstrainPointByHovered(pending.point)) { ClearPending(); break; } // Create a new line segment, so that we continue drawing. hRequest hr = AddRequest(Request::LINE_SEGMENT); SK.GetEntity(hr.entity(1))->PointForceTo(v); // Displace the second point of the new line segment slightly, // to avoid creating zero-length edge warnings. SK.GetEntity(hr.entity(2))->PointForceTo( v.Plus(projRight.ScaledBy(0.5/scale))); // Constrain the line segments to share an endpoint Constraint::ConstrainCoincident(pending.point, hr.entity(1)); // And drag an endpoint of the new line segment pending.operation = DRAGGING_NEW_LINE_POINT; pending.point = hr.entity(2); pending.description = "click next point of line, or press Esc"; break; } case 0: default: ClearPending(); if(!hover.IsEmpty()) { hoverWasSelectedOnMousedown = IsSelected(&hover); MakeSelected(&hover); } break; } SS.ScheduleShowTW(); InvalidateGraphics(); }
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { if(GraphicsEditControlIsVisible()) return; SS.TW.HideEditControl(); if(hover.constraint.v) { constraintBeingEdited = hover.constraint; ClearSuper(); Constraint *c = SK.GetConstraint(constraintBeingEdited); if(!c->HasLabel()) { // Not meaningful to edit a constraint without a dimension return; } if(c->reference) { // Not meaningful to edit a reference dimension return; } Vector p3 = c->GetLabelPos(); Point2d p2 = ProjectPoint(p3); char s[1024]; switch(c->type) { case Constraint::COMMENT: strcpy(s, c->comment.str); break; case Constraint::ANGLE: case Constraint::LENGTH_RATIO: sprintf(s, "%.3f", c->valA); break; default: { double v = fabs(c->valA); // If displayed as radius, also edit as radius. if(c->type == Constraint::DIAMETER && c->disp.toggleA) v /= 2; char *def = SS.MmToString(v); double eps = 1e-12; if(fabs(SS.StringToMm(def) - v) < eps) { // Show value with default number of digits after decimal, // which is at least enough to represent it exactly. strcpy(s, def); } else { // Show value with as many digits after decimal as // required to represent it exactly, up to 10. v /= SS.MmPerUnit(); int i; for(i = 0; i <= 10; i++) { sprintf(s, "%.*f", i, v); if(fabs(atof(s) - v) < eps) break; } } break; } } ShowGraphicsEditControl((int)p2.x, (int)p2.y-4, s); } }