diff --git a/libs/image/KisRenderedDab.h b/libs/image/KisRenderedDab.h index 4b26a4e235..1ea1e61992 100644 --- a/libs/image/KisRenderedDab.h +++ b/libs/image/KisRenderedDab.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2017 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. */ #ifndef KISRENDEREDDAB_H #define KISRENDEREDDAB_H #include "kis_types.h" #include "kis_fixed_paint_device.h" struct KisRenderedDab { KisRenderedDab() {} KisRenderedDab(KisFixedPaintDeviceSP _device) : device(_device), offset(_device->bounds().topLeft()) { } - KisRenderedDab(const KisRenderedDab &rhs) = default; + KisRenderedDab(const KisRenderedDab &/*rhs*/) = default; KisFixedPaintDeviceSP device; QPoint offset; qreal opacity = OPACITY_OPAQUE_F; qreal flow = OPACITY_OPAQUE_F; qreal averageOpacity = OPACITY_TRANSPARENT_F; inline QRect realBounds() const { return QRect(offset, device->bounds().size()); } }; #endif // KISRENDEREDDAB_H diff --git a/libs/image/kis_node.cpp b/libs/image/kis_node.cpp index 5a4010cc80..6d942c9c36 100644 --- a/libs/image/kis_node.cpp +++ b/libs/image/kis_node.cpp @@ -1,658 +1,658 @@ /* * Copyright (c) 2007 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 "kis_node.h" #include #include #include #include #include #include #include #include #include "kis_global.h" #include "kis_node_graph_listener.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" #include "kis_node_progress_proxy.h" #include "kis_busy_progress_indicator.h" #include "kis_clone_layer.h" #include "kis_safe_read_list.h" typedef KisSafeReadList KisSafeReadNodeList; #include "kis_abstract_projection_plane.h" #include "kis_projection_leaf.h" #include "kis_undo_adapter.h" #include "kis_keyframe_channel.h" /** *The link between KisProjection and KisImageUpdater *uses queued signals with an argument of KisNodeSP type, *so we should register it beforehand */ struct KisNodeSPStaticRegistrar { KisNodeSPStaticRegistrar() { qRegisterMetaType("KisNodeSP"); } }; static KisNodeSPStaticRegistrar __registrar1; struct KisNodeListStaticRegistrar { KisNodeListStaticRegistrar() { qRegisterMetaType("KisNodeList"); } }; static KisNodeListStaticRegistrar __registrar2; /** * Note about "thread safety" of KisNode * * 1) One can *read* any information about node and node graph in any * number of threads concurrently. This operation is safe because * of the usage of KisSafeReadNodeList and will run concurrently * (lock-free). * * 2) One can *write* any information into the node or node graph in a * single thread only! Changing the graph concurrently is *not* * sane and therefore not supported. * * 3) One can *read and write* information about the node graph * concurrently, given that there is only *one* writer thread and * any number of reader threads. Please note that in this case the * node's code is just guaranteed *not to crash*, which is ensured * by nodeSubgraphLock. You need to ensure the sanity of the data * read by the reader threads yourself! */ struct Q_DECL_HIDDEN KisNode::Private { public: Private(KisNode *node) : graphListener(0) , nodeProgressProxy(0) , busyProgressIndicator(0) , projectionLeaf(new KisProjectionLeaf(node)) { } KisNodeWSP parent; KisNodeGraphListener *graphListener; KisSafeReadNodeList nodes; KisNodeProgressProxy *nodeProgressProxy; KisBusyProgressIndicator *busyProgressIndicator; QReadWriteLock nodeSubgraphLock; KisProjectionLeafSP projectionLeaf; const KisNode* findSymmetricClone(const KisNode *srcRoot, const KisNode *dstRoot, const KisNode *srcTarget); void processDuplicatedClones(const KisNode *srcDuplicationRoot, const KisNode *dstDuplicationRoot, KisNode *node); }; /** * Finds the layer in \p dstRoot subtree, which has the same path as * \p srcTarget has in \p srcRoot */ const KisNode* KisNode::Private::findSymmetricClone(const KisNode *srcRoot, const KisNode *dstRoot, const KisNode *srcTarget) { if (srcRoot == srcTarget) return dstRoot; KisSafeReadNodeList::const_iterator srcIter = srcRoot->m_d->nodes.constBegin(); KisSafeReadNodeList::const_iterator dstIter = dstRoot->m_d->nodes.constBegin(); for (; srcIter != srcRoot->m_d->nodes.constEnd(); srcIter++, dstIter++) { KIS_ASSERT_RECOVER_RETURN_VALUE((srcIter != srcRoot->m_d->nodes.constEnd()) == (dstIter != dstRoot->m_d->nodes.constEnd()), 0); const KisNode *node = findSymmetricClone(srcIter->data(), dstIter->data(), srcTarget); if (node) return node; } return 0; } /** * This function walks through a subtrees of old and new layers and * searches for clone layers. For each clone layer it checks whether * its copyFrom() lays inside the old subtree, and if it is so resets * it to the corresponding layer in the new subtree. * * That is needed when the user duplicates a group layer with all its * layer subtree. In such a case all the "internal" clones must stay * "internal" and not point to the layers of the older group. */ void KisNode::Private::processDuplicatedClones(const KisNode *srcDuplicationRoot, const KisNode *dstDuplicationRoot, KisNode *node) { if (KisCloneLayer *clone = dynamic_cast(node)) { KIS_ASSERT_RECOVER_RETURN(clone->copyFrom()); const KisNode *newCopyFrom = findSymmetricClone(srcDuplicationRoot, dstDuplicationRoot, clone->copyFrom()); if (newCopyFrom) { KisLayer *newCopyFromLayer = qobject_cast(const_cast(newCopyFrom)); KIS_ASSERT_RECOVER_RETURN(newCopyFromLayer); clone->setCopyFrom(newCopyFromLayer); } } KisSafeReadNodeList::const_iterator iter; FOREACH_SAFE(iter, node->m_d->nodes) { KisNode *child = const_cast((*iter).data()); processDuplicatedClones(srcDuplicationRoot, dstDuplicationRoot, child); } } KisNode::KisNode() : m_d(new Private(this)) { m_d->parent = 0; m_d->graphListener = 0; moveToThread(qApp->thread()); } KisNode::KisNode(const KisNode & rhs) : KisBaseNode(rhs) , m_d(new Private(this)) { m_d->parent = 0; m_d->graphListener = 0; moveToThread(qApp->thread()); // HACK ALERT: we create opacity channel in KisBaseNode, but we cannot // initialize its node from there! So workaround it here! QMap channels = rhs.keyframeChannels(); for (auto it = channels.begin(); it != channels.end(); ++it) { it.value()->setNode(this); } // NOTE: the nodes are not supposed to be added/removed while // creation of another node, so we do *no* locking here! KisSafeReadNodeList::const_iterator iter; FOREACH_SAFE(iter, rhs.m_d->nodes) { KisNodeSP child = (*iter)->clone(); child->createNodeProgressProxy(); m_d->nodes.append(child); child->setParent(this); } m_d->processDuplicatedClones(&rhs, this, this); } KisNode::~KisNode() { if (m_d->busyProgressIndicator) { m_d->busyProgressIndicator->prepareDestroying(); m_d->busyProgressIndicator->deleteLater(); } if (m_d->nodeProgressProxy) { m_d->nodeProgressProxy->prepareDestroying(); m_d->nodeProgressProxy->deleteLater(); } { QWriteLocker l(&m_d->nodeSubgraphLock); m_d->nodes.clear(); } delete m_d; } QRect KisNode::needRect(const QRect &rect, PositionToFilthy pos) const { Q_UNUSED(pos); return rect; } QRect KisNode::changeRect(const QRect &rect, PositionToFilthy pos) const { Q_UNUSED(pos); return rect; } QRect KisNode::accessRect(const QRect &rect, PositionToFilthy pos) const { Q_UNUSED(pos); return rect; } -void KisNode::childNodeChanged(KisNodeSP changedChildNode) +void KisNode::childNodeChanged(KisNodeSP /*changedChildNode*/) { } KisAbstractProjectionPlaneSP KisNode::projectionPlane() const { KIS_ASSERT_RECOVER_NOOP(0 && "KisNode::projectionPlane() is not defined!"); static KisAbstractProjectionPlaneSP plane = toQShared(new KisDumbProjectionPlane()); return plane; } KisProjectionLeafSP KisNode::projectionLeaf() const { return m_d->projectionLeaf; } bool KisNode::accept(KisNodeVisitor &v) { return v.visit(this); } void KisNode::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { visitor.visit(this, undoAdapter); } int KisNode::graphSequenceNumber() const { return m_d->graphListener ? m_d->graphListener->graphSequenceNumber() : -1; } KisNodeGraphListener *KisNode::graphListener() const { return m_d->graphListener; } void KisNode::setGraphListener(KisNodeGraphListener *graphListener) { m_d->graphListener = graphListener; QReadLocker l(&m_d->nodeSubgraphLock); KisSafeReadNodeList::const_iterator iter; FOREACH_SAFE(iter, m_d->nodes) { KisNodeSP child = (*iter); child->setGraphListener(graphListener); } } void KisNode::setParent(KisNodeWSP parent) { QWriteLocker l(&m_d->nodeSubgraphLock); m_d->parent = parent; } KisNodeSP KisNode::parent() const { QReadLocker l(&m_d->nodeSubgraphLock); return m_d->parent.isValid() ? KisNodeSP(m_d->parent) : KisNodeSP(); } KisBaseNodeSP KisNode::parentCallback() const { return parent(); } void KisNode::notifyParentVisibilityChanged(bool value) { QReadLocker l(&m_d->nodeSubgraphLock); KisSafeReadNodeList::const_iterator iter; FOREACH_SAFE(iter, m_d->nodes) { KisNodeSP child = (*iter); child->notifyParentVisibilityChanged(value); } } void KisNode::baseNodeChangedCallback() { if(m_d->graphListener) { m_d->graphListener->nodeChanged(this); } } void KisNode::baseNodeInvalidateAllFramesCallback() { if(m_d->graphListener) { m_d->graphListener->invalidateAllFrames(); } } void KisNode::addKeyframeChannel(KisKeyframeChannel *channel) { channel->setNode(this); KisBaseNode::addKeyframeChannel(channel); } KisNodeSP KisNode::firstChild() const { QReadLocker l(&m_d->nodeSubgraphLock); return !m_d->nodes.isEmpty() ? m_d->nodes.first() : 0; } KisNodeSP KisNode::lastChild() const { QReadLocker l(&m_d->nodeSubgraphLock); return !m_d->nodes.isEmpty() ? m_d->nodes.last() : 0; } KisNodeSP KisNode::prevChildImpl(KisNodeSP child) { /** * Warning: mind locking policy! * * The graph locks must be *always* taken in descending * order. That is if you want to (or it implicitly happens that * you) take a lock of a parent and a chil, you must first take * the lock of a parent, and only after that ask a child to do the * same. Otherwise you'll get a deadlock. */ QReadLocker l(&m_d->nodeSubgraphLock); int i = m_d->nodes.indexOf(child) - 1; return i >= 0 ? m_d->nodes.at(i) : 0; } KisNodeSP KisNode::nextChildImpl(KisNodeSP child) { /** * See a comment in KisNode::prevChildImpl() */ QReadLocker l(&m_d->nodeSubgraphLock); int i = m_d->nodes.indexOf(child) + 1; return i > 0 && i < m_d->nodes.size() ? m_d->nodes.at(i) : 0; } KisNodeSP KisNode::prevSibling() const { KisNodeSP parentNode = parent(); return parentNode ? parentNode->prevChildImpl(const_cast(this)) : 0; } KisNodeSP KisNode::nextSibling() const { KisNodeSP parentNode = parent(); return parentNode ? parentNode->nextChildImpl(const_cast(this)) : 0; } quint32 KisNode::childCount() const { QReadLocker l(&m_d->nodeSubgraphLock); return m_d->nodes.size(); } KisNodeSP KisNode::at(quint32 index) const { QReadLocker l(&m_d->nodeSubgraphLock); if (!m_d->nodes.isEmpty() && index < (quint32)m_d->nodes.size()) { return m_d->nodes.at(index); } return 0; } int KisNode::index(const KisNodeSP node) const { QReadLocker l(&m_d->nodeSubgraphLock); return m_d->nodes.indexOf(node); } QList KisNode::childNodes(const QStringList & nodeTypes, const KoProperties & properties) const { QReadLocker l(&m_d->nodeSubgraphLock); QList nodes; KisSafeReadNodeList::const_iterator iter; FOREACH_SAFE(iter, m_d->nodes) { if (*iter) { if (properties.isEmpty() || (*iter)->check(properties)) { bool rightType = true; if(!nodeTypes.isEmpty()) { rightType = false; Q_FOREACH (const QString &nodeType, nodeTypes) { if ((*iter)->inherits(nodeType.toLatin1())) { rightType = true; break; } } } if (rightType) { nodes.append(*iter); } } } } return nodes; } KisNodeSP KisNode::findChildByName(const QString &name) { KisNodeSP child = firstChild(); while (child) { if (child->name() == name) { return child; } if (child->childCount() > 0) { KisNodeSP grandChild = child->findChildByName(name); if (grandChild) { return grandChild; } } child = child->nextSibling(); } return 0; } bool KisNode::add(KisNodeSP newNode, KisNodeSP aboveThis) { Q_ASSERT(newNode); if (!newNode) return false; if (aboveThis && aboveThis->parent().data() != this) return false; if (!allowAsChild(newNode)) return false; if (newNode->parent()) return false; if (index(newNode) >= 0) return false; int idx = aboveThis ? this->index(aboveThis) + 1 : 0; // threoretical race condition may happen here ('idx' may become // deprecated until the write lock will be held). But we ignore // it, because it is not supported to add/remove nodes from two // concurrent threads simultaneously if (m_d->graphListener) { m_d->graphListener->aboutToAddANode(this, idx); } { QWriteLocker l(&m_d->nodeSubgraphLock); newNode->createNodeProgressProxy(); m_d->nodes.insert(idx, newNode); newNode->setParent(this); newNode->setGraphListener(m_d->graphListener); } childNodeChanged(newNode); if (m_d->graphListener) { m_d->graphListener->nodeHasBeenAdded(this, idx); } return true; } bool KisNode::remove(quint32 index) { if (index < childCount()) { KisNodeSP removedNode = at(index); if (m_d->graphListener) { m_d->graphListener->aboutToRemoveANode(this, index); } { QWriteLocker l(&m_d->nodeSubgraphLock); removedNode->setGraphListener(0); removedNode->setParent(0); // after calling aboutToRemoveANode or then the model get broken according to TT's modeltest m_d->nodes.removeAt(index); } childNodeChanged(removedNode); if (m_d->graphListener) { m_d->graphListener->nodeHasBeenRemoved(this, index); } return true; } return false; } bool KisNode::remove(KisNodeSP node) { return node->parent().data() == this ? remove(index(node)) : false; } KisNodeProgressProxy* KisNode::nodeProgressProxy() const { if (m_d->nodeProgressProxy) { return m_d->nodeProgressProxy; } else if (parent()) { return parent()->nodeProgressProxy(); } return 0; } KisBusyProgressIndicator* KisNode::busyProgressIndicator() const { if (m_d->busyProgressIndicator) { return m_d->busyProgressIndicator; } else if (parent()) { return parent()->busyProgressIndicator(); } return 0; } void KisNode::createNodeProgressProxy() { if (!m_d->nodeProgressProxy) { m_d->nodeProgressProxy = new KisNodeProgressProxy(this); m_d->busyProgressIndicator = new KisBusyProgressIndicator(m_d->nodeProgressProxy); m_d->nodeProgressProxy->moveToThread(this->thread()); m_d->busyProgressIndicator->moveToThread(this->thread()); } } void KisNode::setDirty() { setDirty(extent()); } void KisNode::setDirty(const QVector &rects) { if(m_d->graphListener) { m_d->graphListener->requestProjectionUpdate(this, rects, true); } } void KisNode::setDirty(const QRegion ®ion) { setDirty(region.rects()); } void KisNode::setDirty(const QRect & rect) { setDirty(QVector({rect})); } void KisNode::setDirtyDontResetAnimationCache() { setDirtyDontResetAnimationCache(QVector({extent()})); } void KisNode::setDirtyDontResetAnimationCache(const QRect &rect) { setDirtyDontResetAnimationCache(QVector({rect})); } void KisNode::setDirtyDontResetAnimationCache(const QVector &rects) { if(m_d->graphListener) { m_d->graphListener->requestProjectionUpdate(this, rects, false); } } void KisNode::invalidateFrames(const KisTimeRange &range, const QRect &rect) { if(m_d->graphListener) { m_d->graphListener->invalidateFrames(range, rect); } } void KisNode::requestTimeSwitch(int time) { if(m_d->graphListener) { m_d->graphListener->requestTimeSwitch(time); } } void KisNode::syncLodCache() { // noop. everything is done by getLodCapableDevices() } KisPaintDeviceList KisNode::getLodCapableDevices() const { KisPaintDeviceList list; KisPaintDeviceSP device = paintDevice(); if (device) { list << device; } KisPaintDeviceSP originalDevice = original(); if (originalDevice && originalDevice != device) { list << originalDevice; } list << projectionPlane()->getLodCapableDevices(); return list; } diff --git a/libs/image/lazybrush/kis_colorize_stroke_strategy.cpp b/libs/image/lazybrush/kis_colorize_stroke_strategy.cpp index 437ef92094..9cd02e4e8f 100644 --- a/libs/image/lazybrush/kis_colorize_stroke_strategy.cpp +++ b/libs/image/lazybrush/kis_colorize_stroke_strategy.cpp @@ -1,283 +1,283 @@ /* * Copyright (c) 2016 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 "kis_colorize_stroke_strategy.h" #include #include "krita_utils.h" #include "kis_paint_device.h" #include "kis_lazy_fill_tools.h" #include "kis_gaussian_kernel.h" #include "kis_painter.h" #include "kis_default_bounds_base.h" #include "kis_lod_transform.h" #include "kis_node.h" #include "kis_image_config.h" #include "KisWatershedWorker.h" #include "kis_processing_visitor.h" #include "kis_transaction.h" #include "krita_utils.h" #include #include #include using namespace KisLazyFillTools; struct KisColorizeStrokeStrategy::Private { Private() : filteredSourceValid(false) {} Private(const Private &rhs, int _levelOfDetail) - : progressNode(rhs.progressNode), - src(rhs.src), - dst(rhs.dst), - filteredSource(rhs.filteredSource), - internalFilteredSource(rhs.internalFilteredSource), - filteredSourceValid(rhs.filteredSourceValid), - boundingRect(rhs.boundingRect), - prefilterOnly(rhs.prefilterOnly), - keyStrokes(rhs.keyStrokes), - filteringOptions(rhs.filteringOptions), - levelOfDetail(_levelOfDetail) + : progressNode(rhs.progressNode) + , src(rhs.src) + , dst(rhs.dst) + , filteredSource(rhs.filteredSource) + , internalFilteredSource(rhs.internalFilteredSource) + , filteredSourceValid(rhs.filteredSourceValid) + , boundingRect(rhs.boundingRect) + , prefilterOnly(rhs.prefilterOnly) + , levelOfDetail(_levelOfDetail) + , keyStrokes(rhs.keyStrokes) + , filteringOptions(rhs.filteringOptions) {} KisNodeSP progressNode; KisPaintDeviceSP src; KisPaintDeviceSP dst; KisPaintDeviceSP filteredSource; KisPaintDeviceSP heightMap; KisPaintDeviceSP internalFilteredSource; bool filteredSourceValid; QRect boundingRect; bool prefilterOnly = false; int levelOfDetail = 0; QVector keyStrokes; // default values: disabled FilteringOptions filteringOptions; }; KisColorizeStrokeStrategy::KisColorizeStrokeStrategy(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPaintDeviceSP filteredSource, bool filteredSourceValid, const QRect &boundingRect, KisNodeSP progressNode, bool prefilterOnly) : KisRunnableBasedStrokeStrategy("colorize-stroke", prefilterOnly ? kundo2_i18n("Prefilter Colorize Mask") : kundo2_i18n("Colorize")), m_d(new Private) { m_d->progressNode = progressNode; m_d->src = src; m_d->dst = dst; m_d->filteredSource = filteredSource; m_d->boundingRect = boundingRect; m_d->filteredSourceValid = filteredSourceValid; m_d->prefilterOnly = prefilterOnly; enableJob(JOB_INIT, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); enableJob(JOB_DOSTROKE, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); enableJob(JOB_CANCEL, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); setNeedsExplicitCancel(true); } KisColorizeStrokeStrategy::KisColorizeStrokeStrategy(const KisColorizeStrokeStrategy &rhs, int levelOfDetail) : KisRunnableBasedStrokeStrategy(rhs), m_d(new Private(*rhs.m_d, levelOfDetail)) { KisLodTransform t(levelOfDetail); m_d->boundingRect = t.map(rhs.m_d->boundingRect); } KisColorizeStrokeStrategy::~KisColorizeStrokeStrategy() { } void KisColorizeStrokeStrategy::setFilteringOptions(const FilteringOptions &value) { m_d->filteringOptions = value; } FilteringOptions KisColorizeStrokeStrategy::filteringOptions() const { return m_d->filteringOptions; } void KisColorizeStrokeStrategy::addKeyStroke(KisPaintDeviceSP dev, const KoColor &color) { KoColor convertedColor(color); convertedColor.convertTo(m_d->dst->colorSpace()); m_d->keyStrokes << KeyStroke(dev, convertedColor); } void KisColorizeStrokeStrategy::initStrokeCallback() { using namespace KritaUtils; QVector jobs; const QVector patchRects = splitRectIntoPatches(m_d->boundingRect, optimalPatchSize()); if (!m_d->filteredSourceValid) { // TODO: make this conversion concurrent!!! KisPaintDeviceSP filteredMainDev = KisPainter::convertToAlphaAsAlpha(m_d->src); filteredMainDev->setDefaultBounds(m_d->src->defaultBounds()); struct PrefilterSharedState { QRect boundingRect; KisPaintDeviceSP filteredMainDev; KisPaintDeviceSP filteredMainDevSavedCopy; QScopedPointer activeTransaction; FilteringOptions filteringOptions; }; QSharedPointer state(new PrefilterSharedState()); state->boundingRect = m_d->boundingRect; state->filteredMainDev = filteredMainDev; state->filteringOptions = m_d->filteringOptions; if (m_d->filteringOptions.useEdgeDetection && m_d->filteringOptions.edgeDetectionSize > 0.0) { addJobSequential(jobs, [state] () { state->activeTransaction.reset(new KisTransaction(state->filteredMainDev)); }); Q_FOREACH (const QRect &rc, patchRects) { addJobConcurrent(jobs, [state, rc] () { KisLodTransformScalar t(state->filteredMainDev); KisGaussianKernel::applyLoG(state->filteredMainDev, rc, t.scale(0.5 * state->filteringOptions.edgeDetectionSize), -1.0, QBitArray(), 0); }); } addJobSequential(jobs, [state] () { state->activeTransaction.reset(); normalizeAlpha8Device(state->filteredMainDev, state->boundingRect); state->activeTransaction.reset(new KisTransaction(state->filteredMainDev)); }); Q_FOREACH (const QRect &rc, patchRects) { addJobConcurrent(jobs, [state, rc] () { KisLodTransformScalar t(state->filteredMainDev); KisGaussianKernel::applyGaussian(state->filteredMainDev, rc, t.scale(state->filteringOptions.edgeDetectionSize), t.scale(state->filteringOptions.edgeDetectionSize), QBitArray(), 0); }); } addJobSequential(jobs, [state] () { state->activeTransaction.reset(); }); } if (m_d->filteringOptions.fuzzyRadius > 0) { addJobSequential(jobs, [state] () { state->filteredMainDevSavedCopy = new KisPaintDevice(*state->filteredMainDev); state->activeTransaction.reset(new KisTransaction(state->filteredMainDev)); }); Q_FOREACH (const QRect &rc, patchRects) { addJobConcurrent(jobs, [state, rc] () { KisLodTransformScalar t(state->filteredMainDev); KisGaussianKernel::applyGaussian(state->filteredMainDev, rc, t.scale(state->filteringOptions.fuzzyRadius), t.scale(state->filteringOptions.fuzzyRadius), QBitArray(), 0); KisPainter gc(state->filteredMainDev); gc.bitBlt(rc.topLeft(), state->filteredMainDevSavedCopy, rc); }); } addJobSequential(jobs, [state] () { state->activeTransaction.reset(); }); } addJobSequential(jobs, [this, state] () { normalizeAndInvertAlpha8Device(state->filteredMainDev, state->boundingRect); KisDefaultBoundsBaseSP oldBounds = m_d->filteredSource->defaultBounds(); m_d->filteredSource->makeCloneFrom(state->filteredMainDev, m_d->boundingRect); m_d->filteredSource->setDefaultBounds(oldBounds); m_d->filteredSourceValid = true; }); } if (!m_d->prefilterOnly) { addJobSequential(jobs, [this] () { m_d->heightMap = new KisPaintDevice(*m_d->filteredSource); }); Q_FOREACH (const QRect &rc, patchRects) { addJobConcurrent(jobs, [this, rc] () { KritaUtils::filterAlpha8Device(m_d->heightMap, rc, [](quint8 pixel) { return quint8(255 - pixel); }); }); } addJobSequential(jobs, [this] () { KisProcessingVisitor::ProgressHelper helper(m_d->progressNode); KisWatershedWorker worker(m_d->heightMap, m_d->dst, m_d->boundingRect, helper.updater()); Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) { KoColor color = !stroke.isTransparent ? stroke.color : KoColor(Qt::transparent, m_d->dst->colorSpace()); worker.addKeyStroke(stroke.dev, color); } worker.run(m_d->filteringOptions.cleanUpAmount); }); } addJobSequential(jobs, [this] () { emit sigFinished(m_d->prefilterOnly); }); runnableJobsInterface()->addRunnableJobs(jobs); } void KisColorizeStrokeStrategy::cancelStrokeCallback() { emit sigCancelled(); } KisStrokeStrategy* KisColorizeStrokeStrategy::createLodClone(int levelOfDetail) { KisImageConfig cfg; if (!cfg.useLodForColorizeMask()) return 0; KisColorizeStrokeStrategy *clone = new KisColorizeStrokeStrategy(*this, levelOfDetail); return clone; } diff --git a/libs/libqml/Settings.cpp b/libs/libqml/Settings.cpp index f411fe9a4f..cc340f9530 100644 --- a/libs/libqml/Settings.cpp +++ b/libs/libqml/Settings.cpp @@ -1,148 +1,148 @@ /* This file is part of the KDE project * Copyright (C) 2012 Arjen Hiemstra * * 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 "Settings.h" #include #include #include #include "Theme.h" #include "PropertyContainer.h" #include class Settings::Private { public: Private() : temporaryFile(false), focusItem(0), theme(0){ } QString currentFile; bool temporaryFile; QQuickItem *focusItem; Theme* theme {0}; }; Settings::Settings( QObject* parent ) : QObject( parent ) , d( new Private ) { } Settings::~Settings() { delete d; } void Settings::setTheme(Theme *theme) { d->theme = theme; d->theme->setParent(this); connect(d->theme, SIGNAL(fontCacheRebuilt()), SIGNAL(themeChanged())); } QString Settings::currentFile() const { return d->currentFile; } void Settings::setCurrentFile(const QString& fileName) { qApp->processEvents(); if (fileName != d->currentFile) { d->currentFile = fileName; emit currentFileChanged(); } } bool Settings::isTemporaryFile() const { return d->temporaryFile; } void Settings::setTemporaryFile(bool temp) { if (temp != d->temporaryFile) { d->temporaryFile = temp; emit temporaryFileChanged(); } } QQuickItem* Settings::focusItem() { return d->focusItem; } void Settings::setFocusItem(QQuickItem* item) { if (item != d->focusItem) { d->focusItem = item; emit focusItemChanged(); } } QObject* Settings::theme() const { return d->theme; } QString Settings::themeID() const { if(d->theme) return d->theme->id(); return QString(); } -void Settings::setThemeID(const QString& id) +void Settings::setThemeID(const QString& /*id*/) { // if(!d->theme || id != d->theme->id()) { // if(d->theme) { // delete d->theme; // d->theme = 0; // } // d->theme = Theme::load(id, this); // KSharedConfig::openConfig()->group("General").writeEntry("theme", id); // emit themeChanged(); // } } QObject* Settings::customImageSettings() const { QObject* settings = new PropertyContainer("customImageSettings", qApp); KisConfig cfg; settings->setProperty("Width", cfg.defImageWidth()); settings->setProperty("Height", cfg.defImageHeight()); settings->setProperty("Resolution", qRound(cfg.defImageResolution() * 72)); // otherwise we end up with silly floating point numbers settings->setProperty("ColorModel", cfg.defColorModel()); settings->setProperty("ColorDepth", cfg.defaultColorDepth()); settings->setProperty("ColorProfile", cfg.defColorProfile()); return settings; } QString Settings::lastPreset() const { KisConfig cfg; return cfg.readEntry("LastPreset", QString("Basic_tip_default")); } diff --git a/libs/libqml/plugins/kritasketchplugin/ColorSelectorItem.cpp b/libs/libqml/plugins/kritasketchplugin/ColorSelectorItem.cpp index 6e0722de1f..2577dfe677 100644 --- a/libs/libqml/plugins/kritasketchplugin/ColorSelectorItem.cpp +++ b/libs/libqml/plugins/kritasketchplugin/ColorSelectorItem.cpp @@ -1,337 +1,337 @@ /* This file is part of the KDE project * Copyright (C) 2012 Dan Leinir Turthra Jensen * * 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 "ColorSelectorItem.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_display_color_converter.h" #include class ColorSelectorItem::Private { public: Private(ColorSelectorItem* qq) : q(qq) , selector(new KisColorSelector) , view(0) , colorRole(Acs::Foreground) , grabbingComponent(0) , colorUpdateAllowed(true) , changeBackground(false) , shown(true) , repaintTimer(new QTimer) { ring = new KisColorSelectorRing(selector); ring->setInnerRingRadiusFraction(0.7); triangle = new KisColorSelectorTriangle(selector); slider = new KisColorSelectorSimple(selector); square = new KisColorSelectorSimple(selector); wheel = new KisColorSelectorWheel(selector); main = triangle; sub = ring; connect(main, SIGNAL(paramChanged(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), sub, SLOT(setParam(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), Qt::UniqueConnection); connect(sub, SIGNAL(paramChanged(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), main, SLOT(setParam(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), Qt::UniqueConnection); main->setConfiguration(selector->configuration().mainTypeParameter, selector->configuration().mainType); sub->setConfiguration(selector->configuration().subTypeParameter, selector->configuration().subType); repaintTimer->setInterval(50); repaintTimer->setSingleShot(true); connect(repaintTimer, SIGNAL(timeout()), q, SLOT(repaint())); } ~Private() { selector->deleteLater(); } void repaint(); QImage paintedItem; ColorSelectorItem* q; KisColorSelector* selector; KisColorSelectorRing* ring; KisColorSelectorTriangle* triangle; KisColorSelectorSimple* slider; KisColorSelectorSimple* square; KisColorSelectorWheel* wheel; KisColorSelectorComponent* main; KisColorSelectorComponent* sub; KisViewManager* view; Acs::ColorRole colorRole; KoColor currentColor; KisColorSelectorComponent* grabbingComponent; void commitColor(const KoColor& color, Acs::ColorRole role); bool colorUpdateAllowed; bool changeBackground; bool shown; QTimer* repaintTimer; void colorChangedImpl(const KoColor &color, Acs::ColorRole role); }; void ColorSelectorItem::Private::commitColor(const KoColor& color, Acs::ColorRole role) { if (!view->canvas()) return; KoColor currentColor = Acs::currentColor(view->resourceProvider(), role); if (color == currentColor) return; colorUpdateAllowed = false; Acs::setCurrentColor(view->resourceProvider(), role, color); QColor qcolor = selector->converter()->toQColor(currentColor); emit q->colorChanged(qcolor, color.opacityF(), false); colorUpdateAllowed = true; } ColorSelectorItem::ColorSelectorItem(QQuickItem* parent) : QQuickPaintedItem(parent) , d(new Private(this)) { setFlag(QQuickItem::ItemHasContents, true); setAcceptedMouseButtons( Qt::LeftButton | Qt::RightButton ); } ColorSelectorItem::~ColorSelectorItem() { delete d; } void ColorSelectorItem::paint(QPainter* painter) { if(!d->shown) return; painter->drawImage(boundingRect(), d->paintedItem); } void ColorSelectorItem::Private::repaint() { paintedItem = QImage(q->boundingRect().size().toSize(), QImage::Format_ARGB32_Premultiplied); if(paintedItem.isNull()) return; paintedItem.fill(Qt::transparent); QPainter painter; painter.begin(&paintedItem); main->paintEvent(&painter); sub->paintEvent(&painter); painter.end(); q->update(); } void ColorSelectorItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) { - QRectF bounds = boundingRect(); +// QRectF bounds = boundingRect(); // if (d->selector->configuration().subType==KisColorSelector::Ring) // { // d->ring->setGeometry(bounds.x(),bounds.y(),bounds.width(), bounds.height()); // if (d->selector->configuration().mainType==KisColorSelector::Triangle) // { // d->triangle->setGeometry(bounds.width()/2 - d->ring->innerRadius(), // bounds.height()/2 - d->ring->innerRadius(), // d->ring->innerRadius()*2, // d->ring->innerRadius()*2); // } // else // { // int size = d->ring->innerRadius()*2/sqrt(2.); // d->square->setGeometry(bounds.width()/2 - size/2, // bounds.height()/2 - size/2, // size, // size); // } // } // else // { // // type wheel and square // if (d->selector->configuration().mainType==KisColorSelector::Wheel) // { // d->main->setGeometry(bounds.x(), bounds.y() + height()*0.1, bounds.width(), bounds.height()*0.9); // d->sub->setGeometry( bounds.x(), bounds.y(), bounds.width(), bounds.height()*0.1); // } // else // { // if (bounds.height()>bounds.width()) // { // d->main->setGeometry(bounds.x(), bounds.y() + bounds.height()*0.1, bounds.width(), bounds.height()*0.9); // d->sub->setGeometry( bounds.x(), bounds.y(), bounds.width(), bounds.height()*0.1); // } // else // { // d->main->setGeometry(bounds.x(), bounds.y() + bounds.height()*0.1, bounds.width(), bounds.height()*0.9); // d->sub->setGeometry( bounds.x(), bounds.y(), bounds.width(), bounds.height()*0.1); // } // } // } if (d->view) { d->selector->setColor(Acs::currentColor(d->view->resourceProvider(), d->colorRole)); } d->repaintTimer->start(); QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry); } void ColorSelectorItem::mousePressEvent(QMouseEvent* event) { d->colorRole = d->changeBackground ? Acs::Background : Acs::buttonToRole(event->button()); if (d->main->wantsGrab(event->pos().x(), event->pos().y())) { d->grabbingComponent = d->main; } else if (d->sub->wantsGrab(event->pos().x(), event->pos().y())) { d->grabbingComponent = d->sub; } mouseEvent(event); } void ColorSelectorItem::mouseMoveEvent(QMouseEvent* event) { mouseEvent(event); } void ColorSelectorItem::mouseReleaseEvent(QMouseEvent* /*event*/) { d->grabbingComponent=0; } void ColorSelectorItem::mouseEvent(QMouseEvent* event) { if (d->grabbingComponent && (event->buttons()&Qt::LeftButton || event->buttons()&Qt::RightButton)) { d->grabbingComponent->mouseEvent(event->pos().x(), event->pos().y()); qreal alpha = d->currentColor.opacityF(); d->currentColor = d->main->currentColor(); d->currentColor.setOpacity(alpha); d->commitColor(d->currentColor, d->colorRole); d->repaintTimer->start(); } } QObject* ColorSelectorItem::view() const { return d->view; } void ColorSelectorItem::setView(QObject* newView) { d->view = qobject_cast( newView ); if (d->view) { connect(d->view->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), this, SLOT(fgColorChanged(KoColor))); connect(d->view->resourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), this, SLOT(bgColorChanged(KoColor))); d->commitColor(d->currentColor, d->colorRole); setChangeBackground(changeBackground()); } emit viewChanged(); } bool ColorSelectorItem::changeBackground() const { return d->changeBackground; } void ColorSelectorItem::setChangeBackground(bool newChangeBackground) { d->changeBackground = newChangeBackground; d->colorRole = newChangeBackground ? Acs::Background : Acs::Foreground; emit changeBackgroundChanged(); if (!d->view) return; d->currentColor = Acs::currentColor(d->view->resourceProvider(), d->colorRole); d->main->setColor(d->currentColor); d->sub->setColor(d->currentColor); d->repaintTimer->start(); } bool ColorSelectorItem::shown() const { return d->shown; } void ColorSelectorItem::setShown(bool newShown) { d->shown = newShown; emit shownChanged(); } void ColorSelectorItem::setAlpha(int percentValue) { qreal alpha = (float)percentValue / 100.0; d->currentColor.setOpacity(alpha); if (d->view) { d->commitColor(d->currentColor, d->colorRole); } } void ColorSelectorItem::Private::colorChangedImpl(const KoColor &newColor, Acs::ColorRole role) { if (colorRole != role) return; if (colorUpdateAllowed == false) return; if(newColor == currentColor) return; currentColor = newColor; main->setColor(newColor); sub->setColor(newColor); commitColor(currentColor, colorRole); QColor qcolor = selector->converter()->toQColor(currentColor); emit q->colorChanged(qcolor, currentColor.opacityF(), false); repaintTimer->start(); } void ColorSelectorItem::fgColorChanged(const KoColor& newColor) { d->colorChangedImpl(newColor, Acs::Foreground); } void ColorSelectorItem::bgColorChanged(const KoColor& newColor) { d->colorChangedImpl(newColor, Acs::Background); } void ColorSelectorItem::repaint() { d->repaint(); } diff --git a/libs/libqml/plugins/kritasketchplugin/models/IconImageProvider.cpp b/libs/libqml/plugins/kritasketchplugin/models/IconImageProvider.cpp index a5922c4d8e..5c5096971e 100644 --- a/libs/libqml/plugins/kritasketchplugin/models/IconImageProvider.cpp +++ b/libs/libqml/plugins/kritasketchplugin/models/IconImageProvider.cpp @@ -1,35 +1,35 @@ /* * 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. */ #include "IconImageProvider.h" #include #include "kis_icon_utils.h" IconImageProvider::IconImageProvider() : QQuickImageProvider(QQuickImageProvider::Image) { } -QImage IconImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) +QImage IconImageProvider::requestImage(const QString &id, QSize */*size*/, const QSize &requestedSize) { QIcon icon = KisIconUtils::loadIcon(id); Q_ASSERT(!icon.isNull()); return icon.pixmap(requestedSize).toImage(); } diff --git a/libs/ui/KisAsyncAnimationRendererBase.cpp b/libs/ui/KisAsyncAnimationRendererBase.cpp index 0d0d4f4d7f..d42dbb3c6e 100644 --- a/libs/ui/KisAsyncAnimationRendererBase.cpp +++ b/libs/ui/KisAsyncAnimationRendererBase.cpp @@ -1,158 +1,158 @@ /* * Copyright (c) 2017 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 "KisAsyncAnimationRendererBase.h" #include #include #include "kis_image.h" #include "kis_image_animation_interface.h" #include "kis_signal_auto_connection.h" struct KisAsyncAnimationRendererBase::Private { KisSignalAutoConnectionsStore imageRequestConnections; QTimer regenerationTimeout; KisImageSP requestedImage; int requestedFrame = -1; bool isCancelled = false; static const int WAITING_FOR_FRAME_TIMEOUT = 10000; - void clearFrameRegenerationState(bool cancelled); + void clearFrameRegenerationState(bool); }; KisAsyncAnimationRendererBase::KisAsyncAnimationRendererBase(QObject *parent) : QObject(parent), m_d(new Private()) { connect(&m_d->regenerationTimeout, SIGNAL(timeout()), SLOT(slotFrameRegenerationCancelled())); m_d->regenerationTimeout.setSingleShot(true); m_d->regenerationTimeout.setInterval(Private::WAITING_FOR_FRAME_TIMEOUT); } KisAsyncAnimationRendererBase::~KisAsyncAnimationRendererBase() { } void KisAsyncAnimationRendererBase::startFrameRegeneration(KisImageSP image, int frame) { KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread()); m_d->requestedImage = image; m_d->requestedFrame = frame; m_d->isCancelled = false; KisImageAnimationInterface *animation = m_d->requestedImage->animationInterface(); m_d->imageRequestConnections.clear(); m_d->imageRequestConnections.addConnection( animation, SIGNAL(sigFrameReady(int)), this, SLOT(slotFrameRegenerationFinished(int)), Qt::DirectConnection); m_d->imageRequestConnections.addConnection( animation, SIGNAL(sigFrameCancelled()), this, SLOT(slotFrameRegenerationCancelled()), Qt::AutoConnection); m_d->regenerationTimeout.start(); animation->requestFrameRegeneration(m_d->requestedFrame, image->bounds()); } bool KisAsyncAnimationRendererBase::isActive() const { return m_d->requestedImage; } void KisAsyncAnimationRendererBase::cancelCurrentFrameRendering() { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage); frameCancelledCallback(m_d->requestedFrame); } -void KisAsyncAnimationRendererBase::Private::clearFrameRegenerationState(bool cancelled) +void KisAsyncAnimationRendererBase::Private::clearFrameRegenerationState(bool /*canceled*/) { imageRequestConnections.clear(); requestedImage = 0; requestedFrame = -1; regenerationTimeout.stop(); isCancelled = true; } void KisAsyncAnimationRendererBase::slotFrameRegenerationCancelled() { // the timeout can arrive in async way if (!m_d->requestedImage) return; frameCancelledCallback(m_d->requestedFrame); } void KisAsyncAnimationRendererBase::slotFrameRegenerationFinished(int frame) { // We might have already cancelled the regeneration. We don't check // isCancelled flag here because this code runs asynchronously. if (!m_d->requestedImage) return; // WARNING: executed in the context of image worker thread! // probably a bit too strict... KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() != this->thread()); frameCompletedCallback(frame); } void KisAsyncAnimationRendererBase::notifyFrameCompleted(int frame) { KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread()); // the image events can come with a delay, even after // the processing was cancelled if (m_d->isCancelled) return; KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage); KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedFrame == frame); m_d->clearFrameRegenerationState(false); emit sigFrameCompleted(frame); } void KisAsyncAnimationRendererBase::notifyFrameCancelled(int frame) { KIS_SAFE_ASSERT_RECOVER_NOOP(QThread::currentThread() == this->thread()); // the image events can come with a delay, even after // the processing was cancelled if (m_d->isCancelled) return; KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedImage); KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->requestedFrame == frame); m_d->clearFrameRegenerationState(true); emit sigFrameCancelled(frame); } KisImageSP KisAsyncAnimationRendererBase::requestedImage() const { return m_d->requestedImage; } diff --git a/libs/ui/KisPaletteModel.cpp b/libs/ui/KisPaletteModel.cpp index 4685600b2e..74b6b96c1d 100644 --- a/libs/ui/KisPaletteModel.cpp +++ b/libs/ui/KisPaletteModel.cpp @@ -1,637 +1,637 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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 "KisPaletteModel.h" #include #include #include #include #include #include #include #include #include #include KisPaletteModel::KisPaletteModel(QObject* parent) : QAbstractTableModel(parent), m_colorSet(0), m_displayRenderer(KoDumbColorDisplayRenderer::instance()) { } KisPaletteModel::~KisPaletteModel() { } void KisPaletteModel::setDisplayRenderer(KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { if (m_displayRenderer) { disconnect(m_displayRenderer, 0, this, 0); } m_displayRenderer = displayRenderer; connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(slotDisplayConfigurationChanged())); } else { m_displayRenderer = KoDumbColorDisplayRenderer::instance(); } } void KisPaletteModel::slotDisplayConfigurationChanged() { beginResetModel(); endResetModel(); } QModelIndex KisPaletteModel::getLastEntryIndex() { int endRow = rowCount(); int endColumn = columnCount(); if (m_colorSet->nColors()>0) { QModelIndex i = this->index(endRow, endColumn, QModelIndex()); while (qvariant_cast(i.data(RetrieveEntryRole)).isEmpty()) { i = this->index(endRow, endColumn); endColumn -=1; if (endColumn<0) { endColumn = columnCount(); endRow-=1; } } return i; } return QModelIndex(); } QVariant KisPaletteModel::data(const QModelIndex& index, int role) const { KoColorSetEntry entry; if (m_colorSet && m_displayRenderer) { //now to figure out whether we have a groupname row or not. bool groupNameRow = false; quint32 indexInGroup = 0; QString indexGroupName = QString(); int rowstotal = m_colorSet->nColorsGroup()/columnCount(); if (index.row()<=rowstotal && (quint32)(index.row()*columnCount()+index.column())nColorsGroup()) { indexInGroup = (quint32)(index.row()*columnCount()+index.column()); } if (m_colorSet->nColorsGroup()==0) { rowstotal+=1; //always add one for the default group when considering groups. } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ //we make an int for the rows added by the current group. int newrows = 1+m_colorSet->nColorsGroup(groupName)/columnCount(); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { newrows+=1; } if (newrows==0) { newrows+=1; //always add one for the group when considering groups. } quint32 tempIndex = (quint32)((index.row()-(rowstotal+2))*columnCount()+index.column()); if (index.row() == rowstotal+1) { //rowstotal+1 is taken up by the groupname. indexGroupName = groupName; groupNameRow = true; } else if (index.row() > (rowstotal+1) && index.row() <= rowstotal+newrows && tempIndexnColorsGroup(groupName)){ //otherwise it's an index to the colors in the group. indexGroupName = groupName; indexInGroup = tempIndex; } //add the new rows to the totalrows we've looked at. rowstotal += newrows; } if (groupNameRow) { switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return indexGroupName; } case IsHeaderRole: { return true; } case RetrieveEntryRole: { QStringList entryList; entryList.append(indexGroupName); entryList.append(QString::number(0)); return entryList; } } } else { if (indexInGroup < m_colorSet->nColorsGroup(indexGroupName)) { entry = m_colorSet->getColorGroup(indexInGroup, indexGroupName); switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return entry.name; } case Qt::BackgroundRole: { QColor color = m_displayRenderer->toQColor(entry.color); return QBrush(color); } case IsHeaderRole: { return false; } case RetrieveEntryRole: { QStringList entryList; entryList.append(indexGroupName); entryList.append(QString::number(indexInGroup)); return entryList; } } } } } return QVariant(); } int KisPaletteModel::rowCount(const QModelIndex& /*parent*/) const { if (!m_colorSet) { return 0; } if (m_colorSet->nColors()==0) { return 0; } if (columnCount() > 0) { int countedrows = m_colorSet->nColorsGroup("")/columnCount(); if (m_colorSet->nColorsGroup()%columnCount() > 0) { countedrows+=1; } if (m_colorSet->nColorsGroup()==0) { countedrows+=1; } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()) { countedrows += 1; //add one for the name; countedrows += 1+(m_colorSet->nColorsGroup(groupName)/ columnCount()); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { countedrows+=1; } if (m_colorSet->nColorsGroup(groupName)==0) { countedrows+=1; } } countedrows +=1; //Our code up till now doesn't take 0 into account. return countedrows; } return m_colorSet->nColors()/15 + 1; } int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const { if (m_colorSet && m_colorSet->columnCount() > 0) { return m_colorSet->columnCount(); } return 15; } Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const { if (index.isValid()) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::ItemIsDropEnabled; } QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const { if (m_colorSet) { //make an int to hold the amount of rows we've looked at. The initial is the total rows in the default group. int rowstotal = m_colorSet->nColorsGroup()/columnCount(); if (row<=rowstotal && (quint32)(row*columnCount()+column)nColorsGroup()) { //if the total rows are in the default group, we just return an index. return QAbstractTableModel::index(row, column, parent); } else if(row<0 && column<0) { return QAbstractTableModel::index(0, 0, parent); } if (m_colorSet->nColorsGroup()==0) { rowstotal+=1; //always add one for the default group when considering groups. } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ //we make an int for the rows added by the current group. int newrows = 1+m_colorSet->nColorsGroup(groupName)/columnCount(); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { newrows+=1; } if (m_colorSet->nColorsGroup(groupName)==0) { newrows+=1; //always add one for the group when considering groups. } if (rowstotal + newrows>rowCount()) { newrows = rowCount() - rowstotal; } quint32 tempIndex = (quint32)((row-(rowstotal+2))*columnCount()+column); if (row == rowstotal+1) { //rowstotal+1 is taken up by the groupname. return QAbstractTableModel::index(row, 0, parent); } else if (row > (rowstotal+1) && row <= rowstotal+newrows && tempIndexnColorsGroup(groupName)){ //otherwise it's an index to the colors in the group. return QAbstractTableModel::index(row, column, parent); } //add the new rows to the totalrows we've looked at. rowstotal += newrows; } } return QModelIndex(); } void KisPaletteModel::setColorSet(KoColorSet* colorSet) { m_colorSet = colorSet; beginResetModel(); endResetModel(); } KoColorSet* KisPaletteModel::colorSet() const { return m_colorSet; } QModelIndex KisPaletteModel::indexFromId(int i) const { QModelIndex index = QModelIndex(); if (colorSet()->nColors()==0) { return index; } - if (i > colorSet()->nColors()) { + if (i > (int)colorSet()->nColors()) { qWarning()<<"index is too big"<nColors(); index = this->index(0,0); } if (i < (int)colorSet()->nColorsGroup(0)) { index = QAbstractTableModel::index(i/columnCount(), i%columnCount()); if (!index.isValid()) { index = QAbstractTableModel::index(0,0,QModelIndex()); } return index; } else { int rowstotal = 1+m_colorSet->nColorsGroup()/columnCount(); if (m_colorSet->nColorsGroup()==0) { rowstotal +=1; } int totalIndexes = colorSet()->nColorsGroup(); Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ - if (i+1<=totalIndexes+colorSet()->nColorsGroup(groupName) && i+1>totalIndexes) { - int col = (i-totalIndexes)%columnCount(); - int row = rowstotal+1+((i-totalIndexes)/columnCount()); + if (i + 1 <= (int)(totalIndexes + colorSet()->nColorsGroup(groupName)) && i + 1 > (int)totalIndexes) { + int col = (i - totalIndexes) % columnCount(); + int row = rowstotal + 1 + ((i - totalIndexes) / columnCount()); index = this->index(row, col); return index; } else { - rowstotal += 1+m_colorSet->nColorsGroup(groupName)/columnCount(); + rowstotal += 1 + m_colorSet->nColorsGroup(groupName) / columnCount(); totalIndexes += colorSet()->nColorsGroup(groupName); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { - rowstotal+=1; + rowstotal += 1; } if (m_colorSet->nColorsGroup(groupName)==0) { - rowstotal+=1; //always add one for the group when considering groups. + rowstotal += 1; //always add one for the group when considering groups. } } } } return index; } int KisPaletteModel::idFromIndex(const QModelIndex &index) const { if (index.isValid()==false) { return -1; qWarning()<<"invalid index"; } int i=0; QStringList entryList = qvariant_cast(data(index, RetrieveEntryRole)); if (entryList.isEmpty()) { return -1; qWarning()<<"invalid index, there's no data to retrieve here"; } if (entryList.at(0)==QString()) { return entryList.at(1).toUInt(); } i = colorSet()->nColorsGroup(""); //find at which position the group is. int groupIndex = colorSet()->getGroupNames().indexOf(entryList.at(0)); //add all the groupsizes onto it till we get to our group. for(int g=0; gnColorsGroup(colorSet()->getGroupNames().at(g)); } //then add the index. i += entryList.at(1).toUInt(); return i; } KoColorSetEntry KisPaletteModel::colorSetEntryFromIndex(const QModelIndex &index) const { KoColorSetEntry blank = KoColorSetEntry(); if (!index.isValid()) { return blank; } QStringList entryList = qvariant_cast(data(index, RetrieveEntryRole)); if (entryList.isEmpty()) { return blank; } QString groupName = entryList.at(0); quint32 indexInGroup = entryList.at(1).toUInt(); return m_colorSet->getColorGroup(indexInGroup, groupName); } bool KisPaletteModel::addColorSetEntry(KoColorSetEntry entry, QString groupName) { int col = m_colorSet->nColorsGroup(groupName)%columnCount(); QModelIndex i = getLastEntryIndex(); - if (col+1>columnCount()) { + if (col+1 > columnCount()) { beginInsertRows(QModelIndex(), i.row(), i.row()+1); } - if (m_colorSet->nColors()nColors() < columnCount()) { beginInsertColumns(QModelIndex(), m_colorSet->nColors(), m_colorSet->nColors()+1); } m_colorSet->add(entry, groupName); - if (col+1>columnCount()) { + if (col + 1 > columnCount()) { endInsertRows(); } - if (m_colorSet->nColors()nColors() < (quint32)columnCount()) { endInsertColumns(); } return true; } bool KisPaletteModel::removeEntry(QModelIndex index, bool keepColors) { QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); if (entryList.empty()) { return false; } QString groupName = entryList.at(0); quint32 indexInGroup = entryList.at(1).toUInt(); if (qvariant_cast(index.data(IsHeaderRole))==false) { if (index.column()-1<0 && m_colorSet->nColorsGroup(groupName)%columnCount() <1 && index.row()-1>0 && m_colorSet->nColorsGroup(groupName)/columnCount()>0) { beginRemoveRows(QModelIndex(), index.row(), index.row()-1); } m_colorSet->removeAt(indexInGroup, groupName); if (index.column()-1<0 && m_colorSet->nColorsGroup(groupName)%columnCount() <1 && index.row()-1>0 && m_colorSet->nColorsGroup(groupName)/columnCount()>0) { endRemoveRows(); } } else { beginRemoveRows(QModelIndex(), index.row(), index.row()-1); m_colorSet->removeGroup(groupName, keepColors); endRemoveRows(); } return true; } bool KisPaletteModel::addGroup(QString groupName) { QModelIndex i = getLastEntryIndex(); beginInsertRows(QModelIndex(), i.row(), i.row()+1); m_colorSet->addGroup(groupName); endInsertRows(); return true; } bool KisPaletteModel::removeRows(int row, int count, const QModelIndex &parent) { Q_ASSERT(!parent.isValid()); int beginRow = qMax(0, row); int endRow = qMin(row + count - 1, (int)m_colorSet->nColors() - 1); beginRemoveRows(parent, beginRow, endRow); // Find the palette entry at row, count, remove from KoColorSet endRemoveRows(); return true; } bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) { return false; } if (action == Qt::IgnoreAction) { return false; } int endRow; int endColumn; if (!parent.isValid()) { if (row < 0) { endRow = indexFromId(m_colorSet->nColors()).row(); endColumn = indexFromId(m_colorSet->nColors()).column(); } else { endRow = qMin(row, indexFromId(m_colorSet->nColors()).row()); endColumn = qMin(column, m_colorSet->columnCount()); } } else { endRow = qMin(parent.row(), rowCount()); endColumn = qMin(parent.column(), columnCount()); } if (data->hasFormat("krita/x-colorsetgroup")) { QByteArray encodedData = data->data("krita/x-colorsetgroup"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { QString groupName; stream >> groupName; QModelIndex index = this->index(endRow, 0); if (index.isValid()) { QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupDroppedOn = QString(); if (!entryList.isEmpty()) { groupDroppedOn = entryList.at(0); } int groupIndex = colorSet()->getGroupNames().indexOf(groupName); beginMoveRows( QModelIndex(), groupIndex, groupIndex, QModelIndex(), endRow); m_colorSet->moveGroup(groupName, groupDroppedOn); m_colorSet->save(); endMoveRows(); ++endRow; } } } else { QByteArray encodedData = data->data("krita/x-colorsetentry"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { KoColorSetEntry entry; QString oldGroupName; int indexInGroup; QString colorXml; stream >> entry.name >> entry.id >> entry.spotColor >> indexInGroup >> oldGroupName >> colorXml; QDomDocument doc; doc.setContent(colorXml); QDomElement e = doc.documentElement(); QDomElement c = e.firstChildElement(); if (!c.isNull()) { QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); entry.color = KoColor::fromXML(c, colorDepthId); } QModelIndex index = this->index(endRow, endColumn); if (qvariant_cast(index.data(IsHeaderRole))){ endRow+=1; } if (index.isValid()) { /*this is to figure out the row of the old color. * That way we can in turn avoid moverows from complaining the * index is out of bounds when using index. * Makes me wonder if we shouldn't just insert the index of the * old color when requesting the mimetype... */ int i = indexInGroup; if (oldGroupName != QString()) { colorSet()->nColorsGroup(""); //find at which position the group is. int groupIndex = colorSet()->getGroupNames().indexOf(oldGroupName); //add all the groupsizes onto it till we get to our group. for(int g=0; gnColorsGroup(colorSet()->getGroupNames().at(g)); } } QModelIndex indexOld = indexFromId(i); if (action == Qt::MoveAction){ if (indexOld.row()!=qMax(endRow, 0) && indexOld.row()!=qMax(endRow+1,1)) { beginMoveRows(QModelIndex(), indexOld.row(), indexOld.row(), QModelIndex(), qMax(endRow+1,1)); } if (indexOld.column()!=qMax(endColumn, 0) && indexOld.column()!=qMax(endColumn+1,1)) { beginMoveColumns(QModelIndex(), indexOld.column(), indexOld.column(), QModelIndex(), qMax(endColumn+1,1)); } } else { beginInsertRows(QModelIndex(), endRow, endRow); } QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString entryInGroup = "0"; QString groupName = QString(); if (!entryList.isEmpty()) { groupName = entryList.at(0); entryInGroup = entryList.at(1); } int location = entryInGroup.toInt(); // Insert the entry if (groupName==oldGroupName && qvariant_cast(index.data(IsHeaderRole))==true) { groupName=QString(); location=m_colorSet->nColorsGroup(); } m_colorSet->insertBefore(entry, location, groupName); if (groupName==oldGroupName && locationremoveAt(indexInGroup, oldGroupName); } m_colorSet->save(); if (action == Qt::MoveAction){ if (indexOld.row()!=qMax(endRow, 0) && indexOld.row()!=qMax(endRow+1,1)) { endMoveRows(); } if (indexOld.column()!=qMax(endColumn, 0) && indexOld.column()!=qMax(endColumn+1,1)) { endMoveColumns(); } } else { endInsertRows(); } ++endRow; } } } return true; } QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QString mimeTypeName = "krita/x-colorsetentry"; //Q_FOREACH(const QModelIndex &index, indexes) { QModelIndex index = indexes.last(); if (index.isValid()) { if (qvariant_cast(index.data(IsHeaderRole))==false) { KoColorSetEntry entry = colorSetEntryFromIndex(index); QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupName = QString(); int indexInGroup = 0; if (!entryList.isEmpty()) { groupName = entryList.at(0); QString iig = entryList.at(1); indexInGroup = iig.toInt(); } QDomDocument doc; QDomElement root = doc.createElement("Color"); root.setAttribute("bitdepth", entry.color.colorSpace()->colorDepthId().id()); doc.appendChild(root); entry.color.toXML(doc, root); stream << entry.name << entry.id << entry.spotColor << indexInGroup << groupName << doc.toString(); } else { mimeTypeName = "krita/x-colorsetgroup"; QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupName = QString(); if (!entryList.isEmpty()) { groupName = entryList.at(0); } stream << groupName; } } mimeData->setData(mimeTypeName, encodedData); return mimeData; } QStringList KisPaletteModel::mimeTypes() const { return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup"; } Qt::DropActions KisPaletteModel::supportedDropActions() const { return Qt::MoveAction; } diff --git a/libs/ui/canvas/kis_grid_manager.cpp b/libs/ui/canvas/kis_grid_manager.cpp index dea5eaebaa..2efdce6d07 100644 --- a/libs/ui/canvas/kis_grid_manager.cpp +++ b/libs/ui/canvas/kis_grid_manager.cpp @@ -1,132 +1,132 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_grid_manager.h" #include #include #include #include #include #include "kis_canvas2.h" #include "kis_coordinates_converter.h" #include "kis_config.h" #include "kis_grid_decoration.h" #include "kis_image.h" #include "KisViewManager.h" #include "KisDocument.h" #include "KisView.h" #include "kis_grid_config.h" #include "kis_signals_blocker.h" KisGridManager::KisGridManager(KisViewManager * parent) : QObject(parent) { } KisGridManager::~KisGridManager() { } void KisGridManager::setGridConfig(const KisGridConfig &config) { setGridConfigImpl(config, true); } -void KisGridManager::setGridConfigImpl(const KisGridConfig &config, bool emitModified) +void KisGridManager::setGridConfigImpl(const KisGridConfig &config, bool /*emitModified*/) { if (!m_imageView) return; config.saveStaticData(); m_imageView->document()->setGridConfig(config); m_gridDecoration->setGridConfig(config); m_gridDecoration->setVisible(config.showGrid()); m_toggleGrid->setChecked(config.showGrid()); m_toggleSnapToGrid->setChecked(config.snapToGrid()); } void KisGridManager::setup(KisActionManager* actionManager) { m_toggleGrid = actionManager->createAction("view_grid"); connect(m_toggleGrid, SIGNAL(toggled(bool)), this, SLOT(slotChangeGridVisibilityTriggered(bool))); m_toggleSnapToGrid = actionManager->createAction("view_snap_to_grid"); connect(m_toggleSnapToGrid, SIGNAL(toggled(bool)), this, SLOT(slotSnapToGridTriggered(bool))); } void KisGridManager::updateGUI() { } void KisGridManager::setView(QPointer imageView) { if (m_imageView) { m_gridDecoration = 0; } m_imageView = imageView; if (imageView) { m_gridDecoration = qobject_cast(imageView->canvasBase()->decoration("grid").data()); if (!m_gridDecoration) { m_gridDecoration = new KisGridDecoration(imageView); imageView->canvasBase()->addDecoration(m_gridDecoration); } KisGridConfig config = imageView->document()->gridConfig(); setGridConfigImpl(config, false); KisSignalsBlocker blocker(m_toggleGrid, m_toggleSnapToGrid); Q_UNUSED(blocker); m_toggleGrid->setChecked(config.showGrid()); m_toggleSnapToGrid->setChecked(config.snapToGrid()); } } void KisGridManager::slotChangeGridVisibilityTriggered(bool value) { if (!m_imageView) return; KisGridConfig config = m_imageView->document()->gridConfig(); config.setShowGrid(value); setGridConfig(config); emit sigRequestUpdateGridConfig(config); } void KisGridManager::slotSnapToGridTriggered(bool value) { if (!m_imageView) return; KisGridConfig config = m_imageView->document()->gridConfig(); config.setSnapToGrid(value); setGridConfig(config); emit sigRequestUpdateGridConfig(config); } diff --git a/libs/ui/forms/wdgstrokeselectionproperties.ui b/libs/ui/forms/wdgstrokeselectionproperties.ui index 010612567d..1f258c5e65 100644 --- a/libs/ui/forms/wdgstrokeselectionproperties.ui +++ b/libs/ui/forms/wdgstrokeselectionproperties.ui @@ -1,210 +1,210 @@ WdgStrokeSelection 0 0 - 869 - 601 + 304 + 208 0 0 New Image 0 Stroke 0 Current Brush Line selection Fill: Type: 1 1000000 1 Width: - intSize + lineSize px mm inch None Paint color Background color Custom color Foreground color Line: Color false false false false Foreground color Background color Custom color Color KColorButton QPushButton
kcolorbutton.h
1
diff --git a/libs/ui/input/KisQtWidgetsTweaker.cpp b/libs/ui/input/KisQtWidgetsTweaker.cpp index f889a19797..b23ccc8cef 100644 --- a/libs/ui/input/KisQtWidgetsTweaker.cpp +++ b/libs/ui/input/KisQtWidgetsTweaker.cpp @@ -1,339 +1,334 @@ /* This file is part of the KDE project Copyright (C) 2017 Nikita Vertikov 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 "KisQtWidgetsTweaker.h" #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl_canvas2.h" #include "canvas/kis_qpainter_canvas.h" #include "KisMainWindow.h" Q_GLOBAL_STATIC(KisQtWidgetsTweaker, kqwt_instance) namespace { class ShortcutOverriderBase { public: enum class DecisionOnShortcutOverride { overrideShortcut, askNext, dontOverrideShortcut }; constexpr ShortcutOverriderBase() = default; virtual ~ShortcutOverriderBase() {} virtual bool interestedInEvent(QKeyEvent *event) = 0; virtual DecisionOnShortcutOverride handleEvent(QObject *receiver, QKeyEvent *event) = 0; virtual DecisionOnShortcutOverride finishedPhysicalKeyPressHandling() { return DecisionOnShortcutOverride::askNext; } }; class LineTextEditingShortcutOverrider : public ShortcutOverriderBase { public: constexpr LineTextEditingShortcutOverrider() = default; virtual bool interestedInEvent(QKeyEvent *event) override { static constexpr QKeySequence::StandardKey actionsForQLineEdit[]{ QKeySequence::MoveToNextChar ,QKeySequence::MoveToPreviousChar ,QKeySequence::MoveToStartOfLine ,QKeySequence::MoveToEndOfLine ,QKeySequence::MoveToPreviousWord ,QKeySequence::MoveToNextWord ,QKeySequence::SelectPreviousChar ,QKeySequence::SelectNextChar ,QKeySequence::SelectNextWord ,QKeySequence::SelectPreviousWord ,QKeySequence::SelectStartOfLine ,QKeySequence::SelectEndOfLine ,QKeySequence::SelectAll ,QKeySequence::Deselect ,QKeySequence::Backspace ,QKeySequence::DeleteStartOfWord ,QKeySequence::Delete ,QKeySequence::DeleteEndOfWord ,QKeySequence::DeleteEndOfLine ,QKeySequence::Copy ,QKeySequence::Paste ,QKeySequence::Cut ,QKeySequence::Undo ,QKeySequence::Redo }; for (QKeySequence::StandardKey sk : actionsForQLineEdit) { if (event->matches(sk)) { event->accept(); return true; } } return false; } virtual DecisionOnShortcutOverride handleEvent(QObject *receiver, QKeyEvent *event) override { Q_UNUSED(event); if ((qobject_cast (receiver) != nullptr)|| (qobject_cast (receiver) != nullptr)|| (qobject_cast(receiver) != nullptr)) { return DecisionOnShortcutOverride::overrideShortcut; } else { return DecisionOnShortcutOverride::askNext; } } }; class SpingboxShortcutOverrider : public ShortcutOverriderBase { public: constexpr SpingboxShortcutOverrider() = default; virtual bool interestedInEvent(QKeyEvent *event) override { if (event->modifiers() != Qt::NoModifier) { return false; } switch (event->key()) { case Qt::Key_Down: case Qt::Key_Up: case Qt::Key_PageDown: case Qt::Key_PageUp: event->accept(); return true; default: return false; } } virtual DecisionOnShortcutOverride handleEvent(QObject *receiver, QKeyEvent *event) override { Q_UNUSED(event); if (qobject_cast (receiver) != nullptr|| qobject_cast(receiver) != nullptr) { return DecisionOnShortcutOverride::overrideShortcut; } else { return DecisionOnShortcutOverride::askNext; } } }; class TabShortcutOverrider : public ShortcutOverriderBase { public: constexpr TabShortcutOverrider() = default; virtual bool interestedInEvent(QKeyEvent *event) override { bool tab = event->modifiers() == Qt::NoModifier && ( event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab); bool shiftTab = event->modifiers() == Qt::ShiftModifier && event->key() == Qt::Key_Backtab; if (tab || shiftTab) { return true; }else{ return false; } } virtual DecisionOnShortcutOverride handleEvent(QObject *receiver, QKeyEvent *event) override { Q_UNUSED(event); if (qobject_cast(receiver) != nullptr|| qobject_cast (receiver) != nullptr) { return DecisionOnShortcutOverride::dontOverrideShortcut; } else { m_nooverride = true; return DecisionOnShortcutOverride::askNext; } } virtual DecisionOnShortcutOverride finishedPhysicalKeyPressHandling() override { if (m_nooverride){ m_nooverride = false; return DecisionOnShortcutOverride::overrideShortcut; } return DecisionOnShortcutOverride::askNext; } private: bool m_nooverride = false; }; //for some reason I can't just populate constexpr //pointer array using "new" LineTextEditingShortcutOverrider overrider0; SpingboxShortcutOverrider overrider1; TabShortcutOverrider overrider2; constexpr ShortcutOverriderBase *allShortcutOverriders[] = { &overrider0, &overrider1, &overrider2 }; + constexpr int numOfShortcutOverriders = sizeof(allShortcutOverriders)/ sizeof(allShortcutOverriders[0]); } //namespace struct KisQtWidgetsTweaker::Private { public: Private(KisQtWidgetsTweaker *parent) : q(parent) - , interestedHandlers(numOfShortcutOverriders) - , lastKeyPressProcessingComplete(true) - , decision(ShortcutOverriderBase::DecisionOnShortcutOverride::askNext) { } const KisQtWidgetsTweaker *q; QBitArray interestedHandlers = QBitArray(numOfShortcutOverriders); - - ShortcutOverriderBase::DecisionOnShortcutOverride decision = - ShortcutOverriderBase::DecisionOnShortcutOverride::askNext; - //unsigned long lastEventTimestamp=0; - + ShortcutOverriderBase::DecisionOnShortcutOverride decision = ShortcutOverriderBase::DecisionOnShortcutOverride::askNext; bool lastKeyPressProcessingComplete = true; + void newPhysicalKeyPressed(QKeyEvent *event) { for (int i=0; i < numOfShortcutOverriders; ++i) { if (allShortcutOverriders[i]->interestedInEvent(event)) { interestedHandlers.setBit(i); }else{ interestedHandlers.clearBit(i); } } decision = ShortcutOverriderBase::DecisionOnShortcutOverride::askNext; lastKeyPressProcessingComplete = false; } }; KisQtWidgetsTweaker::KisQtWidgetsTweaker(QObject *parent) :QObject(parent) , d(new KisQtWidgetsTweaker::Private(this)) { } KisQtWidgetsTweaker::~KisQtWidgetsTweaker() { delete d; } bool KisQtWidgetsTweaker::eventFilter(QObject *receiver, QEvent *event) { switch(event->type()) { case QEvent::ShortcutOverride:{ //QLineEdit and other widgets lets qt's shortcut system take away it's keyboard events //even is it knows them, such as ctrl+backspace //if there is application-wide shortcut, assigned to it. //The following code fixes it //by accepting ShortcutOverride events. //if you press key 'a' and then 'b', qt at first call //all handlers for 'a' key press event, and only after that //for 'b' QKeyEvent *key = static_cast(event); if (d->lastKeyPressProcessingComplete) { d->newPhysicalKeyPressed(key); } for(int i = 0; i < numOfShortcutOverriders; ++i) { if (d->decision != ShortcutOverriderBase::DecisionOnShortcutOverride::askNext) { break; } if (d->interestedHandlers.at(i)) { d->decision = allShortcutOverriders[i]->handleEvent(receiver, key); } } //if nothing said whether shortcutoverride to be accepted //last widget that qt will ask will be kismainwindow or docker if (qobject_cast(receiver)!=nullptr|| receiver->inherits(QDockWidget::staticMetaObject.className())) { for (int i = 0; i < numOfShortcutOverriders; ++i) { if (d->decision != ShortcutOverriderBase::DecisionOnShortcutOverride::askNext) { break; } if (d->interestedHandlers.at(i)) { d->decision = allShortcutOverriders[i]->finishedPhysicalKeyPressHandling(); } } d->lastKeyPressProcessingComplete = true; } bool retval = false; switch (d->decision) { case ShortcutOverriderBase::DecisionOnShortcutOverride::askNext: event->ignore(); retval = false; break; case ShortcutOverriderBase::DecisionOnShortcutOverride::dontOverrideShortcut: event->ignore(); retval = true; break; case ShortcutOverriderBase::DecisionOnShortcutOverride::overrideShortcut: event->accept(); //once shortcutoverride acepted, qt stop asking everyone //about it and proceed to handling next event d->lastKeyPressProcessingComplete = true; retval = true; break; } return retval || QObject::eventFilter(receiver, event); }break; //other event types default: break; } //code for tweaking the behavior of other qt elements will go here return QObject::eventFilter(receiver, event); } KisQtWidgetsTweaker *KisQtWidgetsTweaker::instance() { return kqwt_instance; } diff --git a/libs/ui/kis_popup_palette.cpp b/libs/ui/kis_popup_palette.cpp index 311a4f2bf1..d84584f6a0 100644 --- a/libs/ui/kis_popup_palette.cpp +++ b/libs/ui/kis_popup_palette.cpp @@ -1,940 +1,930 @@ /* This file is part of the KDE project Copyright 2009 Vera Lukman Copyright 2011 Sven Langkamp Copyright 2016 Scott Petrovic This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "kis_canvas2.h" #include "kis_config.h" #include "kis_popup_palette.h" #include "kis_paintop_box.h" #include "kis_favorite_resource_manager.h" #include "kis_icon_utils.h" #include #include "kis_resource_server_provider.h" #include #include #include #include #include "KoColorSpaceRegistry.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_signal_compressor.h" #include #include "brushhud/kis_brush_hud.h" #include "brushhud/kis_round_hud_button.h" #include #include "kis_signals_blocker.h" class PopupColorTriangle : public KoTriangleColorSelector { public: PopupColorTriangle(const KoColorDisplayRendererInterface *displayRenderer, QWidget* parent) : KoTriangleColorSelector(displayRenderer, parent) , m_dragging(false) { } ~PopupColorTriangle() override {} void tabletEvent(QTabletEvent* event) override { event->accept(); QMouseEvent* mouseEvent = 0; switch (event->type()) { case QEvent::TabletPress: mouseEvent = new QMouseEvent(QEvent::MouseButtonPress, event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); m_dragging = true; mousePressEvent(mouseEvent); break; case QEvent::TabletMove: mouseEvent = new QMouseEvent(QEvent::MouseMove, event->pos(), (m_dragging) ? Qt::LeftButton : Qt::NoButton, (m_dragging) ? Qt::LeftButton : Qt::NoButton, event->modifiers()); mouseMoveEvent(mouseEvent); break; case QEvent::TabletRelease: mouseEvent = new QMouseEvent(QEvent::MouseButtonRelease, event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); m_dragging = false; mouseReleaseEvent(mouseEvent); break; default: break; } delete mouseEvent; } private: bool m_dragging; }; KisPopupPalette::KisPopupPalette(KisViewManager* viewManager, KisCoordinatesConverter* coordinatesConverter ,KisFavoriteResourceManager* manager, const KoColorDisplayRendererInterface *displayRenderer, KisCanvasResourceProvider *provider, QWidget *parent) : QWidget(parent, Qt::FramelessWindowHint) - , m_hoveredPreset(0) - , m_hoveredColor(0) - , m_selectedColor(0) , m_coordinatesConverter(coordinatesConverter) , m_viewManager(viewManager) , m_actionManager(viewManager->actionManager()) , m_resourceManager(manager) - , m_triangleColorSelector(0) , m_displayRenderer(displayRenderer) , m_colorChangeCompressor(new KisSignalCompressor(50, KisSignalCompressor::POSTPONE)) , m_actionCollection(viewManager->actionCollection()) - , m_brushHud(0) - , m_popupPaletteSize(385.0) - , m_colorHistoryInnerRadius(72.0) - , m_colorHistoryOuterRadius(92.0) - , m_isOverCanvasRotationIndicator(false) - , m_isRotatingCanvasIndicator(false) { // some UI controls are defined and created based off these variables const int borderWidth = 3; if (KisConfig().readEntry("popuppalette/usevisualcolorselector", false)) { m_triangleColorSelector = new KisVisualColorSelector(this); } else { m_triangleColorSelector = new PopupColorTriangle(displayRenderer, this); } m_triangleColorSelector->setDisplayRenderer(displayRenderer); m_triangleColorSelector->setConfig(true,false); m_triangleColorSelector->move(m_popupPaletteSize/2-m_colorHistoryInnerRadius+borderWidth, m_popupPaletteSize/2-m_colorHistoryInnerRadius+borderWidth); m_triangleColorSelector->resize(m_colorHistoryInnerRadius*2-borderWidth*2, m_colorHistoryInnerRadius*2-borderWidth*2); m_triangleColorSelector->setVisible(true); KoColor fgcolor(Qt::black, KoColorSpaceRegistry::instance()->rgb8()); if (m_resourceManager) { fgcolor = provider->fgColor(); } m_triangleColorSelector->slotSetColor(fgcolor); QRegion maskedRegion(0, 0, m_triangleColorSelector->width(), m_triangleColorSelector->height(), QRegion::Ellipse ); m_triangleColorSelector->setMask(maskedRegion); //setAttribute(Qt::WA_TranslucentBackground, true); connect(m_triangleColorSelector, SIGNAL(sigNewColor(const KoColor &)), m_colorChangeCompressor.data(), SLOT(start())); connect(m_colorChangeCompressor.data(), SIGNAL(timeout()), SLOT(slotEmitColorChanged())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_triangleColorSelector, SLOT(configurationChanged())); connect(m_resourceManager, SIGNAL(sigChangeFGColorSelector(KoColor)), SLOT(slotExternalFgColorChanged(KoColor))); connect(this, SIGNAL(sigChangefGColor(KoColor)), m_resourceManager, SIGNAL(sigSetFGColor(KoColor))); connect(this, SIGNAL(sigChangeActivePaintop(int)), m_resourceManager, SLOT(slotChangeActivePaintop(int))); connect(this, SIGNAL(sigUpdateRecentColor(int)), m_resourceManager, SLOT(slotUpdateRecentColor(int))); connect(m_resourceManager, SIGNAL(setSelectedColor(int)), SLOT(slotSetSelectedColor(int))); connect(m_resourceManager, SIGNAL(updatePalettes()), SLOT(slotUpdate())); connect(m_resourceManager, SIGNAL(hidePalettes()), SLOT(slotHide())); // This is used to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible m_timer.setSingleShot(true); connect(this, SIGNAL(sigTriggerTimer()), this, SLOT(slotTriggerTimer())); connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotEnableChangeFGColor())); connect(this, SIGNAL(sigEnableChangeFGColor(bool)), m_resourceManager, SIGNAL(sigEnableChangeColor(bool))); setCursor(Qt::ArrowCursor); setMouseTracking(true); setHoveredPreset(-1); setHoveredColor(-1); setSelectedColor(-1); m_brushHud = new KisBrushHud(provider, parent); m_brushHud->setMaximumHeight(m_popupPaletteSize); m_brushHud->setVisible(false); const int auxButtonSize = 35; m_settingsButton = new KisRoundHudButton(this); m_settingsButton->setGeometry(m_popupPaletteSize - 2.2 * auxButtonSize, m_popupPaletteSize - auxButtonSize, auxButtonSize, auxButtonSize); connect(m_settingsButton, SIGNAL(clicked()), SLOT(slotShowTagsPopup())); KisConfig cfg; m_brushHudButton = new KisRoundHudButton(this); m_brushHudButton->setCheckable(true); m_brushHudButton->setGeometry(m_popupPaletteSize - 1.0 * auxButtonSize, m_popupPaletteSize - auxButtonSize, auxButtonSize, auxButtonSize); connect(m_brushHudButton, SIGNAL(toggled(bool)), SLOT(showHudWidget(bool))); m_brushHudButton->setChecked(cfg.showBrushHud()); // add some stuff below the pop-up palette that will make it easier to use for tablet people QVBoxLayout* vLayout = new QVBoxLayout(this); // main layout QSpacerItem* verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); vLayout->addSpacerItem(verticalSpacer); // this should push the box to the bottom QHBoxLayout* hLayout = new QHBoxLayout(); vLayout->addLayout(hLayout); mirrorMode = new KisHighlightedToolButton(this); mirrorMode->setCheckable(true); mirrorMode->setFixedSize(35, 35); mirrorMode->setToolTip(i18n("Mirror Canvas")); connect(mirrorMode, SIGNAL(clicked(bool)), this, SLOT(slotmirroModeClicked())); canvasOnlyButton = new KisHighlightedToolButton(this); canvasOnlyButton->setCheckable(true); canvasOnlyButton->setFixedSize(35, 35); canvasOnlyButton->setToolTip(i18n("Canvas Only")); connect(canvasOnlyButton, SIGNAL(clicked(bool)), this, SLOT(slotCanvasonlyModeClicked())); zoomToOneHundredPercentButton = new QPushButton(this); zoomToOneHundredPercentButton->setText(i18n("100%")); zoomToOneHundredPercentButton->setFixedHeight(35); zoomToOneHundredPercentButton->setToolTip(i18n("Zoom to 100%")); connect(zoomToOneHundredPercentButton, SIGNAL(clicked(bool)), this, SLOT(slotZoomToOneHundredPercentClicked())); zoomCanvasSlider = new QSlider(Qt::Horizontal, this); zoomSliderMinValue = 10; // set in % zoomSliderMaxValue = 200; // set in % zoomCanvasSlider->setRange(zoomSliderMinValue, zoomSliderMaxValue); zoomCanvasSlider->setFixedHeight(35); zoomCanvasSlider->setValue(m_coordinatesConverter->zoomInPercent()); zoomCanvasSlider->setSingleStep(1); zoomCanvasSlider->setPageStep(1); connect(zoomCanvasSlider, SIGNAL(valueChanged(int)), this, SLOT(slotZoomSliderChanged(int))); slotUpdateIcons(); hLayout->addWidget(mirrorMode); hLayout->addWidget(canvasOnlyButton); hLayout->addWidget(zoomToOneHundredPercentButton); hLayout->addWidget(zoomCanvasSlider); setVisible(true); setVisible(false); // Prevent tablet events from being captured by the canvas setAttribute(Qt::WA_NoMousePropagation, true); } void KisPopupPalette::slotExternalFgColorChanged(const KoColor &color) { //hack to get around cmyk for now. if (color.colorSpace()->colorChannelCount()>3) { KoColor c(KoColorSpaceRegistry::instance()->rgb8()); c.fromKoColor(color); m_triangleColorSelector->slotSetColor(c); } else { m_triangleColorSelector->slotSetColor(color); } } void KisPopupPalette::slotEmitColorChanged() { if (isVisible()) { update(); emit sigChangefGColor(m_triangleColorSelector->getCurrentColor()); } } //setting KisPopupPalette properties int KisPopupPalette::hoveredPreset() const { return m_hoveredPreset; } void KisPopupPalette::setHoveredPreset(int x) { m_hoveredPreset = x; } int KisPopupPalette::hoveredColor() const { return m_hoveredColor; } void KisPopupPalette::setHoveredColor(int x) { m_hoveredColor = x; } int KisPopupPalette::selectedColor() const { return m_selectedColor; } void KisPopupPalette::setSelectedColor(int x) { m_selectedColor = x; } void KisPopupPalette::slotTriggerTimer() { m_timer.start(750); } void KisPopupPalette::slotEnableChangeFGColor() { emit sigEnableChangeFGColor(true); } void KisPopupPalette::slotZoomSliderChanged(int zoom) { emit zoomLevelChanged(zoom); } void KisPopupPalette::adjustLayout(const QPoint &p) { KIS_ASSERT_RECOVER_RETURN(m_brushHud); if (isVisible() && parentWidget()) { float hudMargin = 30.0; const QRect fitRect = kisGrowRect(parentWidget()->rect(), -20.0); // -20 is widget margin const QPoint paletteCenterOffset(m_popupPaletteSize / 2, m_popupPaletteSize / 2); QRect paletteRect = rect(); paletteRect.moveTo(p - paletteCenterOffset); if (m_brushHudButton->isChecked()) { m_brushHud->updateGeometry(); paletteRect.adjust(0, 0, m_brushHud->width() + hudMargin, 0); } paletteRect = kisEnsureInRect(paletteRect, fitRect); move(paletteRect.topLeft()); m_brushHud->move(paletteRect.topLeft() + QPoint(m_popupPaletteSize + hudMargin, 0)); m_lastCenterPoint = p; } } void KisPopupPalette::slotUpdateIcons() { zoomToOneHundredPercentButton->setIcon(KisIconUtils::loadIcon("zoom-original")); canvasOnlyButton->setIcon(KisIconUtils::loadIcon("document-new")); mirrorMode->setIcon(KisIconUtils::loadIcon("symmetry-horizontal")); m_settingsButton->setIcon(KisIconUtils::loadIcon("configure")); m_brushHud->updateIcons(); m_brushHudButton->setOnOffIcons(KisIconUtils::loadIcon("arrow-left"), KisIconUtils::loadIcon("arrow-right")); } void KisPopupPalette::showHudWidget(bool visible) { KIS_ASSERT_RECOVER_RETURN(m_brushHud); const bool reallyVisible = visible && m_brushHudButton->isChecked(); if (reallyVisible) { m_brushHud->updateProperties(); } m_brushHud->setVisible(reallyVisible); adjustLayout(m_lastCenterPoint); KisConfig cfg; cfg.setShowBrushHud(visible); } void KisPopupPalette::showPopupPalette(const QPoint &p) { showPopupPalette(!isVisible()); adjustLayout(p); } void KisPopupPalette::showPopupPalette(bool show) { if (show) { // don't set the zoom slider if we are outside of the zoom slider bounds. It will change the zoom level to within // the bounds and cause the canvas to jump between the slider's min and max if (m_coordinatesConverter->zoomInPercent() > zoomSliderMinValue && - m_coordinatesConverter->zoomInPercent() < zoomSliderMaxValue ){ + m_coordinatesConverter->zoomInPercent() < zoomSliderMaxValue ){ KisSignalsBlocker b(zoomCanvasSlider); zoomCanvasSlider->setValue(m_coordinatesConverter->zoomInPercent()); // sync the zoom slider } emit sigEnableChangeFGColor(!show); } else { emit sigTriggerTimer(); } setVisible(show); m_brushHud->setVisible(show && m_brushHudButton->isChecked()); } //redefinition of setVariable function to change the scope to private void KisPopupPalette::setVisible(bool b) { QWidget::setVisible(b); } void KisPopupPalette::setParent(QWidget *parent) { m_brushHud->setParent(parent); QWidget::setParent(parent); } QSize KisPopupPalette::sizeHint() const { return QSize(m_popupPaletteSize, m_popupPaletteSize + 50); // last number is the space for the toolbar below } void KisPopupPalette::resizeEvent(QResizeEvent*) { } void KisPopupPalette::paintEvent(QPaintEvent* e) { Q_UNUSED(e); QPainter painter(this); QPen pen(palette().color(QPalette::Text)); pen.setWidth(3); painter.setPen(pen); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); //painting background color indicator QPainterPath bgColor; bgColor.addEllipse(QPoint( 50, 80), 30, 30); painter.fillPath(bgColor, m_displayRenderer->toQColor(m_resourceManager->bgColor())); painter.drawPath(bgColor); //painting foreground color indicator QPainterPath fgColor; fgColor.addEllipse(QPoint( 60, 50), 30, 30); painter.fillPath(fgColor, m_displayRenderer->toQColor(m_triangleColorSelector->getCurrentColor())); painter.drawPath(fgColor); // create a circle background that everything else will go into QPainterPath backgroundContainer; float shrinkCircleAmount = 3;// helps the circle when the stroke is put around it QRectF circleRect(shrinkCircleAmount, shrinkCircleAmount, m_popupPaletteSize - shrinkCircleAmount*2,m_popupPaletteSize - shrinkCircleAmount*2); backgroundContainer.addEllipse( circleRect ); painter.fillPath(backgroundContainer,palette().brush(QPalette::Background)); painter.drawPath(backgroundContainer); // create a path slightly inside the container circle. this will create a 'track' to indicate that we can rotate the canvas // with the indicator QPainterPath rotationTrackPath; shrinkCircleAmount = 18; QRectF circleRect2(shrinkCircleAmount, shrinkCircleAmount, - m_popupPaletteSize - shrinkCircleAmount*2,m_popupPaletteSize - shrinkCircleAmount*2); + m_popupPaletteSize - shrinkCircleAmount*2,m_popupPaletteSize - shrinkCircleAmount*2); rotationTrackPath.addEllipse( circleRect2 ); pen.setWidth(1); painter.setPen(pen); painter.drawPath(rotationTrackPath); // this thing will help indicate where the starting brush preset is at. // also what direction they go to give sor order to the presets populated /* pen.setWidth(6); pen.setCapStyle(Qt::RoundCap); painter.setPen(pen); painter.drawArc(circleRect, (16*90), (16*-30)); // span angle (last parameter) is in 16th of degrees QPainterPath brushDir; brushDir.arcMoveTo(circleRect, 60); brushDir.lineTo(brushDir.currentPosition().x()-5, brushDir.currentPosition().y() - 14); painter.drawPath(brushDir); brushDir.lineTo(brushDir.currentPosition().x()-2, brushDir.currentPosition().y() + 6); painter.drawPath(brushDir); */ // the following things needs to be based off the center, so let's translate the painter painter.translate(m_popupPaletteSize / 2, m_popupPaletteSize / 2); // create the canvas rotation handle QPainterPath rotationIndicator = drawRotationIndicator(m_coordinatesConverter->rotationAngle(), true); painter.fillPath(rotationIndicator,palette().brush(QPalette::Text)); // hover indicator for the canvas rotation if (m_isOverCanvasRotationIndicator == true) { - painter.save(); + painter.save(); QPen pen(palette().color(QPalette::Highlight)); pen.setWidth(2); painter.setPen(pen); painter.drawPath(rotationIndicator); painter.restore(); } // create a reset canvas rotation indicator to bring the canvas back to 0 degrees QPainterPath resetRotationIndicator = drawRotationIndicator(0, false); QPen resetPen(palette().color(QPalette::Text)); resetPen.setWidth(1); painter.save(); painter.setPen(resetPen); painter.drawPath(resetRotationIndicator); painter.restore(); //painting favorite brushes QList images(m_resourceManager->favoritePresetImages()); //painting favorite brushes pixmap/icon QPainterPath presetPath; for (int pos = 0; pos < numSlots(); pos++) { painter.save(); presetPath = createPathFromPresetIndex(pos); if (pos < images.size()) { painter.setClipPath(presetPath); QRect bounds = presetPath.boundingRect().toAlignedRect(); painter.drawImage(bounds.topLeft() , images.at(pos).scaled(bounds.size() , Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); } else { painter.fillPath(presetPath, palette().brush(QPalette::Window)); // brush slot that has no brush in it } QPen pen = painter.pen(); pen.setWidth(1); painter.setPen(pen); painter.drawPath(presetPath); painter.restore(); } if (hoveredPreset() > -1) { presetPath = createPathFromPresetIndex(hoveredPreset()); QPen pen(palette().color(QPalette::Highlight)); pen.setWidth(3); painter.setPen(pen); painter.drawPath(presetPath); } // paint recent colors area. painter.setPen(Qt::NoPen); float rotationAngle = -360.0 / m_resourceManager->recentColorsTotal(); - // there might be no recent colors at the start, so paint a placeholder - if (m_resourceManager->recentColorsTotal() == 0) { + // there might be no recent colors at the start, so paint a placeholder + if (m_resourceManager->recentColorsTotal() == 0) { painter.setBrush(Qt::transparent); QPainterPath emptyRecentColorsPath(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius)); painter.setPen(QPen(palette().color(QPalette::Background).lighter(150), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); painter.drawPath(emptyRecentColorsPath); } else { - for (int pos = 0; pos < m_resourceManager->recentColorsTotal(); pos++) { - QPainterPath recentColorsPath(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal())); + for (int pos = 0; pos < m_resourceManager->recentColorsTotal(); pos++) { + QPainterPath recentColorsPath(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal())); - //accessing recent color of index pos - painter.fillPath(recentColorsPath, m_displayRenderer->toQColor( m_resourceManager->recentColorAt(pos) )); - painter.drawPath(recentColorsPath); - painter.rotate(rotationAngle); - } + //accessing recent color of index pos + painter.fillPath(recentColorsPath, m_displayRenderer->toQColor( m_resourceManager->recentColorAt(pos) )); + painter.drawPath(recentColorsPath); + painter.rotate(rotationAngle); + } - } + } //painting hovered color if (hoveredColor() > -1) { painter.setPen(QPen(palette().color(QPalette::Highlight), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); if (m_resourceManager->recentColorsTotal() == 1) { QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius)); painter.drawPath(path_ColorDonut); } else { painter.rotate((m_resourceManager->recentColorsTotal() + hoveredColor()) *rotationAngle); QPainterPath path(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal())); painter.drawPath(path); painter.rotate(hoveredColor() * -1 * rotationAngle); } } //painting selected color if (selectedColor() > -1) { painter.setPen(QPen(palette().color(QPalette::Highlight).darker(130), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); if (m_resourceManager->recentColorsTotal() == 1) { QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius)); painter.drawPath(path_ColorDonut); } else { painter.rotate((m_resourceManager->recentColorsTotal() + selectedColor()) *rotationAngle); QPainterPath path(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal())); painter.drawPath(path); painter.rotate(selectedColor() * -1 * rotationAngle); } } } QPainterPath KisPopupPalette::drawDonutPathFull(int x, int y, int inner_radius, int outer_radius) { QPainterPath path; path.addEllipse(QPointF(x, y), outer_radius, outer_radius); path.addEllipse(QPointF(x, y), inner_radius, inner_radius); path.setFillRule(Qt::OddEvenFill); return path; } QPainterPath KisPopupPalette::drawDonutPathAngle(int inner_radius, int outer_radius, int limit) { QPainterPath path; path.moveTo(-0.999 * outer_radius * sin(M_PI / limit), 0.999 * outer_radius * cos(M_PI / limit)); path.arcTo(-1 * outer_radius, -1 * outer_radius, 2 * outer_radius, 2 * outer_radius, -90.0 - 180.0 / limit, 360.0 / limit); path.arcTo(-1 * inner_radius, -1 * inner_radius, 2 * inner_radius, 2 * inner_radius, -90.0 + 180.0 / limit, - 360.0 / limit); path.closeSubpath(); return path; } QPainterPath KisPopupPalette::drawRotationIndicator(qreal rotationAngle, bool canDrag) { // used for canvas rotation. This function gets called twice. Once by the canvas rotation indicator, // and another time by the reset canvas position - float canvasRotationRadians = qDegreesToRadians(rotationAngle - 90); // -90 will make 0 degrees be at the top - float rotationDialXPosition = qCos(canvasRotationRadians) * (m_popupPaletteSize/2 - 10); // m_popupPaletteSize/2 = radius - float rotationDialYPosition = qSin(canvasRotationRadians) * (m_popupPaletteSize/2 - 10); + float canvasRotationRadians = qDegreesToRadians(rotationAngle - 90); // -90 will make 0 degrees be at the top + float rotationDialXPosition = qCos(canvasRotationRadians) * (m_popupPaletteSize/2 - 10); // m_popupPaletteSize/2 = radius + float rotationDialYPosition = qSin(canvasRotationRadians) * (m_popupPaletteSize/2 - 10); - QPainterPath canvasRotationIndicator; - int canvasIndicatorSize = 15; - float canvasIndicatorMiddle = canvasIndicatorSize/2; - QRect indicatorRectangle = QRect( rotationDialXPosition - canvasIndicatorMiddle, rotationDialYPosition - canvasIndicatorMiddle, - canvasIndicatorSize, canvasIndicatorSize ); + QPainterPath canvasRotationIndicator; + int canvasIndicatorSize = 15; + float canvasIndicatorMiddle = canvasIndicatorSize/2; + QRect indicatorRectangle = QRect( rotationDialXPosition - canvasIndicatorMiddle, rotationDialYPosition - canvasIndicatorMiddle, + canvasIndicatorSize, canvasIndicatorSize ); - if (canDrag) { - m_canvasRotationIndicatorRect = indicatorRectangle; - } else { - m_resetCanvasRotationIndicatorRect = indicatorRectangle; - } + if (canDrag) { + m_canvasRotationIndicatorRect = indicatorRectangle; + } else { + m_resetCanvasRotationIndicatorRect = indicatorRectangle; + } - canvasRotationIndicator.addEllipse(indicatorRectangle.x(), indicatorRectangle.y(), - indicatorRectangle.width(), indicatorRectangle.height() ); + canvasRotationIndicator.addEllipse(indicatorRectangle.x(), indicatorRectangle.y(), + indicatorRectangle.width(), indicatorRectangle.height() ); - return canvasRotationIndicator; + return canvasRotationIndicator; } void KisPopupPalette::mouseMoveEvent(QMouseEvent* event) { QPointF point = event->localPos(); event->accept(); setToolTip(QString()); setHoveredPreset(-1); setHoveredColor(-1); // calculate if we are over the canvas rotation knob // before we started painting, we moved the painter to the center of the widget, so the X/Y positions are offset. we need to // correct them first before looking for a click event intersection float rotationCorrectedXPos = m_canvasRotationIndicatorRect.x() + (m_popupPaletteSize / 2); float rotationCorrectedYPos = m_canvasRotationIndicatorRect.y() + (m_popupPaletteSize / 2); QRect correctedCanvasRotationIndicator = QRect(rotationCorrectedXPos, rotationCorrectedYPos, - m_canvasRotationIndicatorRect.width(), m_canvasRotationIndicatorRect.height()); + m_canvasRotationIndicatorRect.width(), m_canvasRotationIndicatorRect.height()); if (correctedCanvasRotationIndicator.contains(point.x(), point.y())) { m_isOverCanvasRotationIndicator = true; } else { m_isOverCanvasRotationIndicator = false; } if (m_isRotatingCanvasIndicator) { // we are rotating the canvas, so calculate the rotation angle based off the center // calculate the angle we are at first QPoint widgetCenterPoint = QPoint(m_popupPaletteSize/2, m_popupPaletteSize/2); float dX = point.x() - widgetCenterPoint.x(); float dY = point.y() - widgetCenterPoint.y(); float finalAngle = qAtan2(dY,dX) * 180 / M_PI; // what we need if we have two points, but don't know the angle finalAngle = finalAngle + 90; // add 90 degrees so 0 degree position points up float angleDifference = finalAngle - m_coordinatesConverter->rotationAngle(); // the rotation function accepts diffs, so find it out m_coordinatesConverter->rotate(m_coordinatesConverter->widgetCenterPoint(), angleDifference); m_viewManager->canvasBase()->notifyZoomChanged(); // refreshes the canvas after rotation emit sigUpdateCanvas(); } // don't highlight the presets if we are in the middle of rotating the canvas if (m_isRotatingCanvasIndicator == false) { QPainterPath pathColor(drawDonutPathFull(m_popupPaletteSize / 2, m_popupPaletteSize / 2, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius)); { int pos = calculatePresetIndex(point, m_resourceManager->numFavoritePresets()); if (pos >= 0 && pos < m_resourceManager->numFavoritePresets()) { setToolTip(m_resourceManager->favoritePresetList().at(pos).data()->name()); setHoveredPreset(pos); } } if (pathColor.contains(point)) { int pos = calculateIndex(point, m_resourceManager->recentColorsTotal()); if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) { setHoveredColor(pos); } } } update(); } void KisPopupPalette::mousePressEvent(QMouseEvent* event) { QPointF point = event->localPos(); event->accept(); if (event->button() == Qt::LeftButton) { //in favorite brushes area int pos = calculateIndex(point, m_resourceManager->numFavoritePresets()); if (pos >= 0 && pos < m_resourceManager->numFavoritePresets() && isPointInPixmap(point, pos)) { //setSelectedBrush(pos); update(); } if (m_isOverCanvasRotationIndicator) { m_isRotatingCanvasIndicator = true; } // reset the canvas if we are over the reset canvas rotation indicator float rotationCorrectedXPos = m_resetCanvasRotationIndicatorRect.x() + (m_popupPaletteSize / 2); float rotationCorrectedYPos = m_resetCanvasRotationIndicatorRect.y() + (m_popupPaletteSize / 2); QRect correctedResetCanvasRotationIndicator = QRect(rotationCorrectedXPos, rotationCorrectedYPos, m_resetCanvasRotationIndicatorRect.width(), m_resetCanvasRotationIndicatorRect.height()); if (correctedResetCanvasRotationIndicator.contains(point.x(), point.y())) { float angleDifference = -m_coordinatesConverter->rotationAngle(); // the rotation function accepts diffs, so find it ou m_coordinatesConverter->rotate(m_coordinatesConverter->widgetCenterPoint(), angleDifference); m_viewManager->canvasBase()->notifyZoomChanged(); // refreshes the canvas after rotation emit sigUpdateCanvas(); } } } void KisPopupPalette::slotShowTagsPopup() { KisPaintOpPresetResourceServer* rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QStringList tags = rServer->tagNamesList(); std::sort(tags.begin(), tags.end()); if (!tags.isEmpty()) { QMenu menu; Q_FOREACH (const QString& tag, tags) { menu.addAction(tag); } QAction* action = menu.exec(QCursor::pos()); if (action) { m_resourceManager->setCurrentTag(action->text()); } } else { QWhatsThis::showText(QCursor::pos(), i18n("There are no tags available to show in this popup. To add presets, you need to tag them and then select the tag here.")); } } void KisPopupPalette::slotmirroModeClicked() { QAction* action = m_actionCollection->action("mirror_canvas"); if (action) { - action->trigger(); + action->trigger(); } } void KisPopupPalette::slotCanvasonlyModeClicked() { QAction* action = m_actionCollection->action("view_show_canvas_only"); if (action) { - action->trigger(); + action->trigger(); } } void KisPopupPalette::slotZoomToOneHundredPercentClicked() { QAction* action = m_actionCollection->action("zoom_to_100pct"); if (action) { - action->trigger(); + action->trigger(); } // also move the zoom slider to 100% position so they are in sync zoomCanvasSlider->setValue(100); } void KisPopupPalette::tabletEvent(QTabletEvent* event) { event->ignore(); } void KisPopupPalette::mouseReleaseEvent(QMouseEvent * event) { QPointF point = event->localPos(); event->accept(); m_isOverCanvasRotationIndicator = false; m_isRotatingCanvasIndicator = false; if (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) { QPainterPath pathColor(drawDonutPathFull(m_popupPaletteSize / 2, m_popupPaletteSize / 2, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius)); //in favorite brushes area if (hoveredPreset() > -1) { //setSelectedBrush(hoveredBrush()); emit sigChangeActivePaintop(hoveredPreset()); } if (pathColor.contains(point)) { int pos = calculateIndex(point, m_resourceManager->recentColorsTotal()); if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) { emit sigUpdateRecentColor(pos); } } } } int KisPopupPalette::calculateIndex(QPointF point, int n) { calculatePresetIndex(point, n); //translate to (0,0) point.setX(point.x() - m_popupPaletteSize / 2); point.setY(point.y() - m_popupPaletteSize / 2); //rotate float smallerAngle = M_PI / 2 + M_PI / n - atan2(point.y(), point.x()); float radius = sqrt((float)point.x() * point.x() + point.y() * point.y()); point.setX(radius * cos(smallerAngle)); point.setY(radius * sin(smallerAngle)); //calculate brush index int pos = floor(acos(point.x() / radius) * n / (2 * M_PI)); if (point.y() < 0) pos = n - pos - 1; return pos; } bool KisPopupPalette::isPointInPixmap(QPointF& point, int pos) { if (createPathFromPresetIndex(pos).contains(point + QPointF(-m_popupPaletteSize / 2, -m_popupPaletteSize / 2))) { return true; } return false; } KisPopupPalette::~KisPopupPalette() { } QPainterPath KisPopupPalette::createPathFromPresetIndex(int index) { qreal angleSlice = 360.0 / numSlots() ; // how many degrees each slice will get // the starting angle of the slice we need to draw. the negative sign makes us go clockwise. // adding 90 degrees makes us start at the top. otherwise we would start at the right qreal startingAngle = -(index * angleSlice) + 90; // the radius will get smaller as the amount of presets shown increases. 10 slots == 41 qreal presetRadius = m_colorHistoryOuterRadius * qSin(qDegreesToRadians(angleSlice/2)) / (1-qSin(qDegreesToRadians(angleSlice/2))); QPainterPath path; float pathX = (m_colorHistoryOuterRadius + presetRadius) * qCos(qDegreesToRadians(startingAngle)) - presetRadius; float pathY = -(m_colorHistoryOuterRadius + presetRadius) * qSin(qDegreesToRadians(startingAngle)) - presetRadius; float pathDiameter = 2 * presetRadius; // distance is used to calculate the X/Y in addition to the preset circle size path.addEllipse(pathX, pathY, pathDiameter, pathDiameter); return path; } int KisPopupPalette::calculatePresetIndex(QPointF point, int /*n*/) { for(int i = 0; i < numSlots(); i++) { QPointF adujustedPoint = point - QPointF(m_popupPaletteSize/2, m_popupPaletteSize/2); if(createPathFromPresetIndex(i).contains(adujustedPoint)) { return i; } } return -1; } int KisPopupPalette::numSlots() { KisConfig config; return qMax(config.favoritePresets(), 10); } diff --git a/libs/ui/kis_popup_palette.h b/libs/ui/kis_popup_palette.h index 1b2b5f3b12..d94ba27299 100644 --- a/libs/ui/kis_popup_palette.h +++ b/libs/ui/kis_popup_palette.h @@ -1,182 +1,182 @@ /* This file is part of the KDE project Copyright 2009 Vera Lukman Copyright 2016 Scott Petrovic This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 KIS_POPUP_PALETTE_H #define KIS_POPUP_PALETTE_H #include #include #include #include #include #include #include "kis_action_manager.h" #include "KisViewManager.h" #include "kactioncollection.h" #include "kis_coordinates_converter.h" #include "kis_tool_button.h" #include "kis_highlighted_button.h" #include class KisFavoriteResourceManager; class QWidget; class KoColor; class KoTriangleColorSelector; class KisSignalCompressor; class KisBrushHud; class KisRoundHudButton; class KisCanvasResourceProvider; class KisVisualColorSelector; class KisPopupPalette : public QWidget { Q_OBJECT Q_PROPERTY(int hoveredPreset READ hoveredPreset WRITE setHoveredPreset) Q_PROPERTY(int hoveredColor READ hoveredColor WRITE setHoveredColor) Q_PROPERTY(int selectedColor READ selectedColor WRITE setSelectedColor) public: KisPopupPalette(KisViewManager*, KisCoordinatesConverter* ,KisFavoriteResourceManager*, const KoColorDisplayRendererInterface *displayRenderer, KisCanvasResourceProvider *provider, QWidget *parent = 0); ~KisPopupPalette() override; QSize sizeHint() const override; void showPopupPalette(const QPoint&); void showPopupPalette(bool b); //functions to set up selectedBrush void setSelectedBrush(int x); int selectedBrush() const; //functions to set up selectedColor void setSelectedColor(int x); int selectedColor() const; void setParent(QWidget *parent); void tabletEvent(QTabletEvent * event) override; protected: void paintEvent(QPaintEvent*) override; void resizeEvent(QResizeEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; void mousePressEvent(QMouseEvent*) override; //functions to calculate index of favorite brush or recent color in array //n is the total number of favorite brushes or recent colors int calculateIndex(QPointF, int n); int calculatePresetIndex(QPointF, int n); //functions to set up hoveredBrush void setHoveredPreset(int x); int hoveredPreset() const; //functions to set up hoveredColor void setHoveredColor(int x); int hoveredColor() const; private: void setVisible(bool b) override; QPainterPath drawDonutPathFull(int, int, int, int); QPainterPath drawDonutPathAngle(int, int, int); QPainterPath drawRotationIndicator(qreal rotationAngle, bool canDrag); bool isPointInPixmap(QPointF&, int pos); QPainterPath createPathFromPresetIndex(int index); int numSlots(); void adjustLayout(const QPoint &p); private: - int m_hoveredPreset; - int m_hoveredColor; - int m_selectedColor; + int m_hoveredPreset {0}; + int m_hoveredColor {0}; + int m_selectedColor {0}; KisCoordinatesConverter* m_coordinatesConverter; - KisActionManager* m_actionManager; KisViewManager* m_viewManager; + KisActionManager* m_actionManager; KisFavoriteResourceManager* m_resourceManager; KisColorSelectorInterface* m_triangleColorSelector {0}; const KoColorDisplayRendererInterface *m_displayRenderer; QScopedPointer m_colorChangeCompressor; KActionCollection* m_actionCollection; QTimer m_timer; - KisBrushHud *m_brushHud; - float m_popupPaletteSize; - float m_colorHistoryInnerRadius; - float m_colorHistoryOuterRadius; + KisBrushHud *m_brushHud {0}; + float m_popupPaletteSize {385.0}; + float m_colorHistoryInnerRadius {72.0}; + float m_colorHistoryOuterRadius {92.0}; - KisRoundHudButton *m_settingsButton; - KisRoundHudButton *m_brushHudButton; + KisRoundHudButton *m_settingsButton {0}; + KisRoundHudButton *m_brushHudButton {0}; QPoint m_lastCenterPoint; QRect m_canvasRotationIndicatorRect; QRect m_resetCanvasRotationIndicatorRect; - bool m_isOverCanvasRotationIndicator; - bool m_isRotatingCanvasIndicator; - - KisHighlightedToolButton* mirrorMode; - KisHighlightedToolButton* canvasOnlyButton; - QPushButton* zoomToOneHundredPercentButton; - QSlider* zoomCanvasSlider; - int zoomSliderMinValue; - int zoomSliderMaxValue; + bool m_isOverCanvasRotationIndicator {false}; + bool m_isRotatingCanvasIndicator {false}; + + KisHighlightedToolButton *mirrorMode {0}; + KisHighlightedToolButton *canvasOnlyButton {0}; + QPushButton *zoomToOneHundredPercentButton {0}; + QSlider *zoomCanvasSlider {0}; + int zoomSliderMinValue {10}; + int zoomSliderMaxValue {200}; Q_SIGNALS: void sigChangeActivePaintop(int); void sigUpdateRecentColor(int); void sigChangefGColor(const KoColor&); void sigUpdateCanvas(); void zoomLevelChanged(int); // These are used to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible void sigEnableChangeFGColor(bool); void sigTriggerTimer(); public Q_SLOTS: void slotUpdateIcons(); private Q_SLOTS: void slotExternalFgColorChanged(const KoColor &color); void slotEmitColorChanged(); void slotSetSelectedColor(int x) { setSelectedColor(x); update(); } void slotTriggerTimer(); void slotEnableChangeFGColor(); void slotUpdate() { update(); } void slotHide() { showPopupPalette(false); } void slotShowTagsPopup(); void showHudWidget(bool visible); void slotmirroModeClicked(); void slotCanvasonlyModeClicked(); void slotZoomToOneHundredPercentClicked(); void slotZoomSliderChanged(int zoom); }; #endif // KIS_POPUP_PALETTE_H diff --git a/libs/ui/opengl/kis_opengl_p.h b/libs/ui/opengl/kis_opengl_p.h index 4c8f9d4401..ef74ad6bda 100644 --- a/libs/ui/opengl/kis_opengl_p.h +++ b/libs/ui/opengl/kis_opengl_p.h @@ -1,110 +1,110 @@ /* * Copyright (c) 2017 Alvin Wong * * 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_OPENGL_P_H_ #define KIS_OPENGL_P_H_ #include #include class QDebug; class QOpenGLContext; class KLocalizedString; namespace KisOpenGLPrivate { class OpenGLCheckResult { int m_glMajorVersion = 0; int m_glMinorVersion = 0; bool m_supportsDeprecatedFunctions = false; bool m_isOpenGLES = false; QString m_rendererString; QString m_driverVersionString; public: OpenGLCheckResult(QOpenGLContext &context); int glMajorVersion() const { return m_glMajorVersion; } int glMinorVersion() const { return m_glMinorVersion; } bool supportsDeprecatedFunctions() const { return m_supportsDeprecatedFunctions; } bool isOpenGLES() const { return m_isOpenGLES; } QString rendererString() const { return m_rendererString; } QString driverVersionString() const { return m_driverVersionString; } bool isSupportedVersion() const { return #ifdef Q_OS_OSX ((m_glMajorVersion * 100 + m_glMinorVersion) >= 302) #else (m_glMajorVersion >= 3 && (m_supportsDeprecatedFunctions || m_isOpenGLES)) || ((m_glMajorVersion * 100 + m_glMinorVersion) == 201) #endif ; } bool supportsLoD() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 300; } bool hasOpenGL3() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 302; } bool supportsFenceSync() const { return m_glMajorVersion >= 3; } #ifdef Q_OS_WIN // This is only for detecting whether ANGLE is being used. // For detecting generic OpenGL ES please check isOpenGLES bool isUsingAngle() const { return m_rendererString.startsWith("ANGLE", Qt::CaseInsensitive); } #endif }; void appendPlatformOpenGLDebugText(QDebug &debugOut); #ifndef Q_OS_WIN -void appendPlatformOpenGLDebugText(QDebug &debugOut) {} +void appendPlatformOpenGLDebugText(QDebug &/*debugOut*/) {} #endif void appendOpenGLWarningString(KLocalizedString warning); bool isDefaultFormatSet(); } // namespace KisOpenGLPrivate #endif // KIS_OPENGL_P_H_ diff --git a/libs/ui/widgets/kis_gradient_slider.cpp b/libs/ui/widgets/kis_gradient_slider.cpp index 16c0619c38..d6928ab74d 100644 --- a/libs/ui/widgets/kis_gradient_slider.cpp +++ b/libs/ui/widgets/kis_gradient_slider.cpp @@ -1,401 +1,402 @@ /* * This file is part of Krita * * Copyright (c) 2006 Frederic Coiffier * * 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. */ // Local includes. #include "kis_gradient_slider.h" // C++ includes. #include #include // Qt includes. #include #include #include #include #include #include #include #include #define MARGIN 5 #define HANDLE_SIZE 10 KisGradientSlider::KisGradientSlider(QWidget *parent) : QWidget(parent) , m_leftmost(0) , m_rightmost(0) , m_scalingFactor(0) , m_blackCursor(0) , m_whiteCursor(0) , m_gammaCursor(0) , m_black(0) , m_white(255) , m_gamma(1.0) , m_gammaEnabled(false) , m_whiteEnabled(true) , m_feedback(false) , m_inverted(false) { m_grabCursor = None; setMouseTracking(true); setFocusPolicy(Qt::StrongFocus); } KisGradientSlider::~KisGradientSlider() { } int KisGradientSlider::black() const { return m_black; } int KisGradientSlider::white() const { return m_white; } void KisGradientSlider::paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); - int x, y; + int x = 0; + int y = 0; int wWidth = width() - (2 * MARGIN); int wHeight = height(); const int gradientHeight = qRound((double)wHeight / 7.0 * 2); QPainter p1(this); p1.fillRect(rect(), palette().background()); p1.setPen(Qt::black); p1.drawRect(MARGIN, MARGIN, wWidth, height() - 2 * MARGIN - HANDLE_SIZE); // Draw first gradient QLinearGradient grayGradient(MARGIN, y, wWidth, gradientHeight); grayGradient.setColorAt(0, m_inverted ? Qt::white : Qt::black); grayGradient.setColorAt(1, m_inverted ? Qt::black : Qt::white); p1.fillRect(MARGIN, 0, wWidth, gradientHeight, QBrush(grayGradient)); // Draw second gradient y = gradientHeight; p1.fillRect(MARGIN, y, wWidth, gradientHeight, Qt::white); if (m_blackCursor > 0 && !m_inverted) { p1.fillRect(MARGIN, y, m_blackCursor, gradientHeight, Qt::black); } else if (m_blackCursor < wWidth && m_inverted) { p1.fillRect(MARGIN + m_blackCursor, y, wWidth - m_blackCursor, gradientHeight, Qt::black); } int left = qMin(m_blackCursor, m_whiteCursor); int right = qMax(m_blackCursor, m_whiteCursor); for (x = left; x <= right; ++x) { double inten = (double)(x - m_blackCursor) / (double)(m_whiteCursor - m_blackCursor); inten = pow(inten, (1.0 / m_gamma)); int gray = (int)(255 * inten); p1.setPen(QColor(gray, gray, gray)); p1.drawLine(x + MARGIN, y, x + MARGIN, y + gradientHeight - 1); } // Draw cursors y += gradientHeight; QPoint a[3]; p1.setPen(Qt::darkGray); p1.setRenderHint(QPainter::Antialiasing, true); const int cursorHalfBase = (int)(gradientHeight / 1.5); a[0] = QPoint(m_blackCursor + MARGIN, y); a[1] = QPoint(m_blackCursor + MARGIN + cursorHalfBase, wHeight - 1); a[2] = QPoint(m_blackCursor + MARGIN - cursorHalfBase, wHeight - 1); p1.setBrush(Qt::black); p1.drawPolygon(a, 3); p1.setPen(Qt::black); if (m_gammaEnabled) { a[0] = QPoint(m_gammaCursor + MARGIN, y); a[1] = QPoint(m_gammaCursor + MARGIN + cursorHalfBase, wHeight - 1); a[2] = QPoint(m_gammaCursor + MARGIN - cursorHalfBase, wHeight - 1); p1.setBrush(Qt::gray); p1.drawPolygon(a, 3); } if (m_whiteEnabled) { a[0] = QPoint(m_whiteCursor + MARGIN, y); a[1] = QPoint(m_whiteCursor + MARGIN + cursorHalfBase, wHeight - 1); a[2] = QPoint(m_whiteCursor + MARGIN - cursorHalfBase, wHeight - 1); p1.setBrush(Qt::white); p1.drawPolygon(a, 3); } } void KisGradientSlider::resizeEvent(QResizeEvent *) { m_scalingFactor = (double)(width() - 2 * MARGIN) / 255; calculateCursorPositions(); update(); } void KisGradientSlider::mousePressEvent(QMouseEvent *e) { eCursor closest_cursor; int distance; if (e->button() != Qt::LeftButton) return; unsigned int x = e->pos().x(); int xMinusMargin = x - MARGIN; distance = width() + 1; // just a big number if (abs((int)(xMinusMargin - m_blackCursor)) < distance) { distance = abs((int)(xMinusMargin - m_blackCursor)); closest_cursor = BlackCursor; } if (abs((int)(xMinusMargin - m_whiteCursor)) < distance) { distance = abs((int)(xMinusMargin - m_whiteCursor)); closest_cursor = WhiteCursor; } if (m_gammaEnabled) { int gammaDistance = (int)xMinusMargin - m_gammaCursor; if (abs(gammaDistance) < distance) { distance = abs((int)xMinusMargin - m_gammaCursor); closest_cursor = GammaCursor; } else if (abs(gammaDistance) == distance) { if ((closest_cursor == BlackCursor) && (gammaDistance > 0)) { distance = abs(gammaDistance); closest_cursor = GammaCursor; } else if ((closest_cursor == WhiteCursor) && (gammaDistance < 0)) { distance = abs(gammaDistance); closest_cursor = GammaCursor; } } } if (distance > 20) { m_grabCursor = None; return; } // Determine cursor values and the leftmost and rightmost points. switch (closest_cursor) { case BlackCursor: m_blackCursor = xMinusMargin; m_grabCursor = closest_cursor; if (m_inverted) { m_leftmost = m_whiteCursor + 1; m_rightmost = width() - 2 * MARGIN - 1; } else { m_leftmost = 0; m_rightmost = m_whiteCursor - 1; } if (m_gammaEnabled) m_gammaCursor = calculateGammaCursor(); break; case WhiteCursor: m_whiteCursor = xMinusMargin; m_grabCursor = closest_cursor; if (m_inverted) { m_leftmost = 0; m_rightmost = m_blackCursor - 1; } else { m_leftmost = m_blackCursor + 1; m_rightmost = width() - 2 * MARGIN - 1; } if (m_gammaEnabled) m_gammaCursor = calculateGammaCursor(); break; case GammaCursor: m_gammaCursor = x; m_grabCursor = closest_cursor; m_leftmost = qMin(m_blackCursor, m_whiteCursor); m_rightmost = qMax(m_blackCursor, m_whiteCursor); { double delta = (double)(m_whiteCursor - m_blackCursor) / 2.0; double mid = (double)m_blackCursor + delta + MARGIN; double tmp = (xMinusMargin - mid) / delta; m_gamma = 1.0 / pow(10, tmp); } break; default: break; } update(); } void KisGradientSlider::mouseReleaseEvent(QMouseEvent * e) { if (e->button() != Qt::LeftButton) return; update(); switch (m_grabCursor) { case BlackCursor: m_black = qRound(m_blackCursor / m_scalingFactor); m_feedback = true; emit sigModifiedBlack(m_black); break; case WhiteCursor: m_white = qRound(m_whiteCursor / m_scalingFactor); m_feedback = true; emit sigModifiedWhite(m_white); break; case GammaCursor: emit sigModifiedGamma(m_gamma); break; default: break; } m_grabCursor = None; m_feedback = false; } void KisGradientSlider::mouseMoveEvent(QMouseEvent * e) { int x = e->pos().x(); int xMinusMargin = x - MARGIN; if (m_grabCursor != None) { // Else, drag the selected point if (xMinusMargin <= m_leftmost) xMinusMargin = m_leftmost; if (xMinusMargin >= m_rightmost) xMinusMargin = m_rightmost; switch (m_grabCursor) { case BlackCursor: if (m_blackCursor != xMinusMargin) { m_blackCursor = xMinusMargin; if (m_gammaEnabled) { m_gammaCursor = calculateGammaCursor(); } } break; case WhiteCursor: if (m_whiteCursor != xMinusMargin) { m_whiteCursor = xMinusMargin; if (m_gammaEnabled) { m_gammaCursor = calculateGammaCursor(); } } break; case GammaCursor: if (m_gammaCursor != xMinusMargin) { m_gammaCursor = xMinusMargin; double delta = (double)(m_whiteCursor - m_blackCursor) / 2.0; double mid = (double)m_blackCursor + delta; double tmp = (xMinusMargin - mid) / delta; m_gamma = 1.0 / pow(10, tmp); } break; default: break; } } update(); } void KisGradientSlider::calculateCursorPositions() { m_blackCursor = qRound(m_black * m_scalingFactor); m_whiteCursor = qRound(m_white * m_scalingFactor); m_gammaCursor = calculateGammaCursor(); } unsigned int KisGradientSlider::calculateGammaCursor() { double delta = (double)(m_whiteCursor - m_blackCursor) / 2.0; double mid = (double)m_blackCursor + delta; double tmp = log10(1.0 / m_gamma); return (unsigned int)qRound(mid + delta * tmp); } void KisGradientSlider::enableGamma(bool b) { m_gammaEnabled = b; update(); } double KisGradientSlider::getGamma(void) { return m_gamma; } void KisGradientSlider::enableWhite(bool b) { m_whiteEnabled = b; update(); } void KisGradientSlider::setInverted(bool b) { m_inverted = b; update(); } void KisGradientSlider::slotModifyBlack(int v) { if ((m_inverted && (v < m_white || v > width())) || (!m_inverted && (v < 0 || v > m_white)) || m_feedback) return; m_black = v; m_blackCursor = qRound(m_black * m_scalingFactor); m_gammaCursor = calculateGammaCursor(); update(); } void KisGradientSlider::slotModifyWhite(int v) { if ((m_inverted && (v < 0 || v > m_white)) || (!m_inverted && (v < m_black && v > width())) || m_feedback) return; m_white = v; m_whiteCursor = qRound(m_white * m_scalingFactor); m_gammaCursor = calculateGammaCursor(); update(); } void KisGradientSlider::slotModifyGamma(double v) { if (m_gamma != v) { emit sigModifiedGamma(v); } m_gamma = v; m_gammaCursor = calculateGammaCursor(); update(); } diff --git a/libs/widgets/KoConfigAuthorPage.cpp b/libs/widgets/KoConfigAuthorPage.cpp index 5485cefe47..6d5d7a5d9a 100644 --- a/libs/widgets/KoConfigAuthorPage.cpp +++ b/libs/widgets/KoConfigAuthorPage.cpp @@ -1,443 +1,443 @@ /* This file is part of the KDE project Copyright (c) 2000 Simon Hausmann 2006 Martin Pfeiffer 2012 C. Boemann 2017 Wolthera van Hövell tot Westerflier 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 "KoConfigAuthorPage.h" #include "ui_KoConfigAuthorPage.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 class Q_DECL_HIDDEN KoConfigAuthorPage::Private { public: QList profileUiList; QStackedWidget *stack; QComboBox *cmbAuthorProfiles; QToolButton *bnDeleteUser; QStringList positions; QStringList contactModes; QStringList contactKeys; QString defaultAuthor; }; KoConfigAuthorPage::KoConfigAuthorPage() : d(new Private) { QGridLayout *layout = new QGridLayout; d->cmbAuthorProfiles = new QComboBox(); layout->addWidget(d->cmbAuthorProfiles, 0, 0); QToolButton *newUser = new QToolButton(); newUser->setIcon(koIcon("list-add")); newUser->setToolTip(i18n("Add new author profile (starts out as a copy of current)")); layout->addWidget(newUser, 0, 1); d->bnDeleteUser = new QToolButton(); d->bnDeleteUser->setIcon(koIcon("trash-empty")); d->bnDeleteUser->setToolTip(i18n("Delete the author profile")); layout->addWidget(d->bnDeleteUser, 0, 2); QFrame *f = new QFrame(); f->setFrameStyle(QFrame::HLine | QFrame::Sunken); layout->addWidget(f, 1, 0); d->stack = new QStackedWidget(); layout->addWidget(d->stack, 2, 0, 1, 3); setLayout(layout); //list of positions that we can use to provide useful autocompletion. d->positions << QString(i18nc("This is a list of suggestions for positions an artist can take, comma-separated","Adapter,Animator,Artist,Art Director,Author,Assistant," "Editor,Background,Cartoonist,Colorist,Concept Artist," "Corrector,Cover Artist,Creator,Designer,Inker," "Letterer,Matte Painter,Painter,Penciller,Proofreader," "Pixel Artist,Redliner,Sprite Artist,Typographer,Texture Artist," "Translator,Writer,Other")).split(","); //Keep these two in sync! d->contactModes << i18n("Homepage") << i18n("Email") << i18n("Post Address") << i18n("Telephone") << i18n("Fax"); d->contactKeys << "homepage" << "email" << "address" << "telephone" << "fax"; QStringList headerlabels; headerlabels<< i18n("Type") << i18n("Entry"); Ui::KoConfigAuthorPage *aUi = new Ui::KoConfigAuthorPage(); QWidget *w = new QWidget; d->defaultAuthor = i18n("Anonymous"); QStringList profilesNew; QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/"); QStringList filters = QStringList() << "*.authorinfo"; Q_FOREACH(const QString &entry, dir.entryList(filters)) { QFile file(dir.absoluteFilePath(entry)); if (file.exists()) { file.open(QFile::ReadOnly); QByteArray ba = file.readAll(); file.close(); QDomDocument doc = QDomDocument(); doc.setContent(ba); QDomElement root = doc.firstChildElement(); aUi = new Ui::KoConfigAuthorPage(); w = new QWidget; aUi->setupUi(w); QString profile = root.attribute("name"); QDomElement el = root.firstChildElement("nickname"); if (!el.isNull()) { aUi->leNickName->setText(el.text()); } el = root.firstChildElement("givenname"); if (!el.isNull()) { aUi->leFirstName->setText(el.text()); } el = root.firstChildElement("middlename"); if (!el.isNull()) { aUi->leInitials->setText(el.text()); } el = root.firstChildElement("familyname"); if (!el.isNull()) { aUi->leLastName->setText(el.text()); } el = root.firstChildElement("title"); if (!el.isNull()) { aUi->leTitle->setText(el.text()); } el = root.firstChildElement("position"); if (!el.isNull()) { aUi->lePosition->setText(el.text()); } el = root.firstChildElement("company"); if (!el.isNull()) { aUi->leCompany->setText(el.text()); } aUi->tblContactInfo->setItemDelegate(new KoContactInfoDelegate(this, d->contactModes)); QStandardItemModel *modes = new QStandardItemModel(); aUi->tblContactInfo->setModel(modes); el = root.firstChildElement("contact"); while (!el.isNull()) { QList list; QString type = d->contactModes.at(d->contactKeys.indexOf(el.attribute("type"))); list.append(new QStandardItem(type)); list.append(new QStandardItem(el.text())); modes->appendRow(list); el = el.nextSiblingElement("contact"); } modes->setHorizontalHeaderLabels(headerlabels); QCompleter *positionSuggestions = new QCompleter(d->positions); positionSuggestions->setCaseSensitivity(Qt::CaseInsensitive); aUi->lePosition->setCompleter(positionSuggestions); connect(aUi->btnAdd, SIGNAL(clicked()), this, SLOT(addContactEntry())); connect(aUi->btnRemove, SIGNAL(clicked()), this, SLOT(removeContactEntry())); d->cmbAuthorProfiles->addItem(profile); profilesNew.append(profile); d->profileUiList.append(aUi); d->stack->addWidget(w); } } // Add all the user defined profiles (old type) KConfig *config = KoGlobal::calligraConfig(); KConfigGroup authorGroup(config, "Author"); QStringList profiles = authorGroup.readEntry("profile-names", QStringList()); foreach (const QString &profile , profiles) { if (!profilesNew.contains(profile)) { KConfigGroup cgs(&authorGroup, "Author-" + profile); aUi = new Ui::KoConfigAuthorPage(); w = new QWidget; aUi->setupUi(w); aUi->leNickName->setText(cgs.readEntry("creator")); aUi->leFirstName->setText(cgs.readEntry("creator-first-name")); aUi->leLastName->setText(cgs.readEntry("creator-last-name")); aUi->leInitials->setText(cgs.readEntry("initial")); aUi->leTitle->setText(cgs.readEntry("author-title")); aUi->lePosition->setText(cgs.readEntry("position")); QCompleter *positionSuggestions = new QCompleter(d->positions); positionSuggestions->setCaseSensitivity(Qt::CaseInsensitive); aUi->lePosition->setCompleter(positionSuggestions); aUi->leCompany->setText(cgs.readEntry("company")); aUi->tblContactInfo->setItemDelegate(new KoContactInfoDelegate(this, d->contactModes)); QStandardItemModel *modes = new QStandardItemModel(); aUi->tblContactInfo->setModel(modes); if (cgs.hasKey("email")) { QList list; QString email = d->contactModes.at(d->contactKeys.indexOf("email")); list.append(new QStandardItem(email)); list.append(new QStandardItem(cgs.readEntry("email"))); modes->appendRow(list); } if (cgs.hasKey("telephone-work")) { QList list; QString tel = d->contactModes.at(d->contactKeys.indexOf("telephone")); list.append(new QStandardItem(tel)); list.append(new QStandardItem(cgs.readEntry("telephone-work"))); modes->appendRow(list); } if (cgs.hasKey("fax")) { QList list; QString fax = d->contactModes.at(d->contactKeys.indexOf("fax")); list.append(new QStandardItem(fax)); list.append(new QStandardItem(cgs.readEntry("fax"))); modes->appendRow(list); } QStringList postal; postal << cgs.readEntry("street") << cgs.readEntry("postal-code") << cgs.readEntry("city") << cgs.readEntry("country"); QString address; Q_FOREACH(QString part, postal) { if (!part.isEmpty()) { address+= part + "\n"; } } if (!address.isEmpty()) { QList list; QString add = d->contactModes.at(d->contactKeys.indexOf("address")); list.append(new QStandardItem(add)); list.append(new QStandardItem(address)); modes->appendRow(list); } modes->setHorizontalHeaderLabels(headerlabels); connect(aUi->btnAdd, SIGNAL(clicked()), this, SLOT(addContactEntry())); connect(aUi->btnRemove, SIGNAL(clicked()), this, SLOT(removeContactEntry())); d->cmbAuthorProfiles->addItem(profile); d->profileUiList.append(aUi); d->stack->addWidget(w); } } // Add a default profile aUi = new Ui::KoConfigAuthorPage(); w = new QWidget; if (!profiles.contains(d->defaultAuthor) || profilesNew.contains(d->defaultAuthor)) { //w->setEnabled(false); aUi->setupUi(w); w->setEnabled(false); d->cmbAuthorProfiles->insertItem(0, d->defaultAuthor); d->stack->insertWidget(0, w); d->profileUiList.insert(0, aUi); } // Connect slots connect(d->cmbAuthorProfiles, SIGNAL(currentIndexChanged(int)), this, SLOT(profileChanged(int))); connect(newUser, SIGNAL(clicked(bool)), this, SLOT(addUser())); connect(d->bnDeleteUser, SIGNAL(clicked(bool)), this, SLOT(deleteUser())); d->cmbAuthorProfiles->setCurrentIndex(0); profileChanged(0); } KoConfigAuthorPage::~KoConfigAuthorPage() { delete d; } void KoConfigAuthorPage::profileChanged(int i) { d->stack->setCurrentIndex(i); // Profile 0 should never be deleted: it's the anonymous profile. d->bnDeleteUser->setEnabled(i > 0); } void KoConfigAuthorPage::addUser() { bool ok; QString profileName = QInputDialog::getText(this, i18n("Name of Profile"), i18n("Name (not duplicate or blank name):"), QLineEdit::Normal, "", &ok); if (!ok) { return; } Ui::KoConfigAuthorPage *curUi = d->profileUiList[d->cmbAuthorProfiles->currentIndex()]; Ui::KoConfigAuthorPage *aUi = new Ui::KoConfigAuthorPage(); QWidget *w = new QWidget; aUi->setupUi(w); aUi->leNickName->setText(curUi->leNickName->text()); aUi->leInitials->setText(curUi->leInitials->text()); aUi->leTitle->setText(curUi->leTitle->text()); aUi->leCompany->setText(curUi->leCompany->text()); aUi->leFirstName->setText(curUi->leFirstName->text()); aUi->leLastName->setText(curUi->leLastName->text()); aUi->lePosition->setText(curUi->lePosition->text()); QCompleter *positionSuggestions = new QCompleter(d->positions); positionSuggestions->setCaseSensitivity(Qt::CaseInsensitive); aUi->lePosition->setCompleter(positionSuggestions); aUi->tblContactInfo->setItemDelegate(new KoContactInfoDelegate(this, d->contactModes)); QStandardItemModel *modes = new QStandardItemModel(); aUi->tblContactInfo->setModel(modes); connect(aUi->btnAdd, SIGNAL(clicked()), this, SLOT(addContactEntry())); connect(aUi->btnRemove, SIGNAL(clicked()), this, SLOT(removeContactEntry())); int index = d->cmbAuthorProfiles->currentIndex() + 1; d->cmbAuthorProfiles->insertItem(index, profileName); d->profileUiList.insert(index, aUi); d->stack->insertWidget(index, w); d->cmbAuthorProfiles->setCurrentIndex(index); } void KoConfigAuthorPage::deleteUser() { int index = d->cmbAuthorProfiles->currentIndex(); QWidget *w = d->stack->currentWidget(); d->stack->removeWidget(w); d->profileUiList.removeAt(index); d->cmbAuthorProfiles->removeItem(index); delete w; } void KoConfigAuthorPage::addContactEntry() { int i = d->cmbAuthorProfiles->currentIndex(); Ui::KoConfigAuthorPage *aUi = d->profileUiList[i]; QStandardItemModel *contact = static_cast(aUi->tblContactInfo->model()); QListlist; list.append(new QStandardItem(d->contactModes.at(0))); list.append(new QStandardItem(i18n("New Contact Info"))); contact->appendRow(list); aUi->tblContactInfo->setModel(contact); } void KoConfigAuthorPage::removeContactEntry() { int i = d->cmbAuthorProfiles->currentIndex(); Ui::KoConfigAuthorPage *aUi = d->profileUiList[i]; QModelIndex index = aUi->tblContactInfo->selectionModel()->currentIndex(); aUi->tblContactInfo->model()->removeRow(index.row()); } void KoConfigAuthorPage::apply() { QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/"; QDir dir(authorInfo); if (!dir.mkpath(authorInfo)) { qWarning()<<"We can't make an author info directory, and therefore not save!"; return; } for (int i = 0; i < d->profileUiList.size(); i++) { if (d->cmbAuthorProfiles->itemText(i)!= d->defaultAuthor) { QByteArray ba; QDomDocument doc = QDomDocument(); Ui::KoConfigAuthorPage *aUi = d->profileUiList[i]; QDomElement root = doc.createElement("author"); root.setAttribute("name", d->cmbAuthorProfiles->itemText(i)); QDomElement nickname = doc.createElement("nickname"); nickname.appendChild(doc.createTextNode(aUi->leNickName->text())); root.appendChild(nickname); QDomElement givenname = doc.createElement("givenname"); givenname.appendChild(doc.createTextNode(aUi->leFirstName->text())); root.appendChild(givenname); QDomElement familyname = doc.createElement("familyname"); familyname.appendChild(doc.createTextNode(aUi->leLastName->text())); root.appendChild(familyname); QDomElement middlename = doc.createElement("middlename"); middlename.appendChild(doc.createTextNode(aUi->leInitials->text())); root.appendChild(middlename); QDomElement title = doc.createElement("title"); title.appendChild(doc.createTextNode(aUi->leTitle->text())); root.appendChild(title); QDomElement company = doc.createElement("company"); company.appendChild(doc.createTextNode(aUi->leCompany->text())); root.appendChild(company); QDomElement position = doc.createElement("position"); position.appendChild(doc.createTextNode(aUi->lePosition->text())); root.appendChild(position); if (aUi->tblContactInfo) { if (aUi->tblContactInfo->model()) { for (int i=0; itblContactInfo->model()->rowCount(); i++) { QModelIndex index = aUi->tblContactInfo->model()->index(i, 1); QModelIndex typeIndex = aUi->tblContactInfo->model()->index(i, 0); QDomElement contactEl = doc.createElement("contact"); QString content = QVariant(aUi->tblContactInfo->model()->data(index)).toString(); contactEl.appendChild(doc.createTextNode(content)); QString type = QVariant(aUi->tblContactInfo->model()->data(typeIndex)).toString(); contactEl.setAttribute("type", d->contactKeys.at(d->contactModes.indexOf(type))); root.appendChild(contactEl); } } } doc.appendChild(root); ba = doc.toByteArray(); QFile f(authorInfo + d->cmbAuthorProfiles->itemText(i) +".authorinfo"); f.open(QFile::WriteOnly); if (f.write(ba) < 0) { qWarning()<<"Writing author info went wrong:"< 0) { return new QLineEdit(parent); } else { QComboBox *box = new QComboBox(parent); box->addItems(m_contactModes); return box; } } diff --git a/libs/widgetutils/KoUpdater.cpp b/libs/widgetutils/KoUpdater.cpp index 49c8f1e2f7..30fbd3aa1d 100644 --- a/libs/widgetutils/KoUpdater.cpp +++ b/libs/widgetutils/KoUpdater.cpp @@ -1,116 +1,116 @@ /* This file is part of the KDE project * * Copyright (C) 2006-2007 Thomas Zander * Copyright (C) 2009 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 "KoUpdater.h" #include "KoUpdaterPrivate_p.h" KoUpdater::KoUpdater(KoUpdaterPrivate *_d) : m_progressPercent(0) { d = _d; Q_ASSERT(!d.isNull()); connect(this, SIGNAL(sigCancel()), d, SLOT(cancel())); connect(this, SIGNAL(sigProgress(int)), d, SLOT(setProgress(int))); connect(this, SIGNAL(sigNestedNameChanged(QString)), d, SLOT(setAutoNestedName(QString))); connect(this, SIGNAL(sigHasValidRangeChanged(bool)), d, SLOT(setHasValidRange(bool))); connect(d, SIGNAL(sigInterrupted(bool)), this, SLOT(setInterrupted(bool))); setRange(0, 100); m_interrupted = false; } KoUpdater::~KoUpdater() { } void KoUpdater::cancel() { emit sigCancel(); } void KoUpdater::setProgress(int percent) { m_progressPercent = percent; emit sigProgress( percent ); } int KoUpdater::progress() const { return m_progressPercent; } bool KoUpdater::interrupted() const { return m_interrupted; } int KoUpdater::maximum() const { return 100; } void KoUpdater::setValue( int value ) { value = qBound(min, value, max); // Go from range to percent const int range = max - min; if (range == 0) { m_progressPercent = max; emit sigProgress(max); } else { setProgress((100 * (value - min)) / (max - min)); } } void KoUpdater::setRange( int minimum, int maximum ) { min = minimum; max = maximum; range = max - min; emit sigHasValidRangeChanged(range != 0); } void KoUpdater::setFormat( const QString & format ) { emit sigNestedNameChanged(format); } void KoUpdater::setAutoNestedName(const QString &name) { emit sigNestedNameChanged(name); } void KoUpdater::setInterrupted(bool value) { - m_interrupted = true; + m_interrupted = value; } KoDummyUpdater::KoDummyUpdater() : KoUpdater(new KoUpdaterPrivate(0, 0, "dummy")) { } diff --git a/plugins/dockers/animation/kis_animation_utils.cpp b/plugins/dockers/animation/kis_animation_utils.cpp index 1e48595e33..82979e9b83 100644 --- a/plugins/dockers/animation/kis_animation_utils.cpp +++ b/plugins/dockers/animation/kis_animation_utils.cpp @@ -1,267 +1,267 @@ /* * 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 "kis_animation_utils.h" #include "kundo2command.h" #include "kis_algebra_2d.h" #include "kis_image.h" #include "kis_node.h" #include "kis_keyframe_channel.h" #include "kis_post_execution_undo_adapter.h" #include "kis_global.h" #include "kis_tool_utils.h" #include "kis_image_animation_interface.h" #include "kis_command_utils.h" #include "kis_processing_applicator.h" #include "kis_transaction.h" namespace KisAnimationUtils { const QString addFrameActionName = i18n("New Frame"); const QString duplicateFrameActionName = i18n("Copy Frame"); const QString removeFrameActionName = i18n("Remove Frame"); const QString removeFramesActionName = i18n("Remove Frames"); const QString lazyFrameCreationActionName = i18n("Auto Frame Mode"); const QString dropFramesActionName = i18n("Drop Frames"); const QString showLayerActionName = i18n("Show in Timeline"); const QString newLayerActionName = i18n("New Layer"); const QString addExistingLayerActionName = i18n("Add Existing Layer"); const QString removeLayerActionName = i18n("Remove Layer"); const QString addOpacityKeyframeActionName = i18n("Add opacity keyframe"); const QString addTransformKeyframeActionName = i18n("Add transform keyframe"); const QString removeOpacityKeyframeActionName = i18n("Remove opacity keyframe"); const QString removeTransformKeyframeActionName = i18n("Remove transform keyframe"); void createKeyframeLazy(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy) { KIS_SAFE_ASSERT_RECOVER_RETURN(!image->locked()); KUndo2Command *cmd = new KisCommandUtils::LambdaCommand( copy ? kundo2_i18n("Copy Keyframe") : kundo2_i18n("Add Keyframe"), [image, node, channelId, time, copy] () mutable -> KUndo2Command* { bool result = false; QScopedPointer cmd(new KUndo2Command()); KisKeyframeChannel *channel = node->getKeyframeChannel(channelId); bool createdChannel = false; if (!channel) { node->enableAnimation(); channel = node->getKeyframeChannel(channelId, true); if (!channel) return nullptr; createdChannel = true; } if (copy) { if (!channel->keyframeAt(time)) { KisKeyframeSP srcFrame = channel->activeKeyframeAt(time); channel->copyKeyframe(srcFrame, time, cmd.data()); result = true; } } else { if (channel->keyframeAt(time) && !createdChannel) { if (image->animationInterface()->currentTime() == time && channelId == KisKeyframeChannel::Content.id()) { //shortcut: clearing the image instead KisPaintDeviceSP device = node->paintDevice(); if (device) { KisTransaction transaction(kundo2_i18n("Clear"), device, cmd.data()); device->clear(); (void) transaction.endAndTake(); // saved as 'parent' result = true; } } } else { channel->addKeyframe(time, cmd.data()); result = true; } } return result ? new KisCommandUtils::SkipFirstRedoWrapper(cmd.take()) : nullptr; }); KisProcessingApplicator::runSingleCommandStroke(image, cmd, KisStrokeJobData::BARRIER); } void removeKeyframes(KisImageSP image, const FrameItemList &frames) { KIS_SAFE_ASSERT_RECOVER_RETURN(!image->locked()); KUndo2Command *cmd = new KisCommandUtils::LambdaCommand( kundo2_i18np("Remove Keyframe", "Remove Keyframes", frames.size()), [image, frames] () { bool result = false; QScopedPointer cmd(new KUndo2Command()); Q_FOREACH (const FrameItem &item, frames) { const int time = item.time; KisNodeSP node = item.node; - KisKeyframeChannel *channel; + KisKeyframeChannel *channel = 0; if (node) { channel = node->getKeyframeChannel(item.channel); } if (!channel) continue; KisKeyframeSP keyframe = channel->keyframeAt(time); if (!keyframe) continue; channel->deleteKeyframe(keyframe, cmd.data()); result = true; } return result ? new KisCommandUtils::SkipFirstRedoWrapper(cmd.take()) : 0; }); KisProcessingApplicator::runSingleCommandStroke(image, cmd, KisStrokeJobData::BARRIER); } void removeKeyframe(KisImageSP image, KisNodeSP node, const QString &channel, int time) { QVector frames; frames << FrameItem(node, channel, time); removeKeyframes(image, frames); } struct LessOperator { LessOperator(const QPoint &offset) : m_columnCoeff(-KisAlgebra2D::signPZ(offset.x())), m_rowCoeff(-1000000 * KisAlgebra2D::signZZ(offset.y())) { } bool operator()(const QModelIndex &lhs, const QModelIndex &rhs) { return m_columnCoeff * lhs.column() + m_rowCoeff * lhs.row() < m_columnCoeff * rhs.column() + m_rowCoeff * rhs.row(); } private: int m_columnCoeff; int m_rowCoeff; }; void sortPointsForSafeMove(QModelIndexList *points, const QPoint &offset) { std::sort(points->begin(), points->end(), LessOperator(offset)); } KUndo2Command* createMoveKeyframesCommand(const FrameItemList &srcFrames, const FrameItemList &dstFrames, bool copy, KUndo2Command *parentCommand) { KUndo2Command *cmd = new KisCommandUtils::LambdaCommand( !copy ? kundo2_i18np("Move Keyframe", "Move %1 Keyframes", srcFrames.size()) : kundo2_i18np("Copy Keyframe", "Copy %1 Keyframes", srcFrames.size()), parentCommand, [srcFrames, dstFrames, copy] () -> KUndo2Command* { bool result = false; QScopedPointer cmd(new KUndo2Command()); for (int i = 0; i < srcFrames.size(); i++) { const int srcTime = srcFrames[i].time; KisNodeSP srcNode = srcFrames[i].node; KisKeyframeChannel *srcChannel = srcNode->getKeyframeChannel(srcFrames[i].channel); const int dstTime = dstFrames[i].time; KisNodeSP dstNode = dstFrames[i].node; KisKeyframeChannel *dstChannel = dstNode->getKeyframeChannel(dstFrames[i].channel, true); if (srcNode == dstNode) { if (!srcChannel) continue; KisKeyframeSP srcKeyframe = srcChannel->keyframeAt(srcTime); if (srcKeyframe) { if (copy) { srcChannel->copyKeyframe(srcKeyframe, dstTime, cmd.data()); } else { srcChannel->moveKeyframe(srcKeyframe, dstTime, cmd.data()); } } } else { if (!srcChannel|| !dstChannel) continue; KisKeyframeSP srcKeyframe = srcChannel->keyframeAt(srcTime); if (!srcKeyframe) continue; dstChannel->copyExternalKeyframe(srcChannel, srcTime, dstTime, cmd.data()); if (!copy) { srcChannel->deleteKeyframe(srcKeyframe, cmd.data()); } } result = true; } return result ? new KisCommandUtils::SkipFirstRedoWrapper(cmd.take()) : 0; }); return cmd; } void moveKeyframes(KisImageSP image, const FrameItemList &srcFrames, const FrameItemList &dstFrames, bool copy) { KIS_SAFE_ASSERT_RECOVER_RETURN(srcFrames.size() != dstFrames.size()); KIS_SAFE_ASSERT_RECOVER_RETURN(!image->locked()); KUndo2Command *cmd = createMoveKeyframesCommand(srcFrames, dstFrames, copy); KisProcessingApplicator::runSingleCommandStroke(image, cmd, KisStrokeJobData::BARRIER); } void moveKeyframe(KisImageSP image, KisNodeSP node, const QString &channel, int srcTime, int dstTime) { QVector srcFrames; srcFrames << FrameItem(node, channel, srcTime); QVector dstFrames; dstFrames << FrameItem(node, channel, dstTime); moveKeyframes(image, srcFrames, dstFrames); } bool supportsContentFrames(KisNodeSP node) { return node->inherits("KisPaintLayer") || node->inherits("KisFilterMask") || node->inherits("KisTransparencyMask") || node->inherits("KisSelectionBasedLayer"); } } diff --git a/plugins/dockers/colorslider/kis_color_slider_input.cpp b/plugins/dockers/colorslider/kis_color_slider_input.cpp index 4e76de0adb..ede1f1e653 100644 --- a/plugins/dockers/colorslider/kis_color_slider_input.cpp +++ b/plugins/dockers/colorslider/kis_color_slider_input.cpp @@ -1,712 +1,709 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2014 Wolthera van Hövell * Copyright (c) 2015 Moritz Molch * * 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 "kis_color_slider_input.h" #include #ifdef HAVE_OPENEXR #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "kis_hsv_slider.h" #include "kis_display_color_converter.h" #include "kis_double_parse_spin_box.h" KisColorSliderInput::KisColorSliderInput(QWidget* parent, KoColor* color, const int type, KoColorDisplayRendererInterface *displayRenderer, KisCanvas2* canvas) : QWidget(parent), m_type(type), m_color(color), m_displayRenderer(displayRenderer), m_canvas(canvas) { //init } void KisColorSliderInput::init() { QHBoxLayout* m_layout = new QHBoxLayout(this); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(1); QString m_name; switch (m_type){ case 0: m_name=i18n("Hue"); break; case 1: m_name=i18n("Saturation"); break; case 2: m_name=i18n("Value"); break; case 3: m_name=i18n("Hue"); break; case 4: m_name=i18n("Saturation"); break; case 5: m_name=i18n("Lightness"); break; case 6: m_name=i18n("Hue"); break; case 7: m_name=i18n("Saturation"); break; case 8: m_name=i18n("Intensity"); break; case 9: m_name=i18n("Hue"); break; case 10: m_name=i18n("Saturation"); break; case 11: m_name=i18n("Luma"); break; } - + QLabel* m_label = new QLabel(i18n("%1:", m_name), this); m_layout->addWidget(m_label); m_hsvSlider = new KisHSVSlider(Qt::Horizontal, this, m_displayRenderer, m_canvas); m_hsvSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_layout->addWidget(m_hsvSlider); connect (m_hsvSlider, SIGNAL(sliderPressed()), SLOT(sliderIn())); connect (m_hsvSlider, SIGNAL(sliderReleased()), SLOT(sliderOut())); QWidget* m_input = createInput(); m_hsvSlider->setFixedHeight(m_input->sizeHint().height()); m_layout->addWidget(m_input); } KisHSXColorSliderInput::KisHSXColorSliderInput(QWidget* parent, const int type, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, KisCanvas2* canvas) : KisColorSliderInput(parent, color, type, displayRenderer, canvas), m_canvas(canvas), m_hue(0), m_sat(0), m_val(0), R(0), G(0), B(0), Gamma(0) { m_hueupdating = false; m_satupdating = false; m_toneupdating = false; m_sliderisupdating = false; init(); } void KisHSXColorSliderInput::setValue(double v) { //This function returns the colour based on the type of the slider as well as the value// qreal h=0.0; qreal s=0.0; qreal l=0.0; KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); R = cfg.readEntry("lumaR", 0.2126); G = cfg.readEntry("lumaG", 0.7152); B = cfg.readEntry("lumaB", 0.0722); Gamma = cfg.readEntry("gamma", 2.2); switch (m_type) { case 0: m_hue = v; h=m_hue/360.0; s=m_sat/100.0; l=m_val/100.0; *m_color = this->converter()->fromHsvF(h, s, l); if (m_hueupdating==false) { emit(hueUpdated(static_cast(m_hue))); } else { m_hueupdating=false; } break; case 3: m_hue = v; h=m_hue/360.0; s=m_sat/100.0; l=m_val/100.0; *m_color = this->converter()->fromHslF(h, s, l); if (m_hueupdating==false) { emit(hueUpdated(static_cast(m_hue))); } else { m_hueupdating=false; } break; case 6: m_hue = v; h=m_hue/360.0; s=m_sat/100.0; l=m_val/100.0; *m_color = this->converter()->fromHsiF(h, s, l); if (m_hueupdating==false) { emit(hueUpdated(static_cast(m_hue))); } else { m_hueupdating=false; } break; case 9: m_hue = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsyF(h, s, l, R, G, B, Gamma); if (m_hueupdating==false) { emit(hueUpdated(static_cast(m_hue))); } else { m_hueupdating=false; } break; case 1: m_sat = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsvF(h, s, l); if (m_satupdating==false) { emit(satUpdated(static_cast(m_sat), m_type)); } else { m_satupdating=false; } break; case 2: m_val = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsvF(h, s, l); if (m_toneupdating==false) { emit(toneUpdated(static_cast(m_val), m_type)); } else { m_toneupdating=false; } break; case 4: m_sat = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHslF(h, s, l); if (m_satupdating==false) { emit(satUpdated(static_cast(m_sat), m_type)); } else { m_satupdating=false; } break; case 5: m_val = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHslF(h, s, l); if (m_toneupdating==false) { emit(toneUpdated(static_cast(m_val), m_type)); } else { m_toneupdating=false; } break; case 7: m_sat = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsiF(h, s, l); if (m_satupdating==false) { emit(satUpdated(static_cast(m_sat), m_type)); } else { m_satupdating=false; } break; case 8: m_val = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsiF(h, s, l); if (m_toneupdating==false) { emit(toneUpdated(static_cast(m_val), m_type)); } else { m_toneupdating=false; } break; case 10: m_sat = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsyF(h, s, l, R, G, B, Gamma); if (m_satupdating==false) { emit(satUpdated(static_cast(m_sat), m_type)); } else { m_satupdating=false; } break; case 11: m_val = v; h=m_hue/360.0f; s=m_sat/100.0f; l=m_val/100.0f; *m_color = this->converter()->fromHsyF(h, s, l, R, G, B, Gamma); if (m_toneupdating==false) { emit(toneUpdated(static_cast(m_val), m_type)); } else { m_toneupdating=false; } break; default: Q_ASSERT(false); } emit(updated()); } //update void KisHSXColorSliderInput::update() { - - KoColor min = *m_color; - KoColor max = *m_color; - - qreal hue, sat, val, hue_backup, sat_backup, val_backup; + +// KoColor min = *m_color; +// KoColor max = *m_color; + + qreal hue = 0.0; + qreal sat = 0.0; + qreal val = 0.0; + qreal hue_backup, sat_backup, val_backup; //gets the hsv for the appropriate type// hue_backup = m_hue; sat_backup = m_sat; val_backup = m_val; - + switch (m_type) { case 0: this->converter()->getHsvF(*m_color, &hue, &sat, &val); - if (m_sliderisupdating==true) - { - if((sat*100.0)m_sat-2) { - sat = (sat_backup*0.01); + if (m_sliderisupdating) { + if ((sat * 100.0) < m_sat + 2 && (sat * 100.0) > m_sat - 2) { + sat = (sat_backup * 0.01); } - if((val*100.0)m_val-2) { + if ((val * 100.0) < m_val + 2 && (val * 100.0) > m_val - 2) { val = (val_backup*0.01); } - - + } - else{ - if((hue*360.0)m_hue-2) { + else { + if((hue * 360.0) < m_hue + 2 && (hue * 360.0) > m_hue - 2) { hue = (hue_backup/360.0); } } break; case 1: this->converter()->getHsvF(*m_color, &hue, &sat, &val); - if (m_sliderisupdating==true) - { - if( (hue*360.0)m_hue-2 ) { + if (m_sliderisupdating) { + if ((hue * 360.0) < m_hue + 2 && (hue * 360.0) > m_hue - 2 ) { hue = (hue_backup/360.0); } - if((val*100.0)m_val-2) { + if ((val * 100.0) < m_val + 2 && (val * 100.0) > m_val - 2) { val = (val_backup*0.01); } - - } - else{ - - if((sat*100.0)m_sat-2) { + else { + if ((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } } break; case 2: this->converter()->getHsvF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } else{ if((val*100.0)m_val-2) { val = (val_backup*0.01); } } break; case 3: this->converter()->getHslF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } break; case 4: this->converter()->getHslF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ - + if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } } break; case 5: this->converter()->getHslF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } else{ if((val*100.0)m_val-2) { val = (val_backup*0.01); } } break; case 6: this->converter()->getHsiF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } break; case 7: this->converter()->getHsiF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ - + if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } } break; case 8: this->converter()->getHsiF(*m_color, &hue, &sat, &val); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } else{ if((val*100.0)m_val-2) { val = (val_backup*0.01); } } break; case 9: this->converter()->getHsyF(*m_color, &hue, &sat, &val, R, G, B, Gamma); if (m_sliderisupdating==true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } break; case 10: this->converter()->getHsyF(*m_color, &hue, &sat, &val, R, G, B, Gamma); if (m_sliderisupdating==true) { if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } if((val*100.0)m_val-2) { val = (val_backup*0.01); } - - + + } else{ - + if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } } break; case 11: this->converter()->getHsyF(*m_color, &hue, &sat, &val, R, G, B, Gamma); if (m_sliderisupdating == true) { if((sat*100.0)m_sat-2) { sat = (sat_backup*0.01); } if((hue*360.0)m_hue-2) { hue = (hue_backup/360.0); } } else{ if((val*100.0)m_val-2) { val = (val_backup*0.01); } } break; } //this prevents the hue going to 0 when used with grey// - + if (sat<=0.0) { m_hue = hue_backup; } else{ m_hue=(hue*360.0); } - + if (val==0 || val>0.999) { m_sat = sat_backup; } else{ m_sat=(sat*100.0); } - + m_val=(val*100.0); - + if (m_hueupdating==true){m_val=val_backup; m_sat = sat_backup; m_hueupdating=false;} else if (m_satupdating==true){m_val=val_backup; m_hue = hue_backup; m_satupdating=false;} else if (m_toneupdating==true){m_sat=sat_backup; m_hue = hue_backup;m_toneupdating=false;} - + //sets slider and num-input according to type// switch (m_type) { case 0: case 3: case 6: case 9: m_NumInput->setValue(m_hue); m_hsvSlider->setValue(static_cast(m_hue)); break; case 1: m_NumInput->setValue(m_sat); m_hsvSlider->setValue(static_cast(m_sat)); break; case 2: m_NumInput->setValue(m_val); m_hsvSlider->setValue(static_cast(m_val)); break; case 4: m_NumInput->setValue(m_sat); m_hsvSlider->setValue(static_cast(m_sat)); break; case 5: m_NumInput->setValue(m_val); m_hsvSlider->setValue(static_cast(m_val)); break; case 7: m_NumInput->setValue(m_sat); m_hsvSlider->setValue(static_cast(m_sat)); break; case 8: m_NumInput->setValue(m_val); m_hsvSlider->setValue(static_cast(m_val)); break; case 10: m_NumInput->setValue(m_sat); m_hsvSlider->setValue(static_cast(m_sat)); break; case 11: m_NumInput->setValue(m_val); m_hsvSlider->setValue(static_cast(m_val)); break; default: Q_ASSERT(false); } m_hsvSlider->setColors(*m_color,m_type, m_hue, R, G, B, Gamma); } QWidget* KisHSXColorSliderInput::createInput() { m_NumInput = new KisDoubleParseSpinBox(this); m_NumInput->setMinimum(0); m_NumInput->setMaximum(100.0); m_NumInput->setKeyboardTracking(false);//this makes sure that only full values are sent after loss of focus. Much more user friendly// m_hsvSlider->setMaximum(100); switch (m_type) { case 0: case 3: case 6: case 9: m_NumInput->setMaximum(360.0); m_NumInput->setWrapping(true); m_hsvSlider->setMaximum(360); m_NumInput->setSingleStep (5.0); break; case 1: case 2: case 4: case 5: case 7: case 8: case 10: case 11: m_NumInput->setMaximum(100.0); m_hsvSlider->setMaximum(100); m_NumInput->setSingleStep (10.0); break; default: Q_ASSERT(false); } connect(m_hsvSlider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int))); connect(m_NumInput, SIGNAL(valueChanged(double)), this, SLOT(numInputChanged(double))); return m_NumInput; } void KisHSXColorSliderInput::sliderChanged(int i) { m_NumInput->setValue(i*1.0); setValue(i*1.0); } void KisHSXColorSliderInput::sliderIn(){ m_sliderisupdating=true; } void KisHSXColorSliderInput::sliderOut(){ m_sliderisupdating=false; } //attempt at getting rid of dancing sliders... #2859 //The nminput should not be changing the sliders if the sliders are the one changing the input. //As numinpit rounds off at 2 decimals(and there's no point at letting it continue the signal circle). void KisHSXColorSliderInput::numInputChanged(double v) { if (m_sliderisupdating==true){ return; } else { setValue(v); } } //this connects to the display converter. Important for OCIO, breaks on missing of m_canvas somehow. KisDisplayColorConverter* KisHSXColorSliderInput::converter() const { return m_canvas ? m_canvas->displayColorConverter() : KisDisplayColorConverter::dumbConverterInstance(); } void KisHSXColorSliderInput::hueUpdate(int h) { if (h<=m_hue-2 || h>=m_hue+2) { m_hue=h; m_hueupdating=true; update(); } } void KisHSXColorSliderInput::satUpdate(int s, int type) { if (m_type==type+1 || m_type==type-1) { if (s<=m_sat-3 || s>=m_sat+3) { m_sat=s; m_satupdating=true; update(); } } } void KisHSXColorSliderInput::toneUpdate(int l, int type) { if (m_type==type-1 || m_type==type-2) { if (l<25 || l>75){ - + if (l<=m_val-10 || l>=m_val+10) { m_val=l; m_toneupdating=true; update(); } } else { if (l<=m_val-3 || l>=m_val+3) { m_val=l; m_toneupdating=true; update(); } } - - + + } } #include "moc_kis_color_slider_input.cpp" diff --git a/plugins/dockers/colorslider/kis_hsv_slider.cpp b/plugins/dockers/colorslider/kis_hsv_slider.cpp index 9c925e8d18..354eb3eb93 100644 --- a/plugins/dockers/colorslider/kis_hsv_slider.cpp +++ b/plugins/dockers/colorslider/kis_hsv_slider.cpp @@ -1,268 +1,268 @@ /* This file is part of the KDE project Copyright (C) 2006 Sven Langkamp Copyright (c) 2009 Cyrille Berger Copyright (c) 2014 Wolthera van Hövell Copyright (c) 2015 Moritz Molch 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 "kis_hsv_slider.h" #include "KoColorSpace.h" #include #include #include #include #include #include "kis_display_color_converter.h" #define ARROWSIZE 8 struct KisHSVSlider::Private { Private() : upToDate(false), displayRenderer(0) {} KoColor currentColorF; int HSVtype; KoColor minColor; qreal hue_b; QPixmap pixmap; bool upToDate; KoColorDisplayRendererInterface *displayRenderer; }; KisHSVSlider::KisHSVSlider(QWidget* parent, KoColorDisplayRendererInterface *displayRenderer) : KSelector(parent), d(new Private), R(0), G(0), B(0), Gamma(0) { setMaximum(255); d->displayRenderer = displayRenderer; connect(d->displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(update())); } KisHSVSlider::KisHSVSlider(Qt::Orientation o, QWidget *parent, KoColorDisplayRendererInterface *displayRenderer, KisCanvas2* canvas) : KSelector(o, parent), d(new Private), m_canvas(canvas) { setMaximum(255); d->displayRenderer = displayRenderer; connect(d->displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(update())); } KisHSVSlider::~KisHSVSlider() { delete d; } void KisHSVSlider::setColors(const KoColor& currentc, const int type, qreal hue_backup, qreal l_R, qreal l_G, qreal l_B, qreal gamma) { d->currentColorF = currentc; - KoColor c = currentc; +// KoColor c = currentc; d->HSVtype = type; d->hue_b = hue_backup/360.0f; R=l_R; G=l_G; B=l_B; Gamma=gamma; d->upToDate = false; QTimer::singleShot(1, this, SLOT(update())); } void KisHSVSlider::drawContents( QPainter *painter ) { QPixmap checker(8, 8); QPainter p(&checker); p.fillRect(0, 0, 4, 4, Qt::lightGray); p.fillRect(4, 0, 4, 4, Qt::darkGray); p.fillRect(0, 4, 4, 4, Qt::darkGray); p.fillRect(4, 4, 4, 4, Qt::lightGray); p.end(); QRect contentsRect_(contentsRect()); painter->fillRect(contentsRect_, QBrush(checker)); if( !d->upToDate || d->pixmap.isNull() || d->pixmap.width() != contentsRect_.width() || d->pixmap.height() != contentsRect_.height() ) { KoColor c = d->currentColorF; // smart way to fetch colorspace QColor color; int type = d->HSVtype; QImage image(contentsRect_.width(), contentsRect_.height(), QImage::Format_ARGB32 ); if( orientation() == Qt::Horizontal ) { for (int x = 0; x < contentsRect_.width(); x++) { qreal t = static_cast(x) / (contentsRect_.width() - 1); t = 1.0-t; - + //function find current color from hsv thingymabobs. c = HSXcolor(type, t); - + color = d->displayRenderer->toQColor(c); for (int y = 0; y < contentsRect_.height(); y++) image.setPixel(x, y, color.rgba()); } } else { for (int y = 0; y < contentsRect_.height(); y++) { qreal t = static_cast(y) / (contentsRect_.height() - 1); - + c = HSXcolor(type, t); - + color = d->displayRenderer->toQColor(c); for (int x = 0; x < contentsRect_.width(); x++) image.setPixel(x, y, color.rgba()); - } + } } d->pixmap = QPixmap::fromImage(image); d->upToDate = true; } painter->drawPixmap( contentsRect_, d->pixmap, QRect( 0, 0, d->pixmap.width(), d->pixmap.height()) ); } KoColor KisHSVSlider::currentColor() const { KoColor c(d->minColor.colorSpace()); int type = d->HSVtype; qreal t = (value() - minimum()) / qreal(maximum() - minimum()) * 255; c = HSXcolor(type, t); return c; } KoColor KisHSVSlider::HSXcolor(int type, qreal t) const { KoColor coordinate_color(d->currentColorF.colorSpace()); KoColor c = d->currentColorF; qreal hue, sat, val; qreal hue_backup = d->hue_b; switch(type){ case 0: this->converter()->getHsvF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHsvF( (1.0 - t) , sat, val); break;//hsv hue case 1: this->converter()->getHsvF(c, &hue, &sat, &val); if (sat<=0.0 && t<1.0) { hue=hue_backup; } coordinate_color = this->converter()->fromHsvF( hue, (1.0 - t), val); break;//hsv sat case 2: this->converter()->getHsvF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHsvF( hue, sat, (1.0 - t)); break;//hsv value case 3: this->converter()->getHslF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHslF( (1.0 - t) , sat, val); break;//hsl hue case 4: this->converter()->getHslF(c, &hue, &sat, &val); if (sat<=0.0 && t<1.0) { hue=hue_backup; } coordinate_color = this->converter()->fromHslF( hue, (1.0 - t), val); break;//hsl sat case 5: this->converter()->getHslF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHslF( hue, sat, (1.0 - t)); break;//hsl value case 6: this->converter()->getHsiF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHsiF( (1.0 - t) , sat, val); break;//hsi hue case 7: this->converter()->getHsiF(c, &hue, &sat, &val); if (sat<=0.0 && t<1.0) { hue=hue_backup; } coordinate_color = this->converter()->fromHsiF( hue, (1.0 - t), val); break;//hsi sat case 8: this->converter()->getHsiF(c, &hue, &sat, &val); coordinate_color = this->converter()->fromHsiF( hue, sat, (1.0 - t)); break;//hsi value case 9: this->converter()->getHsyF(c, &hue, &sat, &val, R, G, B, Gamma); coordinate_color = this->converter()->fromHsyF( (1.0 - t) , sat, val, R, G, B, Gamma); break;//hsy hue case 10: this->converter()->getHsyF(c, &hue, &sat, &val, R, G, B, Gamma); if (sat==0 && (1.0-t)>0) { hue=hue_backup; } coordinate_color = this->converter()->fromHsyF( hue, (1.0 - t), val, R, G, B, Gamma); break;//hsy sat case 11: this->converter()->getHsyF(c, &hue, &sat, &val, R, G, B, Gamma); coordinate_color = this->converter()->fromHsyF( hue, sat, (1.0 - t), R, G, B, Gamma); break;//hsy value } return coordinate_color; } KisDisplayColorConverter* KisHSVSlider::converter() const { return m_canvas ? m_canvas->displayColorConverter() : KisDisplayColorConverter::dumbConverterInstance(); } void KisHSVSlider::drawArrow(QPainter *painter, const QPoint &pos) { painter->setPen(palette().text().color()); painter->setBrush(palette().text()); QStyleOption o; o.initFrom(this); o.state &= ~QStyle::State_MouseOver; if ( orientation() == Qt::Vertical ) { o.rect = QRect( pos.x(), pos.y() - ARROWSIZE / 2, ARROWSIZE, ARROWSIZE ); } else { o.rect = QRect( pos.x() - ARROWSIZE / 2, pos.y(), ARROWSIZE, ARROWSIZE ); } QStyle::PrimitiveElement arrowPE; switch (arrowDirection()) { case Qt::UpArrow: arrowPE = QStyle::PE_IndicatorArrowUp; break; case Qt::DownArrow: arrowPE = QStyle::PE_IndicatorArrowDown; break; case Qt::RightArrow: arrowPE = QStyle::PE_IndicatorArrowRight; break; case Qt::LeftArrow: default: arrowPE = QStyle::PE_IndicatorArrowLeft; break; } style()->drawPrimitive(arrowPE, &o, painter, this); } diff --git a/plugins/filters/convertheightnormalmap/kis_wdg_convert_height_to_normal_map.cpp b/plugins/filters/convertheightnormalmap/kis_wdg_convert_height_to_normal_map.cpp index 4c84193153..4724ee5210 100644 --- a/plugins/filters/convertheightnormalmap/kis_wdg_convert_height_to_normal_map.cpp +++ b/plugins/filters/convertheightnormalmap/kis_wdg_convert_height_to_normal_map.cpp @@ -1,132 +1,132 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * 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_wdg_convert_height_to_normal_map.h" #include #include #include #include KisWdgConvertHeightToNormalMap::KisWdgConvertHeightToNormalMap(QWidget *parent, const KoColorSpace *cs) : KisConfigWidget(parent), ui(new Ui_WidgetConvertHeightToNormalMap), m_cs(cs) { ui->setupUi(this); m_types << "prewitt"<< "sobol"<< "simple"; m_types_translatable << i18n("Prewitt") << i18n("Sobol") << i18n("Simple"); QStringList swizzle; swizzle<< "X+" << "X-" << "Y+" << "Y-" << "Z+" << "Z-"; ui->cmbType->addItems(m_types_translatable); ui->cmbRed->addItems(swizzle); ui->cmbGreen->addItems(swizzle); ui->cmbBlue->addItems(swizzle); - for (int c = 0; c < m_cs->channelCount(); c++) { + for (int c = 0; c < (int)m_cs->channelCount(); c++) { ui->cmbChannel->addItem(m_cs->channels().at(c)->name()); } ui->btnAspect->setKeepAspectRatio(false); ui->sldHorizontalRadius->setRange(1.0, 100.0, 2); ui->sldHorizontalRadius->setPrefix(i18n("Horizontal Radius:")); connect(ui->sldHorizontalRadius, SIGNAL(valueChanged(qreal)), this, SLOT(horizontalRadiusChanged(qreal))); ui->sldVerticalRadius->setRange(1.0, 100.0, 2); ui->sldVerticalRadius->setPrefix(i18n("Vertical Radius:")); connect(ui->sldVerticalRadius, SIGNAL(valueChanged(qreal)), this, SLOT(verticalRadiusChanged(qreal))); connect(ui->sldHorizontalRadius, SIGNAL(valueChanged(qreal)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->sldVerticalRadius, SIGNAL(valueChanged(qreal)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->btnAspect, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(aspectLockChanged(bool))); connect(ui->cmbType, SIGNAL(currentIndexChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->cmbChannel, SIGNAL(currentIndexChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->cmbRed, SIGNAL(currentIndexChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->cmbGreen, SIGNAL(currentIndexChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); connect(ui->cmbBlue, SIGNAL(currentIndexChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); } KisWdgConvertHeightToNormalMap::~KisWdgConvertHeightToNormalMap() { delete ui; } KisPropertiesConfigurationSP KisWdgConvertHeightToNormalMap::configuration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("height to normal", 1); config->setProperty("horizRadius", ui->sldHorizontalRadius->value()); config->setProperty("vertRadius", ui->sldVerticalRadius->value()); config->setProperty("type", m_types.at(ui->cmbType->currentIndex())); config->setProperty("lockAspect", ui->btnAspect->keepAspectRatio()); config->setProperty("channelToConvert", ui->cmbChannel->currentIndex()); config->setProperty("redSwizzle", ui->cmbRed->currentIndex()); config->setProperty("greenSwizzle", ui->cmbGreen->currentIndex()); config->setProperty("blueSwizzle", ui->cmbBlue->currentIndex()); return config; } void KisWdgConvertHeightToNormalMap::setConfiguration(const KisPropertiesConfigurationSP config) { ui->sldHorizontalRadius->setValue(config->getFloat("horizRadius", 1.0)); ui->sldVerticalRadius->setValue(config->getFloat("vertRadius", 1.0)); int index = 0; if (m_types.contains(config->getString("type", "prewitt"))){ index = m_types.indexOf(config->getString("type", "sobol")); } ui->cmbType->setCurrentIndex(index); ui->cmbChannel->setCurrentIndex(config->getInt("channelToConvert", 0)); ui->btnAspect->setKeepAspectRatio(config->getBool("lockAspect", false)); ui->cmbRed->setCurrentIndex(config->getInt("redSwizzle", xPlus)); ui->cmbGreen->setCurrentIndex(config->getInt("greenSwizzle", yPlus)); ui->cmbBlue->setCurrentIndex(config->getInt("blueSwizzle", zPlus)); } void KisWdgConvertHeightToNormalMap::horizontalRadiusChanged(qreal r) { ui->sldHorizontalRadius->blockSignals(true); ui->sldHorizontalRadius->setValue(r); ui->sldHorizontalRadius->blockSignals(false); if (ui->btnAspect->keepAspectRatio()) { ui->sldVerticalRadius->blockSignals(true); ui->sldVerticalRadius->setValue(r); ui->sldVerticalRadius->blockSignals(false); } } void KisWdgConvertHeightToNormalMap::verticalRadiusChanged(qreal r) { ui->sldVerticalRadius->blockSignals(true); ui->sldVerticalRadius->setValue(r); ui->sldVerticalRadius->blockSignals(false); if (ui->btnAspect->keepAspectRatio()) { ui->sldHorizontalRadius->blockSignals(true); ui->sldHorizontalRadius->setValue(r); ui->sldHorizontalRadius->blockSignals(false); } } void KisWdgConvertHeightToNormalMap::aspectLockChanged(bool v) { if (v) { ui->sldVerticalRadius->setValue( ui->sldHorizontalRadius->value() ); } }