From: Shamus Hammons Date: Fri, 4 Mar 2016 19:57:48 +0000 (-0600) Subject: Added rectangle point selection, canvas zooming. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=sidebyside;h=7fde5a077bc9bbce28662fa2e5aa5043f3b4747f;p=ttedit Added rectangle point selection, canvas zooming. Note that the scrolling & single point selection are still a bit wonky. --- diff --git a/res/cursor-select-multi.png b/res/cursor-select-multi.png new file mode 100644 index 0000000..521627c Binary files /dev/null and b/res/cursor-select-multi.png differ diff --git a/res/toolpal1.png b/res/toolpal1.png index 54ca026..2d29d45 100644 Binary files a/res/toolpal1.png and b/res/toolpal1.png differ diff --git a/src/charnames.cpp b/src/charnames.cpp index 56047bd..d50cfa3 100755 --- a/src/charnames.cpp +++ b/src/charnames.cpp @@ -2,13 +2,13 @@ // CHARNAMES.CPP // // A header file that links Unicode character names to character numbers. -// by James L. Hammons +// by James Hammons // (C) 2004 Underground Software // // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH ??/??/200? Created this file // diff --git a/src/charwindow.cpp b/src/charwindow.cpp index 0309b78..76112e4 100755 --- a/src/charwindow.cpp +++ b/src/charwindow.cpp @@ -6,7 +6,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 08/28/2008 Created this file // JLH 03/19/2009 Converted from wxWidgets to Qt // JLH 03/21/2009 Fixed main screen points rendering diff --git a/src/debug.cpp b/src/debug.cpp index fb77b42..bfe1b0b 100755 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -6,7 +6,7 @@ // JLH = James Hammons // // Who When What -// --- ---------- ------------------------------------------------------------ +// --- ---------- ----------------------------------------------------------- // JLH 07/31/2002 Created this file // JLH 07/31/2002 Added debug log functions & system error logging functions // JLH 08/16/2002 Added debug log function for SQL error reporting, made diff --git a/src/editwindow.cpp b/src/editwindow.cpp index 9d0f5d8..85b4d9c 100755 --- a/src/editwindow.cpp +++ b/src/editwindow.cpp @@ -6,7 +6,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 08/28/2008 Created this file // JLH 09/02/2008 Separated scrolling from dedicated tool to MMB drag // JLH 03/13/2009 Converted from wxWidgets to Qt @@ -36,7 +36,7 @@ #include "editwindow.h" #include "charwindow.h" #include "debug.h" -#include "graphicprimitives.h" +#include "global.h" #include "mainwindow.h" #include "ttedit.h" #include "vector.h" @@ -45,7 +45,8 @@ 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), showRotationCenter(false), haveZeroPoint(false) + polyFirstPoint(true), showRotationCenter(false), haveZeroPoint(false), + selectionInProgress(false) { setBackgroundRole(QPalette::Base); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -54,6 +55,7 @@ EditWindow::EditWindow(QWidget * parent/*= NULL*/): QWidget(parent), CreateCursors(); setCursor(cur[TOOLSelect]); setMouseTracking(true); + ClearSelection(); } @@ -71,12 +73,13 @@ QSize EditWindow::sizeHint() const void EditWindow::CreateCursors(void) { - 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" }; + int hotx[12] = { 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 11 }; + int hoty[12] = { 1, 1, 1, 13, 1, 1, 1, 1, 1, 1, 1, 11 }; + char cursorName[12][48] = { "select", "select-poly", "select-multi", "zoom", + "add-point", "add-poly", "del-point", "del-poly", "rotate", "rotate", + "select", "scroll" }; - for(int i=0; i<11; i++) + for(int i=0; i<12; i++) { QString s; s.sprintf(":/res/cursor-%s.png", cursorName[i]); @@ -88,20 +91,17 @@ void EditWindow::CreateCursors(void) QPoint EditWindow::GetAdjustedMousePosition(QMouseEvent * event) { - QSize winSize = size(); - // This is undoing the transform, e.g. going from client coords to local coords. - // In essence, the height - y is height + (y * -1), the (y * -1) term doing the - // conversion of the y-axis from increasing bottom to top. - return QPoint(offsetX + event->x(), offsetY + (winSize.height() - event->y())); + // This is undoing the transform, e.g. going from client coords to local + // coords. In essence, the height - y is height + (y * -1), the (y * -1) + // term doing the conversion of the y-axis from increasing bottom to top. + return QPoint(offsetX + event->x(), offsetY + (size().height() - event->y())); } QPoint EditWindow::GetAdjustedClientPosition(int x, int y) { - QSize winSize = size(); - // VOODOO ALERT (ON Y COMPONENT!!!!) - return QPoint(-offsetX + x, (winSize.height() - (-offsetY + y)) * +1.0); + return QPoint(-offsetX + x, (size().height() - (-offsetY + y)) * +1.0); } @@ -114,14 +114,21 @@ TODO: */ void EditWindow::paintEvent(QPaintEvent * /*event*/) { - QPainter p(this); + QPainter qtp(this); + Painter painter(&qtp); //hm, causes lockup (or does it???) - p.setRenderHint(QPainter::Antialiasing); - - QSize winSize = size(); - - p.translate(QPoint(-offsetX, winSize.height() - (-offsetY))); - p.scale(1.0, -1.0); +//& it doesn't help with our Bezier rendering code :-P + painter.SetRenderHint(QPainter::Antialiasing); + + Global::zoom = scale; + Global::origin = Vector(offsetX, offsetY); + Global::viewportHeight = size().height(); + Global::screenSize = Vector(size().width(), size().height()); +// p.translate(QPoint(-offsetX, size().height() - (-offsetY))); +// p.scale(1.0, -1.0); +//Nope, a big load of shit. So we'll have to bite the bullet and do it the +//hard way™. +// p.scale(scale, -scale); // Scrolling can be done by using OffsetViewportOrgEx // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform) @@ -130,78 +137,95 @@ void EditWindow::paintEvent(QPaintEvent * /*event*/) // Instead, we have to scale EVERYTHING by hand. Crap! // It's not *that* bad, but not as convenient either... - p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine)); + painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine)); // Draw coordinate axes - p.drawLine(0, -16384, 0, 16384); - p.drawLine(-16384, 0, 16384, 0); + painter.DrawLine(0, -16384, 0, 16384); + painter.DrawLine(-16384, 0, 16384, 0); // 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); + painter.SetPen(QPen(Qt::red, 2.0, Qt::SolidLine)); + painter.DrawLine(rotationCenter.x + 7, rotationCenter.y, rotationCenter.x - 7, rotationCenter.y); + painter.DrawLine(rotationCenter.x, rotationCenter.y + 7, rotationCenter.x, rotationCenter.y - 7); } // Draw points for(int i=0; ibutton() == Qt::RightButton) @@ -329,16 +367,28 @@ void EditWindow::mousePressEvent(QMouseEvent * event) } else if (event->button() == Qt::MidButton) { - setCursor(cur[2]); // Scrolling cursor + // Scrolling cursor + setCursor(cur[11]); + ptPrevious = Vector(event->x(), event->y()); + ptPrevious /= Global::zoom; } else if (event->button() == Qt::LeftButton) { if (tool == TOOLScroll || tool == TOOLZoom) ;//meh CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode + else if (tool == TOOLMultiSelect) + { +// QPoint pt = GetAdjustedMousePosition(event); + Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); + selectionInProgress = true; + selection.setTopLeft(QPoint(pt.x, pt.y)); + selection.setBottomRight(QPoint(pt.x, pt.y)); + } else if (tool == TOOLAddPt) // "Add Point" tool { - QPoint pt = GetAdjustedMousePosition(event); - IPoint pointToAdd(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true)); +// QPoint pt = GetAdjustedMousePosition(event); + Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); + IPoint pointToAdd(pt.x, pt.y, ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true)); if (pts.GetNumPoints() < 2) { @@ -368,10 +418,11 @@ WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts. pts.AddNewPolyAtEnd(); } - QPoint pt = GetAdjustedMousePosition(event); +// QPoint pt = GetAdjustedMousePosition(event); + Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); //printf("GetAdjustedMousePosition = %i, %i\n", pt.x(), pt.y()); // Append a point to the end of the structure - pts += IPoint(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)); ptHighlight = pts.GetNumPoints() - 1; update(); #ifdef DEBUGFOO @@ -382,10 +433,12 @@ WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumP { if (pts.GetNumPoints() > 0) { - pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); +// pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); + Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); //printf("GetAdjustedClientPosition = %i, %i\n", pt.x(), pt.y()); // WarpPointer(pt.x, pt.y); - QCursor::setPos(mapToGlobal(pt)); + QPoint warp(pt.x, pt.y); + QCursor::setPos(mapToGlobal(warp)); if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) { @@ -412,7 +465,8 @@ WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumP // 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); +// rotationCenter = GetAdjustedMousePosition(event); + rotationCenter = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); showRotationCenter = true; haveZeroPoint = false; rotationAngle = 0; @@ -421,11 +475,12 @@ WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumP else if (tool == TOOLRotatePoly) { IPoint centroid = pts.GetPolyCentroid(pts.GetPolyForPointNumber(ptHighlight)); - rotationCenter = QPoint(centroid.x, centroid.y); + rotationCenter = Vector(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)); +// pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); + Vector pt = Painter::QtToCartesianCoords(Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight))); + QCursor::setPos(mapToGlobal(QPoint(pt.x, pt.y))); + rotationZeroPoint = Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); haveZeroPoint = true; rotationAngle = 0; update(); @@ -433,8 +488,9 @@ WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumP else if (tool == TOOLFlipWinding) { pts.InvertPolyDrawSequence(pts.GetPolyForPointNumber(ptHighlight)); - pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); - QCursor::setPos(mapToGlobal(pt)); +// pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); + Vector pt = Painter::QtToCartesianCoords(Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight))); + QCursor::setPos(mapToGlobal(QPoint(pt.x, pt.y))); update(); } } @@ -458,13 +514,14 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) else if (event->buttons() == Qt::MidButton) { // Calc offset from previous point - pt = event->pos(); - ptOffset = QPoint(pt.x() - ptPrevious.x(), pt.y() - ptPrevious.y()); + Vector pt(event->x(), event->y()); + pt /= Global::zoom; + ptOffset = Vector(pt.x - ptPrevious.x, pt.y - ptPrevious.y); // 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(); + offsetX -= ptOffset.x, offsetY += ptOffset.y; update(); ptPrevious = pt; } @@ -476,20 +533,22 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) if (tool == TOOLSelect && pts.GetNumPoints() == 0) return; - QPoint pt2 = GetAdjustedMousePosition(event); - pts.SetXY(ptHighlight, pt2.x(), pt2.y()); +// QPoint pt2 = GetAdjustedMousePosition(event); + Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); + pts.SetXY(ptHighlight, pt2.x, pt2.y); update(); } else if (tool == TOOLPolySelect) { if (pts.GetNumPoints() > 0) { - QPoint pt2 = GetAdjustedMousePosition(event); +// QPoint pt2 = GetAdjustedMousePosition(event); + Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); // 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)); + pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight)); update(); } } @@ -499,18 +558,20 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) { if (!haveZeroPoint) { - rotationZeroPoint = GetAdjustedMousePosition(event); +// rotationZeroPoint = GetAdjustedMousePosition(event); + rotationZeroPoint = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); haveZeroPoint = true; } else { // 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); +// QPoint currentPoint = GetAdjustedMousePosition(event); + Vector currentPoint = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); + 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); @@ -522,6 +583,22 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) update(); } } + else if (tool == TOOLMultiSelect) + { +// QPoint pt = GetAdjustedMousePosition(event); + Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); + selection.setBottomRight(QPoint(pt.x, pt.y)); + + for(int i=0; ibuttons() == Qt::NoButton) { @@ -529,13 +606,14 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt || tool == TOOLPolySelect || tool == TOOLRotatePoly || tool == TOOLFlipWinding) { - QPoint pt2 = GetAdjustedMousePosition(event); +// QPoint pt2 = GetAdjustedMousePosition(event); + Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); double closest = 1.0e+99; for(int i=0; i 1 && tool == TOOLAddPt) { @@ -566,13 +646,15 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) int32_t 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), - v2(pt2.x(), pt2.y(), 0, p2x, p2y, 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.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. +// 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.Magnitude(); @@ -583,12 +665,14 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) //The answer to the above looks like it might be found here: // -//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular -//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and -//{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is -//computed by first computing the area of the triangle the three points form, then dividing by the -//length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the -//triangle formed by three points is the determinant of the following matrix: +//If the segment endpoints are s and e, and the point is p, then the test for +//the perpendicular intercepting the segment is equivalent to insisting that +//the two dot products {s-e}.{s-p} and {e-s}.{e-p} are both non-negative. +//Perpendicular distance from the point to the segment is computed by first +//computing the area of the triangle the three points form, then dividing by +//the length of the segment. Distances are done just by the Pythagorean +//theorem. Twice the area of the triangle formed by three points is the +//determinant of the following matrix: // //sx sy 1 //ex ey 1 @@ -596,8 +680,9 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) // //By translating the start point to the origin, this can be rewritten as: //By subtracting row 1 from all rows, you get the following: -//[because sx = sy = 0. you could leave out the -sx/y terms below. because we subtracted -// row 1 from all rows (including row 1) row 1 turns out to be zero. duh!] +//[because sx = sy = 0. you could leave out the -sx/y terms below. because we +//subtracted row 1 from all rows (including row 1) row 1 turns out to be zero. +//duh!] // //0 0 0 //(ex - sx) (ey - sy) 0 @@ -617,7 +702,7 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event) } } - ptPrevious = event->pos(); + ptPrevious = Vector(event->x(), event->y()); } event->accept(); @@ -660,7 +745,7 @@ void EditWindow::mouseReleaseEvent(QMouseEvent * event) haveZeroPoint = false; if (tool == TOOLRotate) - pts.RotatePoints(rotationAngle, IPoint(rotationCenter.x(), rotationCenter.y())); + pts.RotatePoints(rotationAngle, IPoint(rotationCenter.x, rotationCenter.y)); else { uint16_t poly = pts.GetPolyForPointNumber(ptHighlight); @@ -677,6 +762,11 @@ void EditWindow::mouseReleaseEvent(QMouseEvent * event) ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts); ((TTEdit *)qApp)->charWnd->update(); + if (tool == TOOLMultiSelect) + { + selectionInProgress = false; + update(); + } } event->accept(); diff --git a/src/editwindow.h b/src/editwindow.h index 6525359..11a5b07 100755 --- a/src/editwindow.h +++ b/src/editwindow.h @@ -12,6 +12,8 @@ #include #include "toolwindow.h" // For ToolType enum #include "glyphpoints.h" +#include "painter.h" + class EditWindow: public QWidget { @@ -34,25 +36,29 @@ class EditWindow: public QWidget void CreateCursors(void); QPoint GetAdjustedMousePosition(QMouseEvent *); QPoint GetAdjustedClientPosition(int x, int y); - void DrawGlyph(QPainter & p, GlyphPoints & glyph); - void DrawGlyphPoly(QPainter & p, GlyphPoints & glyph, uint16_t poly); + void DrawGlyph(Painter & p, GlyphPoints & glyph); + void DrawGlyphPoly(Painter & p, GlyphPoints & glyph, uint16_t poly); + void ClearSelection(void); public: QImage image; - QPoint pt, ptOffset, ptPrevious; - double scale; // Window scaling factor - int32_t offsetX, offsetY; // Window offsets - ToolType tool; // Current tool - GlyphPoints pts; // Glyph point structure + Vector pt, ptOffset, ptPrevious; + double scale; // Window scaling factor + int32_t offsetX, offsetY; // Window offsets + ToolType tool; // Current tool + GlyphPoints pts; // Glyph point structure int32_t ptHighlight, oldPtHighlight, ptNextHighlight, oldPtNextHighlight; int16_t polyHighlight, oldPolyHighlight; bool polyFirstPoint; bool showRotationCenter, haveZeroPoint; - QPoint rotationCenter, rotationZeroPoint, rotationCurrentPoint; + Vector rotationCenter, rotationZeroPoint, rotationCurrentPoint; double rotationAngle; ToolWindow * toolPalette; - QCursor cur[11]; + QCursor cur[12]; + bool selectedPoints[65536]; // Potential memory leak :-O + QRect selection; + bool selectionInProgress; }; #endif // __EDITWINDOW_H__ diff --git a/src/global.cpp b/src/global.cpp new file mode 100644 index 0000000..ad562ee --- /dev/null +++ b/src/global.cpp @@ -0,0 +1,51 @@ +// +// This page intentionally left (mostly) blank +// + +#include "global.h" +#include +//#include "structs.h" +#include "toolwindow.h" + +// Initialize static variables + +bool Global::fixedAngle = false; +bool Global::fixedLength = false; +QFont * Global::font = 0; +int Global::viewportHeight = 0; + +bool Global::deleteActive = false; +bool Global::dimensionActive = false; +bool Global::snapToGrid = true; + +//snapToPoints all well here? +bool Global::ignoreClicks = false; +bool Global::dontMove = false; +bool Global::selectionInProgress = false; +QRectF Global::selection; + +int Global::tool = TOOLSelect; +//int Global::toolState = TSNone; + +double Global::gridSpacing; +int Global::currentLayer = 0; +Point Global::snapPoint; +bool Global::snapPointIsValid = false; +uint32_t Global::objectID = 1; + +Vector Global::origin(-10.0, -10.0); +double Global::zoom = 1.0; +Vector Global::screenSize(200.0, 200.0); + +float Global::scale = 0.5; + +Point Global::intersectPoint[16]; // Overkill, yes +double Global::intersectParam[16]; // Ditto +int Global::numIntersectPoints = 0; +int Global::numIntersectParams = 0; + +int Global::activeLayer = 0; +int Global::numLayers = 1; +std::vector Global::layerHidden; +std::vector Global::layerLocked; + diff --git a/src/global.h b/src/global.h new file mode 100644 index 0000000..64422da --- /dev/null +++ b/src/global.h @@ -0,0 +1,59 @@ +#ifndef __GLOBALS_H__ +#define __GLOBALS_H__ + +// Global variable class. Note that all vars are class vars, so we don't have +// to do any instantiation shite--it's treated as a namespace. + +#include +#include +#include +#include "vector.h" + +class QFont; + +enum LineStyle { LSNone, LSSolid, LSDash, LSDot, LSDashDot, LSDashDotDot }; + + +class Global +{ + public: + static double gridSpacing; + static bool selectionInProgress; + static QRectF selection; + static int currentLayer; + static QFont * font; + static Point snapPoint; + static bool snapPointIsValid; + + static bool fixedAngle; + static bool fixedLength; + static int viewportHeight; + static bool deleteActive; + static bool dimensionActive; + + static bool snapToGrid; + static bool ignoreClicks; + static bool dontMove; + static uint32_t objectID; + static int tool; + static int toolState; + + static Point origin; + static double zoom; + static Vector screenSize; + + static float scale; + + static Point intersectPoint[16]; // Overkill, yes + static double intersectParam[16]; // Ditto + static int numIntersectPoints; + static int numIntersectParams; + + static int activeLayer; + static int numLayers; + static std::vector layerHidden; + static std::vector layerLocked; +}; + +#endif // __GLOBALS_H__ + diff --git a/src/glyphpoints.cpp b/src/glyphpoints.cpp index 0b05752..4ae01e5 100755 --- a/src/glyphpoints.cpp +++ b/src/glyphpoints.cpp @@ -10,7 +10,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------ +// --- ---------- ----------------------------------------------------------- // JLH ??/??/200? Created this file // JLH 05/18/2004 Added pure point adding, inserting, better polygon handling // @@ -247,6 +247,7 @@ void GlyphPoints::Clear(void) void GlyphPoints::InsertPoint(uint16_t pt, int xx, int yy, bool oc) { +//wouldn't it be better to treat this case as inserting at the end? if (pt > numPoints) // > because we can insert at end...! throw GP_OUT_OF_RANGE; @@ -267,7 +268,6 @@ void GlyphPoints::InsertPoint(uint16_t pt, int xx, int yy, bool oc) //we're adding to the end of the structure: [DONE, below] int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt)); for(int i=polyInsert; i= numPoints) +#ifdef DEBUG +{ +WriteLogMsg("Exception: GetXY(uint16_t). pt=%u, numPoints=%u\xD\xA", pt, numPoints); +#endif + throw GP_OUT_OF_RANGE; +#ifdef DEBUG +} +#endif + + return Vector(x[pt], y[pt]); +} + + bool GlyphPoints::GetOnCurve(uint16_t pt) { if (pt >= numPoints) diff --git a/src/glyphpoints.h b/src/glyphpoints.h index 8e8011f..5602cbe 100755 --- a/src/glyphpoints.h +++ b/src/glyphpoints.h @@ -12,6 +12,7 @@ #include #include +#include "vector.h" // "IPoint" is an Integer based Point @@ -66,6 +67,7 @@ class GlyphPoints uint16_t GetNumPolys(void); int GetX(uint16_t); int GetY(uint16_t); + Vector GetXY(uint16_t); bool GetOnCurve(uint16_t); int GetX(uint16_t, uint16_t); int GetNextX(uint16_t, uint16_t); diff --git a/src/graphicprimitives.cpp b/src/graphicprimitives.cpp deleted file mode 100755 index 9dec215..0000000 --- a/src/graphicprimitives.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// -// Graphics primitives -// -// Various graphic functions that are slightly more complex than those that -// come with various widget libraries. -// -// by James L. Hammons -// (C) 2005 Underground Software -// -// JLH = James L. Hammons -// -// Who When What -// --- ---------- ------------------------------------------------------------- -// JLH 03/14/1998 Created this file -// JLH 01/20/2005 Converted to use wxWidgets -// JLH 08/30/2008 Repurposed file to handle more than just bezier curves -// - -#include "graphicprimitives.h" - -double abs(double n) // Helper function -{ - return (n < 0 ? -n : n); -} - - -// -// This function takes three points and draws a curve using a second order -// Bezier function. -// -void Bezier(QPainter &p, point p1, point p2, point p3) -{ - double step = abs(p1.x - p3.x), tmp = abs(p1.y - p3.y); - step = (tmp > step ? tmp : step); // Get the larger of the two... - step = (step > 0 ? 1/step : 1); // & convert to valid step value - step *= 2.0; // (double it to draw less...) - - int prevX = (int)p1.x, prevY = (int)p1.y; - - for(double u=0; u<=1; u+=step) - { - double _2u = 2*u, _uu = u*u, _2uu = 2*_uu; - double x = (p1.x * (1 - _2u + _uu)) + (p2.x * (_2u - _2uu)) + (p3.x * _uu); - double y = (p1.y * (1 - _2u + _uu)) + (p2.y * (_2u - _2uu)) + (p3.y * _uu); - - p.drawLine(prevX, prevY, (int)x, (int)y); - prevX = (int)x, prevY = (int)y; - } - - p.drawLine(prevX, prevY, (int)p3.x, (int)p3.y); -} - - -// -// This is a convenience funtion, using IPoints :-) -// -void Bezier(QPainter &p, IPoint p1, IPoint p2, IPoint p3) -{ - Bezier(p, point(p1.x, p1.y), point(p2.x, p2.y), point(p3.x, p3.y)); -} - - -// -// Draw a round dot (5x5, centered on [x, y]) -// -void DrawRoundDot(QPainter &p, int32_t x, int32_t y) -{ - QPoint pt[8]; - - pt[0] = QPoint(x - 1, y - 2); - pt[1] = QPoint(x + 1, y - 2); - pt[2] = QPoint(x + 2, y - 1); - pt[3] = QPoint(x + 2, y + 1); - pt[4] = QPoint(x + 1, y + 2); - pt[5] = QPoint(x - 1, y + 2); - pt[6] = QPoint(x - 2, y + 1); - pt[7] = QPoint(x - 2, y - 1); - - p.drawPolygon(pt, 8); -} - - -// -// Draw a sqaure dot (5x5, centered on [x, y]) -// -void DrawSquareDot(QPainter &p, int32_t x, int32_t y) -{ - QPoint pt[4]; - - pt[0] = QPoint(x - 2, y - 2); - pt[1] = QPoint(x + 2, y - 2); - pt[2] = QPoint(x + 2, y + 2); - pt[3] = QPoint(x - 2, y + 2); - - p.drawPolygon(pt, 4); -} - - -// -// Draw a sqaure dot (nxn, centered on [x, y]) -// -void DrawSquareDotN(QPainter &p, int32_t x, int32_t y, uint32_t n) -{ - QPoint pt[4]; - uint32_t offset = (n - 1) / 2; - - pt[0] = QPoint(x - offset, y - offset); - pt[1] = QPoint(x + offset, y - offset); - pt[2] = QPoint(x + offset, y + offset); - pt[3] = QPoint(x - offset, y + offset); - - p.drawPolygon(pt, 4); -} - - -// -// Draw a round dot (nxn, centered on [x, y]) -// -void DrawRoundDotN(QPainter &p, int32_t x, int32_t y, uint32_t n) -{ - int radius = (n / 2) + 1; - p.drawEllipse(x - radius, y - radius, n, n); -} diff --git a/src/graphicprimitives.h b/src/graphicprimitives.h deleted file mode 100755 index 6d5b27b..0000000 --- a/src/graphicprimitives.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Graphics primitives -// -// Various graphic functions that are slightly more complex than those that -// come with various widget libraries. -// - -#ifndef __GRAPHICPRIMITIVES_H__ -#define __GRAPHICPRIMITIVES_H__ - -#include -#include // For QPainter -#include "glyphpoints.h" // For IPoint - -struct point -{ - float x, y; - - point(float xx = 0, float yy = 0): x(xx), y(yy) {} -}; - -void Bezier(QPainter &, point, point, point); -void Bezier(QPainter &, IPoint, IPoint, IPoint); -void DrawRoundDot(QPainter &, int32_t, int32_t); -void DrawSquareDot(QPainter &, int32_t, int32_t); -void DrawRoundDotN(QPainter &, int32_t, int32_t, uint32_t); -void DrawSquareDotN(QPainter &, int32_t, int32_t, uint32_t); - -#endif // __GRAPHICPRIMITIVES_H__ diff --git a/src/list.h b/src/list.h index b202fcb..cc430d0 100755 --- a/src/list.h +++ b/src/list.h @@ -1,15 +1,15 @@ // // A generic list class using a circular singly linked list -// by James L. Hammons -// (C) 2004 Underground Software +// by James Hammons +// (C) 2016 Underground Software // -// Based upon work I did for CS240 Project 5 at Cal Poly Pomona for Dr. Bruce Hillam. -// Hello Dr. Hillam! :-) +// Based upon work I did for CS240 Project 5 at Cal Poly Pomona for Dr. Bruce +// Hillam. Hello Dr. Hillam! :-) // // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 08/30/1999 Created this file // JLH 05/11/2004 Cleaned up a few things in the implementation // diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index dea9087..ef738e9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6,7 +6,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 04/10/2002 Created this file // JLH 05/10/2004 Translated file from ASM to CPP // JLH 05/14/2004 Added rudimentary editing capability to tool palette tools @@ -18,7 +18,8 @@ // FIXED: // -// - Fix problem with tool palette not getting focus 1st time it's called up [DONE] +// - Fix problem with tool palette not getting focus 1st time it's called up +// [DONE] // - Split out windows/classes defined here into their own files [DONE] // // STILL TO BE DONE: @@ -47,7 +48,7 @@ MainWindow::MainWindow() setCentralWidget(editWnd); editWnd->setFocus(); setWindowIcon(QIcon(":/res/ttedit.png")); - setWindowTitle("TTEdit!"); + setWindowTitle("TTEdit! - Untitled"); #if 0 // createActions(); @@ -102,6 +103,8 @@ MainWindow::MainWindow() #endif // Create status bar + scaleIndicator = new QLabel("Scale: 100%"); + statusBar()->addPermanentWidget(scaleIndicator); statusBar()->showMessage(tr("Ready")); ReadSettings(); @@ -119,8 +122,8 @@ MainWindow::MainWindow() // // Consolidates action creation from a multi-step process to a single-step one. // -QAction * MainWindow::CreateAction(QString name, QString tooltip, QString statustip, - QIcon icon, QKeySequence key, bool checkable/*= false*/) +QAction * MainWindow::CreateAction(QString name, QString tooltip, QString + statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/) { QAction * action = new QAction(icon, name, this); action->setToolTip(tooltip); @@ -136,8 +139,9 @@ QAction * MainWindow::CreateAction(QString name, QString tooltip, QString status // This is essentially the same as the previous function, but this allows more // than one key sequence to be added as key shortcuts. // -QAction * MainWindow::CreateAction(QString name, QString tooltip, QString statustip, - QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/) +QAction * MainWindow::CreateAction(QString name, QString tooltip, QString + statustip, QIcon icon, QKeySequence key1, QKeySequence key2, bool + checkable/*= false*/) { QAction * action = new QAction(icon, name, this); action->setToolTip(tooltip); @@ -155,12 +159,18 @@ QAction * MainWindow::CreateAction(QString name, QString tooltip, QString status void MainWindow::CreateActions(void) { newGlyphAct = CreateAction("&New Glyph", "New Glyph", "Create a new glyph", QIcon(), QKeySequence()); - openFileAct = CreateAction("&Open File", "Open File", "Open a glyph file", QIcon(), QKeySequence()); - saveFileAct = CreateAction("&Save File", "Save File", "Save a glyph file", QIcon(), QKeySequence()); + openFileAct = CreateAction("&Open File", "Open File", "Open a glyph file", QIcon(), QKeySequence("ctrl+o")); + saveFileAct = CreateAction("&Save File", "Save File", "Save a glyph file", QIcon(), QKeySequence("ctrl+s")); + quitAct = CreateAction("&Quit", "Quit", "Exits from the TTEdit application", QIcon(), QKeySequence("ctrl+q")); + zoomInAct = CreateAction("Zoom In", "Zoom In", "Zoom into the canvas", QIcon(), QKeySequence("+"), QKeySequence("=")); + zoomOutAct = CreateAction("Zoom Out", "Zoom Out", "Zoom out of canvas", QIcon(), QKeySequence("-")); connect(newGlyphAct, SIGNAL(triggered()), this, SLOT(NewGlyph())); connect(openFileAct, SIGNAL(triggered()), this, SLOT(OpenFile())); connect(saveFileAct, SIGNAL(triggered()), this, SLOT(SaveFile())); + connect(quitAct, SIGNAL(triggered()), this, SLOT(close())); + connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomIn())); + connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOut())); } @@ -170,8 +180,13 @@ void MainWindow::CreateMenus(void) menu->addAction(newGlyphAct); menu->addAction(openFileAct); menu->addAction(saveFileAct); + menu->addSeparator(); + menu->addAction(quitAct); // menu->addAction(fileSaveAsAct); // menu->addAction(fileCloseAct); + menu = menuBar()->addMenu(tr("&View")); + menu->addAction(zoomInAct); + menu->addAction(zoomOutAct); } @@ -194,6 +209,8 @@ void MainWindow::NewGlyph(void) ((TTEdit *)qApp)->charWnd->update(); // editWnd->polyFirstPoint = true; editWnd->update(); + setWindowTitle("TTEdit! - Untitled"); + editWnd->setFocus(); } @@ -213,6 +230,8 @@ void MainWindow::OpenFile(void) ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&(editWnd->pts)); ((TTEdit *)qApp)->charWnd->update(); editWnd->update(); + setWindowTitle(QString("TTEdit! - %1").arg(filename)); + editWnd->setFocus(); } @@ -228,6 +247,30 @@ void MainWindow::SaveFile(void) editWnd->pts.SaveGlyphToFile(file); fclose(file); + setWindowTitle(QString("TTEdit! - %1").arg(filename)); + editWnd->setFocus(); +} + + +void MainWindow::ZoomIn(void) +{ + if (editWnd->scale == 4.0) + return; + + editWnd->scale *= 2.0; + scaleIndicator->setText(QString("Scale: %1%").arg(editWnd->scale * 100.0)); + editWnd->update(); +} + + +void MainWindow::ZoomOut(void) +{ + if (editWnd->scale == 0.25) + return; + + editWnd->scale *= 0.5; + scaleIndicator->setText(QString("Scale: %1%").arg(editWnd->scale * 100.0)); + editWnd->update(); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 7038b1e..bc547de 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -32,6 +32,8 @@ class MainWindow: public QMainWindow void NewGlyph(void); void OpenFile(void); void SaveFile(void); + void ZoomIn(void); + void ZoomOut(void); private: QAction * CreateAction(QString name, QString tooltip, QString statustip, @@ -46,6 +48,7 @@ class MainWindow: public QMainWindow EditWindow * editWnd; // CharWindow * charWnd; + QLabel * scaleIndicator; #if 0 private: protected: @@ -70,6 +73,11 @@ class MainWindow: public QMainWindow QAction * newGlyphAct; QAction * openFileAct; QAction * saveFileAct; + QAction * quitAct; + QAction * zoomInAct; + QAction * zoomOutAct; + QAction * scaleAct; +// QString filename; }; #endif // __MAINWINDOW_H__ diff --git a/src/mathconstants.h b/src/mathconstants.h new file mode 100644 index 0000000..42f4940 --- /dev/null +++ b/src/mathconstants.h @@ -0,0 +1,23 @@ +// Mathematical Constants used by Architektonas +// +// Part of the Architektonas Project +// (C) 2011 Underground Software +// See the README and GPLv3 files for licensing and warranty information +// +// NOTE: Since this has no code associated with it, there is no corresponding +// .cpp file. +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 04/01/2011 Created this file +// + +#define PI 3.14159265358979323846264338327 +#define PI_OVER_2 (PI / 2.0) +#define PI3_OVER_2 ((3.0 * PI) / 2.0) +#define PI_TIMES_2 (PI * 2.0) +#define RADIANS_TO_DEGREES (180.0 / PI) +#define DEGREES_TO_RADIANS (PI / 180.0) + diff --git a/src/painter.cpp b/src/painter.cpp new file mode 100644 index 0000000..16268e7 --- /dev/null +++ b/src/painter.cpp @@ -0,0 +1,490 @@ +// +// painter.cpp: Paint abstraction layer between Archtektonas and Qt +// +// Part of the Architektonas Project +// (C) 2011 Underground Software +// See the README and GPLv3 files for licensing and warranty information +// +// JLH = James Hammons +// +// WHO WHEN WHAT +// --- ---------- ------------------------------------------------------------ +// JLH 09/20/2011 Created this file +// + +#include "painter.h" +#include "global.h" +#include "mathconstants.h" + + +// Set class variable defaults +//Vector Painter::origin(-10.0, -10.0); +//double Painter::zoom = 1.0; +//Vector Painter::screenSize(200.0, 200.0); + + +Painter::Painter(QPainter * p/*= NULL*/): painter(p) +{ +} + + +Painter::~Painter() +{ +} + + +Vector Painter::CartesianToQtCoords(Vector v) +{ + // Convert regular Cartesian coordinates to the inverted Y-axis Qt + // coordinates at the current origin and zoom level. + return Vector((v.x - Global::origin.x) * Global::zoom, Global::screenSize.y - ((v.y - Global::origin.y) * Global::zoom)); +} + + +Vector Painter::QtToCartesianCoords(Vector v) +{ + // Convert screen location, with inverted Y-axis coordinates, to regular + // Cartesian coordinates at the current zoom level. + return Vector((v.x / Global::zoom) + Global::origin.x, ((Global::screenSize.y - v.y) / Global::zoom) + Global::origin.y); +/* +How to do it: + +e.g., we have a point on the screen at Qt coords of 10, 10, screenSize is 100, 100. +origin is -10, -10 and zoom level is 2 (200%) + +1st, invert the Y: 10, 10 -> 10, 90 +2nd, add origin: 10, 90 -> 0, 80 (no, not right--err, yes, it is) +3rd, aply zoom: 0, 80 -> 0, 40 + +or, is it: + +1st, invert the Y: 10, 10 -> 10, 90 +2nd, aply zoom: 10, 90 -> 5, 45 +3rd, add origin: 5, 45 -> -5, 35 + +it depends on whether or not origin is in Qt coords or cartesian. If Qt, then the 1st +is correct, otherwise, the 2nd is correct. + +The way we calculate the Cartesian to Qt shows the 2nd (origin is cartesian) to be correct. +*/ +} + + +void Painter::SetRenderHint(int hint) +{ + if (!painter) + return; + + painter->setRenderHint((QPainter::RenderHint)hint); +} + + +void Painter::SetPen(QPen pen) +{ + if (!painter) + return; + + painter->setPen(pen); +} + + +void Painter::SetPen(uint32_t color, float size/*= 0*/, int style/*= 0*/) +{ + if (!painter) + return; + + // We can cast style as Qt:PenStyle because they line up 1-to-1 + painter->setPen(QPen(QColor(color >> 16, (color >> 8) & 0xFF, color & 0xFF, 255), + size, (Qt::PenStyle)style)); +} + + +void Painter::SetBrush(QBrush brush) +{ + if (!painter) + return; + + painter->setBrush(brush); +} + + +void Painter::SetBrush(uint32_t color) +{ + if (!painter) + return; + + painter->setBrush(QBrush(QColor(color >> 16, (color >> 8) & 0xFF, color & 0xFF, 255))); +} + + +void Painter::SetFont(QFont font) +{ + if (!painter) + return; + + painter->setFont(font); +} + + +void Painter::DrawAngledText(Vector center, double angle, QString text, double size) +{ + if (!painter) + return; + + // Strategy: Since Qt doesn't have any rotated text drawing functions, + // we instead translate the origin to the center of the text to be drawn and + // then rotate the frame to the desired angle. + center = CartesianToQtCoords(center); + + // We may need this stuff... If dimension text is large enough. +// int textWidth = QFontMetrics(painter->font()).width(text); +// int textHeight = QFontMetrics(painter->font()).height(); + QRectF textBox(-100.0 * Global::zoom * size, -100.0 * Global::zoom * size, 200.0 * Global::zoom * size, 200.0 * Global::zoom * size); // x, y, w, h; x/y = upper left corner + + // This is in pixels. Might not render correctly at all zoom levels. + // 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; + + // Fix text so it isn't upside down... + if ((angle > PI * 0.5) && (angle < PI * 1.5)) + { + angle += PI; + yOffset = 12.0 * Global::zoom * size; + } + + textBox.translate(0, yOffset); + painter->save(); + painter->translate(center.x, center.y); + // Angles are backwards in the Qt coord system, so we flip ours... + painter->rotate(-angle * RADIANS_TO_DEGREES); +//Need to fix this so the text scales as well... + painter->drawText(textBox, Qt::AlignCenter, text); + painter->restore(); +} + + +// +// Draw angled text. Draws text using point p as the upper left corner. +// Size is point size, angle is in radians (defaults to 0). +// +void Painter::DrawTextObject(Point p, QString text, double size, double angle/*= 0*/) +{ + if (!painter) + return; + + p = CartesianToQtCoords(p); + painter->setFont(QFont("Arial", Global::zoom * size)); + int textWidth = QFontMetrics(painter->font()).width(text); + int textHeight = QFontMetrics(painter->font()).height(); + + QRectF textBox(0, 0, textWidth, textHeight); + painter->save(); + painter->translate(p.x, p.y); + // Angles are backwards in the Qt coord system, so we flip ours... + painter->rotate(-angle * RADIANS_TO_DEGREES); + painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop , text); + painter->restore(); +} + + +void Painter::DrawArc(Vector center, double radius, double startAngle, double span) +{ + center = CartesianToQtCoords(center); + // Need to multiply scalar quantities by the zoom factor as well... + radius *= Global::zoom; + QRectF rectangle(QPointF(center.x - radius, center.y - radius), + QPointF(center.x + radius, center.y + radius)); + int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0); + int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0); + painter->drawArc(rectangle, angle1, angle2); +} + + +void Painter::DrawEllipse(Vector center, double axis1, double axis2) +{ + // Need to multiply scalar quantities by the zoom factor as well... + center = CartesianToQtCoords(center); + painter->drawEllipse(QPointF(center.x, center.y), axis1 * Global::zoom, axis2 * Global::zoom); +} + + +// This function is for drawing object handles without regard for zoom level; +// we don't want our object handle size to depend on the zoom level! +void Painter::DrawHandle(Vector center) +{ + center = CartesianToQtCoords(center); + painter->setPen(QPen(Qt::red, 2.0, Qt::DotLine)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0); +} + + +// This function is for drawing object handles without regard for zoom level; +// we don't want our object handle size to depend on the zoom level! +void Painter::DrawArrowHandle(Vector center, double angle) +{ + center = CartesianToQtCoords(center); + QPolygonF arrow; + + // Since we're drawing directly on the screen, the Y is inverted. So we use + // the mirror of the angle. + double orthoAngle = -angle + (PI / 2.0); + Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle)); + Vector unit = Vector(cos(-angle), sin(-angle)); + + Point p0 = center + (unit * 6.0); + Point p1 = center + (unit * 21.0); + Point p1b = center + (unit * 11.0); + Point p2 = p1b + (orthogonal * 5.0); + Point p3 = p1b - (orthogonal * 5.0); + + painter->drawLine(p0.x, p0.y, p1.x, p1.y); + arrow << QPointF(p1.x, p1.y) << QPointF(p2.x, p2.y) << QPointF(p3.x, p3.y); + + painter->drawPolygon(arrow); +} + + +// This function is for drawing object handles without regard for zoom level; +// we don't want our object handle size to depend on the zoom level! +void Painter::DrawArrowToLineHandle(Vector center, double angle) +{ + DrawArrowHandle(center, angle); + center = CartesianToQtCoords(center); + + // Since we're drawing directly on the screen, the Y is inverted. So we use + // the mirror of the angle. + double orthoAngle = -angle + (PI / 2.0); + Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle)); + Vector unit = Vector(cos(-angle), sin(-angle)); + + Point p1 = center + (unit * 21.0); + Point p2 = p1 + (orthogonal * 7.0); + Point p3 = p1 - (orthogonal * 7.0); + + painter->drawLine(p2.x, p2.y, p3.x, p3.y); +} + + +void Painter::DrawLine(int x1, int y1, int x2, int y2) +{ + if (!painter) + return; + + Vector v1 = CartesianToQtCoords(Vector(x1, y1)); + Vector v2 = CartesianToQtCoords(Vector(x2, y2)); + painter->drawLine(v1.x, v1.y, v2.x, v2.y); +} + + +void Painter::DrawLine(Vector v1, Vector v2) +{ + if (!painter) + return; + + v1 = CartesianToQtCoords(v1); + v2 = CartesianToQtCoords(v2); + painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y)); +} + + +void Painter::DrawPoint(int x, int y) +{ + if (!painter) + return; + + Vector v = CartesianToQtCoords(Vector(x, y)); + painter->drawPoint(v.x, v.y); +} + + +// The rect passed in is in Qt coordinates... +void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY) +{ + if (!painter) + return; + + painter->drawRoundedRect(rect, radiusX, radiusY); +} + + +// The rect passed in is in Cartesian but we want to pad it by a set number of +// pixels (currently set at 8), so the pad looks the same regardless of zoom. +void Painter::DrawPaddedRect(QRectF rect) +{ + if (!painter) + return; + + Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y())); + Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom())); + QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y)); + screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom + painter->drawRect(screenRect); +} + + +void Painter::DrawRect(QRectF rect) +{ + if (!painter) + return; + + Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y())); + Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom())); + QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y)); + painter->drawRect(screenRect); +} + + +void Painter::DrawText(QRectF rect, int type, QString text) +{ + if (!painter) + return; + + painter->drawText(rect, (Qt::AlignmentFlag)type, text); +} + + +void Painter::DrawArrowhead(Vector head, Vector tail, double size) +{ + if (!painter) + return; + + QPolygonF arrow; + + // We draw the arrowhead aligned along the line from tail to head + double angle = Vector(head - tail).Angle(); + double orthoAngle = angle + (PI / 2.0); + Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle)); + Vector unit = Vector(head - tail).Unit(); + + Point p1 = head - (unit * 9.0 * size); + Point p2 = p1 + (orthogonal * 3.0 * size); + Point p3 = p1 - (orthogonal * 3.0 * size); + + Point p4 = CartesianToQtCoords(head); + Point p5 = CartesianToQtCoords(p2); + Point p6 = CartesianToQtCoords(p3); + + arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y); + + painter->drawPolygon(arrow); +} + + +// Point is given in Cartesian coordinates +void Painter::DrawCrosshair(Vector point) +{ + if (!painter) + return; + + Vector screenPoint = CartesianToQtCoords(point); + painter->drawLine(0, screenPoint.y, Global::screenSize.x, screenPoint.y); + painter->drawLine(screenPoint.x, 0, screenPoint.x, Global::screenSize.y); +} + + +void Painter::DrawInformativeText(QString text) +{ + painter->setFont(*Global::font); + QRectF bounds = painter->boundingRect(QRectF(), Qt::AlignVCenter, text); + bounds.moveTo(17.0, 17.0); + QRectF textRect = bounds; + textRect.adjust(-7.0, -7.0, 7.0, 7.0); + + QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine); + painter->setPen(pen); + painter->setBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F))); + painter->drawRoundedRect(textRect, 7.0, 7.0); + + pen = QPen(QColor(0x00, 0x5F, 0xDF)); + painter->setPen(pen); + painter->drawText(bounds, Qt::AlignVCenter, text); +} + + +void Painter::DrawBezier(Point p1, Point p2, Point p3) +{ + p1 = CartesianToQtCoords(p1); + p2 = CartesianToQtCoords(p2); + p3 = CartesianToQtCoords(p3); + + QPainterPath path; + path.moveTo(p1.x, p1.y); + path.quadTo(p2.x, p2.y, p3.x, p3.y); + painter->drawPath(path); +} + + +void Painter::DrawBezier(IPoint p1, IPoint p2, IPoint p3) +{ + DrawBezier(Point(p1.x, p1.y), Point(p2.x, p2.y), Point(p3.x, p3.y)); +} + + +// +// Draw a sqaure dot (5x5, centered on Vector; non-scaled) +// +void Painter::DrawSquareDot(Vector v) +{ + QPoint pt[4]; + v = CartesianToQtCoords(v); + + pt[0] = QPoint(v.x - 2, v.y - 2); + pt[1] = QPoint(v.x + 2, v.y - 2); + pt[2] = QPoint(v.x + 2, v.y + 2); + pt[3] = QPoint(v.x - 2, v.y + 2); + + painter->drawPolygon(pt, 4); +} + + +// +// Draw a round dot (5x5, centered on Vector; non-scaled) +// +void Painter::DrawRoundDot(Vector v) +{ + QPoint pt[8]; + v = CartesianToQtCoords(v); + + pt[0] = QPoint(v.x - 1, v.y - 2); + pt[1] = QPoint(v.x + 1, v.y - 2); + pt[2] = QPoint(v.x + 2, v.y - 1); + pt[3] = QPoint(v.x + 2, v.y + 1); + pt[4] = QPoint(v.x + 1, v.y + 2); + pt[5] = QPoint(v.x - 1, v.y + 2); + pt[6] = QPoint(v.x - 2, v.y + 1); + pt[7] = QPoint(v.x - 2, v.y - 1); + + painter->drawPolygon(pt, 8); +} + + +// +// Draw a sqaure dot (nxn, centered on Vector; non-scaled) +// +void Painter::DrawSquareDotN(Vector v, uint32_t n) +{ + QPoint pt[4]; + uint32_t offset = (n - 1) / 2; + v = CartesianToQtCoords(v); + + pt[0] = QPoint(v.x - offset, v.y - offset); + pt[1] = QPoint(v.x + offset, v.y - offset); + pt[2] = QPoint(v.x + offset, v.y + offset); + pt[3] = QPoint(v.x - offset, v.y + offset); + + painter->drawPolygon(pt, 4); +} + + +// +// Draw a round dot (nxn, centered on Vector; non-scaled) +// +void Painter::DrawRoundDotN(Vector v, uint32_t n) +{ + int radius = (n / 2) + 1; + v = CartesianToQtCoords(v); + painter->drawEllipse(v.x - radius, v.y - radius, n, n); +} diff --git a/src/painter.h b/src/painter.h new file mode 100644 index 0000000..c95b84a --- /dev/null +++ b/src/painter.h @@ -0,0 +1,63 @@ +#ifndef __PAINTER_H__ +#define __PAINTER_H__ + +#include +#include +#include "vector.h" +#include "glyphpoints.h" + +//#define SCREEN_ZOOM (1.0 / 4.0) + +// Forward declarations + +class Painter +{ + public: + Painter(QPainter * p = 0); + ~Painter(); + + void SetRenderHint(int); + void SetPen(QPen); + void SetPen(uint32_t, float size = 0, int style = 0); + void SetBrush(QBrush); + void SetBrush(uint32_t); + void SetFont(QFont); + void DrawAngledText(Vector, double, QString, double); + void DrawTextObject(Vector, QString, double, double angle = 0); + void DrawArc(Vector, double, double, double); + void DrawEllipse(Vector, double, double); + void DrawHandle(Vector); + void DrawArrowHandle(Vector, double); + void DrawArrowToLineHandle(Vector, double); + void DrawLine(int, int, int, int); + void DrawLine(Vector, Vector); + void DrawPoint(int, int); + void DrawRoundedRect(QRectF, double, double); + void DrawPaddedRect(QRectF); + void DrawRect(QRectF); + void DrawText(QRectF, int, QString); + void DrawArrowhead(Vector, Vector, double); + void DrawCrosshair(Vector); + void DrawInformativeText(QString); + void DrawBezier(Point, Point, Point); + void DrawBezier(IPoint, IPoint, IPoint); + void DrawSquareDot(Vector); + void DrawRoundDot(Vector); + void DrawSquareDotN(Vector, uint32_t); + void DrawRoundDotN(Vector, uint32_t); + + public: + static Vector CartesianToQtCoords(Vector); + static Vector QtToCartesianCoords(Vector); + + public: + // Class variables +// static Vector origin; // The window origin, not location of the origin +// static double zoom; // Window zoom factor +// static Vector screenSize; // Width & height of the window we're drawing on + + private: + QPainter * painter; +}; + +#endif // __PAINTER_H__ diff --git a/src/toolwindow.cpp b/src/toolwindow.cpp index 13d3754..fda5b8e 100755 --- a/src/toolwindow.cpp +++ b/src/toolwindow.cpp @@ -6,7 +6,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 08/28/2008 Created this file // JLH 03/11/2009 Converted from wxWidgets to Qt // @@ -81,8 +81,10 @@ ToolType ToolWindow::FindSelectedTool(void) newTool = (ToolType)((y * 4) + x); // We don't have 11 yet, so fix this if the user selected the blank space - if (newTool > 10) - newTool = TOOLNone; +//now we do! +// if (newTool > 10) +// newTool = TOOLNone; return newTool; } + diff --git a/src/toolwindow.h b/src/toolwindow.h index 47125c2..2864970 100755 --- a/src/toolwindow.h +++ b/src/toolwindow.h @@ -16,7 +16,7 @@ enum ToolType { TOOLNone = -1, // No tool TOOLSelect = 0, // The "selection" tool TOOLPolySelect, // Polygon selection tool - TOOLScroll, // Scroll window tool + TOOLMultiSelect, // Rectangle selection tool TOOLZoom, // Zoom window tool TOOLAddPt, // Add point tool TOOLAddPoly, // Polygon creation tool @@ -24,7 +24,8 @@ enum ToolType { TOOLDelPoly, // Delete polygon tool TOOLRotate, // Rotate tool TOOLRotatePoly, // Rotate polygon around centroid tool - TOOLFlipWinding // Change polygon's winding direction tool + TOOLFlipWinding, // Change polygon's winding direction tool + TOOLScroll // Scroll window tool }; class ToolWindow: public QWidget diff --git a/src/ttedit.cpp b/src/ttedit.cpp index 9f34039..46e9943 100755 --- a/src/ttedit.cpp +++ b/src/ttedit.cpp @@ -6,7 +6,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH 04/10/2002 Created this file // JLH 05/10/2004 Translated file from ASM to CPP // JLH 05/14/2004 Added rudimentary editing capability to tool palette tools diff --git a/src/ttf.cpp b/src/ttf.cpp index 799f032..c8e6e7f 100755 --- a/src/ttf.cpp +++ b/src/ttf.cpp @@ -11,7 +11,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH ??/??/199? Created this file // // diff --git a/src/vector.cpp b/src/vector.cpp index 1ba2064..fe627cd 100755 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -9,7 +9,7 @@ // JLH = James L. Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ----------------------------------------------------------- // JLH ??/??/2003 Created original implementation // JLH 05/14/2004 Separated header from implementation, added operator- // function @@ -153,7 +153,7 @@ void vector::zero(const double epsilon/*= 1.0e-6*/) // JLH = James L. Hammons // // WHO WHEN WHAT -// --- ---------- ------------------------------------------------------------ +// --- ---------- ---------------------------------------------------------- // JLH 09/19/2006 Created this file // JLH 03/22/2011 Moved implementation of constructor from header to here // JLH 04/02/2011 Fixed divide-by-zero bug in Unit(), added Angle() function diff --git a/ttedit.pro b/ttedit.pro index 1e86018..426123b 100644 --- a/ttedit.pro +++ b/ttedit.pro @@ -5,26 +5,29 @@ CONFIG += qt #CONFIG += qt debug QT += widgets -HEADERS += src/ttedit.h -HEADERS += src/mainwindow.h +HEADERS += src/charwindow.h +HEADERS += src/debug.h HEADERS += src/editwindow.h +HEADERS += src/global.h HEADERS += src/glyphpoints.h -HEADERS += src/debug.h +HEADERS += src/list.h +HEADERS += src/mainwindow.h +HEADERS += src/mathconstants.h +HEADERS += src/painter.h HEADERS += src/toolwindow.h -HEADERS += src/charwindow.h +HEADERS += src/ttedit.h HEADERS += src/vector.h -HEADERS += src/graphicprimitives.h -HEADERS += src/list.h -SOURCES += src/ttedit.cpp -SOURCES += src/mainwindow.cpp +SOURCES += src/charwindow.cpp +SOURCES += src/debug.cpp SOURCES += src/editwindow.cpp +SOURCES += src/global.cpp SOURCES += src/glyphpoints.cpp -SOURCES += src/debug.cpp +SOURCES += src/mainwindow.cpp +SOURCES += src/painter.cpp SOURCES += src/toolwindow.cpp -SOURCES += src/charwindow.cpp +SOURCES += src/ttedit.cpp SOURCES += src/vector.cpp -SOURCES += src/graphicprimitives.cpp RESOURCES += ttedit.qrc diff --git a/ttedit.qrc b/ttedit.qrc index 5607bf9..9fcad59 100644 --- a/ttedit.qrc +++ b/ttedit.qrc @@ -2,6 +2,7 @@ res/cursor-select.png res/cursor-select-poly.png + res/cursor-select-multi.png res/cursor-scroll.png res/cursor-zoom.png res/cursor-add-point.png