//============================================================================= // // File : canvaswidget.cpp // Creation date : Mon Jul 30 07 2001 04:50:50 by Szymon Stefanek // // This file is part of the KVIrc IRC client distribution // Copyright (C) 2001-2010 Szymon Stefanek (pragma at kvirc dot net) // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #include "canvaswidget.h" #ifdef COMPILE_DCC_CANVAS #include "KviCString.h" #include "KviLocale.h" #include #include #include #include #include #include #include #include // // KviCanvasRectangleItem // KviCanvasRectangleItem::KviCanvasRectangleItem(QCanvas * c, int x, int y, int w, int h) : QCanvasRectangle(x, y, w, h, c) { } KviCanvasRectangleItem::~KviCanvasRectangleItem() { } void KviCanvasRectangleItem::drawSelection(QPainter & p) { p.setRasterOp(NotROP); p.fillRect((int)x() + 1, (int)y() + 1, width() - 2, height() - 2, QBrush(Dense6Pattern)); p.setPen(QPen(DotLine)); p.drawRect((int)x(), (int)y(), width(), height()); p.setRasterOp(CopyROP); } void KviCanvasRectangleItem::setProperty(const QString & property, const QVariant & val) { if(m_properties[property].isValid()) { m_properties.replace(property, val); hide(); show(); } } // // KviCanvasPolygon // KviCanvasPolygon::KviCanvasPolygon(QCanvas * c, int x, int y, QPointArray & pnts, double dScaleFactor) : QCanvasPolygon(c) { m_properties.insert("clrForeground", QVariant(QColor(0, 0, 0))); m_properties.insert("uLineWidth", QVariant((unsigned int)0)); m_properties.insert("clrBackground", QVariant(QColor(0, 0, 0))); m_properties.insert("bHasBackground", QVariant(false, 1)); m_dScaleFactor = dScaleFactor; m_points = pnts; resetPoints(); move(x, y); } KviCanvasPolygon::~KviCanvasPolygon() { } void KviCanvasPolygon::setScaleFactor(double dScaleFactor) { m_dScaleFactor = dScaleFactor; resetPoints(); } void KviCanvasPolygon::setInternalPoints(const QPointArray & pnts) { m_points = pnts; resetPoints(); } void KviCanvasPolygon::resetPoints() { QPointArray scaled(m_points.size()); for(unsigned int i = 0; i < m_points.size(); i++) { int px; int py; m_points.point(i, &px, &py); px = (int)(px * m_dScaleFactor); py = (int)(py * m_dScaleFactor); scaled.setPoint(i, px, py); } setPoints(scaled); } int KviCanvasPolygon::rtti() const { return KVI_CANVAS_RTTI_POLYGON; } void KviCanvasPolygon::setProperty(const QString & property, const QVariant & val) { if(m_properties[property].isValid()) { m_properties.replace(property, val); if((property == "clrForeground") || (property == "uLineWidth")) { setPen(QPen(m_properties["clrForeground"].asColor(), m_properties["uLineWidth"].toInt())); } else if((property == "clrBackground") || (property == "bHasBackground")) { if(m_properties["bHasBackground"].asBool()) setBrush(QBrush(m_properties["clrBackground"].asColor())); else setBrush(QBrush()); } else { hide(); show(); } } } void KviCanvasPolygon::draw(QPainter & p) { if(isEnabled()) { p.setBrush(brush()); p.setPen(pen()); p.drawPolygon(areaPoints()); } if(isSelected()) { p.setRasterOp(NotROP); p.setPen(QPen(DotLine)); p.drawPolygon(areaPoints()); p.setBrush(QBrush()); double dVal = 10; p.drawEllipse((int)(x() - dVal), (int)(y() - dVal), (int)(dVal * 2), (int)(dVal * 2)); p.drawLine((int)(x() - (dVal * 2)), (int)y(), (int)(x() + (dVal * 2)), (int)y()); p.drawLine((int)x(), (int)(y() - (dVal * 2)), (int)x(), (int)(y() + (dVal * 2))); p.setRasterOp(CopyROP); canvas()->setChanged(QRect((int)(x() - dVal), (int)(y() - dVal), (int)(dVal * 4), (int)(dVal * 4))); } } // // KviCanvasEllipticItem // KviCanvasEllipticItem::KviCanvasEllipticItem(QCanvas * c, int x, int y, int w, int h) : KviCanvasRectangleItem(c, x, y, w, h) { m_properties.insert("clrForeground", QVariant(QColor(0, 0, 0))); m_properties.insert("uLineWidth", QVariant((unsigned int)0)); m_properties.insert("clrBackground", QVariant(QColor(0, 0, 0))); m_properties.insert("bHasBackground", QVariant(false, 1)); // m_properties.insert("iStartAngle",QVariant(0)); // m_properties.insert("iEndAngle",QVariant(360)); } KviCanvasEllipticItem::~KviCanvasEllipticItem() { } void KviCanvasEllipticItem::draw(QPainter & p) { if(isEnabled()) { QBrush b = p.brush(); if(m_properties["bHasBackground"].asBool()) p.setBrush(m_properties["clrBackground"].asColor()); else p.setBrush(QBrush()); p.setPen(pen()); drawContent(p); p.setBrush(b); } if(isSelected()) drawSelection(p); } void KviCanvasEllipticItem::drawContent(QPainter & p) { } void KviCanvasEllipticItem::setProperty(const QString & property, const QVariant & val) { if(m_properties[property].isValid()) { m_properties.replace(property, val); if((property == "clrForeground") || (property == "uLineWidth")) { setPen(QPen(m_properties["clrForeground"].asColor(), m_properties["uLineWidth"].toInt())); } else { hide(); show(); } } } int KviCanvasEllipticItem::rtti() const { return KVI_CANVAS_RTTI_ELLIPSE; } // // KviCanvasEllipse // KviCanvasEllipse::KviCanvasEllipse(QCanvas * c, int x, int y, int w, int h) : KviCanvasEllipticItem(c, x, y, w, h) { } KviCanvasEllipse::~KviCanvasEllipse() { } int KviCanvasEllipse::rtti() const { return KVI_CANVAS_RTTI_ELLIPSE; } void KviCanvasEllipse::drawContent(QPainter & p) { p.drawEllipse((int)x(), (int)y(), width(), height()); } // // KviCanvasPie // KviCanvasPie::KviCanvasPie(QCanvas * c, int x, int y, int w, int h) : KviCanvasEllipticItem(c, x, y, w, h) { m_properties.insert("iStartAngle", QVariant((int)0)); m_properties.insert("iExtensionAngle", QVariant((int)360)); } KviCanvasPie::~KviCanvasPie() { } int KviCanvasPie::rtti() const { return KVI_CANVAS_RTTI_PIE; } void KviCanvasPie::drawContent(QPainter & p) { int iStartAngle = m_properties["iStartAngle"].asInt() * 16; int iEndAngle = m_properties["iExtensionAngle"].asInt() * 16; p.drawPie((int)x(), (int)y(), width(), height(), iStartAngle, iEndAngle); } // // KviCanvasChord // KviCanvasChord::KviCanvasChord(QCanvas * c, int x, int y, int w, int h) : KviCanvasEllipticItem(c, x, y, w, h) { m_properties.insert("iStartAngle", QVariant((int)0)); m_properties.insert("iExtensionAngle", QVariant((int)360)); } KviCanvasChord::~KviCanvasChord() { } int KviCanvasChord::rtti() const { return KVI_CANVAS_RTTI_CHORD; } void KviCanvasChord::drawContent(QPainter & p) { int iStartAngle = m_properties["iStartAngle"].asInt() * 16; int iEndAngle = m_properties["iExtensionAngle"].asInt() * 16; p.drawChord((int)x(), (int)y(), width(), height(), iStartAngle, iEndAngle); } // // KviCanvasRectangle // KviCanvasRectangle::KviCanvasRectangle(QCanvas * c, int x, int y, int w, int h) : KviCanvasRectangleItem(c, x, y, w, h) { m_properties.insert("clrForeground", QVariant(QColor(0, 0, 0))); m_properties.insert("uLineWidth", QVariant((unsigned int)0)); m_properties.insert("clrBackground", QVariant(QColor(0, 0, 0))); m_properties.insert("bHasBackground", QVariant(false, 1)); } KviCanvasRectangle::~KviCanvasRectangle() { } int KviCanvasRectangle::rtti() const { return KVI_CANVAS_RTTI_RECTANGLE; } void KviCanvasRectangle::setProperty(const QString & property, const QVariant & val) { if(m_properties[property].isValid()) { m_properties.replace(property, val); if((property == "clrForeground") || (property == "uLineWidth")) { setPen(QPen(m_properties["clrForeground"].asColor(), m_properties["uLineWidth"].toInt())); } else { hide(); show(); } } } void KviCanvasRectangle::draw(QPainter & p) { if(isEnabled()) { if(m_properties["bHasBackground"].asBool()) { p.fillRect((int)x() + 1, (int)y() + 1, width() - 2, height() - 2, m_properties["clrBackground"].asColor()); } p.setPen(pen()); p.drawRect((int)x(), (int)y(), width(), height()); } if(isSelected()) drawSelection(p); } // // KviCanvasRichText // KviCanvasRichText::KviCanvasRichText(QCanvas * c, int x, int y, int w, int h) : KviCanvasRectangleItem(c, x, y, w, h) { QFont f = QFont(); f.setStyleHint(QFont::SansSerif); f.setPointSize(12); m_properties.insert("szText", QVariant(QString("Insert here your RICH TEXT"))); m_properties.insert("fntDefault", QVariant(f)); } KviCanvasRichText::~KviCanvasRichText() { } int KviCanvasRichText::rtti() const { return KVI_CANVAS_RTTI_RICHTEXT; } void KviCanvasRichText::draw(QPainter & p) { if(isEnabled()) { QString szText = m_properties["szText"].asString(); QSimpleRichText text(szText, m_properties["fntDefault"].asFont()); text.setWidth(width()); text.draw(&p, (int)x() + 1, (int)y() + 1, QRegion(QRect((int)x() + 1, (int)y() + 1, width(), height())), QColorGroup()); } if(isSelected()) drawSelection(p); } // // KviCanvasLine // KviCanvasLine::KviCanvasLine(QCanvas * c, int x1, int y1, int x2, int y2) : QCanvasLine(c) { setPoints(x1, y1, x2, y2); m_properties.insert("uLineWidth", QVariant((unsigned int)0)); m_properties.insert("clrForeground", QVariant(QColor())); } KviCanvasLine::~KviCanvasLine() { } void KviCanvasLine::setProperty(const QString & property, const QVariant & val) { m_properties.replace(property, val); if((property == "uLineWidth") || (property == "clrForeground")) { setPen(QPen(m_properties["clrForeground"].asColor(), m_properties["uLineWidth"].toInt())); } } int KviCanvasLine::rtti() const { return KVI_CANVAS_RTTI_LINE; } void KviCanvasLine::draw(QPainter & p) { if(isEnabled()) { p.setPen(pen()); p.drawLine(startPoint(), endPoint()); } if(isSelected()) { p.setRasterOp(NotROP); p.setPen(QPen(DotLine)); p.drawLine(startPoint(), endPoint()); p.setRasterOp(CopyROP); } } // // KviCanvasView // KviCanvasView::KviCanvasView(QCanvas * c, DccCanvasWidget * cw, QWidget * par) : QCanvasView(c, par) { m_pCanvasWidget = cw; m_state = Idle; m_dragMode = None; m_pSelectedItem = nullptr; viewport()->setMouseTracking(true); } KviCanvasView::~KviCanvasView() { } void KviCanvasView::insertRectangle() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = Rectangle; } void KviCanvasView::insertRichText() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = RichText; } void KviCanvasView::insertLine() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = Line; } void KviCanvasView::insertEllipse() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = Ellipse; } void KviCanvasView::insertPie() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = Pie; } void KviCanvasView::insertChord() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = Chord; } void KviCanvasView::insertPolygonTriangle() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = PolygonTriangle; } void KviCanvasView::insertPolygonRectangle() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = PolygonRectangle; } void KviCanvasView::insertPolygonPentagon() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = PolygonPentagon; } void KviCanvasView::insertPolygonHexagon() { m_state = SelectOrigin; setCursor(crossCursor); m_objectToInsert = PolygonPentagon; } #ifndef M_PI #define M_PI 3.14159265358979323846 #endif static void calcPolygonPoints(QPointArray & pnts, unsigned int nVertices) { double dDelta = (2 * M_PI) / nVertices; for(unsigned int i = 0; i < nVertices; i++) { double dAng = dDelta * i; double theX = 300 * sin(dAng); double theY = 300 * cos(dAng); pnts.setPoint(i, (int)theX, (int)theY); } } void KviCanvasView::insertObjectAt(const QPoint & pnt, ObjectType o) { QCanvasItem * r = nullptr; switch(o) { case Rectangle: r = new KviCanvasRectangle(canvas(), pnt.x(), pnt.y(), 0, 0); break; case RichText: r = new KviCanvasRichText(canvas(), pnt.x(), pnt.y(), 0, 0); break; case Line: r = new KviCanvasLine(canvas(), pnt.x(), pnt.y(), pnt.x(), pnt.y()); break; case Ellipse: r = new KviCanvasEllipse(canvas(), pnt.x(), pnt.y(), 0, 0); break; case Pie: r = new KviCanvasPie(canvas(), pnt.x(), pnt.y(), 0, 0); break; case Chord: r = new KviCanvasChord(canvas(), pnt.x(), pnt.y(), 0, 0); break; case PolygonTriangle: { QPointArray pa(3); pa.setPoint(0, 0, -500); pa.setPoint(1, -450, 220); pa.setPoint(2, 450, 220); r = new KviCanvasPolygon(canvas(), pnt.x(), pnt.y(), pa, 0.1); } break; case PolygonRectangle: { QPointArray pa(4); pa.setPoint(0, -350, -350); pa.setPoint(1, 350, -350); pa.setPoint(2, 350, 350); pa.setPoint(3, -350, 350); r = new KviCanvasPolygon(canvas(), pnt.x(), pnt.y(), pa, 0.1); } break; case PolygonPentagon: { QPointArray pa(5); calcPolygonPoints(pa, 5); r = new KviCanvasPolygon(canvas(), pnt.x(), pnt.y(), pa, 0.1); } break; case PolygonHexagon: { QPointArray pa(6); calcPolygonPoints(pa, 6); r = new KviCanvasPolygon(canvas(), pnt.x(), pnt.y(), pa, 0.1); } break; } if(r) { setItemSelected(r); r->setEnabled(true); r->show(); } switch(KVI_CANVAS_RTTI_CONTROL_TYPE(r)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: beginDragRectangle((KviCanvasRectangleItem *)r, pnt, true); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: beginDragLine((KviCanvasLine *)r, pnt, true); break; // case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: // beginDragPolygon((KviCanvasPolygon *)r,pnt,true); // break; } // canvas()->update(); } void KviCanvasView::setItemSelected(QCanvasItem * it) { clearSelection(); it->setSelected(true); m_pSelectedItem = it; m_pCanvasWidget->m_pPropertiesWidget->editItem(it); } void KviCanvasView::clearSelection() { if(!m_pSelectedItem) return; m_pSelectedItem->setSelected(false); m_pSelectedItem = nullptr; m_pCanvasWidget->m_pPropertiesWidget->editItem(0); } void KviCanvasView::beginDragLine(KviCanvasLine * it, const QPoint & p, bool bInitial) { QPoint sp = it->startPoint(); m_dragBegin = p - sp; if(bInitial) { m_dragMode = Bottom; setCursor(sizeAllCursor); return; } if((abs(p.x() - sp.x()) < 3) && (abs(p.y() - sp.y()) < 3)) { m_dragMode = Top; setCursor(sizeAllCursor); return; } sp = it->endPoint(); if((abs(p.x() - sp.x()) < 3) && (abs(p.y() - sp.y()) < 3)) { m_dragMode = Bottom; setCursor(sizeAllCursor); return; } m_dragMode = All; setCursor(pointingHandCursor); } void KviCanvasView::dragLine(KviCanvasLine * it, const QPoint & p) { switch(m_dragMode) { case Bottom: { QPoint sp = it->startPoint(); it->setPoints(sp.x(), sp.y(), p.x(), p.y()); } break; case Top: { QPoint ep = it->endPoint(); it->setPoints(p.x(), p.y(), ep.x(), ep.y()); } break; case All: { QPoint sp = p - m_dragBegin; QPoint ep = sp + (it->endPoint() - it->startPoint()); it->setPoints(sp.x(), sp.y(), ep.x(), ep.y()); } break; default: /* make gcc happy */ break; } canvas()->update(); } static double ssm_2d_rotationAngleFromXAxis(double dx, double dy) { // // v1 . v2 dx * 1 + dy * 0 dx //acos(---------) = acos(-----------------) = acos(---------) // |v1||v2| |(dx,dy)| * 1 |(dx,dy)| // //double dVal = hypot(dx,dy); double dVal = sqrt((dx * dx) + (dy * dy)); if(dVal == 0.0) return 0; // ??? dVal = acos(dx / dVal); return (dy > 0.0) ? dVal : -dVal; } static double ssm_2d_rotationAngle(double drefx, double drefy, double drotatedx, double drotatedy) { double dRefAngle = ssm_2d_rotationAngleFromXAxis(drefx, drefy); double dRotAngle = ssm_2d_rotationAngleFromXAxis(drotatedx, drotatedy); return dRotAngle - dRefAngle; } static void ssm_2d_rotate(double & dx, double & dy, double dAngle) { // Rotation matrix: // // | cos(x) sin(x) | // | | // | -sin(x) cos(x) | double s = sin(dAngle); double c = cos(dAngle); double tmpX = (dx * c) - (dy * s); double tmpY = (dx * s) + (dy * c); dx = tmpX; dy = tmpY; } static double ssm_hypot(double a, double b) { return sqrt((a * a) + (b * b)); } void KviCanvasView::beginDragPolygon(KviCanvasPolygon * it, const QPoint & p, bool bShift, bool bCtrl) { m_dragBegin = QPoint((int)(p.x() - it->x()), (int)(p.y() - it->y())); QPointArray pa = it->areaPoints(); for(unsigned int i = 0; i < pa.size(); i++) { QPoint pnt = pa.point(i); double dX = pnt.x() - p.x(); double dY = pnt.y() - p.y(); double dHypot = sqrt((dX * dX) + (dY * dY)); if(dHypot < 3.0) { // We're dragging a point m_dragMode = SinglePoint; m_dragPointIndex = i; setCursor(crossCursor); return; } } if(bShift) { m_dragMode = Scale; m_dragScaleFactor = it->scaleFactor(); setCursor(sizeAllCursor); return; } if(bCtrl) { m_dragMode = Rotate; m_dragPointArray = it->internalPoints(); // qDebug("Here"); setCursor(sizeHorCursor); return; } m_dragMode = All; setCursor(pointingHandCursor); } void KviCanvasView::dragPolygon(KviCanvasPolygon * it, const QPoint & p) { switch(m_dragMode) { case All: it->move(p.x() - m_dragBegin.x(), p.y() - m_dragBegin.y()); break; case SinglePoint: { QPointArray pnt = it->internalPoints(); pnt.setPoint(m_dragPointIndex, (int)((p.x() - it->x()) / it->scaleFactor()), (int)((p.y() - it->y()) / it->scaleFactor())); it->setInternalPoints(pnt); } break; case Scale: { double dDistance = ssm_hypot(p.x() - it->x(), p.y() - it->y()); double dOriginal = ssm_hypot(m_dragBegin.x(), m_dragBegin.y()); if(dOriginal < 1) dOriginal = 1; if(dDistance < 0.1) dDistance = 0.1; it->setScaleFactor(m_dragScaleFactor * dDistance / dOriginal); } break; case Rotate: { QPoint act((int)(p.x() - it->x()), (int)(p.y() - it->y())); double dAngle = ssm_2d_rotationAngle(m_dragBegin.x(), m_dragBegin.y(), act.x(), act.y()); // qDebug("%d,%d %d,%d %f",m_dragBegin.x(),m_dragBegin.y(),act.x(),act.y(),dAngle); QPointArray thePoints = m_dragPointArray.copy(); for(unsigned int i = 0; i < thePoints.size(); i++) { QPoint tmp = thePoints.point(i); double dx = tmp.x(); double dy = tmp.y(); ssm_2d_rotate(dx, dy, dAngle); thePoints.setPoint(i, (int)dx, (int)dy); } it->setInternalPoints(thePoints); } break; default: break; } canvas()->update(); } void KviCanvasView::beginDragRectangle(KviCanvasRectangleItem * it, const QPoint & p, bool bInitial) { m_dragBegin = QPoint((int)(p.x() - it->x()), (int)(p.y() - it->y())); if(bInitial) { // Right bottom m_dragMode = RightBottom; setCursor(sizeFDiagCursor); return; } if(p.x() < (((int)it->x()) + 2)) { // Left edge if(p.y() < (((int)it->y()) + 2)) { // Left top m_dragMode = LeftTop; setCursor(sizeFDiagCursor); return; } if(p.y() > (it->bottom() - 2)) { // Left bottom m_dragMode = LeftBottom; setCursor(sizeBDiagCursor); return; } m_dragMode = Left; setCursor(sizeHorCursor); return; } if(p.x() > (it->right() - 2)) { // Right edge if(p.y() < (((int)it->y()) + 2)) { // Right top m_dragMode = RightTop; setCursor(sizeBDiagCursor); return; } if(p.y() > (it->bottom() - 2)) { // Right bottom m_dragMode = RightBottom; setCursor(sizeFDiagCursor); return; } m_dragMode = Right; setCursor(sizeHorCursor); return; } // Somewhere in the middle if(p.y() < (((int)it->y()) + 2)) { // Top m_dragMode = Top; setCursor(sizeVerCursor); return; } if(p.y() > (it->bottom() - 2)) { // Bottom m_dragMode = Bottom; setCursor(sizeVerCursor); return; } m_dragMode = All; setCursor(pointingHandCursor); } void KviCanvasView::dragRectangle(KviCanvasRectangleItem * it, const QPoint & p) { int aux1, aux2, aux3, aux4; switch(m_dragMode) { case All: it->move(p.x() - m_dragBegin.x(), p.y() - m_dragBegin.y()); break; case Left: aux1 = it->width() + (int)(it->x() - p.x()); aux2 = p.x(); if(aux1 < 1) { aux2 += (aux1 - 1); aux1 = 1; } it->move(aux2, it->y()); it->setSize(aux1, it->height()); break; case Right: aux1 = it->width() + (p.x() - it->right()); if(aux1 < 1) aux1 = 1; it->setSize(aux1, it->height()); break; case Top: aux1 = it->height() + (int)(it->y() - p.y()); aux2 = p.y(); if(aux1 < 1) { aux2 += (aux1 - 1); aux1 = 1; } it->move(it->x(), aux2); it->setSize(it->width(), aux1); break; case Bottom: aux1 = (int)it->height() + (p.y() - it->bottom()); if(aux1 < 1) aux1 = 1; it->setSize(it->width(), aux1); break; case LeftTop: aux1 = it->width() + (int)(it->x() - p.x()); aux3 = p.x(); if(aux1 < 1) { aux3 += (aux1 - 1); aux1 = 1; } aux2 = it->height() + (int)(it->y() - p.y()); aux4 = p.y(); if(aux2 < 1) { aux4 += (aux2 - 1); aux2 = 1; } it->setSize(aux1, aux2); it->move(aux3, aux4); break; case RightTop: aux1 = it->width() + (int)(p.x() - it->right()); if(aux1 < 1) aux1 = 1; aux2 = it->height() + (int)(it->y() - p.y()); aux4 = p.y(); if(aux2 < 1) { aux4 += (aux2 - 1); aux2 = 1; } it->setSize(aux1, aux2); it->move(it->x(), aux4); break; case LeftBottom: aux1 = it->width() + (int)(it->x() - p.x()); aux3 = p.x(); if(aux1 < 1) { aux3 += (aux1 - 1); aux1 = 1; } aux2 = it->height() + (int)(p.y() - it->bottom()); if(aux2 < 1) aux2 = 1; it->setSize(aux1, aux2); it->move(aux3, it->y()); break; case RightBottom: aux1 = it->width() + (int)(p.x() - it->right()); if(aux1 < 1) aux1 = 1; aux2 = it->height() + (int)(p.y() - it->bottom()); if(aux2 < 1) aux2 = 1; it->setSize(aux1, aux2); break; default: break; } canvas()->update(); } void KviCanvasView::contentsMouseMoveEvent(QMouseEvent * e) { // QPoint p = inverseWorldMatrix().map(e->pos()); QPoint p = e->pos(); if(e->state() & Qt::LeftButton) { if((m_dragMode != None) && (m_pSelectedItem)) { if(m_pSelectedItem->isEnabled()) m_pSelectedItem->setEnabled(false); switch(KVI_CANVAS_RTTI_CONTROL_TYPE(m_pSelectedItem)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: dragRectangle((KviCanvasRectangleItem *)m_pSelectedItem, p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: dragLine((KviCanvasLine *)m_pSelectedItem, p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: dragPolygon((KviCanvasPolygon *)m_pSelectedItem, p); break; } } } else { // Without buttons if(m_state == Idle) { QCanvasItemList l = canvas()->collisions(p); QCanvasItemList::Iterator it = l.begin(); if(it != l.end()) { // Got an item QCanvasItem * hit = (QCanvasItem *)*it; // Now find the point on that we have clicked it if(hit == m_pSelectedItem) { switch(KVI_CANVAS_RTTI_CONTROL_TYPE(m_pSelectedItem)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: beginDragRectangle((KviCanvasRectangleItem *)m_pSelectedItem, p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: beginDragLine((KviCanvasLine *)m_pSelectedItem, p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: beginDragPolygon((KviCanvasPolygon *)m_pSelectedItem, p); break; } } else if(m_dragMode != None) setCursor(arrowCursor); } else { if(m_dragMode != None) setCursor(arrowCursor); } } } } void KviCanvasView::contentsMouseReleaseEvent(QMouseEvent * e) { if(m_dragMode != None) { // Was just dragging a rectangle m_dragMode = None; setCursor(arrowCursor); if(m_pSelectedItem) { m_pSelectedItem->setEnabled(true); canvas()->update(); } } } void KviCanvasView::contentsMousePressEvent(QMouseEvent * e) { if(e->button() & Qt::LeftButton) { // QPoint p = inverseWorldMatrix().map(e->pos()); QPoint p = e->pos(); switch(m_state) { case SelectOrigin: clearSelection(); setCursor(arrowCursor); m_state = Idle; insertObjectAt(p, m_objectToInsert); canvas()->update(); break; case Idle: { QCanvasItemList l = canvas()->collisions(p); QCanvasItemList::Iterator it = l.begin(); if(it != l.end()) { // Got an item QCanvasItem * hit = *it; if(hit != m_pSelectedItem) { // Was not selected yet setItemSelected(hit); canvas()->update(); } // Now find the point on that we have clicked it switch(KVI_CANVAS_RTTI_CONTROL_TYPE(hit)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: beginDragRectangle(((KviCanvasRectangleItem *)hit), p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: beginDragLine(((KviCanvasLine *)hit), p); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: beginDragPolygon(((KviCanvasPolygon *)hit), p, e->state() & Qt::ShiftButton, e->state() & Qt::ControlButton); break; } } else { // No item clearSelection(); canvas()->update(); } } break; } } } void KviCanvasView::propertyChanged(const QString & s, const QVariant & v) { if(!m_pSelectedItem) return; switch(KVI_CANVAS_RTTI_CONTROL_TYPE(m_pSelectedItem)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: ((KviCanvasRectangleItem *)m_pSelectedItem)->setProperty(s, v); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: ((KviCanvasLine *)m_pSelectedItem)->setProperty(s, v); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: ((KviCanvasPolygon *)m_pSelectedItem)->setProperty(s, v); break; } canvas()->update(); } // // KviVariantTableItem // KviVariantTableItem::KviVariantTableItem(QTable * t, const QVariant & property) : QTableItem(t, QTableItem::WhenCurrent, QString()) { m_property = property; } KviVariantTableItem::~KviVariantTableItem() { } QWidget * KviVariantTableItem::createEditor() const { switch(m_property.type()) { case QVariant::String: { QLineEdit * e = new QLineEdit(table()->viewport()); e->setText(m_property.toString()); return e; } break; case QVariant::Int: { QLineEdit * e = new QLineEdit(table()->viewport()); QString sz; sz.setNum(m_property.toInt()); e->setText(sz); e->setValidator(new QIntValidator(e)); return e; } break; case QVariant::UInt: { QLineEdit * e = new QLineEdit(table()->viewport()); QString sz; sz.setNum(m_property.toInt()); e->setText(sz); QIntValidator * i = new QIntValidator(e); i->setBottom(0); e->setValidator(i); return e; } break; case QVariant::Bool: { QComboBox * b = new QComboBox(false, table()->viewport()); b->addAction("false"); b->addAction("true"); b->setCurrentItem(m_property.toBool() ? 1 : 0); return b; } break; case QVariant::Color: { QLineEdit * e = new QLineEdit(table()->viewport()); e->setText(m_property.toColor().name()); return e; } break; case QVariant::Font: { QComboBox * b = new QComboBox(true, table()->viewport()); QString tmp; QString tmpDefault; QFont f = QFont(); f.setStyleHint(QFont::SansSerif); tmpDefault = f.family(); f.setStyleHint(QFont::TypeWriter); tmp.setNum(m_property.toFont().pointSize()); tmp.prepend(", "); tmp.prepend(m_property.toFont().family()); b->addAction(tmp); b->addAction(tmpDefault + ", 8"); b->addAction(tmpDefault + ", 10"); b->addAction(tmpDefault + ", 12"); b->addAction(tmpDefault + ", 14"); b->addAction(tmpDefault + ", 16"); b->addAction(tmpDefault + ", 18"); b->addAction(tmpDefault + ", 20"); b->addAction(tmpDefault + ", 24"); b->addAction(tmpDefault + ", 28"); b->addAction(tmpDefault + ", 32"); b->addAction(tmpDefault + ", 40"); b->addAction(tmpDefault + ", 48"); b->addAction(f.family() + ", 12"); b->setCurrentItem(0); b->setCurrentItem(m_property.toBool() ? 1 : 0); return b; } break; default: break; } return nullptr; } void KviVariantTableItem::setContentFromEditor(QWidget * w) { switch(m_property.type()) { case QVariant::String: m_property = QVariant(((QLineEdit *)w)->text()); break; case QVariant::Int: m_property = QVariant(((QLineEdit *)w)->text().toInt()); break; case QVariant::UInt: m_property = QVariant(((QLineEdit *)w)->text().toUInt()); break; case QVariant::Bool: m_property = QVariant(((QComboBox *)w)->currentItem(), 1); break; case QVariant::Color: m_property.asColor().setNamedColor(((QLineEdit *)w)->text()); break; case QVariant::Font: { KviCString txt = ((QComboBox *)w)->currentText(); if(txt.hasData()) { KviCString fam = txt; fam.cutFromFirst(',', true); fam.trimmed(); KviCString psz = txt; psz.cutToFirst(',', true); psz.trimmed(); bool bOk; unsigned int uSize = psz.toUInt(&bOk); if(!bOk) uSize = 12; m_property = QVariant(QFont(fam.ptr(), uSize)); } } break; default: break; } } void KviVariantTableItem::paint(QPainter * p, const QColorGroup & cg, const QRect & cr, bool) { p->fillRect(0, 0, cr.width(), cr.height(), cg.base()); if(m_property.type() == QVariant::Color) { p->fillRect(3, 3, cr.width() - 6, cr.height() - 6, m_property.asColor()); } else { QString sz; switch(m_property.type()) { case QVariant::String: sz = m_property.toString(); break; case QVariant::Bool: sz = m_property.toBool() ? "true" : "false"; break; case QVariant::Font: sz.setNum(m_property.toFont().pointSize()); sz.prepend(", "); sz.prepend(m_property.toFont().family()); break; case QVariant::Int: sz.setNum(m_property.toInt()); break; case QVariant::UInt: sz.setNum(m_property.toUInt()); break; default: break; } p->setPen(cg.text()); p->drawText(0, 0, cr.width(), cr.height(), Qt::AlignLeft | Qt::AlignTop, sz); } } // // KviCanvasItemPropertiesWidget // KviCanvasItemPropertiesWidget::KviCanvasItemPropertiesWidget(QWidget * par) : QTable(par) { setSelectionMode(QTable::NoSelection); setColumnMovingEnabled(false); setRowMovingEnabled(false); setShowGrid(true); setNumCols(2); setSorting(false); setLeftMargin(0); verticalHeader()->hide(); connect(this, SIGNAL(valueChanged(int, int)), this, SLOT(cellEdited(int, int))); } KviCanvasItemPropertiesWidget::~KviCanvasItemPropertiesWidget() { } void KviCanvasItemPropertiesWidget::cellEdited(int row, int) { QTableItem * it = item(row, 0); if(!it) return; QString szName = it->text(); it = item(row, 1); if(!it) return; emit propertyChanged(szName, ((KviVariantTableItem *)it)->property()); } void KviCanvasItemPropertiesWidget::editItem(QCanvasItem * it) { if(!it) { for(int i = 0; i < numRows(); i++) { clearCell(i, 0); clearCell(i, 1); clearCellWidget(i, 1); } setNumRows(0); return; } QMap * m = nullptr; switch(KVI_CANVAS_RTTI_CONTROL_TYPE(it)) { case KVI_CANVAS_RTTI_CONTROL_TYPE_RECTANGLE: m = ((KviCanvasRectangleItem *)it)->properties(); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_LINE: m = ((KviCanvasLine *)it)->properties(); break; case KVI_CANVAS_RTTI_CONTROL_TYPE_POLYGON: m = ((KviCanvasPolygon *)it)->properties(); break; } if(!m) { editItem(0); return; } for(int i = 0; i < numRows(); i++) { clearCell(i, 0); clearCell(i, 1); clearCellWidget(i, 1); } setNumRows(m->count()); QTableItem * item; int idx = 0; for(QMap::ConstIterator iter = m->begin(); iter != m->end(); ++iter) { item = new QTableItem(this, QTableItem::Never, iter.key().toUtf8().data()); setItem(idx, 0, item); item = new KviVariantTableItem(this, iter.data()); setItem(idx, 1, item); idx++; } } // // DccCanvasWidget // DccCanvasWidget::DccCanvasWidget(QWidget * par) : QWidget(par, "canvas_widget") { m_pCanvas = new QCanvas(this); //#warning "Make this size as parameter of Dcc ?" m_pCanvas->resize(648, 480); m_pMenuBar = new QMenuBar(this); m_pSplitter = new QSplitter(QSplitter::Horizontal, this); m_pCanvasView = new KviCanvasView(m_pCanvas, this, m_pSplitter); m_pStatusLabel = new QLabel(this); m_pPropertiesWidget = new KviCanvasItemPropertiesWidget(m_pSplitter); QValueList l; l.append(80); l.append(20); m_pSplitter->setSizes(l); connect(m_pPropertiesWidget, SIGNAL(propertyChanged(const QString &, const QVariant &)), m_pCanvasView, SLOT(propertyChanged(const QString &, const QVariant &))); QMenu * add = new QMenu(m_pMenuBar); QMenu * shapes = new QMenu(add); QMenu * polygons = new QMenu(add); QMenu * items = new QMenu(add); shapes->addAction(__tr2qs_ctx("&Line", "dcc"), m_pCanvasView, SLOT(insertLine())); shapes->addAction(__tr2qs_ctx("&Rectangle", "dcc"), m_pCanvasView, SLOT(insertRectangle())); shapes->addAction(__tr2qs_ctx("&Ellipse", "dcc"), m_pCanvasView, SLOT(insertEllipse())); shapes->addAction(__tr2qs_ctx("&Pie", "dcc"), m_pCanvasView, SLOT(insertPie())); shapes->addAction(__tr2qs_ctx("&Chord", "dcc"), m_pCanvasView, SLOT(insertChord())); items->addAction(__tr2qs_ctx("&Rich text (html)", "dcc"), m_pCanvasView, SLOT(insertRichText())); polygons->addAction(__tr2qs_ctx("&Triangle", "dcc"), m_pCanvasView, SLOT(insertPolygonTriangle())); polygons->addAction(__tr2qs_ctx("&Rectangle", "dcc"), m_pCanvasView, SLOT(insertPolygonRectangle())); polygons->addAction(__tr2qs_ctx("&Pentagon", "dcc"), m_pCanvasView, SLOT(insertPolygonPentagon())); polygons->addAction(__tr2qs_ctx("&Hexagon", "dcc"), m_pCanvasView, SLOT(insertPolygonHexagon())); add->addAction(__tr2qs_ctx("&Shape", "dcc"), shapes); add->addAction(__tr2qs_ctx("&Item", "dcc"), items); add->addAction(__tr2qs_ctx("&Polygons", "dcc"), polygons); m_pMenuBar->addAction(__tr2qs_ctx("&Insert", "dcc"), add); } DccCanvasWidget::~DccCanvasWidget() { } void DccCanvasWidget::resizeEvent(QResizeEvent *) { int h = m_pMenuBar->sizeHint().height(); m_pMenuBar->setGeometry(0, 0, width(), h); int h2 = m_pStatusLabel->sizeHint().height(); m_pStatusLabel->setGeometry(0, height() - h2, width(), h2); m_pSplitter->setGeometry(0, h, width(), height() - (h + h2)); } #endif