diff --git a/src/libkstapp/labelitem.cpp b/src/libkstapp/labelitem.cpp index 8abca68a..b9c6c410 100644 --- a/src/libkstapp/labelitem.cpp +++ b/src/libkstapp/labelitem.cpp @@ -1,488 +1,488 @@ /*************************************************************************** * * * copyright : (C) 2007 The University of Toronto * * netterfield@astro.utoronto.ca * * * * 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. * * * ***************************************************************************/ #include "labelitem.h" #include #include "labelrenderer.h" #include "labelitemdialog.h" #include "labelcreator.h" #include "applicationsettings.h" #include "debug.h" #include "dialogdefaults.h" #include "plotitem.h" #include "cartesianrenderitem.h" #include "labelscriptinterface.h" #include #include #include #include namespace Kst { LabelItem::LabelItem(View *parent, const QString& txt) : ViewItem(parent), _labelRc(0), _dirty(true), _text(txt), _height(0), _resized(false), _dataRelativeDimValid(false), _fixleft(false), _serialOfLastChange(0) { setTypeName(tr("Label", "a label in a plot")); setFixedSize(true); setLockAspectRatio(true); setAllowedGripModes(Move | Resize | Rotate /*| Scale*/); applyDefaults(); } ScriptInterface* LabelItem::createScriptInterface() { return new LabelSI(this); } bool LabelItem::inputsChanged(qint64 serial) { bool no_change = true; foreach (Primitive* primitive, _labelRc->_refObjects) { if (primitive->serialOfLastChange() > _serialOfLastChange) { no_change = false; } } if (!no_change) { triggerUpdate(); } _serialOfLastChange = serial; return !no_change; } void LabelItem::applyDefaults() { QFont font; font.fromString(dialogDefaults().value(defaultsGroupName()+"/font",font.toString()).toString()); _font = font; _color = dialogDefaults().value(defaultsGroupName()+"/color",QColor(Qt::black)).value(); _scale = dialogDefaults().value(defaultsGroupName()+"/fontScale",12).toDouble(); _fixleft = dialogDefaults().value(defaultsGroupName()+"/fixLeft",true).toBool(); - applyDialogDefaultsStroke(); - applyDialogDefaultsFill(); + applyDialogDefaultsStroke(true); + applyDialogDefaultsFill(true); applyDialogDefaultsLockPosToData(); } void LabelItem::saveAsDialogDefaults() const { QFont F = _font; F.setPointSize(_scale); LabelItem::saveDialogDefaultsFont(F, _color); } void LabelItem::saveDialogDefaultsFont(const QFont &F, const QColor &C) { dialogDefaults().setValue(staticDefaultsGroupName()+"/font", QVariant(F).toString()); dialogDefaults().setValue(staticDefaultsGroupName()+"/color", C.name()); dialogDefaults().setValue(staticDefaultsGroupName()+"/fontScale", F.pointSize()); } LabelItem::~LabelItem() { delete _labelRc; } void LabelItem::generateLabel(QPainter *p) { double lines = 1.0; if (_labelRc) { lines = _labelRc->lines; delete _labelRc; } Label::Parsed *parsed = Label::parse(_text, _color); if (parsed) { _dirty = false; QFont font(_font); if (_resized) { font.setPointSizeF(view()->scaledFontSize(_scale, *p->device())); Label::RenderContext *tmpRc = new Label::RenderContext(font, p); double fs_adjust = rect().height()/(tmpRc->fontHeight()*(lines+1)); _scale *= fs_adjust; delete tmpRc; } font.setPointSizeF(view()->scaledFontSize(_scale, *p->device())); _labelRc = new Label::RenderContext(font, p); Label::renderLabel(*_labelRc, parsed->chunk, true, false); _height = _labelRc->fontHeight(); qreal x_margin = _height/8.0; // Make sure we have a rect for selection, movement, etc if (_resized) { _resized = false; double x0 = rect().x(); double y0 = rect().y(); double x1 = x0 + rect().width(); double y1 = y0 + rect().height(); double w = _labelRc->xMax + 2*x_margin; double h = (_labelRc->lines+1) * _height + x_margin; switch(_activeGrip) { case TopLeftGrip: setViewRect(QRectF(x1-w,y1-h,w,h)); break; case TopRightGrip: setViewRect(QRectF(x0,y1-h,w,h)); break; case BottomLeftGrip: setViewRect(QRectF(x1-w,y0,w,h)); break; case BottomRightGrip: case NoGrip: default: setViewRect(QRectF(x0,y0,w,h)); break; } } else { if (fixLeft()) { setViewRect(QRectF(rect().left(), rect().bottom() - (_labelRc->lines+1) * _height - x_margin, _labelRc->xMax+2*x_margin, (_labelRc->lines+1) * _height+x_margin),true); } else { setViewRect(QRectF(rect().right()-_labelRc->xMax-2*x_margin, rect().bottom() - (_labelRc->lines+1) * _height - x_margin, _labelRc->xMax+2*x_margin, (_labelRc->lines+1) * _height + x_margin),true); } } _paintTransform.reset(); _paintTransform.translate(rect().x()+x_margin, rect().y() + _labelRc->fontAscent()); connect(_labelRc, SIGNAL(labelDirty()), this, SLOT(setDirty())); connect(_labelRc, SIGNAL(labelDirty()), this, SLOT(triggerUpdate())); delete parsed; } } void LabelItem::paint(QPainter *painter) { // possible optimization: make _dirty actually work to save label // regeneration on 'paint'. Unlikely to be noticeable though. //if (_dirty || 1) { generateLabel(painter); //} if (_labelRc) { painter->save(); painter->setBrush(brush()); painter->setPen(pen()); painter->drawRect(rect()); painter->setTransform(_paintTransform, true); Label::paintLabel(*_labelRc, painter); painter->restore(); } } void LabelItem::triggerUpdate() { update(); } void LabelItem::save(QXmlStreamWriter &xml) { if (isVisible()) { xml.writeStartElement("label"); xml.writeAttribute("text", _text); xml.writeAttribute("scale", QVariant(_scale).toString()); xml.writeAttribute("color", QVariant(_color).toString()); xml.writeAttribute("font", QVariant(_font).toString()); xml.writeAttribute("fixleft", QVariant(_fixleft).toString()); ViewItem::save(xml); xml.writeEndElement(); } } QString LabelItem::labelText() { return _text; } void LabelItem::setLabelText(const QString &text) { _text = text; setDirty(); } qreal LabelItem::labelScale() { return _scale; } void LabelItem::setLabelScale(const qreal scale) { _scale = scale; setDirty(); } QColor LabelItem::labelColor() const { return _color; } void LabelItem::setLabelColor(const QColor &color) { _color = color; setDirty(); } void LabelItem::edit() { LabelItemDialog *editDialog = new LabelItemDialog(this); editDialog->show(); } QFont LabelItem::labelFont() const { return _font; } void LabelItem::setLabelFont(const QFont &font) { _font = font; setDirty(); } void LabelItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { ViewItem::mouseMoveEvent(event); if ((gripMode() == ViewItem::Resize) && (activeGrip() != NoGrip)) { _resized = true; } } void LabelItem::creationPolygonChanged(View::CreationEvent event) { if (event == View::MouseMove) { if (view()->creationPolygon(View::MouseMove).size()>0) { const QPointF P = view()->creationPolygon(View::MouseMove).last(); setPos(P); setDirty(); } } else if (event == View::MouseRelease) { view()->disconnect(this, SLOT(deleteLater())); //Don't delete ourself view()->disconnect(this, SLOT(creationPolygonChanged(View::CreationEvent))); view()->setMouseMode(View::Default); updateViewItemParent(); updateRelativeSize(); emit creationComplete(); setDirty(); return; } else if (event != View::MousePress) { ViewItem::creationPolygonChanged(event); } } void LabelItem::setFont(const QFont &f, const QColor &c) { setLabelColor(c); setLabelFont(f); setLabelScale(f.pointSize()); } void CreateLabelCommand::createItem() { createTextItem(0); } void CreateLabelCommand::createTextItem(QString *inText) { if (inText) { _item = new LabelItem(_view, *inText); } else { bool ok = false; QString text; LabelCreator dialog; if (dialog.exec() == QDialog::Accepted) { text = dialog.labelText(); ok = true; } if (!ok || text.isEmpty()) { return; } _item = new LabelItem(_view, text); LabelItem *label = qobject_cast(_item); label->setLabelScale(dialog.labelScale()); label->setLabelColor(dialog.labelColor()); label->setLabelFont(dialog.labelFont()); label->setFixLeft(dialog.fixLeft()); label->setLockPosToData(dialog.lockPosToData()); if (dialog.saveAsDefaults()) { label->saveAsDialogDefaults(); dialogDefaults().setValue(label->staticDefaultsGroupName()+"/fixLeft",dialog.fixLeft()); dialogDefaults().setValue(label->staticDefaultsGroupName()+"/lockPosToData",dialog.lockPosToData()); } } _item->view()->scene()->addItem(_item); _view->setCursor(Qt::IBeamCursor); CreateCommand::createItem(); } LabelItemFactory::LabelItemFactory() : GraphicsFactory() { registerFactory("label", this); } LabelItemFactory::~LabelItemFactory() { } ViewItem* LabelItemFactory::generateGraphics(QXmlStreamReader& xml, ObjectStore *store, View *view, ViewItem *parent) { LabelItem *rc = 0; while (!xml.atEnd()) { bool validTag = true; if (xml.isStartElement()) { if (!rc && xml.name().toString() == "label") { QXmlStreamAttributes attrs = xml.attributes(); QStringRef av; av = attrs.value("text"); if (!av.isNull()) { Q_ASSERT(!rc); rc = new LabelItem(view, av.toString()); if (parent) { rc->setParentViewItem(parent); // Add any new specialized LabelItem Properties here. } } av = attrs.value("scale"); if (!av.isNull()) { rc->setLabelScale(QVariant(av.toString()).toInt()); } av = attrs.value("color"); if (!av.isNull()) { rc->setLabelColor(QColor(av.toString())); } av = attrs.value("font"); if (!av.isNull()) { QFont font; font.fromString(av.toString()); rc->setLabelFont(font); } av = attrs.value("fixleft"); if (!av.isNull()) { rc->setFixLeft(QVariant(av.toString()).toBool()); } } else { Q_ASSERT(rc); if (!rc->parse(xml, validTag) && validTag) { ViewItem *i = GraphicsFactory::parse(xml, store, view, rc); if (!i) { } } } } else if (xml.isEndElement()) { if (xml.name().toString() == "label") { break; } else { validTag = false; } } if (!validTag) { qDebug("invalid Tag\n"); Debug::self()->log(QObject::tr("Error creating box object from Kst file."), Debug::Warning); delete rc; return 0; } xml.readNext(); } return rc; } void LabelItem::updateDataRelativeRect( bool force) { CartesianRenderItem* plot = dynamic_cast(parentViewItem()); if (plot) { if ((!lockPosToData()) || force || (!_dataRelativeDimValid)) { _dataRelativeDimValid = ((fabs(rect().width())>1.1) && (fabs(rect().height())>1.1)); QPointF P1 = rect().bottomLeft(); QPointF P2 = rect().bottomRight(); _dataRelativeRect.setTopLeft(plot->plotItem()->mapToProjection(mapToParent(P1))); _dataRelativeRect.setBottomRight(plot->plotItem()->mapToProjection(mapToParent(P2))); } } } void LabelItem::applyDataLockedDimensions() { PlotRenderItem *render_item = dynamic_cast(parentViewItem()); if (render_item) { qreal parentWidth = render_item->width(); qreal parentHeight = render_item->height(); qreal parentX = render_item->rect().x(); qreal parentY = render_item->rect().y(); qreal parentDX = render_item->plotItem()->xMax() - render_item->plotItem()->xMin(); qreal parentDY = render_item->plotItem()->yMax() - render_item->plotItem()->yMin(); QPointF drP1 = _dataRelativeRect.topLeft(); QPointF drP2 = _dataRelativeRect.bottomRight(); QPointF P1(parentX + parentWidth*(drP1.x()-render_item->plotItem()->xMin())/parentDX, parentY + parentHeight*(render_item->plotItem()->yMax() - drP1.y())/parentDY); QPointF P2(parentX + parentWidth*(drP2.x()-render_item->plotItem()->xMin())/parentDX, parentY + parentHeight*(render_item->plotItem()->yMax() - drP2.y())/parentDY); qreal theta = atan2(P2.y() - P1.y(), P2.x() - P1.x()); qreal height = rect().height(); qreal width = rect().width(); if (_fixleft) { setPos(P1); setViewRect(0, -height, width, height); } else { setPos(P2); setViewRect(-width, -height, width, height); } QTransform transform; transform.rotateRadians(theta); setTransform(transform); updateRelativeSize(); } else { qDebug() << "apply data locked dimensions called without a render item (!)"; } } void LabelItem::updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect) { Q_UNUSED(oldParentRect); QRectF itemRect = rect(); if (fixLeft()) { QPointF newBottomLeft = newParentRect.topLeft() + QPointF(newParentRect.width() * _parentRelativeLeft.x(), newParentRect.height() * _parentRelativeLeft.y()); setPos(newBottomLeft); setViewRect(QRectF(0, -itemRect.height(), itemRect.width(), itemRect.height()), true); } else { QPointF newBottomRight = newParentRect.topLeft() + QPointF(newParentRect.width() * _parentRelativeRight.x(), newParentRect.height() * _parentRelativeRight.y()); setPos(newBottomRight); setViewRect(QRectF(-itemRect.width(), -itemRect.height(), itemRect.width(), itemRect.height()), true); } //setViewRect(itemRect, true); } } // vim: ts=2 sw=2 et diff --git a/src/libkstapp/viewitem.cpp b/src/libkstapp/viewitem.cpp index 67779613..a5fb1229 100644 --- a/src/libkstapp/viewitem.cpp +++ b/src/libkstapp/viewitem.cpp @@ -1,2807 +1,2807 @@ /*************************************************************************** * * * copyright : (C) 2007 The University of Toronto * * netterfield@astro.utoronto.ca * * * * 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. * * * ***************************************************************************/ #include "viewitem.h" #include "applicationsettings.h" #include "viewitemdialog.h" #include "viewgridlayout.h" #include "plotitem.h" #include "sharedaxisboxitem.h" #include "plotitemmanager.h" #include "document.h" #include "datacollection.h" #include "formatgridhelper.h" #include "dialogdefaults.h" #include "cartesianrenderitem.h" #include "viewitemscriptinterface.h" #include "layoutboxitem.h" #include #include #include #include #include #include #include #include #include #include #include #include static const qreal ONE_PI = 3.14159265358979323846264338327950288419717; static qreal TWO_PI = 2.0 * ONE_PI; static qreal RAD2DEG = 180.0 / ONE_PI; static const int DRAWING_ZORDER = 500; #define DEBUG_GEOMETRY 0 #define DEBUG_REPARENT 0 // enable drag & drop #define KST_ENABLE_DD namespace Kst { ViewItem::ViewItem(View *parentView) : QObject(parentView), NamedObject(), _isXTiedZoom(false), _isYTiedZoom(false), _plotMaximized(false), _activeGrip(NoGrip), _parentRelativeHeight(0), _parentRelativeWidth(0), _gripMode(Move), _allowedGripModes(Move | Resize | Rotate /*| Scale*/), _creationState(None), _typeName("View Item"), _zoomOnlyMode(View::ZoomOnlyDisabled), _supportsTiedZoom(false), _fixedSize(false), _lockAspectRatio(false), _lockAspectRatioFixed(false), _hasStaticGeometry(false), _lockParent(false), _skipNextParentCheck(false), _allowsLayout(true), _hovering(false), _acceptsChildItems(true), _acceptsContextMenuEvents(true), _updatingLayout(false), _highlighted(false), _allowedGrips(TopLeftGrip | TopRightGrip | BottomRightGrip | BottomLeftGrip | TopMidGrip | RightMidGrip | BottomMidGrip | LeftMidGrip), _lockPosToData(false), _editDialog(0), _interface(0), _dpi(71.0) { _initializeShortName(); setZValue(DRAWING_ZORDER); setAcceptsHoverEvents(true); setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable); connect(parentView, SIGNAL(mouseModeChanged(View::MouseMode)), this, SLOT(viewMouseModeChanged(View::MouseMode))); connect(parentView, SIGNAL(viewModeChanged(View::ViewMode)), this, SLOT(updateView())); connect(this, SIGNAL(geometryChanged()), parentView, SLOT(viewChanged())); setLayoutMargins(ApplicationSettings::self()->layoutMargins()); setLayoutSpacing(ApplicationSettings::self()->layoutSpacing()); // Add actions common to all view objects // create them here in the constructor so we // can register shortcuts. _editAction = new QAction(tr("Edit"), this); _editAction->setShortcut(Qt::Key_E); registerShortcut(_editAction); connect(_editAction, SIGNAL(triggered()), this, SLOT(edit())); _deleteAction = new QAction(tr("Delete"), this); _deleteAction->setShortcut(Qt::Key_Delete); registerShortcut(_deleteAction); connect(_deleteAction, SIGNAL(triggered()), this, SLOT(remove())); _raiseAction = new QAction(tr("Raise"), this); connect(_raiseAction, SIGNAL(triggered()), this, SLOT(raise())); _lowerAction = new QAction(tr("Lower"), this); connect(_lowerAction, SIGNAL(triggered()), this, SLOT(lower())); _autoLayoutAction = new QAction(tr("Automatic"), this); _autoLayoutAction->setShortcut(Qt::Key_U); registerShortcut(_autoLayoutAction); connect(_autoLayoutAction, SIGNAL(triggered()), this, SLOT(createAutoLayout())); _protectedLayoutAction = new QAction(tr("Protect Layout"), this); connect(_protectedLayoutAction, SIGNAL(triggered()), this, SLOT(createProtectedLayout())); _customLayoutAction = new QAction(tr("Columns"), this); connect(_customLayoutAction, SIGNAL(triggered()), this, SLOT(createCustomLayout())); _lockPosToDataAction = new QAction(tr("&Lock Position to Data"),this); _lockPosToDataAction->setCheckable(true); connect(_lockPosToDataAction, SIGNAL(toggled(bool)), this, SLOT(setLockPosToData(bool))); // only drop plots onto TabBar setAcceptDrops(false); } ViewItem::~ViewItem() { } void ViewItem::_initializeShortName() { _shortName = 'D'+QString::number(_viewitemnum); if (_viewitemnum>max_viewitemnum) max_viewitemnum = _viewitemnum; _viewitemnum++; } void ViewItem::save(QXmlStreamWriter &xml) { // when saving, check to see if your parent is a cartesianrenderitem. // if so, we'll need to adjust to take into account that when loaded, // the object will be created in a cartesian render item with no plot // borders, and then resized. // this keeps line end points in the right place. CartesianRenderItem *cri = dynamic_cast(parentItem()); QTransform tr; qreal w = _parentRelativeWidth; if (cri) { QRectF cri_rect = cri->rect(); QRectF plot_rect = cri->parentRect(); qreal oldL = relativeWidth()*cri_rect.width(); qreal r0 = rotationAngleRadians(); qreal dy = oldL*sin(r0)*plot_rect.height()/cri_rect.height(); qreal dx = oldL*cos(r0)*plot_rect.width()/cri_rect.width(); qreal r1 = atan2(dy, dx); w = sqrt(dy*dy + dx*dx)/plot_rect.width(); tr.rotateRadians(r1); } else { tr = transform(); } xml.writeAttribute("name", typeName()); xml.writeStartElement("position"); xml.writeAttribute("x", QVariant(pos().x()).toString()); xml.writeAttribute("y", QVariant(pos().y()).toString()); xml.writeAttribute("z", QVariant(zValue()).toString()); xml.writeEndElement(); xml.writeStartElement("rect"); xml.writeAttribute("x", QVariant(viewRect().x()).toString()); xml.writeAttribute("y", QVariant(viewRect().y()).toString()); xml.writeAttribute("width", QVariant(viewRect().width()).toString()); xml.writeAttribute("height", QVariant(viewRect().height()).toString()); xml.writeEndElement(); xml.writeStartElement("relativesize"); xml.writeAttribute("width", QVariant(w).toString()); xml.writeAttribute("height", QVariant(_parentRelativeHeight).toString()); xml.writeAttribute("centerx", QVariant(_parentRelativeCenter.x()).toString()); xml.writeAttribute("centery", QVariant(_parentRelativeCenter.y()).toString()); xml.writeAttribute("posx", QVariant(_parentRelativePosition.x()).toString()); xml.writeAttribute("posy", QVariant(_parentRelativePosition.y()).toString()); xml.writeAttribute("leftx", QVariant(_parentRelativeLeft.x()).toString()); xml.writeAttribute("lefty", QVariant(_parentRelativeLeft.y()).toString()); xml.writeAttribute("rightx", QVariant(_parentRelativeRight.x()).toString()); xml.writeAttribute("righty", QVariant(_parentRelativeRight.y()).toString()); xml.writeAttribute("fixaspect", QVariant(_lockAspectRatio).toString()); xml.writeAttribute("lockpostodata", QVariant(_lockPosToData).toString()); if (_lockPosToData) { // meaningless if not locked: why pollute the file? xml.writeAttribute("datarect_x", QVariant(_dataRelativeRect.x()).toString()); xml.writeAttribute("datarect_y", QVariant(_dataRelativeRect.y()).toString()); xml.writeAttribute("datarect_width", QVariant(_dataRelativeRect.width()).toString()); xml.writeAttribute("datarect_height", QVariant(_dataRelativeRect.height()).toString()); } xml.writeEndElement(); xml.writeStartElement("transform"); xml.writeAttribute("m11", QVariant(tr.m11()).toString()); xml.writeAttribute("m12", QVariant(tr.m12()).toString()); xml.writeAttribute("m13", QVariant(tr.m13()).toString()); xml.writeAttribute("m21", QVariant(tr.m21()).toString()); xml.writeAttribute("m22", QVariant(tr.m22()).toString()); xml.writeAttribute("m23", QVariant(tr.m23()).toString()); xml.writeAttribute("m31", QVariant(tr.m31()).toString()); xml.writeAttribute("m32", QVariant(tr.m32()).toString()); xml.writeAttribute("m33", QVariant(tr.m33()).toString()); xml.writeEndElement(); xml.writeStartElement("pen"); xml.writeAttribute("style", QVariant((int)pen().style()).toString()); xml.writeAttribute("width", QVariant(storedPen().widthF()).toString()); xml.writeAttribute("miterlimit", QVariant(pen().miterLimit()).toString()); xml.writeAttribute("cap", QVariant(pen().capStyle()).toString()); xml.writeAttribute("joinStyle", QVariant(pen().joinStyle()).toString()); xml.writeStartElement("brush"); xml.writeAttribute("color", pen().brush().color().name()); xml.writeAttribute("alpha", QString::number(pen().brush().color().alphaF())); xml.writeAttribute("style", QVariant((int)pen().brush().style()).toString()); xml.writeEndElement(); xml.writeEndElement(); xml.writeStartElement("brush"); xml.writeAttribute("color", brush().color().name()); xml.writeAttribute("alpha", QString::number(brush().color().alphaF())); xml.writeAttribute("style", QVariant((int)brush().style()).toString()); if (brush().gradient()) { QString stopList; foreach(const QGradientStop &stop, brush().gradient()->stops()) { qreal point = (qreal)stop.first; QColor color = (QColor)stop.second; stopList += QString::number(point); stopList += ','; stopList += color.name(); stopList += ','; } xml.writeAttribute("gradient", stopList); } xml.writeEndElement(); QList list = QGraphicsItem::childItems(); foreach (QGraphicsItem *item, list) { ViewItem *viewItem = dynamic_cast(item); if (!viewItem) continue; viewItem->save(xml); } } -void ViewItem::applyDialogDefaultsFill() { +void ViewItem::applyDialogDefaultsFill(bool default_no_fill) { if (hasBrush()) { //set the brush - QBrush brush = dialogDefaultsBrush(defaultsGroupName()); + QBrush brush = dialogDefaultsBrush(defaultsGroupName(), default_no_fill); setBrush(brush); } } -void ViewItem::applyDialogDefaultsStroke() { +void ViewItem::applyDialogDefaultsStroke(bool default_no_pen) { if (hasStroke()) { // set the pen - QPen pen = dialogDefaultsPen(defaultsGroupName()); + QPen pen = dialogDefaultsPen(defaultsGroupName(), default_no_pen); storePen(pen); } } void ViewItem::applyDialogDefaultsLockPosToData() { setLockPosToData(dialogDefaultsLockPosToData(defaultsGroupName())); } void ViewItem::setLockPosToData(bool lockPosToData) { _lockPosToData = lockPosToData; _lockPosToDataAction->setChecked(lockPosToData); emit(relativeSizeUpdated()); } QRectF ViewItem::parentRect() const { if (parentViewItem()) { return parentViewItem()->rect().normalized(); } else if (view()) { return view()->rect(); } else { Q_ASSERT_X(false,"parent test", "item has no parentview item"); } return QRectF(0,0,1,1); // shouldn't get here } void ViewItem::applyDataLockedDimensions() { PlotRenderItem *render_item = dynamic_cast(parentViewItem()); if (render_item) { qreal parentWidth = render_item->width(); qreal parentHeight = render_item->height(); qreal parentX = render_item->rect().x(); qreal parentY = render_item->rect().y(); qreal aspectRatio; if (rect().width() > 0) { aspectRatio = qreal(rect().height()) / qreal(rect().width()); } else { aspectRatio = 10000.0; } qreal relativeWidth = _dataRelativeRect.width()/(render_item->plotItem()->xMax() - render_item->plotItem()->xMin()); qreal relativeHeight = _dataRelativeRect.height()/(render_item->plotItem()->yMax() - render_item->plotItem()->yMin()); qreal relativeX = (_dataRelativeRect.center().x() - render_item->plotItem()->xMin())/ (render_item->plotItem()->xMax() - render_item->plotItem()->xMin()); qreal relativeY = (_dataRelativeRect.center().y() - render_item->plotItem()->yMin())/ (render_item->plotItem()->yMax() - render_item->plotItem()->yMin()); qreal width = relativeWidth * parentWidth; qreal height; if (lockAspectRatio()) { height = width * aspectRatio; } else { height = relativeHeight * parentHeight; } setPos(parentX + relativeX*parentWidth, parentY + (1.0-relativeY)*parentHeight); setViewRect(-width/2, -height/2, width, height); updateRelativeSize(); } else { qDebug() << "apply data locked dimensions called without a render item (!)"; } } bool ViewItem::parse(QXmlStreamReader &xml, bool &validChildTag) { bool knownTag = false; QString expectedTag; if (xml.isStartElement()) { expectedTag = xml.name().toString(); QXmlStreamAttributes attrs = xml.attributes(); QStringRef av; if (xml.name().toString() == "name") { knownTag = true; av = attrs.value("name"); if (!av.isNull()) { setTypeName(av.toString()); } } else if (xml.name().toString() == "position") { knownTag = true; qreal x = 0, y = 0, z = DRAWING_ZORDER; av = attrs.value("x"); if (!av.isNull()) { x = av.toString().toDouble(); } av = attrs.value("y"); if (!av.isNull()) { y = av.toString().toDouble(); } setPos(x, y); av = attrs.value("z"); if (!av.isNull()) { z = av.toString().toDouble(); } setZValue(z); } else if (xml.name().toString() == "brush") { knownTag = true; QBrush brush; av = attrs.value("gradient"); if (!av.isNull()) { QStringList stopInfo = av.toString().split(',', QString::SkipEmptyParts); QLinearGradient gradient(1,0,0,0); gradient.setCoordinateMode(QGradient::ObjectBoundingMode); for (int i = 0; i < stopInfo.size(); i+=2) { gradient.setColorAt(stopInfo.at(i).toDouble(), QColor(stopInfo.at(i+1))); } brush = QBrush(gradient); } else { av = attrs.value("color"); if (!av.isNull()) { brush.setColor(QColor(av.toString())); } av = attrs.value("style"); if (!av.isNull()) { brush.setStyle((Qt::BrushStyle)av.toString().toInt()); } av = attrs.value("alpha"); if (!av.isNull()) { qreal alpha = av.toString().toDouble(); QColor c = brush.color(); c.setAlphaF(alpha); brush.setColor(c); } } setBrush(brush); } else if (xml.name().toString() == "pen") { knownTag = true; QPen pen; av = attrs.value("style"); if (!av.isNull()) { pen.setStyle((Qt::PenStyle)av.toString().toInt()); } av = attrs.value("width"); if (!av.isNull()) { pen.setWidthF(av.toString().toDouble()); } av = attrs.value("miterlimit"); if (!av.isNull()) { pen.setMiterLimit(av.toString().toDouble()); } av = attrs.value("cap"); if (!av.isNull()) { pen.setCapStyle((Qt::PenCapStyle)av.toString().toInt()); } av = attrs.value("joinstyle"); if (!av.isNull()) { pen.setJoinStyle((Qt::PenJoinStyle)av.toString().toInt()); } xml.readNext(); xml.readNext(); if (xml.isStartElement() && (xml.name().toString() == "brush")) { QBrush penBrush; attrs = xml.attributes(); av = attrs.value("color"); if (!av.isNull()) { penBrush.setColor(QColor(av.toString())); } av = attrs.value("alpha"); if (!av.isNull()) { qreal alpha = av.toString().toDouble(); QColor c = penBrush.color(); c.setAlphaF(alpha); penBrush.setColor(c); } av = attrs.value("style"); if (!av.isNull()) { penBrush.setStyle((Qt::BrushStyle)av.toString().toInt()); } pen.setBrush(penBrush); xml.readNext(); if (!xml.isEndElement() || (xml.name().toString() != "brush")) { expectedTag = "InvalidTag"; } xml.readNext(); } storePen(pen); } else if (xml.name().toString() == "rect") { knownTag = true; qreal x = 0, y = 0, w = 10, h = 10; av = attrs.value("width"); if (!av.isNull()) { w = av.toString().toDouble(); } av = attrs.value("height"); if (!av.isNull()) { h = av.toString().toDouble(); } av = attrs.value("x"); if (!av.isNull()) { x = av.toString().toDouble(); } av = attrs.value("y"); if (!av.isNull()) { y = av.toString().toDouble(); } setViewRect(QRectF(QPointF(x, y), QSizeF(w, h))); } else if (xml.name().toString() == "relativesize") { knownTag = true; qreal width = 0, height = 0, centerx = 0, centery = 0, posx = 0, posy = 0; qreal leftx = -1.0, lefty = -1.0, rightx = -1.0, righty = -1.0; bool lock_aspect_ratio = false; av = attrs.value("width"); if (!av.isNull()) { width = av.toString().toDouble(); } av = attrs.value("height"); if (!av.isNull()) { height = av.toString().toDouble(); } av = attrs.value("centerx"); if (!av.isNull()) { centerx = av.toString().toDouble(); } av = attrs.value("centery"); if (!av.isNull()) { centery = av.toString().toDouble(); } av = attrs.value("posx"); if (!av.isNull()) { posx = av.toString().toDouble(); } av = attrs.value("posy"); if (!av.isNull()) { posy = av.toString().toDouble(); } av = attrs.value("leftx"); if (!av.isNull()) { leftx = av.toString().toDouble(); } av = attrs.value("lefty"); if (!av.isNull()) { lefty = av.toString().toDouble(); } av = attrs.value("rightx"); if (!av.isNull()) { rightx = av.toString().toDouble(); } av = attrs.value("righty"); if (!av.isNull()) { righty = av.toString().toDouble(); } av = attrs.value("fixaspect"); if (!av.isNull()) { lock_aspect_ratio = QVariant(av.toString()).toBool(); } if (rightx <-0.99) { // old kst file: generate from center rightx = centerx + width/2.0; leftx = centerx - width/2.0; righty = centery + height/2.0; lefty = centery + height/2.0; } setRelativeWidth(width); setRelativeHeight(height); setRelativeCenter(QPointF(centerx, centery)); setRelativePosition(QPointF(posx, posy)); setRelativeLeft(QPointF(leftx, lefty)); setRelativeRight(QPointF(rightx, righty)); setLockAspectRatio(lock_aspect_ratio); av = attrs.value("lockpostodata"); if (!av.isNull()) { bool lock_pos_to_data = QVariant(av.toString()).toBool(); setLockPosToData(lock_pos_to_data); if (lock_pos_to_data) { qreal x=0, y=0, w=0.1, h=0.1; av = attrs.value("datarect_x"); if (!av.isNull()) { x = av.toString().toDouble(); } av = attrs.value("datarect_y"); if (!av.isNull()) { y = av.toString().toDouble(); } av = attrs.value("datarect_width"); if (!av.isNull()) { w = av.toString().toDouble(); } av = attrs.value("datarect_height"); if (!av.isNull()) { h = av.toString().toDouble(); } _dataRelativeRect = QRectF(x,y,w,h); } } else { setLockPosToData(false); } } else if (xml.name().toString() == "transform") { knownTag = true; qreal m11 = 1.0, m12 = 0, m13 = 0, m21 = 0, m22 = 1.0, m23 = 0, m31 = 0, m32= 0, m33 = 1.0; av = attrs.value("m11"); if (!av.isNull()) { m11 = av.toString().toDouble(); } av = attrs.value("m12"); if (!av.isNull()) { m12 = av.toString().toDouble(); } av = attrs.value("m13"); if (!av.isNull()) { m13 = av.toString().toDouble(); } av = attrs.value("m21"); if (!av.isNull()) { m21 = av.toString().toDouble(); } av = attrs.value("m22"); if (!av.isNull()) { m22 = av.toString().toDouble(); } av = attrs.value("m23"); if (!av.isNull()) { m23 = av.toString().toDouble(); } av = attrs.value("m31"); if (!av.isNull()) { m31 = av.toString().toDouble(); } av = attrs.value("m32"); if (!av.isNull()) { m32 = av.toString().toDouble(); } av = attrs.value("m33"); if (!av.isNull()) { m33 = av.toString().toDouble(); } setTransform(QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33)); } } if (knownTag) { xml.readNext(); if (xml.isEndElement()) { if ((xml.name().toString() == expectedTag) ) { validChildTag = true; } } } return knownTag; } View *ViewItem::view() const { return qobject_cast(QObject::parent()); } void ViewItem::setView(View* parentView) { QObject::setParent(parentView); reRegisterShortcut(); QList list = QGraphicsItem::childItems(); foreach (QGraphicsItem *item, list) { ViewItem *viewItem = dynamic_cast(item); if (viewItem) { viewItem->setView(parentView); } } } ViewItem *ViewItem::parentViewItem() const { return dynamic_cast(parentItem()); } void ViewItem::setParentViewItem(ViewItem* parent) { QGraphicsItem::setParentItem(parent); updateRelativeSize(true); } ViewItem::GripMode ViewItem::gripMode() const { return _gripMode; } void ViewItem::setGripMode(GripMode mode) { _gripMode = mode; update(); } ViewItem::GripModes ViewItem::allowedGripModes() const { return _allowedGripModes; } void ViewItem::setAllowedGripModes(GripModes modes) { _allowedGripModes = modes; } bool ViewItem::isAllowed(GripMode mode) const { return _allowedGripModes & mode; } QRectF ViewItem::viewRect() const { return rect(); } void ViewItem::setViewRect(const QRectF &viewRect, bool automaticChange) { QRectF oldViewRect = rect(); if (oldViewRect == viewRect) return; setRect(viewRect); emit geometryChanged(); if (!automaticChange) { updateRelativeSize(); } foreach (QGraphicsItem *item, QGraphicsItem::childItems()) { if (item->parentItem() != this) continue; ViewItem *viewItem = dynamic_cast(item); if (!viewItem) continue; if (viewItem->hasStaticGeometry()) continue; viewItem->setSkipNextParentCheck(true); viewItem->updateChildGeometry(oldViewRect, viewRect); } } void ViewItem::setViewRect(qreal x, qreal y, qreal width, qreal height, bool automaticChange) { setViewRect(QRectF(x, y, width, height), automaticChange); } QSizeF ViewItem::sizeOfGrip() const { if (!view()) return QSizeF(); int base = _dpi*11.0/96.0 ; return view()->mapToScene(QRect(0, 0, base, base)).boundingRect().size(); } QPainterPath ViewItem::topLeftGrip() const { QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.topLeft(), sizeOfGrip()); QPainterPath path; if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move) path.addRect(grip); else path.addEllipse(grip); return path; } QPainterPath ViewItem::topRightGrip() const { QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip()); QPainterPath path; if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move) path.addRect(grip); else path.addEllipse(grip); return path; } QPainterPath ViewItem::bottomRightGrip() const { QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.bottomRight() - QPointF(sizeOfGrip().width(), sizeOfGrip().height()), sizeOfGrip()); QPainterPath path; if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move) path.addRect(grip); else path.addEllipse(grip); return path; } QPainterPath ViewItem::bottomLeftGrip() const { QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip()); QPainterPath path; if (_gripMode == Resize || _gripMode == Scale || _gripMode == Move) path.addRect(grip); else path.addEllipse(grip); return path; } QPainterPath ViewItem::topMidGrip() const { if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio) return QPainterPath(); QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.topLeft(), sizeOfGrip()); grip.moveCenter(QPointF(bound.center().x(), grip.center().y())); QPainterPath path; path.addRect(grip); return path; } QPainterPath ViewItem::rightMidGrip() const { if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio) return QPainterPath(); QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width(), 0), sizeOfGrip()); grip.moveCenter(QPointF(grip.center().x(), bound.center().y())); QPainterPath path; path.addRect(grip); return path; } QPainterPath ViewItem::bottomMidGrip() const { if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio) return QPainterPath(); QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.bottomLeft() - QPointF(0, sizeOfGrip().height()), sizeOfGrip()); grip.moveCenter(QPointF(bound.center().x(), grip.center().y())); QPainterPath path; path.addRect(grip); return path; } QPainterPath ViewItem::leftMidGrip() const { if (_gripMode == Move || _gripMode == Rotate || _lockAspectRatio) return QPainterPath(); QRectF bound = gripBoundingRect(); QRectF grip = QRectF(bound.topLeft(), sizeOfGrip()); grip.moveCenter(QPointF(grip.center().x(), bound.center().y())); QPainterPath path; path.addRect(grip); return path; } QPainterPath ViewItem::grips() const { QPainterPath grips; grips.addPath(topLeftGrip()); grips.addPath(topRightGrip()); grips.addPath(bottomRightGrip()); grips.addPath(bottomLeftGrip()); grips.addPath(topMidGrip()); grips.addPath(rightMidGrip()); grips.addPath(bottomMidGrip()); grips.addPath(leftMidGrip()); return grips; } ViewItem::ActiveGrip ViewItem::activeGrip() const { return _activeGrip; } void ViewItem::setActiveGrip(ActiveGrip grip) { _activeGrip = grip; } ViewItem::ActiveGrips ViewItem::allowedGrips() const { return _allowedGrips; } void ViewItem::setAllowedGrips(ActiveGrips grips) { _allowedGrips = grips; } bool ViewItem::isAllowed(ActiveGrip grip) const { return _allowedGrips & grip; } QRectF ViewItem::selectBoundingRect() const { return rect(); } QRectF ViewItem::gripBoundingRect() const { QRectF bound = selectBoundingRect(); bound.setTopLeft(bound.topLeft() - QPointF(sizeOfGrip().width() / 2.0, sizeOfGrip().height() / 2.0)); bound.setWidth(bound.width() + sizeOfGrip().width() / 2.0); bound.setHeight(bound.height() + sizeOfGrip().height() / 2.0); return bound; } QRectF ViewItem::boundingRect() const { bool inCreation = false; if (view()) /* false when exiting */ inCreation = view()->mouseMode() == View::Create; if ((!isSelected() && !isHovering()) || inCreation) return QGraphicsRectItem::boundingRect(); QPolygonF gripBound = gripBoundingRect(); return QRectF(gripBound[0], gripBound[2]); } QPainterPath ViewItem::shape() const { if ((!isSelected() && !isHovering()) || (view()->mouseMode() == View::Create)) return itemShape(); QPainterPath selectPath; selectPath.setFillRule(Qt::WindingFill); selectPath.addPolygon(rect()); selectPath.addPath(grips()); return selectPath; } bool ViewItem::isMaximized() { if (_plotMaximized) { return true; } else if (parentViewItem()) { return parentViewItem()->isMaximized(); } else { return false; } } void ViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); if ((!isMaximized()) && view()->childMaximized()) { return; } _dpi = painter->device()->logicalDpiX(); QPen rescaled_pen(_storedPen); rescaled_pen.setWidth(Curve::lineDim(painter->window(),rescaled_pen.widthF())); setPen(rescaled_pen); painter->save(); painter->setPen(pen()); painter->setBrush(brush()); if (_lockPosToData) { PlotRenderItem *render_item = dynamic_cast(parentViewItem()); if (render_item) { QPolygonF PF = mapFromParent(render_item->rect()); QPainterPath path; path.addPolygon(PF); painter->setClipPath(path); } } paint(painter); //this is the overload that subclasses should use... if (!view()->isPrinting() && !view()->childMaximized()) { painter->setPen(Qt::DotLine); painter->setBrush(Qt::NoBrush); if ((isSelected() || isHovering()) && view()->mouseMode() != View::Create && view()->viewMode() != View::Data) { painter->drawPath(shape()); if (_gripMode == Resize) painter->fillPath(grips(), Qt::blue); else if (_gripMode == Scale) painter->fillPath(grips(), Qt::black); else if (_gripMode == Rotate) painter->fillPath(grips(), Qt::red); else if (_gripMode == Move) painter->fillPath(grips(), Qt::transparent); } else if (isHighlighted()) { QColor highlightColor(QColor(255, 255, 0, 120)); painter->fillPath(shape(), highlightColor); } if (supportsTiedZoom()) { painter->save(); painter->setPen(Qt::black); painter->setRenderHint(QPainter::Antialiasing, true); painter->fillPath(checkBox(), Qt::white); if (isHovering()) { QRectF check = checkBox().controlPointRect(); check.setSize(QSizeF(check.width() / 3.5, check.height() / 3.5)); check.moveCenter(checkBox().controlPointRect().center()); QPainterPath p; p.addEllipse(check); painter->fillPath(p, Qt::black); } if (isTiedZoom()) { painter->save(); QColor c = Qt::black; c.setAlphaF(c.alphaF() * 0.6); painter->fillPath(tiedZoomCheck(), c); painter->restore(); } painter->setBrush(Qt::transparent); painter->drawPath(checkBox()); painter->restore(); } #if DEBUG_GEOMETRY // painter->fillRect(selectBoundingRect(), Qt::blue); QColor semiRed(QColor(255, 0, 0, 50)); painter->fillPath(shape(), semiRed); QPen p = painter->pen(); painter->setPen(Qt::white); painter->drawLine(_normalLine); painter->setPen(Qt::red); painter->drawLine(_rotationLine); painter->setPen(p); painter->drawText(rect().topLeft(), "TL"); painter->drawText(rect().topRight(), "TR"); painter->drawText(rect().bottomLeft(), "BL"); painter->drawText(rect().bottomRight(), "BR"); #endif } painter->restore(); } void ViewItem::paint(QPainter *painter) { Q_UNUSED(painter); } void ViewItem::edit() { if (!_editDialog) { _editDialog = new ViewItemDialog(this, kstApp->mainWindow()); } _editDialog->show(); _editDialog->raise(); } void ViewItem::sharePlots(QPainter *painter, bool creation) { if (!_updatingLayout) { _updatingLayout = true; ViewGridLayout::sharePlots(this, painter, creation); _updatingLayout = false; } } void ViewItem::createAutoLayout() { if (parentViewItem()) { LayoutCommand *layout = new LayoutCommand(parentViewItem()); layout->createLayout(false); } else if (view()) { view()->createLayout(false); } } void ViewItem::createProtectedLayout() { if (parentViewItem()) { LayoutCommand *layout = new LayoutCommand(parentViewItem()); layout->createLayout(true); } else if (view()) { view()->createLayout(true); } } void ViewItem::createCustomLayout(int columns) { bool ok = true; int default_cols = qMax(1,int(sqrt((qreal)Data::self()->plotList().count()))); if (columns<1) { columns = QInputDialog::getInt(view(), tr("Kst: Column Layout"), tr("Layout in columns in order of creation.\nSelect number of columns:"),default_cols, 1, 15, 1, &ok); } if (ok) { if (parentViewItem() && false) { LayoutCommand *layout = new LayoutCommand(parentViewItem()); layout->createLayout(false, columns); } else if (view()) { view()->createLayout(false, columns); } } } void ViewItem::raise() { RaiseCommand *up = new RaiseCommand(this); up->redo(); } void ViewItem::lower() { LowerCommand *down = new LowerCommand(this); down->redo(); } void ViewItem::remove() { RemoveCommand *remove = new RemoveCommand(this); remove->redo(); } void ViewItem::creationPolygonChanged(View::CreationEvent event) { if (event == View::EscapeEvent) { deleteLater(); kstApp->mainWindow()->clearDrawingMarker(); return; } if (event == View::MousePress) { const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MousePress)); setPos(poly.first().x(), poly.first().y()); setViewRect(0.0, 0.0, 0.0, 0.0); view()->scene()->addItem(this); _creationState = InProgress; return; } if (event == View::MouseMove) { const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseMove)); qreal x0 = qMin(qreal(0.0), poly.last().x()); qreal y0 = qMin(qreal(0.0), poly.last().y()); QRectF newRect(x0, y0, fabs(poly.last().x()), fabs(poly.last().y())); setViewRect(newRect); return; } if (event == View::MouseRelease) { const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseRelease)); qreal x0 = qMin(qreal(0.0), poly.last().x()); qreal y0 = qMin(qreal(0.0), poly.last().y()); QRectF newRect(x0, y0, fabs(poly.last().x()), fabs(poly.last().y())); if (!newRect.isValid()) { newRect = newRect.normalized(); newRect.setWidth(qMax(qreal(3.0), newRect.width())); newRect.setHeight(qMax(qreal(3.0), newRect.height())); setPos(pos() + newRect.topLeft()); newRect.moveTopLeft(QPointF(0, 0)); setViewRect(newRect); view()->setPlotBordersDirty(true); } else { setViewRect(newRect.normalized()); } view()->disconnect(this, SLOT(deleteLater())); //Don't delete ourself view()->disconnect(this, SLOT(creationPolygonChanged(View::CreationEvent))); view()->setMouseMode(View::Default); updateViewItemParent(); _creationState = Completed; setZValue(DRAWING_ZORDER); emit creationComplete(); return; } } void ViewItem::creationPolygonChangedFixedAspect(View::CreationEvent event, qreal aspect) { if (event == View::EscapeEvent) { ViewItem::creationPolygonChanged(event); return; } if (event == View::MousePress) { const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MousePress)); setPos(poly.first().x(), poly.first().y()); setViewRect(QRectF(0.0, 0.0, 0.0, sizeOfGrip().height())); setRect(0,0,4,4); view()->scene()->addItem(this); return; } if (event == View::MouseMove) { const QPolygonF poly = mapFromScene(view()->creationPolygon(View::MouseMove)); QPointF offset = lockOffset(poly.last(), aspect, false); if (offset.x()<5.0) { offset.setX(5.0); offset.setY(5.0/aspect); } setViewRect(0,0,offset.x(), offset.y()); return; } if (event == View::MouseRelease) { view()->disconnect(this, SLOT(deleteLater())); //Don't delete ourself view()->disconnect(this, SLOT(creationPolygonChanged(View::CreationEvent))); view()->setMouseMode(View::Default); updateViewItemParent(); _creationState = Completed; setZValue(DRAWING_ZORDER); emit creationComplete(); return; } } void ViewItem::addTitle(QMenu *menu) const { QWidgetAction *action = new QWidgetAction(menu); action->setEnabled(false); QLabel *label = new QLabel(tr("%1 Menu", "title of menu for object type arg1").arg(typeName()), menu); label->setAlignment(Qt::AlignCenter); label->setStyleSheet("QLabel {" "border-bottom: 2px solid lightGray;" "font: bold large;" "padding: 3px;" "margin: 1px;" "}"); action->setDefaultWidget(label); menu->addAction(action); } void ViewItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; addTitle(&menu); if (!(lockParent() || (parentViewItem() && parentViewItem()->lockParent()))) { QMenu *layoutMenu = menu.addMenu(tr("Cleanup Layout")); layoutMenu->setTitle(tr("Cleanup Layout")); layoutMenu->addAction(_autoLayoutAction); layoutMenu->addAction(_protectedLayoutAction); layoutMenu->addAction(_customLayoutAction); } menu.addAction(_editAction); addToMenuForContextEvent(menu); menu.addSeparator(); if (!(lockParent() || (parentViewItem() && parentViewItem()->lockParent()))) { menu.addAction(_raiseAction); menu.addAction(_lowerAction); menu.addAction(_deleteAction); } if (dataPosLockable()) { menu.addSeparator(); menu.addAction(_lockPosToDataAction); } menu.exec(event->screenPos()); } bool ViewItem::dataPosLockable() const { return bool(dynamic_cast(parentViewItem())); } void ViewItem::addToMenuForContextEvent(QMenu &menu) { Q_UNUSED(menu); } void ViewItem::startDragging(QWidget *widget, const QPointF& hotspot) { QPointF old_topleft = rect().topLeft(); normalizePosition(); QPointF new_hotspot = hotspot.toPoint() + rect().topLeft() - old_topleft; // UNDO tied zoom settings done in PlotItem::mousePressEvent setTiedZoom(false, false); QDrag *drag = new QDrag(widget); MimeDataViewItem* mimeData = new MimeDataViewItem; mimeData->item = this; mimeData->hotSpot = new_hotspot; drag->setMimeData(mimeData); qreal theta = rotationAngle()*ONE_PI/180.0; qreal w = fabs(rect().width()*cos(theta)) + fabs(rect().height()*sin(theta)); qreal h = fabs(rect().width()*sin(theta)) + fabs(rect().height()*cos(theta)); #ifdef QT5 int device_pixel_ratio = view()->devicePixelRatio(); #else int device_pixel_ratio = 1; #endif QPixmap pixmap(device_pixel_ratio*(w+2), device_pixel_ratio*(h+2)); #ifdef QT5 pixmap.setDevicePixelRatio(device_pixel_ratio); #endif if (ApplicationSettings::self()->transparentDrag()) { pixmap.fill(Qt::transparent); } else { //pixmap.fill(brush().color()); pixmap.fill(view()->backgroundBrush().color()); } QPainter painter(&pixmap); qreal x1 = -rect().height()*sin(theta); qreal x3 = rect().width()*cos(theta); qreal x2 = x1+x3; qreal dx; dx = qMin(qreal(0.0), x1); dx = qMin(x2,dx); dx = qMin(x3,dx); qreal y1 = rect().height()*cos(theta); qreal y3 = rect().width()*sin(theta); qreal y2 = y1+y3; qreal dy; dy = qMin(qreal(0.0), y1); dy = qMin(y2,dy); dy = qMin(y3,dy); painter.translate(-dx,-dy); painter.rotate(rotationAngle()); painter.translate(-rect().left(), -rect().top()); painter.setPen(pen()); //painter.setBrush(brush()); QBrush brush_hold = brush(); setBrush(Qt::NoBrush); paint(&painter); setBrush(brush_hold); // TODO also paint annotations paintChildItems(painter); painter.end(); drag->setPixmap(pixmap); qreal hx = new_hotspot.toPoint().x()-rect().left(); qreal hy = new_hotspot.toPoint().y()-rect().top(); qreal hx_r = hx * cos(theta) - hy * sin(theta); qreal hy_r = hy * cos(theta) + hx * sin(theta); drag->setHotSpot(QPoint(hx_r-dx,hy_r-dy)); dropHotSpot = QPoint(hx_r-dx-w/2-1,hy_r-dy-h/2-1); hide(); Qt::DropActions dact = Qt::MoveAction; Qt::DropAction dropAction = drag->exec(dact); if (dropAction != Qt::MoveAction) { show(); } kstApp->mainWindow()->document()->setChanged(true); } void ViewItem::paintChildItems(QPainter &painter) { QList children = childItems(); foreach(QGraphicsItem* child, children) { ViewItem* item = dynamic_cast(child); if (item) { painter.save(); painter.translate(item->pos().x(), item->pos().y()); painter.rotate(item->rotationAngle()); item->paint(&painter); item->paintChildItems(painter); painter.restore(); } } } void ViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (view()->viewMode() == View::Data) { event->ignore(); return; } #ifdef KST_ENABLE_DD if (!dragStartPosition.isNull() && event->buttons() & Qt::LeftButton) { if (view()->mouseMode() == View::Move) { startDragging(event->widget(), dragStartPosition.toPoint()); return; } } #endif if (view()->mouseMode() == View::Default) { if (gripMode() == ViewItem::Move || activeGrip() == NoGrip) { view()->setMouseMode(View::Move); view()->undoStack()->beginMacro(tr("Move")); } else if (gripMode() == ViewItem::Resize) { view()->setMouseMode(View::Resize); view()->undoStack()->beginMacro(tr("Resize")); } else if (gripMode() == ViewItem::Scale) { view()->setMouseMode(View::Scale); view()->undoStack()->beginMacro(tr("Scale")); } else if (gripMode() == ViewItem::Rotate) { view()->setMouseMode(View::Rotate); view()->undoStack()->beginMacro(tr("Rotate")); } } if (activeGrip() == NoGrip) return QGraphicsRectItem::mouseMoveEvent(event); QPointF p = event->pos(); QPointF s = event->scenePos(); if (gripMode() == ViewItem::Rotate) { switch(_activeGrip) { case TopLeftGrip: rotateTowards(topLeftGrip().controlPointRect().center(), p); break; case TopRightGrip: rotateTowards(topRightGrip().controlPointRect().center(), p); break; case BottomRightGrip: rotateTowards(bottomRightGrip().controlPointRect().center(), p); break; case BottomLeftGrip: rotateTowards(bottomLeftGrip().controlPointRect().center(), p); break; case TopMidGrip: rotateTowards(topMidGrip().controlPointRect().center(), p); break; case RightMidGrip: rotateTowards(rightMidGrip().controlPointRect().center(), p); break; case BottomMidGrip: rotateTowards(bottomMidGrip().controlPointRect().center(), p); break; case LeftMidGrip: rotateTowards(leftMidGrip().controlPointRect().center(), p); break; case NoGrip: break; } } else if (gripMode() == ViewItem::Resize) { switch(_activeGrip) { case TopLeftGrip: resizeTopLeft(p - topLeftGrip().controlPointRect().center()); break; case TopRightGrip: resizeTopRight(p - topRightGrip().controlPointRect().center()); break; case BottomRightGrip: resizeBottomRight(p - bottomRightGrip().controlPointRect().center()); break; case BottomLeftGrip: resizeBottomLeft(p - bottomLeftGrip().controlPointRect().center()); break; case TopMidGrip: resizeTop(p.y() - topMidGrip().controlPointRect().center().y()); break; case RightMidGrip: resizeRight(p.x() - rightMidGrip().controlPointRect().center().x()); break; case BottomMidGrip: resizeBottom(p.y() - bottomMidGrip().controlPointRect().center().y()); break; case LeftMidGrip: resizeLeft(p.x() - leftMidGrip().controlPointRect().center().x()); break; case NoGrip: break; } } else if (gripMode() == ViewItem::Scale) { switch(_activeGrip) { case TopLeftGrip: setTopLeft(s); break; case TopRightGrip: setTopRight(s); break; case BottomRightGrip: setBottomRight(s); break; case BottomLeftGrip: setBottomLeft(s); break; case TopMidGrip: setTop(s.y()); break; case RightMidGrip: setRight(s.x()); break; case BottomMidGrip: setBottom(s.y()); break; case LeftMidGrip: setLeft(s.x()); break; case NoGrip: break; } } updateRelativeSize(true); } void ViewItem::resizeTopLeft(const QPointF &offset) { const qreal oldAspect = rect().width() / rect().height(); QRectF r = rect(); QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, false) : offset; r.setTopLeft(r.topLeft() + o); if (!r.isValid()) return; const qreal newAspect = r.width() / r.height(); Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true, "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData()); Q_UNUSED(newAspect); setViewRect(r); } void ViewItem::resizeTopRight(const QPointF &offset) { const qreal oldAspect = rect().width() / rect().height(); QRectF r = rect(); QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, true) : offset; r.setTopRight(r.topRight() + o); if (!r.isValid()) return; const qreal newAspect = r.width() / r.height(); Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true, "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData()); Q_UNUSED(newAspect); setViewRect(r); } void ViewItem::resizeBottomLeft(const QPointF &offset) { const qreal oldAspect = rect().width() / rect().height(); QRectF r = rect(); QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, true) : offset; r.setBottomLeft(r.bottomLeft() + o); if (!r.isValid()) return; const qreal newAspect = r.width() / r.height(); Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true, "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData()); Q_UNUSED(newAspect); setViewRect(r); } void ViewItem::resizeBottomRight(const QPointF &offset) { const qreal oldAspect = rect().width() / rect().height(); QRectF r = rect(); QPointF o = _lockAspectRatio ? lockOffset(offset, oldAspect, false) : offset; r.setBottomRight(r.bottomRight() + o); if (!r.isValid()) return; const qreal newAspect = r.width() / r.height(); Q_ASSERT_X(_lockAspectRatio ? qFuzzyCompare(newAspect, oldAspect) : true, "lockAspect error", QString(QString::number(newAspect) + "!=" + QString::number(oldAspect)).toLatin1().constData()); Q_UNUSED(newAspect); setViewRect(r); } void ViewItem::resizeTop(qreal offset) { QRectF r = rect(); r.setTop(r.top() + offset); if (!r.isValid()) return; setViewRect(r); } void ViewItem::resizeBottom(qreal offset) { QRectF r = rect(); r.setBottom(r.bottom() + offset); if (!r.isValid()) return; setViewRect(r); } void ViewItem::resizeLeft(qreal offset) { QRectF r = rect(); r.setLeft(r.left() + offset); if (!r.isValid()) return; setViewRect(r); } void ViewItem::resizeRight(qreal offset) { QRectF r = rect(); r.setRight(r.right() + offset); if (!r.isValid()) return; setViewRect(r); } void ViewItem::setTopLeft(const QPointF &point) { QPointF p = point; QPointF anchor = selectTransform().map(rect().bottomRight()); QRectF from = selectBoundingRect(); QRectF to = from; to.setTopLeft(p); from.moveBottomRight(anchor); to.moveBottomRight(anchor); transformToRect(from, to); } void ViewItem::setTopRight(const QPointF &point) { QPointF p = point; QPointF anchor = selectTransform().map(rect().bottomLeft()); QRectF from = selectBoundingRect(); QRectF to = from; to.setTopRight(p); from.moveBottomLeft(anchor); to.moveBottomLeft(anchor); transformToRect(from, to); } void ViewItem::setBottomLeft(const QPointF &point) { QPointF p = point; QPointF anchor = selectTransform().map(rect().topRight()); QRectF from = selectBoundingRect(); QRectF to = from; to.setBottomLeft(p); from.moveTopRight(anchor); to.moveTopRight(anchor); transformToRect(from, to); } void ViewItem::setBottomRight(const QPointF &point) { QPointF p = point; QPointF anchor = selectTransform().map(rect().topLeft()); QRectF from = selectBoundingRect(); QRectF to = from; to.setBottomRight(p); from.moveTopLeft(anchor); to.moveTopLeft(anchor); transformToRect(from, to); } void ViewItem::setTop(qreal y) { QPointF anchor = selectTransform().map(rect().bottomLeft()); QRectF from = selectBoundingRect(); QRectF to = from; to.setTop(y); from.moveBottomLeft(anchor); to.moveBottomLeft(anchor); transformToRect(from, to); } void ViewItem::setBottom(qreal y) { QPointF anchor = selectTransform().map(rect().topLeft()); QRectF from = selectBoundingRect(); QRectF to = from; to.setBottom(y); from.moveTopLeft(anchor); to.moveTopLeft(anchor); transformToRect(from, to); } void ViewItem::setLeft(qreal x) { QPointF anchor = selectTransform().map(rect().topRight()); QRectF from = selectBoundingRect(); QRectF to = from; to.setLeft(x); from.moveTopRight(anchor); to.moveTopRight(anchor); transformToRect(from, to); } void ViewItem::setRight(qreal x) { QPointF anchor = selectTransform().map(rect().topLeft()); QRectF from = selectBoundingRect(); QRectF to = from; to.setRight(x); from.moveTopLeft(anchor); to.moveTopLeft(anchor); transformToRect(from, to); } QTransform ViewItem::selectTransform() const { /* Converts a point on the rect() to a point on the selectBoundingRect() or the inverse by using selectTransform().inverted(). */ QRectF from = rect(); QRectF to = selectBoundingRect(); QTransform rt = _rotationTransform.inverted(); //inverse rotation so far QPolygonF from_ = QPolygonF(rt.map(from)); from_.pop_back(); //get rid of last closed point QPolygonF to_ = QPolygonF(mapFromScene(to)); to_.pop_back(); //get rid of last closed point QTransform select; QTransform::quadToQuad(from_, to_, select); return _rotationTransform.inverted() * select * transform(); } bool ViewItem::transformToRect(const QRectF &from, const QRectF &to) { //Not sure how to handle yet if (!to.isValid()) { return false; } QPolygonF from_(from); from_.pop_back(); //get rid of last closed point QPolygonF to_(to); to_.pop_back(); //get rid of last closed point return transformToRect(from_, to_); } bool ViewItem::transformToRect(const QPolygonF &from, const QPolygonF &to) { QTransform t; bool success = QTransform::quadToQuad(from, to, t); t = transform() * t; if (success) setTransform(t, false); return success; } void ViewItem::rotateTowards(const QPointF &corner, const QPointF &point) { QPointF origin = centerOfRotation(); if (origin == corner || origin == point) return; _normalLine = QLineF(origin, corner); _rotationLine = QLineF(origin, point); qreal angle1 = ::acos(_normalLine.dx() / _normalLine.length()); if (_normalLine.dy() >= 0) angle1 = TWO_PI - angle1; qreal angle2 = ::acos(_rotationLine.dx() / _rotationLine.length()); if (_rotationLine.dy() >= 0) angle2 = TWO_PI - angle2; qreal angle = RAD2DEG * (angle1 - angle2); QTransform t; t.translate(origin.x(), origin.y()); t.rotate(angle); t.translate(-origin.x(), -origin.y()); _rotationTransform = t * _rotationTransform; setTransform(t, true); } void ViewItem::normalizePosition() { qreal parentWidth = parentRect().width(); qreal parentHeight = parentRect().height(); qreal parentX = parentRect().x(); qreal parentY = parentRect().y(); qreal w = relativeWidth() * parentWidth; qreal h = relativeHeight() * parentHeight; setPos(parentX + relativeCenter().x()*parentWidth, parentY + relativeCenter().y()*parentHeight); setViewRect(-w/2, -h/2, w, h); QTransform transform; transform.rotate(rotationAngle()); setTransform(transform); //updateRelativeSize(); //updateViewItemParent(); } QPointF ViewItem::lockOffset(const QPointF &offset, qreal ratio, bool oddCorner) const { qreal x; qreal y; bool xKey; if (offset.x() < 0 && offset.y() > 0) { xKey = true; x = offset.x(); y = x == 0 ? 0 : (1 / ratio) * x; } else if (offset.y() < 0 && offset.x() > 0) { xKey = false; y = offset.y(); x = y == 0 ? 0 : ratio * y; } else if (qAbs(offset.x()) < qAbs(offset.y())) { xKey = true; x = offset.x(); y = x == 0 ? 0 : (1 / ratio) * x; } else { xKey = false; y = offset.y(); x = y == 0 ? 0 : ratio * y; } QPointF o = offset; if (oddCorner) { o = QPointF(!xKey ? -x : x, xKey ? -y : y); } else { o = QPointF(x, y); } return o; } bool ViewItem::updateViewItemParent(bool force_toplevel) { if (lockParent() || skipNextParentCheck()) { setSkipNextParentCheck(false); return false; } //First get a list of all items that collide with this one QList collisions = collidingItems(Qt::IntersectsItemShape); bool topLevel = !parentItem(); QPointF origin = mapToScene(QPointF(0,0)); #if DEBUG_REPARENT qDebug() << "updateViewItemParent" << this << "topLevel:" << (topLevel ? "true" : "false") << "origin:" << origin << "rect:" << rect() << "collision count:" << collisions.count(); #endif //Doesn't collide then reparent to top-level if (collisions.isEmpty() && !topLevel) { #if DEBUG_REPARENT qDebug() << "reparent to topLevel"; qDebug() << "before transform" << "origin:" << mapToScene(QPointF(0,0)); #endif /*bring the old parent's transform with us*/ setTransform(parentItem()->transform(), true); #if DEBUG_REPARENT qDebug() << "after transform" << "origin:" << mapToScene(QPointF(0,0)); #endif setParentViewItem(0); setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0))); updateRelativeSize(); #if DEBUG_REPARENT qDebug() << "after new parent" << "origin:" << mapToScene(QPointF(0,0)); #endif return true; } if (!force_toplevel) { //Look for collisions that completely contain us foreach (QGraphicsItem *item, collisions) { ViewItem *viewItem = dynamic_cast(item); if (!viewItem || !viewItem->acceptsChildItems() || isAncestorOf(viewItem) || !collidesWithItem(viewItem, Qt::ContainsItemBoundingRect)) { #if DEBUG_REPARENT qDebug() << "rejecting collision" << viewItem << !viewItem->acceptsChildItems() << isAncestorOf(viewItem) << !collidesWithItem(viewItem, Qt::ContainsItemBoundingRect); #endif continue; } if (parentItem() == viewItem) { /*already done*/ #if DEBUG_REPARENT qDebug() << "already in containing parent"; #endif return false; } #if DEBUG_REPARENT qDebug() << "reparent to" << viewItem; qDebug() << "before transform" << "origin:" << mapToScene(QPointF(0,0)); #endif if (!topLevel) { /*bring the old parent's transform with us*/ setTransform(parentItem()->transform(), true); } /*cancel out the new parent's initial transform*/ setTransform(viewItem->transform().inverted(), true); #if DEBUG_REPARENT qDebug() << "after transform" << "origin:" << mapToScene(QPointF(0,0)); #endif setParentViewItem(viewItem); setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0))); updateRelativeSize(true); #if DEBUG_REPARENT qDebug() << "after new parent" << "origin:" << mapToScene(QPointF(0,0)); #endif return true; } } //No suitable collisions then reparent to top-level if (!topLevel) { #if DEBUG_REPARENT qDebug() << "reparent to topLevel"; qDebug() << "before transform" << "origin:" << mapToScene(QPointF(0,0)); #endif /*bring the old parent's transform with us*/ setTransform(parentItem()->transform(), true); #if DEBUG_REPARENT qDebug() << "after transform" << "origin:" << mapToScene(QPointF(0,0)); #endif setParentViewItem(0); setPos(mapToParent(mapFromScene(origin)) + pos() - mapToParent(QPointF(0,0))); updateRelativeSize(); #if DEBUG_REPARENT qDebug() << "after new parent" << "origin:" << mapToScene(QPointF(0,0)); #endif return true; } return false; } void ViewItem::updateDataRelativeRect(bool force) { CartesianRenderItem* plot = dynamic_cast(parentViewItem()); if (plot) { if ((!lockPosToData()) || force) { qreal rotation = rotationAngle(); QTransform transform; setTransform(transform); QPointF top_left = mapToParent(rect().topLeft()); QPointF bottom_right = mapToParent(rect().bottomRight()); QRectF localRect(top_left, bottom_right); _dataRelativeRect = plot->plotItem()->mapToProjection(localRect); transform.rotate(rotation); setTransform(transform); } } } void ViewItem::updateRelativeSize(bool force_data) { if (parentViewItem()) { QPointF P; qreal parentHeight = parentViewItem()->height() == 0 ? 1 : parentViewItem()->height(); qreal parentWidth = parentViewItem()->width() == 0 ? 1 : parentViewItem()->width(); _parentRelativeHeight = (height() / parentHeight); _parentRelativeWidth = (width() / parentWidth); P = mapToParent(rect().center()) - parentViewItem()->rect().topLeft(); _parentRelativeCenter = QPointF(P.x() / parentWidth, P.y() / parentHeight); P = mapToParent(rect().topLeft()) - parentViewItem()->rect().topLeft(); _parentRelativePosition = QPointF(P.x() / parentWidth, P.y() / parentHeight); P = mapToParent(rect().bottomLeft()) - parentViewItem()->rect().topLeft(); _parentRelativeLeft = QPointF(P.x() / parentWidth, P.y() / parentHeight); P = mapToParent(rect().bottomRight()) - parentViewItem()->rect().topLeft(); _parentRelativeRight = QPointF(P.x() / parentWidth, P.y() / parentHeight); updateDataRelativeRect(force_data); } else if (view()) { QPointF P; _parentRelativeHeight = (height() / view()->height()); _parentRelativeWidth = (width() / view()->width()); P = mapToParent(rect().center()) - view()->rect().topLeft(); _parentRelativeCenter = QPointF(P.x() / view()->width(), P.y() / view()->height()); P = mapToParent(rect().topLeft()) - view()->rect().topLeft(); _parentRelativePosition = QPointF(P.x() / view()->width(), P.y() / view()->height()); P = mapToParent(rect().bottomLeft()) - view()->rect().topLeft(); _parentRelativeLeft = QPointF(P.x() / view()->width(), P.y() / view()->height()); P = mapToParent(rect().bottomRight()) - view()->rect().topLeft(); _parentRelativeRight = QPointF(P.x() / view()->width(), P.y() / view()->height()); } else { _parentRelativeHeight = 0; _parentRelativeWidth = 0; _parentRelativeCenter = QPointF(0, 0); _parentRelativePosition = QPointF(0, 0); _parentRelativeLeft = QPointF(0, 0); _parentRelativeRight = QPointF(0, 0); } emit relativeSizeUpdated(); } void ViewItem::updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect) { Q_UNUSED(oldParentRect); QRectF itemRect = rect(); //Lock aspect ratio for rotating objects or children with a lockedAspectRatio //FIXME is the child rotated with respect to the parent is the real question... if (transform().isRotating() || lockAspectRatio()) { if (!_fixedSize) { qreal newHeight = relativeHeight() * newParentRect.height(); qreal newWidth = relativeWidth() * newParentRect.width(); qreal aspectRatio = rect().width() / rect().height(); if ((newWidth / newHeight) > aspectRatio) { // newWidth is too large. Use newHeight as key. newWidth = newHeight * aspectRatio; } else { // newHeight is either too large, or perfect. use newWidth as key. newHeight = newWidth / aspectRatio; } itemRect.setBottom(itemRect.top() + newHeight); itemRect.setRight(itemRect.left() + newWidth); } QPointF newCenter = newParentRect.topLeft() + QPointF(newParentRect.width() * _parentRelativeCenter.x(), newParentRect.height() * _parentRelativeCenter.y()); QRectF r = itemRect; r.moveCenter(mapFromParent(newCenter)); QPointF centerOffset = mapToParent(r.topLeft()) - mapToParent(itemRect.topLeft()); setPos(pos() + centerOffset); } else { qreal newHeight = relativeHeight() * newParentRect.height(); qreal newWidth = relativeWidth() * newParentRect.width(); QPointF newTopLeft = newParentRect.topLeft() - itemRect.topLeft() + QPointF(newParentRect.width() * _parentRelativePosition.x(), newParentRect.height() * _parentRelativePosition.y()); itemRect.setWidth(newWidth); itemRect.setHeight(newHeight); setPos(newTopLeft); } setViewRect(itemRect, true); } void ViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { if (view()->viewMode() == View::Data) { event->ignore(); return; } } void ViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (view()->viewMode() == View::Data) { event->ignore(); return; } const QPointF p = event->pos(); dragStartPosition = p; if (isAllowed(TopLeftGrip) && topLeftGrip().contains(p)) { setActiveGrip(TopLeftGrip); } else if (isAllowed(TopRightGrip) && topRightGrip().contains(p)) { setActiveGrip(TopRightGrip); } else if (isAllowed(BottomRightGrip) && bottomRightGrip().contains(p)) { setActiveGrip(BottomRightGrip); } else if (isAllowed(BottomLeftGrip) && bottomLeftGrip().contains(p)) { setActiveGrip(BottomLeftGrip); } else if (isAllowed(TopMidGrip) && topMidGrip().contains(p)) { setActiveGrip(TopMidGrip); } else if (isAllowed(RightMidGrip) && rightMidGrip().contains(p)) { setActiveGrip(RightMidGrip); } else if (isAllowed(BottomMidGrip) && bottomMidGrip().contains(p)) { setActiveGrip(BottomMidGrip); } else if (isAllowed(LeftMidGrip) && leftMidGrip().contains(p)) { setActiveGrip(LeftMidGrip); } else { setActiveGrip(NoGrip); } if (!grips().contains(event->pos()) && event->button() & Qt::LeftButton) { setGripMode(nextGripMode(_gripMode)); } QGraphicsRectItem::mousePressEvent(event); } ViewItem::GripMode ViewItem::nextGripMode(GripMode currentMode) const { if (!(_allowedGripModes & (Resize | Rotate | Scale))) return currentMode; switch (currentMode) { case Move: if (isAllowed(Resize)) return Resize; else return nextGripMode(Resize); break; case Resize: if (isAllowed(Scale)) return Scale; else return nextGripMode(Scale); break; case Scale: if (isAllowed(Rotate)) return Rotate; else return nextGripMode(Rotate); break; case Rotate: if (isAllowed(Resize)) return Resize; else return nextGripMode(Resize); break; default: break; } return currentMode; } void ViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (view()->viewMode() == View::Data) { event->ignore(); return; } dragStartPosition = QPointF(0, 0); if (view()->mouseMode() != View::Default) { view()->setMouseMode(View::Default); view()->undoStack()->endMacro(); } kstApp->mainWindow()->document()->setChanged(true); QGraphicsRectItem::mouseReleaseEvent(event); } void ViewItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { QGraphicsRectItem::hoverMoveEvent(event); if (view()->viewMode() == View::Data) { return; } if (isSelected()) { QPointF p = event->pos(); if ((isAllowed(TopLeftGrip) && topLeftGrip().contains(p)) || (isAllowed(BottomRightGrip) && bottomRightGrip().contains(p))) { if (gripMode() == ViewItem::Rotate) { view()->setCursor(Qt::CrossCursor); } else if (gripMode() == ViewItem::Resize) { view()->setCursor(Qt::SizeFDiagCursor); } } else if ((isAllowed(TopRightGrip) && topRightGrip().contains(p)) || (isAllowed(BottomLeftGrip) && bottomLeftGrip().contains(p))) { if (gripMode() == ViewItem::Rotate) { view()->setCursor(Qt::CrossCursor); } else if (gripMode() == ViewItem::Resize) { view()->setCursor(Qt::SizeBDiagCursor); } } else if ((isAllowed(TopMidGrip) && topMidGrip().contains(p)) || (isAllowed(BottomMidGrip) && bottomMidGrip().contains(p))) { if (gripMode() == ViewItem::Rotate) { view()->setCursor(Qt::CrossCursor); } else if (gripMode() == ViewItem::Resize) { view()->setCursor(Qt::SizeVerCursor); } } else if ((isAllowed(RightMidGrip) && rightMidGrip().contains(p)) || (isAllowed(LeftMidGrip) && leftMidGrip().contains(p))) { if (gripMode() == ViewItem::Rotate) { view()->setCursor(Qt::CrossCursor); } else if (gripMode() == ViewItem::Resize) { view()->setCursor(Qt::SizeHorCursor); } } else { view()->setCursor(Qt::SizeAllCursor); } } else { //view()->setCursor(Qt::SizeAllCursor); } } void ViewItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { QGraphicsRectItem::hoverMoveEvent(event); _hovering = true; update(); } void ViewItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { QGraphicsRectItem::hoverMoveEvent(event); //view()->setCursor(Qt::ArrowCursor); _hovering = false; update(); } QVariant ViewItem::itemChange(GraphicsItemChange change, const QVariant &value) { if (change == ItemSelectedChange) { bool selected = value.toBool(); if (!selected) { setGripMode(ViewItem::Move); update(); } } return QGraphicsItem::itemChange(change, value); } void ViewItem::moveTo(const QPointF& pos) { QPointF newpos = view()->snapPoint(pos); if (parentViewItem()) { newpos -= parentViewItem()->scenePos(); } setPos(newpos); new MoveCommand(this, _originalPosition, pos); updateViewItemParent(); updateRelativeSize(true); } void ViewItem::setItemPos(qreal x, qreal y) { if (_lockPosToData) { QRectF dr = dataRelativeRect(); dr.moveCenter(QPointF(x,y)); setDataRelativeRect(dr); applyDataLockedDimensions(); } else { QRectF parent_rect = parentRect(); qreal parentWidth = parent_rect.width(); qreal parentHeight = parent_rect.height(); qreal parentX = parent_rect.x(); qreal parentY = parent_rect.y(); x = x*parentWidth + parentX; y = y*parentHeight + parentY; setPos(x,y); } } void ViewItem::setItemSize(qreal w, qreal h) { if (_lockPosToData) { QRectF dr = dataRelativeRect(); QPointF center = dr.center(); dr.setWidth(w); if (h>0) { dr.setHeight(h); } dr.moveCenter(center); setDataRelativeRect(dr); applyDataLockedDimensions(); } else { QRectF parent_rect = parentRect(); qreal parentWidth = parent_rect.width(); qreal parentHeight = parent_rect.height(); qreal width = w * parentWidth; qreal height; if (lockAspectRatio()) { qreal aspectRatio; if (rect().width() > 0) { aspectRatio = qreal(rect().height()) / qreal(rect().width()); } else { aspectRatio = 10000.0; } height = width * aspectRatio; } else if (h < 0.0) { height = rect().height(); } else { height = h * parentHeight; } setViewRect(-width/2, -height/2, width, height); } } void ViewItem::viewMouseModeChanged(View::MouseMode oldMode) { if (view()->mouseMode() == View::Move) { _originalPosition = pos(); } else if (view()->mouseMode() == View::Resize || view()->mouseMode() == View::Scale || view()->mouseMode() == View::Rotate) { _originalRect = rect(); _originalTransform = transform(); } else if (oldMode == View::Move && _originalPosition != pos()) { #ifndef KST_ENABLE_DD moveTo(pos()); #endif } else if (oldMode == View::Resize && _originalRect != rect()) { new ResizeCommand(this, _originalRect, rect()); updateViewItemParent(); } else if (oldMode == View::Scale && _originalTransform != transform()) { new ScaleCommand(this, _originalTransform, transform()); updateViewItemParent(); } else if (oldMode == View::Rotate && _originalTransform != transform()) { new RotateCommand(this, _originalTransform, transform()); updateViewItemParent(); } } void ViewItem::registerShortcut(QAction *action) { Q_ASSERT(action->parent() == this); view()->grabShortcut(action->shortcut()); _shortcutMap.insert(action->shortcut(), action); } void ViewItem::reRegisterShortcut() { QHashIterator it(_shortcutMap); while (it.hasNext()) { it.next(); view()->grabShortcut(it.key()); } } bool ViewItem::tryShortcut(const QString &shortcut) { if (!_shortcutMap.contains(shortcut)) return false; QAction *action = _shortcutMap.value(shortcut); if (!action->isEnabled()) return false; action->trigger(); return true; } QPainterPath ViewItem::checkBox() const { QRectF bound = selectBoundingRect(); QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width() * 1.25, sizeOfGrip().height() * -.25), sizeOfGrip()); QPainterPath path; path.addEllipse(grip); return path; } QPainterPath ViewItem::tiedZoomCheck() const { QRectF bound = selectBoundingRect(); QRectF grip = QRectF(bound.topRight() - QPointF(sizeOfGrip().width() * 1.25, sizeOfGrip().height() * -.25), sizeOfGrip()); QPainterPath path; if (isXTiedZoom() && isYTiedZoom()) { path.addEllipse(grip); } else if (isXTiedZoom()) { path.moveTo(grip.center()); path.arcTo(grip, 225, 180); } else if (isYTiedZoom()) { path.moveTo(grip.center()); path.arcTo(grip, 45, 180); } return path; } void ViewItem::updateView() { update(); } qreal ViewItem::rotationAngle() const { return 180.0/ONE_PI * atan2(transform().m12(), transform().m11()); } qreal ViewItem::rotationAngleRadians() const { return atan2(transform().m12(), transform().m11()); } void ViewItem::setSupportsTiedZoom(const bool supports) { if (supports != _supportsTiedZoom) { _supportsTiedZoom = supports; if (_supportsTiedZoom && ((layoutMargins().width() < tiedZoomSize().width()) || (layoutMargins().height() < tiedZoomSize().height()))) { setLayoutMargins(layoutMargins().expandedTo(tiedZoomSize())); } if (!_supportsTiedZoom) { setTiedZoom(false, false, false); } } } void ViewItem::setTiedZoom(bool tiedXZoom, bool tiedYZoom, bool checkAllTied) { Q_UNUSED(checkAllTied) if ((_isXTiedZoom == tiedXZoom) && (_isYTiedZoom == tiedYZoom)) return; bool wasTiedZoom = isTiedZoom(); _isXTiedZoom = tiedXZoom; _isYTiedZoom = tiedYZoom; if (isTiedZoom() && !wasTiedZoom) { PlotItemManager::self()->addTiedZoomViewItem(this); } else if (!isTiedZoom() && wasTiedZoom) { PlotItemManager::self()->removeTiedZoomViewItem(this); } //FIXME ugh, this is expensive, but need to redraw the checkboxes... update(); } QString ViewItem::_automaticDescriptiveName() const { return typeName(); } QString ViewItem::descriptionTip() const { return typeName(); } ScriptInterface* ViewItem::createScriptInterface() { return new ViewItemSI(this); } ScriptInterface* ViewItem::scriptInterface() { if (!_interface) { _interface = createScriptInterface(); } return _interface; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, ViewItem *viewItem) { dbg.nospace() << viewItem->typeName(); return dbg.space(); } #endif ViewItemCommand::ViewItemCommand(ViewItem *item, const QString &text, bool addToStack, QUndoCommand *parent) : QUndoCommand(text, parent), _item(item) { if (addToStack) _item->view()->undoStack()->push(this); } ViewItemCommand::~ViewItemCommand() { } CreateCommand::CreateCommand(const QString &text, QUndoCommand *parent) : ViewCommand(text, false, parent) { } CreateCommand::CreateCommand(View *view, const QString &text, QUndoCommand *parent) : ViewCommand(view, text, false, parent) { } CreateCommand::~CreateCommand() { } void CreateCommand::undo() { Q_ASSERT(_item); _item->hide(); } void CreateCommand::redo() { Q_ASSERT(_item); _item->show(); } void CreateCommand::createItem() { Q_ASSERT(_item); Q_ASSERT(_view); _view->setMouseMode(View::Create); //If the mouseMode is changed again before we're done with creation //delete ourself. connect(_view, SIGNAL(mouseModeChanged(View::MouseMode)), _item, SLOT(deleteLater())); connect(_view, SIGNAL(creationPolygonChanged(View::CreationEvent)), _item, SLOT(creationPolygonChanged(View::CreationEvent))); connect(_item, SIGNAL(creationComplete()), this, SLOT(creationComplete())); //If the item is interrupted while creating itself it will destroy itself //need to delete this too in response... connect(_item, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater())); } void CreateCommand::creationComplete() { _view->undoStack()->push(this); kstApp->mainWindow()->clearDrawingMarker(); kstApp->mainWindow()->document()->setChanged(true); } void LayoutCommand::undo() { Q_ASSERT(_layout); _layout->reset(); } void LayoutCommand::redo() { Q_ASSERT(_layout); _layout->apply(); } void LayoutCommand::createLayout(bool preserve, int columns) { Q_ASSERT(_item); Q_ASSERT(_item->view()); QList viewItems; QList list = _item->QGraphicsItem::childItems(); if (list.isEmpty()) { return; //not added to undostack } viewItems = _item->view()->layoutableViewItems(); if (viewItems.isEmpty()) { return; //not added to undostack } _layout = new ViewGridLayout(_item); FormatGridHelper grid(viewItems, preserve); if (columns == 0) { int n_view_items = viewItems.size(); for (int i_view_item = 0; i_view_itemaddViewItem(v, rc.row, rc.col, rc.row_span, rc.col_span); } } else { int row = 0; int col = 0; int n_view_items = viewItems.size(); for (int i_view_item = 0; i_view_itemaddViewItem(v, row, col, 1, 1); col++; if (col>=columns) { col = 0; row++; } } } if (qobject_cast(_item)) { QObject::connect(_layout, SIGNAL(enabledChanged(bool)), _item, SLOT(setEnabled(bool))); } _layout->apply(); _item->view()->undoStack()->push(this); } void AppendLayoutCommand::undo() { if (_layout) { _layout->reset(); } } void AppendLayoutCommand::redo() { Q_ASSERT(_layout); _layout->apply(); } void AppendLayoutCommand::appendLayout(CurvePlacement::Layout layout, ViewItem* item, int columns) { Q_ASSERT(_item); Q_ASSERT(_item->view()); Q_ASSERT(item); if (layout == CurvePlacement::Auto) { columns = 0; } if (layout == CurvePlacement::Custom) layout = CurvePlacement::Protect; if (layout == CurvePlacement::Protect) { _layout = new ViewGridLayout(_item); QPointF center = _item->view()->sceneRect().center(); center -= QPointF(100.0, 100.0); item->setPos(center); item->setViewRect(0.0, 0.0, 200.0, 200.0); _item->view()->scene()->addItem(item); //_item->view()->undoStack()->push(this); return; } QList viewItems; viewItems = _item->view()->layoutableViewItems(); _layout = new ViewGridLayout(_item); FormatGridHelper grid(viewItems); if (grid.n_cols == columns) { if (grid.numHoles()=0) { break; } } } if (row<0) { // no empty slots if (grid.n_rows>grid.n_cols) { // add a column row = 0; col = grid.n_cols; } else { // add a row row = grid.n_rows; col = 0; } } int n_views = viewItems.size(); for (int i_view = 0; i_viewaddViewItem(v, rc.row, rc.col, rc.row_span, rc.col_span); } _item->view()->scene()->addItem(item); _layout->addViewItem(item, row, col, 1,1); } else { int row = 0; int col = 0; int n_views = viewItems.size(); for (int i_view = 0; i_viewaddViewItem(v, row, col, 1, 1); col++; if (col>=columns) { col = 0; row++; } } _item->view()->scene()->addItem(item); _layout->addViewItem(item, row, col, 1,1); _layout->setColumnCount(columns); } if (qobject_cast(_item)) { QObject::connect(_layout, SIGNAL(enabledChanged(bool)), _item, SLOT(setEnabled(bool))); } _layout->apply(); } void MoveCommand::undo() { Q_ASSERT(_item); _item->setPos(_originalPos); } void MoveCommand::redo() { Q_ASSERT(_item); _item->setPos(_newPos); } void ResizeCommand::undo() { Q_ASSERT(_item); _item->setViewRect(_originalRect, true); } void ResizeCommand::redo() { Q_ASSERT(_item); _item->setViewRect(_newRect, true); } void RemoveCommand::undo() { Q_ASSERT(_item); _item->show(); } void RemoveCommand::redo() { Q_ASSERT(_item); _item->hide(); // hmmm... view items aren't really deleted!! if we delete them, // then we run into trouble with the undo stack. If we don't, then // they keep holding onto the curves, preventing purge. } void RaiseCommand::undo() { Q_ASSERT(_item); _item->setZValue(_item->zValue() - 1); } void RaiseCommand::redo() { Q_ASSERT(_item); _item->setZValue(_item->zValue() + 1); } void LowerCommand::undo() { Q_ASSERT(_item); _item->setZValue(_item->zValue() + 1); } void LowerCommand::redo() { Q_ASSERT(_item); _item->setZValue(_item->zValue() - 1); } void TransformCommand::undo() { Q_ASSERT(_item); _item->setTransform(_originalTransform); } void TransformCommand::redo() { Q_ASSERT(_item); _item->setTransform(_newTransform); } MimeDataViewItem::MimeDataViewItem() : QMimeData() { } const MimeDataViewItem* MimeDataViewItem::downcast(const QMimeData* m) { return qobject_cast(m); } } // vim: ts=2 sw=2 et diff --git a/src/libkstapp/viewitem.h b/src/libkstapp/viewitem.h index 9c577eae..e00b9721 100644 --- a/src/libkstapp/viewitem.h +++ b/src/libkstapp/viewitem.h @@ -1,671 +1,671 @@ /*************************************************************************** * * * copyright : (C) 2007 The University of Toronto * * netterfield@astro.utoronto.ca * * * * 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. * * * ***************************************************************************/ #ifndef VIEWITEM_H #define VIEWITEM_H #include #include #include #include #include #include #include #include "namedobject.h" #include "kst_export.h" #include "viewcommand.h" #include "view.h" #include "curveplacement.h" //#include "sharedptr.h" #include "application.h" #include "tabwidget.h" namespace Kst { class DialogPage; class ViewGridLayout; class ViewItem; class ViewItemDialog; class ScriptInterface; typedef QList ViewItemList; class ViewItem : public QObject, public NamedObject, public QGraphicsRectItem { Q_OBJECT public: friend class DialogLauncherSI; friend class ViewItemSI; enum GripMode { Move = 1, Resize = 2, Scale = 4, Rotate = 8 }; Q_DECLARE_FLAGS(GripModes, GripMode) enum ActiveGrip { NoGrip = 1, TopLeftGrip = 2, TopRightGrip = 4, BottomRightGrip = 8, BottomLeftGrip = 16, TopMidGrip = 32, RightMidGrip = 64, BottomMidGrip = 128, LeftMidGrip = 256 }; Q_DECLARE_FLAGS(ActiveGrips, ActiveGrip) enum CreationState { None, InProgress, Completed }; explicit ViewItem(View *parent); virtual ~ViewItem(); virtual void save(QXmlStreamWriter &xml); bool parse(QXmlStreamReader &xml, bool &validChildTag); enum { Type = UserType + 1 }; int type() const { return Type; } void setTypeName(const QString& name) { _typeName = name; } const QString typeName() const { return _typeName; } // for dialog defaults virtual const QString defaultsGroupName() const = 0; // for view item dialogs virtual bool hasStroke() const {return false;} virtual bool hasBrush() const {return false;} virtual bool hasFont() const {return false;} virtual void setFont(const QFont &f, const QColor &c) {return;} View* view() const; void setView(View*); ViewItem *parentViewItem() const; void setParentViewItem(ViewItem *parent); virtual void updateRelativeSize(bool force_data = false); virtual void updateDataRelativeRect(bool force = false); void moveTo(const QPointF& pos); qreal relativeHeight() const { return _parentRelativeHeight; } void setRelativeHeight(const qreal height) { _parentRelativeHeight = height; } qreal relativeWidth() const { return _parentRelativeWidth; } void setRelativeWidth(const qreal width) { _parentRelativeWidth = width; } QPointF relativeCenter() const { return _parentRelativeCenter; } void setRelativeCenter(const QPointF center) { _parentRelativeCenter = center; } QPointF relativePosition() const { return _parentRelativePosition; } void setRelativePosition(const QPointF pos) { _parentRelativePosition = pos; } void setRelativeLeft(const QPointF &pos) { _parentRelativeLeft = pos;} QPointF relativeRight() const {return _parentRelativeRight;} void setRelativeRight(const QPointF &pos) { _parentRelativeRight = pos;} QRectF dataRelativeRect() const { return _dataRelativeRect;} void setDataRelativeRect(QRectF r) { _dataRelativeRect = r;} void setItemPos(qreal x, qreal y); void setItemSize(qreal w, qreal h = -10.0); qreal rotationAngle() const; qreal rotationAngleRadians() const; GripMode gripMode() const; void setGripMode(GripMode mode); GripModes allowedGripModes() const; void setAllowedGripModes(GripModes modes); bool isAllowed(GripMode mode) const; bool fixedSize() const { return _fixedSize; } void setFixedSize(bool fixedSize) { _fixedSize = fixedSize; } bool lockAspectRatio() const { return _lockAspectRatio; } void setLockAspectRatio(bool lockAspectRatio) { _lockAspectRatio = lockAspectRatio; } bool lockAspectRatioFixed() const { return _lockAspectRatioFixed; } void setLockAspectRatioFixed(bool enable) { _lockAspectRatioFixed = enable; } bool hasStaticGeometry() const { return _hasStaticGeometry; } void setHasStaticGeometry(bool hasStaticGeometry ) { _hasStaticGeometry = hasStaticGeometry; } bool lockParent() const { return _lockParent; } void setLockParent(bool lockParent ) { _lockParent = lockParent; } bool skipNextParentCheck() const { return _skipNextParentCheck; } void setSkipNextParentCheck(bool skipNextParentCheck) { _skipNextParentCheck = skipNextParentCheck; } bool allowsLayout() const { return _allowsLayout; } void setAllowsLayout(bool allowsLayout ) { _allowsLayout = allowsLayout; } bool isHighlighted() const { return _highlighted; } void setHighlighted(bool highlighted ) { _highlighted = highlighted; } bool lockPosToData() const {return _lockPosToData; } //NOTE This should be used in place of QGraphicsRectItem::setRect()... QRectF viewRect() const; void setViewRect(const QRectF &viewRect, bool automaticChange = false); void setViewRect(qreal x, qreal y, qreal width, qreal height, bool automaticChange = false); qreal width() const { return viewRect().normalized().width(); } qreal height() const { return viewRect().normalized().height(); } ActiveGrip activeGrip() const; void setActiveGrip(ActiveGrip grip); ActiveGrips allowedGrips() const; void setAllowedGrips(ActiveGrips grips); bool isAllowed(ActiveGrip grip) const; virtual QSizeF sizeOfGrip() const; virtual QPainterPath grips() const; virtual QRectF selectBoundingRect() const; virtual QRectF gripBoundingRect() const; virtual QRectF boundingRect() const; virtual QPainterPath shape() const; virtual QPainterPath itemShape() const { return QGraphicsRectItem::shape(); } virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); virtual void paint(QPainter *painter); virtual void paintChildItems(QPainter &painter); virtual QList dialogPages() const { return QList(); } virtual QPointF centerOfRotation() const { return rect().center(); } bool isHovering() const { return _hovering; } bool acceptsChildItems() const { return _acceptsChildItems; } void setAcceptsChildItems(bool acceptsChildItems) { _acceptsChildItems = acceptsChildItems; } QSizeF layoutMargins() const { return _layoutMargins; } void setLayoutMargins(const QSizeF margins) { _layoutMargins = margins; } QSizeF layoutSpacing() const { return _layoutSpacing; } void setLayoutSpacing(const QSizeF spacing) { _layoutSpacing = spacing; } //This is a workaround for context menu bug in Qt4.3 graphicsview bool acceptsContextMenuEvents() const { return _acceptsContextMenuEvents; } void setAcceptsContextMenuEvents(bool acceptsContextMenuEvents) { _acceptsContextMenuEvents = acceptsContextMenuEvents; } virtual bool tryShortcut(const QString &keySequence); virtual QPainterPath checkBox() const; virtual QPainterPath tiedZoomCheck() const; virtual QSizeF tiedZoomSize() const { return QSizeF(checkBox().controlPointRect().size() * 1.5); } virtual bool isTiedZoom() const { return (_isXTiedZoom || _isYTiedZoom); } virtual bool isXTiedZoom() const { return _isXTiedZoom; } virtual bool isYTiedZoom() const { return _isYTiedZoom; } virtual void setTiedZoom(bool tiedXZoom, bool tiedYZoom, bool checkAllTied = true); virtual bool supportsTiedZoom() const { return _supportsTiedZoom; } virtual void setSupportsTiedZoom(const bool supports); View::ZoomOnlyMode zoomOnlyMode() const { return _zoomOnlyMode; } void setZoomOnly(View::ZoomOnlyMode val) { _zoomOnlyMode = val; } CreationState creationState() const { return _creationState; } virtual void setItemPen(const QPen & pen) { storePen(pen); } virtual void setItemBrush(const QBrush & brush) { setBrush(brush); } template static T* retrieveItem(const QString &name); template static QList getItems(bool include_hidden=false); // TODO: Remove, needed only for a Qt 4.3 bug workaround bool doSceneEvent(QGraphicsSceneContextMenuEvent *event) { return sceneEvent(event); } virtual bool isMaximized(); QPointF dropHotSpot; void normalizePosition(); - virtual void applyDialogDefaultsFill(); - virtual void applyDialogDefaultsStroke(); + virtual void applyDialogDefaultsFill(bool default_no_fill = false); + virtual void applyDialogDefaultsStroke(bool default_no_pen = false); void applyDialogDefaultsLockPosToData(); virtual void applyDataLockedDimensions(); virtual bool dataPosLockable() const; QRectF parentRect() const; void storePen(const QPen &pen) {_storedPen = pen; setPen(pen);} QPen storedPen() const { return _storedPen;} virtual ScriptInterface *createScriptInterface(); ScriptInterface *scriptInterface(); virtual bool updateViewItemParent(bool force_toplevel = false); Q_SIGNALS: void geometryChanged(); void creationComplete(); void relativeSizeUpdated(); /*FIXME these should be made private for only undo commands to access*/ public Q_SLOTS: virtual void edit(); virtual void raise(); virtual void lower(); virtual void createAutoLayout(); virtual void createProtectedLayout(); virtual void createCustomLayout(int columns = 0); virtual void sharePlots(QPainter *painter, bool creation); virtual void remove(); void resizeTopLeft(const QPointF &offset); void resizeTopRight(const QPointF &offset); void resizeBottomLeft(const QPointF &offset); void resizeBottomRight(const QPointF &offset); void resizeTop(qreal offset); void resizeBottom(qreal offset); void resizeLeft(qreal offset); void resizeRight(qreal offset); void setTopLeft(const QPointF &point); void setTopRight(const QPointF &point); void setBottomLeft(const QPointF &point); void setBottomRight(const QPointF &point); void setTop(qreal y); void setBottom(qreal y); void setLeft(qreal x); void setRight(qreal x); void setLockPosToData(bool lockPosToData); virtual bool customDimensionsTab() {return false;} virtual void clearEditDialogPtr() {_editDialog = 0;} protected: virtual QPainterPath topLeftGrip() const; virtual QPainterPath topRightGrip() const; virtual QPainterPath bottomRightGrip() const; virtual QPainterPath bottomLeftGrip() const; virtual QPainterPath topMidGrip() const; virtual QPainterPath rightMidGrip() const; virtual QPainterPath bottomMidGrip() const; virtual QPainterPath leftMidGrip() const; QTransform selectTransform() const; bool transformToRect(const QRectF &from, const QRectF &to); bool transformToRect(const QPolygonF &from, const QPolygonF &to); void rotateTowards(const QPointF &corner, const QPointF &point); QPointF lockOffset(const QPointF &offset, qreal ratio, bool oddCorner) const; GripMode nextGripMode(GripMode currentMode) const; void addTitle(QMenu *menu) const; void registerShortcut(QAction *action); void reRegisterShortcut(); QString descriptionTip() const; protected Q_SLOTS: virtual void creationPolygonChanged(View::CreationEvent event); void creationPolygonChangedFixedAspect(View::CreationEvent even, qreal aspect); protected: virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); virtual void addToMenuForContextEvent(QMenu &menu); virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); QAction *_editAction; QAction *_deleteAction; QAction *_raiseAction; QAction *_lowerAction; QAction *_autoLayoutAction; QAction *_protectedLayoutAction; QAction *_customLayoutAction; QAction *_lockPosToDataAction; bool _isXTiedZoom; bool _isYTiedZoom; bool _plotMaximized; private Q_SLOTS: void viewMouseModeChanged(View::MouseMode oldMode); void updateView(); protected: public: virtual void updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect); protected: virtual QString _automaticDescriptiveName() const; virtual void _initializeShortName(); QPointF dragStartPosition; void startDragging(QWidget *widget, const QPointF& hotspot); ActiveGrip _activeGrip; QRectF _dataRelativeRect; QPointF _originalPosition; QPointF _parentRelativeCenter; QPointF _parentRelativePosition; QPointF _parentRelativeLeft; QPointF _parentRelativeRight; qreal _parentRelativeHeight, _parentRelativeWidth; const double dpi() { return _dpi;} private: GripMode _gripMode; GripModes _allowedGripModes; CreationState _creationState; QString _typeName; View::ZoomOnlyMode _zoomOnlyMode; bool _supportsTiedZoom; bool _fixedSize; bool _lockAspectRatio; bool _lockAspectRatioFixed; bool _hasStaticGeometry; bool _lockParent; bool _skipNextParentCheck; bool _allowsLayout; bool _hovering; bool _acceptsChildItems; bool _acceptsContextMenuEvents; bool _updatingLayout; bool _highlighted; QRectF _originalRect; QTransform _originalTransform; QLineF _normalLine; QLineF _rotationLine; ActiveGrips _allowedGrips; QTransform _rotationTransform; QHash _shortcutMap; bool _lockPosToData; QSizeF _layoutMargins, _layoutSpacing; // use view() / setView(View*) QObject* parent() const; void setParent(QObject*); // use setParentViewItem(ViewItem*) void setParentItem(QGraphicsItem*); ViewItemDialog *_editDialog; QPen _storedPen; ScriptInterface *_interface; double _dpi; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ViewItem::GripModes) Q_DECLARE_OPERATORS_FOR_FLAGS(ViewItem::ActiveGrips) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug, ViewItem*); #endif class ViewItemCommand : public QUndoCommand { public: ViewItemCommand(ViewItem *item, const QString &text, bool addToStack = true, QUndoCommand *parent = 0); virtual ~ViewItemCommand(); protected: QPointer _item; }; class CreateCommand : public QObject, public ViewCommand { Q_OBJECT public: explicit CreateCommand(const QString &text, QUndoCommand *parent = 0); CreateCommand(View *view, const QString &text, QUndoCommand *parent = 0); virtual ~CreateCommand(); virtual void undo(); virtual void redo(); virtual void createItem(); ViewItem *item() const { return _item; } public Q_SLOTS: virtual void creationComplete(); protected: QPointer _item; }; class LayoutCommand : public ViewItemCommand { public: explicit LayoutCommand(ViewItem *item) : ViewItemCommand(item, QObject::tr("Create layout"), false) {} virtual ~LayoutCommand() {} virtual void undo(); virtual void redo(); void createLayout(bool preserve = true, int columns = 0); private: QPointer _layout; }; class AppendLayoutCommand : public ViewItemCommand { public: explicit AppendLayoutCommand(ViewItem *item) : ViewItemCommand(item, QObject::tr("Append Item to Layout"), false) {} virtual ~AppendLayoutCommand() {} virtual void undo(); virtual void redo(); void appendLayout(CurvePlacement::Layout layout, ViewItem* item, int columns = 0); private: QPointer _layout; }; class MoveCommand : public ViewItemCommand { public: MoveCommand(ViewItem *item, const QPointF &originalPos, const QPointF &newPos) : ViewItemCommand(item, QObject::tr("Move")), _originalPos(originalPos), _newPos(newPos) {} virtual ~MoveCommand() {} virtual void undo(); virtual void redo(); private: QPointF _originalPos; QPointF _newPos; }; class ResizeCommand : public ViewItemCommand { public: ResizeCommand(ViewItem *item, const QRectF &originalRect, const QRectF &newRect) : ViewItemCommand(item, QObject::tr("Resize")), _originalRect(originalRect), _newRect(newRect) {} virtual ~ResizeCommand() {} virtual void undo(); virtual void redo(); private: QRectF _originalRect; QRectF _newRect; }; class RemoveCommand : public ViewItemCommand { public: explicit RemoveCommand(ViewItem *item) : ViewItemCommand(item, QObject::tr("Remove")) {} virtual ~RemoveCommand() {} virtual void undo(); virtual void redo(); }; class RaiseCommand : public ViewItemCommand { public: explicit RaiseCommand(ViewItem *item) : ViewItemCommand(item, QObject::tr("Raise")) {} virtual ~RaiseCommand() {} virtual void undo(); virtual void redo(); }; class LowerCommand : public ViewItemCommand { public: explicit LowerCommand(ViewItem *item) : ViewItemCommand(item, QObject::tr("Lower")) {} virtual ~LowerCommand() {} virtual void undo(); virtual void redo(); }; class TransformCommand : public ViewItemCommand { public: TransformCommand(ViewItem *item, const QTransform &originalTransform, const QTransform &newTransform, const QString &text) : ViewItemCommand(item, text), _originalTransform(originalTransform), _newTransform(newTransform) {} virtual ~TransformCommand() {} virtual void undo(); virtual void redo(); private: QTransform _originalTransform; QTransform _newTransform; }; class ScaleCommand : public TransformCommand { public: ScaleCommand(ViewItem *item, const QTransform &originalTransform, const QTransform &newTransform) : TransformCommand(item, originalTransform, newTransform, QObject::tr("Scale")) {} virtual ~ScaleCommand() {} }; class RotateCommand : public TransformCommand { public: RotateCommand(ViewItem *item, const QTransform &originalTransform, const QTransform &newTransform) : TransformCommand(item, originalTransform, newTransform, QObject::tr("Rotate")) {} virtual ~RotateCommand() {} }; template QList ViewItem::getItems(bool include_hidden) { QList tItems; ViewItem *viewItem; T* tItem; QList views = kstApp->mainWindow()->tabWidget()->views(); for (int i_view = 0; i_view items = views.at(i_view)->scene()->items(); for (int i_item = 0; i_item(items[i_item]); tItem = dynamic_cast(viewItem); if ((tItem) && (include_hidden || viewItem->isVisible())) { tItems.append(tItem); } } } return tItems; } template T* ViewItem::retrieveItem(const QString &name) { QList tItems = getItems(); int match = -1; if (name.isEmpty()) { return NULL; } QString shortName; QRegExp rx("(\\(|^)([A-Z]\\d+)(\\)$|$)"); rx.indexIn(name); shortName = rx.cap(2); // 1) search for short names int size = tItems.size(); for (int i = 0; i < size; ++i) { if (tItems.at(i)->shortName()==shortName) return tItems.at(i); } // 3) search for descriptive names: must be unique for (int i = 0; i < size; ++i) { if (tItems.at(i)->descriptiveName() == name) { if (match != -1) return NULL; // not unique, so... no match match = i; } } if (match >-1) return tItems.at(match); return NULL; } class MimeDataViewItem : public QMimeData { Q_OBJECT public: MimeDataViewItem(); ViewItem* item; QPointF hotSpot; static const MimeDataViewItem* downcast(const QMimeData*); }; } #endif // vim: ts=2 sw=2 et diff --git a/src/widgets/dialogdefaults.cpp b/src/widgets/dialogdefaults.cpp index 46152925..13db147b 100644 --- a/src/widgets/dialogdefaults.cpp +++ b/src/widgets/dialogdefaults.cpp @@ -1,145 +1,154 @@ /*************************************************************************** * * * copyright : (C) 2007 The University of Toronto * * netterfield@astro.utoronto.ca * * * * 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. * * * ***************************************************************************/ #include "dialogdefaults.h" #include "datasource.h" #include "settings.h" #include namespace Kst { QSettings& dialogDefaults() { static QSettings& settingsObject = createSettings("dialog"); return settingsObject; } void setDataVectorDefaults(DataVectorPtr V) { dialogDefaults().setValue("vector/datasource", V->filename()); } void setGenVectorDefaults(GeneratedVectorPtr V) { dialogDefaults().setValue("genVector/min", V->min()); dialogDefaults().setValue("genVector/max", V->max()); dialogDefaults().setValue("genVector/length", V->length()); } void setDataMatrixDefaults(DataMatrixPtr M) { //qDebug() << "M...filename: " << M->dataSource()->fileName(); // FIXME: data source filename isn't valid... dialogDefaults().setValue("matrix/datasource",M->dataSource()->fileName()); dialogDefaults().setValue("matrix/xCountFromEnd",M->xCountFromEnd()); dialogDefaults().setValue("matrix/yCountFromEnd",M->yCountFromEnd()); dialogDefaults().setValue("matrix/xReadToEnd",M->xReadToEnd()); dialogDefaults().setValue("matrix/yReadToEnd",M->yReadToEnd()); dialogDefaults().setValue("matrix/xNumSteps",M->xNumSteps()); dialogDefaults().setValue("matrix/yNumSteps",M->yNumSteps()); dialogDefaults().setValue("matrix/reqXStart",M->reqXStart()); dialogDefaults().setValue("matrix/reqYStart",M->reqYStart()); dialogDefaults().setValue("matrix/frame",M->frame()); } void setHistogramDefaults(HistogramPtr H) { dialogDefaults().setValue("histogram/realTimeAutoBin", H->realTimeAutoBin()); dialogDefaults().setValue("histogram/normalizationType",H->normalizationType()); } void saveDialogDefaultsLockPosToData(const QString &group_name, const bool lockPosToData) { dialogDefaults().setValue(group_name+"/lockPosToData", QVariant(lockPosToData).toString()); } void saveDialogDefaultsBrush(const QString &group_name, const QBrush &b) { // Save the brush dialogDefaults().setValue(group_name+"/fillBrushColor", QVariant(b.color()).toString()); dialogDefaults().setValue(group_name+"/fillBrushStyle", QVariant((int)b.style()).toString()); dialogDefaults().setValue(group_name+"/fillBrushUseGradient", QVariant(bool(b.gradient())).toString()); if (b.gradient()) { QString stopList; foreach(const QGradientStop &stop, b.gradient()->stops()) { qreal point = (qreal)stop.first; QColor color = (QColor)stop.second; stopList += QString::number(point); stopList += ','; stopList += color.name(); stopList += ','; } dialogDefaults().setValue(group_name+"/fillBrushGradient", stopList); } } void saveDialogDefaultsPen(const QString &group_name, const QPen &p) { // Save stroke... QBrush b = p.brush(); dialogDefaults().setValue(group_name+"/strokeStyle", QVariant((int)p.style()).toString()); dialogDefaults().setValue(group_name+"/strokeWidth", p.widthF()); dialogDefaults().setValue(group_name+"/strokeJoinStyle", QVariant(p.joinStyle()).toString()); dialogDefaults().setValue(group_name+"/strokeCapStyle", QVariant(p.capStyle()).toString()); dialogDefaults().setValue(group_name+"/strokeBrushColor", QVariant(b.color()).toString()); dialogDefaults().setValue(group_name+"/strokeBrushStyle", QVariant((int)b.style()).toString()); } -QBrush dialogDefaultsBrush(const QString &group_name) { +QBrush dialogDefaultsBrush(const QString &group_name, bool default_no_fill) { //set the brush QBrush brush; bool useGradient = dialogDefaults().value(group_name +"/fillBrushUseGradient", false).toBool(); if (useGradient) { QStringList stopInfo = dialogDefaults().value(group_name +"/fillBrushGradient", "0,#000000,1,#ffffff,"). toString().split(',', QString::SkipEmptyParts); QLinearGradient gradient(1,0,0,0); gradient.setCoordinateMode(QGradient::ObjectBoundingMode); for (int i = 0; i < stopInfo.size(); i+=2) { gradient.setColorAt(stopInfo.at(i).toDouble(), QColor(stopInfo.at(i+1))); } brush = QBrush(gradient); } else { QColor color = dialogDefaults().value(group_name +"/fillBrushColor",QColor(Qt::white)).value(); brush.setColor(color); - brush.setStyle((Qt::BrushStyle)dialogDefaults().value(group_name +"/fillBrushStyle",1).toInt()); + if (default_no_fill) { + qDebug() << "setting default to no brush"; + brush.setStyle((Qt::BrushStyle)dialogDefaults().value(group_name +"/fillBrushStyle",0).toInt()); + } else { + brush.setStyle((Qt::BrushStyle)dialogDefaults().value(group_name +"/fillBrushStyle",1).toInt()); + } } return brush; } -QPen dialogDefaultsPen(const QString &group_name) { +QPen dialogDefaultsPen(const QString &group_name, bool default_no_pen) { QPen pen; QColor color; QBrush brush; - pen.setStyle((Qt::PenStyle)dialogDefaults().value(group_name +"/strokeStyle", 1).toInt()); + if (default_no_pen) { + pen.setStyle((Qt::PenStyle)dialogDefaults().value(group_name +"/strokeStyle", 0).toInt()); + } else { + pen.setStyle((Qt::PenStyle)dialogDefaults().value(group_name +"/strokeStyle", 1).toInt()); + } pen.setWidthF(dialogDefaults().value(group_name +"/strokeWidth",0).toDouble()); pen.setJoinStyle((Qt::PenJoinStyle)dialogDefaults().value(group_name +"/strokeJoinStyle",64).toInt()); pen.setCapStyle((Qt::PenCapStyle)dialogDefaults().value(group_name +"/strokeCapStyle",16).toInt()); color = dialogDefaults().value(group_name +"/strokeBrushColor",QColor(Qt::black)).value(); brush.setColor(color); brush.setStyle((Qt::BrushStyle)dialogDefaults().value(group_name +"/strokeBrushStyle",1).toInt()); pen.setBrush(brush); return pen; } bool dialogDefaultsLockPosToData(const QString &group_name) { return dialogDefaults().value(group_name+"/lockPosToData",false).toBool(); } } diff --git a/src/widgets/dialogdefaults.h b/src/widgets/dialogdefaults.h index a4341995..e9933c46 100644 --- a/src/widgets/dialogdefaults.h +++ b/src/widgets/dialogdefaults.h @@ -1,105 +1,105 @@ /*************************************************************************** dialogdefaults.h ------------------- begin : November 13, 2007 copyright : (C) 2007 C. Barth Netterfield email : netterfield@astro.utoronto.ca ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KSTDIALOGDEFAULTS #define KSTDIALOGDEFAULTS #include "datavector.h" #include "psd.h" #include "generatedvector.h" #include "datamatrix.h" #include "histogram.h" #include "kstwidgets_export.h" class QSettings; namespace Kst { KSTWIDGETS_EXPORT QSettings& dialogDefaults(); KSTWIDGETS_EXPORT void setDataVectorDefaults(DataVectorPtr); KSTWIDGETS_EXPORT void setGenVectorDefaults(GeneratedVectorPtr V); KSTWIDGETS_EXPORT void setDataMatrixDefaults(DataMatrixPtr M); KSTWIDGETS_EXPORT void setHistogramDefaults(HistogramPtr H); KSTWIDGETS_EXPORT void saveDialogDefaultsBrush(const QString &group_name, const QBrush &b); KSTWIDGETS_EXPORT void saveDialogDefaultsLockPosToData(const QString &group_name, const bool lockPosToData); KSTWIDGETS_EXPORT void saveDialogDefaultsPen(const QString &group_name, const QPen &p); - KSTWIDGETS_EXPORT QBrush dialogDefaultsBrush(const QString &group_name); - KSTWIDGETS_EXPORT QPen dialogDefaultsPen(const QString &group_name); + KSTWIDGETS_EXPORT QBrush dialogDefaultsBrush(const QString &group_name, bool default_no_fill = false); + KSTWIDGETS_EXPORT QPen dialogDefaultsPen(const QString &group_name, bool default_no_pen = false); KSTWIDGETS_EXPORT bool dialogDefaultsLockPosToData(const QString &group_name); } #endif // Dialog defaults are stored and retrieved from the Kst::dialogDefaults. // As you add defaults, add them here! // Name Type Where used // vector/datasource QString vectordialog datawizard // vector/range int datarange // vector/start int datarange // vector/countFromEnd bool datarange // vector/readToEnd bool datarange // vector/skip int datarange // vector/doSkip bool datarange // vector/doAve bool datarange // // genVector/min" int vectordialog // genVector/max" int vectordialog // genVector/length int vectordialog // spectrum/freq double FFToptions // spectrum/average bool FFToptions // spectrum/len int FFToptions // spectrum/apodize bool FFToptions // spectrum/removeMean bool FFToptions // spectrum/vUnits QString FFToptions // spectrum/rUnits QString FFToptions // spectrum/apodizeFxn int FFToptions // spectrum/gaussianSigma double FFToptions // spectrum/output int FFToptions // spectrum/interpolateHoles bool FFToptions // curve/xvectorfield QString datawizard, curvedialog // export/filename QString exportgraphicsdialog // export/format QString exportgraphicsdialog // export/xsize exportgraphicsdialog // export/ysize exportgraphicsdialog // export/sizeOption exportgraphicsdialog // picture/startdir pictureitem.cpp // histogram/realTimeAutoBin histogramdialog.cpp // matrix/datasource matrixdialog.cpp // matrix/reqXStart matrixdialog.cpp // matrix/reqYStart matrixdialog.cpp // matrix/xCountFromEnd matrixdialog.cpp // matrix/xNumSteps matrixdialog.cpp // matrix/xReadToEnd matrixdialog.cpp // matrix/yCountFromEnd matrixdialog.cpp // matrix/yNumSteps matrixdialog.cpp // matrix/yReadToEnd matrixdialog.cpp // wizard/updateType int datawizard.cpp // wizard/doPSD bool datawizard.cpp // wizard/doXY bool datawizard.cpp // wizard/curvePlacement enum datawizard.cpp // wizard/plotPlacement enum datawizard.cpp // wizard/plotCount int datawizard.cpp // changedatafile/newFileName QString changefiledialog.cpp // viewvector/digits int vectormodel.cpp, viewvectordialog.cpp