diff --git a/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc b/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc index 70894493a7..9300d8a5d3 100644 --- a/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc +++ b/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc @@ -1,913 +1,913 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2010 Geoffry Song * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_global.h" #include KisRulerAssistantTool::KisRulerAssistantTool(KoCanvasBase * canvas) : KisTool(canvas, KisCursor::arrowCursor()), m_canvas(dynamic_cast(canvas)), m_assistantDrag(0), m_newAssistant(0), m_optionsWidget(0), m_handleSize(32), m_handleHalfSize(16) { Q_ASSERT(m_canvas); setObjectName("tool_rulerassistanttool"); } KisRulerAssistantTool::~KisRulerAssistantTool() { } QPointF adjustPointF(const QPointF& _pt, const QRectF& _rc) { return QPointF(qBound(_rc.left(), _pt.x(), _rc.right()), qBound(_rc.top(), _pt.y(), _rc.bottom())); } void KisRulerAssistantTool::activate(ToolActivation toolActivation, const QSet &shapes) { // Add code here to initialize your tool when it got activated KisTool::activate(toolActivation, shapes); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); m_canvas->paintingAssistantsDecoration()->setVisible(true); m_canvas->updateCanvas(); m_handleDrag = 0; m_internalMode = MODE_CREATION; m_assistantHelperYOffset = 10; } void KisRulerAssistantTool::deactivate() { // Add code here to initialize your tool when it got deactivated m_canvas->updateCanvas(); KisTool::deactivate(); } bool KisRulerAssistantTool::mouseNear(const QPointF& mousep, const QPointF& point) { QRectF handlerect(point-QPointF(m_handleHalfSize,m_handleHalfSize), QSizeF(m_handleSize, m_handleSize)); return handlerect.contains(mousep); } KisPaintingAssistantHandleSP KisRulerAssistantTool::nodeNearPoint(KisPaintingAssistantSP grid, QPointF point) { if (mouseNear(point, pixelToView(*grid->topLeft()))) { return grid->topLeft(); } else if (mouseNear(point, pixelToView(*grid->topRight()))) { return grid->topRight(); } else if (mouseNear(point, pixelToView(*grid->bottomLeft()))) { return grid->bottomLeft(); } else if (mouseNear(point, pixelToView(*grid->bottomRight()))) { return grid->bottomRight(); } return 0; } inline double norm2(const QPointF& p) { return p.x() * p.x() + p.y() * p.y(); } void KisRulerAssistantTool::beginPrimaryAction(KoPointerEvent *event) { setMode(KisTool::PAINT_MODE); bool newAssistantAllowed = true; if (m_newAssistant) { m_internalMode = MODE_CREATION; *m_newAssistant->handles().back() = snapToGuide(event, QPointF(), false); if (m_newAssistant->handles().size() == m_newAssistant->numHandles()) { addAssistant(); } else { m_newAssistant->addHandle(new KisPaintingAssistantHandle(snapToGuide(event, QPointF(), false))); } m_canvas->updateCanvas(); return; } m_handleDrag = 0; double minDist = 81.0; QPointF mousePos = m_canvas->viewConverter()->documentToView(snapToGuide(event, QPointF(), false));//m_canvas->viewConverter()->documentToView(event->point); Q_FOREACH (KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_handles) { double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*handle)); if (dist < minDist) { minDist = dist; m_handleDrag = handle; } } if(m_handleDrag && assistant->id() == "perspective") { // Look for the handle which was pressed if (m_handleDrag == assistant->topLeft()) { double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*m_handleDrag)); if (dist < minDist) { minDist = dist; } m_dragStart = QPointF(assistant->topRight().data()->x(),assistant->topRight().data()->y()); m_internalMode = MODE_DRAGGING_NODE; } else if (m_handleDrag == assistant->topRight()) { double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*m_handleDrag)); if (dist < minDist) { minDist = dist; } m_internalMode = MODE_DRAGGING_NODE; m_dragStart = QPointF(assistant->topLeft().data()->x(),assistant->topLeft().data()->y()); } else if (m_handleDrag == assistant->bottomLeft()) { double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*m_handleDrag)); if (dist < minDist) { minDist = dist; } m_internalMode = MODE_DRAGGING_NODE; m_dragStart = QPointF(assistant->bottomRight().data()->x(),assistant->bottomRight().data()->y()); } else if (m_handleDrag == assistant->bottomRight()) { double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*m_handleDrag)); if (dist < minDist) { minDist = dist; } m_internalMode = MODE_DRAGGING_NODE; m_dragStart = QPointF(assistant->bottomLeft().data()->x(),assistant->bottomLeft().data()->y()); } else if (m_handleDrag == assistant->leftMiddle()) { m_internalMode = MODE_DRAGGING_TRANSLATING_TWONODES; m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->topLeft().data()->x())*0.5, (assistant->bottomLeft().data()->y()+assistant->topLeft().data()->y())*0.5); m_selectedNode1 = new KisPaintingAssistantHandle(assistant->topLeft().data()->x(),assistant->topLeft().data()->y()); m_selectedNode2 = new KisPaintingAssistantHandle(assistant->bottomLeft().data()->x(),assistant->bottomLeft().data()->y()); m_newAssistant = toQShared(KisPaintingAssistantFactoryRegistry::instance()->get("perspective")->createPaintingAssistant()); m_newAssistant->addHandle(assistant->topLeft()); m_newAssistant->addHandle(m_selectedNode1); m_newAssistant->addHandle(m_selectedNode2); m_newAssistant->addHandle(assistant->bottomLeft()); m_dragEnd = event->point; m_handleDrag = 0; m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas return; } else if (m_handleDrag == assistant->rightMiddle()) { m_dragStart = QPointF((assistant->topRight().data()->x()+assistant->bottomRight().data()->x())*0.5, (assistant->topRight().data()->y()+assistant->bottomRight().data()->y())*0.5); m_internalMode = MODE_DRAGGING_TRANSLATING_TWONODES; m_selectedNode1 = new KisPaintingAssistantHandle(assistant->topRight().data()->x(),assistant->topRight().data()->y()); m_selectedNode2 = new KisPaintingAssistantHandle(assistant->bottomRight().data()->x(),assistant->bottomRight().data()->y()); m_newAssistant = toQShared(KisPaintingAssistantFactoryRegistry::instance()->get("perspective")->createPaintingAssistant()); m_newAssistant->addHandle(assistant->topRight()); m_newAssistant->addHandle(m_selectedNode1); m_newAssistant->addHandle(m_selectedNode2); m_newAssistant->addHandle(assistant->bottomRight()); m_dragEnd = event->point; m_handleDrag = 0; m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas return; } else if (m_handleDrag == assistant->topMiddle()) { m_dragStart = QPointF((assistant->topLeft().data()->x()+assistant->topRight().data()->x())*0.5, (assistant->topLeft().data()->y()+assistant->topRight().data()->y())*0.5); m_internalMode = MODE_DRAGGING_TRANSLATING_TWONODES; m_selectedNode1 = new KisPaintingAssistantHandle(assistant->topLeft().data()->x(),assistant->topLeft().data()->y()); m_selectedNode2 = new KisPaintingAssistantHandle(assistant->topRight().data()->x(),assistant->topRight().data()->y()); m_newAssistant = toQShared(KisPaintingAssistantFactoryRegistry::instance()->get("perspective")->createPaintingAssistant()); m_newAssistant->addHandle(m_selectedNode1); m_newAssistant->addHandle(m_selectedNode2); m_newAssistant->addHandle(assistant->topRight()); m_newAssistant->addHandle(assistant->topLeft()); m_dragEnd = event->point; m_handleDrag = 0; m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas return; } else if (m_handleDrag == assistant->bottomMiddle()) { m_dragStart = QPointF((assistant->bottomLeft().data()->x()+assistant->bottomRight().data()->x())*0.5, (assistant->bottomLeft().data()->y()+assistant->bottomRight().data()->y())*0.5); m_internalMode = MODE_DRAGGING_TRANSLATING_TWONODES; m_selectedNode1 = new KisPaintingAssistantHandle(assistant->bottomLeft().data()->x(),assistant->bottomLeft().data()->y()); m_selectedNode2 = new KisPaintingAssistantHandle(assistant->bottomRight().data()->x(),assistant->bottomRight().data()->y()); m_newAssistant = toQShared(KisPaintingAssistantFactoryRegistry::instance()->get("perspective")->createPaintingAssistant()); m_newAssistant->addHandle(assistant->bottomLeft()); m_newAssistant->addHandle(assistant->bottomRight()); m_newAssistant->addHandle(m_selectedNode2); m_newAssistant->addHandle(m_selectedNode1); m_dragEnd = event->point; m_handleDrag = 0; m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas return; } m_snapIsRadial = false; } else if (m_handleDrag && assistant->handles().size()>1 && (assistant->id() == "ruler" || assistant->id() == "parallel ruler" || assistant->id() == "infinite ruler" || assistant->id() == "spline")){ if (m_handleDrag == assistant->handles()[0]) { m_dragStart = *assistant->handles()[1]; } else if (m_handleDrag == assistant->handles()[1]) { m_dragStart = *assistant->handles()[0]; } else if(assistant->handles().size()==4){ if (m_handleDrag == assistant->handles()[2]) { m_dragStart = *assistant->handles()[0]; } else if (m_handleDrag == assistant->handles()[3]) { m_dragStart = *assistant->handles()[1]; } } m_snapIsRadial = false; } else if (m_handleDrag && assistant->handles().size()>2 && (assistant->id() == "ellipse" || assistant->id() == "concentric ellipse" || assistant->id() == "fisheye-point")){ m_snapIsRadial = false; if (m_handleDrag == assistant->handles()[0]) { m_dragStart = *assistant->handles()[1]; } else if (m_handleDrag == assistant->handles()[1]) { m_dragStart = *assistant->handles()[0]; } else if (m_handleDrag == assistant->handles()[2]) { m_dragStart = assistant->buttonPosition(); m_radius = QLineF(m_dragStart, *assistant->handles()[0]); m_snapIsRadial = true; } } else { m_dragStart = assistant->buttonPosition(); m_snapIsRadial = false; } } if (m_handleDrag) { // TODO: Shift-press should now be handled using the alternate actions // if (event->modifiers() & Qt::ShiftModifier) { // m_handleDrag->uncache(); // m_handleDrag = m_handleDrag->split()[0]; // m_handles = m_canvas->view()->paintingAssistantsDecoration()->handles(); // } m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas return; } m_assistantDrag.clear(); Q_FOREACH (KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { // This code contains the click event behavior. The actual display of the icons are done at the bottom // of the paint even. Make sure the rectangles positions are the same between the two. // TODO: These 6 lines are duplicated below in the paint layer. It shouldn't be done like this. QPointF actionsPosition = m_canvas->viewConverter()->documentToView(assistant->buttonPosition()); QPointF iconDeletePosition(actionsPosition + QPointF(78, m_assistantHelperYOffset + 7)); QPointF iconSnapPosition(actionsPosition + QPointF(54, m_assistantHelperYOffset + 7)); QPointF iconMovePosition(actionsPosition + QPointF(15, m_assistantHelperYOffset)); QRectF deleteRect(iconDeletePosition, QSizeF(16, 16)); QRectF visibleRect(iconSnapPosition, QSizeF(16, 16)); QRectF moveRect(iconMovePosition, QSizeF(32, 32)); if (moveRect.contains(mousePos)) { m_assistantDrag = assistant; m_cursorStart = event->point; m_currentAdjustment = QPointF(); m_internalMode = MODE_EDITING; return; } if (deleteRect.contains(mousePos)) { removeAssistant(assistant); if(m_canvas->paintingAssistantsDecoration()->assistants().isEmpty()) { m_internalMode = MODE_CREATION; } else m_internalMode = MODE_EDITING; m_canvas->updateCanvas(); return; } if (visibleRect.contains(mousePos)) { newAssistantAllowed = false; if (assistant->snapping()==true){ snappingOff(assistant); outlineOff(assistant); } else{ snappingOn(assistant); outlineOn(assistant); } assistant->uncache();//this updates the chache of the assistant, very important. } } if (newAssistantAllowed==true){//don't make a new assistant when I'm just toogling visiblity// QString key = m_options.comboBox->model()->index( m_options.comboBox->currentIndex(), 0 ).data(Qt::UserRole).toString(); m_newAssistant = toQShared(KisPaintingAssistantFactoryRegistry::instance()->get(key)->createPaintingAssistant()); m_internalMode = MODE_CREATION; m_newAssistant->addHandle(new KisPaintingAssistantHandle(snapToGuide(event, QPointF(), false))); if (m_newAssistant->numHandles() <= 1) { if (key == "vanishing point"){ m_newAssistant->addSideHandle(new KisPaintingAssistantHandle(event->point+QPointF(-70,0))); m_newAssistant->addSideHandle(new KisPaintingAssistantHandle(event->point+QPointF(-140,0))); m_newAssistant->addSideHandle(new KisPaintingAssistantHandle(event->point+QPointF(70,0))); m_newAssistant->addSideHandle(new KisPaintingAssistantHandle(event->point+QPointF(140,0))); } addAssistant(); } else { m_newAssistant->addHandle(new KisPaintingAssistantHandle(snapToGuide(event, QPointF(), false))); } } m_canvas->updateCanvas(); } void KisRulerAssistantTool::continuePrimaryAction(KoPointerEvent *event) { if (m_handleDrag) { *m_handleDrag = event->point; //ported from the gradient tool... we need to think about this more in the future. if (event->modifiers() == Qt::ShiftModifier && m_snapIsRadial) { QLineF dragRadius = QLineF(m_dragStart, event->point); dragRadius.setLength(m_radius.length()); *m_handleDrag = dragRadius.p2(); } else if (event->modifiers() == Qt::ShiftModifier ) { QPointF move = snapToClosestAxis(event->point - m_dragStart); *m_handleDrag = m_dragStart + move; } else { *m_handleDrag = snapToGuide(event, QPointF(), false); } m_handleDrag->uncache(); m_handleCombine = 0; if (!(event->modifiers() & Qt::ShiftModifier)) { double minDist = 49.0; QPointF mousePos = m_canvas->viewConverter()->documentToView(event->point); Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_handles) { if (handle == m_handleDrag) continue; double dist = norm2(mousePos - m_canvas->viewConverter()->documentToView(*handle)); if (dist < minDist) { minDist = dist; m_handleCombine = handle; } } } m_canvas->updateCanvas(); } else if (m_assistantDrag) { QPointF newAdjustment = snapToGuide(event, QPointF(), false) - m_cursorStart; if (event->modifiers() == Qt::ShiftModifier ) { newAdjustment = snapToClosestAxis(newAdjustment); } Q_FOREACH (KisPaintingAssistantHandleSP handle, m_assistantDrag->handles()) { *handle += (newAdjustment - m_currentAdjustment); } if (m_assistantDrag->id()== "vanishing point"){ Q_FOREACH (KisPaintingAssistantHandleSP handle, m_assistantDrag->sideHandles()) { *handle += (newAdjustment - m_currentAdjustment); } } m_currentAdjustment = newAdjustment; m_canvas->updateCanvas(); } else { event->ignore(); } bool wasHiglightedNode = m_higlightedNode != 0; QPointF mousep = m_canvas->viewConverter()->documentToView(event->point); QList pAssistant= m_canvas->paintingAssistantsDecoration()->assistants(); Q_FOREACH (KisPaintingAssistantSP assistant, pAssistant) { if(assistant->id() == "perspective") { if ((m_higlightedNode = nodeNearPoint(assistant, mousep))) { if (m_higlightedNode == m_selectedNode1 || m_higlightedNode == m_selectedNode2) { m_higlightedNode = 0; } else { m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas break; } } } //this following bit sets the translations for the vanishing-point handles. if(m_handleDrag && assistant->id() == "vanishing point" && assistant->sideHandles().size()==4) { //for inner handles, the outer handle gets translated. if (m_handleDrag == assistant->sideHandles()[0]){ QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[0]); qreal length = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]).length(); if (length<2.0){length=2.0;} length +=perspectiveline.length(); perspectiveline.setLength(length); *assistant->sideHandles()[1] = perspectiveline.p2(); } else if (m_handleDrag == assistant->sideHandles()[2]){ QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]); qreal length = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length(); if (length<2.0){length=2.0;} length +=perspectiveline.length(); perspectiveline.setLength(length); *assistant->sideHandles()[3] = perspectiveline.p2(); } //for outer handles, only the vanishing point is translated, but only if there's an intersection. else if (m_handleDrag == assistant->sideHandles()[1]|| m_handleDrag == assistant->sideHandles()[3]){ QPointF vanishingpoint(0,0); QLineF perspectiveline = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]); QLineF perspectiveline2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]); if (QLineF(perspectiveline2).intersect(QLineF(perspectiveline), &vanishingpoint) != QLineF::NoIntersection){ *assistant->handles()[0] = vanishingpoint;} }//and for the vanishing point itself, only the outer handles get translated. else if (m_handleDrag == assistant->handles()[0]){ QLineF perspectiveline = QLineF(*assistant->handles()[0], *assistant->sideHandles()[0]); QLineF perspectiveline2 = QLineF(*assistant->handles()[0], *assistant->sideHandles()[2]); qreal length = QLineF(*assistant->sideHandles()[0], *assistant->sideHandles()[1]).length(); qreal length2 = QLineF(*assistant->sideHandles()[2], *assistant->sideHandles()[3]).length(); if (length<2.0){length=2.0;} if (length2<2.0){length2=2.0;} length +=perspectiveline.length(); length2 +=perspectiveline2.length(); perspectiveline.setLength(length); perspectiveline2.setLength(length2); *assistant->sideHandles()[1] = perspectiveline.p2(); *assistant->sideHandles()[3] = perspectiveline2.p2(); } } } if (wasHiglightedNode && !m_higlightedNode) { m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas } } void KisRulerAssistantTool::endPrimaryAction(KoPointerEvent *event) { setMode(KisTool::HOVER_MODE); if (m_handleDrag) { if (!(event->modifiers() & Qt::ShiftModifier) && m_handleCombine) { m_handleCombine->mergeWith(m_handleDrag); m_handleCombine->uncache(); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); } m_handleDrag = m_handleCombine = 0; m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas } else if (m_assistantDrag) { m_assistantDrag.clear(); m_canvas->updateCanvas(); // TODO update only the relevant part of the canvas } else if(m_internalMode == MODE_DRAGGING_TRANSLATING_TWONODES) { addAssistant(); m_internalMode = MODE_CREATION; m_canvas->updateCanvas(); } else { event->ignore(); } } void KisRulerAssistantTool::addAssistant() { m_canvas->paintingAssistantsDecoration()->addAssistant(m_newAssistant); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); KisAbstractPerspectiveGrid* grid = dynamic_cast(m_newAssistant.data()); if (grid) { m_canvas->viewManager()->resourceProvider()->addPerspectiveGrid(grid); } m_newAssistant.clear(); } void KisRulerAssistantTool::removeAssistant(KisPaintingAssistantSP assistant) { KisAbstractPerspectiveGrid* grid = dynamic_cast(assistant.data()); if (grid) { m_canvas->viewManager()->resourceProvider()->removePerspectiveGrid(grid); } m_canvas->paintingAssistantsDecoration()->removeAssistant(assistant); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); } void KisRulerAssistantTool::snappingOn(KisPaintingAssistantSP assistant) { assistant->setSnapping(true); } void KisRulerAssistantTool::snappingOff(KisPaintingAssistantSP assistant) { assistant->setSnapping(false); } void KisRulerAssistantTool::outlineOn(KisPaintingAssistantSP assistant) { assistant->setOutline(true); } void KisRulerAssistantTool::outlineOff(KisPaintingAssistantSP assistant) { assistant->setOutline(false); } #include QPointF KisRulerAssistantTool::snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!m_canvas->currentImage()) return e->point; KoSnapGuide *snapGuide = m_canvas->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); //return m_canvas->currentImage()->documentToPixel(pos); return pos; } QPointF KisRulerAssistantTool::snapToGuide(const QPointF& pt, const QPointF &offset) { if (!m_canvas) return pt; KoSnapGuide *snapGuide = m_canvas->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return pos; } void KisRulerAssistantTool::mouseMoveEvent(KoPointerEvent *event) { if (m_newAssistant && m_internalMode == MODE_CREATION) { *m_newAssistant->handles().back() = event->point; m_canvas->updateCanvas(); } else if (m_newAssistant && m_internalMode == MODE_DRAGGING_TRANSLATING_TWONODES) { QPointF translate = event->point - m_dragEnd;; m_dragEnd = event->point; m_selectedNode1.data()->operator =(QPointF(m_selectedNode1.data()->x(),m_selectedNode1.data()->y()) + translate); m_selectedNode2.data()->operator = (QPointF(m_selectedNode2.data()->x(),m_selectedNode2.data()->y()) + translate); m_canvas->updateCanvas(); } } void KisRulerAssistantTool::paint(QPainter& _gc, const KoViewConverter &_converter) { QPixmap iconDelete = KisIconUtils::loadIcon("dialog-cancel").pixmap(16, 16); QPixmap iconSnapOn = KisIconUtils::loadIcon("visible").pixmap(16, 16); QPixmap iconSnapOff = KisIconUtils::loadIcon("novisible").pixmap(16, 16); QPixmap iconMove = KisIconUtils::loadIcon("transform-move").pixmap(32, 32); QColor handlesColor(0, 0, 0, 125); if (m_newAssistant) { m_newAssistant->drawAssistant(_gc, QRectF(QPointF(0, 0), QSizeF(m_canvas->image()->size())), m_canvas->coordinatesConverter(), false,m_canvas, true, false); Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_newAssistant->handles()) { QPainterPath path; path.addEllipse(QRectF(_converter.documentToView(*handle) - QPointF(6, 6), QSizeF(12, 12))); KisPaintingAssistant::drawPath(_gc, path); } } // TODO: too many Q_FOREACH loops going through all assistants. Condense this to one to be a little more performant // Draw corner and middle perspective nodes Q_FOREACH (KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_handles) { QRectF ellipse(_converter.documentToView(*handle) - QPointF(6, 6), QSizeF(12, 12)); // render handles when they are being dragged and moved if (handle == m_handleDrag || handle == m_handleCombine) { _gc.save(); _gc.setPen(Qt::transparent); _gc.setBrush(handlesColor); _gc.drawEllipse(ellipse); _gc.restore(); } if ( assistant->id() =="vanishing point") { if (assistant->handles().at(0) == handle ) { // vanishing point handle ellipse = QRectF(_converter.documentToView(*handle) - QPointF(10, 10), QSizeF(20, 20)); // TODO: change this to be smaller, but fill in with a color } //TODO: render outside handles a little bigger than rotation anchor handles } QPainterPath path; path.addEllipse(ellipse); KisPaintingAssistant::drawPath(_gc, path); } } Q_FOREACH (KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { // Draw middle perspective handles if(assistant->id()=="perspective") { assistant->findHandleLocation(); QPointF topMiddle, bottomMiddle, rightMiddle, leftMiddle; topMiddle = (_converter.documentToView(*assistant->topLeft()) + _converter.documentToView(*assistant->topRight()))*0.5; bottomMiddle = (_converter.documentToView(*assistant->bottomLeft()) + _converter.documentToView(*assistant->bottomRight()))*0.5; rightMiddle = (_converter.documentToView(*assistant->topRight()) + _converter.documentToView(*assistant->bottomRight()))*0.5; leftMiddle = (_converter.documentToView(*assistant->topLeft()) + _converter.documentToView(*assistant->bottomLeft()))*0.5; QPainterPath path; path.addEllipse(QRectF(leftMiddle-QPointF(6,6),QSizeF(12,12))); path.addEllipse(QRectF(topMiddle-QPointF(6,6),QSizeF(12,12))); path.addEllipse(QRectF(rightMiddle-QPointF(6,6),QSizeF(12,12))); path.addEllipse(QRectF(bottomMiddle-QPointF(6,6),QSizeF(12,12))); KisPaintingAssistant::drawPath(_gc, path); } if(assistant->id()=="vanishing point") { if (assistant->sideHandles().size() == 4) { // Draw the line QPointF p0 = _converter.documentToView(*assistant->handles()[0]); QPointF p1 = _converter.documentToView(*assistant->sideHandles()[0]); QPointF p2 = _converter.documentToView(*assistant->sideHandles()[1]); QPointF p3 = _converter.documentToView(*assistant->sideHandles()[2]); QPointF p4 = _converter.documentToView(*assistant->sideHandles()[3]); _gc.setPen(QColor(0, 0, 0, 75)); // Draw control lines QPen penStyle(QColor(120, 120, 120, 60), 2.0, Qt::DashDotDotLine); _gc.setPen(penStyle); _gc.drawLine(p0, p1); _gc.drawLine(p0, p3); _gc.drawLine(p1, p2); _gc.drawLine(p3, p4); } } } // Draw the assistant widget Q_FOREACH (const KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { // We are going to put all of the assistant actions below the bounds of the assistant // so they are out of the way // assistant->buttonPosition() gets the center X/Y position point QPointF actionsPosition = m_canvas->viewConverter()->documentToView(assistant->buttonPosition()); QPointF iconDeletePosition(actionsPosition + QPointF(78, m_assistantHelperYOffset + 7)); QPointF iconSnapPosition(actionsPosition + QPointF(54, m_assistantHelperYOffset + 7)); QPointF iconMovePosition(actionsPosition + QPointF(15, m_assistantHelperYOffset )); // Background container for helpers QBrush backgroundColor = m_canvas->viewManager()->mainWindow()->palette().window(); QPointF actionsBGRectangle(actionsPosition + QPointF(25, m_assistantHelperYOffset)); _gc.setRenderHint(QPainter::Antialiasing); QPainterPath bgPath; bgPath.addRoundedRect(QRectF(actionsBGRectangle.x(), actionsBGRectangle.y(), 80, 30), 6, 6); QPen stroke(QColor(60, 60, 60, 80), 2); _gc.setPen(stroke); _gc.fillPath(bgPath, backgroundColor); _gc.drawPath(bgPath); QPainterPath movePath; // render circle behind by move helper _gc.setPen(stroke); movePath.addEllipse(iconMovePosition.x()-5, iconMovePosition.y()-5, 40, 40);// background behind icon _gc.fillPath(movePath, backgroundColor); _gc.drawPath(movePath); // Preview/Snap Tool helper _gc.drawPixmap(iconDeletePosition, iconDelete); if (assistant->snapping()==true) { _gc.drawPixmap(iconSnapPosition, iconSnapOn); } else { _gc.drawPixmap(iconSnapPosition, iconSnapOff); } // Move Assistant Tool helper _gc.drawPixmap(iconMovePosition, iconMove); } } void KisRulerAssistantTool::removeAllAssistants() { m_canvas->viewManager()->resourceProvider()->clearPerspectiveGrids(); m_canvas->paintingAssistantsDecoration()->removeAll(); m_handles = m_canvas->paintingAssistantsDecoration()->handles(); m_canvas->updateCanvas(); } void KisRulerAssistantTool::loadAssistants() { KoFileDialog dialog(m_canvas->viewManager()->mainWindow(), KoFileDialog::OpenFile, "OpenAssistant"); dialog.setCaption(i18n("Select an Assistant")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(QStringList() << "application/x-krita-assistant", "application/x-krita-assistant"); QString filename = dialog.filename(); if (filename.isEmpty()) return; if (!QFileInfo(filename).exists()) return; QFile file(filename); file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); QXmlStreamReader xml(data); QMap handleMap; KisPaintingAssistantSP assistant; bool errors = false; while (!xml.atEnd()) { switch (xml.readNext()) { case QXmlStreamReader::StartElement: if (xml.name() == "handle") { if (assistant && !xml.attributes().value("ref").isEmpty()) { KisPaintingAssistantHandleSP handle = handleMap.value(xml.attributes().value("ref").toString().toInt()); if (handle) { assistant->addHandle(handle); } else { errors = true; } } else { QString strId = xml.attributes().value("id").toString(), strX = xml.attributes().value("x").toString(), strY = xml.attributes().value("y").toString(); if (!strId.isEmpty() && !strX.isEmpty() && !strY.isEmpty()) { int id = strId.toInt(); double x = strX.toDouble(), y = strY.toDouble(); if (!handleMap.contains(id)) { handleMap.insert(id, new KisPaintingAssistantHandle(x, y)); } else { errors = true; } } else { errors = true; } } } else if (xml.name() == "assistant") { const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(xml.attributes().value("type").toString()); if (factory) { if (assistant) { errors = true; assistant.clear(); } assistant = toQShared(factory->createPaintingAssistant()); } else { errors = true; } } break; case QXmlStreamReader::EndElement: if (xml.name() == "assistant") { if (assistant) { if (assistant->handles().size() == assistant->numHandles()) { if (assistant->id() == "vanishing point"){ //ideally we'd save and load side-handles as well, but this is all I've got// QPointF pos = *assistant->handles()[0]; assistant->addSideHandle(new KisPaintingAssistantHandle(pos+QPointF(-70,0))); assistant->addSideHandle(new KisPaintingAssistantHandle(pos+QPointF(-140,0))); assistant->addSideHandle(new KisPaintingAssistantHandle(pos+QPointF(70,0))); assistant->addSideHandle(new KisPaintingAssistantHandle(pos+QPointF(140,0))); } m_canvas->paintingAssistantsDecoration()->addAssistant(assistant); KisAbstractPerspectiveGrid* grid = dynamic_cast(assistant.data()); if (grid) { m_canvas->viewManager()->resourceProvider()->addPerspectiveGrid(grid); } } else { errors = true; } assistant.clear(); } } break; default: break; } } if (assistant) { errors = true; assistant.clear(); } if (xml.hasError()) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), xml.errorString()); } if (errors) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Errors were encountered. Not all assistants were successfully loaded.")); } m_handles = m_canvas->paintingAssistantsDecoration()->handles(); m_canvas->updateCanvas(); } void KisRulerAssistantTool::saveAssistants() { if (m_handles.isEmpty()) return; QByteArray data; QXmlStreamWriter xml(&data); xml.writeStartDocument(); xml.writeStartElement("paintingassistant"); xml.writeStartElement("handles"); QMap handleMap; Q_FOREACH (const KisPaintingAssistantHandleSP handle, m_handles) { int id = handleMap.size(); handleMap.insert(handle, id); xml.writeStartElement("handle"); //xml.writeAttribute("type", handle->handleType()); xml.writeAttribute("id", QString::number(id)); xml.writeAttribute("x", QString::number(double(handle->x()), 'f', 3)); xml.writeAttribute("y", QString::number(double(handle->y()), 'f', 3)); xml.writeEndElement(); } xml.writeEndElement(); xml.writeStartElement("assistants"); Q_FOREACH (const KisPaintingAssistantSP assistant, m_canvas->paintingAssistantsDecoration()->assistants()) { xml.writeStartElement("assistant"); xml.writeAttribute("type", assistant->id()); xml.writeStartElement("handles"); Q_FOREACH (const KisPaintingAssistantHandleSP handle, assistant->handles()) { xml.writeStartElement("handle"); xml.writeAttribute("ref", QString::number(handleMap.value(handle))); xml.writeEndElement(); } xml.writeEndElement(); xml.writeEndElement(); } xml.writeEndElement(); xml.writeEndElement(); xml.writeEndDocument(); KoFileDialog dialog(m_canvas->viewManager()->mainWindow(), KoFileDialog::SaveFile, "OpenAssistant"); dialog.setCaption(i18n("Save Assistant")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(QStringList() << "application/x-krita-assistant", "application/x-krita-assistant"); QString filename = dialog.filename(); if (filename.isEmpty()) return; QFile file(filename); file.open(QIODevice::WriteOnly); file.write(data); } QWidget *KisRulerAssistantTool::createOptionWidget() { if (!m_optionsWidget) { m_optionsWidget = new QWidget; m_options.setupUi(m_optionsWidget); // See https://bugs.kde.org/show_bug.cgi?id=316896 QWidget *specialSpacer = new QWidget(m_optionsWidget); specialSpacer->setObjectName("SpecialSpacer"); specialSpacer->setFixedSize(0, 0); m_optionsWidget->layout()->addWidget(specialSpacer); m_options.loadButton->setIcon(KisIconUtils::loadIcon("document-open")); m_options.saveButton->setIcon(KisIconUtils::loadIcon("document-save")); m_options.deleteButton->setIcon(KisIconUtils::loadIcon("edit-delete")); QList assistants; Q_FOREACH (const QString& key, KisPaintingAssistantFactoryRegistry::instance()->keys()) { QString name = KisPaintingAssistantFactoryRegistry::instance()->get(key)->name(); assistants << KoID(key, name); } std::sort(assistants.begin(), assistants.end(), KoID::compareNames); Q_FOREACH(const KoID &id, assistants) { m_options.comboBox->addItem(id.name(), id.id()); } connect(m_options.saveButton, SIGNAL(clicked()), SLOT(saveAssistants())); connect(m_options.loadButton, SIGNAL(clicked()), SLOT(loadAssistants())); connect(m_options.deleteButton, SIGNAL(clicked()), SLOT(removeAllAssistants())); } return m_optionsWidget; } diff --git a/plugins/dockers/animation/kis_time_based_item_model.cpp b/plugins/dockers/animation/kis_time_based_item_model.cpp index 55b158cdee..b34e9dd393 100644 --- a/plugins/dockers/animation/kis_time_based_item_model.cpp +++ b/plugins/dockers/animation/kis_time_based_item_model.cpp @@ -1,436 +1,437 @@ /* * Copyright (c) 2016 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_time_based_item_model.h" #include #include #include "kis_animation_frame_cache.h" #include "kis_animation_player.h" #include "kis_signal_compressor_with_param.h" #include "kis_image.h" #include "kis_image_animation_interface.h" #include "kis_time_range.h" #include "kis_animation_utils.h" #include "kis_keyframe_channel.h" #include "kis_processing_applicator.h" #include "KisImageBarrierLockerWithFeedback.h" struct KisTimeBasedItemModel::Private { Private() : animationPlayer(0) , numFramesOverride(0) , activeFrameIndex(0) , scrubInProgress(false) , scrubStartFrame(-1) {} KisImageWSP image; KisAnimationFrameCacheWSP framesCache; QPointer animationPlayer; QVector cachedFrames; int numFramesOverride; int activeFrameIndex; bool scrubInProgress; int scrubStartFrame; QScopedPointer > scrubbingCompressor; int baseNumFrames() const { if (image.isNull()) return 0; KisImageAnimationInterface *i = image->animationInterface(); if (!i) return 1; return i->totalLength(); } int effectiveNumFrames() const { if (image.isNull()) return 0; return qMax(baseNumFrames(), numFramesOverride); } int framesPerSecond() { return image->animationInterface()->framerate(); } }; KisTimeBasedItemModel::KisTimeBasedItemModel(QObject *parent) : QAbstractTableModel(parent) , m_d(new Private()) { KisConfig cfg; using namespace std::placeholders; std::function callback( std::bind(&KisTimeBasedItemModel::slotInternalScrubPreviewRequested, this, _1)); m_d->scrubbingCompressor.reset( new KisSignalCompressorWithParam(cfg.scrubbingUpdatesDelay(), callback, KisSignalCompressor::FIRST_ACTIVE)); } KisTimeBasedItemModel::~KisTimeBasedItemModel() {} void KisTimeBasedItemModel::setImage(KisImageWSP image) { KisImageWSP oldImage = m_d->image; m_d->image = image; if (image) { KisImageAnimationInterface *ai = image->animationInterface(); slotCurrentTimeChanged(ai->currentUITime()); connect(ai, SIGNAL(sigFramerateChanged()), SLOT(slotFramerateChanged())); connect(ai, SIGNAL(sigUiTimeChanged(int)), SLOT(slotCurrentTimeChanged(int))); } if (image != oldImage) { - reset(); + beginResetModel(); + endResetModel(); } } void KisTimeBasedItemModel::setFrameCache(KisAnimationFrameCacheSP cache) { if (KisAnimationFrameCacheSP(m_d->framesCache) == cache) return; if (m_d->framesCache) { m_d->framesCache->disconnect(this); } m_d->framesCache = cache; if (m_d->framesCache) { connect(m_d->framesCache, SIGNAL(changed()), SLOT(slotCacheChanged())); } } void KisTimeBasedItemModel::setAnimationPlayer(KisAnimationPlayer *player) { if (m_d->animationPlayer == player) return; if (m_d->animationPlayer) { m_d->animationPlayer->disconnect(this); } m_d->animationPlayer = player; if (m_d->animationPlayer) { connect(m_d->animationPlayer, SIGNAL(sigPlaybackStopped()), SLOT(slotPlaybackStopped())); connect(m_d->animationPlayer, SIGNAL(sigFrameChanged()), SLOT(slotPlaybackFrameChanged())); } } void KisTimeBasedItemModel::setLastVisibleFrame(int time) { const int growThreshold = m_d->effectiveNumFrames() - 3; const int growValue = time + 8; const int shrinkThreshold = m_d->effectiveNumFrames() - 12; const int shrinkValue = qMax(m_d->baseNumFrames(), qMin(growValue, shrinkThreshold)); const bool canShrink = m_d->effectiveNumFrames() > m_d->baseNumFrames(); if (time >= growThreshold) { beginInsertColumns(QModelIndex(), m_d->effectiveNumFrames(), growValue - 1); m_d->numFramesOverride = growValue; endInsertColumns(); } else if (time < shrinkThreshold && canShrink) { beginRemoveColumns(QModelIndex(), shrinkValue, m_d->effectiveNumFrames() - 1); m_d->numFramesOverride = shrinkValue; endRemoveColumns(); } } int KisTimeBasedItemModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_d->effectiveNumFrames(); } QVariant KisTimeBasedItemModel::data(const QModelIndex &index, int role) const { switch (role) { case ActiveFrameRole: { return index.column() == m_d->activeFrameIndex; } } return QVariant(); } bool KisTimeBasedItemModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; switch (role) { case ActiveFrameRole: { setHeaderData(index.column(), Qt::Horizontal, value, role); break; } } return false; } QVariant KisTimeBasedItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { switch (role) { case ActiveFrameRole: return section == m_d->activeFrameIndex; case FrameCachedRole: return m_d->cachedFrames.size() > section ? m_d->cachedFrames[section] : false; case FramesPerSecondRole: return m_d->framesPerSecond(); } } return QVariant(); } bool KisTimeBasedItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if (orientation == Qt::Horizontal) { switch (role) { case ActiveFrameRole: if (value.toBool() && section != m_d->activeFrameIndex) { int prevFrame = m_d->activeFrameIndex; m_d->activeFrameIndex = section; scrubTo(m_d->activeFrameIndex, m_d->scrubInProgress); /** * Optimization Hack Alert: * * ideally, we should emit all four signals, but... The * point is this code is used in a tight loop during * playback, so it should run as fast as possible. To tell * the story short, commenting out these three lines makes * playback run 15% faster ;) */ if (m_d->scrubInProgress) { //emit dataChanged(this->index(0, prevFrame), this->index(rowCount() - 1, prevFrame)); emit dataChanged(this->index(0, m_d->activeFrameIndex), this->index(rowCount() - 1, m_d->activeFrameIndex)); //emit headerDataChanged (Qt::Horizontal, prevFrame, prevFrame); //emit headerDataChanged (Qt::Horizontal, m_d->activeFrameIndex, m_d->activeFrameIndex); } else { emit dataChanged(this->index(0, prevFrame), this->index(rowCount() - 1, prevFrame)); emit dataChanged(this->index(0, m_d->activeFrameIndex), this->index(rowCount() - 1, m_d->activeFrameIndex)); emit headerDataChanged (Qt::Horizontal, prevFrame, prevFrame); emit headerDataChanged (Qt::Horizontal, m_d->activeFrameIndex, m_d->activeFrameIndex); } } } } return false; } bool KisTimeBasedItemModel::removeFrames(const QModelIndexList &indexes) { KisAnimationUtils::FrameItemList frameItems; { KisImageBarrierLockerWithFeedback locker(m_d->image); Q_FOREACH (const QModelIndex &index, indexes) { int time = index.column(); Q_FOREACH(KisKeyframeChannel *channel, channelsAt(index)) { if (channel->keyframeAt(time)) { frameItems << KisAnimationUtils::FrameItem(channel->node(), channel->id(), index.column()); } } } } if (frameItems.isEmpty()) return false; KisAnimationUtils::removeKeyframes(m_d->image, frameItems); return true; } KUndo2Command* KisTimeBasedItemModel::createOffsetFramesCommand(QModelIndexList srcIndexes, const QPoint &offset, bool copyFrames, KUndo2Command *parentCommand) { if (srcIndexes.isEmpty()) return 0; if (offset.isNull()) return 0; KisAnimationUtils::sortPointsForSafeMove(&srcIndexes, offset); KisAnimationUtils::FrameItemList srcFrameItems; KisAnimationUtils::FrameItemList dstFrameItems; Q_FOREACH (const QModelIndex &srcIndex, srcIndexes) { QModelIndex dstIndex = index( srcIndex.row() + offset.y(), srcIndex.column() + offset.x()); KisNodeSP srcNode = nodeAt(srcIndex); KisNodeSP dstNode = nodeAt(dstIndex); if (!srcNode || !dstNode) { return 0; } Q_FOREACH(KisKeyframeChannel *channel, channelsAt(srcIndex)) { if (channel->keyframeAt(srcIndex.column())) { srcFrameItems << KisAnimationUtils::FrameItem(srcNode, channel->id(), srcIndex.column()); dstFrameItems << KisAnimationUtils::FrameItem(dstNode, channel->id(), dstIndex.column()); } } } KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(srcFrameItems.size() == dstFrameItems.size(), 0); if (srcFrameItems.isEmpty()) return 0; return KisAnimationUtils::createMoveKeyframesCommand(srcFrameItems, dstFrameItems, copyFrames, parentCommand); } bool KisTimeBasedItemModel::offsetFrames(QModelIndexList srcIndexes, const QPoint &offset, bool copyFrames) { KUndo2Command *cmd = 0; { KisImageBarrierLockerWithFeedback locker(m_d->image); cmd = createOffsetFramesCommand(srcIndexes, offset, copyFrames); } if (cmd) { KisProcessingApplicator::runSingleCommandStroke(m_d->image, cmd, KisStrokeJobData::BARRIER); } return cmd; } void KisTimeBasedItemModel::slotInternalScrubPreviewRequested(int time) { if (m_d->animationPlayer && !m_d->animationPlayer->isPlaying()) { m_d->animationPlayer->displayFrame(time); } } void KisTimeBasedItemModel::setScrubState(bool active) { if (!m_d->scrubInProgress && active) { m_d->scrubStartFrame = m_d->activeFrameIndex; m_d->scrubInProgress = true; } if (m_d->scrubInProgress && !active) { m_d->scrubInProgress = false; if (m_d->scrubStartFrame >= 0 && m_d->scrubStartFrame != m_d->activeFrameIndex) { scrubTo(m_d->activeFrameIndex, false); } m_d->scrubStartFrame = -1; } } void KisTimeBasedItemModel::scrubTo(int time, bool preview) { if (m_d->animationPlayer && m_d->animationPlayer->isPlaying()) return; KIS_ASSERT_RECOVER_RETURN(m_d->image); if (preview) { if (m_d->animationPlayer) { m_d->scrubbingCompressor->start(time); } } else { m_d->image->animationInterface()->requestTimeSwitchWithUndo(time); } } void KisTimeBasedItemModel::slotFramerateChanged() { emit headerDataChanged(Qt::Horizontal, 0, columnCount() - 1); } void KisTimeBasedItemModel::slotCurrentTimeChanged(int time) { if (time != m_d->activeFrameIndex) { setHeaderData(time, Qt::Horizontal, true, ActiveFrameRole); } } void KisTimeBasedItemModel::slotCacheChanged() { const int numFrames = columnCount(); m_d->cachedFrames.resize(numFrames); for (int i = 0; i < numFrames; i++) { m_d->cachedFrames[i] = m_d->framesCache->frameStatus(i) == KisAnimationFrameCache::Cached; } emit headerDataChanged(Qt::Horizontal, 0, numFrames); } void KisTimeBasedItemModel::slotPlaybackFrameChanged() { if (!m_d->animationPlayer->isPlaying()) return; setData(index(0, m_d->animationPlayer->currentTime()), true, ActiveFrameRole); } void KisTimeBasedItemModel::slotPlaybackStopped() { setData(index(0, m_d->image->animationInterface()->currentUITime()), true, ActiveFrameRole); } void KisTimeBasedItemModel::setPlaybackRange(const KisTimeRange &range) { if (m_d->image.isNull()) return; KisImageAnimationInterface *i = m_d->image->animationInterface(); i->setPlaybackRange(range); } bool KisTimeBasedItemModel::isPlaybackActive() const { return m_d->animationPlayer && m_d->animationPlayer->isPlaying(); } int KisTimeBasedItemModel::currentTime() const { return m_d->image->animationInterface()->currentUITime(); } KisImageWSP KisTimeBasedItemModel::image() const { return m_d->image; } diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp index e42bb122f5..732d3a6ada 100644 --- a/plugins/dockers/animation/timeline_frames_model.cpp +++ b/plugins/dockers/animation/timeline_frames_model.cpp @@ -1,717 +1,718 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "timeline_frames_model.h" #include #include #include #include #include #include #include "kis_layer.h" #include "kis_config.h" #include "kis_global.h" #include "kis_debug.h" #include "kis_image.h" #include "kis_image_animation_interface.h" #include "kis_undo_adapter.h" #include "kis_node_dummies_graph.h" #include "kis_dummies_facade_base.h" #include "kis_signal_compressor.h" #include "kis_signal_compressor_with_param.h" #include "kis_keyframe_channel.h" #include "kundo2command.h" #include "kis_post_execution_undo_adapter.h" #include #include "kis_animation_utils.h" #include "timeline_color_scheme.h" #include "kis_node_model.h" #include "kis_projection_leaf.h" #include "kis_time_range.h" #include "kis_node_view_color_scheme.h" #include "krita_utils.h" #include struct TimelineFramesModel::Private { Private() : activeLayerIndex(0), dummiesFacade(0), needFinishInsertRows(false), needFinishRemoveRows(false), updateTimer(200, KisSignalCompressor::FIRST_INACTIVE), parentOfRemovedNode(0) {} int activeLayerIndex; QPointer dummiesFacade; KisImageWSP image; bool needFinishInsertRows; bool needFinishRemoveRows; QList updateQueue; KisSignalCompressor updateTimer; KisNodeDummy* parentOfRemovedNode; QScopedPointer converter; QScopedPointer nodeInterface; QPersistentModelIndex lastClickedIndex; QVariant layerName(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return QVariant(); return dummy->node()->name(); } bool layerEditable(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return true; return dummy->node()->visible() && !dummy->node()->userLocked(); } bool frameExists(int row, int column) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); return (primaryChannel && primaryChannel->keyframeAt(column)); } bool specialKeyframeExists(int row, int column) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; Q_FOREACH(KisKeyframeChannel *channel, dummy->node()->keyframeChannels()) { if (channel->id() != KisKeyframeChannel::Content.id() && channel->keyframeAt(column)) { return true; } } return false; } int frameColorLabel(int row, int column) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return -1; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); if (!primaryChannel) return -1; KisKeyframeSP frame = primaryChannel->keyframeAt(column); if (!frame) return -1; return frame->colorLabel(); } void setFrameColorLabel(int row, int column, int color) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); if (!primaryChannel) return; KisKeyframeSP frame = primaryChannel->keyframeAt(column); if (!frame) return; frame->setColorLabel(color); } int layerColorLabel(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return -1; return dummy->node()->colorLabelIndex(); } QVariant layerProperties(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return QVariant(); PropertyList props = dummy->node()->sectionModelProperties(); return QVariant::fromValue(props); } bool setLayerProperties(int row, PropertyList props) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisNodePropertyListCommand::setNodePropertiesNoUndo(dummy->node(), image, props); return true; } bool addKeyframe(int row, int column, bool copy) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisNodeSP node = dummy->node(); if (!KisAnimationUtils::supportsContentFrames(node)) return false; KisAnimationUtils::createKeyframeLazy(image, node, KisKeyframeChannel::Content.id(), column, copy); return true; } bool addNewLayer(int row) { Q_UNUSED(row); if (nodeInterface) { KisLayerSP layer = nodeInterface->addPaintLayer(); layer->setUseInTimeline(true); } return true; } bool removeLayer(int row) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; if (nodeInterface) { nodeInterface->removeNode(dummy->node()); } return true; } }; TimelineFramesModel::TimelineFramesModel(QObject *parent) : ModelWithExternalNotifications(parent), m_d(new Private) { connect(&m_d->updateTimer, SIGNAL(timeout()), SLOT(processUpdateQueue())); } TimelineFramesModel::~TimelineFramesModel() { } bool TimelineFramesModel::hasConnectionToCanvas() const { return m_d->dummiesFacade; } void TimelineFramesModel::setNodeManipulationInterface(NodeManipulationInterface *iface) { m_d->nodeInterface.reset(iface); } KisNodeSP TimelineFramesModel::nodeAt(QModelIndex index) const { /** * The dummy might not exist because the user could (quickly) change * active layer and the list of the nodes in m_d->converter will change. */ KisNodeDummy *dummy = m_d->converter->dummyFromRow(index.row()); return dummy ? dummy->node() : 0; } QMap TimelineFramesModel::channelsAt(QModelIndex index) const { KisNodeDummy *srcDummy = m_d->converter->dummyFromRow(index.row()); return srcDummy->node()->keyframeChannels(); } void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageSP image) { KisDummiesFacadeBase *oldDummiesFacade = m_d->dummiesFacade; if (m_d->dummiesFacade && m_d->image) { m_d->image->animationInterface()->disconnect(this); m_d->image->disconnect(this); m_d->dummiesFacade->disconnect(this); } m_d->image = image; KisTimeBasedItemModel::setImage(image); m_d->dummiesFacade = dummiesFacade; m_d->converter.reset(); if (m_d->dummiesFacade) { m_d->converter.reset(new TimelineNodeListKeeper(this, m_d->dummiesFacade)); connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)), SLOT(slotDummyChanged(KisNodeDummy*))); connect(m_d->image->animationInterface(), SIGNAL(sigFullClipRangeChanged()), SIGNAL(sigInfiniteTimelineUpdateNeeded())); connect(m_d->image->animationInterface(), SIGNAL(sigAudioChannelChanged()), SIGNAL(sigAudioChannelChanged())); connect(m_d->image->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SIGNAL(sigAudioChannelChanged())); } if (m_d->dummiesFacade != oldDummiesFacade) { - reset(); + beginResetModel(); + endResetModel(); } if (m_d->dummiesFacade) { emit sigInfiniteTimelineUpdateNeeded(); emit sigAudioChannelChanged(); } } void TimelineFramesModel::slotDummyChanged(KisNodeDummy *dummy) { if (!m_d->updateQueue.contains(dummy)) { m_d->updateQueue.append(dummy); } m_d->updateTimer.start(); } void TimelineFramesModel::processUpdateQueue() { Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) { int row = m_d->converter->rowForDummy(dummy); if (row >= 0) { emit headerDataChanged (Qt::Vertical, row, row); emit dataChanged(this->index(row, 0), this->index(row, columnCount() - 1)); } } m_d->updateQueue.clear(); } void TimelineFramesModel::slotCurrentNodeChanged(KisNodeSP node) { if (!node) { m_d->activeLayerIndex = -1; return; } KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node); KIS_ASSERT_RECOVER_RETURN(dummy); m_d->converter->updateActiveDummy(dummy); const int row = m_d->converter->rowForDummy(dummy); if (row < 0) { qWarning() << "WARNING: TimelineFramesModel::slotCurrentNodeChanged: node not found!"; } if (row >= 0 && m_d->activeLayerIndex != row) { setData(index(row, 0), true, ActiveLayerRole); } } int TimelineFramesModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); if(!m_d->dummiesFacade) return 0; return m_d->converter->rowCount(); } QVariant TimelineFramesModel::data(const QModelIndex &index, int role) const { if(!m_d->dummiesFacade) return QVariant(); switch (role) { case ActiveLayerRole: { return index.row() == m_d->activeLayerIndex; } case FrameEditableRole: { return m_d->layerEditable(index.row()); } case FrameExistsRole: { return m_d->frameExists(index.row(), index.column()); } case SpecialKeyframeExists: { return m_d->specialKeyframeExists(index.row(), index.column()); } case FrameColorLabelIndexRole: { int label = m_d->frameColorLabel(index.row(), index.column()); return label > 0 ? label : QVariant(); } case Qt::DisplayRole: { return m_d->layerName(index.row()); } case Qt::TextAlignmentRole: { return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); } case KoResourceModel::LargeThumbnailRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(index.row()); if (!dummy) { return QVariant(); } const int maxSize = 200; QSize size = dummy->node()->extent().size(); size.scale(maxSize, maxSize, Qt::KeepAspectRatio); if (size.width() == 0 || size.height() == 0) { // No thumbnail can be shown if there isn't width or height... return QVariant(); } QImage image(dummy->node()->createThumbnailForFrame(size.width(), size.height(), index.column())); return image; } } return ModelWithExternalNotifications::data(index, role); } bool TimelineFramesModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || !m_d->dummiesFacade) return false; switch (role) { case ActiveLayerRole: { if (value.toBool() && index.row() != m_d->activeLayerIndex) { int prevLayer = m_d->activeLayerIndex; m_d->activeLayerIndex = index.row(); emit dataChanged(this->index(prevLayer, 0), this->index(prevLayer, columnCount() - 1)); emit dataChanged(this->index(m_d->activeLayerIndex, 0), this->index(m_d->activeLayerIndex, columnCount() - 1)); emit headerDataChanged(Qt::Vertical, prevLayer, prevLayer); emit headerDataChanged(Qt::Vertical, m_d->activeLayerIndex, m_d->activeLayerIndex); KisNodeDummy *dummy = m_d->converter->dummyFromRow(m_d->activeLayerIndex); KIS_ASSERT_RECOVER(dummy) { return true; } emit requestCurrentNodeChanged(dummy->node()); emit sigEnsureRowVisible(m_d->activeLayerIndex); } break; } case FrameColorLabelIndexRole: { m_d->setFrameColorLabel(index.row(), index.column(), value.toInt()); } break; } return ModelWithExternalNotifications::setData(index, value, role); } QVariant TimelineFramesModel::headerData(int section, Qt::Orientation orientation, int role) const { if(!m_d->dummiesFacade) return QVariant(); if (orientation == Qt::Vertical) { switch (role) { case ActiveLayerRole: return section == m_d->activeLayerIndex; case Qt::DisplayRole: { QVariant value = headerData(section, orientation, Qt::ToolTipRole); if (!value.isValid()) return value; QString name = value.toString(); const int maxNameSize = 13; if (name.size() > maxNameSize) { name = QString("%1...").arg(name.left(maxNameSize)); } return name; } case Qt::TextColorRole: { // WARNING: this role doesn't work for header views! Use // bold font to show isolated mode instead! return QVariant(); } case Qt::FontRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return QVariant(); KisNodeSP node = dummy->node(); QFont baseFont; if (node->projectionLeaf()->isDroppedMask()) { baseFont.setStrikeOut(true); } else if (m_d->image && m_d->image->isolatedModeRoot() && KisNodeModel::belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade)) { baseFont.setBold(true); } return baseFont; } case Qt::ToolTipRole: { return m_d->layerName(section); } case TimelinePropertiesRole: { return QVariant::fromValue(m_d->layerProperties(section)); } case OtherLayersRole: { TimelineNodeListKeeper::OtherLayersList list = m_d->converter->otherLayersList(); return QVariant::fromValue(list); } case LayerUsedInTimelineRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return QVariant(); return dummy->node()->useInTimeline(); } case Qt::BackgroundRole: { int label = m_d->layerColorLabel(section); if (label > 0) { KisNodeViewColorScheme scm; QColor color = scm.colorLabel(label); QPalette pal = qApp->palette(); color = KritaUtils::blendColors(color, pal.color(QPalette::Button), 0.3); return QBrush(color); } else { return QVariant(); } } } } return ModelWithExternalNotifications::headerData(section, orientation, role); } bool TimelineFramesModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if (!m_d->dummiesFacade) return false; if (orientation == Qt::Vertical) { switch (role) { case ActiveLayerRole: { setData(index(section, 0), value, role); break; } case TimelinePropertiesRole: { TimelineFramesModel::PropertyList props = value.value(); int result = m_d->setLayerProperties(section, props); emit headerDataChanged (Qt::Vertical, section, section); return result; } case LayerUsedInTimelineRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return false; dummy->node()->setUseInTimeline(value.toBool()); return true; } } } return ModelWithExternalNotifications::setHeaderData(section, orientation, value, role); } Qt::DropActions TimelineFramesModel::supportedDragActions() const { return Qt::MoveAction | Qt::CopyAction; } Qt::DropActions TimelineFramesModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } QStringList TimelineFramesModel::mimeTypes() const { QStringList types; types << QLatin1String("application/x-krita-frame"); return types; } void TimelineFramesModel::setLastClickedIndex(const QModelIndex &index) { m_d->lastClickedIndex = index; } QMimeData* TimelineFramesModel::mimeData(const QModelIndexList &indexes) const { QMimeData *data = new QMimeData(); QByteArray encoded; QDataStream stream(&encoded, QIODevice::WriteOnly); const int baseRow = m_d->lastClickedIndex.row(); const int baseColumn = m_d->lastClickedIndex.column(); stream << indexes.size(); stream << baseRow << baseColumn; Q_FOREACH (const QModelIndex &index, indexes) { stream << index.row() - baseRow << index.column() - baseColumn; } data->setData("application/x-krita-frame", encoded); return data; } inline void decodeBaseIndex(QByteArray *encoded, int *row, int *col) { int size_UNUSED = 0; QDataStream stream(encoded, QIODevice::ReadOnly); stream >> size_UNUSED >> *row >> *col; } bool TimelineFramesModel::canDropFrameData(const QMimeData */*data*/, const QModelIndex &index) { if (!index.isValid()) return false; /** * Now we support D&D around any layer, so just return 'true' all * the time. */ return true; } bool TimelineFramesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(column); bool result = false; if ((action != Qt::MoveAction && action != Qt::CopyAction) || !parent.isValid()) return result; const bool copyFrames = action == Qt::CopyAction; QByteArray encoded = data->data("application/x-krita-frame"); QDataStream stream(&encoded, QIODevice::ReadOnly); int size, baseRow, baseColumn; stream >> size >> baseRow >> baseColumn; QModelIndexList srcIndexes; for (int i = 0; i < size; i++) { int relRow, relColumn; stream >> relRow >> relColumn; int srcRow = baseRow + relRow; int srcColumn = baseColumn + relColumn; srcIndexes << index(srcRow, srcColumn); } const QPoint offset(parent.column() - baseColumn, parent.row() - baseRow); return offsetFrames(srcIndexes, offset, copyFrames); } Qt::ItemFlags TimelineFramesModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = ModelWithExternalNotifications::flags(index); if (!index.isValid()) return flags; if (m_d->frameExists(index.row(), index.column()) || m_d->specialKeyframeExists(index.row(), index.column())) { if (data(index, FrameEditableRole).toBool()) { flags |= Qt::ItemIsDragEnabled; } } /** * Basically we should forbid overrides only if we D&D a single frame * and allow it when we D&D multiple frames. But we cannot distinguish * it here... So allow all the time. */ flags |= Qt::ItemIsDropEnabled; return flags; } bool TimelineFramesModel::insertRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); KIS_ASSERT_RECOVER(count == 1) { return false; } if (row < 0 || row > rowCount()) return false; bool result = m_d->addNewLayer(row); return result; } bool TimelineFramesModel::removeRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); KIS_ASSERT_RECOVER(count == 1) { return false; } if (row < 0 || row >= rowCount()) return false; bool result = m_d->removeLayer(row); return result; } bool TimelineFramesModel::insertOtherLayer(int index, int dstRow) { Q_UNUSED(dstRow); TimelineNodeListKeeper::OtherLayersList list = m_d->converter->otherLayersList(); if (index < 0 || index >= list.size()) return false; list[index].dummy->node()->setUseInTimeline(true); dstRow = m_d->converter->rowForDummy(list[index].dummy); setData(this->index(dstRow, 0), true, ActiveLayerRole); return true; } int TimelineFramesModel::activeLayerRow() const { return m_d->activeLayerIndex; } bool TimelineFramesModel::createFrame(const QModelIndex &dstIndex) { if (!dstIndex.isValid()) return false; return m_d->addKeyframe(dstIndex.row(), dstIndex.column(), false); } bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex) { if (!dstIndex.isValid()) return false; return m_d->addKeyframe(dstIndex.row(), dstIndex.column(), true); } QString TimelineFramesModel::audioChannelFileName() const { return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString(); } void TimelineFramesModel::setAudioChannelFileName(const QString &fileName) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioChannelFileName(fileName); } bool TimelineFramesModel::isAudioMuted() const { return m_d->image ? m_d->image->animationInterface()->isAudioMuted() : false; } void TimelineFramesModel::setAudioMuted(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioMuted(value); } qreal TimelineFramesModel::audioVolume() const { return m_d->image ? m_d->image->animationInterface()->audioVolume() : 0.5; } void TimelineFramesModel::setAudioVolume(qreal value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioVolume(value); } diff --git a/plugins/dockers/animation/timeline_frames_view.cpp b/plugins/dockers/animation/timeline_frames_view.cpp index 3f9ee73af7..a5759a4664 100644 --- a/plugins/dockers/animation/timeline_frames_view.cpp +++ b/plugins/dockers/animation/timeline_frames_view.cpp @@ -1,1098 +1,1098 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "timeline_frames_view.h" #include "timeline_frames_model.h" #include "timeline_ruler_header.h" #include "timeline_layers_header.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "timeline_frames_item_delegate.h" #include "kis_zoom_button.h" #include "kis_icon_utils.h" #include "kis_animation_utils.h" #include "kis_custom_modifiers_catcher.h" #include "kis_action.h" #include "kis_signal_compressor.h" #include "kis_time_range.h" #include "kis_color_label_selector_widget.h" #include "kis_slider_spin_box.h" #include #include #include -#include +#include #include #include "config-qtmultimedia.h" typedef QPair QItemViewPaintPair; typedef QList QItemViewPaintPairs; struct TimelineFramesView::Private { Private(TimelineFramesView *_q) : q(_q), fps(1), zoomStillPointIndex(-1), zoomStillPointOriginalOffset(0), dragInProgress(false), dragWasSuccessful(false), modifiersCatcher(0), selectionChangedCompressor(300, KisSignalCompressor::FIRST_INACTIVE) {} TimelineFramesView *q; TimelineFramesModel *model; TimelineRulerHeader *horizontalRuler; TimelineLayersHeader *layersHeader; int fps; int zoomStillPointIndex; int zoomStillPointOriginalOffset; QPoint initialDragPanValue; QPoint initialDragPanPos; QToolButton *addLayersButton; KisAction *showHideLayerAction; QToolButton *audioOptionsButton; KisColorLabelSelectorWidget *colorSelector; QWidgetAction *colorSelectorAction; KisColorLabelSelectorWidget *multiframeColorSelector; QWidgetAction *multiframeColorSelectorAction; QMenu *audioOptionsMenu; QAction *openAudioAction; QAction *audioMuteAction; KisSliderSpinBox *volumeSlider; QMenu *layerEditingMenu; QMenu *existingLayersMenu; QMenu *frameCreationMenu; QMenu *frameEditingMenu; QMenu *multipleFrameEditingMenu; QMap globalActions; KisZoomButton *zoomDragButton; bool dragInProgress; bool dragWasSuccessful; KisCustomModifiersCatcher *modifiersCatcher; QPoint lastPressedPosition; Qt::KeyboardModifiers lastPressedModifier; KisSignalCompressor selectionChangedCompressor; QStyleOptionViewItem viewOptionsV4() const; QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const; KoIconToolTip tip; }; TimelineFramesView::TimelineFramesView(QWidget *parent) : QTableView(parent), m_d(new Private(this)) { m_d->modifiersCatcher = new KisCustomModifiersCatcher(this); m_d->modifiersCatcher->addModifier("pan-zoom", Qt::Key_Space); m_d->modifiersCatcher->addModifier("offset-frame", Qt::Key_Alt); setCornerButtonEnabled(false); setSelectionBehavior(QAbstractItemView::SelectItems); setSelectionMode(QAbstractItemView::ExtendedSelection); setItemDelegate(new TimelineFramesItemDelegate(this)); setDragEnabled(true); setDragDropMode(QAbstractItemView::DragDrop); setAcceptDrops(true); setDropIndicatorShown(true); setDefaultDropAction(Qt::MoveAction); m_d->horizontalRuler = new TimelineRulerHeader(this); this->setHorizontalHeader(m_d->horizontalRuler); m_d->layersHeader = new TimelineLayersHeader(this); m_d->layersHeader->setSectionResizeMode(QHeaderView::Fixed); m_d->layersHeader->setDefaultSectionSize(24); m_d->layersHeader->setMinimumWidth(60); m_d->layersHeader->setHighlightSections(true); this->setVerticalHeader(m_d->layersHeader); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slotUpdateInfiniteFramesCount())); connect(horizontalScrollBar(), SIGNAL(sliderReleased()), SLOT(slotUpdateInfiniteFramesCount())); /********** New Layer Menu ***********************************************************/ m_d->addLayersButton = new QToolButton(this); m_d->addLayersButton->setAutoRaise(true); m_d->addLayersButton->setIcon(KisIconUtils::loadIcon("addlayer")); m_d->addLayersButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_d->addLayersButton->setPopupMode(QToolButton::InstantPopup); m_d->layerEditingMenu = new QMenu(this); m_d->layerEditingMenu->addAction(KisAnimationUtils::newLayerActionName, this, SLOT(slotAddNewLayer())); m_d->existingLayersMenu = m_d->layerEditingMenu->addMenu(KisAnimationUtils::addExistingLayerActionName); m_d->layerEditingMenu->addSeparator(); m_d->layerEditingMenu->addAction(KisAnimationUtils::removeLayerActionName, this, SLOT(slotRemoveLayer())); connect(m_d->existingLayersMenu, SIGNAL(aboutToShow()), SLOT(slotUpdateLayersMenu())); connect(m_d->existingLayersMenu, SIGNAL(triggered(QAction*)), SLOT(slotAddExistingLayer(QAction*))); connect(m_d->layersHeader, SIGNAL(sigRequestContextMenu(const QPoint&)), SLOT(slotLayerContextMenuRequested(const QPoint&))); m_d->addLayersButton->setMenu(m_d->layerEditingMenu); /********** Audio Channel Menu *******************************************************/ m_d->audioOptionsButton = new QToolButton(this); m_d->audioOptionsButton->setAutoRaise(true); m_d->audioOptionsButton->setIcon(KisIconUtils::loadIcon("audio-none")); m_d->audioOptionsButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_d->audioOptionsButton->setPopupMode(QToolButton::InstantPopup); m_d->audioOptionsMenu = new QMenu(this); #ifndef HAVE_QT_MULTIMEDIA m_d->audioOptionsMenu->addSection(i18nc("@item:inmenu", "Audio playback is not supported in this build!")); #endif m_d->openAudioAction= new QAction("XXX", this); connect(m_d->openAudioAction, SIGNAL(triggered()), this, SLOT(slotSelectAudioChannelFile())); m_d->audioOptionsMenu->addAction(m_d->openAudioAction); m_d->audioMuteAction = new QAction(i18nc("@item:inmenu", "Mute"), this); m_d->audioMuteAction->setCheckable(true); connect(m_d->audioMuteAction, SIGNAL(triggered(bool)), SLOT(slotAudioChannelMute(bool))); m_d->audioOptionsMenu->addAction(m_d->audioMuteAction); m_d->audioOptionsMenu->addAction(i18nc("@item:inmenu", "Remove audio"), this, SLOT(slotAudioChannelRemove())); m_d->audioOptionsMenu->addSeparator(); m_d->volumeSlider = new KisSliderSpinBox(this); m_d->volumeSlider->setRange(0, 100); m_d->volumeSlider->setSuffix("%"); m_d->volumeSlider->setPrefix(i18nc("@item:inmenu, slider", "Volume:")); m_d->volumeSlider->setSingleStep(1); m_d->volumeSlider->setPageStep(10); m_d->volumeSlider->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); connect(m_d->volumeSlider, SIGNAL(valueChanged(int)), SLOT(slotAudioVolumeChanged(int))); QWidgetAction *volumeAction = new QWidgetAction(m_d->audioOptionsMenu); volumeAction->setDefaultWidget(m_d->volumeSlider); m_d->audioOptionsMenu->addAction(volumeAction); m_d->audioOptionsButton->setMenu(m_d->audioOptionsMenu); /********** Frame Editing Context Menu ***********************************************/ m_d->frameCreationMenu = new QMenu(this); m_d->frameCreationMenu->addAction(KisAnimationUtils::addFrameActionName, this, SLOT(slotNewFrame())); m_d->frameCreationMenu->addAction(KisAnimationUtils::duplicateFrameActionName, this, SLOT(slotCopyFrame())); m_d->colorSelector = new KisColorLabelSelectorWidget(this); m_d->colorSelectorAction = new QWidgetAction(this); m_d->colorSelectorAction->setDefaultWidget(m_d->colorSelector); connect(m_d->colorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged); m_d->frameEditingMenu = new QMenu(this); m_d->frameEditingMenu->addAction(KisAnimationUtils::removeFrameActionName, this, SLOT(slotRemoveFrame())); m_d->frameEditingMenu->addAction(m_d->colorSelectorAction); m_d->multiframeColorSelector = new KisColorLabelSelectorWidget(this); m_d->multiframeColorSelectorAction = new QWidgetAction(this); m_d->multiframeColorSelectorAction->setDefaultWidget(m_d->multiframeColorSelector); connect(m_d->multiframeColorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged); m_d->multipleFrameEditingMenu = new QMenu(this); m_d->multipleFrameEditingMenu->addAction(KisAnimationUtils::removeFramesActionName, this, SLOT(slotRemoveFrame())); m_d->multipleFrameEditingMenu->addAction(m_d->multiframeColorSelectorAction); /********** Zoom Button **************************************************************/ m_d->zoomDragButton = new KisZoomButton(this); m_d->zoomDragButton->setAutoRaise(true); m_d->zoomDragButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal")); m_d->zoomDragButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_d->zoomDragButton->setToolTip(i18nc("@info:tooltip", "Zoom Timeline. Hold down and drag left or right.")); m_d->zoomDragButton->setPopupMode(QToolButton::InstantPopup); connect(m_d->zoomDragButton, SIGNAL(zoomLevelChanged(qreal)), SLOT(slotZoomButtonChanged(qreal))); connect(m_d->zoomDragButton, SIGNAL(zoomStarted(qreal)), SLOT(slotZoomButtonPressed(qreal))); setFramesPerSecond(12); setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); connect(&m_d->selectionChangedCompressor, SIGNAL(timeout()), SLOT(slotSelectionChanged())); } TimelineFramesView::~TimelineFramesView() { } QMap TimelineFramesView::globalActions() const { return m_d->globalActions; } void TimelineFramesView::setShowInTimeline(KisAction* action) { m_d->showHideLayerAction = action; m_d->layerEditingMenu->addAction(m_d->showHideLayerAction); } void resizeToMinimalSize(QAbstractButton *w, int minimalSize) { QSize buttonSize = w->sizeHint(); if (buttonSize.height() > minimalSize) { buttonSize = QSize(minimalSize, minimalSize); } w->resize(buttonSize); } void TimelineFramesView::updateGeometries() { QTableView::updateGeometries(); const int availableHeight = m_d->horizontalRuler->height(); const int margin = 2; const int minimalSize = availableHeight - 2 * margin; resizeToMinimalSize(m_d->addLayersButton, minimalSize); resizeToMinimalSize(m_d->audioOptionsButton, minimalSize); resizeToMinimalSize(m_d->zoomDragButton, minimalSize); int x = 2 * margin; int y = (availableHeight - minimalSize) / 2; m_d->addLayersButton->move(x, 2 * y); m_d->audioOptionsButton->move(x + minimalSize + 2 * margin, 2 * y); const int availableWidth = m_d->layersHeader->width(); x = availableWidth - margin - minimalSize; m_d->zoomDragButton->move(x, 2 * y); } void TimelineFramesView::setModel(QAbstractItemModel *model) { TimelineFramesModel *framesModel = qobject_cast(model); m_d->model = framesModel; QTableView::setModel(model); connect(m_d->model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), this, SLOT(slotHeaderDataChanged(Qt::Orientation, int, int))); connect(m_d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(slotDataChanged(QModelIndex,QModelIndex))); connect(m_d->model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(slotReselectCurrentIndex())); connect(m_d->model, SIGNAL(sigInfiniteTimelineUpdateNeeded()), this, SLOT(slotUpdateInfiniteFramesCount())); connect(m_d->model, SIGNAL(sigAudioChannelChanged()), this, SLOT(slotUpdateAudioActions())); connect(selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), &m_d->selectionChangedCompressor, SLOT(start())); connect(m_d->model, SIGNAL(sigEnsureRowVisible(int)), SLOT(slotEnsureRowVisible(int))); slotUpdateAudioActions(); } void TimelineFramesView::setFramesPerSecond(int fps) { m_d->fps = fps; m_d->horizontalRuler->setFramePerSecond(fps); // For some reason simple update sometimes doesn't work here, so // reset the whole header // // m_d->horizontalRuler->reset(); } void TimelineFramesView::slotZoomButtonPressed(qreal staticPoint) { m_d->zoomStillPointIndex = qIsNaN(staticPoint) ? currentIndex().column() : staticPoint; const int w = m_d->horizontalRuler->defaultSectionSize(); m_d->zoomStillPointOriginalOffset = w * m_d->zoomStillPointIndex - horizontalScrollBar()->value(); } void TimelineFramesView::slotZoomButtonChanged(qreal zoomLevel) { if (m_d->horizontalRuler->setZoom(zoomLevel)) { slotUpdateInfiniteFramesCount(); const int w = m_d->horizontalRuler->defaultSectionSize(); horizontalScrollBar()->setValue(w * m_d->zoomStillPointIndex - m_d->zoomStillPointOriginalOffset); viewport()->update(); } } void TimelineFramesView::slotColorLabelChanged(int label) { Q_FOREACH(QModelIndex index, selectedIndexes()) { m_d->model->setData(index, label, TimelineFramesModel::FrameColorLabelIndexRole); } KisImageConfig config; config.setDefaultFrameColorLabel(label); } void TimelineFramesView::slotSelectAudioChannelFile() { if (!m_d->model) return; - QString defaultDir = QDesktopServices::storageLocation(QDesktopServices::MusicLocation); + QString defaultDir = QStandardPaths::writableLocation(QStandardPaths::MusicLocation); const QString currentFile = m_d->model->audioChannelFileName(); QDir baseDir = QFileInfo(currentFile).absoluteDir(); if (baseDir.exists()) { defaultDir = baseDir.absolutePath(); } const QString result = KisImportExportManager::askForAudioFileName(defaultDir, this); const QFileInfo info(result); if (info.exists()) { m_d->model->setAudioChannelFileName(info.absoluteFilePath()); } } void TimelineFramesView::slotAudioChannelMute(bool value) { if (!m_d->model) return; if (value != m_d->model->isAudioMuted()) { m_d->model->setAudioMuted(value); } } void TimelineFramesView::slotAudioChannelRemove() { if (!m_d->model) return; m_d->model->setAudioChannelFileName(QString()); } void TimelineFramesView::slotUpdateAudioActions() { if (!m_d->model) return; const QString currentFile = m_d->model->audioChannelFileName(); if (currentFile.isEmpty()) { m_d->openAudioAction->setText(i18nc("@item:inmenu", "Open audio...")); } else { QFileInfo info(currentFile); m_d->openAudioAction->setText(i18nc("@item:inmenu", "Change audio (%1)...", info.fileName())); } m_d->audioMuteAction->setChecked(m_d->model->isAudioMuted()); QIcon audioIcon; if (currentFile.isEmpty()) { audioIcon = KisIconUtils::loadIcon("audio-none"); } else { if (m_d->model->isAudioMuted()) { audioIcon = KisIconUtils::loadIcon("audio-volume-mute"); } else { audioIcon = KisIconUtils::loadIcon("audio-volume-high"); } } m_d->audioOptionsButton->setIcon(audioIcon); m_d->volumeSlider->setEnabled(!m_d->model->isAudioMuted()); KisSignalsBlocker b(m_d->volumeSlider); m_d->volumeSlider->setValue(qRound(m_d->model->audioVolume() * 100.0)); } void TimelineFramesView::slotAudioVolumeChanged(int value) { m_d->model->setAudioVolume(qreal(value) / 100.0); } void TimelineFramesView::slotUpdateInfiniteFramesCount() { if (horizontalScrollBar()->isSliderDown()) return; const int sectionWidth = m_d->horizontalRuler->defaultSectionSize(); const int calculatedIndex = (horizontalScrollBar()->value() + m_d->horizontalRuler->width() - 1) / sectionWidth; m_d->model->setLastVisibleFrame(calculatedIndex); } void TimelineFramesView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { QTableView::currentChanged(current, previous); if (previous.column() != current.column()) { m_d->model->setData(previous, false, TimelineFramesModel::ActiveFrameRole); m_d->model->setData(current, true, TimelineFramesModel::ActiveFrameRole); } } QItemSelectionModel::SelectionFlags TimelineFramesView::selectionCommand(const QModelIndex &index, const QEvent *event) const { // WARNING: Copy-pasted from KisNodeView! Please keep in sync! /** * Qt has a bug: when we Ctrl+click on an item, the item's * selections gets toggled on mouse *press*, whereas usually it is * done on mouse *release*. Therefore the user cannot do a * Ctrl+D&D with the default configuration. This code fixes the * problem by manually returning QItemSelectionModel::NoUpdate * flag when the user clicks on an item and returning * QItemSelectionModel::Toggle on release. */ if (event && (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) && index.isValid()) { const QMouseEvent *mevent = static_cast(event); if (mevent->button() == Qt::RightButton && selectionModel()->selectedIndexes().contains(index)) { // Allow calling context menu for multiple layers return QItemSelectionModel::NoUpdate; } if (event->type() == QEvent::MouseButtonPress && (mevent->modifiers() & Qt::ControlModifier)) { return QItemSelectionModel::NoUpdate; } if (event->type() == QEvent::MouseButtonRelease && (mevent->modifiers() & Qt::ControlModifier)) { return QItemSelectionModel::Toggle; } } return QAbstractItemView::selectionCommand(index, event); } void TimelineFramesView::slotSelectionChanged() { int minColumn = std::numeric_limits::max(); int maxColumn = std::numeric_limits::min(); foreach (const QModelIndex &idx, selectedIndexes()) { if (idx.column() > maxColumn) { maxColumn = idx.column(); } if (idx.column() < minColumn) { minColumn = idx.column(); } } KisTimeRange range; if (maxColumn > minColumn) { range = KisTimeRange(minColumn, maxColumn - minColumn + 1); } m_d->model->setPlaybackRange(range); } void TimelineFramesView::slotReselectCurrentIndex() { QModelIndex index = currentIndex(); currentChanged(index, index); } void TimelineFramesView::slotEnsureRowVisible(int row) { QModelIndex index = currentIndex(); if (!index.isValid() || row < 0) return; index = m_d->model->index(row, index.column()); scrollTo(index); } void TimelineFramesView::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (m_d->model->isPlaybackActive()) return; int selectedColumn = -1; for (int j = topLeft.column(); j <= bottomRight.column(); j++) { QVariant value = m_d->model->data( m_d->model->index(topLeft.row(), j), TimelineFramesModel::ActiveFrameRole); if (value.isValid() && value.toBool()) { selectedColumn = j; break; } } QModelIndex index = currentIndex(); if (!index.isValid() && selectedColumn < 0) { return; } if (selectedColumn == -1) { selectedColumn = index.column(); } if (selectedColumn != index.column() && !m_d->dragInProgress) { int row= index.isValid() ? index.row() : 0; setCurrentIndex(m_d->model->index(row, selectedColumn)); } } void TimelineFramesView::slotHeaderDataChanged(Qt::Orientation orientation, int first, int last) { Q_UNUSED(first); Q_UNUSED(last); if (orientation == Qt::Horizontal) { const int newFps = m_d->model->headerData(0, Qt::Horizontal, TimelineFramesModel::FramesPerSecondRole).toInt(); if (newFps != m_d->fps) { setFramesPerSecond(newFps); } } } void TimelineFramesView::rowsInserted(const QModelIndex& parent, int start, int end) { QTableView::rowsInserted(parent, start, end); } inline bool isIndexDragEnabled(QAbstractItemModel *model, const QModelIndex &index) { return (model->flags(index) & Qt::ItemIsDragEnabled); } QStyleOptionViewItem TimelineFramesView::Private::viewOptionsV4() const { QStyleOptionViewItem option = q->viewOptions(); option.locale = q->locale(); option.locale.setNumberOptions(QLocale::OmitGroupSeparator); option.widget = q; return option; } QItemViewPaintPairs TimelineFramesView::Private::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const { Q_ASSERT(r); QRect &rect = *r; const QRect viewportRect = q->viewport()->rect(); QItemViewPaintPairs ret; for (int i = 0; i < indexes.count(); ++i) { const QModelIndex &index = indexes.at(i); const QRect current = q->visualRect(index); if (current.intersects(viewportRect)) { ret += qMakePair(current, index); rect |= current; } } rect &= viewportRect; return ret; } QPixmap TimelineFramesView::Private::renderToPixmap(const QModelIndexList &indexes, QRect *r) const { Q_ASSERT(r); QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r); if (paintPairs.isEmpty()) return QPixmap(); QPixmap pixmap(r->size()); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); QStyleOptionViewItem option = viewOptionsV4(); option.state |= QStyle::State_Selected; for (int j = 0; j < paintPairs.count(); ++j) { option.rect = paintPairs.at(j).first.translated(-r->topLeft()); const QModelIndex ¤t = paintPairs.at(j).second; //adjustViewOptionsForIndex(&option, current); q->itemDelegate(current)->paint(&painter, option, current); } return pixmap; } void TimelineFramesView::startDrag(Qt::DropActions supportedActions) { QModelIndexList indexes = selectionModel()->selectedIndexes(); if (!indexes.isEmpty() && m_d->modifiersCatcher->modifierPressed("offset-frame")) { QVector rows; int leftmostColumn = std::numeric_limits::max(); Q_FOREACH (const QModelIndex &index, indexes) { leftmostColumn = qMin(leftmostColumn, index.column()); if (!rows.contains(index.row())) { rows.append(index.row()); } } const int lastColumn = m_d->model->columnCount() - 1; selectionModel()->clear(); Q_FOREACH (const int row, rows) { QItemSelection sel(m_d->model->index(row, leftmostColumn), m_d->model->index(row, lastColumn)); selectionModel()->select(sel, QItemSelectionModel::Select); } supportedActions = Qt::MoveAction; { QModelIndexList indexes = selectedIndexes(); for(int i = indexes.count() - 1 ; i >= 0; --i) { if (!isIndexDragEnabled(m_d->model, indexes.at(i))) indexes.removeAt(i); } selectionModel()->clear(); if (indexes.count() > 0) { QMimeData *data = m_d->model->mimeData(indexes); if (!data) return; QRect rect; QPixmap pixmap = m_d->renderToPixmap(indexes, &rect); rect.adjust(horizontalOffset(), verticalOffset(), 0, 0); QDrag *drag = new QDrag(this); drag->setPixmap(pixmap); drag->setMimeData(data); drag->setHotSpot(m_d->lastPressedPosition - rect.topLeft()); drag->exec(supportedActions, Qt::MoveAction); setCurrentIndex(currentIndex()); } } } else { /** * Workaround for Qt5's bug: if we start a dragging action right during * Shift-selection, Qt will get crazy. We cannot workaround it easily, * because we would need to fork mouseMoveEvent() for that (where the * decision about drag state is done). So we just abort dragging in that * case. * * BUG:373067 */ if (m_d->lastPressedModifier & Qt::ShiftModifier) { return; } /** * Workaround for Qt5's bugs: * * 1) Qt doesn't treat selection the selection on D&D * correctly, so we save it in advance and restore * afterwards. * * 2) There is a private variable in QAbstractItemView: * QAbstractItemView::Private::currentSelectionStartIndex. * It is initialized *only* when the setCurrentIndex() is called * explicitly on the view object, not on the selection model. * Therefore we should explicitly call setCurrentIndex() after * D&D, even if it already has *correct* value! * * 2) We should also call selectionModel()->select() * explicitly. There are two reasons for it: 1) Qt doesn't * maintain selection over D&D; 2) when reselecting single * element after D&D, Qt goes crazy, because it tries to * read *global* keyboard modifiers. Therefore if we are * dragging with Shift or Ctrl pressed it'll get crazy. So * just reset it explicitly. */ QModelIndexList selectionBefore = selectionModel()->selectedIndexes(); QModelIndex currentBefore = selectionModel()->currentIndex(); // initialize a global status variable m_d->dragWasSuccessful = false; QAbstractItemView::startDrag(supportedActions); QModelIndex newCurrent; QPoint selectionOffset; if (m_d->dragWasSuccessful) { newCurrent = currentIndex(); selectionOffset = QPoint(newCurrent.column() - currentBefore.column(), newCurrent.row() - currentBefore.row()); } else { newCurrent = currentBefore; selectionOffset = QPoint(); } setCurrentIndex(newCurrent); selectionModel()->clearSelection(); Q_FOREACH (const QModelIndex &idx, selectionBefore) { QModelIndex newIndex = model()->index(idx.row() + selectionOffset.y(), idx.column() + selectionOffset.x()); selectionModel()->select(newIndex, QItemSelectionModel::Select); } } } void TimelineFramesView::dragEnterEvent(QDragEnterEvent *event) { m_d->dragInProgress = true; m_d->model->setScrubState(true); QTableView::dragEnterEvent(event); } void TimelineFramesView::dragMoveEvent(QDragMoveEvent *event) { m_d->dragInProgress = true; m_d->model->setScrubState(true); QTableView::dragMoveEvent(event); if (event->isAccepted()) { QModelIndex index = indexAt(event->pos()); if (!m_d->model->canDropFrameData(event->mimeData(), index)) { event->ignore(); } else { selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); } } } void TimelineFramesView::dropEvent(QDropEvent *event) { m_d->dragInProgress = false; m_d->model->setScrubState(false); QAbstractItemView::dropEvent(event); m_d->dragWasSuccessful = event->isAccepted(); } void TimelineFramesView::dragLeaveEvent(QDragLeaveEvent *event) { m_d->dragInProgress = false; m_d->model->setScrubState(false); QAbstractItemView::dragLeaveEvent(event); } void TimelineFramesView::mousePressEvent(QMouseEvent *event) { QPersistentModelIndex index = indexAt(event->pos()); if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) { if (event->button() == Qt::RightButton) { // TODO: try calculate index under mouse cursor even when // it is outside any visible row qreal staticPoint = index.isValid() ? index.column() : currentIndex().column(); m_d->zoomDragButton->beginZoom(event->pos(), staticPoint); } else if (event->button() == Qt::LeftButton) { m_d->initialDragPanPos = event->pos(); m_d->initialDragPanValue = QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value()); } event->accept(); } else if (event->button() == Qt::RightButton) { int numSelectedItems = selectionModel()->selectedIndexes().size(); if (index.isValid() && numSelectedItems <= 1 && m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) { model()->setData(index, true, TimelineFramesModel::ActiveLayerRole); model()->setData(index, true, TimelineFramesModel::ActiveFrameRole); setCurrentIndex(index); if (model()->data(index, TimelineFramesModel::FrameExistsRole).toBool() || model()->data(index, TimelineFramesModel::SpecialKeyframeExists).toBool()) { { KisSignalsBlocker b(m_d->colorSelector); QVariant colorLabel = index.data(TimelineFramesModel::FrameColorLabelIndexRole); int labelIndex = colorLabel.isValid() ? colorLabel.toInt() : 0; m_d->colorSelector->setCurrentIndex(labelIndex); } m_d->frameEditingMenu->exec(event->globalPos()); } else { m_d->frameCreationMenu->exec(event->globalPos()); } } else if (numSelectedItems > 1) { int labelIndex = -1; bool haveFrames = false; Q_FOREACH(QModelIndex index, selectedIndexes()) { haveFrames |= index.data(TimelineFramesModel::FrameExistsRole).toBool(); QVariant colorLabel = index.data(TimelineFramesModel::FrameColorLabelIndexRole); if (colorLabel.isValid()) { if (labelIndex == -1) { // First label labelIndex = colorLabel.toInt(); } else if (labelIndex != colorLabel.toInt()) { // Mixed colors in selection labelIndex = -1; break; } } } if (!haveFrames) { m_d->multiframeColorSelectorAction->setVisible(false); } else { KisSignalsBlocker b(m_d->multiframeColorSelector); m_d->multiframeColorSelector->setCurrentIndex(labelIndex); m_d->multiframeColorSelectorAction->setVisible(true); } m_d->multipleFrameEditingMenu->exec(event->globalPos()); } } else if (event->button() == Qt::MidButton) { QModelIndex index = model()->buddy(indexAt(event->pos())); if (index.isValid()) { QStyleOptionViewItem option = viewOptions(); option.rect = visualRect(index); // The offset of the headers is needed to get the correct position inside the view. m_d->tip.showTip(this, event->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index); } event->accept(); } else { if (index.isValid()) { m_d->model->setLastClickedIndex(index); } m_d->lastPressedPosition = QPoint(horizontalOffset(), verticalOffset()) + event->pos(); m_d->lastPressedModifier = event->modifiers(); QAbstractItemView::mousePressEvent(event); } } void TimelineFramesView::mouseMoveEvent(QMouseEvent *e) { if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) { if (e->buttons() & Qt::RightButton) { m_d->zoomDragButton->continueZoom(e->pos()); } else if (e->buttons() & Qt::LeftButton) { QPoint diff = e->pos() - m_d->initialDragPanPos; QPoint offset = QPoint(m_d->initialDragPanValue.x() - diff.x(), m_d->initialDragPanValue.y() - diff.y()); const int height = m_d->layersHeader->defaultSectionSize(); horizontalScrollBar()->setValue(offset.x()); verticalScrollBar()->setValue(offset.y() / height); } e->accept(); } else if (e->buttons() == Qt::MidButton) { QModelIndex index = model()->buddy(indexAt(e->pos())); if (index.isValid()) { QStyleOptionViewItem option = viewOptions(); option.rect = visualRect(index); // The offset of the headers is needed to get the correct position inside the view. m_d->tip.showTip(this, e->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index); } e->accept(); } else { m_d->model->setScrubState(true); QTableView::mouseMoveEvent(e); } } void TimelineFramesView::mouseReleaseEvent(QMouseEvent *e) { if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) { e->accept(); } else { m_d->model->setScrubState(false); QTableView::mouseReleaseEvent(e); } } void TimelineFramesView::wheelEvent(QWheelEvent *e) { QModelIndex index = currentIndex(); int column= -1; if (index.isValid()) { column= index.column() + ((e->delta() > 0) ? 1 : -1); } if (column >= 0 && !m_d->dragInProgress) { setCurrentIndex(m_d->model->index(index.row(), column)); } } void TimelineFramesView::slotUpdateLayersMenu() { QAction *action = 0; m_d->existingLayersMenu->clear(); QVariant value = model()->headerData(0, Qt::Vertical, TimelineFramesModel::OtherLayersRole); if (value.isValid()) { TimelineFramesModel::OtherLayersList list = value.value(); int i = 0; Q_FOREACH (const TimelineFramesModel::OtherLayer &l, list) { action = m_d->existingLayersMenu->addAction(l.name); action->setData(i++); } } } void TimelineFramesView::slotLayerContextMenuRequested(const QPoint &globalPos) { m_d->layerEditingMenu->exec(globalPos); } void TimelineFramesView::slotAddNewLayer() { QModelIndex index = currentIndex(); const int newRow = index.isValid() ? index.row() : 0; model()->insertRow(newRow); } void TimelineFramesView::slotAddExistingLayer(QAction *action) { QVariant value = action->data(); if (value.isValid()) { QModelIndex index = currentIndex(); const int newRow = index.isValid() ? index.row() + 1 : 0; m_d->model->insertOtherLayer(value.toInt(), newRow); } } void TimelineFramesView::slotRemoveLayer() { QModelIndex index = currentIndex(); if (!index.isValid()) return; model()->removeRow(index.row()); } void TimelineFramesView::slotNewFrame() { QModelIndex index = currentIndex(); if (!index.isValid() || !m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) { return; } m_d->model->createFrame(index); } void TimelineFramesView::slotCopyFrame() { QModelIndex index = currentIndex(); if (!index.isValid() || !m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) { return; } m_d->model->copyFrame(index); } void TimelineFramesView::slotRemoveFrame() { QModelIndexList indexes = selectionModel()->selectedIndexes(); for (auto it = indexes.begin(); it != indexes.end(); /*noop*/) { if (!m_d->model->data(*it, TimelineFramesModel::FrameEditableRole).toBool()) { it = indexes.erase(it); } else { ++it; } } if (!indexes.isEmpty()) { m_d->model->removeFrames(indexes); } } bool TimelineFramesView::viewportEvent(QEvent *event) { if (event->type() == QEvent::ToolTip && model()) { QHelpEvent *he = static_cast(event); QModelIndex index = model()->buddy(indexAt(he->pos())); if (index.isValid()) { QStyleOptionViewItem option = viewOptions(); option.rect = visualRect(index); // The offset of the headers is needed to get the correct position inside the view. m_d->tip.showTip(this, he->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index); return true; } } return QTableView::viewportEvent(event); } diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp index 717531fcda..8c479ba6cf 100644 --- a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp @@ -1,717 +1,717 @@ /* Copyright (C) 2011 Silvio Heinrich This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_color_selector.h" static const int MIN_NUM_HUE_PIECES = 1; static const int MAX_NUM_HUE_PIECES = 48; static const int MIN_NUM_LIGHT_PIECES = 1; static const int MAX_NUM_LIGHT_PIECES = 30; static const int MIN_NUM_SATURATION_RINGS = 1; static const int MAX_NUM_SATURATION_RINGS = 20; KisColorSelector::KisColorSelector(QWidget* parent, KisColor::Type type): QWidget(parent), m_colorSpace(type), m_inverseSaturation(false), m_relativeLight(false), m_light(0.5f), m_selectedColorRole(Acs::Foreground), m_clickedRing(-1) { recalculateRings(9, 12); recalculateAreas(9); selectColor(KisColor(Qt::red, KisColor::HSY)); using namespace std::placeholders; // For _1 placeholder auto function = std::bind(&KisColorSelector::slotUpdateColorAndPreview, this, _1); m_updateColorCompressor.reset(new ColorCompressorType(20 /* ms */, function)); } void KisColorSelector::setColorSpace(KisColor::Type type) { m_colorSpace = type; m_selectedColor = KisColor(m_selectedColor, m_colorSpace); update(); } void KisColorSelector::setNumLightPieces(int num) { num = qBound(MIN_NUM_LIGHT_PIECES, num, MAX_NUM_LIGHT_PIECES); - + recalculateAreas(quint8(num)); - + if (m_selectedLightPiece >= 0) m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); - + update(); } void KisColorSelector::setNumPieces(int num) { num = qBound(MIN_NUM_HUE_PIECES, num, MAX_NUM_HUE_PIECES); - + recalculateRings(quint8(getNumRings()), quint8(num)); - + if (m_selectedPiece >= 0) m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2); - + update(); } void KisColorSelector::setNumRings(int num) { num = qBound(MIN_NUM_SATURATION_RINGS, num, MAX_NUM_SATURATION_RINGS); - + recalculateRings(quint8(num), quint8(getNumPieces())); - + if (m_selectedRing >= 0) m_selectedRing = getSaturationIndex(m_selectedColor.getS()); - + update(); } void KisColorSelector::selectColor(const KisColor& color) { m_selectedColor = KisColor(color, m_colorSpace); m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2); m_selectedRing = getSaturationIndex(m_selectedColor.getS()); m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); update(); } void KisColorSelector::setFgColor(const KisColor& fgColor) { m_fgColor = KisColor(fgColor, m_colorSpace); update(); } void KisColorSelector::setBgColor(const KisColor& bgColor) { m_bgColor = KisColor(bgColor, m_colorSpace); update(); } void KisColorSelector::resetRings() { for(int i=0; i= 0) { m_colorRings[m_selectedRing].angle = 0.0f; update(); } } void KisColorSelector::setLight(float light, bool relative) { m_light = qBound(0.0f, light, 1.0f); - + m_selectedColor.setX(getLight(m_light, m_selectedColor.getH(), relative)); m_relativeLight = relative; m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); update(); } void KisColorSelector::setInverseSaturation(bool inverse) { if (m_inverseSaturation != inverse) { m_selectedRing = (getNumRings()-1) - m_selectedRing; m_inverseSaturation = inverse; recalculateRings(quint8(getNumRings()), quint8(getNumPieces())); update(); } } QPointF KisColorSelector::mapCoord(const QPointF& pt, const QRectF& rect) const { qreal w = rect.width() / 2.0; qreal h = rect.height() / 2.0; qreal x = pt.x() - (rect.x() + w); qreal y = pt.y() - (rect.y() + h); return QPointF(x/w, y/h); } qint8 KisColorSelector::getLightIndex(const QPointF& pt) const { if (m_lightStripArea.contains(pt.toPoint(), true)) { qreal t = (pt.x() - m_lightStripArea.x()) / qreal(m_lightStripArea.width()); t = (pt.y() - m_lightStripArea.y()) / qreal(m_lightStripArea.height()); return qint8(t * getNumLightPieces()); } - + return -1; } qint8 KisColorSelector::getLightIndex(qreal light) const { light = qreal(1) - qBound(qreal(0), light, qreal(1)); return qint8(qRound(light * (getNumLightPieces()-1))); } qreal KisColorSelector::getLight(qreal light, qreal hue, bool relative) const { if (relative) { KisColor color(hue, 1.0f, m_colorSpace); qreal cl = color.getX(); light = (light * 2.0f) - 1.0f; return (light < 0.0f) ? (cl + cl*light) : (cl + (1.0f-cl)*light); } - + return light; } qreal KisColorSelector::getLight(const QPointF& pt) const { qint8 clickedLightPiece = getLightIndex(pt); - + if (clickedLightPiece >= 0) { if (getNumLightPieces() > 1) { return 1.0 - (qreal(clickedLightPiece) / qreal(getNumLightPieces()-1)); } return 1.0 - (qreal(pt.y()) / qreal(m_lightStripArea.height())); } - + return qreal(0); } qint8 KisColorSelector::getHueIndex(Radian hue, Radian shift) const { hue -= shift; qreal partSize = 1.0 / qreal(getNumPieces()); return qint8(qRound(hue.scaled(0.0f, 1.0f) / partSize) % getNumPieces()); } qreal KisColorSelector::getHue(int hueIdx, Radian shift) const { Radian hue = (qreal(hueIdx) / qreal(getNumPieces())) * PI2; hue += shift; return hue.scaled(0.0f, 1.0f); } qint8 KisColorSelector::getSaturationIndex(qreal saturation) const { saturation = qBound(qreal(0), saturation, qreal(1)); saturation = m_inverseSaturation ? (qreal(1) - saturation) : saturation; return qint8(saturation * qreal(getNumRings() - 1)); } qint8 KisColorSelector::getSaturationIndex(const QPointF& pt) const { qreal length = std::sqrt(pt.x()*pt.x() + pt.y()*pt.y()); - + for(int i=0; i= m_colorRings[i].innerRadius && length < m_colorRings[i].outerRadius) return qint8(i); } return -1; } qreal KisColorSelector::getSaturation(int saturationIdx) const { qreal sat = qreal(saturationIdx) / qreal(getNumRings()-1); return m_inverseSaturation ? (1.0 - sat) : sat; } void KisColorSelector::recalculateAreas(quint8 numLightPieces) { const qreal LIGHT_STRIP_RATIO = 0.075; - + int width = QWidget::width(); int height = QWidget::height(); int size = qMin(width, height); int stripThick = int(size * LIGHT_STRIP_RATIO); - + width -= stripThick; size = qMin(width, height); - + int x = (width - size) / 2; int y = (height - size) / 2; - + m_renderArea = QRect(x+stripThick, y, size, size); m_lightStripArea = QRect(0, 0, stripThick, QWidget::height()); m_renderBuffer = QImage(size, size, QImage::Format_ARGB32); m_numLightPieces = numLightPieces; } void KisColorSelector::recalculateRings(quint8 numRings, quint8 numPieces) { m_colorRings.resize(numRings); m_numPieces = numPieces; - + for(int i=0; i(numPieces, 1); ring.innerRadius = innerRadius; ring.outerRadius = outerRadius; ring.pieced.resize(numParts); - + qreal partSize = 360.0 / qreal(numParts); QRectF outerRect(-outerRadius, -outerRadius, outerRadius*2.0, outerRadius*2.0); QRectF innerRect(-innerRadius, -innerRadius, innerRadius*2.0, innerRadius*2.0); - + for(int i=0; istart(qMakePair(color, role)); } void KisColorSelector::slotUpdateColorAndPreview(QPair color) { const bool selectAsFgColor = color.second == Acs::Foreground; if (selectAsFgColor) { m_fgColor = color.first; } else { m_bgColor = color.first; } m_selectedColor = color.first; m_selectedColorRole = color.second; if (selectAsFgColor) { emit sigFgColorChanged(m_selectedColor); } else { emit sigBgColorChanged(m_selectedColor); } } void KisColorSelector::drawRing(QPainter& painter, KisColorSelector::ColorRing& ring, const QRect& rect) { painter.setRenderHint(QPainter::Antialiasing, false); painter.resetTransform(); painter.translate(rect.width()/2, rect.height()/2); - + if (ring.pieced.size() > 1) { painter.rotate(-ring.getShift().degrees()); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(Qt::NoPen); - + QBrush brush(Qt::SolidPattern); - + for(int i=0; i= 1.0f) ? (hue - 1.0f) : hue; hue = (hue < 0.0f) ? (hue + 1.0f) : hue; - + KisColor color(hue, 1.0f, m_colorSpace); color.setS(ring.saturation); color.setX(getLight(m_light, hue, m_relativeLight)); - + brush.setColor(color.getQColor()); painter.fillPath(ring.pieced[i], brush); } } else { KisColor colors[7] = { KisColor(Qt::red , m_colorSpace), KisColor(Qt::yellow , m_colorSpace), KisColor(Qt::green , m_colorSpace), KisColor(Qt::cyan , m_colorSpace), KisColor(Qt::blue , m_colorSpace), KisColor(Qt::magenta, m_colorSpace), KisColor(Qt::red , m_colorSpace) }; - + QConicalGradient gradient(0, 0, 0); - + for(int i=0; i<=6; ++i) { qreal hue = float(i) / 6.0f; colors[i].setS(ring.saturation); colors[i].setX(getLight(m_light, hue, m_relativeLight)); gradient.setColorAt(hue, colors[i].getQColor()); } - + painter.scale(rect.width()/2, rect.height()/2); painter.fillPath(ring.pieced[0], QBrush(gradient)); } - + painter.resetTransform(); } void KisColorSelector::drawOutline(QPainter& painter, const QRect& rect) { painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(QPen(QBrush(Qt::gray), 0.005)); - + if (getNumPieces() > 1) { for(int i=0; i= 0 && m_selectedPiece >= 0) { painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); painter.rotate(-m_colorRings[m_selectedRing].getShift().degrees()); painter.scale(rect.width()/2, rect.height()/2); - + painter.setPen(QPen(QBrush(Qt::red), 0.01)); painter.drawPath(m_colorRings[m_selectedRing].pieced[m_selectedPiece]); } } else { for(int i=0; i= 0) { qreal iRad = m_colorRings[m_selectedRing].innerRadius; qreal oRad = m_colorRings[m_selectedRing].outerRadius; - + painter.setPen(QPen(QBrush(Qt::red), 0.005)); painter.drawEllipse(QRectF(-iRad, -iRad, iRad*2.0, iRad*2.0)); painter.drawEllipse(QRectF(-oRad, -oRad, oRad*2.0, oRad*2.0)); - + if (getNumPieces() <= 1) { float c = std::cos(-m_selectedColor.getH() * PI2); float s = std::sin(-m_selectedColor.getH() * PI2); painter.drawLine(QPointF(c*iRad, s*iRad), QPointF(c*oRad, s*oRad)); } } } void KisColorSelector::drawLightStrip(QPainter& painter, const QRect& rect) { bool isVertical = true; qreal penSize = qreal(qMin(QWidget::width(), QWidget::height())) / 200.0; KisColor color(m_selectedColor); - + painter.resetTransform(); - + if (getNumLightPieces() > 1) { painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(QBrush(Qt::red), penSize)); - + QTransform matrix; matrix.translate(rect.x(), rect.y()); matrix.scale(rect.width(), rect.height()); - + for(int i=0; i (1,0,0) // 1 yellow -> (1,1,0) // 2 green -> (0,1,0) // 3 cyan -> (0,1,1) // 4 blue -> (0,0,1) // 5 maenta -> (1,0,1) // 6 red -> (1,0,0) - + m_renderBuffer.fill(0); - + QPainter imgPainter(&m_renderBuffer); QPainter wdgPainter(this); - + QRect fgRect(0, 0 , QWidget::width(), QWidget::height()/2); QRect bgRect(0, QWidget::height()/2, QWidget::width(), QWidget::height()/2); wdgPainter.fillRect(fgRect, m_fgColor.getQColor()); wdgPainter.fillRect(bgRect, m_bgColor.getQColor()); - + for(int i=0; iposF(), m_renderArea); + m_clickPos = mapCoord(event->localPos(), m_renderArea); m_mouseMoved = false; m_pressedButtons = event->buttons(); m_clickedRing = getSaturationIndex(m_clickPos); - - qint8 clickedLightPiece = getLightIndex(event->posF()); - + + qint8 clickedLightPiece = getLightIndex(event->localPos()); + if (clickedLightPiece >= 0) { - setLight(getLight(event->posF()), m_relativeLight); + setLight(getLight(event->localPos()), m_relativeLight); m_selectedLightPiece = clickedLightPiece; requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); m_mouseMoved = true; } else if (m_clickedRing >= 0) { if (getNumPieces() > 1) { for(int i=0; iposF(), m_renderArea); - qint8 clickedLightPiece = getLightIndex(event->posF()); - + QPointF dragPos = mapCoord(event->localPos(), m_renderArea); + qint8 clickedLightPiece = getLightIndex(event->localPos()); + if (clickedLightPiece >= 0) { - setLight(getLight(event->posF()), m_relativeLight); + setLight(getLight(event->localPos()), m_relativeLight); m_selectedLightPiece = clickedLightPiece; requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); } - + if (m_clickedRing < 0) return; - + if (getNumPieces() > 1) { float angle = std::atan2(dragPos.x(), dragPos.y()) - std::atan2(m_clickPos.x(), m_clickPos.y()); float dist = std::sqrt(dragPos.x()*dragPos.x() + dragPos.y()*dragPos.y()) * 0.80f; float threshold = 5.0f * (1.0f-(dist*dist)); - + if (qAbs(angle * TO_DEG) >= threshold || m_mouseMoved) { bool selectedRingMoved = true; - + if (m_pressedButtons & Qt::RightButton) { selectedRingMoved = m_clickedRing == m_selectedRing; m_colorRings[m_clickedRing].angle = m_colorRings[m_clickedRing].tmpAngle + angle; } else for(int i=0; i= 0) { Radian angle = std::atan2(m_clickPos.x(), m_clickPos.y()) - RAD_90; - + m_selectedRing = m_clickedRing; m_selectedPiece = getHueIndex(angle, m_colorRings[m_clickedRing].getShift()); - + if (getNumPieces() > 1) m_selectedColor.setH(getHue(m_selectedPiece, m_colorRings[m_clickedRing].getShift())); else m_selectedColor.setH(angle.scaled(0.0f, 1.0f)); - + m_selectedColor.setS(getSaturation(m_selectedRing)); m_selectedColor.setX(getLight(m_light, m_selectedColor.getH(), m_relativeLight)); - + requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); } else if (m_mouseMoved) requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); - + m_clickedRing = -1; update(); } void KisColorSelector::resizeEvent(QResizeEvent* /*event*/) { recalculateAreas(quint8(getNumLightPieces())); } void KisColorSelector::saveSettings() { KisConfig cfg; cfg.writeEntry("ArtColorSel.ColorSpace" , qint32(m_colorSpace)); cfg.writeEntry("ArtColorSel.NumRings" , m_colorRings.size()); cfg.writeEntry("ArtColorSel.RingPieces" , qint32(m_numPieces)); cfg.writeEntry("ArtColorSel.LightPieces", qint32(m_numLightPieces)); - + cfg.writeEntry("ArtColorSel.InversedSaturation", m_inverseSaturation); cfg.writeEntry("ArtColorSel.RelativeLight" , m_relativeLight); cfg.writeEntry("ArtColorSel.Light" , m_light); - + cfg.writeEntry("ArtColorSel.SelColorH", m_selectedColor.getH()); cfg.writeEntry("ArtColorSel.SelColorS", m_selectedColor.getS()); cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX()); cfg.writeEntry("ArtColorSel.SelColorA", m_selectedColor.getA()); - + QList angles; - + for(int i=0; i("ArtColorSel.ColorSpace" , KisColor::HSY))); - + setNumLightPieces(cfg.readEntry("ArtColorSel.LightPieces", 19)); - + m_selectedColor.setH(cfg.readEntry("ArtColorSel.SelColorH", 0.0f)); m_selectedColor.setS(cfg.readEntry("ArtColorSel.SelColorS", 0.0f)); m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0f)); m_selectedColor.setA(1.0f); - + setInverseSaturation(cfg.readEntry("ArtColorSel.InversedSaturation", false)); setLight(cfg.readEntry("ArtColorSel.Light", 0.5f), cfg.readEntry("ArtColorSel.RelativeLight", false)); - + recalculateRings( cfg.readEntry("ArtColorSel.NumRings" , 11), cfg.readEntry("ArtColorSel.RingPieces", 12) ); - + QList angles = cfg.readList("ArtColorSel.RingAngles"); for (int i = 0; i < m_colorRings.size(); ++i) { if (i < angles.size() && i < m_colorRings.size()) { m_colorRings[i].angle = angles[i]; } } - + selectColor(m_selectedColor); update(); } diff --git a/plugins/dockers/compositiondocker/compositiondocker_dock.cpp b/plugins/dockers/compositiondocker/compositiondocker_dock.cpp index 25b24757c2..91788aa87e 100644 --- a/plugins/dockers/compositiondocker/compositiondocker_dock.cpp +++ b/plugins/dockers/compositiondocker/compositiondocker_dock.cpp @@ -1,304 +1,304 @@ /* * Copyright (c) 2012 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "compositiondocker_dock.h" #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "compositionmodel.h" CompositionDockerDock::CompositionDockerDock( ) : QDockWidget(i18n("Compositions")), m_canvas(0) { QWidget* widget = new QWidget(this); setupUi(widget); m_model = new CompositionModel(this); compositionView->setModel(m_model); compositionView->installEventFilter(this); deleteButton->setIcon(KisIconUtils::loadIcon("edit-delete")); saveButton->setIcon(KisIconUtils::loadIcon("list-add")); exportButton->setIcon(KisIconUtils::loadIcon("document-export")); deleteButton->setToolTip(i18n("Delete Composition")); saveButton->setToolTip(i18n("New Composition")); exportButton->setToolTip(i18n("Export Composition")); setWidget(widget); connect( compositionView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(activated ( const QModelIndex & ) ) ); compositionView->setContextMenuPolicy(Qt::CustomContextMenu); connect( compositionView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint))); connect( deleteButton, SIGNAL(clicked(bool)), this, SLOT(deleteClicked())); connect( saveButton, SIGNAL(clicked(bool)), this, SLOT(saveClicked())); connect( exportButton, SIGNAL(clicked(bool)), this, SLOT(exportClicked())); saveNameEdit->setPlaceholderText(i18n("Insert Name")); } CompositionDockerDock::~CompositionDockerDock() { } void CompositionDockerDock::setCanvas(KoCanvasBase * canvas) { if (m_canvas && m_canvas->viewManager()) { Q_FOREACH (KisAction *action, m_actions) { m_canvas->viewManager()->actionManager()->takeAction(action); } } unsetCanvas(); setEnabled(canvas != 0); m_canvas = dynamic_cast(canvas); if (m_canvas && m_canvas->viewManager()) { if (m_actions.isEmpty()) { KisAction *updateAction = m_canvas->viewManager()->actionManager()->createAction("update_composition"); connect(updateAction, SIGNAL(triggered()), this, SLOT(updateComposition())); m_actions.append(updateAction); KisAction *renameAction = m_canvas->viewManager()->actionManager()->createAction("rename_composition"); connect(renameAction, SIGNAL(triggered()), this, SLOT(renameComposition())); m_actions.append(renameAction); } else { Q_FOREACH (KisAction *action, m_actions) { m_canvas->viewManager()->actionManager()->addAction(action->objectName(), action); } } updateModel(); } } void CompositionDockerDock::unsetCanvas() { setEnabled(false); m_canvas = 0; m_model->setCompositions(QList()); } void CompositionDockerDock::activated(const QModelIndex& index) { KisLayerCompositionSP composition = m_model->compositionFromIndex(index); composition->apply(); } void CompositionDockerDock::deleteClicked() { QModelIndex index = compositionView->currentIndex(); if (m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->image() && index.isValid()) { KisLayerCompositionSP composition = m_model->compositionFromIndex(index); m_canvas->viewManager()->image()->removeComposition(composition); updateModel(); } } void CompositionDockerDock::saveClicked() { KisImageWSP image = m_canvas->viewManager()->image(); if (!image) return; // format as 001, 002 ... QString name = saveNameEdit->text(); if (name.isEmpty()) { bool found = false; int i = 1; do { name = QString("%1").arg(i, 3, 10, QChar('0')); found = false; Q_FOREACH (KisLayerCompositionSP composition, m_canvas->viewManager()->image()->compositions()) { if (composition->name() == name) { found = true; break; } } i++; } while(found && i < 1000); } KisLayerCompositionSP composition(new KisLayerComposition(image, name)); composition->store(); image->addComposition(composition); saveNameEdit->clear(); updateModel(); compositionView->setCurrentIndex(m_model->index(image->compositions().count()-1, 0)); image->setModified(); } void CompositionDockerDock::updateModel() { if (m_model && m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->image()) { m_model->setCompositions(m_canvas->viewManager()->image()->compositions()); } } void CompositionDockerDock::exportClicked() { if (m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->image()) { QString path; KoFileDialog dialog(0, KoFileDialog::OpenDirectory, "compositiondockerdock"); dialog.setCaption(i18n("Select a Directory")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); path = dialog.filename(); if (path.isNull()) return; if (!path.endsWith('/')) { path.append('/'); } KisImageWSP image = m_canvas->viewManager()->image(); QString filename = m_canvas->viewManager()->document()->localFilePath(); if (!filename.isEmpty()) { QFileInfo info(filename); path += info.baseName() + '_'; } Q_FOREACH (KisLayerCompositionSP composition, m_canvas->viewManager()->image()->compositions()) { if (!composition->isExportEnabled()) { continue; } composition->apply(); image->refreshGraph(); image->lock(); #if 0 image->rootLayer()->projection()->convertToQImage(0, 0, 0, image->width(), image->height()).save(path + composition->name() + ".png"); #else QRect r = image->bounds(); KisDocument *d = KisPart::instance()->createDocument(); KisImageWSP dst = new KisImage(d->createUndoStore(), r.width(), r.height(), image->colorSpace(), composition->name()); dst->setResolution(image->xRes(), image->yRes()); d->setCurrentImage(dst); KisPaintLayer* paintLayer = new KisPaintLayer(dst, "projection", OPACITY_OPAQUE_U8); KisPainter gc(paintLayer->paintDevice()); gc.bitBlt(QPoint(0, 0), image->rootLayer()->projection(), r); dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0)); dst->refreshGraph(); d->setFileBatchMode(true); const QByteArray outputFormat("image/png"); d->exportDocumentSync(QUrl::fromLocalFile(path + composition->name() + ".png"), outputFormat); delete d; #endif image->unlock(); } } } bool CompositionDockerDock::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { // new index will be set after the method is called QTimer::singleShot(0, this, SLOT(activateCurrentIndex())); } return false; } else { return QObject::eventFilter(obj, event); } } void CompositionDockerDock::activateCurrentIndex() { QModelIndex index = compositionView->currentIndex(); if (index.isValid()) { activated(index); } } void CompositionDockerDock::customContextMenuRequested(QPoint pos) { if (m_actions.isEmpty()) return; QMenu menu; Q_FOREACH (KisAction *action, m_actions) { menu.addAction(action); } menu.exec(compositionView->mapToGlobal(pos)); } void CompositionDockerDock::updateComposition() { QModelIndex index = compositionView->currentIndex(); if (m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->image() && index.isValid()) { KisLayerCompositionSP composition = m_model->compositionFromIndex(index); composition->store(); m_canvas->image()->setModified(); } } void CompositionDockerDock::renameComposition() { dbgKrita << "rename"; QModelIndex index = compositionView->currentIndex(); if (m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->image() && index.isValid()) { KisLayerCompositionSP composition = m_model->compositionFromIndex(index); bool ok; QString name = QInputDialog::getText(this, i18n("Rename Composition"), i18n("New Name:"), QLineEdit::Normal, composition->name(), &ok); if (ok && !name.isEmpty()) { composition->setName(name); m_canvas->image()->setModified(); } } } diff --git a/plugins/dockers/compositiondocker/compositionmodel.cpp b/plugins/dockers/compositiondocker/compositionmodel.cpp index abe4796ffa..b8561b4aef 100644 --- a/plugins/dockers/compositiondocker/compositionmodel.cpp +++ b/plugins/dockers/compositiondocker/compositionmodel.cpp @@ -1,109 +1,110 @@ /* * Copyright (c) 2012 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "compositionmodel.h" #include #include #include CompositionModel::CompositionModel(QObject* parent): QAbstractTableModel(parent) { } CompositionModel::~CompositionModel() { } QVariant CompositionModel::data(const QModelIndex& index, int role) const { if (index.isValid()) { switch (role) { case Qt::DisplayRole: { return m_compositions.at(index.row())->name(); } case Qt::DecorationRole: { return KisIconUtils::loadIcon("tools-wizard"); } case Qt::CheckStateRole: { return m_compositions.at(index.row())->isExportEnabled() ? Qt::Checked : Qt::Unchecked; } } } return QVariant(); } bool CompositionModel::setData ( const QModelIndex& index, const QVariant& value, int role ) { if (index.isValid()) { if (role == Qt::CheckStateRole) { Q_ASSERT(index.row() < rowCount()); Q_ASSERT(index.column() < columnCount()); if (index.column() == 0) { bool exportEnabled = value.toInt() == Qt::Checked; KisLayerCompositionSP layerComposition = m_compositions.at(index.row()); if (layerComposition) { layerComposition->setExportEnabled(exportEnabled); } } } return true; } return false; } QVariant CompositionModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return i18n("Composition"); } int CompositionModel::rowCount(const QModelIndex& /*parent*/) const { return m_compositions.count(); } int CompositionModel::columnCount(const QModelIndex& /*parent*/) const { return 2; } Qt::ItemFlags CompositionModel::flags(const QModelIndex& /*index*/) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; return flags; } KisLayerCompositionSP CompositionModel::compositionFromIndex(const QModelIndex& index) { if(index.isValid()) { return m_compositions.at(index.row()); } return KisLayerCompositionSP(); } void CompositionModel::setCompositions(QList< KisLayerCompositionSP > compositions) { m_compositions = compositions; - reset(); + beginResetModel(); + endResetModel(); } diff --git a/plugins/dockers/historydocker/KisUndoModel.cpp b/plugins/dockers/historydocker/KisUndoModel.cpp index 89d56f914e..ae1ceb5a0d 100644 --- a/plugins/dockers/historydocker/KisUndoModel.cpp +++ b/plugins/dockers/historydocker/KisUndoModel.cpp @@ -1,282 +1,283 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "KisUndoModel.h" #include KisUndoModel::KisUndoModel(QObject *parent) : QAbstractItemModel(parent) { m_blockOutgoingHistoryChange = false; m_stack = 0; m_canvas = 0; m_sel_model = new QItemSelectionModel(this, this); connect(m_sel_model, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(setStackCurrentIndex(QModelIndex))); m_empty_label = i18n(""); } QItemSelectionModel *KisUndoModel::selectionModel() const { return m_sel_model; } KUndo2QStack *KisUndoModel::stack() const { return m_stack; } void KisUndoModel::setStack(KUndo2QStack *stack) { if (m_stack == stack) return; if (m_stack != 0) { disconnect(m_stack, SIGNAL(canRedoChanged(bool)), this, SLOT(stackChanged())); disconnect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged())); disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged())); disconnect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*))); disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int))); } m_stack = stack; if (m_stack != 0) { connect(m_stack, SIGNAL(canRedoChanged(bool)), this, SLOT(stackChanged())); connect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged())); connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged())); connect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*))); connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int))); } stackChanged(); } void KisUndoModel::stackDestroyed(QObject *obj) { if (obj != m_stack) return; m_stack = 0; stackChanged(); } void KisUndoModel::stackChanged() { - reset(); + beginResetModel(); + endResetModel(); m_blockOutgoingHistoryChange = true; m_sel_model->setCurrentIndex(selectedIndex(), QItemSelectionModel::ClearAndSelect); m_blockOutgoingHistoryChange = false; } void KisUndoModel::setStackCurrentIndex(const QModelIndex &index) { if (m_blockOutgoingHistoryChange) return; if (m_stack == 0) return; if (index == selectedIndex()) return; if (index.column() != 0) return; m_stack->setIndex(index.row()); } QModelIndex KisUndoModel::selectedIndex() const { return m_stack == 0 ? QModelIndex() : createIndex(m_stack->index(), 0); } QModelIndex KisUndoModel::index(int row, int column, const QModelIndex &parent) const { if (m_stack == 0) return QModelIndex(); if (parent.isValid()) return QModelIndex(); if (column != 0) return QModelIndex(); if (row < 0 || row > m_stack->count()) return QModelIndex(); return createIndex(row, column); } QModelIndex KisUndoModel::parent(const QModelIndex&) const { return QModelIndex(); } int KisUndoModel::rowCount(const QModelIndex &parent) const { if (m_stack == 0) return 0; if (parent.isValid()) return 0; return m_stack->count() + 1; } int KisUndoModel::columnCount(const QModelIndex&) const { return 1; } QVariant KisUndoModel::data(const QModelIndex &index, int role) const { if (m_stack == 0){ return QVariant(); } if (index.column() != 0){ return QVariant(); } if (index.row() < 0 || index.row() > m_stack->count()){ return QVariant(); } if (role == Qt::DisplayRole) { if (index.row() == 0){ return m_empty_label; } KUndo2Command* currentCommand = const_cast(m_stack->command(index.row() - 1)); return currentCommand->isMerged()?m_stack->text(index.row() - 1)+"(Merged)":m_stack->text(index.row() - 1); } else if (role == Qt::DecorationRole) { if (index.row() > 0) { const KUndo2Command* currentCommand = m_stack->command(index.row() - 1); if (m_imageMap.contains(currentCommand)) { return m_imageMap[currentCommand]; } } } return QVariant(); } QString KisUndoModel::emptyLabel() const { return m_empty_label; } void KisUndoModel::setEmptyLabel(const QString &label) { m_empty_label = label; stackChanged(); } void KisUndoModel::setCleanIcon(const QIcon &icon) { m_clean_icon = icon; stackChanged(); } QIcon KisUndoModel::cleanIcon() const { return m_clean_icon; } void KisUndoModel::setCanvas(KisCanvas2 *canvas) { m_canvas = canvas; } void KisUndoModel::addImage(int idx) { if (m_stack == 0 || m_stack->count() == 0) { return; } const KUndo2Command* currentCommand = m_stack->command(idx-1); if (m_stack->count() == idx && !m_imageMap.contains(currentCommand)) { KisImageWSP historyImage = m_canvas->viewManager()->image(); KisPaintDeviceSP paintDevice = historyImage->projection(); QImage image = paintDevice->createThumbnail(32, 32, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); m_imageMap[currentCommand] = image; } QList list; for (int i = 0; i < m_stack->count(); ++i) { list << m_stack->command(i); } for (QMap:: iterator it = m_imageMap.begin(); it != m_imageMap.end();) { if (!list.contains(it.key())) { it = m_imageMap.erase(it); } else { ++it; } } } bool KisUndoModel::checkMergedCommand(int index) { Q_UNUSED(index) return false; } diff --git a/plugins/dockers/imagedocker/image_strip_scene.cpp b/plugins/dockers/imagedocker/image_strip_scene.cpp index 48ad8838e4..534db68aed 100644 --- a/plugins/dockers/imagedocker/image_strip_scene.cpp +++ b/plugins/dockers/imagedocker/image_strip_scene.cpp @@ -1,199 +1,199 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "image_strip_scene.h" #include #include #include #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////////////////// // ------------- ImageLoader ---------------------------------------------------------- // ImageLoader::ImageLoader(float size) : m_size(size) , m_run(true) { connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(stopExecution())); } void ImageLoader::run() { typedef QHash::iterator Iterator; for (Iterator data = m_data.begin(); data != m_data.end() && m_run; ++data) { QImage img = QImage(data->path); if (!img.isNull()) { data->image = img.scaled(m_size, m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); } //dbgKrita << "Loaded" << data->path; data->isLoaded = true; emit sigItemContentChanged(data.key()); } } void ImageLoader::stopExecution() { m_run = false; } ///////////////////////////////////////////////////////////////////////////////////////////// // ------------- ImageItem ------------------------------------------------------------ // void ImageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(option); Q_UNUSED(widget); if (m_loader->isImageLoaded(this)) { QImage image = m_loader->getImage(this); if (!image.isNull()) { QPointF offset((m_size-image.width()) / 2.0, (m_size-image.height()) / 2.0); painter->drawImage(offset, image); } else { QIcon icon = KisIconUtils::loadIcon("edit-delete"); QRect rect = boundingRect().toRect(); QPixmap img = icon.pixmap(rect.size()); painter->drawPixmap(rect, img, img.rect()); } } else { QIcon icon = KisIconUtils::loadIcon("folder-pictures"); QRect rect = boundingRect().toRect(); QPixmap img = icon.pixmap(rect.size()); painter->drawPixmap(rect, img, img.rect()); } if (isSelected()) { painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(0.50); painter->fillRect(boundingRect().toRect(), palette().color(QPalette::Active, QPalette::Highlight)); painter->setCompositionMode(QPainter::CompositionMode_SourceOver); QPen pen(palette().color(QPalette::Active, QPalette::Highlight), 3); painter->setPen(pen); } painter->drawRect(boundingRect()); } QSizeF ImageItem::sizeHint(Qt::SizeHint /*which*/, const QSizeF& /*constraint*/) const { return QSizeF(m_size, m_size); } ///////////////////////////////////////////////////////////////////////////////////////////// // ------------- ImageStripScene ------------------------------------------------------ // ImageStripScene::ImageStripScene(): m_imgSize(80) , m_loader(0) { } ImageStripScene::~ImageStripScene() { delete m_loader; } bool ImageStripScene::setCurrentDirectory(const QString& path) { m_path = path; QMutexLocker locker(&m_mutex); QDir directory(path); QImageReader reader; if (directory.exists()) { clear(); if (m_loader) { m_loader->disconnect(this); m_loader->stopExecution(); if (!m_loader->wait(500)) { m_loader->terminate(); m_loader->wait(); } } delete m_loader; m_numItems = 0; m_loader = new ImageLoader(m_imgSize); connect(m_loader, SIGNAL(sigItemContentChanged(ImageItem*)), SLOT(slotItemContentChanged(ImageItem*))); QStringList files = directory.entryList(QDir::Files); QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(); for (QStringList::iterator name=files.begin(); name!=files.end(); ++name) { QString path = directory.absoluteFilePath(*name); QString fileExtension = QFileInfo(path).suffix(); if (!fileExtension.compare("DNG", Qt::CaseInsensitive)) { warnKrita << "WARNING: Qt is known to crash when trying to open a DNG file. Skip it"; continue; } reader.setFileName(path); if(reader.canRead()) { ImageItem* item = new ImageItem(m_imgSize, path, m_loader); m_loader->addPath(item, path); layout->addItem(item); ++m_numItems; } } QGraphicsWidget* widget = new QGraphicsWidget(); widget->setLayout(layout); widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); addItem(widget); setSceneRect(widget->boundingRect()); QTimer::singleShot(0, m_loader, SLOT(start())); return true; } return false; } void ImageStripScene::slotItemContentChanged(ImageItem* item) { QMutexLocker locker(&m_mutex); item->update(); } void ImageStripScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { - ImageItem* item = static_cast(itemAt(event->scenePos())); + ImageItem* item = static_cast(itemAt(event->scenePos().x(), event->scenePos().y(), QTransform())); if (item) emit sigImageActivated(item->path()); } diff --git a/plugins/dockers/imagedocker/imagedocker_dock.cpp b/plugins/dockers/imagedocker/imagedocker_dock.cpp index 7c98b23996..7060aaba4f 100644 --- a/plugins/dockers/imagedocker/imagedocker_dock.cpp +++ b/plugins/dockers/imagedocker/imagedocker_dock.cpp @@ -1,593 +1,593 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "imagedocker_dock.h" #include "image_strip_scene.h" #include "image_view.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "ui_wdgimagedocker.h" #include "ui_wdgImageViewPopup.h" /////////////////////////////////////////////////////////////////////////////// // --------- ImageFilter --------------------------------------------------- // class ImageFilter: public QSortFilterProxyModel { bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override { QFileSystemModel* model = static_cast(sourceModel()); QModelIndex index = sourceModel()->index(source_row, 0, source_parent); if(model->isDir(index)) return true; QString ext = model->fileInfo(index).suffix().toLower(); if(s_supportedImageFormats.isEmpty()) { s_supportedImageFormats = QImageReader::supportedImageFormats(); } //QImageReader::supportedImageFormats return a list with mixed-case ByteArrays so //iterate over it manually to make it possible to do toLower(). Q_FOREACH (const QByteArray& format, s_supportedImageFormats) { if(format.toLower() == ext.toUtf8()) { return true; } } return false; } bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const override { Q_UNUSED(source_parent); return source_column == 0; } static QList s_supportedImageFormats; }; QList ImageFilter::s_supportedImageFormats; /////////////////////////////////////////////////////////////////////////////// // --------- ImageListModel ------------------------------------------------ // class ImageListModel: public QAbstractListModel { struct Data { QPixmap icon; QString text; qint64 id; }; public: void addImage(const QPixmap& pixmap, const QString& text, qint64 id) { Data data; data.icon = pixmap.scaled(70, 70, Qt::KeepAspectRatio, Qt::SmoothTransformation); data.text = text; data.id = id; emit layoutAboutToBeChanged(); m_data.push_back(data); emit layoutChanged(); } qint64 imageID(int index) const { return m_data[index].id; } void removeImage(qint64 id) { typedef QList::iterator Iterator; for(Iterator data=m_data.begin(); data!=m_data.end(); ++data) { if(data->id == id) { emit layoutAboutToBeChanged(); m_data.erase(data); emit layoutChanged(); return; } } } int indexFromID(qint64 id) { for(int i=0; i m_data; }; /////////////////////////////////////////////////////////////////////////////// // --------- ImageDockerUI ------------------------------------------------- // struct ImageDockerUI: public QWidget, public Ui_wdgImageDocker { ImageDockerUI() { setupUi(this); } }; /////////////////////////////////////////////////////////////////////////////// // --------- PopupWidgetUI ------------------------------------------------- // struct PopupWidgetUI: public QWidget, public Ui_wdgImageViewPopup { PopupWidgetUI() { setupUi(this); } }; /////////////////////////////////////////////////////////////////////////////// // --------- ImageDockerDock ----------------------------------------------- // ImageDockerDock::ImageDockerDock(): QDockWidget(i18n("Reference Images")), m_canvas(0), m_currImageID(-1) { m_ui = new ImageDockerUI(); m_popupUi = new PopupWidgetUI(); m_zoomButtons = new QButtonGroup(); m_imgListModel = new ImageListModel(); m_imageStripScene = new ImageStripScene(); m_model = new QFileSystemModel(); m_proxyModel = new ImageFilter(); m_proxyModel->setSourceModel(m_model); m_proxyModel->setDynamicSortFilter(true); m_ui->bnBack->setIcon(KisIconUtils::loadIcon("arrow-left")); m_ui->bnUp->setIcon(KisIconUtils::loadIcon("arrow-up")); m_ui->bnHome->setIcon(KisIconUtils::loadIcon("go-home")); m_ui->bnImgPrev->setIcon(KisIconUtils::loadIcon("arrow-left")); m_ui->bnImgNext->setIcon(KisIconUtils::loadIcon("arrow-right")); m_ui->bnImgClose->setIcon(KisIconUtils::loadIcon("window-close")); m_ui->thumbView->setScene(m_imageStripScene); m_ui->treeView->setModel(m_proxyModel); m_ui->cmbImg->setModel(m_imgListModel); m_ui->bnPopup->setIcon(KisIconUtils::loadIcon("zoom-original")); m_ui->bnPopup->setPopupWidget(m_popupUi); m_popupUi->zoomSlider->setRange(5, 500); m_popupUi->zoomSlider->setValue(100); m_zoomButtons->addButton(m_popupUi->bnZoomFit , ImageView::VIEW_MODE_FIT); m_zoomButtons->addButton(m_popupUi->bnZoomAdjust, ImageView::VIEW_MODE_ADJUST); m_zoomButtons->addButton(m_popupUi->bnZoom25 , 25); m_zoomButtons->addButton(m_popupUi->bnZoom50 , 50); m_zoomButtons->addButton(m_popupUi->bnZoom75 , 75); m_zoomButtons->addButton(m_popupUi->bnZoom100 , 100); installEventFilter(this); - m_ui->cmbPath->addItem(KisIconUtils::loadIcon("folder-pictures"), QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); - m_ui->cmbPath->addItem(KisIconUtils::loadIcon("folder-documents"), QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); - m_ui->cmbPath->addItem(KisIconUtils::loadIcon("go-home"), QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + m_ui->cmbPath->addItem(KisIconUtils::loadIcon("folder-pictures"), QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); + m_ui->cmbPath->addItem(KisIconUtils::loadIcon("folder-documents"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); + m_ui->cmbPath->addItem(KisIconUtils::loadIcon("go-home"), QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); Q_FOREACH (const QFileInfo &info, QDir::drives()) { m_ui->cmbPath->addItem(KisIconUtils::loadIcon("drive-harddisk"), info.absolutePath()); } connect(m_ui->cmbPath, SIGNAL(activated(const QString&)), SLOT(slotChangeRoot(const QString&))); connect(m_ui->treeView , SIGNAL(doubleClicked(const QModelIndex&)) , SLOT(slotItemDoubleClicked(const QModelIndex&))); connect(m_ui->bnBack , SIGNAL(clicked(bool)) , SLOT(slotBackButtonClicked())); connect(m_ui->bnHome , SIGNAL(clicked(bool)) , SLOT(slotHomeButtonClicked())); connect(m_ui->bnUp , SIGNAL(clicked(bool)) , SLOT(slotUpButtonClicked())); connect(m_imageStripScene , SIGNAL(sigImageActivated(const QString&)) , SLOT(slotOpenImage(QString))); connect(m_ui->bnImgNext , SIGNAL(clicked(bool)) , SLOT(slotNextImage())); connect(m_ui->bnImgPrev , SIGNAL(clicked(bool)) , SLOT(slotPrevImage())); connect(m_ui->bnImgClose , SIGNAL(clicked(bool)) , SLOT(slotCloseCurrentImage())); connect(m_ui->cmbImg , SIGNAL(activated(int)) , SLOT(slotImageChoosenFromComboBox(int))); connect(m_ui->imgView , SIGNAL(sigColorSelected(const QColor&)) , SLOT(slotColorSelected(const QColor))); connect(m_ui->imgView , SIGNAL(sigViewModeChanged(int, qreal)) , SLOT(slotViewModeChanged(int, qreal))); connect(m_popupUi->zoomSlider , SIGNAL(valueChanged(int)) , SLOT(slotZoomChanged(int))); connect(m_zoomButtons , SIGNAL(buttonClicked(int)) , SLOT(slotZoomChanged(int))); connect(m_zoomButtons , SIGNAL(buttonClicked(int)) , SLOT(slotCloseZoomPopup())); setWidget(m_ui); setAcceptDrops(true); } ImageDockerDock::~ImageDockerDock() { saveConfigState(); delete m_proxyModel; delete m_model; delete m_imageStripScene; delete m_imgListModel; delete m_zoomButtons; qDeleteAll(m_temporaryFiles); } void ImageDockerDock::dragEnterEvent(QDragEnterEvent *event) { event->setAccepted(event->mimeData()->hasImage() || event->mimeData()->hasUrls()); } void ImageDockerDock::dropEvent(QDropEvent *event) { QImage image; if (event->mimeData()->hasImage()) { image = qvariant_cast(event->mimeData()->imageData()); } if (!image.isNull()) { QTemporaryFile *file = new QTemporaryFile(QDir::tempPath () + QDir::separator() + "krita_reference_dnd_XXXXXX.png"); m_temporaryFiles.append(file); file->open(); image.save(file, "PNG"); file->close(); slotOpenImage(file->fileName()); } else if (event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); Q_FOREACH (const QUrl &url, urls) { QString path = url.path(); QFileInfo info(path); if (info.exists() && !QImageReader::imageFormat(path).isEmpty()) { slotOpenImage(path); } } } } void ImageDockerDock::showEvent(QShowEvent *) { loadConfigState(); } void ImageDockerDock::hideEvent(QHideEvent *event) { saveConfigState(); } void ImageDockerDock::setCanvas(KoCanvasBase* canvas) { // Intentionally not disabled if there's no canvas // "Every connection you make emits a signal, so duplicate connections emit two signals" if(m_canvas) { m_canvas->disconnectCanvasObserver(this); } m_canvas = canvas; } void ImageDockerDock::addCurrentPathToHistory() { m_history.push_back(m_model->filePath(m_proxyModel->mapToSource(m_ui->treeView->rootIndex()))); } void ImageDockerDock::updatePath(const QString& path) { m_ui->bnBack->setDisabled(m_history.empty()); m_imageStripScene->setCurrentDirectory(path); } qint64 ImageDockerDock::generateImageID() const { static qint64 id = 0; return ++id; } void ImageDockerDock::setCurrentImage(qint64 imageID) { if(m_imgInfoMap.contains(m_currImageID)) m_imgInfoMap[m_currImageID].scrollPos = m_ui->imgView->getScrollPos(); m_ui->bnImgClose->setDisabled(imageID < 0); m_ui->bnPopup->setDisabled(imageID < 0); if(imageID < 0) { m_currImageID = -1; m_ui->imgView->setPixmap(QPixmap()); } else if(m_imgInfoMap.contains(imageID)) { ImageInfoIter info = m_imgInfoMap.find(imageID); m_ui->imgView->blockSignals(true); m_ui->imgView->setPixmap(info->pixmap); setZoom(*info); m_ui->imgView->blockSignals(false); m_ui->bnImgPrev->setDisabled(info == m_imgInfoMap.begin()); m_ui->bnImgNext->setDisabled((info+1) == m_imgInfoMap.end()); m_ui->cmbImg->blockSignals(true); m_ui->cmbImg->setCurrentIndex(m_imgListModel->indexFromID(imageID)); m_ui->cmbImg->blockSignals(false); m_currImageID = imageID; } } void ImageDockerDock::setZoom(const ImageInfo& info) { m_ui->imgView->setViewMode(info.viewMode, info.scale); m_ui->imgView->setScrollPos(info.scrollPos); int zoom = qRound(m_ui->imgView->getScale() * 100.0f); m_popupUi->zoomSlider->blockSignals(true); m_popupUi->zoomSlider->setValue(zoom); m_popupUi->zoomSlider->blockSignals(false); } void ImageDockerDock::saveConfigState() { const QString lastUsedDirectory = m_model->filePath(m_proxyModel->mapToSource(m_ui->treeView->rootIndex())); KConfigGroup cfg = KSharedConfig::openConfig()->group("referenceImageDocker"); cfg.writeEntry("lastUsedDirectory", lastUsedDirectory); } void ImageDockerDock::loadConfigState() { - const QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::PicturesLocation); + const QString defaultLocation = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); KConfigGroup cfg = KSharedConfig::openConfig()->group("referenceImageDocker"); QString lastUsedDirectory = cfg.readEntry("lastUsedDirectory", defaultLocation); if (!QFileInfo(lastUsedDirectory).exists()) { lastUsedDirectory = defaultLocation; } m_model->setRootPath(lastUsedDirectory); m_ui->treeView->setRootIndex(m_proxyModel->mapFromSource(m_model->index(lastUsedDirectory))); updatePath(lastUsedDirectory); } // ------------ slots ------------------------------------------------- // void ImageDockerDock::slotItemDoubleClicked(const QModelIndex& index) { QModelIndex mappedIndex = m_proxyModel->mapToSource(index); mappedIndex = m_model->index(mappedIndex.row(), 0, mappedIndex.parent()); QString path(m_model->filePath(mappedIndex)); if(m_model->isDir(mappedIndex)) { addCurrentPathToHistory(); updatePath(path); m_ui->treeView->setRootIndex(m_proxyModel->mapFromSource(mappedIndex)); } else slotOpenImage(path); } void ImageDockerDock::slotBackButtonClicked() { if(!m_history.empty()) { QString path = m_history.last(); QModelIndex index = m_proxyModel->mapFromSource(m_model->index(path)); m_ui->treeView->setRootIndex(index); m_history.pop_back(); updatePath(path); } } void ImageDockerDock::slotHomeButtonClicked() { addCurrentPathToHistory(); QModelIndex index = m_proxyModel->mapFromSource(m_model->index(QDir::homePath())); m_ui->treeView->setRootIndex(index); updatePath(QDir::homePath()); } void ImageDockerDock::slotUpButtonClicked() { addCurrentPathToHistory(); QModelIndex index = m_proxyModel->mapToSource(m_ui->treeView->rootIndex()); QDir dir(m_model->filePath(index)); dir.makeAbsolute(); if(dir.cdUp()) { index = m_proxyModel->mapFromSource(m_model->index(dir.path())); m_ui->treeView->setRootIndex(index); updatePath(dir.path()); } } void ImageDockerDock::slotOpenImage(const QString& path) { QPixmap pixmap(path); if(!pixmap.isNull()) { QFileInfo fileInfo(path); ImageInfo imgInfo; imgInfo.id = generateImageID(); imgInfo.name = fileInfo.fileName(); imgInfo.path = fileInfo.absoluteFilePath(); imgInfo.viewMode = ImageView::VIEW_MODE_FIT; imgInfo.scale = 1.0f; imgInfo.pixmap = pixmap; imgInfo.scrollPos = QPoint(0, 0); m_imgInfoMap[imgInfo.id] = imgInfo; m_imgListModel->addImage(imgInfo.pixmap, imgInfo.name, imgInfo.id); setCurrentImage(imgInfo.id); m_ui->tabWidget->setCurrentIndex(1); } } void ImageDockerDock::slotCloseCurrentImage() { ImageInfoIter info = m_imgInfoMap.find(m_currImageID); if(info != m_imgInfoMap.end()) { ImageInfoIter next = info + 1; ImageInfoIter prev = info - 1; qint64 id = -1; if(next != m_imgInfoMap.end()) id = next->id; else if(info != m_imgInfoMap.begin()) id = prev->id; m_imgListModel->removeImage(info->id); m_imgInfoMap.erase(info); setCurrentImage(id); if(id < 0) m_ui->tabWidget->setCurrentIndex(0); } } void ImageDockerDock::slotNextImage() { ImageInfoIter info = m_imgInfoMap.find(m_currImageID); if(info != m_imgInfoMap.end()) { ++info; if(info != m_imgInfoMap.end()) setCurrentImage(info->id); } } void ImageDockerDock::slotPrevImage() { ImageInfoIter info = m_imgInfoMap.find(m_currImageID); if(info != m_imgInfoMap.end() && info != m_imgInfoMap.begin()) { --info; setCurrentImage(info->id); } } void ImageDockerDock::slotImageChoosenFromComboBox(int index) { setCurrentImage(m_imgListModel->imageID(index)); } void ImageDockerDock::slotZoomChanged(int zoom) { if(isImageLoaded()) { ImageInfoIter info = m_imgInfoMap.find(m_currImageID); switch(zoom) { case ImageView::VIEW_MODE_FIT: case ImageView::VIEW_MODE_ADJUST: info->viewMode = zoom; break; default: info->viewMode = ImageView::VIEW_MODE_FREE; info->scale = float(zoom) / 100.0f; break; } setZoom(*info); } } void ImageDockerDock::slotColorSelected(const QColor& color) { if (m_canvas) { m_canvas->resourceManager()->setForegroundColor(KoColor(color, KoColorSpaceRegistry::instance()->rgb8())); } } void ImageDockerDock::slotViewModeChanged(int viewMode, qreal scale) { if(isImageLoaded()) { m_imgInfoMap[m_currImageID].viewMode = viewMode; m_imgInfoMap[m_currImageID].scale = scale; int zoom = qRound(scale * 100.0); m_popupUi->zoomSlider->blockSignals(true); m_popupUi->zoomSlider->setValue(zoom); m_popupUi->zoomSlider->blockSignals(false); } } void ImageDockerDock::slotCloseZoomPopup() { m_ui->bnPopup->hidePopupWidget(); } void ImageDockerDock::slotChangeRoot(const QString &path) { m_model->setRootPath(path); m_ui->treeView->setRootIndex(m_proxyModel->mapFromSource(m_model->index(path))); updatePath(path); } bool ImageDockerDock::eventFilter(QObject *obj, QEvent *event) { Q_UNUSED(obj); if (event->type() == QEvent::Resize) { m_ui->treeView->setColumnWidth(0, width()); return true; } return false; } diff --git a/plugins/dockers/shapedockers/CollectionItemModel.cpp b/plugins/dockers/shapedockers/CollectionItemModel.cpp index f437b67c6f..9dbb287ac1 100644 --- a/plugins/dockers/shapedockers/CollectionItemModel.cpp +++ b/plugins/dockers/shapedockers/CollectionItemModel.cpp @@ -1,129 +1,134 @@ /* This file is part of the KDE project * Copyright (C) 2008 Peter Simonsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "CollectionItemModel.h" #include #include #include #include CollectionItemModel::CollectionItemModel(QObject *parent) : QAbstractListModel(parent) { - setSupportedDragActions(Qt::CopyAction); } QVariant CollectionItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() > m_shapeTemplateList.count()) { return QVariant(); } switch (role) { case Qt::ToolTipRole: return m_shapeTemplateList[index.row()].toolTip; case Qt::DecorationRole: return m_shapeTemplateList[index.row()].icon; case Qt::UserRole: return m_shapeTemplateList[index.row()].id; case Qt::DisplayRole: return m_shapeTemplateList[index.row()].name; default: return QVariant(); } return QVariant(); } int CollectionItemModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_shapeTemplateList.count(); } void CollectionItemModel::setShapeTemplateList(const QList &newlist) { m_shapeTemplateList = newlist; - reset(); + beginResetModel(); + endResetModel(); } QMimeData *CollectionItemModel::mimeData(const QModelIndexList &indexes) const { if (indexes.isEmpty()) { return 0; } QModelIndex index = indexes.first(); if (!index.isValid()) { return 0; } if (m_shapeTemplateList.isEmpty()) { return 0; } QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); dataStream << m_shapeTemplateList[index.row()].id; const KoProperties *props = m_shapeTemplateList[index.row()].properties; if (props) { dataStream << props->store("shapes"); } else { dataStream << QString(); } QMimeData *mimeData = new QMimeData; mimeData->setData(SHAPETEMPLATE_MIMETYPE, itemData); return mimeData; } QStringList CollectionItemModel::mimeTypes() const { QStringList mimetypes; mimetypes << SHAPETEMPLATE_MIMETYPE; return mimetypes; } Qt::ItemFlags CollectionItemModel::flags(const QModelIndex &index) const { if (index.isValid()) { return QAbstractListModel::flags(index) | Qt::ItemIsDragEnabled; } return QAbstractListModel::flags(index); } const KoProperties *CollectionItemModel::properties(const QModelIndex &index) const { if (!index.isValid() || index.row() > m_shapeTemplateList.count()) { return 0; } return m_shapeTemplateList[index.row()].properties; } + +Qt::DropActions CollectionItemModel::supportedDragActions() const +{ + return Qt::CopyAction; +} diff --git a/plugins/dockers/shapedockers/CollectionItemModel.h b/plugins/dockers/shapedockers/CollectionItemModel.h index 7f0731854e..ccb887b0c8 100644 --- a/plugins/dockers/shapedockers/CollectionItemModel.h +++ b/plugins/dockers/shapedockers/CollectionItemModel.h @@ -1,75 +1,77 @@ /* This file is part of the KDE project * Copyright (C) 2008 Peter Simonsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIVIOSHAPETEMPLATEMODEL_H #define KIVIOSHAPETEMPLATEMODEL_H #include #include #include #include #include class KoProperties; /** * Struct containing the information stored in CollectionItemModel item */ struct KoCollectionItem { KoCollectionItem() { properties = 0; }; QString id; QString name; QString toolTip; QIcon icon; const KoProperties *properties; }; class CollectionItemModel : public QAbstractListModel { Q_OBJECT public: explicit CollectionItemModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::ItemFlags flags(const QModelIndex &index) const override; /** * Set the list of KoCollectionItem to be stored in the model */ void setShapeTemplateList(const QList &newlist); QList shapeTemplateList() const { return m_shapeTemplateList; } const KoProperties *properties(const QModelIndex &index) const; + Qt::DropActions supportedDragActions() const; + private: QList m_shapeTemplateList; QString m_family; }; #endif //KIVIOSHAPETEMPLATEMODEL_H diff --git a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp index 1429cc0847..752264d14b 100644 --- a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp +++ b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.cpp @@ -1,208 +1,212 @@ /* This file is part of the KDE project * Copyright (C) 2008 Peter Simonsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SvgSymbolCollectionDocker.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_WdgSvgCollection.h" #include // // SvgCollectionModel // SvgCollectionModel::SvgCollectionModel(QObject *parent) : QAbstractListModel(parent) { - setSupportedDragActions(Qt::CopyAction); } QVariant SvgCollectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() > m_symbolCollection->symbols().count()) { return QVariant(); } switch (role) { case Qt::ToolTipRole: return m_symbolCollection->symbols()[index.row()]->title; case Qt::DecorationRole: { QPixmap px = QPixmap::fromImage(m_symbolCollection->symbols()[index.row()]->icon()); QIcon icon(px); return icon; } case Qt::UserRole: return m_symbolCollection->symbols()[index.row()]->id; case Qt::DisplayRole: return m_symbolCollection->symbols()[index.row()]->title; default: return QVariant(); } return QVariant(); } int SvgCollectionModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_symbolCollection->symbols().count(); } QMimeData *SvgCollectionModel::mimeData(const QModelIndexList &indexes) const { if (indexes.isEmpty()) { return 0; } QModelIndex index = indexes.first(); if (!index.isValid()) { return 0; } if (m_symbolCollection->symbols().isEmpty()) { return 0; } QList shapes; shapes.append(m_symbolCollection->symbols()[index.row()]->shape); KoDrag drag; drag.setSvg(shapes); QMimeData *mimeData = drag.mimeData(); return mimeData; } QStringList SvgCollectionModel::mimeTypes() const { return QStringList() << SHAPETEMPLATE_MIMETYPE << "image/svg+xml"; } Qt::ItemFlags SvgCollectionModel::flags(const QModelIndex &index) const { if (index.isValid()) { return QAbstractListModel::flags(index) | Qt::ItemIsDragEnabled; } return QAbstractListModel::flags(index); } +Qt::DropActions SvgCollectionModel::supportedDragActions() const +{ + return Qt::CopyAction; +} + void SvgCollectionModel::setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource *resource) { m_symbolCollection = resource; } // // SvgSymbolCollectionDockerFactory // SvgSymbolCollectionDockerFactory::SvgSymbolCollectionDockerFactory() : KoDockFactoryBase() { } QString SvgSymbolCollectionDockerFactory::id() const { return QString("SvgSymbolCollectionDocker"); } QDockWidget *SvgSymbolCollectionDockerFactory::createDockWidget() { SvgSymbolCollectionDocker *docker = new SvgSymbolCollectionDocker(); return docker; } // // SvgSymbolCollectionDocker // SvgSymbolCollectionDocker::SvgSymbolCollectionDocker(QWidget *parent) : QDockWidget(parent) , m_wdgSvgCollection(new Ui_WdgSvgCollection()) { setWindowTitle(i18n("Vector Libraries")); QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_wdgSvgCollection->setupUi(mainWidget); connect(m_wdgSvgCollection->cmbCollections, SIGNAL(activated(int)), SLOT(collectionActivated(int))); KoResourceServer *svgCollectionProvider = KoResourceServerProvider::instance()->svgSymbolCollectionServer(); Q_FOREACH(KoSvgSymbolCollectionResource *r, svgCollectionProvider->resources()) { m_wdgSvgCollection->cmbCollections->addSqueezedItem(r->name()); SvgCollectionModel *model = new SvgCollectionModel(); model->setSvgSymbolCollectionResource(r); m_models.append(model); } m_wdgSvgCollection->listCollection->setDragEnabled(true); m_wdgSvgCollection->listCollection->setDragDropMode(QAbstractItemView::DragOnly); m_wdgSvgCollection->listCollection->setSelectionMode(QListView::SingleSelection); KConfigGroup cfg = KSharedConfig::openConfig()->group("SvgSymbolCollection"); int i = cfg.readEntry("currentCollection", 0); if (i > m_wdgSvgCollection->cmbCollections->count()) { i = 0; } m_wdgSvgCollection->cmbCollections->setCurrentIndex(i); collectionActivated(i); } void SvgSymbolCollectionDocker::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); } void SvgSymbolCollectionDocker::unsetCanvas() { setEnabled(false); } void SvgSymbolCollectionDocker::collectionActivated(int index) { if (index < m_models.size()) { KConfigGroup cfg = KSharedConfig::openConfig()->group("SvgSymbolCollection"); cfg.writeEntry("currentCollection", index); m_wdgSvgCollection->listCollection->setModel(m_models[index]); } } diff --git a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h index bb349bc0ac..817d2df48a 100644 --- a/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h +++ b/plugins/dockers/shapedockers/SvgSymbolCollectionDocker.h @@ -1,86 +1,87 @@ /* This file is part of the KDE project * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SVGSYMBOLCOLLECTIONDOCKER_H #define SVGSYMBOLCOLLECTIONDOCKER_H #include #include #include #include #include #include #include #include "ui_WdgSvgCollection.h" class KoSvgSymbolCollectionResource; class SvgCollectionModel : public QAbstractListModel { Q_OBJECT public: explicit SvgCollectionModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::ItemFlags flags(const QModelIndex &index) const override; + Qt::DropActions supportedDragActions() const; public: void setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource *resource); private: KoSvgSymbolCollectionResource *m_symbolCollection; }; class SvgSymbolCollectionDockerFactory : public KoDockFactoryBase { public: SvgSymbolCollectionDockerFactory(); QString id() const override; QDockWidget *createDockWidget() override; DockPosition defaultDockPosition() const override { return DockRight; } }; class SvgSymbolCollectionDocker : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: explicit SvgSymbolCollectionDocker(QWidget *parent = 0); /// reimplemented void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; private Q_SLOTS: void collectionActivated(int index); private: Ui_WdgSvgCollection *m_wdgSvgCollection; QVector m_models; }; #endif //KOSHAPECOLLECTIONDOCKER_H diff --git a/plugins/dockers/tasksetdocker/tasksetmodel.cpp b/plugins/dockers/tasksetdocker/tasksetmodel.cpp index 8595866a64..26661e1301 100644 --- a/plugins/dockers/tasksetdocker/tasksetmodel.cpp +++ b/plugins/dockers/tasksetdocker/tasksetmodel.cpp @@ -1,100 +1,102 @@ /* * Copyright (c) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tasksetmodel.h" #include #include #include TasksetModel::TasksetModel(QObject* parent): QAbstractTableModel(parent) { } TasksetModel::~TasksetModel() { } QVariant TasksetModel::data(const QModelIndex& index, int role) const { if (index.isValid()) { switch (role) { case Qt::DisplayRole: { return m_actions.at(index.row())->iconText(); } case Qt::DecorationRole: { const QIcon icon = m_actions.at(index.row())->icon(); if (icon.isNull()) { return KisIconUtils::loadIcon("tools-wizard"); } return icon; } } } return QVariant(); } QVariant TasksetModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return i18n("Task"); } int TasksetModel::rowCount(const QModelIndex& /*parent*/) const { return m_actions.count(); } int TasksetModel::columnCount(const QModelIndex& /*parent*/) const { return 1; } Qt::ItemFlags TasksetModel::flags(const QModelIndex& /*index*/) const { Qt::ItemFlags flags = /*Qt::ItemIsSelectable |*/ Qt::ItemIsEnabled; return flags; } void TasksetModel::addAction(QAction* action) { m_actions.append(action); - reset(); + beginResetModel(); + endResetModel(); } QVector< QAction* > TasksetModel::actions() { return m_actions; } QAction* TasksetModel::actionFromIndex(const QModelIndex& index) { if(index.isValid()) { return m_actions.at(index.row()); } return 0; } void TasksetModel::clear() { m_actions.clear(); - reset(); + beginResetModel(); + endResetModel(); } diff --git a/plugins/extensions/bigbrother/bigbrother.cc b/plugins/extensions/bigbrother/bigbrother.cc index 0586196030..2df5da991c 100644 --- a/plugins/extensions/bigbrother/bigbrother.cc +++ b/plugins/extensions/bigbrother/bigbrother.cc @@ -1,238 +1,238 @@ /* * Copyright (c) 2007 Cyrille Berger (cberger@cberger.net) * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bigbrother.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "actionseditor/kis_actions_editor.h" #include "actionseditor/kis_actions_editor_dialog.h" -#include +#include #include K_PLUGIN_FACTORY_WITH_JSON(BigBrotherPluginFactory, "kritabigbrother.json", registerPlugin();) class RecordedActionSaveContext : public KisRecordedActionSaveContext { public: void saveGradient(const KoAbstractGradient* ) override {} void savePattern(const KoPattern* ) override {} }; class RecordedActionLoadContext : public KisRecordedActionLoadContext { public: KoAbstractGradient* gradient(const QString& name) const override { return KoResourceServerProvider::instance()->gradientServer()->resourceByName(name); } KoPattern* pattern(const QString& name) const override { return KoResourceServerProvider::instance()->patternServer()->resourceByName(name); } }; BigBrotherPlugin::BigBrotherPlugin(QObject *parent, const QVariantList &) : KisViewPlugin(parent) , m_recorder(0) { if (parent->inherits("KisViewManager")) { m_view = (KisViewManager*) parent; // Open and play action KisAction* action = createAction("Macro_Open_Play"); connect(action, SIGNAL(triggered()), this, SLOT(slotOpenPlay())); // Open and edit action action = createAction("Macro_Open_Edit"); connect(action, SIGNAL(triggered()), this, SLOT(slotOpenEdit())); // Start recording action m_startRecordingMacroAction = createAction("Recording_Start_Recording_Macro"); connect(m_startRecordingMacroAction, SIGNAL(triggered()), this, SLOT(slotStartRecordingMacro())); // Save recorded action m_stopRecordingMacroAction = createAction("Recording_Stop_Recording_Macro"); connect(m_stopRecordingMacroAction, SIGNAL(triggered()), this, SLOT(slotStopRecordingMacro())); m_stopRecordingMacroAction->setEnabled(false); } } BigBrotherPlugin::~BigBrotherPlugin() { m_view = 0; delete m_recorder; } void BigBrotherPlugin::slotOpenPlay() { KisMacro* m = openMacro(); dbgKrita << m; if (!m) return; dbgPlugins << "Play the macro"; KoUpdaterPtr updater = m_view->createUnthreadedUpdater(i18n("Playing back macro")); KisMacroPlayer player(m, KisPlayInfo(m_view->image(), m_view->activeNode()), updater); player.start(); while(player.isRunning()) { QApplication::processEvents(); } dbgPlugins << "Finished"; delete m; } void BigBrotherPlugin::slotOpenEdit() { KisMacro *macro = openMacro(); if (!macro) return; KisActionsEditorDialog aed(m_view->mainWindow()); aed.actionsEditor()->setMacro(macro); if (aed.exec() == QDialog::Accepted) { saveMacro(macro); } delete macro; } void BigBrotherPlugin::slotStartRecordingMacro() { dbgPlugins << "Start recording macro"; if (m_recorder) return; // Alternate actions m_startRecordingMacroAction->setEnabled(false); m_stopRecordingMacroAction->setEnabled(true); // Create recorder m_recorder = new KisMacro(); connect(m_view->image()->actionRecorder(), SIGNAL(addedAction(const KisRecordedAction&)), m_recorder, SLOT(addAction(const KisRecordedAction&))); } void BigBrotherPlugin::slotStopRecordingMacro() { dbgPlugins << "Stop recording macro"; if (!m_recorder) return; // Alternate actions m_startRecordingMacroAction->setEnabled(true); m_stopRecordingMacroAction->setEnabled(false); // Save the macro saveMacro(m_recorder); // Delete recorder delete m_recorder; m_recorder = 0; } KisMacro* BigBrotherPlugin::openMacro() { QStringList mimeFilter; mimeFilter << "*.krarec|Recorded actions (*.krarec)"; KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::OpenFile, "OpenDocument"); dialog.setCaption(i18n("Open Macro")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(QStringList() << "application/krita-recorded-macro", "application/krita-recorded-macro"); QString filename = dialog.filename(); RecordedActionLoadContext loadContext; if (!filename.isNull()) { QDomDocument doc; QFile f(filename); if (f.exists()) { dbgPlugins << f.open(QIODevice::ReadOnly); QString err; int line, col; if (!doc.setContent(&f, &err, &line, &col)) { // TODO error message dbgPlugins << err << " line = " << line << " col = " << col; f.close(); return 0; } f.close(); QDomElement docElem = doc.documentElement(); if (!docElem.isNull() && docElem.tagName() == "RecordedActions") { dbgPlugins << "Load the macro"; KisMacro* m = new KisMacro(); m->fromXML(docElem, &loadContext); return m; } else { // TODO error message } } else { dbgPlugins << "Unexistant file : " << filename; } } return 0; } void BigBrotherPlugin::saveMacro(const KisMacro* macro) { KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::SaveFile, "bigbrother"); dialog.setCaption(i18n("Save Macro")); dialog.setMimeTypeFilters(QStringList() << "application/krita-recorded-macro", "application/krita-recorded-macro"); QString filename = dialog.filename(); if (!filename.isNull()) { QDomDocument doc; QDomElement e = doc.createElement("RecordedActions"); RecordedActionSaveContext context; macro->toXML(doc, e, &context); doc.appendChild(e); QFile f(filename); f.open(QIODevice::WriteOnly); QTextStream stream(&f); stream.setCodec("UTF-8"); doc.save(stream, 2); f.close(); } } #include "bigbrother.moc" diff --git a/plugins/extensions/imagesplit/imagesplit.cpp b/plugins/extensions/imagesplit/imagesplit.cpp index 884d0b34a6..a0817223f4 100644 --- a/plugins/extensions/imagesplit/imagesplit.cpp +++ b/plugins/extensions/imagesplit/imagesplit.cpp @@ -1,207 +1,207 @@ /* * imagesplit.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2011 Srikanth Tiyyagura * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "imagesplit.h" #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_imagesplit.h" K_PLUGIN_FACTORY_WITH_JSON(ImagesplitFactory, "kritaimagesplit.json", registerPlugin();) Imagesplit::Imagesplit(QObject *parent, const QVariantList &) : KisViewPlugin(parent) { KisAction *action = createAction("imagesplit"); connect(action, SIGNAL(triggered()), this, SLOT(slotImagesplit())); } Imagesplit::~Imagesplit() { } bool Imagesplit::saveAsImage(const QRect &imgSize, const QString &mimeType, const QString &url) { KisImageSP image = m_view->image(); KisDocument *document = KisPart::instance()->createDocument(); KisImageSP dst = new KisImage(document->createUndoStore(), imgSize.width(), imgSize.height(), image->colorSpace(), image->objectName()); dst->setResolution(image->xRes(), image->yRes()); document->setCurrentImage(dst); KisPaintLayer* paintLayer = new KisPaintLayer(dst, dst->nextLayerName(), 255); KisPainter gc(paintLayer->paintDevice()); gc.bitBlt(QPoint(0, 0), image->projection(), imgSize); dst->addNode(paintLayer, KisNodeSP(0)); dst->refreshGraph(); document->setFileBatchMode(true); if (!document->exportDocumentSync(QUrl::fromLocalFile(url), mimeType.toLatin1())) { if (document->errorMessage().isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save\n%1", document->localFilePath())); } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save %1\nReason: %2", document->localFilePath(), document->errorMessage())); } return false; } delete document; return true; } void Imagesplit::slotImagesplit() { // Taking the title - url from caption function and removing file extension QStringList strList = ((m_view->document())->caption()).split('.'); QString suffix = strList.at(0); // Getting all mime types and converting them into names which are displayed at combo box QStringList listMimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Export); QString defaultMime = QString::fromLatin1(m_view->document()->mimeType()); int defaultMimeIndex = 0; listMimeFilter.sort(); QStringList filteredMimeTypes; QStringList listFileType; int i = 0; Q_FOREACH (const QString & mimeType, listMimeFilter) { listFileType.append(KisMimeDatabase::descriptionForMimeType(mimeType)); filteredMimeTypes.append(mimeType); if (mimeType == defaultMime) { defaultMimeIndex = i; } i++; } listMimeFilter = filteredMimeTypes; Q_ASSERT(listMimeFilter.size() == listFileType.size()); DlgImagesplit *dlgImagesplit = new DlgImagesplit(m_view, suffix, listFileType, defaultMimeIndex); dlgImagesplit->setObjectName("Imagesplit"); Q_CHECK_PTR(dlgImagesplit); KisImageWSP image = m_view->image(); if (dlgImagesplit->exec() == QDialog::Accepted) { int numHorizontalLines = dlgImagesplit->horizontalLines(); int numVerticalLines = dlgImagesplit->verticalLines(); int img_width = image->width() / (numVerticalLines + 1); int img_height = image->height() / (numHorizontalLines + 1); bool stop = false; if (dlgImagesplit->autoSave()) { KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::OpenDirectory, "OpenDocument"); dialog.setCaption(i18n("Save Image on Split")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); QStringList mimeFilter = m_view->document()->importExportManager()->mimeFilter(KisImportExportManager::Export); QString defaultMime = QString::fromLatin1(m_view->document()->mimeType()); dialog.setMimeTypeFilters(mimeFilter, defaultMime); QUrl directory = QUrl::fromUserInput(dialog.filename()); if (directory.isEmpty()) return; for (int i = 0, k = 1; i < (numVerticalLines + 1); i++) { for (int j = 0; j < (numHorizontalLines + 1); j++, k++) { QString mimeTypeSelected = listMimeFilter.at(dlgImagesplit->cmbIndex); QString homepath = directory.toLocalFile(); QString suffix = KisMimeDatabase::suffixesForMimeType(mimeTypeSelected).first(); qDebug() << "suffix" << suffix; if (suffix.startsWith("*.")) { suffix = suffix.remove(0, 1); } qDebug() << "\tsuffix" << suffix; if (!suffix.startsWith(".")) { suffix = suffix.prepend('.'); } qDebug() << "\tsuffix" << suffix; QString fileName = dlgImagesplit->suffix() + '_' + QString::number(k) + suffix; QString url = homepath + '/' + fileName; if (!saveAsImage(QRect((i * img_width), (j * img_height), img_width, img_height), listMimeFilter.at(dlgImagesplit->cmbIndex), url)) { stop = true; break; } } if (stop) { break; } } } else { for (int i = 0; i < (numVerticalLines + 1); i++) { for (int j = 0; j < (numHorizontalLines + 1); j++) { KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::SaveFile, "OpenDocument"); dialog.setCaption(i18n("Save Image on Split")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(listMimeFilter, defaultMime); QUrl url = QUrl::fromUserInput(dialog.filename()); QString mimefilter = KisMimeDatabase::mimeTypeForFile(url.toLocalFile()); if (url.isEmpty()) return; if (!saveAsImage(QRect((i * img_width), (j * img_height), img_width, img_height), mimefilter, url.toLocalFile())) { stop = true; break; } } if (stop) { break; } } } } delete dlgImagesplit; } #include "imagesplit.moc" diff --git a/plugins/extensions/pykrita/plugin/version_checker.h b/plugins/extensions/pykrita/plugin/version_checker.h index bfb9c2c5fb..33a32d292a 100644 --- a/plugins/extensions/pykrita/plugin/version_checker.h +++ b/plugins/extensions/pykrita/plugin/version_checker.h @@ -1,279 +1,279 @@ // This file is part of PyKrita, Krita' Python scripting plugin. // // Copyright (C) 2013 Alex Turbov // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) version 3. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; see the file COPYING.LIB. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #ifndef __VERSION_CHECKER_H__ # define __VERSION_CHECKER_H__ # include # include # include namespace PyKrita { /** * \brief Class \c version */ class version { enum type { undefined = -1 , zero = 0 }; public: /// Default constructor explicit version( const int major = zero , const int minor = zero , const int patch = zero ) : m_major(major) , m_minor(minor) , m_patch(patch) { } int major() const { return m_major; } int minor() const { return m_minor; } int patch() const { return m_patch; } bool isValid() const { return major() != undefined && minor() != undefined && patch() != undefined; } operator QString() const { return QString("%1.%2.%3").arg(major()).arg(minor()).arg(patch()); } static version fromString(const QString& version_str) { int tmp[3] = {zero, zero, zero}; QStringList parts = version_str.split('.'); for ( unsigned long i = 0 ; i < qMin(static_cast(sizeof(tmp) / sizeof(int)), static_cast(parts.size())) ; ++i ) { bool ok; const int num = parts[i].toInt(&ok); if (ok) tmp[i] = num; else { tmp[i] = undefined; break; } } return version(tmp[0], tmp[1], tmp[2]); }; static version invalid() { static version s_bad(undefined, undefined, undefined); return s_bad; } private: int m_major; int m_minor; int m_patch; }; inline bool operator==(const version& left, const version& right) { return left.major() == right.major() && left.minor() == right.minor() && left.patch() == right.patch() ; } inline bool operator!=(const version& left, const version& right) { return !(left == right); } inline bool operator<(const version& left, const version& right) { return left.major() < right.major() || (left.major() == right.major() && left.minor() < right.minor()) || (left.major() == right.major() && left.minor() == right.minor() && left.patch() < right.patch()) ; } inline bool operator>(const version& left, const version& right) { return left.major() > right.major() || (left.major() == right.major() && left.minor() > right.minor()) || (left.major() == right.major() && left.minor() == right.minor() && left.patch() > right.patch()) ; } inline bool operator<=(const version& left, const version& right) { return left == right || left < right; } inline bool operator>=(const version& left, const version& right) { return left == right || left > right; } /** * \brief Class \c version_checker */ class version_checker { public: enum operation { invalid , undefined , less , less_or_equal , greather , greather_or_equal , not_equal , equal , last__ }; /// Default constructor explicit version_checker(const operation op = invalid) : m_op(op) { } bool isValid() const { return m_op != invalid; } bool isEmpty() const { return m_op == undefined; } void bind_second(const version& rhs) { m_rhs = rhs; } bool operator()(const version& left) { switch (m_op) { case less: return left < m_rhs; case greather: return left > m_rhs; case equal: return left == m_rhs; case not_equal: return left != m_rhs; case less_or_equal: return left <= m_rhs; case greather_or_equal: return left >= m_rhs; default: Q_ASSERT(!"Sanity check"); break; } return false; } version required() const { return m_rhs; } QString operationToString() const { QString result; switch (m_op) { case less: result = " < "; break; case greather: result = " > "; break; case equal: result = " = "; break; case not_equal: result = " != "; break; case less_or_equal: result = " <= "; break; case greather_or_equal: result = " >= "; break; default: Q_ASSERT(!"Sanity check"); break; } return result; } static version_checker fromString(const QString& version_info) { version_checker checker(invalid); if (version_info.isEmpty()) return checker; bool lookup_next_char = false; int strip_lead_pos = 0; - switch (version_info.at(0).toAscii()) { + switch (version_info.at(0).toLatin1()) { case '<': checker.m_op = less; lookup_next_char = true; break; case '>': checker.m_op = greather; lookup_next_char = true; break; case '=': strip_lead_pos = 1; checker.m_op = equal; break; default: strip_lead_pos = 0; checker.m_op = equal; break; } if (lookup_next_char) { - if (version_info.at(1).toAscii() == '=') { + if (version_info.at(1).toLatin1() == '=') { // NOTE Shift state checker.m_op = operation(int(checker.m_op) + 1); strip_lead_pos = 2; } else { strip_lead_pos = 1; } } // QString rhs_str = version_info.mid(strip_lead_pos).trimmed(); version rhs = version::fromString(rhs_str); if (rhs.isValid()) checker.bind_second(rhs); else checker.m_op = invalid; return checker; } private: operation m_op; version m_rhs; }; } // namespace PyKrita #endif // __VERSION_CHECKER_H__ diff --git a/plugins/extensions/qmic/QMic.cpp b/plugins/extensions/qmic/QMic.cpp index ea27fbec84..ff26f78eb2 100644 --- a/plugins/extensions/qmic/QMic.cpp +++ b/plugins/extensions/qmic/QMic.cpp @@ -1,460 +1,460 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "QMic.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_input_output_mapper.h" #include "kis_qmic_simple_convertor.h" #include "kis_import_qmic_processing_visitor.h" #include #include "kis_qmic_applicator.h" static const char ack[] = "ack"; K_PLUGIN_FACTORY_WITH_JSON(QMicFactory, "kritaqmic.json", registerPlugin();) QMic::QMic(QObject *parent, const QVariantList &) : KisViewPlugin(parent) , m_gmicApplicator(0) { #ifndef Q_OS_MAC // KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance(); // PluginSettingsFactory* settingsFactory = new PluginSettingsFactory(); // preferenceSetRegistry->add("QMicPluginSettingsFactory", settingsFactory); m_qmicAction = createAction("QMic"); m_qmicAction->setActivationFlags(KisAction::ACTIVE_DEVICE); connect(m_qmicAction , SIGNAL(triggered()), this, SLOT(slotQMic())); m_againAction = createAction("QMicAgain"); m_againAction->setActivationFlags(KisAction::ACTIVE_DEVICE); m_againAction->setEnabled(false); connect(m_againAction, SIGNAL(triggered()), this, SLOT(slotQMicAgain())); m_gmicApplicator = new KisQmicApplicator(); connect(m_gmicApplicator, SIGNAL(gmicFinished(bool, int, QString)), this, SLOT(slotGmicFinished(bool, int, QString))); #endif } QMic::~QMic() { Q_FOREACH(QSharedMemory *memorySegment, m_sharedMemorySegments) { qDebug() << "detaching" << memorySegment->key(); memorySegment->detach(); } qDeleteAll(m_sharedMemorySegments); m_sharedMemorySegments.clear(); if (m_pluginProcess) { m_pluginProcess->close(); } delete m_gmicApplicator; delete m_localServer; } void QMic::slotQMicAgain() { slotQMic(true); } void QMic::slotQMic(bool again) { m_qmicAction->setEnabled(false); m_againAction->setEnabled(false); // find the krita-gmic-qt plugin QString pluginPath = PluginSettings::gmicQtPath(); if (pluginPath.isEmpty() || !QFileInfo(pluginPath).exists() || !QFileInfo(pluginPath).isFile()) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Krita cannot find the gmic-qt plugin.")); return; } m_key = QUuid::createUuid().toString(); m_localServer = new QLocalServer(); m_localServer->listen(m_key); connect(m_localServer, SIGNAL(newConnection()), SLOT(connected())); m_pluginProcess = new QProcess(this); m_pluginProcess->setProcessChannelMode(QProcess::ForwardedChannels); connect(m_pluginProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(pluginFinished(int,QProcess::ExitStatus))); connect(m_pluginProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(pluginStateChanged(QProcess::ProcessState))); - m_pluginProcess->start(pluginPath, QStringList() << m_key << (again ? QString(" reapply") : QString::null)); + m_pluginProcess->start(pluginPath, QStringList() << m_key << (again ? QString(" reapply") : QString())); bool r = m_pluginProcess->waitForStarted(); while (m_pluginProcess->waitForFinished(10)) { qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } qDebug() << "Plugin started" << r << m_pluginProcess->state(); } void QMic::connected() { qDebug() << "connected"; QLocalSocket *socket = m_localServer->nextPendingConnection(); if (!socket) { return; } while (socket->bytesAvailable() < static_cast(sizeof(quint32))) { if (!socket->isValid()) { // stale request return; } socket->waitForReadyRead(1000); } QDataStream ds(socket); QByteArray msg; quint32 remaining; ds >> remaining; msg.resize(remaining); int got = 0; char* uMsgBuf = msg.data(); // FIXME: Should use read transaction for Qt >= 5.7: // https://doc.qt.io/qt-5/qdatastream.html#using-read-transactions do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); if (got < 0) { qWarning() << "Message reception failed" << socket->errorString(); delete socket; m_localServer->close(); delete m_localServer; m_localServer = 0; return; } QString message = QString::fromUtf8(msg); qDebug() << "Received" << message; // Check the message: we can get three different ones QMultiMap messageMap; Q_FOREACH(QString line, message.split('\n', QString::SkipEmptyParts)) { QList kv = line.split('=', QString::SkipEmptyParts); if (kv.size() == 2) { messageMap.insert(kv[0], kv[1]); } else { qWarning() << "line" << line << "is invalid."; } } if (!messageMap.contains("command")) { qWarning() << "Message did not contain a command"; return; } int mode = 0; if (messageMap.contains("mode")) { mode = messageMap.values("mode").first().toInt(); } QByteArray ba; QString messageBoxWarningText; if (messageMap.values("command").first() == "gmic_qt_get_image_size") { KisSelectionSP selection = m_view->image()->globalSelection(); if (selection) { QRect selectionRect = selection->selectedExactRect(); ba = QByteArray::number(selectionRect.width()) + "," + QByteArray::number(selectionRect.height()); } else { ba = QByteArray::number(m_view->image()->width()) + "," + QByteArray::number(m_view->image()->height()); } } else if (messageMap.values("command").first() == "gmic_qt_get_cropped_images") { // Parse the message, create the shared memory segments, and create a new message to send back and waid for ack QRectF cropRect(0.0, 0.0, 1.0, 1.0); if (!messageMap.contains("croprect") || messageMap.values("croprect").first().split(',', QString::SkipEmptyParts).size() != 4) { qWarning() << "gmic-qt didn't send a croprect or not a valid croprect"; } else { QStringList cr = messageMap.values("croprect").first().split(',', QString::SkipEmptyParts); cropRect.setX(cr[0].toFloat()); cropRect.setY(cr[1].toFloat()); cropRect.setWidth(cr[2].toFloat()); cropRect.setHeight(cr[3].toFloat()); } if (!prepareCroppedImages(&ba, cropRect, mode)) { qWarning() << "Failed to prepare images for gmic-qt"; } } else if (messageMap.values("command").first() == "gmic_qt_output_images") { // Parse the message. read the shared memory segments, fix up the current image and send an ack qDebug() << "gmic_qt_output_images"; QStringList layers = messageMap.values("layer"); m_outputMode = (OutputMode)mode; if (m_outputMode != IN_PLACE) { messageBoxWarningText = i18n("Sorry, this output mode is not implemented yet."); m_outputMode = IN_PLACE; } slotStartApplicator(layers); } else if (messageMap.values("command").first() == "gmic_qt_detach") { Q_FOREACH(QSharedMemory *memorySegment, m_sharedMemorySegments) { qDebug() << "detaching" << memorySegment->key() << memorySegment->isAttached(); if (memorySegment->isAttached()) { if (!memorySegment->detach()) { qDebug() << "\t" << memorySegment->error() << memorySegment->errorString(); } } } qDeleteAll(m_sharedMemorySegments); m_sharedMemorySegments.clear(); } else { qWarning() << "Received unknown command" << messageMap.values("command"); } qDebug() << "Sending" << QString::fromUtf8(ba); // HACK: Make sure QDataStream does not refuse to write! // Proper fix: Change the above read to use read transaction ds.resetStatus(); ds.writeBytes(ba.constData(), ba.length()); // Flush the socket because we might not return to the event loop! if (!socket->waitForBytesWritten(2000)) { qWarning() << "Failed to write response:" << socket->error(); } // Wait for the ack bool r = true; r &= socket->waitForReadyRead(2000); // wait for ack r &= (socket->read(qstrlen(ack)) == ack); if (!socket->waitForDisconnected(2000)) { qWarning() << "Remote not disconnected:" << socket->error(); // Wait again socket->disconnectFromServer(); if (socket->waitForDisconnected(2000)) { qWarning() << "Disconnect timed out:" << socket->error(); } } if (!messageBoxWarningText.isEmpty()) { // Defer the message box to the event loop QTimer::singleShot(0, [messageBoxWarningText]() { QMessageBox::warning(KisPart::instance()->currentMainwindow(), i18nc("@title:window", "Krita"), messageBoxWarningText); }); } } void QMic::pluginStateChanged(QProcess::ProcessState state) { qDebug() << "stateChanged" << state; } void QMic::pluginFinished(int exitCode, QProcess::ExitStatus exitStatus) { qDebug() << "pluginFinished" << exitCode << exitStatus; delete m_pluginProcess; m_pluginProcess = 0; delete m_localServer; m_localServer = 0; m_qmicAction->setEnabled(true); m_againAction->setEnabled(true); } void QMic::slotGmicFinished(bool successfully, int milliseconds, const QString &msg) { qDebug() << "slotGmicFinished();" << successfully << milliseconds << msg; if (successfully) { m_gmicApplicator->finish(); } else { m_gmicApplicator->cancel(); QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("G'Mic failed, reason:") + msg); } } void QMic::slotStartApplicator(QStringList gmicImages) { qDebug() << "slotStartApplicator();" << gmicImages; // Create a vector of gmic images QVector *> images; Q_FOREACH(const QString &image, gmicImages) { QStringList parts = image.split(',', QString::SkipEmptyParts); Q_ASSERT(parts.size() == 4); QString key = parts[0]; QString layerName = QByteArray::fromHex(parts[1].toLatin1()); int spectrum = parts[2].toInt(); int width = parts[3].toInt(); int height = parts[4].toInt(); qDebug() << key << layerName << width << height; QSharedMemory m(key); if (!m.attach(QSharedMemory::ReadOnly)) { qWarning() << "Could not attach to shared memory area." << m.error() << m.errorString(); } if (m.isAttached()) { if (!m.lock()) { qDebug() << "Could not lock memeory segment" << m.error() << m.errorString(); } qDebug() << "Memory segment" << key << m.size() << m.constData() << m.data(); gmic_image *gimg = new gmic_image(); gimg->assign(width, height, 1, spectrum); gimg->name = layerName; gimg->_data = new float[width * height * spectrum * sizeof(float)]; qDebug() << "width" << width << "height" << height << "size" << width * height * spectrum * sizeof(float) << "shared memory size" << m.size(); memcpy(gimg->_data, m.constData(), width * height * spectrum * sizeof(float)); qDebug() << "created gmic image" << gimg->name << gimg->_width << gimg->_height; if (!m.unlock()) { qDebug() << "Could not unlock memeory segment" << m.error() << m.errorString(); } if (!m.detach()) { qDebug() << "Could not detach from memeory segment" << m.error() << m.errorString(); } images.append(gimg); } } qDebug() << "Got" << images.size() << "gmic images"; // Start the applicator KUndo2MagicString actionName = kundo2_i18n("Gmic filter"); KisNodeSP rootNode = m_view->image()->root(); KisInputOutputMapper mapper(m_view->image(), m_view->activeNode()); KisNodeListSP layers = mapper.inputNodes(m_inputMode); m_gmicApplicator->setProperties(m_view->image(), rootNode, images, actionName, layers); m_gmicApplicator->preview(); m_gmicApplicator->finish(); } bool QMic::prepareCroppedImages(QByteArray *message, QRectF &rc, int inputMode) { m_view->image()->lock(); m_inputMode = (InputLayerMode)inputMode; qDebug() << "prepareCroppedImages()" << QString::fromUtf8(*message) << rc << inputMode; KisInputOutputMapper mapper(m_view->image(), m_view->activeNode()); KisNodeListSP nodes = mapper.inputNodes(m_inputMode); if (nodes->isEmpty()) { m_view->image()->unlock(); return false; } for (int i = 0; i < nodes->size(); ++i) { KisNodeSP node = nodes->at(i); if (node && node->paintDevice()) { QRect cropRect; KisSelectionSP selection = m_view->image()->globalSelection(); if (selection) { cropRect = selection->selectedExactRect(); } else { cropRect = m_view->image()->bounds(); } qDebug() << "Converting node" << node->name() << cropRect; const QRectF mappedRect = KisAlgebra2D::mapToRect(cropRect).mapRect(rc); const QRect resultRect = mappedRect.toAlignedRect(); QSharedMemory *m = new QSharedMemory(QString("key_%1").arg(QUuid::createUuid().toString())); m_sharedMemorySegments.append(m); if (!m->create(resultRect.width() * resultRect.height() * 4 * sizeof(float))) { //buf.size())) { qWarning() << "Could not create shared memory segment" << m->error() << m->errorString(); return false; } m->lock(); gmic_image img; img.assign(resultRect.width(), resultRect.height(), 1, 4); img._data = reinterpret_cast(m->data()); KisQmicSimpleConvertor::convertToGmicImageFast(node->paintDevice(), &img, resultRect); message->append(m->key().toUtf8()); m->unlock(); message->append(","); message->append(node->name().toUtf8().toHex()); message->append(","); message->append(QByteArray::number(resultRect.width())); message->append(","); message->append(QByteArray::number(resultRect.height())); message->append("\n"); } } qDebug() << QString::fromUtf8(*message); m_view->image()->unlock(); return true; } #include "QMic.moc" diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp index daa5cc8abf..3f2ca1ca21 100644 --- a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp @@ -1,438 +1,438 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_create_bundle.h" #include "ui_wdgdlgcreatebundle.h" #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceBundle.h" #define ICON_SIZE 48 DlgCreateBundle::DlgCreateBundle(KisResourceBundle *bundle, QWidget *parent) : KoDialog(parent) , m_ui(new Ui::WdgDlgCreateBundle) , m_bundle(bundle) { m_page = new QWidget(); m_ui->setupUi(m_page); setMainWidget(m_page); setFixedSize(m_page->sizeHint()); setButtons(Ok | Cancel); setDefaultButton(Ok); setButtonText(Ok, i18n("Save")); connect(m_ui->bnSelectSaveLocation, SIGNAL(clicked()), SLOT(selectSaveLocation())); KoDocumentInfo info; info.updateParameters(); if (bundle) { setCaption(i18n("Edit Resource Bundle")); m_ui->lblSaveLocation->setText(QFileInfo(bundle->filename()).absolutePath()); m_ui->editBundleName->setText(bundle->name()); m_ui->editAuthor->setText(bundle->getMeta("author")); m_ui->editEmail->setText(bundle->getMeta("email")); m_ui->editLicense->setText(bundle->getMeta("license")); m_ui->editWebsite->setText(bundle->getMeta("website")); m_ui->editDescription->document()->setPlainText(bundle->getMeta("description")); m_ui->lblPreview->setPixmap(QPixmap::fromImage(bundle->image().scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation))); Q_FOREACH (const QString & resType, bundle->resourceTypes()) { if (resType == "gradients") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedGradients << res->shortFilename(); } } } else if (resType == "patterns") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPatterns << res->shortFilename(); } } } else if (resType == "brushes") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedBrushes << res->shortFilename(); } } } else if (resType == "palettes") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPalettes << res->shortFilename(); } } } else if (resType == "workspaces") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedWorkspaces << res->shortFilename(); } } } else if (resType == "paintoppresets") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPresets << res->shortFilename(); } } } } } else { setCaption(i18n("Create Resource Bundle")); KisConfig cfg; m_ui->editAuthor->setText(cfg.readEntry("BundleAuthorName", info.authorInfo("creator"))); m_ui->editEmail->setText(cfg.readEntry("BundleAuthorEmail", info.authorInfo("email"))); m_ui->editWebsite->setText(cfg.readEntry("BundleWebsite", "http://")); m_ui->editLicense->setText(cfg.readEntry("BundleLicense", "CC-BY-SA")); - m_ui->lblSaveLocation->setText(cfg.readEntry("BundleExportLocation", QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation))); + m_ui->lblSaveLocation->setText(cfg.readEntry("BundleExportLocation", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))); } m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right")); connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected())); m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left")); connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected())); m_ui->cmbResourceTypes->addItem(i18n("Brushes"), QString("brushes")); m_ui->cmbResourceTypes->addItem(i18n("Brush Presets"), QString("presets")); m_ui->cmbResourceTypes->addItem(i18n("Gradients"), QString("gradients")); m_ui->cmbResourceTypes->addItem(i18n("Patterns"), QString("patterns")); m_ui->cmbResourceTypes->addItem(i18n("Palettes"), QString("palettes")); m_ui->cmbResourceTypes->addItem(i18n("Workspaces"), QString("workspaces")); connect(m_ui->cmbResourceTypes, SIGNAL(activated(int)), SLOT(resourceTypeSelected(int))); m_ui->tableAvailable->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection); m_ui->tableSelected->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableSelected->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(m_ui->bnGetPreview, SIGNAL(clicked()), SLOT(getPreviewImage())); resourceTypeSelected(0); } DlgCreateBundle::~DlgCreateBundle() { delete m_ui; } QString DlgCreateBundle::bundleName() const { return m_ui->editBundleName->text().replace(" ", "_"); } QString DlgCreateBundle::authorName() const { return m_ui->editAuthor->text(); } QString DlgCreateBundle::email() const { return m_ui->editEmail->text(); } QString DlgCreateBundle::website() const { return m_ui->editWebsite->text(); } QString DlgCreateBundle::license() const { return m_ui->editLicense->text(); } QString DlgCreateBundle::description() const { return m_ui->editDescription->document()->toPlainText(); } QString DlgCreateBundle::saveLocation() const { return m_ui->lblSaveLocation->text(); } QString DlgCreateBundle::previewImage() const { return m_previewImage; } void DlgCreateBundle::accept() { QString name = m_ui->editBundleName->text().remove(" "); if (name.isEmpty()) { m_ui->editBundleName->setStyleSheet(QString(" border: 1px solid red")); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The resource bundle name cannot be empty.")); return; } else { QFileInfo fileInfo(m_ui->lblSaveLocation->text() + "/" + name + ".bundle"); if (fileInfo.exists() && !m_bundle) { m_ui->editBundleName->setStyleSheet("border: 1px solid red"); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("A bundle with this name already exists.")); return; } else { if (!m_bundle) { KisConfig cfg; cfg.writeEntry("BunleExportLocation", m_ui->lblSaveLocation->text()); cfg.writeEntry("BundleAuthorName", m_ui->editAuthor->text()); cfg.writeEntry("BundleAuthorEmail", m_ui->editEmail->text()); cfg.writeEntry("BundleWebsite", m_ui->editWebsite->text()); cfg.writeEntry("BundleLicense", m_ui->editLicense->text()); } KoDialog::accept(); } } } void DlgCreateBundle::selectSaveLocation() { KoFileDialog dialog(this, KoFileDialog::OpenDirectory, "resourcebundlesavelocation"); dialog.setDefaultDir(m_ui->lblSaveLocation->text()); dialog.setCaption(i18n("Select a directory to save the bundle")); QString location = dialog.filename(); m_ui->lblSaveLocation->setText(location); } void DlgCreateBundle::addSelected() { int row = m_ui->tableAvailable->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableAvailable->selectedItems()) { m_ui->tableSelected->addItem(m_ui->tableAvailable->takeItem(m_ui->tableAvailable->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.append(item->data(Qt::UserRole).toString()); } } m_ui->tableAvailable->setCurrentRow(row); } void DlgCreateBundle::removeSelected() { int row = m_ui->tableSelected->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableSelected->selectedItems()) { m_ui->tableAvailable->addItem(m_ui->tableSelected->takeItem(m_ui->tableSelected->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.removeAll(item->data(Qt::UserRole).toString()); } } m_ui->tableSelected->setCurrentRow(row); } QPixmap imageToIcon(const QImage &img) { QPixmap pixmap(ICON_SIZE, ICON_SIZE); pixmap.fill(); QImage scaled = img.scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); int x = (ICON_SIZE - scaled.width()) / 2; int y = (ICON_SIZE - scaled.height()) / 2; QPainter gc(&pixmap); gc.drawImage(x, y, scaled); gc.end(); return pixmap; } void DlgCreateBundle::resourceTypeSelected(int idx) { QString resourceType = m_ui->cmbResourceTypes->itemData(idx).toString(); m_ui->tableAvailable->clear(); m_ui->tableSelected->clear(); if (resourceType == "brushes") { KisBrushResourceServer *server = KisBrushServer::instance()->brushServer(); Q_FOREACH (KisBrushSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedBrushes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "presets") { KisPaintOpPresetResourceServer* server = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (KisPaintOpPresetSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPresets.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "gradients") { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (KoResource *res, server->resources()) { if (res->filename()!="Foreground to Transparent" && res->filename()!="Foreground to Background") { //technically we should read from the file-name whether or not the file can be opened, but this works for now. The problem is making sure that bundle-resource know where they are stored.// //dbgKrita<filename(); QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedGradients.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } } else if (resourceType == "patterns") { KoResourceServer* server = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPatterns.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "palettes") { KoResourceServer* server = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPalettes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "workspaces") { KoResourceServer* server = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedWorkspaces.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } } void DlgCreateBundle::getPreviewImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BundlePreviewImage"); dialog.setCaption(i18n("Select file to use as bundle icon")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); m_previewImage = dialog.filename(); QImage img(m_previewImage); img = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_ui->lblPreview->setPixmap(QPixmap::fromImage(img)); } diff --git a/plugins/extensions/resourcemanager/resourcemanager.cpp b/plugins/extensions/resourcemanager/resourcemanager.cpp index 67fc7091e3..fc121c8071 100644 --- a/plugins/extensions/resourcemanager/resourcemanager.cpp +++ b/plugins/extensions/resourcemanager/resourcemanager.cpp @@ -1,324 +1,324 @@ /* * resourcemanager.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "resourcemanager.h" #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_bundle_manager.h" #include "dlg_create_bundle.h" class ResourceManager::Private { public: Private() { brushServer = KisBrushServer::instance()->brushServer(false); paintopServer = KisResourceServerProvider::instance()->paintOpPresetServer(false); gradientServer = KoResourceServerProvider::instance()->gradientServer(false); patternServer = KoResourceServerProvider::instance()->patternServer(false); paletteServer = KoResourceServerProvider::instance()->paletteServer(false); workspaceServer = KisResourceServerProvider::instance()->workspaceServer(false); } KisBrushResourceServer* brushServer; KisPaintOpPresetResourceServer * paintopServer; KoResourceServer* gradientServer; KoResourceServer *patternServer; KoResourceServer* paletteServer; KoResourceServer* workspaceServer; }; K_PLUGIN_FACTORY_WITH_JSON(ResourceManagerFactory, "kritaresourcemanager.json", registerPlugin();) ResourceManager::ResourceManager(QObject *parent, const QVariantList &) : KisViewPlugin(parent) , d(new Private()) { KisAction *action = new KisAction(i18n("Import Bundles..."), this); addAction("import_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBundles())); action = new KisAction(i18n("Import Brushes..."), this); addAction("import_brushes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBrushes())); action = new KisAction(i18n("Import Gradients..."), this); addAction("import_gradients", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportGradients())); action = new KisAction(i18n("Import Palettes..."), this); addAction("import_palettes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPalettes())); action = new KisAction(i18n("Import Patterns..."), this); addAction("import_patterns", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPatterns())); action = new KisAction(i18n("Import Presets..."), this); addAction("import_presets", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPresets())); action = new KisAction(i18n("Import Workspaces..."), this); addAction("import_workspaces", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportWorkspaces())); action = new KisAction(i18n("Create Resource Bundle..."), this); addAction("create_bundle", action); connect(action, SIGNAL(triggered()), this, SLOT(slotCreateBundle())); action = new KisAction(i18n("Manage Resources..."), this); addAction("manage_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotManageBundles())); } ResourceManager::~ResourceManager() { } void ResourceManager::slotCreateBundle() { DlgCreateBundle dlgCreateBundle; if (dlgCreateBundle.exec() != QDialog::Accepted) { return; } saveBundle(dlgCreateBundle); } KisResourceBundle *ResourceManager::saveBundle(const DlgCreateBundle &dlgCreateBundle) { QString bundlePath = dlgCreateBundle.saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"; KisResourceBundle *newBundle = new KisResourceBundle(bundlePath); newBundle->addMeta("name", dlgCreateBundle.bundleName()); newBundle->addMeta("author", dlgCreateBundle.authorName()); newBundle->addMeta("email", dlgCreateBundle.email()); newBundle->addMeta("license", dlgCreateBundle.license()); newBundle->addMeta("website", dlgCreateBundle.website()); newBundle->addMeta("description", dlgCreateBundle.description()); newBundle->setThumbnail(dlgCreateBundle.previewImage()); QStringList res = dlgCreateBundle.selectedBrushes(); Q_FOREACH (const QString &r, res) { KoResource *res = d->brushServer->resourceByFilename(r).data(); newBundle->addResource("kis_brushes", res->filename(), d->brushServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGradients(); Q_FOREACH (const QString &r, res) { KoResource *res = d->gradientServer->resourceByFilename(r); newBundle->addResource("ko_gradients", res->filename(), d->gradientServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPalettes(); Q_FOREACH (const QString &r, res) { KoResource *res = d->paletteServer->resourceByFilename(r); newBundle->addResource("ko_palettes", res->filename(), d->paletteServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPatterns(); Q_FOREACH (const QString &r, res) { KoResource *res = d->patternServer->resourceByFilename(r); newBundle->addResource("ko_patterns", res->filename(), d->patternServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPresets(); Q_FOREACH (const QString &r, res) { KisPaintOpPresetSP preset = d->paintopServer->resourceByFilename(r); KoResource *res = preset.data(); newBundle->addResource("kis_paintoppresets", res->filename(), d->paintopServer->assignedTagsList(res), res->md5()); KisPaintOpSettingsSP settings = preset->settings(); if (settings->hasProperty("requiredBrushFile")) { QString brushFile = settings->getString("requiredBrushFile"); KisBrush *brush = d->brushServer->resourceByFilename(brushFile).data(); if (brush) { newBundle->addResource("kis_brushes", brushFile, d->brushServer->assignedTagsList(brush), brush->md5()); } else { qWarning() << "There is no brush with name" << brushFile; } } } res = dlgCreateBundle.selectedWorkspaces(); Q_FOREACH (const QString &r, res) { KoResource *res = d->workspaceServer->resourceByFilename(r); newBundle->addResource("kis_workspaces", res->filename(), d->workspaceServer->assignedTagsList(res), res->md5()); } newBundle->addMeta("fileName", bundlePath); newBundle->addMeta("created", QDate::currentDate().toString("dd/MM/yyyy")); if (!newBundle->save()) { QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("Could not create the new bundle.")); } else { newBundle->setValid(true); if (QDir(KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation()) != QDir(QFileInfo(bundlePath).path())) { newBundle->setFilename(KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"); } if (KisResourceServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())) { KisResourceServerProvider::instance()->resourceBundleServer()->removeResourceFromServer( KisResourceServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())); } KisResourceServerProvider::instance()->resourceBundleServer()->addResource(newBundle, true); newBundle->load(); } return newBundle; } void ResourceManager::slotManageBundles() { DlgBundleManager* dlg = new DlgBundleManager(this, m_view->actionManager()); if (dlg->exec() != QDialog::Accepted) { return; } } QStringList ResourceManager::importResources(const QString &title, const QStringList &mimes) const { KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::OpenFiles, "krita_resources"); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setCaption(title); dialog.setMimeTypeFilters(mimes); return dialog.filenames(); } void ResourceManager::slotImportBrushes() { QStringList resources = importResources(i18n("Import Brushes"), QStringList() << "image/x-gimp-brush" << "image/x-gimp-x-gimp-brush-animated" << "image/x-adobe-brushlibrary" << "image/png" << "image/svg+xml"); Q_FOREACH (const QString &res, resources) { d->brushServer->importResourceFile(res); } } void ResourceManager::slotImportPresets() { QStringList resources = importResources(i18n("Import Presets"), QStringList() << "application/x-krita-paintoppreset"); Q_FOREACH (const QString &res, resources) { d->paintopServer->importResourceFile(res); } } void ResourceManager::slotImportGradients() { QStringList resources = importResources(i18n("Import Gradients"), QStringList() << "image/svg+xml" << "application/x-gimp-gradient" << "applicaition/x-karbon-gradient"); Q_FOREACH (const QString &res, resources) { d->gradientServer->importResourceFile(res); } } void ResourceManager::slotImportBundles() { QStringList resources = importResources(i18n("Import Bundles"), QStringList() << "application/x-krita-bundle"); Q_FOREACH (const QString &res, resources) { KisResourceBundle *bundle = KisResourceServerProvider::instance()->resourceBundleServer()->createResource(res); bundle->load(); if (bundle->valid()) { if (!bundle->install()) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not install the resources for bundle %1.").arg(res)); } } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not load bundle %1.").arg(res)); } QFileInfo fi(res); QString newFilename = KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + bundle->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + QString("%1").arg(i) + bundle->defaultFileExtension()); i++; } bundle->setFilename(fileInfo.filePath()); QFile::copy(res, newFilename); KisResourceServerProvider::instance()->resourceBundleServer()->addResource(bundle, false); } } void ResourceManager::slotImportPatterns() { QStringList resources = importResources(i18n("Import Patterns"), QStringList() << "image/png" << "image/svg+xml" << "application/x-gimp-pattern" << "image/jpeg" << "image/tiff" << "image/bmp" << "image/xpg"); Q_FOREACH (const QString &res, resources) { d->patternServer->importResourceFile(res); } } void ResourceManager::slotImportPalettes() { QStringList resources = importResources(i18n("Import Palettes"), QStringList() << "image/x-gimp-color-palette"); Q_FOREACH (const QString &res, resources) { d->paletteServer->importResourceFile(res); } } void ResourceManager::slotImportWorkspaces() { QStringList resources = importResources(i18n("Import Workspaces"), QStringList() << "application/x-krita-workspace"); Q_FOREACH (const QString &res, resources) { d->workspaceServer->importResourceFile(res); } } #include "resourcemanager.moc" diff --git a/plugins/extensions/separate_channels/kis_channel_separator.cc b/plugins/extensions/separate_channels/kis_channel_separator.cc index 32859b9ead..e5b88d88d0 100644 --- a/plugins/extensions/separate_channels/kis_channel_separator.cc +++ b/plugins/extensions/separate_channels/kis_channel_separator.cc @@ -1,272 +1,272 @@ /* * This file is part of Krita * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_channel_separator.h" #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_iterator_ng.h" #include #include #include #include #include #include KisChannelSeparator::KisChannelSeparator(KisViewManager * view) : m_view(view) { } void KisChannelSeparator::separate(KoUpdater * progressUpdater, enumSepAlphaOptions alphaOps, enumSepSource sourceOps, enumSepOutput outputOps, bool downscale, bool toColor) { KisImageSP image = m_view->image(); if (!image) return; KisPaintDeviceSP src; // Use the flattened image, if required switch (sourceOps) { case ALL_LAYERS: // the content will be locked later src = image->projection(); break; case CURRENT_LAYER: src = m_view->activeDevice(); break; default: break; } if (!src) return; progressUpdater->setProgress(1); const KoColorSpace * dstCs = 0; quint32 numberOfChannels = src->channelCount(); const KoColorSpace * srcCs = src->colorSpace(); QList channels = srcCs->channels(); vKisPaintDeviceSP layers; QList::const_iterator begin = channels.constBegin(); QList::const_iterator end = channels.constEnd(); QRect rect = src->exactBounds(); image->lock(); int i = 0; for (QList::const_iterator it = begin; it != end; ++it) { KoChannelInfo * ch = (*it); if (ch->channelType() == KoChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { continue; } qint32 channelSize = ch->size(); qint32 channelPos = ch->pos(); qint32 destSize = 1; KisPaintDeviceSP dev; if (toColor) { // We don't downscale if we separate to color channels dev = new KisPaintDevice(srcCs); } else { if (channelSize == 1 || downscale) { dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), 0)); } else { dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), 0)); destSize = 2; } } dstCs = dev->colorSpace(); layers.push_back(dev); KisHLineConstIteratorSP srcIt = src->createHLineConstIteratorNG(rect.x(), rect.y(), rect.width()); KisHLineIteratorSP dstIt = dev->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); for (qint32 row = 0; row < rect.height(); ++row) { do { if (toColor) { dstCs->singleChannelPixel(dstIt->rawData(), srcIt->oldRawData(), channelPos); if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { //dstCs->setAlpha(dstIt->rawData(), srcIt->oldRawData()[srcAlphaPos], 1); dstCs->setOpacity(dstIt->rawData(), srcCs->opacityU8(srcIt->oldRawData()), 1); } else { dstCs->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } } else { // To grayscale // Decide whether we need downscaling if (channelSize == 1 && destSize == 1) { // Both 8-bit channels dstIt->rawData()[0] = srcIt->oldRawData()[channelPos]; if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { dstCs->setOpacity(dstIt->rawData(), srcCs->opacityU8(srcIt->oldRawData()), 1); } else { dstCs->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } } else if (channelSize == 2 && destSize == 2) { // Both 16-bit dstIt->rawData()[0] = srcIt->oldRawData()[channelPos]; dstIt->rawData()[1] = srcIt->oldRawData()[channelPos + 1]; if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { dstCs->setOpacity(dstIt->rawData(), srcCs->opacityU8(srcIt->oldRawData()), 1); } else { dstCs->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } } else if (channelSize != 1 && destSize == 1) { // Downscale memset(dstIt->rawData(), srcCs->scaleToU8(srcIt->oldRawData(), channelPos), 1); // XXX: Do alpha dstCs->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } else if (channelSize != 2 && destSize == 2) { // Upscale dstIt->rawData()[0] = srcCs->scaleToU8(srcIt->oldRawData(), channelPos); // XXX: Do alpha dstCs->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } } } while (dstIt->nextPixel() && srcIt->nextPixel()); dstIt->nextRow(); srcIt->nextRow(); } ++i; progressUpdater->setProgress((i * 100) / numberOfChannels); if (progressUpdater->interrupted()) { break; } } vKisPaintDeviceSP_it deviceIt = layers.begin(); progressUpdater->setProgress(100); if (!progressUpdater->interrupted()) { KisUndoAdapter * undo = image->undoAdapter(); if (outputOps == TO_LAYERS) { undo->beginMacro(kundo2_i18n("Separate Image")); } // Flatten the image if required switch (sourceOps) { case(ALL_LAYERS): image->flatten(); break; default: break; } KisNodeCommandsAdapter adapter(m_view); for (QList::const_iterator it = begin; it != end; ++it) { KoChannelInfo * ch = (*it); if (ch->channelType() == KoChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { // Don't make an separate separation of the alpha channel if the user didn't ask for it. continue; } if (outputOps == TO_LAYERS) { KisPaintLayerSP l = KisPaintLayerSP(new KisPaintLayer(image.data(), ch->name(), OPACITY_OPAQUE_U8, *deviceIt)); adapter.addNode(l.data(), image->rootLayer(), 0); } else { KoFileDialog dialog(m_view->mainWindow(), KoFileDialog::SaveFile, "OpenDocument"); dialog.setCaption(i18n("Export Layer") + '(' + ch->name() + ')'); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Export)); QUrl url = QUrl::fromUserInput(dialog.filename()); if (url.isEmpty()) return; const QString mimeType = KisMimeDatabase::mimeTypeForFile(url.toLocalFile()); KisPaintLayerSP l = KisPaintLayerSP(new KisPaintLayer(image.data(), ch->name(), OPACITY_OPAQUE_U8, *deviceIt)); QRect r = l->exactBounds(); KisDocument *d = KisPart::instance()->createDocument(); KisImageWSP dst = KisImageWSP(new KisImage(d->createUndoStore(), r.width(), r.height(), (*deviceIt)->colorSpace(), l->name())); d->setCurrentImage(dst); dst->addNode(l->clone().data(), dst->rootLayer()); d->exportDocumentSync(url, mimeType.toLatin1()); delete d; } ++deviceIt; } if (outputOps == TO_LAYERS) { undo->endMacro(); } image->unlock(); image->setModified(); } } diff --git a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp index d6c6d04a1a..c8f9da8d15 100644 --- a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp +++ b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp @@ -1,302 +1,302 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2005 C. Boemann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brightness_contrast_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include "KoColorSpace.h" #include "KoColorTransformation.h" #include "KoCompositeOp.h" #include #include "kis_config_widget.h" #include "kis_bookmarked_configuration_manager.h" #include "kis_paint_device.h" #include "widgets/kis_curve_widget.h" #include "kis_histogram.h" #include "kis_painter.h" #include #include #include KisBrightnessContrastFilterConfiguration::KisBrightnessContrastFilterConfiguration() : KisColorTransformationConfiguration("brightnesscontrast", 1) { } KisBrightnessContrastFilterConfiguration::~KisBrightnessContrastFilterConfiguration() { } void KisBrightnessContrastFilterConfiguration::fromLegacyXML(const QDomElement& root) { fromXML(root); } void KisBrightnessContrastFilterConfiguration::updateTransfer() { m_transfer = m_curve.uint16Transfer(); } void KisBrightnessContrastFilterConfiguration::setCurve(const KisCubicCurve &curve) { m_curve = curve; updateTransfer(); } const QVector& KisBrightnessContrastFilterConfiguration::transfer() const { return m_transfer; } const KisCubicCurve& KisBrightnessContrastFilterConfiguration::curve() const { return m_curve; } void KisBrightnessContrastFilterConfiguration::fromXML(const QDomElement& root) { KisCubicCurve curve; int version; version = root.attribute("version").toInt(); QDomElement e = root.firstChild().toElement(); QString attributeName; while (!e.isNull()) { if ((attributeName = e.attribute("name")) != "nTransfers") { QRegExp rx("curve(\\d+)"); if (rx.indexIn(attributeName, 0) != -1) { quint16 index = rx.cap(1).toUShort(); if (index == 0 && !e.text().isEmpty()) { /** * We are going to use first curve only */ curve.fromString(e.text()); } } } e = e.nextSiblingElement(); } setVersion(version); setCurve(curve); } /** * Inherited from KisPropertiesConfiguration */ //void KisPerChannelFilterConfiguration::fromXML(const QString& s) void KisBrightnessContrastFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { /** * * 1 * 0,0;0.5,0.5;1,1; * */ /* This is a constant for Brightness/Contranst filter */ const qint32 numTransfers = 1; root.setAttribute("version", version()); QDomElement t = doc.createElement("param"); QDomText text = doc.createTextNode(QString::number(numTransfers)); t.setAttribute("name", "nTransfers"); t.appendChild(text); root.appendChild(t); t = doc.createElement("param"); t.setAttribute("name", "curve0"); text = doc.createTextNode(m_curve.toString()); t.appendChild(text); root.appendChild(t); } /** * Inherited from KisPropertiesConfiguration */ //QString KisPerChannelFilterConfiguration::toXML() KisBrightnessContrastFilter::KisBrightnessContrastFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Brightness/Contrast curve...")) { setSupportsPainting(false); setColorSpaceIndependence(TO_LAB16); } KisConfigWidget * KisBrightnessContrastFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisBrightnessContrastConfigWidget(parent, dev); } KisFilterConfigurationSP KisBrightnessContrastFilter::factoryConfiguration() const { return new KisBrightnessContrastFilterConfiguration(); } KoColorTransformation* KisBrightnessContrastFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { const KisBrightnessContrastFilterConfiguration* configBC = dynamic_cast(config.data()); if (!configBC) return 0; KoColorTransformation * adjustment = cs->createBrightnessContrastAdjustment(configBC->transfer().constData()); return adjustment; } -KisBrightnessContrastConfigWidget::KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f) +KisBrightnessContrastConfigWidget::KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f) : KisConfigWidget(parent, f) { int i; int height; m_page = new WdgBrightnessContrast(this); QHBoxLayout * l = new QHBoxLayout(this); Q_CHECK_PTR(l); //Hide these buttons and labels as they are not implemented in 1.5 m_page->pb_more_contrast->hide(); m_page->pb_less_contrast->hide(); m_page->pb_more_brightness->hide(); m_page->pb_less_brightness->hide(); m_page->textLabelBrightness->hide(); m_page->textLabelContrast->hide(); l->addWidget(m_page, 1, Qt::AlignTop); l->setContentsMargins(0,0,0,0); height = 256; connect(m_page->curveWidget, SIGNAL(modified()), SIGNAL(sigConfigurationItemChanged())); // Create the horizontal gradient label QPixmap hgradientpix(256, 1); QPainter hgp(&hgradientpix); hgp.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (i = 0; i < 256; ++i) { hgp.setPen(QColor(i, i, i)); hgp.drawPoint(i, 0); } m_page->hgradient->setPixmap(hgradientpix); // Create the vertical gradient label QPixmap vgradientpix(1, 256); QPainter vgp(&vgradientpix); vgp.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (i = 0; i < 256; ++i) { vgp.setPen(QColor(i, i, i)); vgp.drawPoint(0, 255 - i); } m_page->vgradient->setPixmap(vgradientpix); KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); KisHistogram histogram(dev, dev->exactBounds(), producer, LINEAR); QPalette appPalette = QApplication::palette(); QPixmap pix(256, height); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); double highest = (double)histogram.calculations().getHighest(); qint32 bins = histogram.producer()->numberOfBins(); if (histogram.getHistogramType() == LINEAR) { double factor = (double)height / highest; for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(histogram.getValue(i) * factor)); } } else { double factor = (double)height / (double)log(highest); for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(log((double)histogram.getValue(i)) * factor)); } } m_page->curveWidget->setPixmap(pix); m_page->curveWidget->setBasePixmap(pix); } KisBrightnessContrastConfigWidget::~KisBrightnessContrastConfigWidget() { KoToolManager::instance()->switchBackRequested(); delete m_page; } KisPropertiesConfigurationSP KisBrightnessContrastConfigWidget::configuration() const { KisBrightnessContrastFilterConfiguration * cfg = new KisBrightnessContrastFilterConfiguration(); cfg->setCurve(m_page->curveWidget->curve()); return cfg; } void KisBrightnessContrastConfigWidget::slotDrawLine(const KoColor &color) { QColor colorNew = color.toQColor(); int i = (colorNew.red() + colorNew.green() + colorNew.blue())/3 ; QPixmap pix = m_page->curveWidget->getBasePixmap(); QPainter p(&pix); p.setPen(QPen(Qt::black, 1, Qt::SolidLine)); p.drawLine(i,0,i,255); QString label = "x:"; label.insert(2,QString(QString::number(i))); p.drawText(i,250,label); m_page->curveWidget->setPixmap(pix); } void KisBrightnessContrastConfigWidget::setView(KisViewManager *view) { connect(view->resourceProvider(), SIGNAL(sigFGColorChanged(const KoColor&)), this, SLOT(slotDrawLine(const KoColor&))); KoToolManager::instance()->switchToolTemporaryRequested("KritaSelected/KisToolColorPicker"); } void KisBrightnessContrastConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { const KisBrightnessContrastFilterConfiguration * cfg = dynamic_cast(config.data()); Q_ASSERT(cfg); m_page->curveWidget->setCurve(cfg->curve()); } diff --git a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h index b92dddac7c..955d9cfc7c 100644 --- a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h +++ b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h @@ -1,116 +1,116 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_BRIGHTNESS_CONTRAST_FILTER_H_ #define _KIS_BRIGHTNESS_CONTRAST_FILTER_H_ #include #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" #include "ui_wdg_brightness_contrast.h" #include #include #include #include #include class QWidget; class KoColorTransformation; class WdgBrightnessContrast : public QWidget, public Ui::WdgBrightnessContrast { Q_OBJECT public: WdgBrightnessContrast(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KisBrightnessContrastFilterConfiguration : public KisColorTransformationConfiguration { public: using KisFilterConfiguration::fromXML; using KisFilterConfiguration::toXML; using KisFilterConfiguration::fromLegacyXML; void fromLegacyXML(const QDomElement& root) override; void fromXML(const QDomElement& e) override; void toXML(QDomDocument& doc, QDomElement& root) const override; KisBrightnessContrastFilterConfiguration(); ~KisBrightnessContrastFilterConfiguration() override; void setCurve(const KisCubicCurve &curve) override; const QVector& transfer() const; const KisCubicCurve& curve() const override; private: void updateTransfer(); private: KisCubicCurve m_curve; QVector m_transfer; }; /** * This class affect Intensity Y of the image */ class KisBrightnessContrastFilter : public KisColorTransformationFilter { public: KisBrightnessContrastFilter(); public: KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const override; static inline KoID id() { return KoID("brightnesscontrast", i18n("Brightness / Contrast")); } KisFilterConfigurationSP factoryConfiguration() const override; KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const override; }; class KisBrightnessContrastConfigWidget : public KisConfigWidget { Q_OBJECT public: - KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); + KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); ~KisBrightnessContrastConfigWidget() override; KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; WdgBrightnessContrast * m_page; void setView(KisViewManager *view) override; public Q_SLOTS: void slotDrawLine(const KoColor &color); }; #endif diff --git a/plugins/filters/colorsfilters/kis_desaturate_filter.cpp b/plugins/filters/colorsfilters/kis_desaturate_filter.cpp index 30a48acdbf..6e3821fbae 100644 --- a/plugins/filters/colorsfilters/kis_desaturate_filter.cpp +++ b/plugins/filters/colorsfilters/kis_desaturate_filter.cpp @@ -1,121 +1,121 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_desaturate_filter.h" #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include #include #include #include #include #include #include #include #include #include #include #include "filter/kis_filter_registry.h" #include #include #include #include KisDesaturateFilter::KisDesaturateFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Desaturate...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U)); setSupportsPainting(true); } KisDesaturateFilter::~KisDesaturateFilter() { } KisConfigWidget *KisDesaturateFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisDesaturateConfigWidget(parent); } KoColorTransformation* KisDesaturateFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; if (config) { params["type"] = config->getInt("type", 0); } return cs->createColorTransformation("desaturate_adjustment", params); } KisFilterConfigurationSP KisDesaturateFilter::factoryConfiguration() const { KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 1); config->setProperty("type", 0); return config; } -KisDesaturateConfigWidget::KisDesaturateConfigWidget(QWidget * parent, Qt::WFlags f) : KisConfigWidget(parent, f) +KisDesaturateConfigWidget::KisDesaturateConfigWidget(QWidget * parent, Qt::WindowFlags f) : KisConfigWidget(parent, f) { m_page = new Ui_WdgDesaturate(); m_page->setupUi(this); m_group = new QButtonGroup(this); m_group->addButton(m_page->radioLightness, 0); m_group->addButton(m_page->radioLuminosityBT709, 1); m_group->addButton(m_page->radioLuminosityBT601, 2); m_group->addButton(m_page->radioAverage, 3); m_group->addButton(m_page->radioMin, 4); m_group->addButton(m_page->radioMax, 5); m_group->setExclusive(true); connect(m_group, SIGNAL(buttonClicked(int)), SIGNAL(sigConfigurationItemChanged())); } KisDesaturateConfigWidget::~KisDesaturateConfigWidget() { delete m_page; } KisPropertiesConfigurationSP KisDesaturateConfigWidget::configuration() const { KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(KisDesaturateFilter::id().id(), 0); c->setProperty("type", m_group->checkedId()); return c; } void KisDesaturateConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_group->button(config->getInt("type", 0))->setChecked(true); emit sigConfigurationItemChanged(); } diff --git a/plugins/filters/colorsfilters/kis_desaturate_filter.h b/plugins/filters/colorsfilters/kis_desaturate_filter.h index a2e058052b..59bf312011 100644 --- a/plugins/filters/colorsfilters/kis_desaturate_filter.h +++ b/plugins/filters/colorsfilters/kis_desaturate_filter.h @@ -1,70 +1,70 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DESATURATE_FILTER_H #define KIS_DESATURATE_FILTER_H #include #include #include #include #include "ui_wdg_desaturate.h" class KoColorSpace; class KoColorTransformation; class KisDesaturateFilter : public KisColorTransformationFilter { public: KisDesaturateFilter(); ~KisDesaturateFilter() override; public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const override; KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const override; static inline KoID id() { return KoID("desaturate", i18n("Desaturate")); } KisFilterConfigurationSP factoryConfiguration() const override; }; class KisDesaturateConfigWidget : public KisConfigWidget { Q_OBJECT public: - KisDesaturateConfigWidget(QWidget * parent, Qt::WFlags f = 0); + KisDesaturateConfigWidget(QWidget * parent, Qt::WindowFlags f = 0); ~KisDesaturateConfigWidget() override; KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; Ui_WdgDesaturate *m_page; QButtonGroup *m_group; }; #endif diff --git a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp index f197ce3eb9..44277ed32c 100644 --- a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp +++ b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp @@ -1,207 +1,207 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2 * of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_hsv_adjustment_filter.h" #include #include #include #include #include namespace { struct SliderConfig { QString m_text; int m_minimum; int m_maximum; inline void apply(QSpinBox* spinBox, QSlider* slider, QLabel* label) const { label->setText(m_text); slider->setMinimum(m_minimum); slider->setMaximum(m_maximum); spinBox->setMinimum(m_minimum); spinBox->setMaximum(m_maximum); int sliderValue = slider->value(); if (sliderValue < m_minimum || sliderValue > m_maximum) { slider->setValue((m_minimum + m_maximum) / 2); } } inline double normalize(int value) const { return (double)value / (double)m_maximum; } inline void resetSlider( QSlider* slider) const { slider->setValue(0); } }; struct WidgetSlidersConfig { SliderConfig m_sliders[3]; }; #define PERCENT_FIELD_REL(x) {x, -100, 100} #define PERCENT_FIELD_ABS(x) {x, 0, 100} #define DEGREES_FIELD_REL(x) {x, -180, 180} #define DEGREES_FIELD_ABS(x) {x, 0, 360} #define HSX_CONFIGS(x) { \ { {DEGREES_FIELD_REL(i18n("Hue:")), PERCENT_FIELD_REL(i18n("Saturation:")), PERCENT_FIELD_REL(x)} }, \ { {DEGREES_FIELD_ABS(i18n("Hue:")), PERCENT_FIELD_ABS(i18n("Saturation:")), PERCENT_FIELD_REL(x)} } \ } const WidgetSlidersConfig WIDGET_CONFIGS[][2] = { // Hue/Saturation/Value HSX_CONFIGS(i18n("Value:")), // Hue/Saturation/Lightness HSX_CONFIGS(i18n("Lightness:")), // Hue/Saturation/Intensity HSX_CONFIGS(i18n("Intensity:")), // Hue/Saturation/Luminosity HSX_CONFIGS(i18n("Luma:")), // Blue Chroma/Red Chroma/Luma {{ {PERCENT_FIELD_REL(i18n("Yellow-Blue:")), PERCENT_FIELD_REL(i18n("Green-Red:")), PERCENT_FIELD_REL(i18n("Luma:"))} }, { {PERCENT_FIELD_ABS(i18n("Yellow-Blue:")), PERCENT_FIELD_ABS(i18n("Green-Red:")), PERCENT_FIELD_REL(i18n("Luma:"))} }} }; inline const WidgetSlidersConfig& getCurrentWidgetConfig(int type, bool colorize) { return WIDGET_CONFIGS[type][colorize ? 1 : 0]; } } KisHSVAdjustmentFilter::KisHSVAdjustmentFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&HSV Adjustment...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U)); setSupportsPainting(true); } KisConfigWidget * KisHSVAdjustmentFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisHSVConfigWidget(parent); } KoColorTransformation* KisHSVAdjustmentFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; if (config) { int type = config->getInt("type", 1); bool colorize = config->getBool("colorize", false); const WidgetSlidersConfig& widgetConfig = getCurrentWidgetConfig(type, colorize); params["h"] = widgetConfig.m_sliders[0].normalize(config->getInt("h", 0)); params["s"] = widgetConfig.m_sliders[1].normalize(config->getInt("s", 0)); params["v"] = widgetConfig.m_sliders[2].normalize(config->getInt("v", 0)); params["type"] = type; params["colorize"] = colorize; params["lumaRed"] = cs->lumaCoefficients()[0]; params["lumaGreen"] = cs->lumaCoefficients()[1]; params["lumaBlue"] = cs->lumaCoefficients()[2]; } return cs->createColorTransformation("hsv_adjustment", params); } KisFilterConfigurationSP KisHSVAdjustmentFilter::factoryConfiguration() const { KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 1); config->setProperty("h", 0); config->setProperty("s", 0); config->setProperty("v", 0); config->setProperty("type", 1); config->setProperty("colorize", false); return config; } -KisHSVConfigWidget::KisHSVConfigWidget(QWidget * parent, Qt::WFlags f) : KisConfigWidget(parent, f) +KisHSVConfigWidget::KisHSVConfigWidget(QWidget * parent, Qt::WindowFlags f) : KisConfigWidget(parent, f) { m_page = new Ui_WdgHSVAdjustment(); m_page->setupUi(this); connect(m_page->cmbType, SIGNAL(activated(int)), this, SLOT(configureSliderLimitsAndLabels())); connect(m_page->chkColorize, SIGNAL(toggled(bool)), this, SLOT(configureSliderLimitsAndLabels())); connect(m_page->reset,SIGNAL(clicked(bool)),this,SLOT(resetFilter())); // connect horizontal sliders connect(m_page->hueSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->saturationSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->valueSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->hueSpinBox, SIGNAL(valueChanged(int)), m_page->hueSlider, SLOT(setValue(int))); connect(m_page->saturationSpinBox, SIGNAL(valueChanged(int)), m_page->saturationSlider, SLOT(setValue(int))); connect(m_page->valueSpinBox, SIGNAL(valueChanged(int)), m_page->valueSlider, SLOT(setValue(int))); connect(m_page->hueSlider, SIGNAL(valueChanged(int)), m_page->hueSpinBox, SLOT(setValue(int))); connect(m_page->saturationSlider, SIGNAL(valueChanged(int)), m_page->saturationSpinBox, SLOT(setValue(int))); connect(m_page->valueSlider, SIGNAL(valueChanged(int)), m_page->valueSpinBox, SLOT(setValue(int))); } KisHSVConfigWidget::~KisHSVConfigWidget() { delete m_page; } KisPropertiesConfigurationSP KisHSVConfigWidget::configuration() const { KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(KisHSVAdjustmentFilter::id().id(), 0); c->setProperty("h", m_page->hueSlider->value()); c->setProperty("s", m_page->saturationSlider->value()); c->setProperty("v", m_page->valueSlider->value()); c->setProperty("type", m_page->cmbType->currentIndex()); c->setProperty("colorize", m_page->chkColorize->isChecked()); return c; } void KisHSVConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_page->cmbType->setCurrentIndex(config->getInt("type", 1)); m_page->chkColorize->setChecked(config->getBool("colorize", false)); m_page->hueSlider->setValue(config->getInt("h", 0)); m_page->saturationSlider->setValue(config->getInt("s", 0)); m_page->valueSlider->setValue(config->getInt("v", 0)); configureSliderLimitsAndLabels(); } void KisHSVConfigWidget::configureSliderLimitsAndLabels() { const WidgetSlidersConfig& widget = getCurrentWidgetConfig(m_page->cmbType->currentIndex(), m_page->chkColorize->isChecked()); widget.m_sliders[0].apply(m_page->hueSpinBox, m_page->hueSlider, m_page->label); widget.m_sliders[1].apply(m_page->saturationSpinBox, m_page->saturationSlider, m_page->label_2); widget.m_sliders[2].apply(m_page->valueSpinBox, m_page->valueSlider, m_page->label_3); emit sigConfigurationItemChanged(); } void KisHSVConfigWidget::resetFilter() { const WidgetSlidersConfig& widget = getCurrentWidgetConfig(m_page->cmbType->currentIndex(), m_page->chkColorize->isChecked()); widget.m_sliders[0].resetSlider(m_page->hueSlider); widget.m_sliders[1].resetSlider(m_page->saturationSlider); widget.m_sliders[2].resetSlider(m_page->valueSlider); } diff --git a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h index 3afb7c14e2..2e007d42df 100644 --- a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h +++ b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h @@ -1,78 +1,78 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2 * of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_HSV_ADJUSTMENT_FILTER_H_ #define _KIS_HSV_ADJUSTMENT_FILTER_H_ #include #include "filter/kis_filter.h" #include "kis_config_widget.h" #include "ui_wdg_hsv_adjustment.h" #include "filter/kis_color_transformation_filter.h" class QWidget; class KoColorTransformation; /** * This class affect Intensity Y of the image */ class KisHSVAdjustmentFilter : public KisColorTransformationFilter { public: KisHSVAdjustmentFilter(); public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const override; KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const override; static inline KoID id() { return KoID("hsvadjustment", i18n("HSV/HSL Adjustment")); } KisFilterConfigurationSP factoryConfiguration() const override; }; class KisHSVConfigWidget : public KisConfigWidget { Q_OBJECT public: - KisHSVConfigWidget(QWidget * parent, Qt::WFlags f = 0); + KisHSVConfigWidget(QWidget * parent, Qt::WindowFlags f = 0); ~KisHSVConfigWidget() override; KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; Ui_WdgHSVAdjustment * m_page; private Q_SLOTS: void configureSliderLimitsAndLabels(); void resetFilter(); }; #endif diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp index dc31bfd439..a27240ffc1 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp @@ -1,613 +1,613 @@ /* * This file is part of Krita * * Copyright (c) 2005 C. Boemann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_perchannel_filter.h" #include #include #include #include #include #include #include #include #include "KoChannelInfo.h" #include "KoBasicHistogramProducers.h" #include "KoColorModelStandardIds.h" #include "KoColorSpace.h" #include "KoColorTransformation.h" #include "KoCompositeColorTransformation.h" #include "KoCompositeOp.h" #include "KoID.h" #include "kis_signals_blocker.h" #include "kis_bookmarked_configuration_manager.h" #include "kis_config_widget.h" #include #include #include #include #include "kis_histogram.h" #include "kis_painter.h" #include "widgets/kis_curve_widget.h" QVector getVirtualChannels(const KoColorSpace *cs) { const bool supportsLightness = cs->colorModelId() != LABAColorModelID && cs->colorModelId() != GrayAColorModelID && cs->colorModelId() != GrayColorModelID && cs->colorModelId() != AlphaColorModelID; QVector vchannels; QList sortedChannels = KoChannelInfo::displayOrderSorted(cs->channels()); if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs); } Q_FOREACH (KoChannelInfo *channel, sortedChannels) { int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels); vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs); } if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs); } return vchannels; } -KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f) +KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f) : KisConfigWidget(parent, f), m_histogram(0) { Q_ASSERT(dev); m_page = new WdgPerChannel(this); QHBoxLayout * layout = new QHBoxLayout(this); Q_CHECK_PTR(layout); layout->setContentsMargins(0,0,0,0); layout->addWidget(m_page); m_dev = dev; m_activeVChannel = 0; const KoColorSpace *targetColorSpace = dev->compositionSourceColorSpace(); // fill in the channel chooser, in the display order, but store the pixel index as well. m_virtualChannels = getVirtualChannels(targetColorSpace); const int virtualChannelCount = m_virtualChannels.size(); KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, virtualChannelCount); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_page->cmbChannel->addItem(info.name(), info.pixelIndex()); m_curves[i].setName(info.name()); } connect(m_page->cmbChannel, SIGNAL(activated(int)), this, SLOT(setActiveChannel(int))); connect((QObject*)(m_page->chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(logHistView())); // create the horizontal and vertical gradient labels m_page->hgradient->setPixmap(createGradient(Qt::Horizontal)); m_page->vgradient->setPixmap(createGradient(Qt::Vertical)); // init histogram calculator QList keys = KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(targetColorSpace); if(keys.size() > 0) { KoHistogramProducerFactory *hpf; hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0)); m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); } connect(m_page->curveWidget, SIGNAL(modified()), this, SIGNAL(sigConfigurationItemChanged())); m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, 0, 100); { KisSignalsBlocker b(m_page->curveWidget); m_page->curveWidget->setCurve(m_curves[0]); setActiveChannel(0); } } KisPerChannelConfigWidget::~KisPerChannelConfigWidget() { delete m_histogram; } inline QPixmap KisPerChannelConfigWidget::createGradient(Qt::Orientation orient /*, int invert (not used yet) */) { int width; int height; int *i, inc, col; int x = 0, y = 0; if (orient == Qt::Horizontal) { i = &x; inc = 1; col = 0; width = 256; height = 1; } else { i = &y; inc = -1; col = 255; width = 1; height = 256; } QPixmap gradientpix(width, height); QPainter p(&gradientpix); p.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (; *i < 256; (*i)++, col += inc) { p.setPen(QColor(col, col, col)); p.drawPoint(x, y); } return gradientpix; } inline QPixmap KisPerChannelConfigWidget::getHistogram() { int i; int height = 256; QPixmap pix(256, height); bool logarithmic = m_page->chkLogarithmic->isChecked(); if (logarithmic) m_histogram->setHistogramType(LOGARITHMIC); else m_histogram->setHistogramType(LINEAR); QPalette appPalette = QApplication::palette(); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QColor(appPalette.color(QPalette::Text))); p.save(); p.setOpacity(0.2); const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel]; if (m_histogram && info.type() == VirtualChannelInfo::REAL) { m_histogram->setChannel(info.pixelIndex()); double highest = (double)m_histogram->calculations().getHighest(); qint32 bins = m_histogram->producer()->numberOfBins(); if (m_histogram->getHistogramType() == LINEAR) { double factor = (double)height / highest; for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); } } else { double factor = (double)height / (double)log(highest); for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); } } } p.restore(); return pix; } #define BITS_PER_BYTE 8 #define pwr2(p) (1<curveWidget->curve(); m_activeVChannel = ch; m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); m_page->curveWidget->setPixmap(getHistogram()); m_page->cmbChannel->setCurrentIndex(m_activeVChannel); // Getting range accepted by channel VirtualChannelInfo ¤tVChannel = m_virtualChannels[m_activeVChannel]; KoChannelInfo::enumChannelValueType valueType = currentVChannel.valueType(); int order = BITS_PER_BYTE * currentVChannel.channelSize(); int maxValue = pwr2(order); int min; int max; m_page->curveWidget->dropInOutControls(); switch (valueType) { case KoChannelInfo::UINT8: case KoChannelInfo::UINT16: case KoChannelInfo::UINT32: m_shift = 0; m_scale = double(maxValue); min = 0; max = maxValue - 1; break; case KoChannelInfo::INT8: case KoChannelInfo::INT16: m_shift = 0.5; m_scale = double(maxValue); min = -maxValue / 2; max = maxValue / 2 - 1; break; case KoChannelInfo::FLOAT16: case KoChannelInfo::FLOAT32: case KoChannelInfo::FLOAT64: default: m_shift = 0; m_scale = 100.0; //Hack Alert: should be changed to float min = 0; max = 100; break; } m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, min, max); } KisPropertiesConfigurationSP KisPerChannelConfigWidget::configuration() const { int numChannels = m_virtualChannels.size(); KisPropertiesConfigurationSP cfg = new KisPerChannelFilterConfiguration(numChannels); KIS_ASSERT_RECOVER(m_activeVChannel < m_curves.size()) { return cfg; } m_curves[m_activeVChannel] = m_page->curveWidget->curve(); static_cast(cfg.data())->setCurves(m_curves); return cfg; } void KisPerChannelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { const KisPerChannelFilterConfiguration * cfg = dynamic_cast(config.data()); if (!cfg) return; if (cfg->curves().size() == 0) { /** * HACK ALERT: our configuration factory generates * default configuration with nTransfers==0. * Catching it here. Just reset all the transfers. */ const int virtualChannelCount = m_virtualChannels.size(); KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, virtualChannelCount); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_curves[i].setName(info.name()); } } else if (cfg->curves().size() != int(m_virtualChannels.size())) { warnKrita << "WARNING: trying to load a curve with incorrect number of channels!"; warnKrita << "WARNING: expected:" << m_virtualChannels.size(); warnKrita << "WARNING: got:" << cfg->curves().size(); return; } else { for (int ch = 0; ch < cfg->curves().size(); ch++) m_curves[ch] = cfg->curves()[ch]; } // HACK: we save the previous curve in setActiveChannel, so just copy it m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); setActiveChannel(0); } KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int nCh) : KisColorTransformationConfiguration("perchannel", 1) { initDefaultCurves(m_curves, nCh); updateTransfers(); } KisPerChannelFilterConfiguration::~KisPerChannelFilterConfiguration() { } bool KisPerChannelFilterConfiguration::isCompatible(const KisPaintDeviceSP dev) const { return (int)dev->compositionSourceColorSpace()->channelCount() == m_curves.size(); } void KisPerChannelFilterConfiguration::setCurves(QList &curves) { m_curves.clear(); m_curves = curves; updateTransfers(); } void KisPerChannelFilterConfiguration::initDefaultCurves(QList &curves, int nCh) { curves.clear(); for (int i = 0; i < nCh; i++) { curves.append(KisCubicCurve()); } } void KisPerChannelFilterConfiguration::updateTransfers() { m_transfers.resize(m_curves.size()); for (int i = 0; i < m_curves.size(); i++) { m_transfers[i] = m_curves[i].uint16Transfer(); } } const QVector >& KisPerChannelFilterConfiguration::transfers() const { return m_transfers; } const QList& KisPerChannelFilterConfiguration::curves() const { return m_curves; } void KisPerChannelFilterConfiguration::fromLegacyXML(const QDomElement& root) { fromXML(root); } void KisPerChannelFilterConfiguration::fromXML(const QDomElement& root) { QList curves; quint16 numTransfers = 0; int version; version = root.attribute("version").toInt(); QDomElement e = root.firstChild().toElement(); QString attributeName; KisCubicCurve curve; quint16 index; while (!e.isNull()) { if ((attributeName = e.attribute("name")) == "nTransfers") { numTransfers = e.text().toUShort(); } else { QRegExp rx("curve(\\d+)"); if (rx.indexIn(attributeName, 0) != -1) { index = rx.cap(1).toUShort(); index = qMin(index, quint16(curves.count())); if (!e.text().isEmpty()) { curve.fromString(e.text()); } curves.insert(index, curve); } } e = e.nextSiblingElement(); } if (!numTransfers) return; setVersion(version); setCurves(curves); } /** * Inherited from KisPropertiesConfiguration */ //void KisPerChannelFilterConfiguration::fromXML(const QString& s) void addParamNode(QDomDocument& doc, QDomElement& root, const QString &name, const QString &value) { QDomText text = doc.createTextNode(value); QDomElement t = doc.createElement("param"); t.setAttribute("name", name); t.appendChild(text); root.appendChild(t); } void KisPerChannelFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { /** * * 3 * 0,0;0.5,0.5;1,1; * 0,0;1,1; * 0,0;1,1; * */ root.setAttribute("version", version()); QDomText text; QDomElement t; addParamNode(doc, root, "nTransfers", QString::number(m_curves.size())); KisCubicCurve curve; QString paramName; for (int i = 0; i < m_curves.size(); ++i) { QString name = QLatin1String("curve") + QString::number(i); QString value = m_curves[i].toString(); addParamNode(doc, root, name, value); } } /** * Inherited from KisPropertiesConfiguration */ //QString KisPerChannelFilterConfiguration::toXML() KisPerChannelFilter::KisPerChannelFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Color Adjustment curves...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M)); setSupportsPainting(true); setColorSpaceIndependence(TO_LAB16); } KisConfigWidget * KisPerChannelFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisPerChannelConfigWidget(parent, dev); } KisFilterConfigurationSP KisPerChannelFilter::factoryConfiguration() const { return new KisPerChannelFilterConfiguration(0); } KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { const KisPerChannelFilterConfiguration* configBC = dynamic_cast(config.data()); // Somehow, this shouldn't happen Q_ASSERT(configBC); const QVector > &originalTransfers = configBC->transfers(); const QList &originalCurves = configBC->curves(); /** * TODO: What about the order of channels? (DK) * * Virtual channels are sorted in display order, does Lcms accepts * transforms in display order? Why on Earth it works?! Is it * documented anywhere? */ const QVector virtualChannels = getVirtualChannels(cs); if (originalTransfers.size() != int(virtualChannels.size())) { // We got an illegal number of colorchannels :( return 0; } bool colorsNull = true; bool lightnessNull = true; bool allColorsNull = true; int alphaIndexInReal = -1; QVector > realTransfers; QVector lightnessTransfer; QVector allColorsTransfer; for (int i = 0; i < virtualChannels.size(); i++) { if (virtualChannels[i].type() == VirtualChannelInfo::REAL) { realTransfers << originalTransfers[i]; if (virtualChannels[i].isAlpha()) { alphaIndexInReal = realTransfers.size() - 1; } if (colorsNull && !originalCurves[i].isNull()) { colorsNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) { KIS_ASSERT_RECOVER_NOOP(lightnessTransfer.isEmpty()); lightnessTransfer = originalTransfers[i]; if (lightnessNull && !originalCurves[i].isNull()) { lightnessNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::ALL_COLORS) { KIS_ASSERT_RECOVER_NOOP(allColorsTransfer.isEmpty()); allColorsTransfer = originalTransfers[i]; if (allColorsNull && !originalCurves[i].isNull()) { allColorsNull = false; } } } KoColorTransformation *lightnessTransform = 0; KoColorTransformation *allColorsTransform = 0; KoColorTransformation *colorTransform = 0; if (!colorsNull) { const quint16** transfers = new const quint16*[realTransfers.size()]; for(int i = 0; i < realTransfers.size(); ++i) { transfers[i] = realTransfers[i].constData(); /** * createPerChannelAdjustment() expects alpha channel to * be the last channel in the list, so just it here */ KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal || alphaIndexInReal == (realTransfers.size() - 1)); } colorTransform = cs->createPerChannelAdjustment(transfers); delete [] transfers; } if (!lightnessNull) { lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTransfer.constData()); } if (!allColorsNull) { const quint16** allColorsTransfers = new const quint16*[realTransfers.size()]; for(int i = 0; i < realTransfers.size(); ++i) { allColorsTransfers[i] = (i != alphaIndexInReal) ? allColorsTransfer.constData() : 0; /** * createPerChannelAdjustment() expects alpha channel to * be the last channel in the list, so just it here */ KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal || alphaIndexInReal == (realTransfers.size() - 1)); } allColorsTransform = cs->createPerChannelAdjustment(allColorsTransfers); delete[] allColorsTransfers; } QVector allTransforms; allTransforms << colorTransform; allTransforms << allColorsTransform; allTransforms << lightnessTransform; return KoCompositeColorTransformation::createOptimizedCompositeTransform(allTransforms); } bool KisPerChannelFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); return cs->colorModelId() == AlphaColorModelID; } void KisPerChannelConfigWidget::logHistView() { m_page->curveWidget->setPixmap(getHistogram()); } diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.h b/plugins/filters/colorsfilters/kis_perchannel_filter.h index 4844503100..044d618621 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.h +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.h @@ -1,136 +1,136 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_PERCHANNEL_FILTER_H_ #define _KIS_PERCHANNEL_FILTER_H_ #include #include #include #include #include #include #include "ui_wdg_perchannel.h" #include "virtual_channel_info.h" class WdgPerChannel : public QWidget, public Ui::WdgPerChannel { Q_OBJECT public: WdgPerChannel(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KisPerChannelFilterConfiguration : public KisColorTransformationConfiguration { public: KisPerChannelFilterConfiguration(int n); ~KisPerChannelFilterConfiguration() override; using KisFilterConfiguration::fromXML; using KisFilterConfiguration::toXML; using KisFilterConfiguration::fromLegacyXML; void fromLegacyXML(const QDomElement& root) override; void fromXML(const QDomElement& e) override; void toXML(QDomDocument& doc, QDomElement& root) const override; void setCurves(QList &curves) override; static inline void initDefaultCurves(QList &curves, int nCh); bool isCompatible(const KisPaintDeviceSP) const override; const QVector >& transfers() const; const QList& curves() const override; private: QList m_curves; private: void updateTransfers(); private: QVector > m_transfers; }; /** * This class is generic for filters that affect channel separately */ class KisPerChannelFilter : public KisColorTransformationFilter { public: KisPerChannelFilter(); public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const override; KisFilterConfigurationSP factoryConfiguration() const override; KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const override; bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const override; static inline KoID id() { return KoID("perchannel", i18n("Color Adjustment")); } private: }; class KisPerChannelConfigWidget : public KisConfigWidget { Q_OBJECT public: - KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); + KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); ~KisPerChannelConfigWidget() override; void setConfiguration(const KisPropertiesConfigurationSP config) override; KisPropertiesConfigurationSP configuration() const override; private Q_SLOTS: virtual void setActiveChannel(int ch); void logHistView(); private: QVector m_virtualChannels; int m_activeVChannel; // private routines inline QPixmap getHistogram(); inline QPixmap createGradient(Qt::Orientation orient /*, int invert (not used now) */); // members WdgPerChannel * m_page; KisPaintDeviceSP m_dev; KisHistogram *m_histogram; mutable QList m_curves; // scales for displaying color numbers double m_scale; double m_shift; }; #endif diff --git a/plugins/filters/gradientmap/gradientmap.cpp b/plugins/filters/gradientmap/gradientmap.cpp index 983ccbfae4..e9e74cb7f4 100644 --- a/plugins/filters/gradientmap/gradientmap.cpp +++ b/plugins/filters/gradientmap/gradientmap.cpp @@ -1,126 +1,126 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Spencer Brown * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "QObject" #include "gradientmap.h" #include #include #include "krita_filter_gradient_map.h" #include "KoResourceServerProvider.h" #include "kis_config_widget.h" #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KritaGradientMapFactory, "kritagradientmap.json", registerPlugin();) -KritaGradientMapConfigWidget::KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WFlags f) +KritaGradientMapConfigWidget::KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WindowFlags f) : KisConfigWidget(parent, f) { Q_UNUSED(dev) m_page = new WdgGradientMap(this); QHBoxLayout *l = new QHBoxLayout(this); Q_CHECK_PTR(l); l->addWidget(m_page); l->setContentsMargins(0, 0, 0, 0); KoResourceServerProvider *serverProvider = KoResourceServerProvider::instance(); QSharedPointer gradientResourceAdapter( new KoResourceServerAdapter(serverProvider->gradientServer())); m_gradientChangedCompressor = new KisSignalCompressor(100, KisSignalCompressor::FIRST_ACTIVE); m_gradientPopUp = new KoResourcePopupAction(gradientResourceAdapter, m_page->btnGradientChooser); m_activeGradient = KoStopGradient::fromQGradient(dynamic_cast(gradientResourceAdapter->resources().first())->toQGradient()); m_page->gradientEditor->setGradient(m_activeGradient); m_page->gradientEditor->setCompactMode(true); m_page->gradientEditor->setEnabled(true); m_page->btnGradientChooser->setDefaultAction(m_gradientPopUp); m_page->btnGradientChooser->setPopupMode(QToolButton::InstantPopup); connect(m_gradientPopUp, SIGNAL(resourceSelected(QSharedPointer)), this, SLOT(setAbstractGradientToEditor())); connect(m_page->gradientEditor, SIGNAL(sigGradientChanged()), m_gradientChangedCompressor, SLOT(start())); connect(m_gradientChangedCompressor, SIGNAL(timeout()), this, SIGNAL(sigConfigurationItemChanged())); } KritaGradientMapConfigWidget::~KritaGradientMapConfigWidget() { delete m_page; } void KritaGradientMapConfigWidget::setAbstractGradientToEditor() { QSharedPointer bg = qSharedPointerDynamicCast( m_gradientPopUp->currentBackground()); m_activeGradient = KoStopGradient::fromQGradient(bg->gradient()); m_page->gradientEditor->setGradient(m_activeGradient); } KisPropertiesConfigurationSP KritaGradientMapConfigWidget::configuration() const { KisFilterConfigurationSP cfg = new KisFilterConfiguration("gradientmap", 2); if (m_activeGradient) { QDomDocument doc; QDomElement elt = doc.createElement("gradient"); m_activeGradient->toXML(doc, elt); doc.appendChild(elt); cfg->setProperty("gradientXML", doc.toString()); } return cfg; } //----------------------------- void KritaGradientMapConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { Q_ASSERT(config); QDomDocument doc; if (config->hasProperty("gradientXML")) { doc.setContent(config->getString("gradientXML", "")); qDebug()<getString("gradientXML", ""); KoStopGradient gradient = KoStopGradient::fromXML(doc.firstChildElement()); if (gradient.stops().size()>0) { m_activeGradient->setStops(gradient.stops()); } } } void KritaGradientMapConfigWidget::setView(KisViewManager *view) { Q_UNUSED(view) } //------------------------------ KritaGradientMap::KritaGradientMap(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KritaFilterGradientMap())); } KritaGradientMap::~KritaGradientMap() { } //----------------------------- #include "gradientmap.moc" diff --git a/plugins/filters/gradientmap/gradientmap.h b/plugins/filters/gradientmap/gradientmap.h index fa5fcbebdb..bcaf3eaa29 100644 --- a/plugins/filters/gradientmap/gradientmap.h +++ b/plugins/filters/gradientmap/gradientmap.h @@ -1,83 +1,83 @@ /* * This file is part of Krita * * Copyright (c) 2016 Spencer Brown * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "QObject" #include "ui_wdg_gradientmap.h" #include "kis_properties_configuration.h" #include "filter/kis_color_transformation_configuration.h" #include "kis_config_widget.h" #include #include #include class WdgGradientMap : public QWidget, public Ui::WdgGradientMap { Q_OBJECT public: WdgGradientMap(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KritaGradientMapFilterConfiguration : public KisColorTransformationConfiguration { public: KritaGradientMapFilterConfiguration(); ~KritaGradientMapFilterConfiguration() override; virtual void setGradient(const KoResource* gradient); virtual const KoResource* gradient() const; private: KoResource const* m_gradient; }; class KritaGradientMapConfigWidget : public KisConfigWidget { Q_OBJECT public: - KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); + KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); ~KritaGradientMapConfigWidget() override; KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; WdgGradientMap *m_page; KoResourcePopupAction *m_gradientPopUp; KisSignalCompressor *m_gradientChangedCompressor; KoStopGradient *m_activeGradient; void setView(KisViewManager *view) override; private Q_SLOTS: void setAbstractGradientToEditor(); }; class KritaGradientMap : public QObject { Q_OBJECT public: KritaGradientMap(QObject *parent, const QVariantList &); ~KritaGradientMap() override; }; diff --git a/plugins/filters/indexcolors/kiswdgindexcolors.cpp b/plugins/filters/indexcolors/kiswdgindexcolors.cpp index fd2659e8aa..51ce63d45b 100644 --- a/plugins/filters/indexcolors/kiswdgindexcolors.cpp +++ b/plugins/filters/indexcolors/kiswdgindexcolors.cpp @@ -1,192 +1,192 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #include "filter/kis_color_transformation_configuration.h" #include "kiswdgindexcolors.h" #include "palettegeneratorconfig.h" #include "ui_kiswdgindexcolors.h" #include "kis_int_parse_spin_box.h" #include -KisWdgIndexColors::KisWdgIndexColors(QWidget* parent, Qt::WFlags f, int delay): KisConfigWidget(parent, f, delay) +KisWdgIndexColors::KisWdgIndexColors(QWidget* parent, Qt::WindowFlags f, int delay): KisConfigWidget(parent, f, delay) { ui = new Ui::KisWdgIndexColors; ui->setupUi(this); connect(ui->diagCheck, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(ui->inbetweenSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->alphaStepsSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->colorLimit, SIGNAL(valueChanged(int)), SLOT(slotColorLimitChanged(int))); connect(ui->colorLimit, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->colorLimitCheck, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(ui->luminanceSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->aSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->bSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); } void KisWdgIndexColors::slotColorLimitChanged(int value) { ui->colorLimit->setSuffix(i18ncp("suffix for a spinbox", " color", " colors", value)); } void KisWdgIndexColors::setup(QStringList shadesLabels, int ramps) { int rows = shadesLabels.length(); int collumns = ramps; m_colorSelectors.resize(rows); m_stepSpinners.resize(rows-1); // Labels for the shades for(int row = 0; row < rows; ++row) { QLabel* l = new QLabel(shadesLabels[row], ui->colorsBox); ui->layoutColors->addWidget(l, row+1, 0); m_colorSelectors[row].resize(collumns); } // Labels for the ramps /*for(int col = 0; col < collumns; ++col) { QLabel* l = new QLabel(rampsLabels[col], ui->colorsBox); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ui->layoutColors->addWidget(l, 0, col+1); }*/ // Step selectors for the shade gradients for(int row = 0; row < (rows-1); ++row) { QLabel* l0 = new QLabel(shadesLabels[row+1]); QLabel* l1 = new QLabel(QString::fromUtf8("↔")); QLabel* l2 = new QLabel(shadesLabels[row]); QSpinBox* s = new KisIntParseSpinBox(); s->setMinimum(0); s->setMaximum(32); s->setValue(2); connect(s, SIGNAL(valueChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); m_stepSpinners[row] = s; ui->layoutRowSteps->addWidget(l0, row, 0); ui->layoutRowSteps->addWidget(l1, row, 1); ui->layoutRowSteps->addWidget(l2, row, 2); ui->layoutRowSteps->addWidget(s, row, 3); } // Color selectors for(int y = 0; y < rows; ++y) for(int x = 0; x < collumns; ++x) { KisColorButton* b = new KisColorButton; QCheckBox* c = new QCheckBox; c->setChecked(false); b->setEnabled(false); b->setMaximumWidth(50); c->setMaximumWidth(21); // Ugh. I hope this won't be causing any issues. Trying to get rid of the unnecessary spacing after it. connect(c, SIGNAL(toggled(bool)), b, SLOT(setEnabled(bool))); connect(c, SIGNAL(toggled(bool)), this, SIGNAL(sigConfigurationItemChanged())); connect(b, SIGNAL(changed(KoColor)), this, SIGNAL(sigConfigurationItemChanged())); QHBoxLayout* cell = new QHBoxLayout(); cell->setSpacing(0); cell->setContentsMargins(0, 0, 0, 0); cell->addWidget(c); cell->addWidget(b); ui->layoutColors->addLayout(cell, 1+y, 1+x); m_colorSelectors[y][x].button = b; m_colorSelectors[y][x].checkbox = c; } } KisPropertiesConfigurationSP KisWdgIndexColors::configuration() const { KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration("indexcolors", 1); PaletteGeneratorConfig palCfg; for(int y = 0; y < 4; ++y) for(int x = 0; x < 4; ++x) { palCfg.colors[y][x] = m_colorSelectors[y][x].button->color().toQColor(); palCfg.colorsEnabled[y][x] = m_colorSelectors[y][x].button->isEnabled(); } for(int y = 0; y < 3; ++y) palCfg.gradientSteps[y] = m_stepSpinners[y]->value(); palCfg.diagonalGradients = ui->diagCheck->isChecked(); palCfg.inbetweenRampSteps = ui->inbetweenSpinBox->value(); IndexColorPalette pal = palCfg.generate(); ui->colorCount->setText(QString::number(pal.numColors())); config->setProperty("paletteGen", palCfg.toByteArray()); config->setProperty("LFactor", ui->luminanceSlider->value() / 100.f); config->setProperty("aFactor", ui->aSlider->value() / 100.f); config->setProperty("bFactor", ui->bSlider->value() / 100.f); config->setProperty("reduceColorsEnabled", ui->colorLimitCheck->isChecked()); config->setProperty("colorLimit", ui->colorLimit->value()); config->setProperty("alphaSteps", ui->alphaStepsSpinBox->value()); return config; } void KisWdgIndexColors::setConfiguration(const KisPropertiesConfigurationSP config) { PaletteGeneratorConfig palCfg; palCfg.fromByteArray(config->getProperty("paletteGen").toByteArray()); ui->luminanceSlider->setValue(config->getFloat("LFactor")*100); ui->aSlider->setValue(config->getFloat("aFactor")*100); ui->bSlider->setValue(config->getFloat("bFactor")*100); ui->alphaStepsSpinBox->setValue(config->getInt("alphaSteps")); ui->colorLimitCheck->setChecked(config->getBool("reduceColorsEnabled")); ui->colorLimit->setEnabled(config->getBool("reduceColorsEnabled")); ui->colorLimit->setValue(config->getInt("colorLimit")); ui->diagCheck->setChecked(palCfg.diagonalGradients); ui->inbetweenSpinBox->setValue(palCfg.inbetweenRampSteps); for(int y = 0; y < 4; ++y) for(int x = 0; x < 4; ++x) { m_colorSelectors[y][x].checkbox->setChecked(palCfg.colorsEnabled[y][x]); m_colorSelectors[y][x].button->setEnabled(palCfg.colorsEnabled[y][x]); KoColor c; c.fromQColor(palCfg.colors[y][x]); m_colorSelectors[y][x].button->setColor(c); } for(int y = 0; y < 3; ++y) m_stepSpinners[y]->setValue(palCfg.gradientSteps[y]); IndexColorPalette pal = palCfg.generate(); ui->colorCount->setText(QString::number(pal.numColors())); } diff --git a/plugins/filters/indexcolors/kiswdgindexcolors.h b/plugins/filters/indexcolors/kiswdgindexcolors.h index 902f9a73af..bb997290f3 100644 --- a/plugins/filters/indexcolors/kiswdgindexcolors.h +++ b/plugins/filters/indexcolors/kiswdgindexcolors.h @@ -1,59 +1,59 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #ifndef KISWDGINDEXCOLORS_H #define KISWDGINDEXCOLORS_H #include #include class QCheckBox; class KisColorButton; namespace Ui { class KisWdgIndexColors; } class KisWdgIndexColors : public KisConfigWidget { Q_OBJECT public: - KisWdgIndexColors(QWidget* parent = 0, Qt::WFlags f = 0, int delay = 500); + KisWdgIndexColors(QWidget* parent = 0, Qt::WindowFlags f = 0, int delay = 500); KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; void setup(QStringList shadesLabels, int ramps); private Q_SLOTS: void slotColorLimitChanged(int value); private: struct ColorWidgets { KisColorButton* button; QCheckBox* checkbox; }; QVector< QVector > m_colorSelectors; QVector< QSpinBox* > m_stepSpinners; Ui::KisWdgIndexColors* ui; }; #endif // KISWDGINDEXCOLORS_H diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp index de3399d0cd..d0011fe093 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp @@ -1,186 +1,186 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_phong_bumpmap_config_widget.h" #include #include #include "phong_bumpmap_constants.h" #include "KoChannelInfo.h" #include "KoColorSpace.h" -KisPhongBumpmapConfigWidget::KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WFlags f) +KisPhongBumpmapConfigWidget::KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WindowFlags f) : KisConfigWidget(parent, f) , m_device(dev) { Q_ASSERT(m_device); m_page = new KisPhongBumpmapWidget(this); KisSizeGroup *matPropLabelsGroup = new KisSizeGroup(this); matPropLabelsGroup->addWidget(m_page->lblAmbientReflectivity); matPropLabelsGroup->addWidget(m_page->lblDiffuseReflectivity); matPropLabelsGroup->addWidget(m_page->lblSpecularReflectivity); matPropLabelsGroup->addWidget(m_page->lblSpecularShinyExp); // Connect widgets to each other connect(m_page->azimuthDial1, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox1, SLOT(setValue(int))); connect(m_page->azimuthDial2, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox2, SLOT(setValue(int))); connect(m_page->azimuthDial3, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox3, SLOT(setValue(int))); connect(m_page->azimuthDial4, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox4, SLOT(setValue(int))); connect(m_page->azimuthSpinBox1, SIGNAL(valueChanged(int)), m_page->azimuthDial1, SLOT(setValue(int))); connect(m_page->azimuthSpinBox2, SIGNAL(valueChanged(int)), m_page->azimuthDial2, SLOT(setValue(int))); connect(m_page->azimuthSpinBox3, SIGNAL(valueChanged(int)), m_page->azimuthDial3, SLOT(setValue(int))); connect(m_page->azimuthSpinBox4, SIGNAL(valueChanged(int)), m_page->azimuthDial4, SLOT(setValue(int))); //Let widgets warn the preview of when they are updated connect(m_page->azimuthDial1, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial2, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial3, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial4, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo1, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo2, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo3, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo4, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox1, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox2, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox3, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox4, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->useNormalMap, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->diffuseReflectivityGroup, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->specularReflectivityGroup, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->ambientReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->diffuseReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->specularReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->shinynessExponentKisSliderSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->heightChannelComboBox, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox1, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox2, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox3, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox4, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); QVBoxLayout *l = new QVBoxLayout(this); Q_CHECK_PTR(l); l->addWidget(m_page); /* fill in the channel chooser */ QList channels = m_device->colorSpace()->channels(); for (quint8 ch = 0; ch < m_device->colorSpace()->colorChannelCount(); ch++) m_page->heightChannelComboBox->addItem(channels.at(ch)->name()); connect(m_page->useNormalMap, SIGNAL(toggled(bool)), this, SLOT(slotDisableHeightChannelCombobox(bool) ) ); } void KisPhongBumpmapConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { if (!config) return; QVariant tempcolor; if (config->getBool(USE_NORMALMAP_IS_ENABLED)) { m_page->heightChannelComboBox->setEnabled(false); } else { m_page->heightChannelComboBox->setEnabled(true); } m_page->ambientReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_AMBIENT_REFLECTIVITY) ); m_page->diffuseReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_DIFFUSE_REFLECTIVITY) ); m_page->specularReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_SPECULAR_REFLECTIVITY) ); m_page->shinynessExponentKisSliderSpinBox->setValue( config->getInt(PHONG_SHINYNESS_EXPONENT) ); m_page->useNormalMap->setChecked( config->getBool(USE_NORMALMAP_IS_ENABLED) ); m_page->diffuseReflectivityGroup->setChecked( config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED) ); m_page->specularReflectivityGroup->setChecked( config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED) ); // NOTE: Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 m_page->lightSourceGroupBox1->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[0]) ); m_page->lightSourceGroupBox2->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[1]) ); m_page->lightSourceGroupBox3->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[2]) ); m_page->lightSourceGroupBox4->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[3]) ); config->getProperty(PHONG_ILLUMINANT_COLOR[0], tempcolor); m_page->lightKColorCombo1->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[1], tempcolor); m_page->lightKColorCombo2->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[2], tempcolor); m_page->lightKColorCombo3->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[3], tempcolor); m_page->lightKColorCombo4->setColor(tempcolor.value()); m_page->azimuthSpinBox1->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[0]) ); m_page->azimuthSpinBox2->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[1]) ); m_page->azimuthSpinBox3->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[2]) ); m_page->azimuthSpinBox4->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[3]) ); m_page->inclinationSpinBox1->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[0]) ); m_page->inclinationSpinBox2->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[1]) ); m_page->inclinationSpinBox3->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[2]) ); m_page->inclinationSpinBox4->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[3]) ); } KisPropertiesConfigurationSP KisPhongBumpmapConfigWidget::configuration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("phongbumpmap", 2); config->setProperty(PHONG_HEIGHT_CHANNEL, m_page->heightChannelComboBox->currentText()); config->setProperty(USE_NORMALMAP_IS_ENABLED, m_page->useNormalMap->isChecked()); config->setProperty(PHONG_AMBIENT_REFLECTIVITY, m_page->ambientReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY, m_page->diffuseReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_SPECULAR_REFLECTIVITY, m_page->specularReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_SHINYNESS_EXPONENT, m_page->shinynessExponentKisSliderSpinBox->value()); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED, m_page->diffuseReflectivityGroup->isChecked()); config->setProperty(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED, m_page->specularReflectivityGroup->isChecked()); //config->setProperty(PHONG_SHINYNESS_EXPONENT_IS_ENABLED, m_page->specularReflectivityCheckBox->isChecked()); // Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[0], m_page->lightSourceGroupBox1->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[1], m_page->lightSourceGroupBox2->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[2], m_page->lightSourceGroupBox3->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[3], m_page->lightSourceGroupBox4->isChecked()); config->setProperty(PHONG_ILLUMINANT_COLOR[0], m_page->lightKColorCombo1->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[1], m_page->lightKColorCombo2->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[2], m_page->lightKColorCombo3->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[3], m_page->lightKColorCombo4->color()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[0], m_page->azimuthSpinBox1->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[1], m_page->azimuthSpinBox2->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[2], m_page->azimuthSpinBox3->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[3], m_page->azimuthSpinBox4->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[0], m_page->inclinationSpinBox1->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[1], m_page->inclinationSpinBox2->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[2], m_page->inclinationSpinBox3->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[3], m_page->inclinationSpinBox4->value()); // Read configuration /* QMap rofl = QMap(config->getProperties()); QMap::const_iterator i; for (i = rofl.constBegin(); i != rofl.constEnd(); ++i) dbgKrita << i.key() << ":" << i.value(); */ return config; } void KisPhongBumpmapConfigWidget::slotDisableHeightChannelCombobox(bool normalmapchecked) { if (normalmapchecked) { m_page->heightChannelComboBox->setEnabled(false); } else { m_page->heightChannelComboBox->setEnabled(true); } } diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h index aed4fe678b..7367ca4b5d 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h @@ -1,66 +1,66 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PHONG_BUMPMAP_CONFIG_WIDGET_H #define KIS_PHONG_BUMPMAP_CONFIG_WIDGET_H #include "ui_wdgphongbumpmap.h" #include "kis_paint_device.h" #include "kis_config_widget.h" #include "kis_image.h" class KisPhongBumpmapWidget : public QWidget, public Ui::WdgPhongBumpmap { Q_OBJECT public: KisPhongBumpmapWidget(QWidget *parent) : QWidget(parent) { setupUi(this); ambientReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); diffuseReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); specularReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); shinynessExponentKisSliderSpinBox -> setRange(1, 200); ambientReflectivityKisDoubleSliderSpinBox -> setValue(0.1); diffuseReflectivityKisDoubleSliderSpinBox -> setValue(0.5); specularReflectivityKisDoubleSliderSpinBox -> setValue(0.5); shinynessExponentKisSliderSpinBox -> setValue(40); } }; class KisPhongBumpmapConfigWidget : public KisConfigWidget { Q_OBJECT public: - KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WFlags f = 0); + KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WindowFlags f = 0); ~KisPhongBumpmapConfigWidget() override {} void setConfiguration(const KisPropertiesConfigurationSP config) override; KisPropertiesConfigurationSP configuration() const override; KisPhongBumpmapWidget *m_page; private: KisPaintDeviceSP m_device; private Q_SLOTS: void slotDisableHeightChannelCombobox(bool normalmapchecked); }; #endif //KIS_PHONG_BUMPMAP_CONFIG_WIDGET_H diff --git a/plugins/flake/textshape/CMakeLists.txt b/plugins/flake/textshape/CMakeLists.txt index c0999ed2fc..fe40faaa7e 100644 --- a/plugins/flake/textshape/CMakeLists.txt +++ b/plugins/flake/textshape/CMakeLists.txt @@ -1,160 +1,170 @@ project( textPlugin) +remove_definitions( + -DQT_DISABLE_DEPRECATED_BEFORE=0x50900 +) + +add_definitions( + -DQT_DISABLE_DEPRECATED_BEFORE=0 +) + add_subdirectory( textlayout ) add_subdirectory( kotext ) + + set ( textshape_SRCS TextPlugin.cpp TextShape.cpp TextShapeFactory.cpp TextTool.cpp TextEditingPluginContainer.cpp TextToolFactory.cpp ShrinkToFitShapeContainer.cpp SimpleRootAreaProvider.cpp AnnotationTextShape.cpp AnnotationTextShapeFactory.cpp ChangeTracker.cpp ReviewTool.cpp ReviewToolFactory.cpp TextChanges.cpp TextChange.cpp FontSizeAction.cpp FontFamilyAction.cpp ReferencesTool.cpp ReferencesToolFactory.cpp # dialogs/StylesWidget.cpp # dialogs/SpecialButton.cpp dialogs/StylesCombo.cpp dialogs/StylesComboPreview.cpp dialogs/DockerStylesComboModel.cpp dialogs/SimpleCharacterWidget.cpp dialogs/SimpleParagraphWidget.cpp dialogs/SimpleTableWidget.cpp dialogs/SimpleInsertWidget.cpp dialogs/LinkInsertionDialog.cpp dialogs/SimpleTableOfContentsWidget.cpp dialogs/SimpleCitationBibliographyWidget.cpp dialogs/SimpleLinksWidget.cpp dialogs/SimpleSpellCheckingWidget.cpp dialogs/CitationInsertionDialog.cpp dialogs/InsertBibliographyDialog.cpp dialogs/SimpleFootEndNotesWidget.cpp dialogs/NotesConfigurationDialog.cpp dialogs/SimpleCaptionsWidget.cpp dialogs/ParagraphLayout.cpp dialogs/ParagraphIndentSpacing.cpp dialogs/ParagraphDecorations.cpp dialogs/ParagraphBulletsNumbers.cpp dialogs/ParagraphSettingsDialog.cpp dialogs/ParagraphDropCaps.cpp dialogs/ListsSpinBox.cpp dialogs/StylesModel.cpp dialogs/StylesManagerModel.cpp dialogs/StylesSortFilterProxyModel.cpp dialogs/AbstractStylesModel.cpp dialogs/StylesFilteredModelBase.cpp dialogs/ValidParentStylesProxyModel.cpp dialogs/StylesDelegate.cpp dialogs/StyleManager.cpp dialogs/StyleManagerDialog.cpp dialogs/ParagraphGeneral.cpp dialogs/CharacterGeneral.cpp dialogs/CharacterHighlighting.cpp dialogs/InsertCharacter.cpp dialogs/FontDia.cpp dialogs/FontDecorations.cpp dialogs/LanguageTab.cpp dialogs/FormattingPreview.cpp dialogs/StyleManagerWelcome.cpp dialogs/TableDialog.cpp dialogs/QuickTableButton.cpp dialogs/FormattingButton.cpp dialogs/ChangeConfigureDialog.cpp dialogs/AcceptRejectChangeDialog.cpp dialogs/TrackedChangeModel.cpp dialogs/TrackedChangeManager.cpp dialogs/BibliographyConfigureDialog.cpp dialogs/TableOfContentsConfigure.cpp dialogs/TableOfContentsStyleConfigure.cpp dialogs/TableOfContentsStyleModel.cpp dialogs/TableOfContentsStyleDelegate.cpp dialogs/TableOfContentsPreview.cpp dialogs/TableOfContentsEntryDelegate.cpp dialogs/TableOfContentsEntryModel.cpp dialogs/TableOfContentsTemplate.cpp dialogs/BibliographyTemplate.cpp dialogs/BibliographyPreview.cpp dialogs/ListLevelChooser.cpp dialogs/SimpleAnnotationWidget.cpp dialogs/ManageBookmarkDialog.cpp dialogs/SectionFormatDialog.cpp dialogs/SectionsSplitDialog.cpp commands/ChangeListLevelCommand.cpp commands/ShowChangesCommand.cpp commands/AcceptChangeCommand.cpp commands/RejectChangeCommand.cpp commands/AutoResizeCommand.cpp ) ki18n_wrap_ui(textshape_SRCS dialogs/SimpleCharacterWidget.ui dialogs/SimpleParagraphWidget.ui dialogs/SimpleTableWidget.ui dialogs/SimpleInsertWidget.ui dialogs/SimpleTableOfContentsWidget.ui dialogs/SimpleCitationBibliographyWidget.ui dialogs/SimpleSpellCheckingWidget.ui dialogs/CitationInsertionDialog.ui dialogs/InsertBibliographyDialog.ui dialogs/SimpleFootEndNotesWidget.ui dialogs/NotesConfigurationDialog.ui dialogs/SimpleCaptionsWidget.ui dialogs/StylesWidget.ui dialogs/ParagraphLayout.ui dialogs/ParagraphIndentSpacing.ui dialogs/ParagraphDecorations.ui dialogs/ParagraphBulletsNumbers.ui dialogs/ParagraphDropCaps.ui dialogs/StyleManager.ui dialogs/CharacterGeneral.ui dialogs/CharacterHighlighting.ui dialogs/StyleManagerWelcome.ui dialogs/TableDialog.ui dialogs/BibliographyConfigureDialog.ui dialogs/TableOfContentsConfigure.ui dialogs/SimpleLinksWidget.ui dialogs/TableOfContentsStyleConfigure.ui dialogs/SimpleAnnotationWidget.ui dialogs/FontDecorations.ui dialogs/LanguageTab.ui dialogs/ChangeConfigureDialog.ui dialogs/AcceptRejectChangeDialog.ui dialogs/TrackedChangeManager.ui dialogs/LinkInsertionDialog.ui dialogs/ManageBookmark.ui dialogs/SectionFormatDialog.ui dialogs/SectionsSplitDialog.ui ) qt5_add_resources(textshape_SRCS textshape.qrc) add_library(krita_shape_text MODULE ${textshape_SRCS}) target_link_libraries(krita_shape_text kritatext kritatextlayout kritawidgetutils kritawidgets Qt5::Network KF5::Completion KF5::ItemViews KF5::WidgetsAddons ) if( SHOULD_BUILD_FEATURE_RDF ) target_link_libraries(krita_shape_text ${SOPRANO_LIBRARIES}) endif() install(TARGETS krita_shape_text DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) diff --git a/plugins/flake/vectorshape/VectorShape.cpp b/plugins/flake/vectorshape/VectorShape.cpp index 2a80a5cb20..0d847d54ed 100644 --- a/plugins/flake/vectorshape/VectorShape.cpp +++ b/plugins/flake/vectorshape/VectorShape.cpp @@ -1,498 +1,490 @@ /* This file is part of the KDE project * * Copyright (C) 2009 - 2011 Inge Wallin * Copyright (C) 2011 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ // Own #include "VectorShape.h" // Posix #include // Qt #include #include #include #include #include #include #include #include // Calligra #include "KoUnit.h" #include "KoStore.h" #include "KoXmlNS.h" #include "KoXmlReader.h" #include "KoXmlWriter.h" #include #include #include #include #include // Wmf support #include "WmfPainterBackend.h" // Vector shape #include "EmfParser.h" #include "EmfOutputPainterStrategy.h" #include "EmfOutputDebugStrategy.h" #include "SvmParser.h" #include "SvmPainterBackend.h" #include "kis_painting_tweaks.h" // Comment out to get uncached painting, which is good for debugging //#define VECTORSHAPE_PAINT_UNCACHED // Comment out to get unthreaded painting, which is good for debugging //#define VECTORSHAPE_PAINT_UNTHREADED VectorShape::VectorShape() : KoFrameShape(KoXmlNS::draw, "image") , m_type(VectorTypeNone) , m_isRendering(false) { setShapeId(VectorShape_SHAPEID); // Default size of the shape. KoShape::setSize(QSizeF(CM_TO_POINT(8), CM_TO_POINT(5))); m_cache.setMaxCost(3); } VectorShape::~VectorShape() { // Wait for the render-thread to finish before the shape is allowed to be // destroyed so we can make sure to prevent crashes or unwanted // side-effects. Maybe as alternate we could just kill the render-thread... QMutexLocker locker(&m_mutex); } // Methods specific to the vector shape. QByteArray VectorShape::compressedContents() const { return m_contents; } VectorShape::VectorType VectorShape::vectorType() const { return m_type; } void VectorShape::setCompressedContents(const QByteArray &newContents, VectorType vectorType) { QMutexLocker locker(&m_mutex); m_contents = newContents; m_type = vectorType; m_cache.clear(); update(); } RenderThread::RenderThread(const QByteArray &contents, VectorShape::VectorType type, const QSizeF &size, const QSize &boundingSize, qreal zoomX, qreal zoomY) : QObject(), QRunnable(), m_contents(contents), m_type(type), m_size(size), m_boundingSize(boundingSize), m_zoomX(zoomX), m_zoomY(zoomY) { setAutoDelete(true); } RenderThread::~RenderThread() { } void RenderThread::run() { QImage *image = new QImage(m_boundingSize, QImage::Format_ARGB32); image->fill(0); QPainter painter; if (!painter.begin(image)) { //kWarning(31000) << "Failed to create image-cache"; delete image; image = 0; } else { painter.scale(m_zoomX, m_zoomY); draw(painter); painter.end(); } emit finished(m_boundingSize, image); } void RenderThread::draw(QPainter &painter) { // If the data is uninitialized, e.g. because loading failed, draw the null shape. if (m_contents.isEmpty()) { drawNull(painter); return; } // Actually draw the contents switch (m_type) { case VectorShape::VectorTypeWmf: drawWmf(painter); break; case VectorShape::VectorTypeEmf: drawEmf(painter); break; case VectorShape::VectorTypeSvm: drawSvm(painter); break; case VectorShape::VectorTypeSvg: drawSvg(painter); break; case VectorShape::VectorTypeNone: default: drawNull(painter); } } void RenderThread::drawNull(QPainter &painter) const { QRectF rect(QPointF(0, 0), m_size); painter.save(); // Draw a simple cross in a rectangle just to indicate that there is something here. painter.setPen(QPen(QColor(172, 196, 206))); painter.drawRect(rect); painter.drawLine(rect.topLeft(), rect.bottomRight()); painter.drawLine(rect.bottomLeft(), rect.topRight()); painter.restore(); } void RenderThread::drawWmf(QPainter &painter) const { Libwmf::WmfPainterBackend wmfPainter(&painter, m_size); if (!wmfPainter.load(m_contents)) { drawNull(painter); return; } painter.save(); // Actually paint the WMF. wmfPainter.play(); painter.restore(); } void RenderThread::drawEmf(QPainter &painter) const { // FIXME: Make emfOutput use QSizeF QSize shapeSizeInt(m_size.width(), m_size.height()); //kDebug(31000) << "-------------------------------------------"; //kDebug(31000) << "size: " << shapeSizeInt << m_size; //kDebug(31000) << "position: " << position(); //kDebug(31000) << "-------------------------------------------"; Libemf::Parser emfParser; #if 1 // Set to 0 to get debug output // Create a new painter output strategy. Last param = true means keep aspect ratio. Libemf::OutputPainterStrategy emfPaintOutput(painter, shapeSizeInt, true); emfParser.setOutput(&emfPaintOutput); #else Libemf::OutputDebugStrategy emfDebugOutput; emfParser.setOutput(&emfDebugOutput); #endif emfParser.load(m_contents); } void RenderThread::drawSvm(QPainter &painter) const { QSize shapeSizeInt(m_size.width(), m_size.height()); Libsvm::SvmParser svmParser; // Create a new painter backend. Libsvm::SvmPainterBackend svmPaintOutput(&painter, shapeSizeInt); svmParser.setBackend(&svmPaintOutput); svmParser.parse(m_contents); } void RenderThread::drawSvg(QPainter &painter) const { QSvgRenderer renderer(m_contents); renderer.render(&painter, QRectF(0, 0, m_size.width(), m_size.height())); } void VectorShape::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &) { #ifdef VECTORSHAPE_PAINT_UNCACHED bool useCache = false; #else bool useCache = true; #endif -#ifdef VECTORSHAPE_PAINT_UNTHREADED - bool asynchronous = false; -#else - // Since the backends may use QPainter::drawText we need to make sure to only - // use threads if the font-backend supports that what is in most cases. - bool asynchronous = QFontDatabase::supportsThreadedFontRendering(); -#endif - - QImage *cache = render(converter, asynchronous, useCache); + QImage *cache = render(converter, true, useCache); if (cache) { // paint cached image Q_ASSERT(!cache->isNull()); QVector clipRects = KisPaintingTweaks::safeClipRegion(painter).rects(); foreach (const QRect &rc, clipRects) { painter.drawImage(rc.topLeft(), *cache, rc); } } } void VectorShape::renderFinished(QSize boundingSize, QImage *image) { if (image) { m_cache.insert(boundingSize.height(), image); update(); } m_isRendering = false; } // ---------------------------------------------------------------- // Loading and Saving void VectorShape::saveOdf(KoShapeSavingContext &context) const { QMutexLocker locker(&m_mutex); KoEmbeddedDocumentSaver &fileSaver = context.embeddedSaver(); KoXmlWriter &xmlWriter = context.xmlWriter(); QString fileName = fileSaver.getFilename("VectorImages/Image"); QByteArray mimeType; switch (m_type) { case VectorTypeWmf: mimeType = "image/x-wmf"; break; case VectorTypeEmf: mimeType = "image/x-emf"; break; case VectorTypeSvm: mimeType = "image/x-svm"; // mimetype as used inside LO/AOO break; case VectorTypeSvg: mimeType = "image/svg+xml"; default: // FIXME: What here? mimeType = "application/x-what"; break; } xmlWriter.startElement("draw:frame"); saveOdfAttributes(context, OdfAllAttributes); fileSaver.embedFile(xmlWriter, "draw:image", fileName, mimeType, qUncompress(m_contents)); xmlWriter.endElement(); // draw:frame } bool VectorShape::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) { //kDebug(31000) <<"Loading ODF frame in the vector shape. Element = " << element.tagName(); loadOdfAttributes(element, context, OdfAllAttributes); return loadOdfFrame(element, context); } inline static int read32(const char *buffer, const int offset) { // little endian int result = (int) buffer[offset]; result |= (int) buffer[offset + 1] << 8; result |= (int) buffer[offset + 2] << 16; result |= (int) buffer[offset + 3] << 24; return result; } // Load the actual contents within the vector shape. bool VectorShape::loadOdfFrameElement(const KoXmlElement &element, KoShapeLoadingContext &context) { //kDebug(31000) <<"Loading ODF element: " << element.tagName(); QMutexLocker locker(&m_mutex); // Get the reference to the vector file. If there is no href, then just return. const QString href = element.attribute("href"); if (href.isEmpty()) { return false; } // Try to open the embedded file. KoStore *store = context.odfLoadingContext().store(); bool result = store->open(href); if (!result) { return false; } int size = store->size(); if (size < 88) { store->close(); return false; } m_contents = store->read(size); store->close(); if (m_contents.count() < size) { //kDebug(31000) << "Too few bytes read: " << m_contents.count() << " instead of " << size; return false; } // Try to recognize the type. We should do this before the // compression below, because that's a semi-expensive operation. m_type = vectorType(m_contents); // Return false if we didn't manage to identify the type. if (m_type == VectorTypeNone) { return false; } // Compress for biiiig memory savings. m_contents = qCompress(m_contents); return true; } void VectorShape::waitUntilReady(const KoViewConverter &converter, bool asynchronous) const { render(converter, asynchronous, true); } QImage *VectorShape::render(const KoViewConverter &converter, bool asynchronous, bool useCache) const { QRectF rect = converter.documentToView(boundingRect()); int id = rect.size().toSize().height(); QImage *cache = useCache ? m_cache[id] : 0; if (!cache || cache->isNull()) { // recreate the cached image cache = 0; if (!m_isRendering) { m_isRendering = true; qreal zoomX, zoomY; converter.zoom(&zoomX, &zoomY); QMutexLocker locker(&m_mutex); const QByteArray uncompressedContents = m_type != VectorShape::VectorTypeNone ? qUncompress(m_contents) : QByteArray(); RenderThread *t = new RenderThread(uncompressedContents, m_type, size(), rect.size().toSize(), zoomX, zoomY); connect(t, SIGNAL(finished(QSize,QImage*)), this, SLOT(renderFinished(QSize,QImage*))); if (asynchronous) { // render and paint the image threaded QThreadPool::globalInstance()->start(t); } else { // non-threaded rendering and painting of the image t->run(); cache = m_cache[id]; } } } return cache; } VectorShape::VectorType VectorShape::vectorType(const QByteArray &newContents) { VectorType vectorType; if (isWmf(newContents)) { vectorType = VectorShape::VectorTypeWmf; } else if (isEmf(newContents)) { vectorType = VectorShape::VectorTypeEmf; } else if (isSvm(newContents)) { vectorType = VectorShape::VectorTypeSvm; } else if (isSvg(newContents)) { vectorType = VectorShape::VectorTypeSvg; } else { vectorType = VectorShape::VectorTypeNone; } return vectorType; } bool VectorShape::isWmf(const QByteArray &bytes) { //kDebug(31000) << "Check for WMF"; const char *data = bytes.constData(); const int size = bytes.count(); if (size < 10) { return false; } // This is how the 'file' command identifies a WMF. if (data[0] == '\327' && data[1] == '\315' && data[2] == '\306' && data[3] == '\232') { // FIXME: Is this a compressed wmf? Check it up. //kDebug(31000) << "WMF identified: header 1"; return true; } if (data[0] == '\002' && data[1] == '\000' && data[2] == '\011' && data[3] == '\000') { //kDebug(31000) << "WMF identified: header 2"; return true; } if (data[0] == '\001' && data[1] == '\000' && data[2] == '\011' && data[3] == '\000') { //kDebug(31000) << "WMF identified: header 3"; return true; } return false; } bool VectorShape::isEmf(const QByteArray &bytes) { //kDebug(31000) << "Check for EMF"; const char *data = bytes.constData(); const int size = bytes.count(); // This is how the 'file' command identifies an EMF. // 1. Check type qint32 mark = read32(data, 0); if (mark != 0x00000001) { //kDebug(31000) << "Not an EMF: mark = " << mark << " instead of 0x00000001"; return false; } // 2. An EMF has the string " EMF" at the start + offset 40. if (size > 44 && data[40] == ' ' && data[41] == 'E' && data[42] == 'M' && data[43] == 'F') { //kDebug(31000) << "EMF identified"; return true; } return false; } bool VectorShape::isSvm(const QByteArray &bytes) { //kDebug(31000) << "Check for SVM"; // Check the SVM signature. if (bytes.startsWith("VCLMTF")) { //kDebug(31000) << "SVM identified"; return true; } return false; } bool VectorShape::isSvg(const QByteArray &bytes) { //kDebug(31000) << "Check for SVG"; return (bytes.contains("svg")); } diff --git a/plugins/flake/vectorshape/VectorTool.cpp b/plugins/flake/vectorshape/VectorTool.cpp index 026cfffc4a..8b3aff4cdb 100644 --- a/plugins/flake/vectorshape/VectorTool.cpp +++ b/plugins/flake/vectorshape/VectorTool.cpp @@ -1,117 +1,117 @@ /* This file is part of the KDE project Copyright 2007 Montel Laurent Copyright 2011 Boudewijn Rempt This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "VectorTool.h" #include "VectorShape.h" #include "ChangeVectorDataCommand.h" #include #include -#include +#include #include #include #include #include #include #include #include #include VectorTool::VectorTool(KoCanvasBase *canvas) : KoToolBase(canvas) , m_shape(0) { } void VectorTool::activate(ToolActivation activation, const QSet &shapes) { KoToolBase::activate(activation, shapes); foreach (KoShape *shape, shapes) { m_shape = dynamic_cast(shape); if (m_shape) { break; } } if (!m_shape) { emit done(); return; } useCursor(Qt::ArrowCursor); } void VectorTool::deactivate() { m_shape = 0; KoToolBase::deactivate(); } QWidget *VectorTool::createOptionWidget() { QWidget *optionWidget = new QWidget(); QGridLayout *layout = new QGridLayout(optionWidget); QToolButton *button = 0; button = new QToolButton(optionWidget); button->setIcon(koIcon("document-open")); button->setToolTip(i18n("Open Vector Image (EMF/WMF/SVM)")); layout->addWidget(button, 0, 0); connect(button, SIGNAL(clicked(bool)), this, SLOT(changeUrlPressed())); return optionWidget; } void VectorTool::changeUrlPressed() { if (m_shape == 0) { return; } KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setCaption(i18n("Select a Vector Image")); - dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(QString("image/x-emf,image/x-wmf,image/x-svm,image/svg+xml").split(',')); QString fn = dialog.filename(); if (!fn.isEmpty()) { QFile f(fn); if (f.exists()) { f.open(QFile::ReadOnly); QByteArray ba = f.readAll(); f.close(); if (!ba.isEmpty()) { const VectorShape::VectorType vectorType = VectorShape::vectorType(ba); ChangeVectorDataCommand *cmd = new ChangeVectorDataCommand(m_shape, qCompress(ba), vectorType); canvas()->addCommand(cmd); } } } } void VectorTool::mouseDoubleClickEvent(KoPointerEvent *event) { if (canvas()->shapeManager()->shapeAt(event->point) != m_shape) { event->ignore(); // allow the event to be used by another return; } changeUrlPressed(); } diff --git a/plugins/impex/kra/kra_converter.cpp b/plugins/impex/kra/kra_converter.cpp index 79b5976bfa..8724b36ae2 100644 --- a/plugins/impex/kra/kra_converter.cpp +++ b/plugins/impex/kra/kra_converter.cpp @@ -1,353 +1,352 @@ /* * Copyright (C) 2016 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kra_converter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char CURRENT_DTD_VERSION[] = "2.0"; KraConverter::KraConverter(KisDocument *doc) : m_doc(doc) , m_image(doc->savingImage()) { } KraConverter::~KraConverter() { delete m_store; delete m_kraSaver; delete m_kraLoader; } KisImageBuilder_Result KraConverter::buildImage(QIODevice *io) { m_store = KoStore::createStore(io, KoStore::Read, "", KoStore::Zip); if (m_store->bad()) { m_doc->setErrorMessage(i18n("Not a valid Krita file")); return KisImageBuilder_RESULT_FAILURE; } bool success; { if (m_store->hasFile("root") || m_store->hasFile("maindoc.xml")) { // Fallback to "old" file format (maindoc.xml) KoXmlDocument doc; bool ok = oldLoadAndParse(m_store, "root", doc); if (ok) ok = loadXML(doc, m_store); if (!ok) { return KisImageBuilder_RESULT_FAILURE; } } else { errUI << "ERROR: No maindoc.xml" << endl; m_doc->setErrorMessage(i18n("Invalid document: no file 'maindoc.xml'.")); return KisImageBuilder_RESULT_FAILURE; } if (m_store->hasFile("documentinfo.xml")) { KoXmlDocument doc; if (oldLoadAndParse(m_store, "documentinfo.xml", doc)) { m_doc->documentInfo()->load(doc); } } success = completeLoading(m_store); } return success ? KisImageBuilder_RESULT_OK : KisImageBuilder_RESULT_FAILURE; } KisImageSP KraConverter::image() { return m_image; } vKisNodeSP KraConverter::activeNodes() { return m_activeNodes; } QList KraConverter::assistants() { return m_assistants; } KisImageBuilder_Result KraConverter::buildFile(QIODevice *io) { m_store = KoStore::createStore(io, KoStore::Write, m_doc->nativeFormatMimeType(), KoStore::Zip); if (m_store->bad()) { m_doc->setErrorMessage(i18n("Could not create the file for saving")); return KisImageBuilder_RESULT_FAILURE; } bool result = false; m_kraSaver = new KisKraSaver(m_doc); result = saveRootDocuments(m_store); if (!result) { return KisImageBuilder_RESULT_FAILURE; } result = m_kraSaver->saveKeyframes(m_store, m_doc->url().toLocalFile(), true); if (!result) { qWarning() << "saving key frames failed"; } result = m_kraSaver->saveBinaryData(m_store, m_image, m_doc->url().toLocalFile(), true, m_doc->isAutosaving()); if (!result) { qWarning() << "saving binary data failed"; } if (!m_store->finalize()) { return KisImageBuilder_RESULT_FAILURE; } if (!m_kraSaver->errorMessages().isEmpty()) { m_doc->setErrorMessage(m_kraSaver->errorMessages().join(".\n")); return KisImageBuilder_RESULT_FAILURE; } return KisImageBuilder_RESULT_OK; } bool KraConverter::saveRootDocuments(KoStore *store) { dbgFile << "Saving root"; if (store->open("root")) { KoStoreDevice dev(store); if (!saveToStream(&dev) || !store->close()) { dbgUI << "saveToStream failed"; return false; } } else { m_doc->setErrorMessage(i18n("Not able to write '%1'. Partition full?", QString("maindoc.xml"))); return false; } bool success = false; if (store->open("documentinfo.xml")) { QDomDocument doc = KisDocument::createDomDocument("document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1"); doc = m_doc->documentInfo()->save(doc); KoStoreDevice dev(store); QByteArray s = doc.toByteArray(); // this is already Utf8! success = dev.write(s.data(), s.size()); store->close(); } if (store->open("preview.png")) { // ### TODO: missing error checking (The partition could be full!) savePreview(store); (void)store->close(); } dbgUI << "Saving done of url:" << m_doc->url().toLocalFile(); // Success return success; } bool KraConverter::saveToStream(QIODevice *dev) { QDomDocument doc = createDomDocument(); // Save to buffer QByteArray s = doc.toByteArray(); // utf8 already dev->open(QIODevice::WriteOnly); int nwritten = dev->write(s.data(), s.size()); if (nwritten != (int)s.size()) { warnUI << "wrote " << nwritten << "- expected" << s.size(); } return nwritten == (int)s.size(); } QDomDocument KraConverter::createDomDocument() { QDomDocument doc = m_doc->createDomDocument("DOC", CURRENT_DTD_VERSION); QDomElement root = doc.documentElement(); root.setAttribute("editor", "Krita"); root.setAttribute("syntaxVersion", "2"); root.setAttribute("kritaVersion", KritaVersionWrapper::versionString(false)); root.appendChild(m_kraSaver->saveXML(doc, m_image)); if (!m_kraSaver->errorMessages().isEmpty()) { m_doc->setErrorMessage(m_kraSaver->errorMessages().join(".\n")); } return doc; } bool KraConverter::savePreview(KoStore *store) { QPixmap pix = m_doc->generatePreview(QSize(256, 256)); QImage preview(pix.toImage().convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly)); if (preview.size() == QSize(0,0)) { QSize newSize = m_doc->savingImage()->bounds().size(); newSize.scale(QSize(256, 256), Qt::KeepAspectRatio); preview = QImage(newSize, QImage::Format_ARGB32); preview.fill(QColor(0, 0, 0, 0)); } KoStoreDevice io(store); if (!io.open(QIODevice::WriteOnly)) { return false; } bool ret = preview.save(&io, "PNG"); io.close(); return ret; } bool KraConverter::oldLoadAndParse(KoStore *store, const QString &filename, KoXmlDocument &xmldoc) { //dbgUI <<"Trying to open" << filename; if (!store->open(filename)) { warnUI << "Entry " << filename << " not found!"; m_doc->setErrorMessage(i18n("Could not find %1", filename)); return false; } // Error variables for QDomDocument::setContent QString errorMsg; int errorLine, errorColumn; bool ok = xmldoc.setContent(store->device(), &errorMsg, &errorLine, &errorColumn); store->close(); if (!ok) { errUI << "Parsing error in " << filename << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg << endl; m_doc->setErrorMessage(i18n("Parsing error in %1 at line %2, column %3\nError message: %4" , filename , errorLine, errorColumn , - QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0, - QCoreApplication::UnicodeUTF8))); + QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0))); return false; } dbgUI << "File" << filename << " loaded and parsed"; return true; } bool KraConverter::loadXML(const KoXmlDocument &doc, KoStore *store) { Q_UNUSED(store); KoXmlElement root; KoXmlNode node; if (doc.doctype().name() != "DOC") { m_doc->setErrorMessage(i18n("The format is not supported or the file is corrupted")); return false; } root = doc.documentElement(); int syntaxVersion = root.attribute("syntaxVersion", "3").toInt(); if (syntaxVersion > 2) { m_doc->setErrorMessage(i18n("The file is too new for this version of Krita (%1).", syntaxVersion)); return false; } if (!root.hasChildNodes()) { m_doc->setErrorMessage(i18n("The file has no layers.")); return false; } m_kraLoader = new KisKraLoader(m_doc, syntaxVersion); // Legacy from the multi-image .kra file period. for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isElement()) { if (node.nodeName() == "IMAGE") { KoXmlElement elem = node.toElement(); if (!(m_image = m_kraLoader->loadXML(elem))) { if (m_kraLoader->errorMessages().isEmpty()) { m_doc->setErrorMessage(i18n("Unknown error.")); } else { m_doc->setErrorMessage(m_kraLoader->errorMessages().join("\n")); } return false; } return true; } else { if (m_kraLoader->errorMessages().isEmpty()) { m_doc->setErrorMessage(i18n("The file does not contain an image.")); } return false; } } } return false; } bool KraConverter::completeLoading(KoStore* store) { if (!m_image) { if (m_kraLoader->errorMessages().isEmpty()) { m_doc->setErrorMessage(i18n("Unknown error.")); } else { m_doc->setErrorMessage(m_kraLoader->errorMessages().join("\n")); } return false; } m_image->blockUpdates(); m_kraLoader->loadBinaryData(store, m_image, m_doc->localFilePath(), true); m_image->unblockUpdates(); bool retval = true; if (!m_kraLoader->warningMessages().isEmpty()) { m_doc->setWarningMessage(m_kraLoader->warningMessages().join("\n")); retval = true; } if (retval) { m_activeNodes = m_kraLoader->selectedNodes(); m_assistants = m_kraLoader->assistants(); } return retval; } void KraConverter::cancel() { m_stop = true; } diff --git a/plugins/impex/raw/3rdparty/libkdcraw/src/dcrawsettingswidget.cpp b/plugins/impex/raw/3rdparty/libkdcraw/src/dcrawsettingswidget.cpp index 7ed4cb4b59..8157920dbf 100644 --- a/plugins/impex/raw/3rdparty/libkdcraw/src/dcrawsettingswidget.cpp +++ b/plugins/impex/raw/3rdparty/libkdcraw/src/dcrawsettingswidget.cpp @@ -1,1324 +1,1324 @@ /** =========================================================== * @file * * This file is a part of digiKam project * http://www.digikam.org * * @date 2006-09-13 * @brief LibRaw settings widgets * * @author Copyright (C) 2006-2015 by Gilles Caulier * caulier dot gilles at gmail dot com * @author Copyright (C) 2006-2011 by Marcel Wiesweg * marcel dot wiesweg at gmx dot de * @author Copyright (C) 2007-2008 by Guillaume Castagnino * casta at xwing dot info * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dcrawsettingswidget.h" // C++ includes #include // Qt includes #include #include #include #include #include #include #include -#include +#include // KDE includes #include // Local includes #include "kdcraw.h" #include "rnuminput.h" #include "rcombobox.h" #include "rexpanderbox.h" #include "libkdcraw_debug.h" #include namespace KDcrawIface { class Q_DECL_HIDDEN DcrawSettingsWidget::Private { public: Private() { autoBrightnessBox = 0; sixteenBitsImage = 0; fourColorCheckBox = 0; brightnessLabel = 0; brightnessSpinBox = 0; blackPointCheckBox = 0; blackPointSpinBox = 0; whitePointCheckBox = 0; whitePointSpinBox = 0; whiteBalanceComboBox = 0; whiteBalanceLabel = 0; customWhiteBalanceSpinBox = 0; customWhiteBalanceLabel = 0; customWhiteBalanceGreenSpinBox = 0; customWhiteBalanceGreenLabel = 0; unclipColorLabel = 0; dontStretchPixelsCheckBox = 0; RAWQualityComboBox = 0; RAWQualityLabel = 0; noiseReductionComboBox = 0; NRSpinBox1 = 0; NRSpinBox2 = 0; NRLabel1 = 0; NRLabel2 = 0; enableCACorrectionBox = 0; autoCACorrectionBox = 0; caRedMultSpinBox = 0; caBlueMultSpinBox = 0; caRedMultLabel = 0; caBlueMultLabel = 0; unclipColorComboBox = 0; reconstructLabel = 0; reconstructSpinBox = 0; outputColorSpaceLabel = 0; outputColorSpaceComboBox = 0; demosaicingSettings = 0; whiteBalanceSettings = 0; correctionsSettings = 0; colormanSettings = 0; medianFilterPassesSpinBox = 0; medianFilterPassesLabel = 0; inIccUrlEdit = 0; outIccUrlEdit = 0; inputColorSpaceLabel = 0; inputColorSpaceComboBox = 0; fixColorsHighlightsBox = 0; refineInterpolationBox = 0; noiseReductionLabel = 0; expoCorrectionBox = 0; expoCorrectionShiftSpinBox = 0; expoCorrectionHighlightSpinBox = 0; expoCorrectionShiftLabel = 0; expoCorrectionHighlightLabel = 0; } /** Convert Exposure correction shift E.V value from GUI to Linear value needs by libraw decoder. */ double shiftExpoFromEvToLinear(double ev) const { // From GUI : -2.0EV => 0.25 // +3.0EV => 8.00 return (1.55*ev + 3.35); } /** Convert Exposure correction shift Linear value from liraw decoder to E.V value needs by GUI. */ double shiftExpoFromLinearToEv(double lin) const { // From GUI : 0.25 => -2.0EV // 8.00 => +3.0EV return ((lin-3.35) / 1.55); } public: QWidget* demosaicingSettings; QWidget* whiteBalanceSettings; QWidget* correctionsSettings; QWidget* colormanSettings; QLabel* whiteBalanceLabel; QLabel* customWhiteBalanceLabel; QLabel* customWhiteBalanceGreenLabel; QLabel* brightnessLabel; QLabel* RAWQualityLabel; QLabel* NRLabel1; QLabel* NRLabel2; QLabel* caRedMultLabel; QLabel* caBlueMultLabel; QLabel* unclipColorLabel; QLabel* reconstructLabel; QLabel* inputColorSpaceLabel; QLabel* outputColorSpaceLabel; QLabel* medianFilterPassesLabel; QLabel* noiseReductionLabel; QLabel* expoCorrectionShiftLabel; QLabel* expoCorrectionHighlightLabel; QCheckBox* blackPointCheckBox; QCheckBox* whitePointCheckBox; QCheckBox* sixteenBitsImage; QCheckBox* autoBrightnessBox; QCheckBox* fourColorCheckBox; QCheckBox* dontStretchPixelsCheckBox; QCheckBox* enableCACorrectionBox; QCheckBox* autoCACorrectionBox; QCheckBox* fixColorsHighlightsBox; QCheckBox* refineInterpolationBox; QCheckBox* expoCorrectionBox; RFileSelector* inIccUrlEdit; RFileSelector* outIccUrlEdit; RComboBox* noiseReductionComboBox; RComboBox* whiteBalanceComboBox; RComboBox* RAWQualityComboBox; RComboBox* unclipColorComboBox; RComboBox* inputColorSpaceComboBox; RComboBox* outputColorSpaceComboBox; RIntNumInput* customWhiteBalanceSpinBox; RIntNumInput* reconstructSpinBox; RIntNumInput* blackPointSpinBox; RIntNumInput* whitePointSpinBox; RIntNumInput* NRSpinBox1; RIntNumInput* NRSpinBox2; RIntNumInput* medianFilterPassesSpinBox; RDoubleNumInput* customWhiteBalanceGreenSpinBox; RDoubleNumInput* caRedMultSpinBox; RDoubleNumInput* caBlueMultSpinBox; RDoubleNumInput* brightnessSpinBox; RDoubleNumInput* expoCorrectionShiftSpinBox; RDoubleNumInput* expoCorrectionHighlightSpinBox; }; DcrawSettingsWidget::DcrawSettingsWidget(QWidget* const parent, int advSettings) : RExpanderBox(parent), d(new Private) { setup(advSettings); } void DcrawSettingsWidget::setup(int advSettings) { setObjectName( QLatin1String("DCRawSettings Expander" )); // --------------------------------------------------------------- // DEMOSAICING Settings panel d->demosaicingSettings = new QWidget(this); QGridLayout* const demosaicingLayout = new QGridLayout(d->demosaicingSettings); int line = 0; d->sixteenBitsImage = new QCheckBox(i18nc("@option:check", "16 bits color depth"), d->demosaicingSettings); d->sixteenBitsImage->setToolTip(i18nc("@info:whatsthis", "

If enabled, all RAW files will " "be decoded in 16-bit color depth using a linear gamma curve. To " "prevent dark picture rendering in the editor, it is recommended to " "use Color Management in this mode.

" "

If disabled, all RAW files will be decoded in 8-bit color " "depth with a BT.709 gamma curve and a 99th-percentile white point. " "This mode is faster than 16-bit decoding.

")); demosaicingLayout->addWidget(d->sixteenBitsImage, 0, 0, 1, 2); if (advSettings & SIXTEENBITS) { d->sixteenBitsImage->show(); line = 1; } else { d->sixteenBitsImage->hide(); } d->fourColorCheckBox = new QCheckBox(i18nc("@option:check", "Interpolate RGB as four colors"), d->demosaicingSettings); d->fourColorCheckBox->setToolTip(i18nc("@info:whatsthis", "Interpolate RGB as four " "colors" "

The default is to assume that all green pixels are the same. " "If even-row green pixels are more sensitive to ultraviolet light " "than odd-row this difference causes a mesh pattern in the output; " "using this option solves this problem with minimal loss of detail.

" "

To resume, this option blurs the image a little, but it " "eliminates false 2x2 mesh patterns with VNG quality method or " "mazes with AHD quality method.

")); demosaicingLayout->addWidget(d->fourColorCheckBox, line, 0, 1, line == 0 ? 2 : 3); line++; QLabel* const dcrawVersion = new QLabel(d->demosaicingSettings); dcrawVersion->setAlignment(Qt::AlignRight); dcrawVersion->setToolTip(i18nc("@info:tooltip", "Visit LibRaw project website")); dcrawVersion->setOpenExternalLinks(true); dcrawVersion->setTextFormat(Qt::RichText); dcrawVersion->setTextInteractionFlags(Qt::LinksAccessibleByMouse); dcrawVersion->setText(QString::fromLatin1("%2") .arg(QLatin1String("http://www.libraw.org")) .arg(QString::fromLatin1("libraw %1").arg(KDcraw::librawVersion()))); demosaicingLayout->addWidget(dcrawVersion, 0, 2, 1, 1); d->dontStretchPixelsCheckBox = new QCheckBox(i18nc("@option:check", "Do not stretch or rotate pixels"), d->demosaicingSettings); d->dontStretchPixelsCheckBox->setToolTip(i18nc("@info:whatsthis", "Do not stretch or rotate pixels" "

For Fuji Super CCD cameras, show the image tilted 45 degrees. " "For cameras with non-square pixels, do not stretch the image to " "its correct aspect ratio. In any case, this option guarantees that " "each output pixel corresponds to one RAW pixel.

")); demosaicingLayout->addWidget(d->dontStretchPixelsCheckBox, line, 0, 1, 3); line++; d->RAWQualityLabel = new QLabel(i18nc("@label:listbox", "Quality:"), d->demosaicingSettings); d->RAWQualityComboBox = new RComboBox(d->demosaicingSettings); // Original dcraw demosaicing methods d->RAWQualityComboBox->insertItem(RawDecodingSettings::BILINEAR, i18nc("@item:inlistbox Quality", "Bilinear")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::VNG, i18nc("@item:inlistbox Quality", "VNG")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::PPG, i18nc("@item:inlistbox Quality", "PPG")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::AHD, i18nc("@item:inlistbox Quality", "AHD")); // Extended demosaicing method from GPL2 pack d->RAWQualityComboBox->insertItem(RawDecodingSettings::DCB, i18nc("@item:inlistbox Quality", "DCB")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::PL_AHD, i18nc("@item:inlistbox Quality", "AHD v2")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::AFD, i18nc("@item:inlistbox Quality", "AFD")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::VCD, i18nc("@item:inlistbox Quality", "VCD")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::VCD_AHD, i18nc("@item:inlistbox Quality", "VCD & AHD")); d->RAWQualityComboBox->insertItem(RawDecodingSettings::LMMSE, i18nc("@item:inlistbox Quality", "LMMSE")); // Extended demosaicing method from GPL3 pack d->RAWQualityComboBox->insertItem(RawDecodingSettings::AMAZE, i18nc("@item:inlistbox Quality", "AMaZE")); // If Libraw do not support GPL2 pack, disable entries relevant. if (!KDcraw::librawUseGPL2DemosaicPack()) { for (int i=RawDecodingSettings::DCB ; i <=RawDecodingSettings::LMMSE ; ++i) d->RAWQualityComboBox->combo()->setItemData(i, false, Qt::UserRole-1); } // If Libraw do not support GPL3 pack, disable entries relevant. if (!KDcraw::librawUseGPL3DemosaicPack()) { d->RAWQualityComboBox->combo()->setItemData(RawDecodingSettings::AMAZE, false, Qt::UserRole-1); } d->RAWQualityComboBox->setDefaultIndex(RawDecodingSettings::BILINEAR); d->RAWQualityComboBox->setCurrentIndex(RawDecodingSettings::BILINEAR); d->RAWQualityComboBox->setToolTip(i18nc("@info:whatsthis", "Quality (interpolation)" "

Select here the demosaicing method to use when decoding RAW " "images. A demosaicing algorithm is a digital image process used to " "interpolate a complete image from the partial raw data received " "from the color-filtered image sensor, internal to many digital " "cameras, in form of a matrix of colored pixels. Also known as CFA " "interpolation or color reconstruction, another common spelling is " "demosaicing. The following methods are available for demosaicing " "RAW images:

" // Original dcraw demosaicing methods "

  • Bilinear: use " "high-speed but low-quality bilinear interpolation (default - for " "slow computers). In this method, the red value of a non-red pixel " "is computed as the average of the adjacent red pixels, and similarly " "for blue and green.
  • " "
  • VNG: use Variable Number " "of Gradients interpolation. This method computes gradients near " "the pixel of interest and uses the lower gradients (representing " "smoother and more similar parts of the image) to make an estimate.
  • " "
  • PPG: use Patterned-Pixel-" "Grouping interpolation. Pixel Grouping uses assumptions about " "natural scenery in making estimates. It has fewer color artifacts " "on natural images than the Variable Number of Gradients method.
  • " "
  • AHD: use Adaptive " "Homogeneity-Directed interpolation. This method selects the " "direction of interpolation so as to maximize a homogeneity metric, " "thus typically minimizing color artifacts.
  • " // Extended demosaicing method "
  • DCB: DCB interpolation from " "linuxphoto.org project.
  • " "
  • AHD v2: modified AHD " "interpolation using Variance of Color Differences method.
  • " "
  • AFD: Adaptive Filtered " "Demosaicing interpolation through 5 pass median filter from PerfectRaw " "project.
  • " "
  • VCD: Variance of Color " "Differences interpolation.
  • " "
  • VCD & AHD: Mixed demosaicing " "between VCD and AHD.
  • " "
  • LMMSE: color demosaicing via " "directional linear minimum mean-square error estimation interpolation " "from PerfectRaw.
  • " "
  • AMaZE: Aliasing Minimization " "interpolation and Zipper Elimination to apply color aberration removal " "from RawTherapee project.

" "

Note: some methods can be unavailable if RAW decoder have been built " "without extension packs.

")); demosaicingLayout->addWidget(d->RAWQualityLabel, line, 0, 1, 1); demosaicingLayout->addWidget(d->RAWQualityComboBox, line, 1, 1, 2); line++; d->medianFilterPassesSpinBox = new RIntNumInput(d->demosaicingSettings); d->medianFilterPassesSpinBox->setRange(0, 10, 1); d->medianFilterPassesSpinBox->setDefaultValue(0); d->medianFilterPassesLabel = new QLabel(i18nc("@label:slider", "Pass:"), d->whiteBalanceSettings); d->medianFilterPassesSpinBox->setToolTip( i18nc("@info:whatsthis", "Pass" "

Set here the passes used by the median filter applied after " "interpolation to Red-Green and Blue-Green channels.

" "

This setting is only available for specific Quality options: " "Bilinear, " "VNG, PPG, " "AHD, " "DCB, and VCD & AHD.

")); demosaicingLayout->addWidget(d->medianFilterPassesLabel, line, 0, 1, 1); demosaicingLayout->addWidget(d->medianFilterPassesSpinBox, line, 1, 1, 2); line++; d->refineInterpolationBox = new QCheckBox(i18nc("@option:check", "Refine interpolation"), d->demosaicingSettings); d->refineInterpolationBox->setToolTip(i18nc("@info:whatsthis", "Refine interpolation" "

This setting is available only for few Quality options:

" "

  • DCB: turn on " "the enhance interpolated colors filter.
  • " "
  • VCD & AHD: turn on the " "enhanced effective color interpolation (EECI) refine to improve " "sharpness.

")); demosaicingLayout->addWidget(d->refineInterpolationBox, line, 0, 1, 2); // If Libraw do not support GPL2 pack, disable options relevant. if (!KDcraw::librawUseGPL2DemosaicPack()) { d->medianFilterPassesLabel->setEnabled(false); d->medianFilterPassesSpinBox->setEnabled(false); d->refineInterpolationBox->setEnabled(false); } addItem(d->demosaicingSettings, KisIconUtils::loadIcon("kdcraw").pixmap(16, 16), i18nc("@label", "Demosaicing"), QString("demosaicing"), true); // --------------------------------------------------------------- // WHITE BALANCE Settings Panel d->whiteBalanceSettings = new QWidget(this); QGridLayout* const whiteBalanceLayout = new QGridLayout(d->whiteBalanceSettings); d->whiteBalanceLabel = new QLabel(i18nc("@label:listbox", "Method:"), d->whiteBalanceSettings); d->whiteBalanceComboBox = new RComboBox(d->whiteBalanceSettings); d->whiteBalanceComboBox->insertItem(RawDecodingSettings::NONE, i18nc("@item:inlistbox", "Default D65")); d->whiteBalanceComboBox->insertItem(RawDecodingSettings::CAMERA, i18nc("@item:inlistbox", "Camera")); d->whiteBalanceComboBox->insertItem(RawDecodingSettings::AUTO, i18nc("@item:inlistbox set while balance automatically", "Automatic")); d->whiteBalanceComboBox->insertItem(RawDecodingSettings::CUSTOM, i18nc("@item:inlistbox set white balance manually", "Manual")); d->whiteBalanceComboBox->setDefaultIndex(RawDecodingSettings::CAMERA); d->whiteBalanceComboBox->setToolTip(i18nc("@info:whatsthis", "White Balance" "

Configure the raw white balance:

" "

  • Default D65: " "Use a standard daylight D65 white balance.
  • " "
  • Camera: Use the white " "balance specified by the camera. If not available, reverts to " "default neutral white balance.
  • " "
  • Automatic: Calculates an " "automatic white balance averaging the entire image.
  • " "
  • Manual: Set a custom " "temperature and green level values.

")); d->customWhiteBalanceSpinBox = new RIntNumInput(d->whiteBalanceSettings); d->customWhiteBalanceSpinBox->setRange(2000, 12000, 10); d->customWhiteBalanceSpinBox->setDefaultValue(6500); d->customWhiteBalanceLabel = new QLabel(i18nc("@label:slider", "T(K):"), d->whiteBalanceSettings); d->customWhiteBalanceSpinBox->setToolTip( i18nc("@info:whatsthis", "Temperature" "

Set here the color temperature in Kelvin.

")); d->customWhiteBalanceGreenSpinBox = new RDoubleNumInput(d->whiteBalanceSettings); d->customWhiteBalanceGreenSpinBox->setDecimals(2); d->customWhiteBalanceGreenSpinBox->setRange(0.2, 2.5, 0.01); d->customWhiteBalanceGreenSpinBox->setDefaultValue(1.0); d->customWhiteBalanceGreenLabel = new QLabel(i18nc("@label:slider Green component", "Green:"), d->whiteBalanceSettings); d->customWhiteBalanceGreenSpinBox->setToolTip(i18nc("@info:whatsthis", "

Set here the " "green component to set magenta color cast removal level.

")); d->unclipColorLabel = new QLabel(i18nc("@label:listbox", "Highlights:"), d->whiteBalanceSettings); d->unclipColorComboBox = new RComboBox(d->whiteBalanceSettings); d->unclipColorComboBox->insertItem(0, i18nc("@item:inlistbox", "Solid white")); d->unclipColorComboBox->insertItem(1, i18nc("@item:inlistbox", "Unclip")); d->unclipColorComboBox->insertItem(2, i18nc("@item:inlistbox", "Blend")); d->unclipColorComboBox->insertItem(3, i18nc("@item:inlistbox", "Rebuild")); d->unclipColorComboBox->setDefaultIndex(0); d->unclipColorComboBox->setToolTip(i18nc("@info:whatsthis", "Highlights" "

Select here the highlight clipping method:

" "

  • Solid white: " "clip all highlights to solid white
  • " "
  • Unclip: leave highlights " "unclipped in various shades of pink
  • " "
  • Blend:Blend clipped and " "unclipped values together for a gradual fade to white
  • " "
  • Rebuild: reconstruct " "highlights using a level value

")); d->reconstructLabel = new QLabel(i18nc("@label:slider Highlight reconstruct level", "Level:"), d->whiteBalanceSettings); d->reconstructSpinBox = new RIntNumInput(d->whiteBalanceSettings); d->reconstructSpinBox->setRange(0, 6, 1); d->reconstructSpinBox->setDefaultValue(0); d->reconstructSpinBox->setToolTip(i18nc("@info:whatsthis", "Level" "

Specify the reconstruct highlight level. Low values favor " "whites and high values favor colors.

")); d->expoCorrectionBox = new QCheckBox(i18nc("@option:check", "Exposure Correction (E.V)"), d->whiteBalanceSettings); d->expoCorrectionBox->setToolTip(i18nc("@info:whatsthis", "

Turn on the exposure " "correction before interpolation.

")); d->expoCorrectionShiftLabel = new QLabel(i18nc("@label:slider", "Linear Shift:"), d->whiteBalanceSettings); d->expoCorrectionShiftSpinBox = new RDoubleNumInput(d->whiteBalanceSettings); d->expoCorrectionShiftSpinBox->setDecimals(2); d->expoCorrectionShiftSpinBox->setRange(-2.0, 3.0, 0.01); d->expoCorrectionShiftSpinBox->setDefaultValue(0.0); d->expoCorrectionShiftSpinBox->setToolTip(i18nc("@info:whatsthis", "Shift" "

Linear Shift of exposure correction before interpolation in E.V

")); d->expoCorrectionHighlightLabel = new QLabel(i18nc("@label:slider", "Highlight:"), d->whiteBalanceSettings); d->expoCorrectionHighlightSpinBox = new RDoubleNumInput(d->whiteBalanceSettings); d->expoCorrectionHighlightSpinBox->setDecimals(2); d->expoCorrectionHighlightSpinBox->setRange(0.0, 1.0, 0.01); d->expoCorrectionHighlightSpinBox->setDefaultValue(0.0); d->expoCorrectionHighlightSpinBox->setToolTip(i18nc("@info:whatsthis", "Highlight" "

Amount of highlight preservation for exposure correction " "before interpolation in E.V. Only take effect if Shift Correction is > 1.0 E.V

")); d->fixColorsHighlightsBox = new QCheckBox(i18nc("@option:check", "Correct false colors in highlights"), d->whiteBalanceSettings); d->fixColorsHighlightsBox->setToolTip(i18nc("@info:whatsthis", "

If enabled, images with " "overblown channels are processed much more accurately, without " "'pink clouds' (and blue highlights under tungsten lamps).

")); d->autoBrightnessBox = new QCheckBox(i18nc("@option:check", "Auto Brightness"), d->whiteBalanceSettings); d->autoBrightnessBox->setToolTip(i18nc("@info:whatsthis", "

If disable, use a fixed white level " "and ignore the image histogram to adjust brightness.

")); d->brightnessLabel = new QLabel(i18nc("@label:slider", "Brightness:"), d->whiteBalanceSettings); d->brightnessSpinBox = new RDoubleNumInput(d->whiteBalanceSettings); d->brightnessSpinBox->setDecimals(2); d->brightnessSpinBox->setRange(0.0, 10.0, 0.01); d->brightnessSpinBox->setDefaultValue(1.0); d->brightnessSpinBox->setToolTip(i18nc("@info:whatsthis", "Brightness" "

Specify the brightness level of output image. The default " "value is 1.0 (works in 8-bit mode only).

")); if (! (advSettings & POSTPROCESSING)) { d->brightnessLabel->hide(); d->brightnessSpinBox->hide(); } d->blackPointCheckBox = new QCheckBox(i18nc("@option:check Black point", "Black:"), d->whiteBalanceSettings); d->blackPointCheckBox->setToolTip(i18nc("@info:whatsthis", "Black point" "

Use a specific black point value to decode RAW pictures. If " "you set this option to off, the Black Point value will be " "automatically computed.

")); d->blackPointSpinBox = new RIntNumInput(d->whiteBalanceSettings); d->blackPointSpinBox->setRange(0, 1000, 1); d->blackPointSpinBox->setDefaultValue(0); d->blackPointSpinBox->setToolTip(i18nc("@info:whatsthis", "Black point value" "

Specify specific black point value of the output image.

")); d->whitePointCheckBox = new QCheckBox(i18nc("@option:check White point", "White:"), d->whiteBalanceSettings); d->whitePointCheckBox->setToolTip(i18nc("@info:whatsthis", "White point" "

Use a specific white point value to decode RAW pictures. If " "you set this option to off, the White Point value will be " "automatically computed.

")); d->whitePointSpinBox = new RIntNumInput(d->whiteBalanceSettings); d->whitePointSpinBox->setRange(0, 20000, 1); d->whitePointSpinBox->setDefaultValue(0); d->whitePointSpinBox->setToolTip(i18nc("@info:whatsthis", "White point value" "

Specify specific white point value of the output image.

")); if (! (advSettings & BLACKWHITEPOINTS)) { d->blackPointCheckBox->hide(); d->blackPointSpinBox->hide(); d->whitePointCheckBox->hide(); d->whitePointSpinBox->hide(); } whiteBalanceLayout->addWidget(d->whiteBalanceLabel, 0, 0, 1, 1); whiteBalanceLayout->addWidget(d->whiteBalanceComboBox, 0, 1, 1, 2); whiteBalanceLayout->addWidget(d->customWhiteBalanceLabel, 1, 0, 1, 1); whiteBalanceLayout->addWidget(d->customWhiteBalanceSpinBox, 1, 1, 1, 2); whiteBalanceLayout->addWidget(d->customWhiteBalanceGreenLabel, 2, 0, 1, 1); whiteBalanceLayout->addWidget(d->customWhiteBalanceGreenSpinBox, 2, 1, 1, 2); whiteBalanceLayout->addWidget(d->unclipColorLabel, 3, 0, 1, 1); whiteBalanceLayout->addWidget(d->unclipColorComboBox, 3, 1, 1, 2); whiteBalanceLayout->addWidget(d->reconstructLabel, 4, 0, 1, 1); whiteBalanceLayout->addWidget(d->reconstructSpinBox, 4, 1, 1, 2); whiteBalanceLayout->addWidget(d->expoCorrectionBox, 5, 0, 1, 2); whiteBalanceLayout->addWidget(d->expoCorrectionShiftLabel, 6, 0, 1, 1); whiteBalanceLayout->addWidget(d->expoCorrectionShiftSpinBox, 6, 1, 1, 2); whiteBalanceLayout->addWidget(d->expoCorrectionHighlightLabel, 7, 0, 1, 1); whiteBalanceLayout->addWidget(d->expoCorrectionHighlightSpinBox, 7, 1, 1, 2); whiteBalanceLayout->addWidget(d->fixColorsHighlightsBox, 8, 0, 1, 3); whiteBalanceLayout->addWidget(d->autoBrightnessBox, 9, 0, 1, 3); whiteBalanceLayout->addWidget(d->brightnessLabel, 10, 0, 1, 1); whiteBalanceLayout->addWidget(d->brightnessSpinBox, 10, 1, 1, 2); whiteBalanceLayout->addWidget(d->blackPointCheckBox, 11, 0, 1, 1); whiteBalanceLayout->addWidget(d->blackPointSpinBox, 11, 1, 1, 2); whiteBalanceLayout->addWidget(d->whitePointCheckBox, 12, 0, 1, 1); whiteBalanceLayout->addWidget(d->whitePointSpinBox, 12, 1, 1, 2); whiteBalanceLayout->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); whiteBalanceLayout->setMargin(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); addItem(d->whiteBalanceSettings, KisIconUtils::loadIcon("kdcraw").pixmap(16, 16), i18nc("@label", "White Balance"), QString("whitebalance"), true); // --------------------------------------------------------------- // CORRECTIONS Settings panel d->correctionsSettings = new QWidget(this); QGridLayout* const correctionsLayout = new QGridLayout(d->correctionsSettings); d->noiseReductionLabel = new QLabel(i18nc("@label:listbox", "Noise reduction:"), d->correctionsSettings); d->noiseReductionComboBox = new RComboBox(d->colormanSettings); d->noiseReductionComboBox->insertItem(RawDecodingSettings::NONR, i18nc("@item:inlistbox Noise Reduction", "None")); d->noiseReductionComboBox->insertItem(RawDecodingSettings::WAVELETSNR, i18nc("@item:inlistbox Noise Reduction", "Wavelets")); d->noiseReductionComboBox->insertItem(RawDecodingSettings::FBDDNR, i18nc("@item:inlistbox Noise Reduction", "FBDD")); d->noiseReductionComboBox->insertItem(RawDecodingSettings::LINENR, i18nc("@item:inlistbox Noise Reduction", "CFA Line Denoise")); d->noiseReductionComboBox->insertItem(RawDecodingSettings::IMPULSENR, i18nc("@item:inlistbox Noise Reduction", "Impulse Denoise")); d->noiseReductionComboBox->setDefaultIndex(RawDecodingSettings::NONR); d->noiseReductionComboBox->setToolTip(i18nc("@info:whatsthis", "Noise Reduction" "

Select here the noise reduction method to apply during RAW " "decoding.

" "

  • None: no " "noise reduction.
  • " "
  • Wavelets: wavelets " "correction to erase noise while preserving real detail. It's " "applied after interpolation.
  • " "
  • FBDD: Fake Before " "Demosaicing Denoising noise reduction. It's applied before " "interpolation.
  • " "
  • CFA Line Denoise: Banding " "noise suppression. It's applied after interpolation.
  • " "
  • Impulse Denoise: Impulse " "noise suppression. It's applied after interpolation.

")); d->NRSpinBox1 = new RIntNumInput(d->correctionsSettings); d->NRSpinBox1->setRange(100, 1000, 1); d->NRSpinBox1->setDefaultValue(100); d->NRLabel1 = new QLabel(d->correctionsSettings); d->NRSpinBox2 = new RIntNumInput(d->correctionsSettings); d->NRSpinBox2->setRange(100, 1000, 1); d->NRSpinBox2->setDefaultValue(100); d->NRLabel2 = new QLabel(d->correctionsSettings); d->enableCACorrectionBox = new QCheckBox(i18nc("@option:check", "Enable Chromatic Aberration correction"), d->correctionsSettings); d->enableCACorrectionBox->setToolTip(i18nc("@info:whatsthis", "Enable Chromatic " "Aberration correction" "

Enlarge the raw red-green and blue-yellow axis by the given " "factors (automatic by default).

")); d->autoCACorrectionBox = new QCheckBox(i18nc("@option:check", "Automatic color axis adjustments"), d->correctionsSettings); d->autoCACorrectionBox->setToolTip(i18nc("@info:whatsthis", "Automatic Chromatic " "Aberration correction" "

If this option is turned on, it will try to shift image " "channels slightly and evaluate Chromatic Aberration change. Note " "that if you shot blue-red pattern, the method may fail. In this " "case, disable this option and tune manually color factors.

")); d->caRedMultLabel = new QLabel(i18nc("@label:slider", "Red-Green:"), d->correctionsSettings); d->caRedMultSpinBox = new RDoubleNumInput(d->correctionsSettings); d->caRedMultSpinBox->setDecimals(1); d->caRedMultSpinBox->setRange(-4.0, 4.0, 0.1); d->caRedMultSpinBox->setDefaultValue(0.0); d->caRedMultSpinBox->setToolTip(i18nc("@info:whatsthis", "Red-Green multiplier" "

Set here the amount of correction on red-green axis

")); d->caBlueMultLabel = new QLabel(i18nc("@label:slider", "Blue-Yellow:"), d->correctionsSettings); d->caBlueMultSpinBox = new RDoubleNumInput(d->correctionsSettings); d->caBlueMultSpinBox->setDecimals(1); d->caBlueMultSpinBox->setRange(-4.0, 4.0, 0.1); d->caBlueMultSpinBox->setDefaultValue(0.0); d->caBlueMultSpinBox->setToolTip(i18nc("@info:whatsthis", "Blue-Yellow multiplier" "

Set here the amount of correction on blue-yellow axis

")); correctionsLayout->addWidget(d->noiseReductionLabel, 0, 0, 1, 1); correctionsLayout->addWidget(d->noiseReductionComboBox, 0, 1, 1, 2); correctionsLayout->addWidget(d->NRLabel1, 1, 0, 1, 1); correctionsLayout->addWidget(d->NRSpinBox1, 1, 1, 1, 2); correctionsLayout->addWidget(d->NRLabel2, 2, 0, 1, 1); correctionsLayout->addWidget(d->NRSpinBox2, 2, 1, 1, 2); correctionsLayout->addWidget(d->enableCACorrectionBox, 3, 0, 1, 3); correctionsLayout->addWidget(d->autoCACorrectionBox, 4, 0, 1, 3); correctionsLayout->addWidget(d->caRedMultLabel, 5, 0, 1, 1); correctionsLayout->addWidget(d->caRedMultSpinBox, 5, 1, 1, 2); correctionsLayout->addWidget(d->caBlueMultLabel, 6, 0, 1, 1); correctionsLayout->addWidget(d->caBlueMultSpinBox, 6, 1, 1, 2); correctionsLayout->setRowStretch(7, 10); correctionsLayout->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); correctionsLayout->setMargin(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); addItem(d->correctionsSettings, KisIconUtils::loadIcon("kdcraw").pixmap(16, 16), i18nc("@label", "Corrections"), QString("corrections"), false); // --------------------------------------------------------------- // COLOR MANAGEMENT Settings panel d->colormanSettings = new QWidget(this); QGridLayout* const colormanLayout = new QGridLayout(d->colormanSettings); d->inputColorSpaceLabel = new QLabel(i18nc("@label:listbox", "Camera Profile:"), d->colormanSettings); d->inputColorSpaceComboBox = new RComboBox(d->colormanSettings); d->inputColorSpaceComboBox->insertItem(RawDecodingSettings::NOINPUTCS, i18nc("@item:inlistbox Camera Profile", "None")); d->inputColorSpaceComboBox->insertItem(RawDecodingSettings::EMBEDDED, i18nc("@item:inlistbox Camera Profile", "Embedded")); d->inputColorSpaceComboBox->insertItem(RawDecodingSettings::CUSTOMINPUTCS, i18nc("@item:inlistbox Camera Profile", "Custom")); d->inputColorSpaceComboBox->setDefaultIndex(RawDecodingSettings::NOINPUTCS); d->inputColorSpaceComboBox->setToolTip(i18nc("@info:whatsthis", "Camera Profile" "

Select here the input color space used to decode RAW data.

" "

  • None: no " "input color profile is used during RAW decoding.
  • " "
  • Embedded: use embedded " "color profile from RAW file, if it exists.
  • " "
  • Custom: use a custom " "input color space profile.

")); d->inIccUrlEdit = new RFileSelector(d->colormanSettings); d->inIccUrlEdit->setFileDlgMode(QFileDialog::ExistingFile); d->inIccUrlEdit->setFileDlgFilter(i18n("ICC Files (*.icc; *.icm)")); d->outputColorSpaceLabel = new QLabel(i18nc("@label:listbox", "Workspace:"), d->colormanSettings); d->outputColorSpaceComboBox = new RComboBox( d->colormanSettings ); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::RAWCOLOR, i18nc("@item:inlistbox Workspace", "Raw (no profile)")); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::SRGB, i18nc("@item:inlistbox Workspace", "sRGB")); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::ADOBERGB, i18nc("@item:inlistbox Workspace", "Adobe RGB")); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::WIDEGAMMUT, i18nc("@item:inlistbox Workspace", "Wide Gamut")); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::PROPHOTO, i18nc("@item:inlistbox Workspace", "Pro-Photo")); d->outputColorSpaceComboBox->insertItem(RawDecodingSettings::CUSTOMOUTPUTCS, i18nc("@item:inlistbox Workspace", "Custom")); d->outputColorSpaceComboBox->setDefaultIndex(RawDecodingSettings::SRGB); d->outputColorSpaceComboBox->setToolTip(i18nc("@info:whatsthis", "Workspace" "

Select here the output color space used to decode RAW data.

" "

  • Raw (linear): " "in this mode, no output color space is used during RAW decoding.
  • " "
  • sRGB: this is an RGB " "color space, created cooperatively by Hewlett-Packard and " "Microsoft. It is the best choice for images destined for the Web " "and portrait photography.
  • " "
  • Adobe RGB: this color " "space is an extended RGB color space, developed by Adobe. It is " "used for photography applications such as advertising and fine " "art.
  • " "
  • Wide Gamut: this color " "space is an expanded version of the Adobe RGB color space.
  • " "
  • Pro-Photo: this color " "space is an RGB color space, developed by Kodak, that offers an " "especially large gamut designed for use with photographic outputs " "in mind.
  • " "
  • Custom: use a custom " "output color space profile.

")); d->outIccUrlEdit = new RFileSelector(d->colormanSettings); d->outIccUrlEdit->setFileDlgMode(QFileDialog::ExistingFile); d->outIccUrlEdit->setFileDlgFilter(i18n("ICC Files (*.icc; *.icm)")); colormanLayout->addWidget(d->inputColorSpaceLabel, 0, 0, 1, 1); colormanLayout->addWidget(d->inputColorSpaceComboBox, 0, 1, 1, 2); colormanLayout->addWidget(d->inIccUrlEdit, 1, 0, 1, 3); colormanLayout->addWidget(d->outputColorSpaceLabel, 2, 0, 1, 1); colormanLayout->addWidget(d->outputColorSpaceComboBox, 2, 1, 1, 2); colormanLayout->addWidget(d->outIccUrlEdit, 3, 0, 1, 3); colormanLayout->setRowStretch(4, 10); colormanLayout->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); colormanLayout->setMargin(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); addItem(d->colormanSettings, KisIconUtils::loadIcon("kdcraw").pixmap(16, 16), i18nc("@label", "Color Management"), QString("colormanagement"), false); if (! (advSettings & COLORSPACE)) removeItem(COLORMANAGEMENT); addStretch(); // --------------------------------------------------------------- connect(d->unclipColorComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotUnclipColorActivated); connect(d->whiteBalanceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotWhiteBalanceToggled); connect(d->noiseReductionComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotNoiseReductionChanged); connect(d->enableCACorrectionBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::slotCACorrectionToggled); connect(d->autoCACorrectionBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::slotAutoCAToggled); connect(d->blackPointCheckBox, SIGNAL(toggled(bool)), d->blackPointSpinBox, SLOT(setEnabled(bool))); connect(d->whitePointCheckBox, SIGNAL(toggled(bool)), d->whitePointSpinBox, SLOT(setEnabled(bool))); connect(d->sixteenBitsImage, &QCheckBox::toggled, this, &DcrawSettingsWidget::slotsixteenBitsImageToggled); connect(d->inputColorSpaceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotInputColorSpaceChanged); connect(d->outputColorSpaceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotOutputColorSpaceChanged); connect(d->expoCorrectionBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::slotExposureCorrectionToggled); connect(d->expoCorrectionShiftSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::slotExpoCorrectionShiftChanged); // Wrapper to emit signal when something is changed in settings. connect(d->inIccUrlEdit->lineEdit(), &QLineEdit::textChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->outIccUrlEdit->lineEdit(), &QLineEdit::textChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->whiteBalanceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->RAWQualityComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::slotRAWQualityChanged); connect(d->unclipColorComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->inputColorSpaceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->outputColorSpaceComboBox, static_cast(&RComboBox::activated), this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->blackPointCheckBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->whitePointCheckBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->sixteenBitsImage, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->fixColorsHighlightsBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->autoBrightnessBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->fourColorCheckBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->dontStretchPixelsCheckBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->refineInterpolationBox, &QCheckBox::toggled, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->customWhiteBalanceSpinBox, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->reconstructSpinBox, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->blackPointSpinBox, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->whitePointSpinBox, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->NRSpinBox1, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->NRSpinBox2, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->medianFilterPassesSpinBox, &RIntNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->customWhiteBalanceGreenSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->caRedMultSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->caBlueMultSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->brightnessSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); connect(d->expoCorrectionHighlightSpinBox, &RDoubleNumInput::valueChanged, this, &DcrawSettingsWidget::signalSettingsChanged); } DcrawSettingsWidget::~DcrawSettingsWidget() { delete d; } void DcrawSettingsWidget::updateMinimumWidth() { int width = 0; for (int i = 0; i < count(); i++) { if (widget(i)->width() > width) width = widget(i)->width(); } setMinimumWidth(width); } RFileSelector* DcrawSettingsWidget::inputProfileUrlEdit() const { return d->inIccUrlEdit; } RFileSelector* DcrawSettingsWidget::outputProfileUrlEdit() const { return d->outIccUrlEdit; } void DcrawSettingsWidget::resetToDefault() { setSettings(RawDecodingSettings()); } void DcrawSettingsWidget::slotsixteenBitsImageToggled(bool b) { setEnabledBrightnessSettings(!b); emit signalSixteenBitsImageToggled(d->sixteenBitsImage->isChecked()); } void DcrawSettingsWidget::slotWhiteBalanceToggled(int v) { if (v == 3) { d->customWhiteBalanceSpinBox->setEnabled(true); d->customWhiteBalanceGreenSpinBox->setEnabled(true); d->customWhiteBalanceLabel->setEnabled(true); d->customWhiteBalanceGreenLabel->setEnabled(true); } else { d->customWhiteBalanceSpinBox->setEnabled(false); d->customWhiteBalanceGreenSpinBox->setEnabled(false); d->customWhiteBalanceLabel->setEnabled(false); d->customWhiteBalanceGreenLabel->setEnabled(false); } } void DcrawSettingsWidget::slotUnclipColorActivated(int v) { if (v == 3) // Reconstruct Highlight method { d->reconstructLabel->setEnabled(true); d->reconstructSpinBox->setEnabled(true); } else { d->reconstructLabel->setEnabled(false); d->reconstructSpinBox->setEnabled(false); } } void DcrawSettingsWidget::slotNoiseReductionChanged(int item) { d->NRSpinBox1->setEnabled(true); d->NRLabel1->setEnabled(true); d->NRSpinBox2->setEnabled(true); d->NRLabel2->setEnabled(true); d->NRLabel1->setText(i18nc("@label", "Threshold:")); d->NRSpinBox1->setToolTip(i18nc("@info:whatsthis", "Threshold" "

Set here the noise reduction threshold value to use.

")); switch(item) { case RawDecodingSettings::WAVELETSNR: case RawDecodingSettings::FBDDNR: case RawDecodingSettings::LINENR: d->NRSpinBox2->setVisible(false); d->NRLabel2->setVisible(false); break; case RawDecodingSettings::IMPULSENR: d->NRLabel1->setText(i18nc("@label", "Luminance:")); d->NRSpinBox1->setToolTip(i18nc("@info:whatsthis", "Luminance" "

Amount of Luminance impulse noise reduction.

")); d->NRLabel2->setText(i18nc("@label", "Chrominance:")); d->NRSpinBox2->setToolTip(i18nc("@info:whatsthis", "Chrominance" "

Amount of Chrominance impulse noise reduction.

")); d->NRSpinBox2->setVisible(true); d->NRLabel2->setVisible(true); break; default: d->NRSpinBox1->setEnabled(false); d->NRLabel1->setEnabled(false); d->NRSpinBox2->setEnabled(false); d->NRLabel2->setEnabled(false); d->NRSpinBox2->setVisible(false); d->NRLabel2->setVisible(false); break; } emit signalSettingsChanged(); } void DcrawSettingsWidget::slotCACorrectionToggled(bool b) { d->autoCACorrectionBox->setEnabled(b); slotAutoCAToggled(d->autoCACorrectionBox->isChecked()); } void DcrawSettingsWidget::slotAutoCAToggled(bool b) { if (b) { d->caRedMultSpinBox->setValue(0.0); d->caBlueMultSpinBox->setValue(0.0); } bool mult = (!b) && (d->autoCACorrectionBox->isEnabled()); d->caRedMultSpinBox->setEnabled(mult); d->caBlueMultSpinBox->setEnabled(mult); d->caRedMultLabel->setEnabled(mult); d->caBlueMultLabel->setEnabled(mult); emit signalSettingsChanged(); } void DcrawSettingsWidget::slotExposureCorrectionToggled(bool b) { d->expoCorrectionShiftLabel->setEnabled(b); d->expoCorrectionShiftSpinBox->setEnabled(b); d->expoCorrectionHighlightLabel->setEnabled(b); d->expoCorrectionHighlightSpinBox->setEnabled(b); slotExpoCorrectionShiftChanged(d->expoCorrectionShiftSpinBox->value()); } void DcrawSettingsWidget::slotExpoCorrectionShiftChanged(double ev) { // Only enable Highligh exposure correction if Shift correction is >= 1.0, else this settings do not take effect. bool b = (ev >= 1.0); d->expoCorrectionHighlightLabel->setEnabled(b); d->expoCorrectionHighlightSpinBox->setEnabled(b); emit signalSettingsChanged(); } void DcrawSettingsWidget::slotInputColorSpaceChanged(int item) { d->inIccUrlEdit->setEnabled(item == RawDecodingSettings::CUSTOMINPUTCS); } void DcrawSettingsWidget::slotOutputColorSpaceChanged(int item) { d->outIccUrlEdit->setEnabled(item == RawDecodingSettings::CUSTOMOUTPUTCS); } void DcrawSettingsWidget::slotRAWQualityChanged(int quality) { switch(quality) { case RawDecodingSettings::DCB: case RawDecodingSettings::VCD_AHD: // These options can be only available if Libraw use GPL2 pack. d->medianFilterPassesLabel->setEnabled(KDcraw::librawUseGPL2DemosaicPack()); d->medianFilterPassesSpinBox->setEnabled(KDcraw::librawUseGPL2DemosaicPack()); d->refineInterpolationBox->setEnabled(KDcraw::librawUseGPL2DemosaicPack()); break; case RawDecodingSettings::PL_AHD: case RawDecodingSettings::AFD: case RawDecodingSettings::VCD: case RawDecodingSettings::LMMSE: case RawDecodingSettings::AMAZE: d->medianFilterPassesLabel->setEnabled(false); d->medianFilterPassesSpinBox->setEnabled(false); d->refineInterpolationBox->setEnabled(false); break; default: // BILINEAR, VNG, PPG, AHD d->medianFilterPassesLabel->setEnabled(true); d->medianFilterPassesSpinBox->setEnabled(true); d->refineInterpolationBox->setEnabled(false); break; } emit signalSettingsChanged(); } void DcrawSettingsWidget::setEnabledBrightnessSettings(bool b) { d->brightnessLabel->setEnabled(b); d->brightnessSpinBox->setEnabled(b); } bool DcrawSettingsWidget::brightnessSettingsIsEnabled() const { return d->brightnessSpinBox->isEnabled(); } void DcrawSettingsWidget::setSettings(const RawDecodingSettings& settings) { d->sixteenBitsImage->setChecked(settings.sixteenBitsImage); switch(settings.whiteBalance) { case RawDecodingSettings::CAMERA: d->whiteBalanceComboBox->setCurrentIndex(1); break; case RawDecodingSettings::AUTO: d->whiteBalanceComboBox->setCurrentIndex(2); break; case RawDecodingSettings::CUSTOM: d->whiteBalanceComboBox->setCurrentIndex(3); break; default: d->whiteBalanceComboBox->setCurrentIndex(0); break; } slotWhiteBalanceToggled(d->whiteBalanceComboBox->currentIndex()); d->customWhiteBalanceSpinBox->setValue(settings.customWhiteBalance); d->customWhiteBalanceGreenSpinBox->setValue(settings.customWhiteBalanceGreen); d->fourColorCheckBox->setChecked(settings.RGBInterpolate4Colors); d->autoBrightnessBox->setChecked(settings.autoBrightness); d->fixColorsHighlightsBox->setChecked(settings.fixColorsHighlights); switch(settings.unclipColors) { case 0: d->unclipColorComboBox->setCurrentIndex(0); break; case 1: d->unclipColorComboBox->setCurrentIndex(1); break; case 2: d->unclipColorComboBox->setCurrentIndex(2); break; default: // Reconstruct Highlight method d->unclipColorComboBox->setCurrentIndex(3); d->reconstructSpinBox->setValue(settings.unclipColors-3); break; } slotUnclipColorActivated(d->unclipColorComboBox->currentIndex()); d->dontStretchPixelsCheckBox->setChecked(settings.DontStretchPixels); d->brightnessSpinBox->setValue(settings.brightness); d->blackPointCheckBox->setChecked(settings.enableBlackPoint); d->blackPointSpinBox->setEnabled(settings.enableBlackPoint); d->blackPointSpinBox->setValue(settings.blackPoint); d->whitePointCheckBox->setChecked(settings.enableWhitePoint); d->whitePointSpinBox->setEnabled(settings.enableWhitePoint); d->whitePointSpinBox->setValue(settings.whitePoint); int q = settings.RAWQuality; // If Libraw do not support GPL2 pack, reset to BILINEAR. if (!KDcraw::librawUseGPL2DemosaicPack()) { for (int i=RawDecodingSettings::DCB ; i <=RawDecodingSettings::LMMSE ; ++i) { if (q == i) { q = RawDecodingSettings::BILINEAR; qCDebug(LIBKDCRAW_LOG) << "Libraw GPL2 pack not available. Raw quality set to Bilinear"; break; } } } // If Libraw do not support GPL3 pack, reset to BILINEAR. if (!KDcraw::librawUseGPL3DemosaicPack() && (q == RawDecodingSettings::AMAZE)) { q = RawDecodingSettings::BILINEAR; qCDebug(LIBKDCRAW_LOG) << "Libraw GPL3 pack not available. Raw quality set to Bilinear"; } d->RAWQualityComboBox->setCurrentIndex(q); switch(q) { case RawDecodingSettings::DCB: d->medianFilterPassesSpinBox->setValue(settings.dcbIterations); d->refineInterpolationBox->setChecked(settings.dcbEnhanceFl); break; case RawDecodingSettings::VCD_AHD: d->medianFilterPassesSpinBox->setValue(settings.eeciRefine); d->refineInterpolationBox->setChecked(settings.eeciRefine); break; default: d->medianFilterPassesSpinBox->setValue(settings.medianFilterPasses); d->refineInterpolationBox->setChecked(false); // option not used. break; } slotRAWQualityChanged(q); d->inputColorSpaceComboBox->setCurrentIndex((int)settings.inputColorSpace); slotInputColorSpaceChanged((int)settings.inputColorSpace); d->outputColorSpaceComboBox->setCurrentIndex((int)settings.outputColorSpace); slotOutputColorSpaceChanged((int)settings.outputColorSpace); d->noiseReductionComboBox->setCurrentIndex(settings.NRType); slotNoiseReductionChanged(settings.NRType); d->NRSpinBox1->setValue(settings.NRThreshold); d->NRSpinBox2->setValue(settings.NRChroThreshold); d->enableCACorrectionBox->setChecked(settings.enableCACorrection); d->caRedMultSpinBox->setValue(settings.caMultiplier[0]); d->caBlueMultSpinBox->setValue(settings.caMultiplier[1]); d->autoCACorrectionBox->setChecked((settings.caMultiplier[0] == 0.0) && (settings.caMultiplier[1] == 0.0)); slotCACorrectionToggled(settings.enableCACorrection); d->expoCorrectionBox->setChecked(settings.expoCorrection); slotExposureCorrectionToggled(settings.expoCorrection); d->expoCorrectionShiftSpinBox->setValue(d->shiftExpoFromLinearToEv(settings.expoCorrectionShift)); d->expoCorrectionHighlightSpinBox->setValue(settings.expoCorrectionHighlight); d->inIccUrlEdit->lineEdit()->setText(settings.inputProfile); d->outIccUrlEdit->lineEdit()->setText(settings.outputProfile); } RawDecodingSettings DcrawSettingsWidget::settings() const { RawDecodingSettings prm; prm.sixteenBitsImage = d->sixteenBitsImage->isChecked(); switch(d->whiteBalanceComboBox->currentIndex()) { case 1: prm.whiteBalance = RawDecodingSettings::CAMERA; break; case 2: prm.whiteBalance = RawDecodingSettings::AUTO; break; case 3: prm.whiteBalance = RawDecodingSettings::CUSTOM; break; default: prm.whiteBalance = RawDecodingSettings::NONE; break; } prm.customWhiteBalance = d->customWhiteBalanceSpinBox->value(); prm.customWhiteBalanceGreen = d->customWhiteBalanceGreenSpinBox->value(); prm.RGBInterpolate4Colors = d->fourColorCheckBox->isChecked(); prm.autoBrightness = d->autoBrightnessBox->isChecked(); prm.fixColorsHighlights = d->fixColorsHighlightsBox->isChecked(); switch(d->unclipColorComboBox->currentIndex()) { case 0: prm.unclipColors = 0; break; case 1: prm.unclipColors = 1; break; case 2: prm.unclipColors = 2; break; default: // Reconstruct Highlight method prm.unclipColors = d->reconstructSpinBox->value()+3; break; } prm.DontStretchPixels = d->dontStretchPixelsCheckBox->isChecked(); prm.brightness = d->brightnessSpinBox->value(); prm.enableBlackPoint = d->blackPointCheckBox->isChecked(); prm.blackPoint = d->blackPointSpinBox->value(); prm.enableWhitePoint = d->whitePointCheckBox->isChecked(); prm.whitePoint = d->whitePointSpinBox->value(); prm.RAWQuality = (RawDecodingSettings::DecodingQuality)d->RAWQualityComboBox->currentIndex(); switch(prm.RAWQuality) { case RawDecodingSettings::DCB: prm.dcbIterations = d->medianFilterPassesSpinBox->value(); prm.dcbEnhanceFl = d->refineInterpolationBox->isChecked(); break; case RawDecodingSettings::VCD_AHD: prm.esMedPasses = d->medianFilterPassesSpinBox->value(); prm.eeciRefine = d->refineInterpolationBox->isChecked(); break; default: prm.medianFilterPasses = d->medianFilterPassesSpinBox->value(); break; } prm.NRType = (RawDecodingSettings::NoiseReduction)d->noiseReductionComboBox->currentIndex(); switch (prm.NRType) { case RawDecodingSettings::NONR: { prm.NRThreshold = 0; prm.NRChroThreshold = 0; break; } case RawDecodingSettings::WAVELETSNR: case RawDecodingSettings::FBDDNR: case RawDecodingSettings::LINENR: { prm.NRThreshold = d->NRSpinBox1->value(); prm.NRChroThreshold = 0; break; } default: // IMPULSENR { prm.NRThreshold = d->NRSpinBox1->value(); prm.NRChroThreshold = d->NRSpinBox2->value(); break; } } prm.enableCACorrection = d->enableCACorrectionBox->isChecked(); prm.caMultiplier[0] = d->caRedMultSpinBox->value(); prm.caMultiplier[1] = d->caBlueMultSpinBox->value(); prm.expoCorrection = d->expoCorrectionBox->isChecked(); prm.expoCorrectionShift = d->shiftExpoFromEvToLinear(d->expoCorrectionShiftSpinBox->value()); prm.expoCorrectionHighlight = d->expoCorrectionHighlightSpinBox->value(); prm.inputColorSpace = (RawDecodingSettings::InputColorSpace)(d->inputColorSpaceComboBox->currentIndex()); prm.outputColorSpace = (RawDecodingSettings::OutputColorSpace)(d->outputColorSpaceComboBox->currentIndex()); prm.inputProfile = d->inIccUrlEdit->lineEdit()->text(); prm.outputProfile = d->outIccUrlEdit->lineEdit()->text(); return prm; } void DcrawSettingsWidget::writeSettings(KConfigGroup& group) { RawDecodingSettings prm = settings(); prm.writeSettings(group); RExpanderBox::writeSettings(group); } void DcrawSettingsWidget::readSettings(KConfigGroup& group) { RawDecodingSettings prm; prm.readSettings(group); setSettings(prm); RExpanderBox::readSettings(group); } } // NameSpace KDcrawIface diff --git a/plugins/impex/raw/3rdparty/libkdcraw/src/kdcraw_p.cpp b/plugins/impex/raw/3rdparty/libkdcraw/src/kdcraw_p.cpp index 38fdc2b2b7..cf5ffa482d 100644 --- a/plugins/impex/raw/3rdparty/libkdcraw/src/kdcraw_p.cpp +++ b/plugins/impex/raw/3rdparty/libkdcraw/src/kdcraw_p.cpp @@ -1,690 +1,690 @@ /** =========================================================== * @file * * This file is a part of digiKam project * http://www.digikam.org * * @date 2008-10-09 * @brief internal private container for KDcraw * * @author Copyright (C) 2008-2015 by Gilles Caulier * caulier dot gilles at gmail dot com * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "kdcraw.h" #include "kdcraw_p.h" // Qt includes #include #include // Local includes #include "libkdcraw_debug.h" namespace KDcrawIface { int callbackForLibRaw(void* data, enum LibRaw_progress p, int iteration, int expected) { if (data) { KDcraw::Private* const d = static_cast(data); if (d) { return d->progressCallback(p, iteration, expected); } } return 0; } // -------------------------------------------------------------------------------------------------- KDcraw::Private::Private(KDcraw* const p) { m_progress = 0.0; m_parent = p; } KDcraw::Private::~Private() { } void KDcraw::Private::createPPMHeader(QByteArray& imgData, libraw_processed_image_t* const img) { QString header = QString("P%1\n%2 %3\n%4\n").arg(img->colors == 3 ? "6" : "5") .arg(img->width) .arg(img->height) .arg((1 << img->bits)-1); imgData.append(header.toLatin1()); imgData.append(QByteArray((const char*)img->data, (int)img->data_size)); } int KDcraw::Private::progressCallback(enum LibRaw_progress p, int iteration, int expected) { qCDebug(LIBKDCRAW_LOG) << "LibRaw progress: " << libraw_strprogress(p) << " pass " << iteration << " of " << expected; // post a little change in progress indicator to show raw processor activity. setProgress(progressValue()+0.01); // Clean processing termination by user... if (m_parent->checkToCancelWaitingData()) { qCDebug(LIBKDCRAW_LOG) << "LibRaw process terminaison invoked..."; m_parent->m_cancel = true; m_progress = 0.0; return 1; } // Return 0 to continue processing... return 0; } void KDcraw::Private::setProgress(double value) { m_progress = value; m_parent->setWaitingDataProgress(m_progress); } double KDcraw::Private::progressValue() const { return m_progress; } void KDcraw::Private::fillIndentifyInfo(LibRaw* const raw, DcrawInfoContainer& identify) { - identify.dateTime.setTime_t(raw->imgdata.other.timestamp); + identify.dateTime.setSecsSinceEpoch(raw->imgdata.other.timestamp); identify.make = QString(raw->imgdata.idata.make); identify.model = QString(raw->imgdata.idata.model); identify.owner = QString(raw->imgdata.other.artist); identify.DNGVersion = QString::number(raw->imgdata.idata.dng_version); identify.sensitivity = raw->imgdata.other.iso_speed; identify.exposureTime = raw->imgdata.other.shutter; identify.aperture = raw->imgdata.other.aperture; identify.focalLength = raw->imgdata.other.focal_len; identify.imageSize = QSize(raw->imgdata.sizes.width, raw->imgdata.sizes.height); identify.fullSize = QSize(raw->imgdata.sizes.raw_width, raw->imgdata.sizes.raw_height); identify.outputSize = QSize(raw->imgdata.sizes.iwidth, raw->imgdata.sizes.iheight); identify.thumbSize = QSize(raw->imgdata.thumbnail.twidth, raw->imgdata.thumbnail.theight); identify.topMargin = raw->imgdata.sizes.top_margin; identify.leftMargin = raw->imgdata.sizes.left_margin; identify.hasIccProfile = raw->imgdata.color.profile ? true : false; identify.isDecodable = true; identify.pixelAspectRatio = raw->imgdata.sizes.pixel_aspect; identify.rawColors = raw->imgdata.idata.colors; identify.rawImages = raw->imgdata.idata.raw_count; identify.blackPoint = raw->imgdata.color.black; for (int ch = 0; ch < 4; ch++) { identify.blackPointCh[ch] = raw->imgdata.color.cblack[ch]; } identify.whitePoint = raw->imgdata.color.maximum; identify.orientation = (DcrawInfoContainer::ImageOrientation)raw->imgdata.sizes.flip; memcpy(&identify.cameraColorMatrix1, &raw->imgdata.color.cmatrix, sizeof(raw->imgdata.color.cmatrix)); memcpy(&identify.cameraColorMatrix2, &raw->imgdata.color.rgb_cam, sizeof(raw->imgdata.color.rgb_cam)); memcpy(&identify.cameraXYZMatrix, &raw->imgdata.color.cam_xyz, sizeof(raw->imgdata.color.cam_xyz)); if (raw->imgdata.idata.filters) { if (!raw->imgdata.idata.cdesc[3]) { raw->imgdata.idata.cdesc[3] = 'G'; } for (int i=0; i < 16; i++) { identify.filterPattern.append(raw->imgdata.idata.cdesc[raw->COLOR(i >> 1,i & 1)]); } identify.colorKeys = raw->imgdata.idata.cdesc; } for(int c = 0 ; c < raw->imgdata.idata.colors ; c++) { identify.daylightMult[c] = raw->imgdata.color.pre_mul[c]; } if (raw->imgdata.color.cam_mul[0] > 0) { for(int c = 0 ; c < 4 ; c++) { identify.cameraMult[c] = raw->imgdata.color.cam_mul[c]; } } } bool KDcraw::Private::loadFromLibraw(const QString& filePath, QByteArray& imageData, int& width, int& height, int& rgbmax) { m_parent->m_cancel = false; LibRaw raw; // Set progress call back function. raw.set_progress_handler(callbackForLibRaw, this); QByteArray deadpixelPath = QFile::encodeName(m_parent->m_rawDecodingSettings.deadPixelMap); QByteArray cameraProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.inputProfile); QByteArray outputProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.outputProfile); if (!m_parent->m_rawDecodingSettings.autoBrightness) { // Use a fixed white level, ignoring the image histogram. raw.imgdata.params.no_auto_bright = 1; } if (m_parent->m_rawDecodingSettings.sixteenBitsImage) { // (-4) 16bit ppm output raw.imgdata.params.output_bps = 16; } if (m_parent->m_rawDecodingSettings.halfSizeColorImage) { // (-h) Half-size color image (3x faster than -q). raw.imgdata.params.half_size = 1; } if (m_parent->m_rawDecodingSettings.RGBInterpolate4Colors) { // (-f) Interpolate RGB as four colors. raw.imgdata.params.four_color_rgb = 1; } if (m_parent->m_rawDecodingSettings.DontStretchPixels) { // (-j) Do not stretch the image to its correct aspect ratio. raw.imgdata.params.use_fuji_rotate = 1; } // (-H) Unclip highlight color. raw.imgdata.params.highlight = m_parent->m_rawDecodingSettings.unclipColors; if (m_parent->m_rawDecodingSettings.brightness != 1.0) { // (-b) Set Brightness value. raw.imgdata.params.bright = m_parent->m_rawDecodingSettings.brightness; } if (m_parent->m_rawDecodingSettings.enableBlackPoint) { // (-k) Set Black Point value. raw.imgdata.params.user_black = m_parent->m_rawDecodingSettings.blackPoint; } if (m_parent->m_rawDecodingSettings.enableWhitePoint) { // (-S) Set White Point value (saturation). raw.imgdata.params.user_sat = m_parent->m_rawDecodingSettings.whitePoint; } if (m_parent->m_rawDecodingSettings.medianFilterPasses > 0) { // (-m) After interpolation, clean up color artifacts by repeatedly applying a 3x3 median filter to the R-G and B-G channels. raw.imgdata.params.med_passes = m_parent->m_rawDecodingSettings.medianFilterPasses; } if (!m_parent->m_rawDecodingSettings.deadPixelMap.isEmpty()) { // (-P) Read the dead pixel list from this file. raw.imgdata.params.bad_pixels = deadpixelPath.data(); } switch (m_parent->m_rawDecodingSettings.whiteBalance) { case RawDecodingSettings::NONE: { break; } case RawDecodingSettings::CAMERA: { // (-w) Use camera white balance, if possible. raw.imgdata.params.use_camera_wb = 1; break; } case RawDecodingSettings::AUTO: { // (-a) Use automatic white balance. raw.imgdata.params.use_auto_wb = 1; break; } case RawDecodingSettings::CUSTOM: { /* Convert between Temperature and RGB. */ double T; double RGB[3]; double xD, yD, X, Y, Z; DcrawInfoContainer identify; T = m_parent->m_rawDecodingSettings.customWhiteBalance; /* Here starts the code picked and adapted from ufraw (0.12.1) to convert Temperature + green multiplier to RGB multipliers */ /* Convert between Temperature and RGB. * Base on information from http://www.brucelindbloom.com/ * The fit for D-illuminant between 4000K and 12000K are from CIE * The generalization to 2000K < T < 4000K and the blackbody fits * are my own and should be taken with a grain of salt. */ const double XYZ_to_RGB[3][3] = { { 3.24071, -0.969258, 0.0556352 }, {-1.53726, 1.87599, -0.203996 }, {-0.498571, 0.0415557, 1.05707 } }; // Fit for CIE Daylight illuminant if (T <= 4000) { xD = 0.27475e9/(T*T*T) - 0.98598e6/(T*T) + 1.17444e3/T + 0.145986; } else if (T <= 7000) { xD = -4.6070e9/(T*T*T) + 2.9678e6/(T*T) + 0.09911e3/T + 0.244063; } else { xD = -2.0064e9/(T*T*T) + 1.9018e6/(T*T) + 0.24748e3/T + 0.237040; } yD = -3*xD*xD + 2.87*xD - 0.275; X = xD/yD; Y = 1; Z = (1-xD-yD)/yD; RGB[0] = X*XYZ_to_RGB[0][0] + Y*XYZ_to_RGB[1][0] + Z*XYZ_to_RGB[2][0]; RGB[1] = X*XYZ_to_RGB[0][1] + Y*XYZ_to_RGB[1][1] + Z*XYZ_to_RGB[2][1]; RGB[2] = X*XYZ_to_RGB[0][2] + Y*XYZ_to_RGB[1][2] + Z*XYZ_to_RGB[2][2]; /* End of the code picked to ufraw */ RGB[1] = RGB[1] / m_parent->m_rawDecodingSettings.customWhiteBalanceGreen; /* By default, decraw override his default D65 WB We need to keep it as a basis : if not, colors with some DSLR will have a high dominant of color that will lead to a completely wrong WB */ if (rawFileIdentify(identify, filePath)) { RGB[0] = identify.daylightMult[0] / RGB[0]; RGB[1] = identify.daylightMult[1] / RGB[1]; RGB[2] = identify.daylightMult[2] / RGB[2]; } else { RGB[0] = 1.0 / RGB[0]; RGB[1] = 1.0 / RGB[1]; RGB[2] = 1.0 / RGB[2]; qCDebug(LIBKDCRAW_LOG) << "Warning: cannot get daylight multipliers"; } // (-r) set Raw Color Balance Multipliers. raw.imgdata.params.user_mul[0] = RGB[0]; raw.imgdata.params.user_mul[1] = RGB[1]; raw.imgdata.params.user_mul[2] = RGB[2]; raw.imgdata.params.user_mul[3] = RGB[1]; break; } case RawDecodingSettings::AERA: { // (-A) Calculate the white balance by averaging a rectangular area from image. raw.imgdata.params.greybox[0] = m_parent->m_rawDecodingSettings.whiteBalanceArea.left(); raw.imgdata.params.greybox[1] = m_parent->m_rawDecodingSettings.whiteBalanceArea.top(); raw.imgdata.params.greybox[2] = m_parent->m_rawDecodingSettings.whiteBalanceArea.width(); raw.imgdata.params.greybox[3] = m_parent->m_rawDecodingSettings.whiteBalanceArea.height(); break; } } // (-q) Use an interpolation method. raw.imgdata.params.user_qual = m_parent->m_rawDecodingSettings.RAWQuality; switch (m_parent->m_rawDecodingSettings.NRType) { case RawDecodingSettings::WAVELETSNR: { // (-n) Use wavelets to erase noise while preserving real detail. raw.imgdata.params.threshold = m_parent->m_rawDecodingSettings.NRThreshold; break; } case RawDecodingSettings::FBDDNR: { // (100 - 1000) => (1 - 10) conversion raw.imgdata.params.fbdd_noiserd = lround(m_parent->m_rawDecodingSettings.NRThreshold / 100.0); break; } case RawDecodingSettings::LINENR: { // (100 - 1000) => (0.001 - 0.02) conversion. raw.imgdata.params.linenoise = m_parent->m_rawDecodingSettings.NRThreshold * 2.11E-5 + 0.00111111; raw.imgdata.params.cfaline = true; break; } case RawDecodingSettings::IMPULSENR: { // (100 - 1000) => (0.005 - 0.05) conversion. raw.imgdata.params.lclean = m_parent->m_rawDecodingSettings.NRThreshold * 5E-5; raw.imgdata.params.cclean = m_parent->m_rawDecodingSettings.NRChroThreshold * 5E-5; raw.imgdata.params.cfa_clean = true; break; } default: // No Noise Reduction { raw.imgdata.params.threshold = 0; raw.imgdata.params.fbdd_noiserd = 0; raw.imgdata.params.linenoise = 0; raw.imgdata.params.cfaline = false; raw.imgdata.params.lclean = 0; raw.imgdata.params.cclean = 0; raw.imgdata.params.cfa_clean = false; break; } } // Chromatic aberration correction. raw.imgdata.params.ca_correc = m_parent->m_rawDecodingSettings.enableCACorrection; raw.imgdata.params.cared = m_parent->m_rawDecodingSettings.caMultiplier[0]; raw.imgdata.params.cablue = m_parent->m_rawDecodingSettings.caMultiplier[1]; // Exposure Correction before interpolation. raw.imgdata.params.exp_correc = m_parent->m_rawDecodingSettings.expoCorrection; raw.imgdata.params.exp_shift = m_parent->m_rawDecodingSettings.expoCorrectionShift; raw.imgdata.params.exp_preser = m_parent->m_rawDecodingSettings.expoCorrectionHighlight; switch (m_parent->m_rawDecodingSettings.inputColorSpace) { case RawDecodingSettings::EMBEDDED: { // (-p embed) Use input profile from RAW file to define the camera's raw colorspace. raw.imgdata.params.camera_profile = (char*)"embed"; break; } case RawDecodingSettings::CUSTOMINPUTCS: { if (!m_parent->m_rawDecodingSettings.inputProfile.isEmpty()) { // (-p) Use input profile file to define the camera's raw colorspace. raw.imgdata.params.camera_profile = cameraProfile.data(); } break; } default: { // No input profile break; } } switch (m_parent->m_rawDecodingSettings.outputColorSpace) { case RawDecodingSettings::CUSTOMOUTPUTCS: { if (!m_parent->m_rawDecodingSettings.outputProfile.isEmpty()) { // (-o) Use ICC profile file to define the output colorspace. raw.imgdata.params.output_profile = outputProfile.data(); } break; } default: { // (-o) Define the output colorspace. raw.imgdata.params.output_color = m_parent->m_rawDecodingSettings.outputColorSpace; break; } } //-- Extended demosaicing settings ---------------------------------------------------------- raw.imgdata.params.dcb_iterations = m_parent->m_rawDecodingSettings.dcbIterations; raw.imgdata.params.dcb_enhance_fl = m_parent->m_rawDecodingSettings.dcbEnhanceFl; raw.imgdata.params.eeci_refine = m_parent->m_rawDecodingSettings.eeciRefine; raw.imgdata.params.es_med_passes = m_parent->m_rawDecodingSettings.esMedPasses; //------------------------------------------------------------------------------------------- setProgress(0.1); qCDebug(LIBKDCRAW_LOG) << filePath; qCDebug(LIBKDCRAW_LOG) << m_parent->m_rawDecodingSettings; int ret = raw.open_file((const char*)(QFile::encodeName(filePath)).constData()); if (ret != LIBRAW_SUCCESS) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret); raw.recycle(); return false; } if (m_parent->m_cancel) { raw.recycle(); return false; } setProgress(0.2); ret = raw.unpack(); if (ret != LIBRAW_SUCCESS) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret); raw.recycle(); return false; } if (m_parent->m_cancel) { raw.recycle(); return false; } setProgress(0.25); if (m_parent->m_rawDecodingSettings.fixColorsHighlights) { qCDebug(LIBKDCRAW_LOG) << "Applying LibRaw highlights adjustments"; // 1.0 is fallback to default value raw.imgdata.params.adjust_maximum_thr = 1.0; } else { qCDebug(LIBKDCRAW_LOG) << "Disabling LibRaw highlights adjustments"; // 0.0 disables this feature raw.imgdata.params.adjust_maximum_thr = 0.0; } ret = raw.dcraw_process(); if (ret != LIBRAW_SUCCESS) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret); raw.recycle(); return false; } if (m_parent->m_cancel) { raw.recycle(); return false; } setProgress(0.3); libraw_processed_image_t* img = raw.dcraw_make_mem_image(&ret); if(!img) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret); raw.recycle(); return false; } if (m_parent->m_cancel) { // Clear memory allocation. Introduced with LibRaw 0.11.0 raw.dcraw_clear_mem(img); raw.recycle(); return false; } setProgress(0.35); width = img->width; height = img->height; rgbmax = (1 << img->bits)-1; if (img->colors == 3) { imageData = QByteArray((const char*)img->data, (int)img->data_size); } else { // img->colors == 1 (Grayscale) : convert to RGB imageData = QByteArray(); for (int i = 0 ; i < (int)img->data_size ; ++i) { for (int j = 0 ; j < 3 ; ++j) { imageData.append(img->data[i]); } } } // Clear memory allocation. Introduced with LibRaw 0.11.0 raw.dcraw_clear_mem(img); raw.recycle(); if (m_parent->m_cancel) { return false; } setProgress(0.4); qCDebug(LIBKDCRAW_LOG) << "LibRaw: data info: width=" << width << " height=" << height << " rgbmax=" << rgbmax; return true; } bool KDcraw::Private::loadEmbeddedPreview(QByteArray& imgData, LibRaw& raw) { int ret = raw.unpack_thumb(); if (ret != LIBRAW_SUCCESS) { raw.recycle(); qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack_thumb: " << libraw_strerror(ret); raw.recycle(); return false; } libraw_processed_image_t* const thumb = raw.dcraw_make_mem_thumb(&ret); if(!thumb) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_thumb: " << libraw_strerror(ret); raw.recycle(); return false; } if(thumb->type == LIBRAW_IMAGE_BITMAP) { createPPMHeader(imgData, thumb); } else { imgData = QByteArray((const char*)thumb->data, (int)thumb->data_size); } // Clear memory allocation. Introduced with LibRaw 0.11.0 raw.dcraw_clear_mem(thumb); raw.recycle(); if ( imgData.isEmpty() ) { qCDebug(LIBKDCRAW_LOG) << "Failed to load JPEG thumb from LibRaw!"; return false; } return true; } bool KDcraw::Private::loadHalfPreview(QImage& image, LibRaw& raw) { raw.imgdata.params.use_auto_wb = 1; // Use automatic white balance. raw.imgdata.params.use_camera_wb = 1; // Use camera white balance, if possible. raw.imgdata.params.half_size = 1; // Half-size color image (3x faster than -q). QByteArray imgData; int ret = raw.unpack(); if (ret != LIBRAW_SUCCESS) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret); raw.recycle(); return false; } ret = raw.dcraw_process(); if (ret != LIBRAW_SUCCESS) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret); raw.recycle(); return false; } libraw_processed_image_t* halfImg = raw.dcraw_make_mem_image(&ret); if(!halfImg) { qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret); raw.recycle(); return false; } Private::createPPMHeader(imgData, halfImg); // Clear memory allocation. Introduced with LibRaw 0.11.0 raw.dcraw_clear_mem(halfImg); raw.recycle(); if ( imgData.isEmpty() ) { qCDebug(LIBKDCRAW_LOG) << "Failed to load half preview from LibRaw!"; return false; } if (!image.loadFromData(imgData)) { qCDebug(LIBKDCRAW_LOG) << "Failed to load PPM data from LibRaw!"; return false; } return true; } } // namespace KDcrawIface diff --git a/plugins/paintops/libpaintop/kis_multi_sensors_model_p.cpp b/plugins/paintops/libpaintop/kis_multi_sensors_model_p.cpp index f7cd7237e2..8616b67f88 100644 --- a/plugins/paintops/libpaintop/kis_multi_sensors_model_p.cpp +++ b/plugins/paintops/libpaintop/kis_multi_sensors_model_p.cpp @@ -1,125 +1,124 @@ /* * Copyright (c) 2011 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_multi_sensors_model_p.h" #include "kis_dynamic_sensor.h" #include "kis_curve_option.h" KisMultiSensorsModel::KisMultiSensorsModel(QObject* parent) : QAbstractListModel(parent) , m_curveOption(0) { } KisMultiSensorsModel::~KisMultiSensorsModel() { } void KisMultiSensorsModel::setCurveOption(KisCurveOption *curveOption) { beginResetModel(); m_curveOption = curveOption; endResetModel(); } int KisMultiSensorsModel::rowCount(const QModelIndex &/*parent*/) const { if (m_curveOption) { return m_curveOption->sensors().size(); } else { return 0; } } QVariant KisMultiSensorsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role == Qt::DisplayRole) { return KisDynamicSensor::sensorsIds()[index.row()].name(); } else if (role == Qt::CheckStateRole) { QString selectedSensorId = KisDynamicSensor::sensorsIds()[index.row()].id(); KisDynamicSensorSP sensor = m_curveOption->sensor(KisDynamicSensor::id2Type(selectedSensorId), false); if (sensor) { //dbgKrita << sensor->id() << sensor->isActive(); return QVariant(sensor->isActive() ? Qt::Checked : Qt::Unchecked); } else { return QVariant(Qt::Unchecked); } } return QVariant(); } bool KisMultiSensorsModel::setData(const QModelIndex &index, const QVariant &value, int role) { bool result = false; if (role == Qt::CheckStateRole) { bool checked = (value.toInt() == Qt::Checked); if (checked || m_curveOption->activeSensors().size() != 1) { // Don't uncheck the last sensor (but why not?) KisDynamicSensorSP sensor = m_curveOption->sensor(KisDynamicSensor::id2Type(KisDynamicSensor::sensorsIds()[index.row()].id()), false); if (!sensor) { sensor = KisDynamicSensor::id2Sensor(KisDynamicSensor::sensorsIds()[index.row()].id()); m_curveOption->replaceSensor(sensor); } sensor->setActive(checked); emit(parametersChanged()); result = true; } } return result; } Qt::ItemFlags KisMultiSensorsModel::flags(const QModelIndex & /*index */) const { return Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; } KisDynamicSensorSP KisMultiSensorsModel::getSensor(const QModelIndex& index) { if (!index.isValid()) return 0; QString id = KisDynamicSensor::sensorsIds()[index.row()].id(); return m_curveOption->sensor(KisDynamicSensor::id2Type(id), false); } void KisMultiSensorsModel::setCurrentCurve(const QModelIndex& currentIndex, const KisCubicCurve& curve, bool useSameCurve) { if (!currentIndex.isValid()) return; QString selectedSensorId = KisDynamicSensor::sensorsIds()[currentIndex.row()].id(); m_curveOption->setCurve(KisDynamicSensor::id2Type(selectedSensorId), useSameCurve, curve); } QModelIndex KisMultiSensorsModel::sensorIndex(KisDynamicSensorSP arg1) { return index(KisDynamicSensor::sensorsIds().indexOf(KoID(KisDynamicSensor::id(arg1->sensorType())))); } void KisMultiSensorsModel::resetCurveOption() { beginResetModel(); - reset(); endResetModel(); } diff --git a/plugins/tools/karbonplugins/filtereffects/ColorMatrixEffectConfigWidget.cpp b/plugins/tools/karbonplugins/filtereffects/ColorMatrixEffectConfigWidget.cpp index b1880cd462..a97c78abe7 100644 --- a/plugins/tools/karbonplugins/filtereffects/ColorMatrixEffectConfigWidget.cpp +++ b/plugins/tools/karbonplugins/filtereffects/ColorMatrixEffectConfigWidget.cpp @@ -1,181 +1,181 @@ /* This file is part of the KDE project * Copyright (c) 2009-2010 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "ColorMatrixEffectConfigWidget.h" #include "ColorMatrixEffect.h" #include "KoFilterEffect.h" #include "MatrixDataModel.h" #include #include #include #include #include #include #include #include #include "kis_double_parse_spin_box.h" ColorMatrixEffectConfigWidget::ColorMatrixEffectConfigWidget(QWidget *parent) : KoFilterEffectConfigWidgetBase(parent) , m_effect(0) { QGridLayout *g = new QGridLayout(this); m_type = new KComboBox(this); m_type->addItem(i18n("Apply color matrix")); m_type->addItem(i18n("Saturate colors")); m_type->addItem(i18n("Rotate hue")); m_type->addItem(i18n("Luminance to alpha")); g->addWidget(m_type, 0, 0); m_stack = new QStackedWidget(this); m_stack->setContentsMargins(0, 0, 0, 0); g->addWidget(m_stack, 1, 0); m_matrixModel = new MatrixDataModel(this); QTableView *matrixWidget = new QTableView(m_stack); matrixWidget->setModel(m_matrixModel); matrixWidget->horizontalHeader()->hide(); - matrixWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + matrixWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); matrixWidget->verticalHeader()->hide(); - matrixWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); + matrixWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_stack->addWidget(matrixWidget); QWidget *saturateWidget = new QWidget(m_stack); QGridLayout *saturateLayout = new QGridLayout(saturateWidget); saturateLayout->addWidget(new QLabel(i18n("Saturate value"), saturateWidget), 0, 0); m_saturate = new KisDoubleParseSpinBox(saturateWidget); m_saturate->setRange(0.0, 1.0); m_saturate->setSingleStep(0.05); saturateLayout->addWidget(m_saturate, 0, 1); saturateLayout->addItem(new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 1, 0); saturateWidget->setLayout(saturateLayout); m_stack->addWidget(saturateWidget); QWidget *hueRotateWidget = new QWidget(m_stack); QGridLayout *hueRotateLayout = new QGridLayout(hueRotateWidget); hueRotateLayout->addWidget(new QLabel(i18n("Angle"), hueRotateWidget), 0, 0); m_hueRotate = new KisDoubleParseSpinBox(hueRotateWidget); m_hueRotate->setRange(0.0, 360.0); m_hueRotate->setSingleStep(1.0); hueRotateLayout->addWidget(m_hueRotate, 0, 1); hueRotateLayout->addItem(new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 1, 0); hueRotateWidget->setLayout(hueRotateLayout); m_stack->addWidget(hueRotateWidget); QWidget *luminanceWidget = new QWidget(m_stack); m_stack->addWidget(luminanceWidget); setLayout(g); connect(m_type, SIGNAL(currentIndexChanged(int)), m_stack, SLOT(setCurrentIndex(int))); connect(m_type, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int))); connect(m_saturate, SIGNAL(valueChanged(double)), this, SLOT(saturateChanged(double))); connect(m_hueRotate, SIGNAL(valueChanged(double)), this, SLOT(hueRotateChanged(double))); connect(m_matrixModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(matrixChanged())); } bool ColorMatrixEffectConfigWidget::editFilterEffect(KoFilterEffect *filterEffect) { m_effect = dynamic_cast(filterEffect); if (!m_effect) { return false; } m_type->blockSignals(true); switch (m_effect->type()) { case ColorMatrixEffect::Matrix: m_type->setCurrentIndex(0); m_matrixModel->setMatrix(m_effect->colorMatrix(), m_effect->colorMatrixRowCount(), m_effect->colorMatrixColumnCount()); break; case ColorMatrixEffect::Saturate: m_type->setCurrentIndex(1); m_saturate->blockSignals(true); m_saturate->setValue(m_effect->saturate()); m_saturate->blockSignals(false); break; case ColorMatrixEffect::HueRotate: m_type->setCurrentIndex(2); m_hueRotate->blockSignals(true); m_hueRotate->setValue(m_effect->hueRotate()); m_hueRotate->blockSignals(false); break; case ColorMatrixEffect::LuminanceAlpha: m_type->setCurrentIndex(3); break; } m_type->blockSignals(false); m_stack->setCurrentIndex(m_type->currentIndex()); return true; } void ColorMatrixEffectConfigWidget::matrixChanged() { if (!m_effect) { return; } m_effect->setColorMatrix(m_matrixModel->matrix()); emit filterChanged(); } void ColorMatrixEffectConfigWidget::saturateChanged(double saturate) { if (!m_effect) { return; } m_effect->setSaturate(saturate); emit filterChanged(); } void ColorMatrixEffectConfigWidget::hueRotateChanged(double angle) { if (!m_effect) { return; } m_effect->setHueRotate(angle); emit filterChanged(); } void ColorMatrixEffectConfigWidget::typeChanged(int index) { if (!m_effect) { return; } if (index == ColorMatrixEffect::Matrix) { m_effect->setColorMatrix(m_matrixModel->matrix()); } else if (index == ColorMatrixEffect::Saturate) { m_effect->setSaturate(m_saturate->value()); } else if (index == ColorMatrixEffect::HueRotate) { m_effect->setHueRotate(m_hueRotate->value()); } else { m_effect->setLuminanceAlpha(); } emit filterChanged(); } diff --git a/plugins/tools/karbonplugins/filtereffects/ConvolveMatrixEffectConfigWidget.cpp b/plugins/tools/karbonplugins/filtereffects/ConvolveMatrixEffectConfigWidget.cpp index 6bacd30a5a..7d8a7e8c2f 100644 --- a/plugins/tools/karbonplugins/filtereffects/ConvolveMatrixEffectConfigWidget.cpp +++ b/plugins/tools/karbonplugins/filtereffects/ConvolveMatrixEffectConfigWidget.cpp @@ -1,262 +1,262 @@ /* This file is part of the KDE project * Copyright (c) 2010 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "ConvolveMatrixEffectConfigWidget.h" #include "ConvolveMatrixEffect.h" #include "KoFilterEffect.h" #include "MatrixDataModel.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_double_parse_spin_box.h" #include "kis_int_parse_spin_box.h" ConvolveMatrixEffectConfigWidget::ConvolveMatrixEffectConfigWidget(QWidget *parent) : KoFilterEffectConfigWidgetBase(parent) , m_effect(0) { QGridLayout *g = new QGridLayout(this); m_edgeMode = new KComboBox(this); m_edgeMode->addItem(i18n("Duplicate")); m_edgeMode->addItem(i18n("Wrap")); m_edgeMode->addItem(i18n("None")); g->addWidget(new QLabel(i18n("Edge mode:"), this), 0, 0); g->addWidget(m_edgeMode, 0, 1, 1, 3); m_orderX = new KisIntParseSpinBox(this); m_orderX->setRange(1, 30); m_orderY = new KisIntParseSpinBox(this); m_orderY->setRange(1, 30); g->addWidget(new QLabel(i18n("Kernel size:"), this), 1, 0); g->addWidget(m_orderX, 1, 1); g->addWidget(new QLabel("X", this), 1, 2, Qt::AlignHCenter); g->addWidget(m_orderY, 1, 3); m_targetX = new KisIntParseSpinBox(this); m_targetX->setRange(0, 30); m_targetY = new KisIntParseSpinBox(this); m_targetY->setRange(0, 30); g->addWidget(new QLabel(i18n("Target point:"), this), 2, 0); g->addWidget(m_targetX, 2, 1); g->addWidget(new QLabel("X", this), 2, 2, Qt::AlignHCenter); g->addWidget(m_targetY, 2, 3); m_divisor = new KisDoubleParseSpinBox(this); m_bias = new KisDoubleParseSpinBox(this); g->addWidget(new QLabel(i18n("Divisor:"), this), 3, 0); g->addWidget(m_divisor, 3, 1); g->addWidget(new QLabel(i18n("Bias:"), this), 3, 2); g->addWidget(m_bias, 3, 3); m_preserveAlpha = new QCheckBox(i18n("Preserve alpha"), this); g->addWidget(m_preserveAlpha, 4, 1, 1, 3); QPushButton *kernelButton = new QPushButton(i18n("Edit kernel"), this); g->addWidget(kernelButton, 5, 0, 1, 4); setLayout(g); connect(m_edgeMode, SIGNAL(currentIndexChanged(int)), this, SLOT(edgeModeChanged(int))); connect(m_orderX, SIGNAL(valueChanged(int)), this, SLOT(orderChanged(int))); connect(m_orderY, SIGNAL(valueChanged(int)), this, SLOT(orderChanged(int))); connect(m_targetX, SIGNAL(valueChanged(int)), this, SLOT(targetChanged(int))); connect(m_targetY, SIGNAL(valueChanged(int)), this, SLOT(targetChanged(int))); connect(m_divisor, SIGNAL(valueChanged(double)), this, SLOT(divisorChanged(double))); connect(m_bias, SIGNAL(valueChanged(double)), this, SLOT(biasChanged(double))); connect(kernelButton, SIGNAL(clicked(bool)), this, SLOT(editKernel())); connect(m_preserveAlpha, SIGNAL(toggled(bool)), this, SLOT(preserveAlphaChanged(bool))); m_matrixModel = new MatrixDataModel(this); } bool ConvolveMatrixEffectConfigWidget::editFilterEffect(KoFilterEffect *filterEffect) { m_effect = dynamic_cast(filterEffect); if (!m_effect) { return false; } m_edgeMode->blockSignals(true); m_edgeMode->setCurrentIndex(m_effect->edgeMode()); m_edgeMode->blockSignals(false); m_orderX->blockSignals(true); m_orderX->setValue(m_effect->order().x()); m_orderX->blockSignals(false); m_orderY->blockSignals(true); m_orderY->setValue(m_effect->order().y()); m_orderY->blockSignals(false); m_targetX->blockSignals(true); m_targetX->setMaximum(m_orderX->value()); m_targetX->setValue(m_effect->target().x() + 1); m_targetX->blockSignals(false); m_targetY->blockSignals(true); m_targetY->setMaximum(m_orderY->value()); m_targetY->setValue(m_effect->target().y() + 1); m_targetY->blockSignals(false); m_divisor->blockSignals(true); m_divisor->setValue(m_effect->divisor()); m_divisor->blockSignals(false); m_bias->blockSignals(true); m_bias->setValue(m_effect->bias()); m_bias->blockSignals(false); m_preserveAlpha->blockSignals(true); m_preserveAlpha->setChecked(m_effect->isPreserveAlphaEnabled()); m_preserveAlpha->blockSignals(false); return true; } void ConvolveMatrixEffectConfigWidget::edgeModeChanged(int id) { if (!m_effect) { return; } switch (id) { case ConvolveMatrixEffect::Duplicate: m_effect->setEdgeMode(ConvolveMatrixEffect::Duplicate); break; case ConvolveMatrixEffect::Wrap: m_effect->setEdgeMode(ConvolveMatrixEffect::Wrap); break; case ConvolveMatrixEffect::None: m_effect->setEdgeMode(ConvolveMatrixEffect::None); break; } emit filterChanged(); } void ConvolveMatrixEffectConfigWidget::orderChanged(int) { if (!m_effect) { return; } QPoint newOrder(m_orderX->value(), m_orderY->value()); QPoint oldOrder = m_effect->order(); if (newOrder != oldOrder) { m_effect->setOrder(newOrder); emit filterChanged(); } m_targetX->setMaximum(newOrder.x()); m_targetY->setMaximum(newOrder.y()); } void ConvolveMatrixEffectConfigWidget::targetChanged(int) { if (!m_effect) { return; } QPoint newTarget(m_targetX->value() - 1, m_targetY->value() - 1); QPoint oldTarget = m_effect->target(); if (newTarget != oldTarget) { m_effect->setTarget(newTarget); emit filterChanged(); } } void ConvolveMatrixEffectConfigWidget::divisorChanged(double divisor) { if (!m_effect) { return; } if (divisor != m_effect->divisor()) { m_effect->setDivisor(divisor); emit filterChanged(); } } void ConvolveMatrixEffectConfigWidget::biasChanged(double bias) { if (!m_effect) { return; } if (bias != m_effect->bias()) { m_effect->setBias(bias); emit filterChanged(); } } void ConvolveMatrixEffectConfigWidget::preserveAlphaChanged(bool checked) { if (!m_effect) { return; } m_effect->enablePreserveAlpha(checked); emit filterChanged(); } void ConvolveMatrixEffectConfigWidget::editKernel() { if (!m_effect) { return; } QVector oldKernel = m_effect->kernel(); QPoint kernelSize = m_effect->order(); m_matrixModel->setMatrix(oldKernel, kernelSize.y(), kernelSize.x()); connect(m_matrixModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(kernelChanged())); QPointer dlg = new QDialog(this); QTableView *table = new QTableView(dlg); table->setModel(m_matrixModel); table->horizontalHeader()->hide(); - table->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); table->verticalHeader()->hide(); - table->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); + table->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); QVBoxLayout *mainLayout = new QVBoxLayout; dlg->setLayout(mainLayout); mainLayout->addWidget(table); if (dlg->exec() == QDialog::Accepted) { m_effect->setKernel(m_matrixModel->matrix()); emit filterChanged(); } else { m_effect->setKernel(oldKernel); } delete dlg; disconnect(m_matrixModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(kernelChanged())); } void ConvolveMatrixEffectConfigWidget::kernelChanged() { if (!m_effect) { return; } m_effect->setKernel(m_matrixModel->matrix()); emit filterChanged(); } diff --git a/plugins/tools/karbonplugins/filtereffects/MatrixDataModel.cpp b/plugins/tools/karbonplugins/filtereffects/MatrixDataModel.cpp index ace47513cf..6c0a699657 100644 --- a/plugins/tools/karbonplugins/filtereffects/MatrixDataModel.cpp +++ b/plugins/tools/karbonplugins/filtereffects/MatrixDataModel.cpp @@ -1,86 +1,87 @@ /* This file is part of the KDE project * Copyright (c) 2010 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "MatrixDataModel.h" #include "kis_num_parser.h" MatrixDataModel::MatrixDataModel(QObject *parent) : QAbstractTableModel(parent) , m_rows(0) , m_cols(0) { } void MatrixDataModel::setMatrix(const QVector &matrix, int rows, int cols) { m_matrix = matrix; m_rows = rows; m_cols = cols; Q_ASSERT(m_rows); Q_ASSERT(m_cols); Q_ASSERT(m_matrix.count() == m_rows * m_cols); - reset(); + beginResetModel(); + endResetModel(); } QVector MatrixDataModel::matrix() const { return m_matrix; } int MatrixDataModel::rowCount(const QModelIndex &/*parent*/) const { return m_rows; } int MatrixDataModel::columnCount(const QModelIndex &/*parent*/) const { return m_cols; } QVariant MatrixDataModel::data(const QModelIndex &index, int role) const { int element = index.row() * m_cols + index.column(); switch (role) { case Qt::DisplayRole: case Qt::EditRole: return QVariant(QString("%1").arg(m_matrix[element], 2)); break; default: return QVariant(); } } bool MatrixDataModel::setData(const QModelIndex &index, const QVariant &value, int /*role*/) { int element = index.row() * m_cols + index.column(); bool valid = false; qreal elementValue = KisNumericParser::parseSimpleMathExpr(value.toString(), &valid); if (!valid) { return false; } m_matrix[element] = elementValue; emit dataChanged(index, index); return true; } Qt::ItemFlags MatrixDataModel::flags(const QModelIndex &/*index*/) const { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectSceneItems.cpp b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectSceneItems.cpp index 871a4f8003..b633cc4ef5 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectSceneItems.cpp +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectSceneItems.cpp @@ -1,321 +1,321 @@ /* This file is part of the KDE project * Copyright (c) 2009 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "FilterEffectSceneItems.h" #include "KoFilterEffect.h" #include #include #include #include #include const QSizeF ConnectorSize = QSize(20, 20); const qreal ItemWidth = 15 * ConnectorSize.height(); const qreal FontSize = 0.8 * ConnectorSize.height(); ConnectorItem::ConnectorItem(ConnectorType type, int index, QGraphicsItem *parent) : QGraphicsEllipseItem(parent) , m_type(type) , m_index(index) { if (m_type == Output) { setBrush(QBrush(Qt::red)); } else if (m_type == Input) { setBrush(QBrush(Qt::green)); } setAcceptDrops(true); setRect(QRectF(QPointF(), ConnectorSize)); } void ConnectorItem::setCenter(const QPointF &position) { QRectF r = rect(); r.moveCenter(position); setRect(r); } ConnectorItem::ConnectorType ConnectorItem::connectorType() { return m_type; } int ConnectorItem::connectorIndex() const { return m_index; } KoFilterEffect *ConnectorItem::effect() const { if (!parentItem()) { return 0; } EffectItemBase *effectItem = dynamic_cast(parentItem()); if (!effectItem) { return 0; } return effectItem->effect(); } ConnectorMimeData::ConnectorMimeData(ConnectorItem *connector) : m_connector(connector) { } ConnectorItem *ConnectorMimeData::connector() const { return m_connector; } EffectItemBase::EffectItemBase(KoFilterEffect *effect) : QGraphicsRectItem(0), m_effect(effect) { setZValue(1); setFlags(QGraphicsItem::ItemIsSelectable); setAcceptDrops(true); setHandlesChildEvents(true); } void EffectItemBase::createText(const QString &text) { QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(text, this); QFont font = textItem->font(); font.setPointSize(FontSize); textItem->setFont(font); QRectF textBox = textItem->boundingRect(); QPointF offset = rect().center() - textBox.center(); - textItem->translate(offset.x(), offset.y()); + setTransform(QTransform::fromTranslate(offset.x(), offset.y()), true); } void EffectItemBase::createOutput(const QPointF &position, const QString &name) { ConnectorItem *connector = new ConnectorItem(ConnectorItem::Output, 0, this); connector->setCenter(position); m_outputPosition = position; m_outputName = name; } void EffectItemBase::createInput(const QPointF &position) { int inputCount = m_inputPositions.count(); ConnectorItem *connector = new ConnectorItem(ConnectorItem::Input, inputCount, this); connector->setCenter(position); m_inputPositions.append(position); } QPointF EffectItemBase::outputPosition() const { return m_outputPosition; } QPointF EffectItemBase::inputPosition(int index) const { if (index < 0 || index >= m_inputPositions.count()) { return QPointF(); } return m_inputPositions[index]; } QString EffectItemBase::outputName() const { return m_outputName; } QSizeF EffectItemBase::connectorSize() const { return ConnectorSize; } KoFilterEffect *EffectItemBase::effect() const { return m_effect; } void EffectItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event) { ConnectorItem *connector = connectorAtPosition(event->scenePos()); if (!connector) { return; } ConnectorMimeData *data = new ConnectorMimeData(connector); QDrag *drag = new QDrag(event->widget()); drag->setMimeData(data); drag->start(); } void EffectItemBase::dragMoveEvent(QGraphicsSceneDragDropEvent *event) { event->ignore(); ConnectorItem *targetItem = connectorAtPosition(event->scenePos()); if (!targetItem) { return; } const ConnectorMimeData *data = dynamic_cast(event->mimeData()); if (!data) { return; } ConnectorItem *sourceItem = data->connector(); int sourceItemType = sourceItem->connectorType(); int targetItemType = targetItem->connectorType(); if (sourceItemType == targetItemType) { return; } // do not accept connection within single effect item if (sourceItem->parentItem() == targetItem->parentItem()) { return; } if (sourceItemType == ConnectorItem::Input) { // we can only connect input with output above if (sourceItem->scenePos().y() < targetItem->scenePos().y()) { return; } } if (sourceItemType == ConnectorItem::Output) { // we can only connect output with input below if (sourceItem->scenePos().y() > targetItem->scenePos().y()) { return; } } event->accept(); } void EffectItemBase::dropEvent(QGraphicsSceneDragDropEvent *event) { ConnectorItem *connector = connectorAtPosition(event->scenePos()); if (!connector) { return; } const ConnectorMimeData *data = dynamic_cast(event->mimeData()); if (!data) { return; } } ConnectorItem *EffectItemBase::connectorAtPosition(const QPointF &scenePosition) { Q_FOREACH (QGraphicsItem *childItem, childItems()) { ConnectorItem *connector = dynamic_cast(childItem); if (!connector) { continue; } if (connector->contains(connector->mapFromScene(scenePosition))) { return connector; } } return 0; } DefaultInputItem::DefaultInputItem(const QString &name, KoFilterEffect *effect) : EffectItemBase(effect), m_name(name) { setRect(0, 0, ItemWidth, 2 * ConnectorSize.height()); createOutput(QPointF(ItemWidth, 0.5 * rect().height()), name); createText(name); QLinearGradient g(QPointF(0, 0), QPointF(1, 1)); g.setCoordinateMode(QGradient::ObjectBoundingMode); g.setColorAt(0, Qt::white); g.setColorAt(1, QColor(255, 168, 88)); setBrush(QBrush(g)); } EffectItem::EffectItem(KoFilterEffect *effect) : EffectItemBase(effect) { Q_ASSERT(effect); QRectF circle(QPointF(), ConnectorSize); QPointF position(ItemWidth, ConnectorSize.height()); // create input connectors int requiredInputCount = effect->requiredInputCount(); int usedInputCount = qMax(requiredInputCount, effect->inputs().count()); for (int i = 0; i < usedInputCount; ++i) { createInput(position); position.ry() += 1.5 * ConnectorSize.height(); } // create a new input connector when maximal input count in not reached yet if (usedInputCount < effect->maximalInputCount()) { createInput(position); position.ry() += 1.5 * ConnectorSize.height(); } // create output connector position.ry() += 0.5 * ConnectorSize.height(); createOutput(position, effect->output()); setRect(0, 0, ItemWidth, position.y() + ConnectorSize.height()); createText(effect->id()); QLinearGradient g(QPointF(0, 0), QPointF(1, 1)); g.setCoordinateMode(QGradient::ObjectBoundingMode); g.setColorAt(0, Qt::white); g.setColorAt(1, QColor(0, 192, 192)); setBrush(QBrush(g)); } ConnectionItem::ConnectionItem(EffectItemBase *source, EffectItemBase *target, int targetInput) : QGraphicsPathItem(0) , m_source(source) , m_target(target) , m_targetInput(targetInput) { setPen(QPen(Qt::black)); } EffectItemBase *ConnectionItem::sourceItem() const { return m_source; } EffectItemBase *ConnectionItem::targetItem() const { return m_target; } int ConnectionItem::targetInput() const { return m_targetInput; } void ConnectionItem::setSourceItem(EffectItemBase *source) { m_source = source; } void ConnectionItem::setTargetItem(EffectItemBase *target, int targetInput) { m_target = target; m_targetInput = targetInput; }