// drawingview.cpp
//
// Part of the Architektonas Project
-// (C) 2011 Underground Software
+// (C) 2011-2020 Underground Software
// See the README and GPLv3 files for licensing and warranty information
//
// JLH = James Hammons <jlhamm@acm.org>
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),
we do! :-)
*/
- SetGridSize(12); // This is in pixels
+ gridPixels = 12; //tmp
+ SetGridSize(12.0); // This is in pixels
+}
+
+
+void DrawingView::DrawBackground(Painter * painter)
+{
+ Point ul = Painter::QtToCartesianCoords(Vector(0, 0));
+ Point br = Painter::QtToCartesianCoords(Vector(Global::screenSize.x, Global::screenSize.y));
+
+ painter->SetBrush(0xF0F0F0);
+ painter->SetPen(0xF0F0F0, 1, 1);
+ painter->DrawRect(QRectF(QPointF(ul.x, ul.y), QPointF(br.x, br.y)));
+
+ double spacing = Global::gridSpacing;
+
+ if (spacing < 1.0)
+ spacing = 1.0;
+
+ double leftx = floor(ul.x / spacing) * spacing;
+ double bottomy = floor(br.y / spacing) * spacing;
+
+ double w = (br.x - ul.x) + Global::gridSpacing + 1.0;
+ double h = (ul.y - br.y) + Global::gridSpacing + 1.0;
+
+ Vector start(leftx, bottomy), size(w, h);
+
+ if (Global::gridSpacing <= 0.015625)
+ DrawSubGrid(painter, 0xFFD2D2, 0.015625, start, size);
+
+ if (Global::gridSpacing <= 0.03125)
+ DrawSubGrid(painter, 0xFFD2D2, 0.03125, start, size);
+
+ if (Global::gridSpacing <= 0.0625)
+ DrawSubGrid(painter, 0xB8ECFF, 0.0625, start, size);
+
+ if (Global::gridSpacing <= 0.125)
+ DrawSubGrid(painter, 0xB8ECFF, 0.125, start, size);
+
+ if (Global::gridSpacing <= 0.25)
+ DrawSubGrid(painter, 0xDBDBFF, 0.25, start, size);
+
+ if (Global::gridSpacing <= 0.5)
+ DrawSubGrid(painter, 0xDBDBFF, 0.5, start, size);
+
+ painter->SetPen(QPen(QColor(0xD2, 0xD2, 0xFF), 2.0, Qt::SolidLine));
+
+ for(double i=0; i<=w; i+=spacing)
+ painter->DrawVLine(leftx + i);
+
+ for(double i=0; i<=h; i+=spacing)
+ painter->DrawHLine(bottomy + i);
+}
+
+
+void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Vector start, Vector size)
+{
+ painter->SetPen(color, 1, 1);
+
+ for(double i=-step; i<=size.x; i+=step*2.0)
+ painter->DrawVLine(start.x + i);
+
+ for(double i=-step; i<=size.y; i+=step*2.0)
+ painter->DrawHLine(start.y + i);
}
void DrawingView::SetGridSize(uint32_t size)
{
+#if 0
// Sanity check
if (size == gridPixels)
return;
+ // tmp...
+ if (size <= 1)
+ return;
+
// Recreate the background bitmap
gridPixels = size;
QPainter pmp(&gridBackground);
pmp.end();
// Set up new BG brush & zoom level (pixels per base unit)
- Global::zoom = gridPixels / Global::gridSpacing;
+// This shouldn't be done here, because it fucks up the scrollwheel zooming...
+// Global::zoom = gridPixels / Global::gridSpacing;
UpdateGridBackground();
+#endif
}
void DrawingView::UpdateGridBackground(void)
{
+#if 0
// Transform the origin to Qt coordinates
Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector());
int x = (int)pixmapOrigin.x;
pal.setBrush(backgroundRole(), QBrush(pm));
setAutoFillBackground(true);
setPalette(pal);
+#endif
+}
+
+
+void DrawingView::SetGridSize(double size)
+{
+#if 0
+ // Sanity check
+ if (size == gridPixelsF)
+ return;
+
+ // tmp...
+ if (size <= 1)
+ return;
+
+ // Recreate the background bitmap
+ gridPixelsF = size;
+ QPainter pmp(&gridBackground);
+ pmp.fillRect(0, 0, BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE, QColor(240, 240, 240));
+ pmp.setPen(QPen(QColor(210, 210, 255), 2.0, Qt::SolidLine));
+
+ for(double i=0; i<(BACKGROUND_MAX_SIZE-1); i+=gridPixelsF)
+ {
+ pmp.drawLine(i, 0, i, (double)(BACKGROUND_MAX_SIZE - 1));
+ pmp.drawLine(0, i, (double)(BACKGROUND_MAX_SIZE - 1), i);
+ }
+
+ pmp.end();
+
+ // Set up new BG brush & zoom level (pixels per base unit)
+// This shouldn't be done here, because it fucks up the scrollwheel zooming...
+// Global::zoom = gridPixels / Global::gridSpacing;
+ UpdateGridBackgroundF();
+#endif
+}
+
+
+void DrawingView::UpdateGridBackgroundF(void)
+{
+#if 0
+ // Transform the origin to Qt coordinates
+ Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector());
+ int x = 0;// (int)pixmapOrigin.x;
+ int y = 0;// (int)pixmapOrigin.y;
+ // Use mod arithmetic to grab the correct swatch of background
+
+/* if (x < 0)
+ x = -x % gridPixels;
+ else
+ x = (gridPixels - (x % gridPixels)) % gridPixels;
+
+ if (y < 0)
+ y = -y % gridPixels;
+ else
+ y = (gridPixels - (y % gridPixels)) % gridPixels;*/
+
+ // Here we grab a section of the bigger pixmap, so that the background
+ // *looks* like it's scrolling...
+ QPixmap pm = gridBackground.copy(x, y, gridPixelsF, gridPixelsF);
+ QPalette pal = palette();
+ pal.setBrush(backgroundRole(), QBrush(pm));
+ setAutoFillBackground(true);
+ setPalette(pal);
+#endif
}
void DrawingView::DeleteCurrentLayer(int layer)
{
//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
- std::vector<void *>::iterator i = document.objects.begin();
+ VPVectorIter i = document.objects.begin();
while (i != document.objects.end())
{
//
void DrawingView::HandleLayerSwap(int layer1, int layer2)
{
+// !!! FIX !!! This doesn't properly handle container contents...
//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2);
- std::vector<void *>::iterator i;
-
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
Object * obj = (Object *)(*i);
void DrawingView::HandlePenWidth(float width)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->thickness = width;
void DrawingView::HandlePenStyle(int style)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->style = style;
void DrawingView::HandlePenColor(uint32_t color)
{
- std::vector<void *>::iterator i = select.begin();
-
- for(; i!=select.end(); i++)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
{
Object * obj = (Object *)(*i);
obj->color = color;
}
+void DrawingView::HandlePenStamp(void)
+{
+ VPVector flat = Flatten(select);
+
+ for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
+ {
+ Object * obj = (Object *)(*i);
+
+ if (obj->type != OTText)
+ obj->thickness = Global::penWidth;
+
+ obj->style = Global::penStyle;
+ obj->color = Global::penColor;
+ }
+
+ update();
+}
+
+
QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
{
// This is undoing the transform, e.g. going from client coords to local
Global::viewportHeight = size().height();
+ DrawBackground(&painter);
+
// Draw coordinate axes
painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine));
painter.DrawLine(0, -16384, 0, 16384);
!!! FIX !!!
[Well, it seems to work OK *except* when you move one of the points, then you get to see nothing. Is it worth fixing there to get rid of problems here? Have to investigate...]
*/
-void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int layer, bool ignoreLayer/*= false*/)
+void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool ignoreLayer/*= false*/)
{
- std::vector<void *>::iterator i;
-
- for(i=v.begin(); i!=v.end(); i++)
+ for(VPVectorIter i=v.begin(); i!=v.end(); i++)
{
Object * obj = (Object *)(*i);
float scaledThickness = Global::scale * obj->thickness;
unit = Vector(d->lp[0], d->lp[1]).Unit();
- Point p1 = d->lp[0] + (ortho * 10.0 * scaledThickness);
- Point p2 = d->lp[1] + (ortho * 10.0 * scaledThickness);
- Point p3 = d->lp[0] + (ortho * 16.0 * scaledThickness);
- Point p4 = d->lp[1] + (ortho * 16.0 * scaledThickness);
+ Point p1 = d->lp[0] + (ortho * (d->offset + (10.0 * scaledThickness)));
+ Point p2 = d->lp[1] + (ortho * (d->offset + (10.0 * scaledThickness)));
+ Point p3 = d->lp[0] + (ortho * (d->offset + (16.0 * scaledThickness)));
+ Point p4 = d->lp[1] + (ortho * (d->offset + (16.0 * scaledThickness)));
Point p5 = d->p[0] + (ortho * 4.0 * scaledThickness);
Point p6 = d->p[1] + (ortho * 4.0 * scaledThickness);
dimText = QString("%1' %2\"").arg(feet).arg(inches);
}
+/*
+Where is the text offset? It looks like it's drawing in the center, but obviously it isn't. It isn't here, it's in Painter::DrawAngledText().
+*/
painter->DrawAngledText(ctr, angle, dimText, scaledThickness);
if (d->hitObject)
}
+//
+// This toggles the selection being hovered (typically, only 1 object)
+//
void DrawingView::AddHoveredToSelection(void)
{
- std::vector<void *>::iterator i;
-
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->hovered)
- ((Object *)(*i))->selected = true;
+// ((Object *)(*i))->selected = true;
+ ((Object *)(*i))->selected = !((Object *)(*i))->selected;
}
}
-void DrawingView::GetSelection(std::vector<void *> & v)
+VPVector DrawingView::GetSelection(void)
{
- v.clear();
- std::vector<void *>::iterator i;
+ VPVector v;
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->selected)
v.push_back(*i);
}
-}
-
-#if 0
-void DrawingView::GetHovered(std::vector<void *> & v)
-{
- v.clear();
- std::vector<void *>::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;
}
-#endif
-std::vector<void *> DrawingView::GetHovered(void)
+VPVector DrawingView::GetHovered(void)
{
- std::vector<void *> v;
- std::vector<void *>::iterator i;
+ VPVector v;
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
{
if (((Object *)(*i))->hovered)
-// {
-//printf("GetHovered: adding object (%X) to hover... hp1=%s, hp2=%s, hl=%s\n", (*i), (((Line *)(*i))->hitPoint[0] ? "true" : "false"), (((Line *)(*i))->hitPoint[1] ? "true" : "false"), (((Line *)(*i))->hitObject ? "true" : "false"));
v.push_back(*i);
-// }
}
return v;
angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
- std::vector<void *>::iterator j = select.begin();
+ VPVectorIter j = select.begin();
// std::vector<Object>::iterator i = toolScratch.begin();
- std::vector<void *>::iterator i = toolScratch2.begin();
+ VPVectorIter i = toolScratch2.begin();
// for(; i!=toolScratch.end(); i++, j++)
for(; i!=toolScratch2.end(); i++, j++)
// Container * c = (Container *)&objT;
Container * c = (Container *)objT;
Container * c2 = (Container *)objS;
- std::vector<void *>::iterator l = c->objects.begin();
+ VPVectorIter l = c->objects.begin();
// TODO: Rotate items in the container
// TODO: Make this recursive
- for(std::vector<void *>::iterator k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
+ for(VPVectorIter k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
{
Object * obj3 = (Object *)(*k);
Object * obj4 = (Object *)(*l);
if (ctrlDown)
{
// Stamp a copy of the selection at the current rotation & bail
- std::vector<void *> temp;
+ VPVector temp;
CopyObjects(select, temp);
ClearSelected(temp);
AddObjectsTo(document.objects, temp);
angleSnap = true;
double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
- std::vector<void *>::iterator j = select.begin();
+ VPVectorIter j = select.begin();
std::vector<Object>::iterator i = toolScratch.begin();
for(; i!=toolScratch.end(); i++, j++)
if (ctrlDown)
{
// Stamp a copy of the selection at the current rotation & bail
- std::vector<void *> temp;
+ VPVector temp;
CopyObjects(select, temp);
ClearSelected(temp);
AddObjectsTo(document.objects, temp);
if (numHovered != 1)
break;
- std::vector<void *> hover = GetHovered();
+ VPVector hover = GetHovered();
Object * obj = (Object *)hover[0];
// Skip if it's not a line...
return;
}
- std::vector<void *> hover = GetHovered();
+ VPVector hover = GetHovered();
Object * obj = (Object *)hover[0];
// Skip if it's not a line...
// Currently only deal with line against line trimming, can expand to
// others as well (line/circle, circle/circle, line/arc, etc)
- std::vector<void *>::iterator i;
+ VPVectorIter i;
for(i=document.objects.begin(); i!=document.objects.end(); i++)
{
obj = (Object *)(*i);
{
if (event->button() == Qt::LeftButton)
{
-printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
+//printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
// Handle tool processing, if any
AddHoveredToSelection();
update(); // needed??
// GetHovered(hover); // prolly needed
- std::vector<void *> hover2 = GetHovered();
+ VPVector hover2 = GetHovered();
dragged = (Object *)hover2[0];
draggingObject = true;
-printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
+//printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
// Alert the pen widget
emit ObjectSelected(dragged);
return;
}
- // Didn't hit any object and not using a tool, so do a selection rectangle
+ // Didn't hit any object and not using a tool, so do a selection
+ // rectangle
Global::selectionInProgress = true;
Global::selection.setTopLeft(QPointF(point.x, point.y));
Global::selection.setBottomRight(QPointF(point.x, point.y));
+ select = GetSelection();
}
else if (event->button() == Qt::MiddleButton)
{
void DrawingView::mouseMoveEvent(QMouseEvent * event)
{
+ // It seems that wheelEvent() triggers this for some reason...
+ if (scrollWheelSeen)
+ {
+ scrollWheelSeen = false;
+ return;
+ }
+
Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
Global::selection.setBottomRight(QPointF(point.x, point.y));
// Only needs to be done here, as mouse down is always preceded by movement
if (Global::selectionInProgress)
{
CheckObjectBounds();
+
+ // Make sure previously selected objects stay selected (CTRL held)
+ for(VPVectorIter i=select.begin(); i!=select.end(); i++)
+ ((Object *)(*i))->selected = true;
+
update();
return;
}
// Do object hit testing...
bool needUpdate = HitTestObjects(point);
-// GetHovered(hover);
- std::vector<void *> hover2 = GetHovered();
+ VPVector hover2 = GetHovered();
+#if 0
{
if (needUpdate)
{
printf(" (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]);
}
}
+#endif
// Check for multi-hover...
if (numHovered > 1)
return;
}
- if (Global::selectionInProgress)
+// if (Global::selectionInProgress)
Global::selectionInProgress = false;
informativeText.clear();
// Should we be doing this automagically? Hmm...
// Clear our vectors
- select.clear();
-// hover.clear();
-
- // Scoop 'em up
- std::vector<void *>::iterator i;
+// select.clear();
+//// hover.clear();
- for(i=document.objects.begin(); i!=document.objects.end(); i++)
- {
- if (((Object *)(*i))->selected)
- select.push_back(*i);
- }
+ // Scoop 'em up (do we need to??? Seems we do, because keyboard movement uses it. Also, tools use it too. But we can move it out of here)
+ select = GetSelection();
draggingObject = false;
}
void DrawingView::wheelEvent(QWheelEvent * event)
{
- double zoomFactor = 1.25;
- QSize sizeWin = size();
- Vector center(sizeWin.width() / 2.0, sizeWin.height() / 2.0);
- center = Painter::QtToCartesianCoords(center);
+ double zoomFactor = 1.20;
+ scrollWheelSeen = true;
- // This is not centering for some reason. Need to figure out why. :-/
- if (event->delta() > 0)
+ if (event->angleDelta().y() < 0)
{
- Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
- Global::origin = newOrigin;
+ if (Global::zoom > 400.0)
+ return;
+
Global::zoom *= zoomFactor;
}
else
{
- Vector newOrigin = center + ((-center + Global::origin) * zoomFactor);
- Global::origin = newOrigin;
+ if (Global::zoom < 0.125)
+ return;
+
Global::zoom /= zoomFactor;
}
-// Global::gridSpacing = gridPixels / Painter::zoom;
-// UpdateGridBackground();
- SetGridSize(Global::gridSpacing * Global::zoom);
- update();
-// zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
+ Point np = Painter::QtToCartesianCoords(oldScrollPoint);
+ Global::origin += (oldPoint - np);
+
+ emit(NeedZoomUpdate());
}
else if (event->key() == Qt::Key_Alt)
altDown = true;
+ // If there's a change in any of the modifier key states, pass it on to
+ // the current tool's handler
if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
{
if (Global::tool)
case OTContainer:
{
Container * c = (Container *)obj;
- std::vector<void *>::iterator i = c->objects.begin();
+ VPVectorIter i = c->objects.begin();
rect = GetObjectExtents((Object *)*i);
i++;
void DrawingView::CheckObjectBounds(void)
{
- std::vector<void *>::iterator i;
+ VPVectorIter i;
for(i=document.objects.begin(); i!=document.objects.end(); i++)
{
bool DrawingView::HitTestObjects(Point point)
{
- std::vector<void *>::iterator i;
+ VPVectorIter i;
numHovered = 0;
bool needUpdate = false;
hoverPointValid = false;
Vector orthogonal = Vector::Normal(d->lp[0], d->lp[1]);
// Get our line parallel to our points
float scaledThickness = Global::scale * obj->thickness;
- Point p1 = d->lp[0] + (orthogonal * 10.0 * scaledThickness);
- Point p2 = d->lp[1] + (orthogonal * 10.0 * scaledThickness);
+#if 1
+ Point p1 = d->lp[0] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+ Point p2 = d->lp[1] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+#else
+ Point p1 = d->lp[0] + (orthogonal * (10.0 + d->offset) * scaledThickness);
+ Point p2 = d->lp[1] + (orthogonal * (10.0 + d->offset) * scaledThickness);
+#endif
Point p3(p1, point);
Vector v1(d->p[0], point);
likely we can just rely on the object itself and steal its state like we have in the commented out portion below; can prolly rewrite the HitTest() portion to be one line: needUpdate = HitTest(cObj, point);
Well, you could if there was only one object in the Container. But since there isn't, we have to keep the if HitTest() == true then needUpdate = true bit. Because otherwise, a false result anywhere will kill the needed update elsewhere.
*/
-
Container * c = (Container *)obj;
c->hitObject = false;
c->hovered = false;
c->clicked = NULL;
- std::vector<void *> flat = Flatten(c);
+ VPVector flat = Flatten(c);
//printf("HitTest::OTContainer (size=%li)\n", flat.size());
- for(std::vector<void *>::iterator i=flat.begin(); i!=flat.end(); i++)
+ for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
{
Object * cObj = (Object *)(*i);
c->clicked = cObj;
}//*/
+ if (cObj->hitPoint[2] == true)
+ {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
+ c->hitPoint[2] = true;
+ c->clicked = cObj;
+ }//*/
+
if (cObj->hovered == true)
c->hovered = true;//*/
}
obj->p[1] = point;
else if (obj->hitObject)
{
- obj->p[0] += delta;
- obj->p[1] += delta;
+ // Move measurement lines in/out
+ if (shiftDown)
+ {
+ Dimension * d = (Dimension *)obj;
+ double dist = Geometry::DistanceToLineFromPoint(d->lp[0], d->lp[1], point);
+ float scaledThickness = Global::scale * obj->thickness;
+ // Looks like offset is 0 to +MAX, but line is at 10.0. So
+ // anything less than 10.0 should set the offset to 0.
+ d->offset = 0;
+
+ if (dist > (10.0 * scaledThickness))
+ d->offset = dist - (10.0 * scaledThickness);
+ }
+ else
+ {
+ obj->p[0] += delta;
+ obj->p[1] += delta;
+ }
}
break;