diff --git a/libs/ui/kis_painting_assistant.h b/libs/ui/kis_painting_assistant.h --- a/libs/ui/kis_painting_assistant.h +++ b/libs/ui/kis_painting_assistant.h @@ -99,6 +99,14 @@ bool isSnappingActive() const; void setSnappingActive(bool set); + // used for setting settings that only apply to one type of assistant + // vanishing point has an angle setting for example for its outline + virtual void setCustomPropertyFloat(QString propertyName, float value ); + float getCustomPropertyFloat(QString propertyName); + QHash customFloatProperties; + + + /** * Adjust the position given in parameter. * @param point the coordinates in point in the document reference diff --git a/libs/ui/kis_painting_assistant.cc b/libs/ui/kis_painting_assistant.cc --- a/libs/ui/kis_painting_assistant.cc +++ b/libs/ui/kis_painting_assistant.cc @@ -167,6 +167,20 @@ d->isSnappingActive = set; } +void KisPaintingAssistant::setCustomPropertyFloat(QString propertyName, float value) +{ + customFloatProperties.insert(propertyName, value); // updates value too if it already exists +} + +float KisPaintingAssistant::getCustomPropertyFloat(QString propertyName) +{ + if (customFloatProperties.contains(propertyName)) { + return customFloatProperties.value(propertyName); + } + + return -1; // is not found +} + void KisPaintingAssistant::drawPath(QPainter& painter, const QPainterPath &path, bool isSnappingOn) { int alpha = d->assistantColor.alpha(); @@ -331,6 +345,22 @@ xml.writeStartElement("assistant"); xml.writeAttribute("type",d->id); xml.writeAttribute("active", QString::number(d->isSnappingActive)); + + + // write custom properties if they exist with the assistant + // the vanishing point assistant angle is the only one right now + if (customFloatProperties.count() > 0) { + xml.writeStartElement("floatProperties"); + + QHash::iterator i; + for (i = customFloatProperties.begin(); i != customFloatProperties.end(); ++i) { + xml.writeAttribute(i.key(), QString::number(i.value())); + } + xml.writeEndElement(); + } + + + // write individual handle data xml.writeStartElement("handles"); Q_FOREACH (const KisPaintingAssistantHandleSP handle, d->handles) { int id = handleMap.size(); @@ -365,6 +395,12 @@ d->isSnappingActive = (active != "0"); } + if (xml.name() == "floatProperties") { + for (int i=0; i < xml.attributes().size(); ++i) { + setCustomPropertyFloat(xml.attributes().at(i).name().toString(), xml.attributes().at(i).value().toFloat()); + } + } + if (xml.name() == "handle") { QString strId = xml.attributes().value("id").toString(), strX = xml.attributes().value("x").toString(), diff --git a/libs/ui/kis_painting_assistants_decoration.h b/libs/ui/kis_painting_assistants_decoration.h --- a/libs/ui/kis_painting_assistants_decoration.h +++ b/libs/ui/kis_painting_assistants_decoration.h @@ -69,6 +69,14 @@ QList handles(); QList assistants() const; + + /// getter and setter functions for what assistant is currently selected + /// this is used to control some tool options that are specific to a assistant + KisPaintingAssistantSP selectedAssistant(); + void setSelectedAssistant(KisPaintingAssistantSP assistant); + void deselectAssistant(); + + /// called when assistant editor is activated /// right now this happens when the assistants tool is selected void activateAssistantsEditor(); @@ -111,6 +119,8 @@ Q_SIGNALS: void assistantChanged(); + void selectedAssistantChanged(); + public Q_SLOTS: /// toggles whether the assistant is active or not diff --git a/libs/ui/kis_painting_assistants_decoration.cpp b/libs/ui/kis_painting_assistants_decoration.cpp --- a/libs/ui/kis_painting_assistants_decoration.cpp +++ b/libs/ui/kis_painting_assistants_decoration.cpp @@ -47,6 +47,7 @@ bool outlineVisible; bool snapOnlyOneAssistant; KisPaintingAssistantSP firstAssistant; + KisPaintingAssistantSP selectedAssistant; bool aFirstStroke; QColor m_assistantsColor = QColor(176, 176, 176, 255); // kis_assistant_tool has same default color specified bool m_isEditingAssistants = false; @@ -290,6 +291,23 @@ return assistants; } +KisPaintingAssistantSP KisPaintingAssistantsDecoration::selectedAssistant() +{ + return d->selectedAssistant; +} + +void KisPaintingAssistantsDecoration::setSelectedAssistant(KisPaintingAssistantSP assistant) +{ + d->selectedAssistant = assistant; + emit selectedAssistantChanged(); +} + +void KisPaintingAssistantsDecoration::deselectAssistant() +{ + d->selectedAssistant = 0; +} + + void KisPaintingAssistantsDecoration::setAssistantVisible(bool set) { d->assistantVisible=set; @@ -439,4 +457,5 @@ gc.drawPixmap(iconDeletePosition, d->m_iconDelete); + } diff --git a/plugins/assistants/Assistants/AssistantsToolOptions.ui b/plugins/assistants/Assistants/AssistantsToolOptions.ui --- a/plugins/assistants/Assistants/AssistantsToolOptions.ui +++ b/plugins/assistants/Assistants/AssistantsToolOptions.ui @@ -6,8 +6,8 @@ 0 0 - 188 - 211 + 284 + 274 @@ -59,54 +59,45 @@ - - - - 0 - 0 - - - - Opacity: - - - - 100 - - - - - + - + 0 0 - - Color: + + + 20 + 0 + + + + + + + Qt::Horizontal + + + + + - - - - 0 - 0 - - + - 30 - 0 + 0 + 20 @@ -121,7 +112,7 @@ 20 - 0 + 5 @@ -141,6 +132,12 @@
kis_slider_spin_box.h
1 + + KisDoubleSliderSpinBox + QWidget +
kis_slider_spin_box.h
+ 1 +
diff --git a/plugins/assistants/Assistants/VanishingPointAssistant.h b/plugins/assistants/Assistants/VanishingPointAssistant.h --- a/plugins/assistants/Assistants/VanishingPointAssistant.h +++ b/plugins/assistants/Assistants/VanishingPointAssistant.h @@ -50,6 +50,9 @@ QPointF buttonPosition() const override; int numHandles() const override { return 1; } + // set the angle property + void setCustomPropertyFloat(QString propertyName, float value ) override; + bool isAssistantComplete() const; protected: @@ -58,6 +61,9 @@ private: QPointF project(const QPointF& pt, const QPointF& strokeBegin); KisCanvas2 *m_canvas; + + float m_referenceLineDensity = 5.0; + }; class VanishingPointAssistantFactory : public KisPaintingAssistantFactory diff --git a/plugins/assistants/Assistants/VanishingPointAssistant.cc b/plugins/assistants/Assistants/VanishingPointAssistant.cc --- a/plugins/assistants/Assistants/VanishingPointAssistant.cc +++ b/plugins/assistants/Assistants/VanishingPointAssistant.cc @@ -177,12 +177,40 @@ } - gc.restore(); + // draw references guide for vanishing points at specified density + // this is shown as part of the preview, so don't show if preview is off + if( canvas->paintingAssistantsDecoration()->outlineVisibility()) { - KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible); + // cycle through degrees from 0 to 180. We are doing an infinite line, so we don't need to go 360 + QTransform initialTransform = converter->documentToWidgetTransform(); + QPointF p0 = initialTransform.map(*handles()[0]); // main vanishing point + for (int currentAngle=0; currentAngle <= 180; currentAngle = currentAngle + m_referenceLineDensity ) { + + // determine the correct angle based on the iteration + float xPos = cos(currentAngle * M_PI / 180); + float yPos = sin(currentAngle * M_PI / 180); + QPointF unitAngle; + unitAngle.setX(p0.x() + xPos); + unitAngle.setY(p0.y() + yPos); + + // find point + QLineF snapLine= QLineF(p0, unitAngle); + QRect viewport= gc.viewport(); + KisAlgebra2D::intersectLineRect(snapLine, viewport); + + // make a line from VP center to edge of canvas with that angle + QPainterPath path; + path.moveTo(snapLine.p1()); + path.lineTo(snapLine.p2()); + drawPreview(gc, path);//and we draw the preview. + } + } + gc.restore(); + + KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached, canvas, assistantVisible, previewVisible); } void VanishingPointAssistant::drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible) @@ -215,6 +243,20 @@ return (*handles()[0]); } +void VanishingPointAssistant::setCustomPropertyFloat(QString propertyName, float value) +{ + if (propertyName == "angleDensity") { + // cannot have less than a 1 degree + if (value < 1.0) { + value = 1.0; + } + + m_referenceLineDensity = value; + } + + KisPaintingAssistant::setCustomPropertyFloat(propertyName, value); +} + bool VanishingPointAssistant::isAssistantComplete() const { return handles().size() > 0; // only need one point to be ready diff --git a/plugins/assistants/Assistants/kis_assistant_tool.h b/plugins/assistants/Assistants/kis_assistant_tool.h --- a/plugins/assistants/Assistants/kis_assistant_tool.h +++ b/plugins/assistants/Assistants/kis_assistant_tool.h @@ -82,10 +82,18 @@ void addAssistant(); void removeAssistant(KisPaintingAssistantSP assistant); + void assistantSelected(KisPaintingAssistantSP assistant); + + void updateToolOptionsUI(); + + public Q_SLOTS: void activate(ToolActivation toolActivation, const QSet &shapes) override; void deactivate() override; + + void slotChangeVanishingPointAngle(double value); + private Q_SLOTS: void removeAllAssistants(); void saveAssistants(); diff --git a/plugins/assistants/Assistants/kis_assistant_tool.cc b/plugins/assistants/Assistants/kis_assistant_tool.cc --- a/plugins/assistants/Assistants/kis_assistant_tool.cc +++ b/plugins/assistants/Assistants/kis_assistant_tool.cc @@ -46,7 +46,7 @@ #include #include #include "kis_global.h" - +#include "VanishingPointAssistant.h" #include @@ -64,6 +64,7 @@ void KisAssistantTool::activate(ToolActivation toolActivation, const QSet &shapes) { + KisTool::activate(toolActivation, shapes); m_canvas->paintingAssistantsDecoration()->activateAssistantsEditor(); @@ -76,6 +77,12 @@ m_canvas->paintingAssistantsDecoration()->setHandleSize(17); m_handleSize = 17; + if (m_optionsWidget) { + m_canvas->paintingAssistantsDecoration()->deselectAssistant(); + + updateToolOptionsUI(); + } + m_canvas->updateCanvas(); } @@ -115,18 +122,32 @@ // we probably need to stop storing a reference in m_handles and call the assistants directly m_handles = m_canvas->paintingAssistantsDecoration()->handles(); + Q_FOREACH (KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { - // find out which handle on all assistants is closes to the mouse position - Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_handles) { - double dist = KisPaintingAssistant::norm2(mousePos - m_canvas->viewConverter()->documentToView(*handle)); - if (dist < minDist) { - minDist = dist; - m_handleDrag = handle; + + // find out which handle on all assistants is closest to the mouse position + // vanishing points have "side handles", so make sure to include that + { + QList allAssistantHandles; + allAssistantHandles.append(assistant->handles()); + allAssistantHandles.append(assistant->sideHandles()); + + Q_FOREACH (const KisPaintingAssistantHandleSP handle, allAssistantHandles) { + + double dist = KisPaintingAssistant::norm2(mousePos - m_canvas->viewConverter()->documentToView(*handle)); + if (dist < minDist) { + minDist = dist; + m_handleDrag = handle; + + assistantSelected(assistant); // whatever handle is the closest contains the selected assistant + } } } + + if(m_handleDrag && assistant->id() == "perspective") { // Look for the handle which was pressed @@ -297,6 +318,10 @@ m_cursorStart = event->point; m_currentAdjustment = QPointF(); m_internalMode = MODE_EDITING; + + + assistantSelected(assistant); // whatever handle is the closest contains the selected assistant + return; } @@ -314,6 +339,8 @@ newAssistantAllowed = false; assistant->setSnappingActive(!assistant->isSnappingActive()); // toggle assistant->uncache();//this updates the chache of the assistant, very important. + + assistantSelected(assistant); // whatever handle is the closest contains the selected assistant } } if (newAssistantAllowed==true){//don't make a new assistant when I'm just toogling visiblity// @@ -500,11 +527,16 @@ { m_canvas->paintingAssistantsDecoration()->addAssistant(m_newAssistant); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); + m_canvas->paintingAssistantsDecoration()->setSelectedAssistant(m_newAssistant); + updateToolOptionsUI(); // vanishing point assistant will get an extra option + KisAbstractPerspectiveGrid* grid = dynamic_cast(m_newAssistant.data()); if (grid) { m_canvas->viewManager()->resourceProvider()->addPerspectiveGrid(grid); } m_newAssistant.clear(); + + } void KisAssistantTool::removeAssistant(KisPaintingAssistantSP assistant) @@ -515,6 +547,51 @@ } m_canvas->paintingAssistantsDecoration()->removeAssistant(assistant); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); + + m_canvas->paintingAssistantsDecoration()->deselectAssistant(); + updateToolOptionsUI(); +} + +void KisAssistantTool::assistantSelected(KisPaintingAssistantSP assistant) +{ + m_canvas->paintingAssistantsDecoration()->setSelectedAssistant(assistant); + updateToolOptionsUI(); +} + +void KisAssistantTool::updateToolOptionsUI() +{ + KisPaintingAssistantSP m_selectedAssistant = m_canvas->paintingAssistantsDecoration()->selectedAssistant(); + + if (m_selectedAssistant) { + bool showDensityOption = m_selectedAssistant->id() == "vanishing point"; + m_options.vanishingPointAngleSpinbox->setVisible(showDensityOption); + + if (showDensityOption) { + // load density setting + if (m_selectedAssistant->getCustomPropertyFloat("angleDensity") == -1) { + m_options.vanishingPointAngleSpinbox->setValue(15.0); + } else { + m_options.vanishingPointAngleSpinbox->setValue( m_selectedAssistant->getCustomPropertyFloat("angleDensity")); + } + } + + } else { + // nothing selected, so hide UI controls + m_options.vanishingPointAngleSpinbox->setVisible(false); + } +} + +void KisAssistantTool::slotChangeVanishingPointAngle(double value) +{ + if ( m_canvas->paintingAssistantsDecoration()->assistants().length() == 0) { + return; + } + + // get the selected assistant and change the angle value + if ( m_canvas->paintingAssistantsDecoration()->selectedAssistant()) { + m_canvas->paintingAssistantsDecoration()->selectedAssistant()->setCustomPropertyFloat("angleDensity", (float)value); + } + } void KisAssistantTool::mouseMoveEvent(KoPointerEvent *event) @@ -584,6 +661,9 @@ m_canvas->paintingAssistantsDecoration()->removeAll(); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); m_canvas->updateCanvas(); + + m_canvas->paintingAssistantsDecoration()->deselectAssistant(); + updateToolOptionsUI(); } void KisAssistantTool::loadAssistants() @@ -632,7 +712,12 @@ errors = true; } } - } else if (xml.name() == "assistant") { + } else if (xml.name() == "floatProperties") { + for (int i=0; i < xml.attributes().size(); ++i) { + assistant->setCustomPropertyFloat(xml.attributes().at(i).name().toString(), xml.attributes().at(i).value().toFloat()); + } + } + else if (xml.name() == "assistant") { const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(xml.attributes().value("type").toString()); if (factory) { if (assistant) { @@ -710,9 +795,27 @@ } xml.writeEndElement(); xml.writeStartElement("assistants"); + + + + Q_FOREACH (const KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { xml.writeStartElement("assistant"); xml.writeAttribute("type", assistant->id()); + + // custom assistant properties like angle density on vanishing point + if (assistant->customFloatProperties.count() > 0) { + xml.writeStartElement("floatProperties"); + + QHash::iterator i; + for (i = assistant->customFloatProperties.begin(); i != assistant->customFloatProperties.end(); ++i) { + xml.writeAttribute(i.key(), QString::number(i.value())); + } + xml.writeEndElement(); + } + + + // handle information xml.writeStartElement("handles"); Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) { xml.writeStartElement("handle"); @@ -772,8 +875,12 @@ connect(m_options.assistantsOpacitySlider, SIGNAL(valueChanged(int)), SLOT(slotAssistantOpacityChanged())); + connect(m_options.vanishingPointAngleSpinbox, SIGNAL(valueChanged(double)), this, SLOT(slotChangeVanishingPointAngle(double))); + + m_options.assistantsColor->setColor(QColor(176, 176, 176, 255)); // grey default for all assistants m_options.assistantsOpacitySlider->setValue(100); // 100% + m_options.assistantsOpacitySlider->setPrefix(i18n("Opacity: ")); m_options.assistantsOpacitySlider->setSuffix(" %"); m_assistantsOpacity = m_options.assistantsOpacitySlider->value()*0.01; @@ -781,6 +888,16 @@ QColor newColor = m_options.assistantsColor->color(); newColor.setAlpha(m_assistantsOpacity*255); m_canvas->paintingAssistantsDecoration()->setAssistantsColor(newColor); + + m_options.vanishingPointAngleSpinbox->setPrefix(i18n("Density: ")); + m_options.vanishingPointAngleSpinbox->setSuffix(QChar(Qt::Key_degree)); + m_options.vanishingPointAngleSpinbox->setRange(1.0, 30.0); + m_options.vanishingPointAngleSpinbox->setSingleStep(0.5); + + + m_options.vanishingPointAngleSpinbox->setVisible(false); + + } return m_optionsWidget; }