From bf5a50feb0f84a4627a65c5b82c3ca2d2eefe54b Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Thu, 28 May 2020 20:22:57 -0500 Subject: [PATCH] GUI functionality fixes. - 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, 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. --- TODO | 10 +- res/architektonas.qrc | 1 + res/pen-stamp.png | Bin 0 -> 2277 bytes src/applicationwindow.cpp | 29 +++- src/applicationwindow.h | 2 + src/drawingview.cpp | 205 +++++++++++++++----------- src/drawingview.h | 16 +- src/geometry.cpp | 23 +++ src/geometry.h | 1 + src/global.cpp | 6 +- src/global.h | 10 +- src/painter.cpp | 6 +- src/penwidget.cpp | 16 ++ src/penwidget.h | 2 + src/structs.h | 3 +- src/utils.cpp | 299 ++++++++++++++++++++++++++++---------- src/utils.h | 33 +++-- src/vector.cpp | 2 +- 18 files changed, 462 insertions(+), 202 deletions(-) create mode 100644 res/pen-stamp.png diff --git a/TODO b/TODO index d5ea1c7..4409438 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ + Stuff To Be Implemented/Fixed ----------------------------- @@ -6,10 +7,6 @@ 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 @@ -31,6 +28,10 @@ Stuff To Be Implemented/Fixed 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] @@ -45,4 +46,3 @@ Stuff That's Done - Mirror tool (started, needs actual mirroring implementation) (Rotate tool is also done :-D) [Shamus 2013-09-01] - diff --git a/res/architektonas.qrc b/res/architektonas.qrc index 16283e4..a0ae553 100644 --- a/res/architektonas.qrc +++ b/res/architektonas.qrc @@ -43,5 +43,6 @@ editcut2.png editcopy2.png editpaste2.png + pen-stamp.png diff --git a/res/pen-stamp.png b/res/pen-stamp.png new file mode 100644 index 0000000000000000000000000000000000000000..7afa68e9323e1639165034bf9a162a033b1a2672 GIT binary patch literal 2277 zcmVEX>4Tx04R}tkv&MmKpe$iQ;Q-M2Q!E|1guULL`5963Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4P#IXWr2NQwVz3N2zhIPS;0dyl(!fKV$j-R>9%bi=Wd z@tBm(tV*4)2w@NcL<}p;Hs@qH0pIa;j{slqqCCt0+@GUI%i0VGNW`f6M;^|Gt z($qcRatG*tG8Ic{NI{xHE(g4y(Kls)zFVMs&FihXkJASrMO`IsfP+I| zG*8*NRD!r!AVc700006VoOIv04xAu05=TUePRFr010qNS#tmY z3ljhU3ljkVnw%H_000McNlirueSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00zBDL_t(|+U=WNY!p=#$A5R(U0c}FqNR#}1;n6%7y|-| z(eQvT#s`g2jEOI5A~7)(NhC%MX#6IE_yHF1t9+HVu2p3XPv2i5jX0%i`+zrr z({YSN0n`=%7-PDDr+_lB3|J*ep9KbieqaO`2bTLDJt)Rc0^2+gqSl)ggr)+Z{k{cw z1E>PmN##qD__aW{w_bgg0@M5eya&8!t*xaold5Lm3Qhk+^mKP`iJ0$3C= z%}E)|jn>)&c>~bwK&VfWT_Q$HVtkqY?$Y;*V&*sq{0Y1uThbYkpfP44@U9G75il92 zS_1qf+fnX_NKku!J#dwz-3Tq0-RN${dYh#IR|2oe@Z~`(6(H5}4v3lsfFr~9c@A?8 zYrX+(r;bR5%F==-a+s?d_zXA$oNFXkXr%_62fof}t`cxH@Qk%~yd^fk7<19c0Kh9b zt?^gj9mNBwvdttseY zqyZ`C8;p^3*!Tmu2k6cs{g!D!3Xq44G5rZF`EjZJ@4y~wZMCV=r-fy4Ywaod^Dr8b z%AW!rR1VRaQeD;(Q`YjdF=mx&1pUeoi>eQF`S$xdX+i9Kah2ty6{6fVATH=ome>!> z)#y@qTN4r?V z+?>TNgm%g2dvQabDnRudg0c27fIPG|Mblt9-4bfG z1{8oBQ)J-)c_QMTXAdsRiFFw(;j(HTT<^R5p^jMng={* zj9F-mDR?77x&?2fb%(`fGw)N`GVq8Jq75_L-iuob2iOk0ihG8jZj3qXizU23YJ~u( z1BZ<Ly(Q~Ii;`S3C z0`3C-&I5o7@Tj(ocZk75e82qpAxZhTRDBa}X?&dw+a^hDDy54%BQT1+On@BtUj@Z9Z-;fM8Emcg0C?c}x#O=-LA1a<(mFkWYp#3XK8Y720Kq*n+S zBP88+qY2-Z%^U|*ftP^q0?c;;6@eo@cbOajU*J-ZkL@L8YpM;X3|ynAvl!*V3kgu% z?6bn1L{$N>iwg%aQv=WgJgJHLIt&2sH0s(o;U%#FU&zPTI}Cu5jPr)LxFZyRabp-a zhB4Q@Z38|e#qpFjA&c8u{}QN;Cuxs+jE79L6?nVDv|t3cx3JpNfH3}&7`Cz^xo)|X zPH}}t6uCY&=0=6_8W2RLVl5Tdb&TVl_d5}1P1}sl0$%~Y0i%_G3-t3ED$T$H4)C#J z|FWXP(Kcp&9QYpiMTyWv2u~O10)A8~7k7EQmey|Vsj4!-UTMZ)hW&X;b%C0~>IvLp zsUy2nk_)Q{@RFE1ufLaT4JF)DB-5H}FYvmw;D0~72;(sk0N(W;x4XL?xJ?<~An>gg z;V1>INwcPL&-P3!9-oI>|2NViN2&7^?vEq9hKZl%>e=%Gs}4M%w0obDos$A@uijrB zgIW|1i2w+K;J?=6GSUa!uUdcuJT0d8a-q#t*FJQ7(|YBsx-V@daL-Jk`x@NV*{GiL z=5odYUMh-*PyoViin9-@`ZzvG5fUpnA$fg6^+&Jj6lnlb@Q|q}>RVhbV0c;+-NZ1T zsa|Pk*eh{%p`9ry59abuXJselect.size() > 0) { DeleteContents(clipboard); - CopySelectedObjectsTo(clipboard, drawing->document.objects); + clipboard = CopySelectedObjects(drawing->document.objects); } } @@ -731,7 +731,7 @@ void ApplicationWindow::EditCut(void) if (drawing->select.size() > 0) { DeleteContents(clipboard); - MoveSelectedObjectsTo(clipboard, drawing->document.objects); + clipboard = MoveSelectedObjectsFrom(drawing->document.objects); drawing->update(); } } @@ -742,14 +742,26 @@ void ApplicationWindow::EditPaste(void) 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."), @@ -844,6 +856,9 @@ void ApplicationWindow::CreateActions(void) 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); @@ -919,6 +934,7 @@ void ApplicationWindow::CreateMenus(void) menu->addAction(connectAct); menu->addAction(disconnectAct); menu->addSeparator(); + menu->addAction(selectAllAct); menu->addAction(editCutAct); menu->addAction(editCopyAct); menu->addAction(editPasteAct); @@ -999,6 +1015,7 @@ void ApplicationWindow::CreateToolbars(void) 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))); } diff --git a/src/applicationwindow.h b/src/applicationwindow.h index d10e4dd..0bd3581 100644 --- a/src/applicationwindow.h +++ b/src/applicationwindow.h @@ -53,6 +53,7 @@ class ApplicationWindow: public QMainWindow void EditCut(void); void EditCopy(void); void EditPaste(void); + void SelectAllObjects(void); signals: void ReloadLayers(void); @@ -108,6 +109,7 @@ class ApplicationWindow: public QMainWindow QAction * editCutAct; QAction * editCopyAct; QAction * editPasteAct; + QAction * selectAllAct; std::vector clipboard; diff --git a/src/drawingview.cpp b/src/drawingview.cpp index 842c5b3..de356d2 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -48,7 +48,7 @@ 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), @@ -239,7 +239,7 @@ zero; so we do another modulus operation on the result to achieve this. void DrawingView::DeleteCurrentLayer(int layer) { //printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer); - std::vector::iterator i = document.objects.begin(); + VPVectorIter i = document.objects.begin(); while (i != document.objects.end()) { @@ -277,10 +277,9 @@ void DrawingView::HandleLayerToggle(void) // 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::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); @@ -294,9 +293,7 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2) void DrawingView::HandlePenWidth(float width) { - std::vector::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; @@ -306,9 +303,7 @@ void DrawingView::HandlePenWidth(float width) void DrawingView::HandlePenStyle(int style) { - std::vector::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; @@ -318,9 +313,7 @@ void DrawingView::HandlePenStyle(int style) void DrawingView::HandlePenColor(uint32_t color) { - std::vector::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; @@ -328,6 +321,25 @@ void DrawingView::HandlePenColor(uint32_t 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 @@ -416,11 +428,9 @@ N.B.: Since we have "hoverPointValid" drawing regular object handles above, !!! 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*/) +void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool ignoreLayer/*= false*/) { - std::vector::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; @@ -541,10 +551,10 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int 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); @@ -599,6 +609,9 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v, int 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) @@ -699,24 +712,25 @@ printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), } +// +// This toggles the selection being hovered (typically, only 1 object) +// void DrawingView::AddHoveredToSelection(void) { - std::vector::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 & v) +void DrawingView::GetSelection(VPVector & v) { v.clear(); - std::vector::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); @@ -724,36 +738,28 @@ void DrawingView::GetSelection(std::vector & v) } -#if 0 -void DrawingView::GetHovered(std::vector & v) +VPVector DrawingView::GetSelection(void) { - v.clear(); - std::vector::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 DrawingView::GetHovered(void) +VPVector DrawingView::GetHovered(void) { - std::vector v; - std::vector::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; @@ -1152,9 +1158,9 @@ void DrawingView::RotateHandler(int mode, Point p) angleSnap = true; double angle = Vector(toolPoint[0], toolPoint[1]).Angle(); - std::vector::iterator j = select.begin(); + VPVectorIter j = select.begin(); // std::vector::iterator i = toolScratch.begin(); - std::vector::iterator i = toolScratch2.begin(); + VPVectorIter i = toolScratch2.begin(); // for(; i!=toolScratch.end(); i++, j++) for(; i!=toolScratch2.end(); i++, j++) @@ -1187,10 +1193,10 @@ void DrawingView::RotateHandler(int mode, Point p) // Container * c = (Container *)&objT; Container * c = (Container *)objT; Container * c2 = (Container *)objS; - std::vector::iterator l = c->objects.begin(); + VPVectorIter 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++) + for(VPVectorIter k=c2->objects.begin(); k!=c2->objects.end(); k++, l++) { Object * obj3 = (Object *)(*k); Object * obj4 = (Object *)(*l); @@ -1235,7 +1241,7 @@ void DrawingView::RotateHandler(int mode, Point p) if (ctrlDown) { // Stamp a copy of the selection at the current rotation & bail - std::vector temp; + VPVector temp; CopyObjects(select, temp); ClearSelected(temp); AddObjectsTo(document.objects, temp); @@ -1306,7 +1312,7 @@ void DrawingView::MirrorHandler(int mode, Point p) angleSnap = true; double angle = Vector(toolPoint[0], toolPoint[1]).Angle(); - std::vector::iterator j = select.begin(); + VPVectorIter j = select.begin(); std::vector::iterator i = toolScratch.begin(); for(; i!=toolScratch.end(); i++, j++) @@ -1355,7 +1361,7 @@ N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have if (ctrlDown) { // Stamp a copy of the selection at the current rotation & bail - std::vector temp; + VPVector temp; CopyObjects(select, temp); ClearSelected(temp); AddObjectsTo(document.objects, temp); @@ -1444,7 +1450,7 @@ void DrawingView::TriangulateHandler(int mode, Point/*p*/) if (numHovered != 1) break; - std::vector hover = GetHovered(); + VPVector hover = GetHovered(); Object * obj = (Object *)hover[0]; // Skip if it's not a line... @@ -1613,7 +1619,7 @@ n.b.: this code is lifted straight out of the old oo code. needs to be updated. return; } - std::vector hover = GetHovered(); + VPVector hover = GetHovered(); Object * obj = (Object *)hover[0]; // Skip if it's not a line... @@ -1628,7 +1634,7 @@ n.b.: this code is lifted straight out of the old oo code. needs to be updated. // 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; + VPVectorIter i; for(i=document.objects.begin(); i!=document.objects.end(); i++) { obj = (Object *)(*i); @@ -1692,7 +1698,7 @@ void DrawingView::mousePressEvent(QMouseEvent * event) { 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 @@ -1727,10 +1733,10 @@ printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered); AddHoveredToSelection(); update(); // needed?? // GetHovered(hover); // prolly needed - std::vector 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); @@ -1770,10 +1776,12 @@ printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", 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) { @@ -1817,14 +1825,19 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) 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 hover2 = GetHovered(); + VPVector hover2 = GetHovered(); +#if 0 { if (needUpdate) { @@ -1834,6 +1847,7 @@ if (needUpdate) printf(" (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]); } } +#endif // Check for multi-hover... if (numHovered > 1) @@ -1962,23 +1976,17 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event) 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::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; } @@ -2000,12 +2008,18 @@ void DrawingView::wheelEvent(QWheelEvent * event) // 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; @@ -2032,6 +2046,8 @@ void DrawingView::keyPressEvent(QKeyEvent * event) 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) @@ -2210,7 +2226,7 @@ Rect DrawingView::GetObjectExtents(Object * obj) case OTContainer: { Container * c = (Container *)obj; - std::vector::iterator i = c->objects.begin(); + VPVectorIter i = c->objects.begin(); rect = GetObjectExtents((Object *)*i); i++; @@ -2228,7 +2244,7 @@ Rect DrawingView::GetObjectExtents(Object * obj) void DrawingView::CheckObjectBounds(void) { - std::vector::iterator i; + VPVectorIter i; for(i=document.objects.begin(); i!=document.objects.end(); i++) { @@ -2355,7 +2371,7 @@ void DrawingView::CheckObjectBounds(void) bool DrawingView::HitTestObjects(Point point) { - std::vector::iterator i; + VPVectorIter i; numHovered = 0; bool needUpdate = false; hoverPointValid = false; @@ -2514,8 +2530,13 @@ bool DrawingView::HitTest(Object * obj, Point point) 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); @@ -2592,16 +2613,15 @@ 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; c->clicked = NULL; - std::vector flat = Flatten(c); + VPVector flat = Flatten(c); //printf("HitTest::OTContainer (size=%li)\n", flat.size()); - for(std::vector::iterator i=flat.begin(); i!=flat.end(); i++) + for(VPVectorIter i=flat.begin(); i!=flat.end(); i++) { Object * cObj = (Object *)(*i); @@ -2643,6 +2663,13 @@ Well, you could if there was only one object in the Container. But since there 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;//*/ } @@ -2834,8 +2861,24 @@ void DrawingView::HandleObjectMovement(Point point) 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; diff --git a/src/drawingview.h b/src/drawingview.h index 768c5c0..7e5a9d1 100644 --- a/src/drawingview.h +++ b/src/drawingview.h @@ -22,11 +22,11 @@ class DrawingView: public QWidget void UpdateGridBackground(void); Point SnapPointToGrid(Point); Point SnapPointToAngle(Point); - void RenderObjects(Painter *, std::vector &, int, bool ignoreLayer = false); + void RenderObjects(Painter *, VPVector &, int, bool ignoreLayer = false); void AddHoveredToSelection(void); - void GetSelection(std::vector &); -// void GetHovered(std::vector &); - std::vector GetHovered(void); + void GetSelection(VPVector &); + VPVector GetSelection(void); + VPVector GetHovered(void); void ToolHandler(int, Point); void ToolDraw(Painter *); void LineHandler(int, Point); @@ -53,6 +53,7 @@ class DrawingView: public QWidget void HandlePenWidth(float); void HandlePenStyle(int); void HandlePenColor(uint32_t); + void HandlePenStamp(void); signals: void ObjectHovered(Object *); @@ -95,11 +96,10 @@ class DrawingView: public QWidget QString informativeText; public: - std::vector select; -// std::vector hover; - std::vector toolObjects; + VPVector select; + VPVector toolObjects; std::vector toolScratch; - std::vector toolScratch2; + VPVector toolScratch2; Point toolPoint[32]; Object * toolObj[32]; Point intersectionPoint; diff --git a/src/geometry.cpp b/src/geometry.cpp index 4cd229f..95d12c6 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -39,6 +39,29 @@ double Geometry::ParameterOfLineAndPoint(Point tail, Point head, Point point) } +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 diff --git a/src/geometry.h b/src/geometry.h index 41cd472..bc532da 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -9,6 +9,7 @@ class Geometry 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); diff --git a/src/global.cpp b/src/global.cpp index 6dfbd90..7a7cc9b 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -49,6 +49,6 @@ int Global::numIntersectParams = 0; int Global::activeLayer = 0; int Global::numLayers = 1; -std::vector Global::layerHidden; -std::vector Global::layerLocked; -std::vector Global::layerName; +BVector Global::layerHidden; +BVector Global::layerLocked; +SVector Global::layerName; diff --git a/src/global.h b/src/global.h index cdcd204..93ad6f7 100644 --- a/src/global.h +++ b/src/global.h @@ -14,6 +14,10 @@ class QFont; enum LineStyle { LSNone, LSSolid, LSDash, LSDot, LSDashDot, LSDashDotDot }; +typedef std::vector VPVector; +typedef std::vector::iterator VPVectorIter; +typedef std::vector BVector; +typedef std::vector SVector; class Global { @@ -56,9 +60,9 @@ class Global static int activeLayer; static int numLayers; - static std::vector layerHidden; - static std::vector layerLocked; - static std::vector layerName; + static BVector layerHidden; + static BVector layerLocked; + static SVector layerName; }; #endif // __GLOBALS_H__ diff --git a/src/painter.cpp b/src/painter.cpp index 16edb26..6cb74ea 100644 --- a/src/painter.cpp +++ b/src/painter.cpp @@ -139,13 +139,15 @@ void Painter::DrawAngledText(Vector center, double angle, QString text, double s // 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); diff --git a/src/penwidget.cpp b/src/penwidget.cpp index 2a557e3..4bd966a 100644 --- a/src/penwidget.cpp +++ b/src/penwidget.cpp @@ -29,6 +29,14 @@ PenWidget::PenWidget(void): QWidget(), r(0), g(0), b(0), programChange(false) 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")); @@ -63,6 +71,7 @@ PenWidget::PenWidget(void): QWidget(), r(0), g(0), b(0), programChange(false) 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); @@ -72,6 +81,7 @@ PenWidget::PenWidget(void): QWidget(), r(0), g(0), b(0), programChange(false) 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 *))); } @@ -175,3 +185,9 @@ void PenWidget::HandleBlueSelected(QString text) emit ColorSelected(Global::penColor); } + +void PenWidget::HandleStamp(QAction * /* action */) +{ + emit StampSelected(); +} + diff --git a/src/penwidget.h b/src/penwidget.h index 11dcdcf..5809c44 100644 --- a/src/penwidget.h +++ b/src/penwidget.h @@ -22,11 +22,13 @@ class PenWidget: public QWidget 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; diff --git a/src/structs.h b/src/structs.h index 5f69488..bef3c52 100644 --- a/src/structs.h +++ b/src/structs.h @@ -128,13 +128,14 @@ struct Spline { struct Container { OBJECT_COMMON; - std::vector 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) { diff --git a/src/utils.cpp b/src/utils.cpp index 98902d7..b9ca463 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -12,6 +12,7 @@ // #include "utils.h" +#include #include // For memcpy() #include "geometry.h" @@ -20,9 +21,9 @@ // 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 & from, std::vector & to) +void CopyObjects(VPVector & from, VPVector & to) { - for(std::vector::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); @@ -31,6 +32,20 @@ void CopyObjects(std::vector & from, std::vector & to) } +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. // @@ -60,12 +75,10 @@ Object * CopyObject(Object * obj) 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)); @@ -77,6 +90,7 @@ Object * CopyObject(Object * obj) // 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: @@ -91,9 +105,72 @@ Object * CopyObject(Object * obj) } -void MoveSelectedObjectsTo(std::vector & dest, std::vector & 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::iterator i = from.begin(); + VPVectorIter i = from.begin(); while (i != from.end()) { @@ -110,45 +187,83 @@ void MoveSelectedObjectsTo(std::vector & dest, std::vector & fro } +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 & dest, std::vector & from) +void CopySelectedObjectsTo(VPVector & dest, VPVector & from) { - for(std::vector::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 & dest, std::vector & from) +VPVector CopySelectedObjects(VPVector & src) { - for(std::vector::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 & v) +void AddObjectsTo(VPVector & dest, VPVector & from) { - std::vector::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 & v) +// +// Select all *visible* objects. If an object's layer is invisible, skip it. +// +void SelectAll(VPVector & v) { - std::vector::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; + } } @@ -160,11 +275,9 @@ void SelectAll(std::vector & v) // have to keep track of that stuff ourselves. :-P Believe it or not, this is // a Good Thing(TM). ;-) // -void DeleteContents(std::vector & v) +void DeleteContents(VPVector & v) { - std::vector::iterator i; - - for(i=v.begin(); i!=v.end(); i++) + for(VPVectorIter i=v.begin(); i!=v.end(); i++) { Object * obj = (Object *)(*i); @@ -178,9 +291,9 @@ void DeleteContents(std::vector & v) } -void DeleteSelectedObjects(std::vector & v) +void DeleteSelectedObjects(VPVector & v) { - std::vector::iterator i = v.begin(); + VPVectorIter i = v.begin(); while (i != v.end()) { @@ -201,9 +314,9 @@ void DeleteSelectedObjects(std::vector & v) // This is used to remove selected objects from one container in order to move // them to a different container. // -void RemoveSelectedObjects(std::vector & v) +void RemoveSelectedObjects(VPVector & v) { - std::vector::iterator i = v.begin(); + VPVectorIter i = v.begin(); while (i != v.end()) { @@ -217,12 +330,12 @@ void RemoveSelectedObjects(std::vector & v) } -void SavePointsFrom(std::vector & v, std::vector & save) +void SavePointsFrom(VPVector & v, std::vector & save) { save.clear(); Object o; - for(std::vector::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); @@ -230,12 +343,12 @@ void SavePointsFrom(std::vector & v, std::vector & save) } -void RestorePointsTo(std::vector & v, std::vector & s) +void RestorePointsTo(VPVector & v, std::vector & s) { - std::vector::iterator i = s.begin(); - std::vector::iterator j = v.begin(); + std::vector::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]; @@ -248,12 +361,9 @@ void RestorePointsTo(std::vector & v, std::vector & s) } -void RestorePointsTo(std::vector & v, std::vector & s) +void RestorePointsTo(VPVector & v, VPVector & s) { - std::vector::iterator i = s.begin(); - std::vector::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); @@ -274,21 +384,22 @@ void RestorePointsTo(std::vector & v, std::vector & s) } +// +// 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::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; } @@ -298,14 +409,16 @@ So we need to make it so that we pick the container's point clicked on, and tran 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) { @@ -315,6 +428,7 @@ printf("TranslateContainer: boop (%i)\n", i++); 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; @@ -322,12 +436,21 @@ printf("TranslateContainer: boop (%i)\n", i++); 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: @@ -342,41 +465,61 @@ printf("TranslateContainer: boop (%i)\n", i++); } -void TranslateObjects(std::vector & 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::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::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 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 flat; - std::vector::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); @@ -384,7 +527,7 @@ std::vector Flatten(Container * src) // Recursively add objects to the flat vector, if necessary if (obj->type == OTContainer) { - std::vector sub = Flatten((Container *)obj); + VPVector sub = Flatten(((Container *)obj)->objects); flat.insert(flat.end(), sub.begin(), sub.end()); } } diff --git a/src/utils.h b/src/utils.h index a72ca39..6fd59d0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -4,22 +4,27 @@ #include #include "structs.h" -void CopyObjects(std::vector & from, std::vector & to); +void CopyObjects(VPVector & from, VPVector & to); +VPVector CopyObjects(VPVector & from); Object * CopyObject(Object * obj); -void MoveSelectedObjectsTo(std::vector & dest, std::vector & from); -void CopySelectedObjectsTo(std::vector & dest, std::vector & from); -void AddObjectsTo(std::vector & dest, std::vector & from); -void ClearSelected(std::vector & v); -void SelectAll(std::vector & v); -void DeleteContents(std::vector & v); -void DeleteSelectedObjects(std::vector & v); -void RemoveSelectedObjects(std::vector & v); -void SavePointsFrom(std::vector & v, std::vector & s); -void RestorePointsTo(std::vector & v, std::vector & s); -void RestorePointsTo(std::vector & v, std::vector & 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 & s); +void RestorePointsTo(VPVector & v, std::vector & 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 & v, Point delta); -std::vector Flatten(Container * src); +void TranslateObjects(VPVector & v, Point delta); +VPVector Flatten(Container * src); +VPVector Flatten(VPVector src); #endif // __UTILS_H__ diff --git a/src/vector.cpp b/src/vector.cpp index 20b8ef5..57f49fb 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -205,7 +205,7 @@ Vector Vector::Unit(void) double Vector::Magnitude(void) { - return sqrt(x * x + y * y + z * z); + return sqrt((x * x) + (y * y) + (z * z)); } -- 2.37.2