#define DEBUGTP // Toolpalette debugging...
#include "editwindow.h"
-//#include <QtGui>
-#include "graphicprimitives.h"
-#include "debug.h"
-#include "vector.h"
#include "charwindow.h"
+#include "debug.h"
+#include "graphicprimitives.h"
+#include "mainwindow.h"
#include "ttedit.h"
+#include "vector.h"
+
EditWindow::EditWindow(QWidget * parent/*= NULL*/): QWidget(parent),
scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
- polyFirstPoint(true)
+ polyFirstPoint(true), showRotationCenter(false), haveZeroPoint(false)
{
setBackgroundRole(QPalette::Base);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setMouseTracking(true);
}
+
QSize EditWindow::minimumSizeHint() const
{
return QSize(50, 50);
}
+
QSize EditWindow::sizeHint() const
{
return QSize(400, 400);
}
+
void EditWindow::CreateCursors(void)
{
- int hotx[8] = { 1, 1, 11, 15, 1, 1, 1, 1 };
- int hoty[8] = { 1, 1, 11, 13, 1, 1, 1, 1 };
+ int hotx[11] = { 1, 1, 11, 15, 1, 1, 1, 1, 1, 1, 1 };
+ int hoty[11] = { 1, 1, 11, 13, 1, 1, 1, 1, 1, 1, 1 };
+ char cursorName[11][48] = { "select", "select-poly", "scroll", "zoom", "add-point",
+ "add-poly", "del-point", "del-poly", "rotate", "rotate", "select" };
- for(int i=0; i<8; i++)
+ for(int i=0; i<11; i++)
{
QString s;
- s.sprintf(":/res/cursor%u.png", i+1);
+ s.sprintf(":/res/cursor-%s.png", cursorName[i]);
QPixmap pmTmp(s);
cur[i] = QCursor(pmTmp, hotx[i], hoty[i]);
}
}
+
QPoint EditWindow::GetAdjustedMousePosition(QMouseEvent * event)
{
QSize winSize = size();
return QPoint(offsetX + event->x(), offsetY + (winSize.height() - event->y()));
}
+
QPoint EditWindow::GetAdjustedClientPosition(int x, int y)
{
QSize winSize = size();
return QPoint(-offsetX + x, (winSize.height() - (-offsetY + y)) * +1.0);
}
+
/*
TODO:
o Different colors for polys on selected points
QPainter p(this);
//hm, causes lockup (or does it???)
p.setRenderHint(QPainter::Antialiasing);
-//Doesn't do crap!
-//dc.SetBackground(*wxWHITE_BRUSH);
-// Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
-// the upper left corner--regardless of axis orientation, etc...
-// int width, height;
-// dc.GetSize(&width, &height);
QSize winSize = size();
-// dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
-// dc.SetAxisOrientation(true, true);
p.translate(QPoint(-offsetX, winSize.height() - (-offsetY)));
p.scale(1.0, -1.0);
// Instead, we have to scale EVERYTHING by hand. Crap!
// It's not *that* bad, but not as convenient either...
-// dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
-//// dc.DrawLine(0, 0, 10, 10);
p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
- // Draw coordinate axes
+ // Draw coordinate axes
-// dc.CrossHair(0, 0);
p.drawLine(0, -16384, 0, 16384);
p.drawLine(-16384, 0, 16384, 0);
- // Draw points
+ // Draw rotation center (if active)
+
+ if (showRotationCenter)
+ {
+ p.setPen(QPen(Qt::red, 2.0, Qt::SolidLine));
+ p.drawLine(rotationCenter.x() + 7, rotationCenter.y(), rotationCenter.x() - 7, rotationCenter.y());
+ p.drawLine(rotationCenter.x(), rotationCenter.y() + 7, rotationCenter.x(), rotationCenter.y() - 7);
+ }
+
+ // Draw points
for(int i=0; i<pts.GetNumPoints(); i++)
{
if (i == ptHighlight)
{
-// dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
-//// SelectObject(hdc, hRedPen1);
p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
if (pts.GetOnCurve(i))
}
else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
{
-// dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
-//// SelectObject(hdc, hGreenPen1);
p.setPen(QPen(Qt::green, 1.0, Qt::SolidLine));
if (pts.GetOnCurve(i))
}
else
{
-// dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
-//// SelectObject(hdc, hBlackPen1);
p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
if (pts.GetOnCurve(i))
if (tool == TOOLDelPt && i == ptHighlight)
{
-#if 0
- dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
-// SelectObject(hdc, hRedPen1);
-// MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
-// LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
-// LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
-// MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
-// LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
-// LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
-#endif
p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
p.drawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
p.drawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
}
}
-//// SelectObject(hdc, hBlackPen1);
-// dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
- p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
-
// Draw curve formed by points
- for(int poly=0; poly<pts.GetNumPolys(); poly++)
+ p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+ DrawGlyph(p, pts);
+
+ if (haveZeroPoint)
{
- if (pts.GetNumPoints(poly) > 2)
- {
- // Initial move...
- // If it's not on curve, then move to it, otherwise move to last point...
+ // Rotation code
+ GlyphPoints rotated = pts;
- int x, y;
+ if (tool == TOOLRotate)
+ rotated.RotatePoints(rotationAngle, IPoint(rotationCenter.x(), rotationCenter.y()));
+ else if (tool == TOOLRotatePoly)
+ {
+ uint16 poly = rotated.GetPolyForPointNumber(ptHighlight);
+ rotated.RotatePolyAroundCentroid(poly, rotationAngle);
+ }
- if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
- x = (int)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (int)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
- else
- x = (int)pts.GetX(poly, 0), y = (int)pts.GetY(poly, 0);
+ p.setPen(QPen(QColor(255, 0, 255), 1.0, Qt::SolidLine));
+ DrawGlyph(p, rotated);
+ }
+}
- for(int i=0; i<pts.GetNumPoints(poly); i++)
- {
- if (pts.GetOnCurve(poly, i))
-// LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
- {
- p.drawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
- x = (int)pts.GetX(poly, i), y = (int)pts.GetY(poly, i);
- }
- else
- {
- uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
- float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
- nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
- if (!pts.GetOnCurve(poly, prev))
- px = (px + pts.GetX(poly, i)) / 2.0f,
- py = (py + pts.GetY(poly, i)) / 2.0f;
+void EditWindow::DrawGlyph(QPainter & p, GlyphPoints & glyph)
+{
+ for(int poly=0; poly<glyph.GetNumPolys(); poly++)
+ {
+ if (glyph.GetNumPoints(poly) < 3)
+ continue;
- if (!pts.GetOnCurve(poly, next))
- nx = (nx + pts.GetX(poly, i)) / 2.0f,
- ny = (ny + pts.GetY(poly, i)) / 2.0f;
+ // Initial move: If our start point is on curve, then go to it. Otherwise,
+ // check previous point. If it's on curve, go to it otherwise go the
+ // midpoint between start point and previous (since it's between two curve
+ // control points).
+ IPoint pt = (glyph.GetOnCurve(poly, 0)
+ ? glyph.GetPoint(poly, 0) : (glyph.GetPrevOnCurve(poly, 0)
+ ? glyph.GetPrevPoint(poly, 0) : glyph.GetMidpointToPrev(poly, 0)));
- Bezier(p, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
- x = (int)nx, y = (int)ny;
+// Need to add separate color handling here for polys that are being manipulated...
- if (pts.GetOnCurve(poly, next))
- i++; // Following point is on curve, so move past it
- }
+ for(int i=0; i<glyph.GetNumPoints(poly); i++)
+ {
+ // If this point and then next are both on curve, we have a line...
+ if (glyph.GetOnCurve(poly, i) && glyph.GetNextOnCurve(poly, i))
+ {
+ IPoint pt2 = glyph.GetNextPoint(poly, i);
+ p.drawLine(pt.x, pt.y, pt2.x, pt2.y);
+ pt = pt2;
}
+ else
+ {
+ // Skip point if it's on curve (start of curve--it's already
+ // been plotted so we don't need to handle it...)
+ if (glyph.GetOnCurve(poly, i))
+ continue;
+
+ // We are now guaranteed that we are sitting on a curve control point
+ // (off curve). Figure the extent of the curve: If the following is a
+ // curve control point, then use the midpoint to it otherwise go to
+ // the next point since it's on curve.
+ IPoint pt2 = (glyph.GetNextOnCurve(poly, i)
+ ? glyph.GetNextPoint(poly, i) : glyph.GetMidpointToNext(poly, i));
+
+ Bezier(p, pt, glyph.GetPoint(poly, i), pt2);
+ pt = pt2;
+ }
+ }
+ }
+}
+
+
+void EditWindow::DrawGlyphPoly(QPainter & p, GlyphPoints & glyph, uint16 poly)
+{
+ // Sanity check
+ if (glyph.GetNumPoints(poly) < 3)
+ return;
+
+ // Initial move: If our start point is on curve, then go to it. Otherwise,
+ // check previous point. If it's on curve, go to it otherwise go the
+ // midpoint between start point and previous (since it's between two curve
+ // control points).
+ IPoint pt = (glyph.GetOnCurve(poly, 0)
+ ? glyph.GetPoint(poly, 0) : (glyph.GetPrevOnCurve(poly, 0)
+ ? glyph.GetPrevPoint(poly, 0) : glyph.GetMidpointToPrev(poly, 0)));
+
+ for(int i=0; i<glyph.GetNumPoints(poly); i++)
+ {
+ // If this point and then next are both on curve, we have a line...
+ if (glyph.GetOnCurve(poly, i) && glyph.GetNextOnCurve(poly, i))
+ {
+ IPoint pt2 = glyph.GetNextPoint(poly, i);
+ p.drawLine(pt.x, pt.y, pt2.x, pt2.y);
+ pt = pt2;
+ }
+ else
+ {
+ // Skip point if it's on curve (start of curve--it's already
+ // been plotted so we don't need to handle it...)
+ if (glyph.GetOnCurve(poly, i))
+ continue;
+
+ // We are now guaranteed that we are sitting on a curve control point
+ // (off curve). Figure the extent of the curve: If the following is a
+ // curve control point, then use the midpoint to it otherwise go to
+ // the next point since it's on curve.
+ IPoint pt2 = (glyph.GetNextOnCurve(poly, i)
+ ? glyph.GetNextPoint(poly, i) : glyph.GetMidpointToNext(poly, i));
+
+ Bezier(p, pt, glyph.GetPoint(poly, i), pt2);
+ pt = pt2;
}
}
}
+
void EditWindow::mousePressEvent(QMouseEvent * event)
{
if (event->button() == Qt::RightButton)
;//meh CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
else if (tool == TOOLAddPt) // "Add Point" tool
{
- if (pts.GetNumPoints() > 0)
+ QPoint pt = GetAdjustedMousePosition(event);
+ IPoint pointToAdd(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+
+ if (pts.GetNumPoints() < 2)
{
- QPoint pt = GetAdjustedMousePosition(event);
- pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+// pts += IPoint(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+ pts += pointToAdd;
+ ptHighlight = pts.GetNumPoints() - 1;
+ }
+ else
+ {
+// QPoint pt = GetAdjustedMousePosition(event);
+// pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+ pts.InsertPoint(pts.GetNext(ptHighlight), pointToAdd);
ptHighlight = ptNextHighlight;
- update();
+// update();
}
+
+ update();
}
else if (tool == TOOLAddPoly) // "Add Poly" tool
{
update();
}
}
+ else if (tool == TOOLRotate)
+ {
+ // I think what's needed here is to keep the initial mouse click,
+ // paint the rotation center, then use the 1st mouse move event to establish
+ // the rotation "zero line", which becomes the line of reference to all
+ // subsequent mouse moves.
+ rotationCenter = GetAdjustedMousePosition(event);
+ showRotationCenter = true;
+ haveZeroPoint = false;
+ rotationAngle = 0;
+ update();
+ }
+ else if (tool == TOOLRotatePoly)
+ {
+ IPoint centroid = pts.GetPolyCentroid(pts.GetPolyForPointNumber(ptHighlight));
+ rotationCenter = QPoint(centroid.x, centroid.y);
+ showRotationCenter = true;
+ pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+ QCursor::setPos(mapToGlobal(pt));
+ rotationZeroPoint = QPoint(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+ haveZeroPoint = true;
+ rotationAngle = 0;
+ update();
+ }
+ else if (tool == TOOLFlipWinding)
+ {
+ pts.InvertPolyDrawSequence(pts.GetPolyForPointNumber(ptHighlight));
+ pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+ QCursor::setPos(mapToGlobal(pt));
+ update();
+ }
}
event->accept();
}
+
void EditWindow::mouseMoveEvent(QMouseEvent * event)
{
if (event->buttons() == Qt::RightButton)
}
else if (event->buttons() == Qt::LeftButton)
{
-#if 0
- if (tool == TOOLScroll)
- {
- // Extract current point from lParam/calc offset from previous point
-
- pt = e.GetPosition();
- ptOffset.x = pt.x - ptPrevious.x,
- ptOffset.y = pt.y - ptPrevious.y;
-
- // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
-
-//Seems there's no equivalent for this in wxWidgets...!
-//!!! FIX !!!
-// hdc = GetDC(hWnd);
-// OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
-// ReleaseDC(hWnd, hdc);
+ if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
+ {
+ // Bail out if we have the select tool and no points yet...
+ if (tool == TOOLSelect && pts.GetNumPoints() == 0)
+ return;
-// this shows that it works, so the logic above must be faulty...
-// And it is. It should convert the coords first, then do the subtraction to figure the offset...
-// Above: DONE
-// Then multiply it by the scaling factor. Whee!
- // This looks wacky because we're using screen coords for the offset...
- // Otherwise, we would subtract both offsets!
- offsetX -= ptOffset.x, offsetY += ptOffset.y;
- Refresh();
+ QPoint pt2 = GetAdjustedMousePosition(event);
+ pts.SetXY(ptHighlight, pt2.x(), pt2.y());
+ update();
+ }
+ else if (tool == TOOLPolySelect)
+ {
+ if (pts.GetNumPoints() > 0)
+ {
+ QPoint pt2 = GetAdjustedMousePosition(event);
+ // Should also set onCurve here as well, depending on keystate
+//Or should we?
+//Would be nice, but we'd need to trap the keyPressEvent() as well, otherwise pressing/releasing
+//the hotkey would show no change until the user moved their mouse.
+ pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight));
+ update();
}
- else
-#endif
- if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
+ }
+ else if (tool == TOOLRotate || tool == TOOLRotatePoly)
+ {
+ if (pts.GetNumPoints() > 0)
{
- if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
+ if (!haveZeroPoint)
{
-//temporary, for testing. BTW, Select drag bug is here...!
-#if 1
- QPoint pt2 = GetAdjustedMousePosition(event);
- pts.SetXY(ptHighlight, pt2.x(), pt2.y());
- update();
-#endif
+ rotationZeroPoint = GetAdjustedMousePosition(event);
+ haveZeroPoint = true;
}
- }
- else if (tool == TOOLPolySelect)
- {
- if (pts.GetNumPoints() > 0)
+ else
{
- QPoint pt2 = GetAdjustedMousePosition(event);
- // Should also set onCurve here as well, depending on keystate
-//Or should we?
- pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight));
- update();
+ // Figure out the angle between the "zero" vector and the current one,
+ // then rotate all points relative to the "zero" vector (done by paint())
+ QPoint currentPoint = GetAdjustedMousePosition(event);
+ Vector v1(rotationZeroPoint.x(), rotationZeroPoint.y(), 0,
+ rotationCenter.x(), rotationCenter.y(), 0);
+ Vector v2(currentPoint.x(), currentPoint.y(), 0,
+ rotationCenter.x(), rotationCenter.y(), 0);
+// rotationAngle = v1.Angle(v2);
+ rotationAngle = v2.Angle(v1);
+
+ QString s;
+ s.sprintf("%.3f degrees", rotationAngle * 180.0 / 3.14159265358979323);
+ ((TTEdit *)qApp)->mainWindow->statusBar()->showMessage(s);
}
+
+ update();
}
+ }
}
else if (event->buttons() == Qt::NoButton)
{
// Moving, not dragging...
if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
- || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
+ || tool == TOOLPolySelect || tool == TOOLRotatePoly || tool == TOOLFlipWinding)
{
QPoint pt2 = GetAdjustedMousePosition(event);
double closest = 1.0e+99;
int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
- vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x(), pt2.y(), 0, p1x, p1y, 0),
+ Vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x(), pt2.y(), 0, p1x, p1y, 0),
v2(pt2.x(), pt2.y(), 0, p2x, p2y, 0);
- double pp = ls.dot(v1) / ls.length(), dist;
+ double pp = ls.Dot(v1) / ls.Magnitude(), dist;
// Geometric interpretation:
// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
// then the perpendicular lies beyond the 2nd endpoint.
if (pp < 0.0)
- dist = v1.length();
- else if (pp > ls.length())
- dist = v2.length();
+ dist = v1.Magnitude();
+ else if (pp > ls.Magnitude())
+ dist = v2.Magnitude();
else // distance = ?Det?(ls, v1) / |ls|
- dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
+ dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.Magnitude());
//The answer to the above looks like it might be found here:
//
event->accept();
}
+
void EditWindow::mouseReleaseEvent(QMouseEvent * event)
{
if (event->button() == Qt::RightButton)
}
else if (event->button() == Qt::LeftButton)
{
+ if (showRotationCenter)
+ {
+ showRotationCenter = false;
+ haveZeroPoint = false;
+
+ if (tool == TOOLRotate)
+ pts.RotatePoints(rotationAngle, IPoint(rotationCenter.x(), rotationCenter.y()));
+ else
+ {
+ uint16 poly = pts.GetPolyForPointNumber(ptHighlight);
+ pts.RotatePolyAroundCentroid(poly, rotationAngle);
+ }
+
+ update();
+ ((TTEdit *)qApp)->mainWindow->statusBar()->showMessage("");
+ }
+
// if (tool == TOOLScroll || tool == TOOLZoom)
// ReleaseMouse();
//this is prolly too much
((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts);
((TTEdit *)qApp)->charWnd->update();
+
}
event->accept();