From b5981e2c452fa0ad5d922025780f9200450698dc Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Mon, 3 Oct 2011 23:09:51 +0000 Subject: [PATCH] Fixed zoom to zoom in/out of center, new icons. --- res/architektonas.qrc | 2 + src/applicationwindow.cpp | 71 ++++-- src/drawingview.cpp | 519 +------------------------------------- src/drawingview.h | 2 - 4 files changed, 58 insertions(+), 536 deletions(-) diff --git a/res/architektonas.qrc b/res/architektonas.qrc index 0b5079e..c3e6385 100644 --- a/res/architektonas.qrc +++ b/res/architektonas.qrc @@ -8,5 +8,7 @@ generic-tool.png splash.png quit.png + zoom-in.png + zoom-out.png diff --git a/src/applicationwindow.cpp b/src/applicationwindow.cpp index f658a9b..3ade284 100644 --- a/src/applicationwindow.cpp +++ b/src/applicationwindow.cpp @@ -10,6 +10,8 @@ // Who When What // --- ---------- ------------------------------------------------------------- // JLH 03/22/2011 Created this file +// JLH 09/29/2011 Added simple zoom in/out functionality +// JLH 10/03/2011 Fixed zoom tool to zoom in/out from center of screen // // FIXED: @@ -103,19 +105,64 @@ void ApplicationWindow::RotateTool(void) void ApplicationWindow::ZoomInTool(void) { + double zoomFactor = 2.0; +/* +We need to find the center of the screen, then figure out where the new corner +will be in the zoomed in window. + +So we know in Qt coords, the center is found via: +size.width() / 2 --> xCenter +size.height() / 2 --> yCenter + +transform x/yCenter to Cartesian coordinates. So far, so good. + +when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.y) / 2 +(after subtracting from center, that is...) +*/ + QSize size = drawing->size(); + Vector center(size.width() / 2.0, size.height() / 2.0); +//printf("Zoom in... Center=%.2f,%.2f; ", center.x, center.y); + center = Painter::QtToCartesianCoords(center); +//printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y); + Vector newOrigin = center - ((center - Painter::origin) / zoomFactor); +//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y); + Painter::origin = newOrigin; + //printf("Zoom in... level going from %02f to ", Painter::zoom); - // This just zooms leaving origin intact... should zoom in at the current center! -// drawing->ZoomIn(); - Painter::zoom *= 2.0; + // This just zooms leaving origin intact... should zoom in at the current center! [DONE] + Painter::zoom *= zoomFactor; drawing->update(); } void ApplicationWindow::ZoomOutTool(void) { +/* +Ok, real example. +center = (436, 311) +origin = (223, 160.5) +newOrigin should be (-10, -10) +Why isn't it? + +center - origin = (213, 150.5) +origin - center = (-213, -150.5) +x 2 = (-426, -301) ++ center = (-10, -10) + +*/ + double zoomFactor = 2.0; + QSize size = drawing->size(); + Vector center(size.width() / 2.0, size.height() / 2.0); +//printf("Zoom out... Center=%.2f,%.2f; ", center.x, center.y); + center = Painter::QtToCartesianCoords(center); +//printf("(%.2f,%.2f); origin=%.2f,%.2f; ", center.x, center.y, Painter::origin.x, Painter::origin.y); +// Vector newOrigin = (center - Painter::origin) * zoomFactor; +// Vector newOrigin = center - (Painter::origin * zoomFactor); + Vector newOrigin = center + ((Painter::origin - center) * zoomFactor); +//printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y); + Painter::origin = newOrigin; //printf("Zoom out...\n"); - // This just zooms leaving origin intact... should zoom out at the current center! -// drawing->ZoomOut(); - Painter::zoom /= 2.0; + // This just zooms leaving origin intact... should zoom out at the current center! [DONE] + Painter::zoom /= zoomFactor; drawing->update(); } @@ -169,10 +216,10 @@ void ApplicationWindow::CreateActions(void) rotateAct = CreateAction(tr("&Rotate Objects"), tr("Rotate"), tr("Rotate object(s) around an arbitrary center."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("R,O")), true); connect(rotateAct, SIGNAL(triggered()), this, SLOT(RotateTool())); - zoomInAct = CreateAction(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("="))); + zoomInAct = CreateAction2(tr("Zoom &In"), tr("Zoom In"), tr("Zoom in on the document."), QIcon(":/res/zoom-in.png"), QKeySequence(tr("+")), QKeySequence(tr("="))); connect(zoomInAct, SIGNAL(triggered()), this, SLOT(ZoomInTool())); - zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("-"))); + zoomOutAct = CreateAction(tr("Zoom &Out"), tr("Zoom Out"), tr("Zoom out of the document."), QIcon(":/res/zoom-out.png"), QKeySequence(tr("-"))); connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(ZoomOutTool())); fileNewAct = CreateAction(tr("&New Drawing"), tr("New Drawing"), tr("Creates a new drawing."), QIcon(":/res/generic-tool.png"), QKeySequence(tr("Ctrl+n"))); @@ -260,16 +307,8 @@ void ApplicationWindow::CreateMenus(void) menu->addSeparator(); menu->addAction(settingsAct); -// editMenu = menuBar()->addMenu(tr("&Edit")); -// editMenu->addAction(cutAct); -// editMenu->addAction(copyAct); -// editMenu->addAction(pasteAct); - -// menuBar()->addSeparator(); - menu = menuBar()->addMenu(tr("&Help")); menu->addAction(aboutAct); -// helpMenu->addAction(aboutQtAct); } void ApplicationWindow::CreateToolbars(void) diff --git a/src/drawingview.cpp b/src/drawingview.cpp index a3a6eb1..4a71fa6 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -9,6 +9,7 @@ // Who When What // --- ---------- ------------------------------------------------------------- // JLH 03/22/2011 Created this file +// JLH 09/29/2011 Added middle mouse button panning // // FIXED: @@ -77,17 +78,6 @@ void DrawingView::SetRotateToolActive(bool state/*= true*/) update(); } -//These are not needed... :-P -#if 0 -void DrawingView::ZoomIn(void) -{ -} - -void DrawingView::ZoomOut(void); -{ -} -#endif - QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event) { // This is undoing the transform, e.g. going from client coords to local coords. @@ -113,22 +103,6 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) qtPainter.setRenderHint(QPainter::Antialiasing); Painter::screenSize = Vector(size().width(), size().height()); -// Painter::zoom = 2.0; // 200% zoom -#if 0 -#if 0 - painter.translate(QPoint(-offsetX, size.height() - (-offsetY))); - painter.scale(1.0, -1.0); -#else - QTransform transform; -//order of operations is important! N.B.: Can't use scaling other than 1.0, it -//causes lines to look strange (i.e., it scales the pen strokes too) -// transform.translate(-offsetX, size().height() - (-offsetY)); - transform.scale(1.0, -1.0); - transform.translate(-offsetX, -size().height() - offsetY); -// transform.scale(0.25, 0.25); - painter.setTransform(transform); -#endif -#endif Object::SetViewportHeight(size().height()); // Draw coordinate axes @@ -254,494 +228,3 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event) setCursor(Qt::ArrowCursor); } } - - -#if 0 -QSize DrawingView::minimumSizeHint() const -{ - return QSize(50, 50); -} - -QSize DrawingView::sizeHint() const -{ - return QSize(400, 400); -} - -void DrawingView::CreateCursors(void) -{ - int hotx[8] = { 1, 1, 11, 15, 1, 1, 1, 1 }; - int hoty[8] = { 1, 1, 11, 13, 1, 1, 1, 1 }; - - for(int i=0; i<8; i++) - { - QString s; - s.sprintf(":/res/cursor%u.png", i+1); - QPixmap pmTmp(s); - cur[i] = QCursor(pmTmp, hotx[i], hoty[i]); - } -} - -/* -TODO: - o Different colors for polys on selected points - o Different colors for handles on non-selected polys - o Line of sight (dashed, dotted) for off-curve points - o Repaints for press/release of CTRL/SHIFT during point creation -*/ -void DrawingView::paintEvent(QPaintEvent * /*event*/) -{ - QPainter p(this); -//hm, causes lockup -// 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); - -// Scrolling can be done by using OffsetViewportOrgEx -// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform) -// you'd use: % = ViewportExt / WindowExt -// But it makes the window look like crap: fuggetuboutit. -// 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 - -// dc.CrossHair(0, 0); - p.drawLine(0, -16384, 0, 16384); - p.drawLine(-16384, 0, 16384, 0); - - // Draw points - - for(int i=0; iFindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID))); -//// SelectObject(hdc, hRedPen1); - p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine)); - - if (pts.GetOnCurve(i)) - { - DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7); - DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9); - } - else - { - DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7); - DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9); - } - } - 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)) - { - DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7); - DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9); - } - else - { - DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7); - DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9); - } - } - 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)) - DrawSquareDot(p, pts.GetX(i), pts.GetY(i)); - else - DrawRoundDot(p, pts.GetX(i), pts.GetY(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 2) - { - // Initial move... - // If it's not on curve, then move to it, otherwise move to last point... - - int x, y; - - 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); - - for(int i=0; ibutton() == Qt::RightButton) - { - toolPalette->move(event->globalPos()); - toolPalette->setVisible(true); - setCursor(cur[TOOLSelect]); - toolPalette->prevTool = TOOLSelect; - } - else if (event->button() == Qt::MidButton) - { - setCursor(cur[2]); // Scrolling cursor - } - 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 == TOOLAddPt) // "Add Point" tool - { - if (pts.GetNumPoints() > 0) - { - QPoint pt = GetAdjustedMousePosition(event); - pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true)); - ptHighlight = ptNextHighlight; - update(); - } - } - else if (tool == TOOLAddPoly) // "Add Poly" tool - { -#ifdef DEBUGFOO -WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints()); -#endif - if (polyFirstPoint) - { - polyFirstPoint = false; - pts.AddNewPolyAtEnd(); - } - - QPoint pt = GetAdjustedMousePosition(event); -//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)); - ptHighlight = pts.GetNumPoints() - 1; - update(); -#ifdef DEBUGFOO -WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints()); -#endif - } - else if (tool == TOOLSelect || tool == TOOLPolySelect) - { - if (pts.GetNumPoints() > 0) - { - pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight)); -//printf("GetAdjustedClientPosition = %i, %i\n", pt.x(), pt.y()); -// WarpPointer(pt.x, pt.y); - QCursor::setPos(mapToGlobal(pt)); - - if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) - { - pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight)); - update(); - } - } - } - else if (tool == TOOLDelPt) - { - if (pts.GetNumPoints() > 0) -//Or could use: -// if (ptHighlight != -1) - { -//This assumes that WM_MOUSEMOVE happens before this! -//The above commented out line should take care of this contingency... !!! FIX !!! - pts.DeletePoint(ptHighlight); - update(); - } - } - } - - event->accept(); -} - -void DrawingView::mouseMoveEvent(QMouseEvent * event) -{ - if (event->buttons() == Qt::RightButton) - { - ToolType newTool = toolPalette->FindSelectedTool(); - - if (newTool != toolPalette->prevTool) - { - toolPalette->prevTool = newTool; - toolPalette->repaint(); - } - } - else if (event->buttons() == Qt::MidButton) - { - // Calc offset from previous point - pt = event->pos(); - ptOffset = QPoint(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(); - update(); - ptPrevious = pt; - } - 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); - -// 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(); - } - else -#endif - if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect) - { - if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch. - { -//temporary, for testing. BTW, Select drag bug is here...! -#if 1 - QPoint pt2 = GetAdjustedMousePosition(event); - pts.SetXY(ptHighlight, pt2.x(), pt2.y()); - update(); -#endif - } - } - 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? - pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight)); - update(); - } - } - } - else if (event->buttons() == Qt::NoButton) - { - // Moving, not dragging... - if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt - || tool == TOOLPolySelect)// || tool == TOOLAddPoly) - { - QPoint pt2 = GetAdjustedMousePosition(event); - double closest = 1.0e+99; - - for(int i=0; i 1 && tool == TOOLAddPt) - { - double smallest = 1.0e+99; - - for(int i=0; i 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(); - else // distance = ?Det?(ls, v1) / |ls| - dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length()); - -//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: -// -//sx sy 1 -//ex ey 1 -//px py 1 -// -//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!] -// -//0 0 0 -//(ex - sx) (ey - sy) 0 -//(px - sx) (py - sy) 0 -// -//which greatly simplifies the calculation of the determinant. - - if (dist < smallest) - smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i; - } - - if (ptNextHighlight != oldPtNextHighlight) - { - oldPtNextHighlight = ptNextHighlight; - update(); - } - } - } - - ptPrevious = event->pos(); - } - - event->accept(); -} - -void DrawingView::mouseReleaseEvent(QMouseEvent * event) -{ - if (event->button() == Qt::RightButton) - { - ToolType newTool = toolPalette->FindSelectedTool(); - - // We only change the tool if a new one was actually selected. Otherwise, we do nothing. - if (newTool != TOOLNone) - { - tool = newTool; - - if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly - || tool == TOOLDelPoly) - ptHighlight = -1; - - if (tool == TOOLAddPoly) - polyFirstPoint = true; - } - - toolPalette->setVisible(false); - setCursor(cur[tool]); - // Just in case we changed highlighting style with the new tool... - update(); - } - else if (event->button() == Qt::MidButton) - { - setCursor(cur[tool]); // Restore previous cursor - } - else if (event->button() == Qt::LeftButton) - { -// if (tool == TOOLScroll || tool == TOOLZoom) -// ReleaseMouse(); -//this is prolly too much - ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts); - ((TTEdit *)qApp)->charWnd->update(); - } - - event->accept(); -} -#endif diff --git a/src/drawingview.h b/src/drawingview.h index dfb9f8f..7d4301e 100644 --- a/src/drawingview.h +++ b/src/drawingview.h @@ -14,8 +14,6 @@ class DrawingView: public QWidget public: void SetRotateToolActive(bool state = true); -// void ZoomIn(void); -// void ZoomOut(void); protected: void paintEvent(QPaintEvent * event); -- 2.37.2