diff --git a/krita/krita.action b/krita/krita.action
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -355,6 +355,17 @@
true
+
+ transform_icons_penPressure
+ Use Pen Pressure
+
+ Use Pen Pressure
+ Use Pen Pressure
+ 10000
+
+ true
+
+
symmetry-horizontal
Horizontal Mirror Tool
diff --git a/krita/pics/tool_transform/dark_transform_icons_penPressure_locked.png b/krita/pics/tool_transform/dark_transform_icons_penPressure_locked.png
new file mode 100644
index 0000000000000000000000000000000000000000..f18f35ffec6143d4be825a8c4a41f9ccee06a649
GIT binary patch
literal 3440
zc$@)n4Uh7PP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T
zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p
z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&nehQ1i
z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW
zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X
zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4
zfg=2N-7=cNnjjOr{yriy6mMFgG#l
znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U
zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya?
z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y
zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB
zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt
z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C
z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB
zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe
zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0
z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$
z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4
z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu
zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu
z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E
ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw
zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX
z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i&
z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01
z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R
z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw
zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD
zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3|
zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy
zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z
zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F}
z0007;Nkl{Q)fv!HsTOOp73LDGUs_m=Y%`Y=->BIOF(c-n-*^Eu~y
z&oO3ZW^kS?%c46wJI{A_cVC{BC-{%@`TSeP*t1Y5WS$EMg+lQA{je+xQ&UsDy}iBZ
zMx)^z9v(jG?Cfj-@N|EFAIW4Av$L}&0N9Vtry_B4XP%9LK@f*cfuT9O0b5o1dS*b0%PV
zdKyDRLw8-*P4xBkMbqgtVT_?#tzu4E1^)wr!)my&ctR6@(Bl#*(#K?Q15Jc|+szH~^qhsdQvAnHQUz
zn?23V%|D!LsZ>h-^9PMaqoZE0Go@7c
z`1lxFYZ!(B(=;XL{G02#>r%=V&Ux4N_O>{6#6
literal 0
Hc$@
-
-
+
+
dark_transform_icons_cage.png
dark_transform_icons_liquify_erase.png
dark_transform_icons_liquify_main.png
@@ -18,7 +17,6 @@
dark_transform_icons_mirror_y.svg
dark_transform_icons_rotate_cw.svg
dark_transform_icons_rotate_ccw.svg
-
light_transform_icons_cage.png
light_transform_icons_liquify_erase.png
light_transform_icons_liquify_main.png
@@ -36,5 +34,7 @@
light_transform_icons_mirror_y.svg
light_transform_icons_rotate_cw.svg
light_transform_icons_rotate_ccw.svg
+ light_transform_icons_penPressure_locked.png
+ dark_transform_icons_penPressure_locked.png
diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt
--- a/libs/flake/CMakeLists.txt
+++ b/libs/flake/CMakeLists.txt
@@ -16,6 +16,7 @@
KoCanvasBase.cpp
KoResourceManager_p.cpp
KoDerivedResourceConverter.cpp
+ KoResourceUpdateMediator.cpp
KoCanvasResourceManager.cpp
KoDocumentResourceManager.cpp
KoCanvasObserverBase.cpp
diff --git a/libs/flake/KoCanvasResourceManager.h b/libs/flake/KoCanvasResourceManager.h
--- a/libs/flake/KoCanvasResourceManager.h
+++ b/libs/flake/KoCanvasResourceManager.h
@@ -25,6 +25,7 @@
#include "kritaflake_export.h"
#include "KoDerivedResourceConverter.h"
+#include "KoResourceUpdateMediator.h"
class KoShape;
class KoShapeStroke;
@@ -250,6 +251,22 @@
*/
void removeDerivedResourceConverter(int key);
+ /**
+ * @see KoReosurceManager::addResourceUpdateMediator
+ */
+ void addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator);
+
+ /**
+ * @see KoReosurceManager::hasResourceUpdateMediator
+ */
+ bool hasResourceUpdateMediator(int key);
+
+ /**
+
+ * @see KoReosurceManager::removeResourceUpdateMediator
+ */
+ void removeResourceUpdateMediator(int key);
+
Q_SIGNALS:
/**
* This signal is emitted every time a resource is set that is either
diff --git a/libs/flake/KoCanvasResourceManager.cpp b/libs/flake/KoCanvasResourceManager.cpp
--- a/libs/flake/KoCanvasResourceManager.cpp
+++ b/libs/flake/KoCanvasResourceManager.cpp
@@ -180,3 +180,18 @@
{
d->manager.removeDerivedResourceConverter(key);
}
+
+void KoCanvasResourceManager::addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator)
+{
+ d->manager.addResourceUpdateMediator(mediator);
+}
+
+bool KoCanvasResourceManager::hasResourceUpdateMediator(int key)
+{
+ return d->manager.hasResourceUpdateMediator(key);
+}
+
+void KoCanvasResourceManager::removeResourceUpdateMediator(int key)
+{
+ d->manager.removeResourceUpdateMediator(key);
+}
diff --git a/libs/flake/KoDerivedResourceConverter.h b/libs/flake/KoDerivedResourceConverter.h
--- a/libs/flake/KoDerivedResourceConverter.h
+++ b/libs/flake/KoDerivedResourceConverter.h
@@ -49,6 +49,14 @@
int key() const;
int sourceKey() const;
+ QVariant readFromSource(const QVariant &value);
+ QVariant writeToSource(const QVariant &value,
+ const QVariant &sourceValue,
+ bool *changed);
+
+ virtual bool notifySourceChanged(const QVariant &sourceValue);
+
+protected:
/**
* Converts the \p value of the source resource into the space of
* the "derived" resource. E.g. preset -> opacity.
diff --git a/libs/flake/KoDerivedResourceConverter.cpp b/libs/flake/KoDerivedResourceConverter.cpp
--- a/libs/flake/KoDerivedResourceConverter.cpp
+++ b/libs/flake/KoDerivedResourceConverter.cpp
@@ -19,15 +19,17 @@
#include "KoDerivedResourceConverter.h"
#include "QVariant"
-
+#include "kis_assert.h"
struct KoDerivedResourceConverter::Private
{
Private(int _key, int _sourceKey)
: key(_key), sourceKey(_sourceKey) {}
int key;
int sourceKey;
+
+ QVariant lastKnownValue;
};
@@ -50,3 +52,42 @@
return m_d->sourceKey;
}
+bool KoDerivedResourceConverter::notifySourceChanged(const QVariant &sourceValue)
+{
+ const QVariant newValue = fromSource(sourceValue);
+
+ const bool valueChanged = m_d->lastKnownValue != newValue;
+ m_d->lastKnownValue = newValue;
+
+ return valueChanged;
+}
+
+QVariant KoDerivedResourceConverter::readFromSource(const QVariant &sourceValue)
+{
+ const QVariant result = fromSource(sourceValue);
+
+ KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->lastKnownValue.isNull() ||
+ result == m_d->lastKnownValue);
+
+ m_d->lastKnownValue = result;
+
+ return m_d->lastKnownValue;
+}
+
+QVariant KoDerivedResourceConverter::writeToSource(const QVariant &value,
+ const QVariant &sourceValue,
+ bool *changed)
+{
+ if (changed) {
+ *changed = m_d->lastKnownValue != value;
+ }
+
+ QVariant newSourceValue = sourceValue;
+
+ if (*changed || value != fromSource(sourceValue)) {
+ m_d->lastKnownValue = value;
+ newSourceValue = toSource(value, sourceValue);
+ }
+
+ return newSourceValue;
+}
diff --git a/libs/flake/KoResourceManager_p.h b/libs/flake/KoResourceManager_p.h
--- a/libs/flake/KoResourceManager_p.h
+++ b/libs/flake/KoResourceManager_p.h
@@ -29,6 +29,8 @@
#include
#include
#include "KoDerivedResourceConverter.h"
+#include "KoResourceUpdateMediator.h"
+
class KoShape;
class QVariant;
@@ -144,15 +146,15 @@
void clearResource(int key);
/**
- * Some of the resources may be "derive" from the other. For
+ * Some of the resources may be "derived" from the others. For
* example opacity, composite op and erase mode properties are
* contained inside a paintop preset, so we need not create a
* separate resource for them. Instead we created a derived resource,
* that loads/saves values from/to another resource, but has its own
* "resource changed" signal (via a different key).
*
* When a parent resource changes, the resource manager emits
- * update signals for all its derived resources.
+ * update signals for all its derived resources.
*/
void addDerivedResourceConverter(KoDerivedResourceConverterSP converter);
@@ -172,11 +174,35 @@
*/
void removeDerivedResourceConverter(int key);
+ /**
+ * Some resources can "mutate", that is their value doesn't change
+ * (a pointer), whereas the contents changes. But we should still
+ * notify all the derived resources subscribers that the resource
+ * has changed. For that purpose we use a special mediator class
+ * that connects the resource (which is not a QObject at all) and
+ * the resource manager controls that connection.
+ */
+ void addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator);
+
+ /**
+ * \see addResourceUpdateMediator()
+ */
+ bool hasResourceUpdateMediator(int key);
+
+ /**
+ * \see addResourceUpdateMediator()
+ */
+ void removeResourceUpdateMediator(int key);
+
Q_SIGNALS:
void resourceChanged(int key, const QVariant &value);
private:
void notifyResourceChanged(int key, const QVariant &value);
+ void notifyDerivedResourcesChanged(int key, const QVariant &value);
+
+private Q_SLOTS:
+ void slotResourceInternalsChanged(int key);
private:
KoResourceManager(const KoResourceManager&);
@@ -186,6 +212,8 @@
QHash m_derivedResources;
QMultiHash m_derivedFromSource;
+
+ QHash m_updateMediators;
};
#endif
diff --git a/libs/flake/KoResourceManager_p.cpp b/libs/flake/KoResourceManager_p.cpp
--- a/libs/flake/KoResourceManager_p.cpp
+++ b/libs/flake/KoResourceManager_p.cpp
@@ -25,43 +25,68 @@
#include
#include "KoShape.h"
+#include "kis_assert.h"
+#include "kis_debug.h"
-void KoResourceManager::setResource(int key, const QVariant &value)
+void KoResourceManager::slotResourceInternalsChanged(int key)
{
- QVariant realValue = value;
- int realKey = key;
- QVariant currentValue = m_resources.value(key, QVariant());
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_resources.contains(key));
+ notifyDerivedResourcesChanged(key, m_resources[key]);
+}
+void KoResourceManager::setResource(int key, const QVariant &value)
+{
KoDerivedResourceConverterSP converter =
m_derivedResources.value(key, KoDerivedResourceConverterSP());
if (converter) {
- realKey = converter->sourceKey();
- currentValue = m_resources.value(realKey, QVariant());
- realValue = converter->toSource(value, currentValue);
- }
+ const int sourceKey = converter->sourceKey();
+ const QVariant oldSourceValue = m_resources.value(sourceKey, QVariant());
+
+ bool valueChanged = false;
+ const QVariant newSourceValue = converter->writeToSource(value, oldSourceValue, &valueChanged);
+
+ if (valueChanged) {
+ notifyResourceChanged(key, value);
+ }
+
+ if (oldSourceValue != newSourceValue) {
+ m_resources[sourceKey] = newSourceValue;
+ notifyResourceChanged(sourceKey, newSourceValue);
+ }
- if (m_resources.contains(realKey)) {
- if (!converter && currentValue == realValue)
- return;
- m_resources[realKey] = realValue;
} else {
- m_resources.insert(realKey, realValue);
- }
+ const QVariant oldValue = m_resources.value(key, QVariant());
+ m_resources[key] = value;
- notifyResourceChanged(key, value);
+ if (m_updateMediators.contains(key)) {
+ m_updateMediators[key]->connectResource(value);
+ }
+
+ if (oldValue != value) {
+ notifyResourceChanged(key, value);
+ }
+ }
}
void KoResourceManager::notifyResourceChanged(int key, const QVariant &value)
{
emit resourceChanged(key, value);
+ notifyDerivedResourcesChanged(key, value);
+}
+void KoResourceManager::notifyDerivedResourcesChanged(int key, const QVariant &value)
+{
QMultiHash::const_iterator it = m_derivedFromSource.constFind(key);
QMultiHash::const_iterator end = m_derivedFromSource.constEnd();
while (it != end && it.key() == key) {
KoDerivedResourceConverterSP converter = it.value();
- notifyResourceChanged(converter->key(), converter->fromSource(value));
+
+ if (converter->notifySourceChanged(value)) {
+ notifyResourceChanged(converter->key(), converter->readFromSource(value));
+ }
+
it++;
}
}
@@ -74,7 +99,7 @@
const int realKey = converter ? converter->sourceKey() : key;
QVariant value = m_resources.value(realKey, QVariant());
- return converter ? converter->fromSource(value) : value;
+ return converter ? converter->readFromSource(value) : value;
}
void KoResourceManager::setResource(int key, const KoColor &color)
@@ -175,7 +200,7 @@
void KoResourceManager::addDerivedResourceConverter(KoDerivedResourceConverterSP converter)
{
- Q_ASSERT(!m_derivedResources.contains(converter->key()));
+ KIS_SAFE_ASSERT_RECOVER_NOOP(!m_derivedResources.contains(converter->key()));
m_derivedResources.insert(converter->key(), converter);
m_derivedFromSource.insertMulti(converter->sourceKey(), converter);
@@ -194,3 +219,21 @@
m_derivedResources.remove(key);
m_derivedFromSource.remove(converter->sourceKey(), converter);
}
+
+void KoResourceManager::addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator)
+{
+ KIS_SAFE_ASSERT_RECOVER_NOOP(!m_updateMediators.contains(mediator->key()));
+ m_updateMediators.insert(mediator->key(), mediator);
+ connect(mediator.data(), SIGNAL(sigResourceChanged(int)), SLOT(slotResourceInternalsChanged(int)));
+}
+
+bool KoResourceManager::hasResourceUpdateMediator(int key)
+{
+ return m_updateMediators.contains(key);
+}
+
+void KoResourceManager::removeResourceUpdateMediator(int key)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_updateMediators.contains(key));
+ m_updateMediators.remove(key);
+}
diff --git a/libs/flake/KoResourceUpdateMediator.h b/libs/flake/KoResourceUpdateMediator.h
new file mode 100644
--- /dev/null
+++ b/libs/flake/KoResourceUpdateMediator.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef __KO_RESOURCE_UPDATE_MEDIATOR_H
+#define __KO_RESOURCE_UPDATE_MEDIATOR_H
+
+#include
+#include
+#include "kritaflake_export.h"
+
+/**
+ * A special mediator class that connects the resource and the
+ * resource manager. The resource manager connects to a
+ * sigResourceChanged() changed and when a resource changes, the
+ * manager calls connectResource() for this resource. After that, the
+ * mediator should notify the manager about every change that happens
+ * to the resource by emitting the corresponding signal.
+ *
+ * There is only one mediator for one type (key) of the resource.
+ */
+
+class KRITAFLAKE_EXPORT KoResourceUpdateMediator : public QObject
+{
+ Q_OBJECT
+public:
+ KoResourceUpdateMediator(int key);
+ virtual ~KoResourceUpdateMediator();
+
+ int key() const;
+ virtual void connectResource(QVariant sourceResource) = 0;
+
+Q_SIGNALS:
+ void sigResourceChanged(int key);
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
+
+typedef QSharedPointer KoResourceUpdateMediatorSP;
+
+#endif /* __KO_RESOURCE_UPDATE_MEDIATOR_H */
diff --git a/plugins/paintops/particle/kis_particle_paintop_settings.h b/libs/flake/KoResourceUpdateMediator.cpp
copy from plugins/paintops/particle/kis_particle_paintop_settings.h
copy to libs/flake/KoResourceUpdateMediator.cpp
--- a/plugins/paintops/particle/kis_particle_paintop_settings.h
+++ b/libs/flake/KoResourceUpdateMediator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Lukáš Tvrdý
+ * 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
@@ -16,20 +16,26 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef KIS_PARTICLE_PAINTOP_SETTINGS_H_
-#define KIS_PARTICLE_PAINTOP_SETTINGS_H_
+#include "KoResourceUpdateMediator.h"
-#include
-#include
-class KisParticlePaintOpSettings : public KisPaintOpSettings
+struct KoResourceUpdateMediator::Private
{
+ Private(int _key) : key(_key) {}
+ int key;
+};
-public:
- bool paintIncremental();
- bool isAirbrushing() const;
- int rate() const;
-};
+KoResourceUpdateMediator::KoResourceUpdateMediator(int key)
+ : m_d(new Private(key))
+{
+}
-#endif
+KoResourceUpdateMediator::~KoResourceUpdateMediator()
+{
+}
+
+int KoResourceUpdateMediator::key() const
+{
+ return m_d->key;
+}
diff --git a/libs/flake/tests/TestResourceManager.h b/libs/flake/tests/TestResourceManager.h
--- a/libs/flake/tests/TestResourceManager.h
+++ b/libs/flake/tests/TestResourceManager.h
@@ -30,6 +30,7 @@
void testUnitChanged();
void testConverters();
void testDerivedChanged();
+ void testComplexResource();
};
#endif // TESTRESOURCEMANAGER_H
diff --git a/libs/flake/tests/TestResourceManager.cpp b/libs/flake/tests/TestResourceManager.cpp
--- a/libs/flake/tests/TestResourceManager.cpp
+++ b/libs/flake/tests/TestResourceManager.cpp
@@ -26,6 +26,8 @@
#include
#include
+#include "kis_debug.h"
+
void TestResourceManager::koShapeResource()
{
KoPathShape * shape = new KoPathShape();
@@ -118,27 +120,270 @@
m.setResource(derivedKey, 16);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.count(), 3);
QList args;
args = spy[0];
QCOMPARE(args[0].toInt(), derivedKey);
QCOMPARE(args[1].toInt(), 16);
+ args = spy[1];
+ QCOMPARE(args[0].toInt(), key2);
+ QCOMPARE(args[1].toInt(), 6);
+
+ args = spy[2];
+ QCOMPARE(args[0].toInt(), otherDerivedKey);
+ QCOMPARE(args[1].toInt(), 16);
+
+ spy.clear();
+
m.setResource(key2, 7);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.count(), 3);
- args = spy[1];
+ args = spy[0];
QCOMPARE(args[0].toInt(), key2);
QCOMPARE(args[1].toInt(), 7);
- args = spy[2];
+ args = spy[1];
QCOMPARE(args[0].toInt(), otherDerivedKey);
QCOMPARE(args[1].toInt(), 17);
- args = spy[3];
+ args = spy[2];
QCOMPARE(args[0].toInt(), derivedKey);
QCOMPARE(args[1].toInt(), 17);
}
+struct ComplexResource {
+ QHash m_resources;
+};
+
+typedef QSharedPointer ComplexResourceSP;
+Q_DECLARE_METATYPE(ComplexResourceSP);
+
+struct ComplexConverter : public KoDerivedResourceConverter
+{
+ ComplexConverter(int key, int sourceKey) : KoDerivedResourceConverter(key, sourceKey) {}
+
+ QVariant fromSource(const QVariant &value) {
+ KIS_ASSERT(value.canConvert());
+ ComplexResourceSP res = value.value();
+
+ return res->m_resources[key()];
+ }
+
+ QVariant toSource(const QVariant &value, const QVariant &sourceValue) {
+ KIS_ASSERT(sourceValue.canConvert());
+ ComplexResourceSP res = sourceValue.value();
+
+ res->m_resources[key()] = value;
+ return QVariant::fromValue(res);
+ }
+};
+
+struct ComplexMediator : public KoResourceUpdateMediator
+{
+ ComplexMediator(int key) : KoResourceUpdateMediator(key) {}
+
+ void connectResource(QVariant sourceResource) {
+ m_res = sourceResource;
+ }
+
+ void forceNotify() {
+ emit sigResourceChanged(key());
+ }
+
+ QVariant m_res;
+};
+typedef QSharedPointer ComplexMediatorSP;
+
+void TestResourceManager::testComplexResource()
+{
+ const int key = 2;
+ const int complex1 = 3;
+ const int complex2 = 4;
+
+ KoCanvasResourceManager m(0);
+ m.addDerivedResourceConverter(toQShared(new ComplexConverter(complex1, key)));
+ m.addDerivedResourceConverter(toQShared(new ComplexConverter(complex2, key)));
+
+ ComplexMediatorSP mediator(new ComplexMediator(key));
+ m.addResourceUpdateMediator(mediator);
+
+ QSignalSpy spy(&m, SIGNAL(canvasResourceChanged(int, const QVariant &)));
+
+ ComplexResourceSP r1(new ComplexResource());
+ r1->m_resources[complex1] = 10;
+ r1->m_resources[complex2] = 20;
+
+ ComplexResourceSP r2(new ComplexResource());
+ r2->m_resources[complex1] = 15;
+ r2->m_resources[complex2] = 25;
+
+
+ // ####################################################
+ // Initial assignment
+ // ####################################################
+ m.setResource(key, QVariant::fromValue(r1));
+
+ QCOMPARE(mediator->m_res.value(), r1);
+ QCOMPARE(m.resource(key).value(), r1);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 20);
+
+ QCOMPARE(spy[0][0].toInt(), key);
+ QCOMPARE(spy[0][1].value(), r1);
+ QCOMPARE(spy[1][0].toInt(), complex2);
+ QCOMPARE(spy[1][1].toInt(), 20);
+ QCOMPARE(spy[2][0].toInt(), complex1);
+ QCOMPARE(spy[2][1].toInt(), 10);
+ spy.clear();
+
+ // ####################################################
+ // Change the whole resource
+ // ####################################################
+ m.setResource(key, QVariant::fromValue(r2));
+
+ QCOMPARE(mediator->m_res.value(), r2);
+ QCOMPARE(m.resource(key).value(), r2);
+ QCOMPARE(m.resource(complex1).toInt(), 15);
+ QCOMPARE(m.resource(complex2).toInt(), 25);
+
+ QCOMPARE(spy[0][0].toInt(), key);
+ QCOMPARE(spy[0][1].value(), r2);
+ QCOMPARE(spy[1][0].toInt(), complex2);
+ QCOMPARE(spy[1][1].toInt(), 25);
+ QCOMPARE(spy[2][0].toInt(), complex1);
+ QCOMPARE(spy[2][1].toInt(), 15);
+ spy.clear();
+
+ // ####################################################
+ // Change a derived resource
+ // ####################################################
+ m.setResource(complex1, 16);
+
+ QCOMPARE(mediator->m_res.value(), r2);
+ QCOMPARE(m.resource(key).value(), r2);
+ QCOMPARE(m.resource(complex1).toInt(), 16);
+ QCOMPARE(m.resource(complex2).toInt(), 25);
+
+ QCOMPARE(spy[0][0].toInt(), complex1);
+ QCOMPARE(spy[0][1].toInt(), 16);
+ spy.clear();
+
+ // ####################################################
+ // Change another derived resource
+ // ####################################################
+ m.setResource(complex2, 26);
+
+ QCOMPARE(mediator->m_res.value(), r2);
+ QCOMPARE(m.resource(key).value(), r2);
+ QCOMPARE(m.resource(complex1).toInt(), 16);
+ QCOMPARE(m.resource(complex2).toInt(), 26);
+
+ QCOMPARE(spy[0][0].toInt(), complex2);
+ QCOMPARE(spy[0][1].toInt(), 26);
+ spy.clear();
+
+ // ####################################################
+ // Switch back the whole source resource
+ // ####################################################
+ m.setResource(key, QVariant::fromValue(r1));
+
+ QCOMPARE(mediator->m_res.value(), r1);
+ QCOMPARE(m.resource(key).value(), r1);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 20);
+
+ QCOMPARE(spy[0][0].toInt(), key);
+ QCOMPARE(spy[0][1].value(), r1);
+ QCOMPARE(spy[1][0].toInt(), complex2);
+ QCOMPARE(spy[1][1].toInt(), 20);
+ QCOMPARE(spy[2][0].toInt(), complex1);
+ QCOMPARE(spy[2][1].toInt(), 10);
+ spy.clear();
+
+ // ####################################################
+ // The value keep unchanged case!
+ // ####################################################
+ m.setResource(complex1, 10);
+
+ QCOMPARE(mediator->m_res.value(), r1);
+ QCOMPARE(m.resource(key).value(), r1);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 20);
+
+ QCOMPARE(spy.size(), 0);
+ spy.clear();
+
+ // ####################################################
+ // While switching a complex resource one derived value
+ // is kept unchanged
+ // ####################################################
+ r2->m_resources[complex1] = 10;
+ m.setResource(key, QVariant::fromValue(r2));
+
+ QCOMPARE(mediator->m_res.value(), r2);
+ QCOMPARE(m.resource(key).value(), r2);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 26);
+
+ QCOMPARE(spy[0][0].toInt(), key);
+ QCOMPARE(spy[0][1].value(), r2);
+ QCOMPARE(spy[1][0].toInt(), complex2);
+ QCOMPARE(spy[1][1].toInt(), 26);
+ spy.clear();
+
+ // ####################################################
+ // No devived values are changed!
+ // ####################################################
+ *r1 = *r2;
+ m.setResource(key, QVariant::fromValue(r1));
+
+ QCOMPARE(mediator->m_res.value(), r1);
+ QCOMPARE(m.resource(key).value(), r1);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 26);
+
+ QCOMPARE(spy[0][0].toInt(), key);
+ QCOMPARE(spy[0][1].value(), r1);
+ spy.clear();
+
+ // ####################################################
+ // Try to set the same pointer. No signals emitted!
+ // ####################################################
+ m.setResource(key, QVariant::fromValue(r1));
+
+ QCOMPARE(mediator->m_res.value(), r1);
+ QCOMPARE(m.resource(key).value(), r1);
+ QCOMPARE(m.resource(complex1).toInt(), 10);
+ QCOMPARE(m.resource(complex2).toInt(), 26);
+
+ QCOMPARE(spy.size(), 0);
+ spy.clear();
+
+
+ // ####################################################
+ // Internals 'officially' changed, but the values not
+ // ####################################################
+ mediator->forceNotify();
+
+ QCOMPARE(spy.size(), 0);
+ spy.clear();
+
+ // ####################################################
+ // We changed the values, but didn't notify anyone :)
+ // ####################################################
+ r1->m_resources[complex1] = 11;
+ r1->m_resources[complex2] = 21;
+
+ mediator->forceNotify();
+
+ QCOMPARE(spy[0][0].toInt(), complex2);
+ QCOMPARE(spy[0][1].toInt(), 21);
+ QCOMPARE(spy[1][0].toInt(), complex1);
+ QCOMPARE(spy[1][1].toInt(), 11);
+ spy.clear();
+}
+
+
QTEST_MAIN(TestResourceManager)
diff --git a/libs/global/kis_global.h b/libs/global/kis_global.h
--- a/libs/global/kis_global.h
+++ b/libs/global/kis_global.h
@@ -251,6 +251,47 @@
return newList;
}
+
+/**
+ * Convert a list of strong pointers into a list of weak pointers
+ */
+template class Container, class T>
+Container> listStrongToWeak(const Container> &containter)
+{
+ Container > result;
+ Q_FOREACH (QSharedPointer v, containter) {
+ result << v;
+ }
+ return result;
+}
+
+/**
+ * Convert a list of weak pointers into a list of strong pointers
+ *
+ * WARNING: By default, uses "all or nothing" rule. If at least one of
+ * the weak pointers is invalid, returns an *empty* list!
+ * Even though some other pointer can still be converted
+ * correctly.
+ */
+template class Container, class T>
+ Container > listWeakToStrong(const Container> &containter,
+ bool allOrNothing = true)
+{
+ Container > result;
+ Q_FOREACH (QWeakPointer v, containter) {
+ QSharedPointer strong(v);
+ if (!strong && allOrNothing) {
+ result.clear();
+ return result;
+ }
+
+ if (strong) {
+ result << strong;
+ }
+ }
+ return result;
+}
+
/**
* A special wrapper object that converts Qt-style mutexes and locks
* into an object that supports Std's (and Boost's) "Lockable"
diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt
--- a/libs/image/CMakeLists.txt
+++ b/libs/image/CMakeLists.txt
@@ -65,10 +65,14 @@
brushengine/kis_paintop_preset.cpp
brushengine/kis_paintop_registry.cc
brushengine/kis_paintop_settings.cpp
+ brushengine/kis_paintop_settings_update_proxy.cpp
brushengine/kis_locked_properties.cc
brushengine/kis_locked_properties_proxy.cpp
brushengine/kis_locked_properties_server.cpp
brushengine/kis_paintop_config_widget.cpp
+ brushengine/kis_uniform_paintop_property.cpp
+ brushengine/kis_combo_based_paintop_property.cpp
+ brushengine/kis_standard_uniform_properties_factory.cpp
commands/kis_deselect_global_selection_command.cpp
commands/kis_image_change_layers_command.cpp
commands/kis_image_command.cpp
diff --git a/libs/image/brushengine/kis_callback_based_paintop_property.h b/libs/image/brushengine/kis_callback_based_paintop_property.h
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_callback_based_paintop_property.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_CALLBACK_BASED_PAINTOP_PROPERTY_H
+#define __KIS_CALLBACK_BASED_PAINTOP_PROPERTY_H
+
+#include
+
+
+template
+class KisCallbackBasedPaintopProperty : public ParentClass
+{
+public:
+ KisCallbackBasedPaintopProperty(typename ParentClass::Type type,
+ const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent)
+ : ParentClass(type, id, name, settings, parent) {}
+
+ KisCallbackBasedPaintopProperty(const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent)
+ : ParentClass(id, name, settings, parent) {}
+
+ typedef std::function Callback;
+ typedef std::function VisibleCallback;
+
+ void setReadCallback(Callback func) { m_readFunc = func; }
+ void setWriteCallback(Callback func) { m_writeFunc = func; }
+ void setIsVisibleCallback(VisibleCallback func) { m_visibleFunc = func; }
+
+protected:
+ virtual void readValueImpl() { if (m_readFunc) m_readFunc(this); }
+ virtual void writeValueImpl() { if (m_writeFunc) m_writeFunc(this); }
+ virtual bool isVisible() const { return m_visibleFunc ? m_visibleFunc(this) : true; }
+
+private:
+ Callback m_readFunc;
+ Callback m_writeFunc;
+ VisibleCallback m_visibleFunc;
+};
+
+#endif /* __KIS_CALLBACK_BASED_PAINTOP_PROPERTY_H */
diff --git a/libs/image/brushengine/kis_combo_based_paintop_property.h b/libs/image/brushengine/kis_combo_based_paintop_property.h
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_combo_based_paintop_property.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_COMBO_BASED_PAINTOP_PROPERTY_H
+#define __KIS_COMBO_BASED_PAINTOP_PROPERTY_H
+
+#include
+
+#include "kis_uniform_paintop_property.h"
+#include "kis_types.h"
+#include "kritaimage_export.h"
+
+class QIcon;
+
+
+class KRITAIMAGE_EXPORT KisComboBasedPaintOpProperty : public KisUniformPaintOpProperty
+{
+public:
+ KisComboBasedPaintOpProperty(const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent);
+ ~KisComboBasedPaintOpProperty();
+
+ // callback-compatible c-tor
+ KisComboBasedPaintOpProperty(Type type,
+ const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent);
+
+ QList items() const;
+ void setItems(const QList &list);
+
+ QList icons() const;
+ void setIcons(const QList &list);
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
+
+#endif /* __KIS_COMBO_BASED_PAINTOP_PROPERTY_H */
diff --git a/libs/image/brushengine/kis_combo_based_paintop_property.cpp b/libs/image/brushengine/kis_combo_based_paintop_property.cpp
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_combo_based_paintop_property.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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_combo_based_paintop_property.h"
+#include "kis_paintop_settings.h"
+
+#include "QIcon"
+
+
+struct KisComboBasedPaintOpProperty::Private
+{
+ QList items;
+ QList icons;
+};
+
+KisComboBasedPaintOpProperty::KisComboBasedPaintOpProperty(const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent)
+ : KisUniformPaintOpProperty(Combo, id, name, settings, parent),
+ m_d(new Private)
+{
+}
+
+KisComboBasedPaintOpProperty::~KisComboBasedPaintOpProperty()
+{
+}
+
+QList KisComboBasedPaintOpProperty::items() const
+{
+ return m_d->items;
+}
+
+void KisComboBasedPaintOpProperty::setItems(const QList &list)
+{
+ m_d->items = list;
+}
+
+QList KisComboBasedPaintOpProperty::icons() const
+{
+ return m_d->icons;
+}
+
+void KisComboBasedPaintOpProperty::setIcons(const QList &list)
+{
+ m_d->icons = list;
+}
+
+
diff --git a/libs/image/brushengine/kis_locked_properties_proxy.h b/libs/image/brushengine/kis_locked_properties_proxy.h
--- a/libs/image/brushengine/kis_locked_properties_proxy.h
+++ b/libs/image/brushengine/kis_locked_properties_proxy.h
@@ -52,4 +52,7 @@
const KisPropertiesConfiguration *m_parent;
};
+typedef QSharedPointer KisLockedPropertiesProxySP;
+typedef QWeakPointer KisLockedPropertiesProxyWSP;
+
#endif // KIS_LOCKED_PROPERTIES_PROXY_H
diff --git a/libs/image/brushengine/kis_paintop_config_widget.h b/libs/image/brushengine/kis_paintop_config_widget.h
--- a/libs/image/brushengine/kis_paintop_config_widget.h
+++ b/libs/image/brushengine/kis_paintop_config_widget.h
@@ -38,12 +38,17 @@
KisPaintOpConfigWidget(QWidget * parent = 0, Qt::WFlags f = 0);
virtual ~KisPaintOpConfigWidget();
+ void writeConfigurationSafe(KisPropertiesConfiguration *config) const;
+ void setConfigurationSafe(const KisPropertiesConfiguration *config);
+
+protected:
/**
* Write the settings in this widget to the given properties
* configuration, which is cleared first.
*/
virtual void writeConfiguration(KisPropertiesConfiguration *config) const;
virtual void setConfiguration(const KisPropertiesConfiguration * config);
+public:
virtual KisPaintopLodLimitations lodLimitations() const = 0;
@@ -90,6 +95,8 @@
KisImageWSP m_image;
KisNodeWSP m_node;
bool m_userAllowedLod;
+
+ mutable int m_isInsideUpdateCall;
};
#endif
diff --git a/libs/image/brushengine/kis_paintop_config_widget.cpp b/libs/image/brushengine/kis_paintop_config_widget.cpp
--- a/libs/image/brushengine/kis_paintop_config_widget.cpp
+++ b/libs/image/brushengine/kis_paintop_config_widget.cpp
@@ -23,13 +23,32 @@
KisPaintOpConfigWidget::KisPaintOpConfigWidget(QWidget * parent, Qt::WFlags f)
: KisConfigWidget(parent, f, 10),
- m_userAllowedLod(true)
+ m_userAllowedLod(true),
+ m_isInsideUpdateCall(0)
{
}
KisPaintOpConfigWidget::~KisPaintOpConfigWidget() {
}
+void KisPaintOpConfigWidget::writeConfigurationSafe(KisPropertiesConfiguration *config) const
+{
+ if (m_isInsideUpdateCall) return;
+
+ m_isInsideUpdateCall++;
+ writeConfiguration(config);
+ m_isInsideUpdateCall--;
+}
+
+void KisPaintOpConfigWidget::setConfigurationSafe(const KisPropertiesConfiguration *config)
+{
+ if (m_isInsideUpdateCall) return;
+
+ m_isInsideUpdateCall++;
+ setConfiguration(config);
+ m_isInsideUpdateCall--;
+}
+
void KisPaintOpConfigWidget::writeConfiguration(KisPropertiesConfiguration *config) const {
KisPaintOpSettings::setLodUserAllowed(config, m_userAllowedLod);
}
diff --git a/libs/image/brushengine/kis_paintop_preset.h b/libs/image/brushengine/kis_paintop_preset.h
--- a/libs/image/brushengine/kis_paintop_preset.h
+++ b/libs/image/brushengine/kis_paintop_preset.h
@@ -25,7 +25,10 @@
#include "kis_types.h"
#include "kis_shared.h"
#include "kritaimage_export.h"
+#include
+class KisPaintopSettingsUpdateProxy;
+class KisPaintOpConfigWidget;
/**
* A KisPaintOpPreset contains a particular set of settings
@@ -103,6 +106,13 @@
bool m_isDirty;
};
+ void setOptionsWidget(KisPaintOpConfigWidget *widget);
+
+ KisPaintopSettingsUpdateProxy* updateProxy() const;
+ KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const;
+
+ QList uniformProperties();
+
private:
struct Private;
diff --git a/libs/image/brushengine/kis_paintop_preset.cpp b/libs/image/brushengine/kis_paintop_preset.cpp
--- a/libs/image/brushengine/kis_paintop_preset.cpp
+++ b/libs/image/brushengine/kis_paintop_preset.cpp
@@ -33,6 +33,8 @@
#include
#include "kis_paint_device.h"
#include "kis_image.h"
+#include "kis_paintop_settings_update_proxy.h"
+#include
#include
@@ -45,7 +47,7 @@
KisPaintOpSettingsSP settings;
bool dirtyPreset;
-
+ QScopedPointer updateProxy;
};
@@ -89,6 +91,10 @@
void KisPaintOpPreset::setPresetDirty(bool value)
{
m_d->dirtyPreset = value;
+
+ if (m_d->updateProxy && m_d->dirtyPreset != value) {
+ m_d->updateProxy->notifySettingsChanged();
+ }
}
bool KisPaintOpPreset::isPresetDirty() const
{
@@ -107,24 +113,49 @@
return KoID(m_d->settings->getString("paintop"), name());
}
+void KisPaintOpPreset::setOptionsWidget(KisPaintOpConfigWidget* widget)
+{
+ if (m_d->settings) {
+ m_d->settings->setOptionsWidget(widget);
+
+ if (widget) {
+ widget->setConfigurationSafe(m_d->settings);
+ }
+ }
+}
+
void KisPaintOpPreset::setSettings(KisPaintOpSettingsSP settings)
{
Q_ASSERT(settings);
Q_ASSERT(!settings->getString("paintop", "").isEmpty());
DirtyStateSaver dirtyStateSaver(this);
+ KisPaintOpConfigWidget *oldOptionsWidget = 0;
+
if (m_d->settings) {
+ oldOptionsWidget = m_d->settings->optionsWidget();
+ m_d->settings->setOptionsWidget(0);
m_d->settings->setPreset(0);
m_d->settings = 0;
}
if (settings) {
m_d->settings = settings->clone();
m_d->settings->setPreset(KisPaintOpPresetWSP(this));
+
+ if (oldOptionsWidget) {
+ m_d->settings->setOptionsWidget(oldOptionsWidget);
+ oldOptionsWidget->setConfigurationSafe(m_d->settings);
+ }
}
setValid(m_d->settings);
+
+ if (m_d->updateProxy) {
+ m_d->updateProxy->notifyUniformPropertiesChanged();
+ m_d->updateProxy->notifySettingsChanged();
+ }
}
KisPaintOpSettingsSP KisPaintOpPreset::settings() const
@@ -343,3 +374,20 @@
}
+KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxy() const
+{
+ if (!m_d->updateProxy) {
+ m_d->updateProxy.reset(new KisPaintopSettingsUpdateProxy());
+ }
+ return m_d->updateProxy.data();
+}
+
+KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxyNoCreate() const
+{
+ return m_d->updateProxy.data();
+}
+
+QList KisPaintOpPreset::uniformProperties()
+{
+ return m_d->settings->uniformProperties();
+}
diff --git a/libs/image/brushengine/kis_paintop_settings.h b/libs/image/brushengine/kis_paintop_settings.h
--- a/libs/image/brushengine/kis_paintop_settings.h
+++ b/libs/image/brushengine/kis_paintop_settings.h
@@ -28,9 +28,12 @@
#include "kis_shared.h"
#include "kis_properties_configuration.h"
#include
+#include
+
class KisPaintOpConfigWidget;
+class KisPaintopSettingsUpdateProxy;
/**
* This class is used to cache the settings for a paintop
@@ -158,23 +161,6 @@
QPointF const& start, qreal lengthScale, qreal angle);
/**
- * The behaviour might be different per paintop. Most of the time
- * the brush diameter is increased by x pixels, y ignored
- *
- * @param x is add to the diameter or radius (according the paintop)
- * It might be also negative, to decrease the value of the brush diameter/radius.
- * x is in pixels
- * @param y is unused, it supposed to be used to change some different attribute
- * of the brush like softness or density
- */
- virtual void changePaintOpSize(qreal x, qreal y);
-
- /**
- * @return The width and the height of the brush mask/dab in pixels
- */
- virtual QSizeF paintOpSize() const;
-
- /**
* Set paintop opacity directly in the properties
*/
void setPaintOpOpacity(qreal value);
@@ -204,6 +190,16 @@
*/
QString paintOpCompositeOp() const;
+ /**
+ * Set paintop size directly in the properties
+ */
+ void setPaintOpSize(qreal value);
+
+ /**
+ * @return size saved in the properties
+ */
+ qreal paintOpSize() const;
+
void setEraserMode(bool value);
bool eraserMode() const;
@@ -253,15 +249,18 @@
*/
void setProperty(const QString & name, const QVariant & value);
+ virtual QList uniformProperties();
+
static bool isLodUserAllowed(const KisPropertiesConfiguration *config);
static void setLodUserAllowed(KisPropertiesConfiguration *config, bool value);
-protected:
/**
* @return the option widget of the paintop (can be 0 is no option widgets is set)
*/
KisPaintOpConfigWidget* optionsWidget() const;
+protected:
+
/**
* The callback is called every time when a property changes
*/
diff --git a/libs/image/brushengine/kis_paintop_settings.cpp b/libs/image/brushengine/kis_paintop_settings.cpp
--- a/libs/image/brushengine/kis_paintop_settings.cpp
+++ b/libs/image/brushengine/kis_paintop_settings.cpp
@@ -36,15 +36,22 @@
#include
#include "kis_paintop_config_widget.h"
#include
+#include "kis_paintop_settings_update_proxy.h"
#include
#include
+#include
+
+#include
+#include
+
struct Q_DECL_HIDDEN KisPaintOpSettings::Private {
Private() : disableDirtyNotifications(false) {}
QPointer settingsWidget;
QString modelName;
KisPaintOpPresetWSP preset;
+ QList uniformProperties;
bool disableDirtyNotifications;
@@ -67,6 +74,14 @@
bool m_oldNotificationsState;
Q_DISABLE_COPY(DirtyNotificationsLocker)
};
+
+ KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const {
+ return preset ? preset->updateProxyNoCreate() : 0;
+ }
+
+ KisPaintopSettingsUpdateProxy* updateProxyCreate() const {
+ return preset ? preset->updateProxy() : 0;
+ }
};
@@ -146,61 +161,100 @@
{
}
-void KisPaintOpSettings::changePaintOpSize(qreal x, qreal y)
+void KisPaintOpSettings::setPaintOpOpacity(qreal value)
{
- if (!d->settingsWidget.isNull()) {
- d->settingsWidget.data()->changePaintOpSize(x, y);
- d->settingsWidget.data()->writeConfiguration(this);
- }
-}
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+ proxy->setProperty("OpacityValue", value);
+}
-QSizeF KisPaintOpSettings::paintOpSize() const
+void KisPaintOpSettings::setPaintOpFlow(qreal value)
{
- if (!d->settingsWidget.isNull()) {
- return d->settingsWidget.data()->paintOpSize();
- }
- return QSizeF(1.0, 1.0);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ proxy->setProperty("FlowValue", value);
}
-void KisPaintOpSettings::setPaintOpOpacity(qreal value)
+void KisPaintOpSettings::setPaintOpCompositeOp(const QString &value)
{
- setProperty("OpacityValue", value);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ proxy->setProperty("CompositeOp", value);
}
-void KisPaintOpSettings::setPaintOpFlow(qreal value)
+qreal KisPaintOpSettings::paintOpOpacity() const
{
- setProperty("FlowValue", value);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ return proxy->getDouble("OpacityValue", 1.0);
}
-void KisPaintOpSettings::setPaintOpCompositeOp(const QString &value)
+qreal KisPaintOpSettings::paintOpFlow() const
{
- setProperty("CompositeOp", value);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ return proxy->getDouble("FlowValue", 1.0);
}
-qreal KisPaintOpSettings::paintOpOpacity() const
+void KisPaintOpSettings::setPaintOpSize(qreal value)
{
- return getDouble("OpacityValue", 1.0);
+ /**
+ * The widget already has the wrapping for the locked setings
+ * functionality, so just request it.
+ */
+
+ if (d->settingsWidget) {
+ const qreal sizeDiff = value - paintOpSize();
+
+ {
+ KisSignalsBlocker b(d->settingsWidget);
+ d->settingsWidget.data()->setConfigurationSafe(this);
+ d->settingsWidget.data()->changePaintOpSize(sizeDiff, 0);
+ }
+ d->settingsWidget.data()->writeConfigurationSafe(this);
+ }
}
-qreal KisPaintOpSettings::paintOpFlow() const
+qreal KisPaintOpSettings::paintOpSize() const
{
- return getDouble("FlowValue", 1.0);
+ // see a comment about locked settings in setPaintOpSize()
+
+ qreal size = 1.0;
+
+ if (d->settingsWidget) {
+ size = d->settingsWidget.data()->paintOpSize().width();
+ }
+
+ return size;
}
QString KisPaintOpSettings::paintOpCompositeOp() const
{
- return getString("CompositeOp", COMPOSITE_OVER);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ return proxy->getString("CompositeOp", COMPOSITE_OVER);
}
void KisPaintOpSettings::setEraserMode(bool value)
{
- setProperty("EraserMode", value);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ proxy->setProperty("EraserMode", value);
}
bool KisPaintOpSettings::eraserMode() const
{
- return getBool("EraserMode", false);
+ KisLockedPropertiesProxySP proxy(
+ KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this));
+
+ return proxy->getBool("EraserMode", false);
}
QString KisPaintOpSettings::effectivePaintOpCompositeOp() const
@@ -347,7 +401,11 @@
void KisPaintOpSettings::onPropertyChanged()
{
+ KisPaintopSettingsUpdateProxy *proxy = d->updateProxyNoCreate();
+ if (proxy) {
+ proxy->notifySettingsChanged();
+ }
}
bool KisPaintOpSettings::isLodUserAllowed(const KisPropertiesConfiguration *config)
@@ -359,3 +417,24 @@
{
config->setProperty("lodUserAllowed", value);
}
+
+#include "kis_standard_uniform_properties_factory.h"
+
+QList KisPaintOpSettings::uniformProperties()
+{
+ QList props =
+ listWeakToStrong(d->uniformProperties);
+
+
+ if (props.isEmpty()) {
+ using namespace KisStandardUniformPropertiesFactory;
+
+ props.append(createProperty(opacity, this, d->updateProxyCreate()));
+ props.append(createProperty(size, this, d->updateProxyCreate()));
+ props.append(createProperty(flow, this, d->updateProxyCreate()));
+
+ d->uniformProperties = listStrongToWeak(props);
+ }
+
+ return props;
+}
diff --git a/libs/ui/kis_aspect_ratio_locker.h b/libs/image/brushengine/kis_paintop_settings_update_proxy.h
copy from libs/ui/kis_aspect_ratio_locker.h
copy to libs/image/brushengine/kis_paintop_settings_update_proxy.h
--- a/libs/ui/kis_aspect_ratio_locker.h
+++ b/libs/image/brushengine/kis_paintop_settings_update_proxy.h
@@ -16,38 +16,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ASPECT_RATIO_LOCKER_H
-#define __KIS_ASPECT_RATIO_LOCKER_H
+#ifndef __KIS_PAINTOP_SETTINGS_UPDATE_PROXY_H
+#define __KIS_PAINTOP_SETTINGS_UPDATE_PROXY_H
#include
#include
-#include "kritaui_export.h"
-class QSpinBox;
-class KoAspectButton;
-class KRITAUI_EXPORT KisAspectRatioLocker : public QObject
+class KisPaintopSettingsUpdateProxy : public QObject
{
Q_OBJECT
-public:
- KisAspectRatioLocker(QObject *parent);
- ~KisAspectRatioLocker();
-
- void connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *apectButton);
+public:
+ KisPaintopSettingsUpdateProxy(QObject *parent = 0);
+ ~KisPaintopSettingsUpdateProxy();
-private Q_SLOTS:
- void slotSpinOneChanged();
- void slotSpinTwoChanged();
- void slotAspectButtonChanged();
+ void notifySettingsChanged();
+ void notifyUniformPropertiesChanged();
Q_SIGNALS:
- void sliderValueChanged();
- void aspectButtonChanged();
+ void sigSettingsChanged();
+ void sigUniformPropertiesChanged();
private:
struct Private;
const QScopedPointer m_d;
};
-#endif /* __KIS_ASPECT_RATIO_LOCKER_H */
+#endif /* __KIS_PAINTOP_SETTINGS_UPDATE_PROXY_H */
diff --git a/libs/flake/KoDerivedResourceConverter.cpp b/libs/image/brushengine/kis_paintop_settings_update_proxy.cpp
copy from libs/flake/KoDerivedResourceConverter.cpp
copy to libs/image/brushengine/kis_paintop_settings_update_proxy.cpp
--- a/libs/flake/KoDerivedResourceConverter.cpp
+++ b/libs/image/brushengine/kis_paintop_settings_update_proxy.cpp
@@ -16,37 +16,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "KoDerivedResourceConverter.h"
+#include "kis_paintop_settings_update_proxy.h"
-#include "QVariant"
+#include "kis_signal_compressor.h"
-struct KoDerivedResourceConverter::Private
+struct KisPaintopSettingsUpdateProxy::Private
{
- Private(int _key, int _sourceKey)
- : key(_key), sourceKey(_sourceKey) {}
-
- int key;
- int sourceKey;
+ Private() : updatesCompressor(100, KisSignalCompressor::FIRST_ACTIVE) {}
+ KisSignalCompressor updatesCompressor;
};
-
-KoDerivedResourceConverter::KoDerivedResourceConverter(int key, int sourceKey)
- : m_d(new Private(key, sourceKey))
+KisPaintopSettingsUpdateProxy::KisPaintopSettingsUpdateProxy(QObject *parent)
+ : QObject(parent),
+ m_d(new Private)
{
+ connect(&m_d->updatesCompressor, SIGNAL(timeout()), SIGNAL(sigSettingsChanged()));
}
-KoDerivedResourceConverter::~KoDerivedResourceConverter()
+KisPaintopSettingsUpdateProxy::~KisPaintopSettingsUpdateProxy()
{
}
-int KoDerivedResourceConverter::key() const
+void KisPaintopSettingsUpdateProxy::notifySettingsChanged()
{
- return m_d->key;
+ m_d->updatesCompressor.start();
}
-int KoDerivedResourceConverter::sourceKey() const
+void KisPaintopSettingsUpdateProxy::notifyUniformPropertiesChanged()
{
- return m_d->sourceKey;
+ emit sigUniformPropertiesChanged();
}
-
diff --git a/libs/image/brushengine/kis_slider_based_paintop_property.h b/libs/image/brushengine/kis_slider_based_paintop_property.h
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_slider_based_paintop_property.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_SLIDER_BASED_PAINTOP_PROPERTY_H
+#define __KIS_SLIDER_BASED_PAINTOP_PROPERTY_H
+
+#include "kis_uniform_paintop_property.h"
+
+
+/**
+ * This is a general class for the properties that can be represented
+ * in the GUI as an integer or double slider. The GUI representation
+ * creates a slider and connects it to this property using all the
+ * information contained in it.
+ *
+ * Methods of this property basically copy the methods of
+ * Kis{,Double}SliderSpinbox
+ */
+
+template
+class KisSliderBasedPaintOpProperty : public KisUniformPaintOpProperty
+{
+public:
+ KisSliderBasedPaintOpProperty(Type type,
+ const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent)
+ : KisUniformPaintOpProperty(type, id, name, settings, parent),
+ m_min(T(0)),
+ m_max(T(100)),
+ m_singleStep(T(1)),
+ m_pageStep(T(10)),
+ m_exponentRatio(1.0),
+ m_decimals(2)
+ {
+ }
+
+ T min() const {
+ return m_min;
+ }
+ T max() const {
+ return m_max;
+ }
+ void setRange(T min, T max) {
+ m_min = min;
+ m_max = max;
+ }
+
+ T singleStep() const {
+ return m_singleStep;
+ }
+ void setSingleStep(T value) {
+ m_singleStep = value;
+ }
+
+ T pageStep() const {
+ return m_pageStep;
+ }
+ void setPageStep(T value) {
+ m_pageStep = value;
+ }
+
+ qreal exponentRatio() const {
+ return m_exponentRatio;
+ }
+ void setExponentRatio(qreal value) {
+ m_exponentRatio = value;
+ }
+
+ int decimals() const {
+ return m_decimals;
+ }
+ void setDecimals(int value) {
+ m_decimals = value;
+ }
+
+ QString suffix() const {
+ return m_suffix;
+ }
+ void setSuffix(QString value) {
+ m_suffix = value;
+ }
+
+
+private:
+ T m_min;
+ T m_max;
+
+ T m_singleStep;
+ T m_pageStep;
+ qreal m_exponentRatio;
+
+ int m_decimals;
+ QString m_suffix;
+};
+
+typedef KisSliderBasedPaintOpProperty KisIntSliderBasedPaintOpProperty;
+typedef KisSliderBasedPaintOpProperty KisDoubleSliderBasedPaintOpProperty;
+
+#include "kis_callback_based_paintop_property.h"
+
+typedef KisCallbackBasedPaintopProperty KisIntSliderBasedPaintOpPropertyCallback;
+typedef KisCallbackBasedPaintopProperty KisDoubleSliderBasedPaintOpPropertyCallback;
+
+#endif /* __KIS_SLIDER_BASED_PAINTOP_PROPERTY_H */
diff --git a/libs/image/brushengine/kis_standard_uniform_properties_factory.h b/libs/image/brushengine/kis_standard_uniform_properties_factory.h
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_standard_uniform_properties_factory.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_STANDARD_UNIFORM_PROPERTIES_FACTORY_H
+#define __KIS_STANDARD_UNIFORM_PROPERTIES_FACTORY_H
+
+#include
+
+#include "kis_uniform_paintop_property.h"
+
+class KisPaintopSettingsUpdateProxy;
+
+namespace KisStandardUniformPropertiesFactory
+{
+ static const KoID size("size", i18n("Size"));
+ static const KoID opacity("opacity", i18n("Opacity"));
+ static const KoID flow("flow", i18n("Flow"));
+ static const KoID angle("angle", i18n("Angle"));
+ static const KoID spacing("spacing", i18n("Spacing"));
+
+ /**
+ * Overload of createProperty(const QString &id, ...)
+ */
+ KisUniformPaintOpPropertySP createProperty(const KoID &id,
+ KisPaintOpSettingsSP settings,
+ KisPaintopSettingsUpdateProxy *updateProxy);
+
+ /**
+ * Factory for creating standard uniform properties. Right now
+ * it supports only size, opacity and flow.
+ */
+ KisUniformPaintOpPropertySP createProperty(const QString &id,
+ KisPaintOpSettingsSP settings,
+ KisPaintopSettingsUpdateProxy *updateProxy);
+}
+
+#endif /* __KIS_STANDARD_UNIFORM_PROPERTIES_FACTORY_H */
diff --git a/libs/image/brushengine/kis_standard_uniform_properties_factory.cpp b/libs/image/brushengine/kis_standard_uniform_properties_factory.cpp
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_standard_uniform_properties_factory.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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_standard_uniform_properties_factory.h"
+
+#include "kis_slider_based_paintop_property.h"
+#include "kis_paintop_settings.h"
+#include "kis_paintop_settings_update_proxy.h"
+
+namespace KisStandardUniformPropertiesFactory {
+
+ KisUniformPaintOpPropertySP createProperty(const KoID &id,
+ KisPaintOpSettingsSP settings,
+ KisPaintopSettingsUpdateProxy *updateProxy)
+ {
+ return createProperty(id.id(), settings, updateProxy);
+ }
+
+ KisUniformPaintOpPropertySP createProperty(const QString &id,
+ KisPaintOpSettingsSP settings,
+ KisPaintopSettingsUpdateProxy *updateProxy)
+ {
+ KisUniformPaintOpPropertySP result;
+
+
+ if (id == size.id()) {
+ KisDoubleSliderBasedPaintOpPropertyCallback *prop =
+ new KisDoubleSliderBasedPaintOpPropertyCallback(
+ KisDoubleSliderBasedPaintOpPropertyCallback::Double,
+ "size",
+ i18n("Size"),
+ settings, 0);
+
+ prop->setRange(0, 1000);
+ prop->setDecimals(2);
+ prop->setSingleStep(1);
+ prop->setExponentRatio(3.0);
+ prop->setSuffix(i18n(" px"));
+
+ prop->setReadCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->setValue(prop->settings()->paintOpSize());
+ });
+ prop->setWriteCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->settings()->setPaintOpSize(prop->value().toReal());
+ });
+
+ QObject::connect(updateProxy, SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+ prop->requestReadValue();
+ result = toQShared(prop);
+ } else if (id == opacity.id()) {
+ KisDoubleSliderBasedPaintOpPropertyCallback *prop =
+ new KisDoubleSliderBasedPaintOpPropertyCallback(
+ KisDoubleSliderBasedPaintOpPropertyCallback::Double,
+ opacity.id(),
+ opacity.name(),
+ settings, 0);
+
+ prop->setRange(0.0, 1.0);
+ prop->setSingleStep(0.01);
+
+ prop->setReadCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->setValue(prop->settings()->paintOpOpacity());
+ });
+ prop->setWriteCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->settings()->setPaintOpOpacity(prop->value().toReal());
+ });
+
+ QObject::connect(updateProxy, SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+ prop->requestReadValue();
+ result = toQShared(prop);
+ } else if (id == flow.id()) {
+ KisDoubleSliderBasedPaintOpPropertyCallback *prop =
+ new KisDoubleSliderBasedPaintOpPropertyCallback(
+ KisDoubleSliderBasedPaintOpPropertyCallback::Double,
+ flow.id(),
+ flow.name(),
+ settings, 0);
+
+ prop->setRange(0.0, 1.0);
+ prop->setSingleStep(0.01);
+
+ prop->setReadCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->setValue(prop->settings()->paintOpFlow());
+ });
+ prop->setWriteCallback(
+ [](KisUniformPaintOpProperty *prop) {
+ prop->settings()->setPaintOpFlow(prop->value().toReal());
+ });
+
+ QObject::connect(updateProxy, SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+ prop->requestReadValue();
+ result = toQShared(prop);
+ } else if (id == angle.id()) {
+ qFatal("Not implemented");
+ } else if (id == spacing.id()) {
+ qFatal("Not implemented");
+ }
+
+ if (!result) {
+ KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "Unknown Uniform property id!");
+ }
+
+ return result;
+ }
+}
diff --git a/libs/image/brushengine/kis_uniform_paintop_property.h b/libs/image/brushengine/kis_uniform_paintop_property.h
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_uniform_paintop_property.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_UNIFORM_PAINT_OP_PROPERTY_H
+#define __KIS_UNIFORM_PAINT_OP_PROPERTY_H
+
+#include
+#include
+
+#include "kritaimage_export.h"
+#include "kis_types.h"
+
+
+class KRITAIMAGE_EXPORT KisUniformPaintOpProperty : public QObject
+{
+ Q_OBJECT
+public:
+ enum Type {
+ Int = 0,
+ Double,
+ Bool,
+ Combo
+ };
+
+public:
+ KisUniformPaintOpProperty(Type type,
+ const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent);
+ ~KisUniformPaintOpProperty();
+
+ QString id() const;
+ QString name() const;
+ Type type() const;
+
+ QVariant value() const;
+
+ QWidget *createPropertyWidget();
+
+ KisPaintOpSettingsSP settings() const;
+
+ virtual bool isVisible() const;
+
+public Q_SLOTS:
+ void setValue(const QVariant &value);
+ void requestReadValue();
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &value);
+
+protected:
+ virtual void readValueImpl();
+ virtual void writeValueImpl();
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
+
+template class QSharedPointer;
+template class QWeakPointer;
+template class QList;
+
+typedef QSharedPointer KisUniformPaintOpPropertySP;
+typedef QWeakPointer KisUniformPaintOpPropertyWSP;
+
+#endif /* __KIS_UNIFORM_PAINT_OP_PROPERTY_H */
diff --git a/libs/image/brushengine/kis_uniform_paintop_property.cpp b/libs/image/brushengine/kis_uniform_paintop_property.cpp
new file mode 100644
--- /dev/null
+++ b/libs/image/brushengine/kis_uniform_paintop_property.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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_uniform_paintop_property.h"
+
+#include
+#include "kis_debug.h"
+#include "kis_paintop_settings.h"
+
+struct KisUniformPaintOpProperty::Private
+{
+ Private(Type _type,
+ const QString &_id,
+ const QString &_name,
+ KisPaintOpSettingsSP _settings)
+ : type(_type),
+ id(_id),
+ name(_name),
+ settings(_settings),
+ isReadingValue(false),
+ isWritingValue(false) {}
+
+ Type type;
+ QString id;
+ QString name;
+
+ QVariant value;
+
+ KisPaintOpSettingsSP settings;
+ bool isReadingValue;
+ bool isWritingValue;
+};
+
+KisUniformPaintOpProperty::KisUniformPaintOpProperty(Type type,
+ const QString &id,
+ const QString &name,
+ KisPaintOpSettingsSP settings,
+ QObject *parent)
+ : QObject(parent),
+ m_d(new Private(type, id, name, settings))
+{
+}
+
+KisUniformPaintOpProperty::~KisUniformPaintOpProperty()
+{
+}
+
+QString KisUniformPaintOpProperty::id() const
+{
+ return m_d->id;
+}
+
+QString KisUniformPaintOpProperty::name() const
+{
+ return m_d->name;
+}
+
+KisUniformPaintOpProperty::Type KisUniformPaintOpProperty::type() const
+{
+ return m_d->type;
+}
+
+QVariant KisUniformPaintOpProperty::value() const
+{
+ return m_d->value;
+}
+
+QWidget *KisUniformPaintOpProperty::createPropertyWidget()
+{
+ return 0;
+}
+
+void KisUniformPaintOpProperty::setValue(const QVariant &value)
+{
+ if (m_d->value == value) return;
+ m_d->value = value;
+
+ emit valueChanged(value);
+
+ if (!m_d->isReadingValue) {
+ m_d->isWritingValue = true;
+ writeValueImpl();
+ m_d->isWritingValue = false;
+ }
+}
+
+void KisUniformPaintOpProperty::requestReadValue()
+{
+ if (m_d->isWritingValue) return;
+
+ m_d->isReadingValue = true;
+ readValueImpl();
+ m_d->isReadingValue = false;
+}
+
+KisPaintOpSettingsSP KisUniformPaintOpProperty::settings() const
+{
+ // correct conversion weak-to-strong shared pointer
+ return m_d->settings ? m_d->settings : 0;
+}
+
+bool KisUniformPaintOpProperty::isVisible() const
+{
+ return true;
+}
+
+void KisUniformPaintOpProperty::readValueImpl()
+{
+}
+
+void KisUniformPaintOpProperty::writeValueImpl()
+{
+}
+
diff --git a/libs/image/kis_acyclic_signal_connector.h b/libs/image/kis_acyclic_signal_connector.h
--- a/libs/image/kis_acyclic_signal_connector.h
+++ b/libs/image/kis_acyclic_signal_connector.h
@@ -73,6 +73,12 @@
void connectBackwardVoid(QObject *sender, const char *signal,
QObject *receiver, const char *method);
+ void connectForwardVariant(QObject *sender, const char *signal,
+ QObject *receiver, const char *method);
+
+ void connectBackwardVariant(QObject *sender, const char *signal,
+ QObject *receiver, const char *method);
+
private Q_SLOTS:
void forwardSlotDouble(double value);
void backwardSlotDouble(double value);
@@ -86,6 +92,9 @@
void forwardSlotVoid();
void backwardSlotVoid();
+ void forwardSlotVariant(const QVariant &value);
+ void backwardSlotVariant(const QVariant &value);
+
Q_SIGNALS:
void forwardSignalDouble(double value);
void backwardSignalDouble(double value);
@@ -99,6 +108,9 @@
void forwardSignalVoid();
void backwardSignalVoid();
+ void forwardSignalVariant(const QVariant &value);
+ void backwardSignalVariant(const QVariant &value);
+
private:
int m_signalsBlocked;
};
diff --git a/libs/image/kis_acyclic_signal_connector.cpp b/libs/image/kis_acyclic_signal_connector.cpp
--- a/libs/image/kis_acyclic_signal_connector.cpp
+++ b/libs/image/kis_acyclic_signal_connector.cpp
@@ -91,6 +91,21 @@
connect(this, SIGNAL(backwardSignalVoid()), receiver, method);
}
+void KisAcyclicSignalConnector::connectForwardVariant(QObject *sender, const char *signal,
+ QObject *receiver, const char *method)
+{
+
+ connect(sender, signal, this, SLOT(forwardSlotVariant(const QVariant&)));
+ connect(this, SIGNAL(forwardSignalVariant(const QVariant&)), receiver, method);
+}
+
+void KisAcyclicSignalConnector::connectBackwardVariant(QObject *sender, const char *signal,
+ QObject *receiver, const char *method)
+{
+ connect(sender, signal, this, SLOT(backwardSlotVariant(const QVariant&)));
+ connect(this, SIGNAL(backwardSignalVariant(const QVariant&)), receiver, method);
+}
+
void KisAcyclicSignalConnector::forwardSlotDouble(double value)
{
if (m_signalsBlocked) return;
@@ -163,3 +178,20 @@
m_signalsBlocked--;
}
+void KisAcyclicSignalConnector::forwardSlotVariant(const QVariant &value)
+{
+ if (m_signalsBlocked) return;
+
+ m_signalsBlocked++;
+ emit forwardSignalVariant(value);
+ m_signalsBlocked--;
+}
+
+void KisAcyclicSignalConnector::backwardSlotVariant(const QVariant &value)
+{
+ if (m_signalsBlocked) return;
+
+ m_signalsBlocked++;
+ emit backwardSignalVariant(value);
+ m_signalsBlocked--;
+}
diff --git a/libs/image/kis_config_widget.h b/libs/image/kis_config_widget.h
--- a/libs/image/kis_config_widget.h
+++ b/libs/image/kis_config_widget.h
@@ -86,7 +86,6 @@
private:
KisSignalCompressor m_compressor;
- int m_delay;
};
diff --git a/libs/image/kis_config_widget.cpp b/libs/image/kis_config_widget.cpp
--- a/libs/image/kis_config_widget.cpp
+++ b/libs/image/kis_config_widget.cpp
@@ -24,23 +24,24 @@
: QWidget(parent, f)
, m_compressor(delay, KisSignalCompressor::FIRST_ACTIVE)
{
- connect(&m_compressor, SIGNAL(timeout()), SLOT(slotConfigChanged()));
- connect(this, SIGNAL(sigConfigurationItemChanged()), &m_compressor, SLOT(start()));
+ connect(this, SIGNAL(sigConfigurationItemChanged()), SLOT(slotConfigChanged()));
+ connect(&m_compressor, SIGNAL(timeout()), SIGNAL(sigConfigurationUpdated()));
}
KisConfigWidget::~KisConfigWidget()
{
}
void KisConfigWidget::slotConfigChanged()
{
- emit sigConfigurationUpdated();
+ if (!signalsBlocked()) {
+ m_compressor.start();
+ }
}
void KisConfigWidget::setView(KisViewManager *view)
{
if (!view) {
warnKrita << "KisConfigWidget::setView has got view == 0. That's a bug! Please report it!";
}
}
-
diff --git a/libs/image/kis_convolution_painter.cc b/libs/image/kis_convolution_painter.cc
--- a/libs/image/kis_convolution_painter.cc
+++ b/libs/image/kis_convolution_painter.cc
@@ -24,8 +24,6 @@
#include
#include
-#include
-#include
#include
#include
#include
diff --git a/libs/image/kis_progress_update_helper.h b/libs/image/kis_progress_update_helper.h
--- a/libs/image/kis_progress_update_helper.h
+++ b/libs/image/kis_progress_update_helper.h
@@ -26,6 +26,7 @@
public:
KisProgressUpdateHelper(KoUpdaterPtr progressUpdater, int portion, int numSteps)
: m_progressUpdater(progressUpdater),
+ m_baseProgress(0),
m_portion(portion),
m_currentStep(0),
m_numSteps(numSteps)
diff --git a/libs/image/kis_signal_auto_connection.h b/libs/image/kis_signal_auto_connection.h
--- a/libs/image/kis_signal_auto_connection.h
+++ b/libs/image/kis_signal_auto_connection.h
@@ -21,6 +21,8 @@
#include
#include
+#include
+
/**
* A special wrapper class that represents a connection between two QObject objects.
diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt
--- a/libs/ui/CMakeLists.txt
+++ b/libs/ui/CMakeLists.txt
@@ -78,6 +78,9 @@
flake/kis_shape_selection_canvas.cpp
flake/kis_shape_selection_model.cpp
flake/kis_take_all_shapes_command.cpp
+ brushhud/kis_uniform_paintop_property_widget.cpp
+ brushhud/kis_brush_hud.cpp
+ brushhud/kis_round_hud_button.cpp
kis_aspect_ratio_locker.cpp
kis_autogradient.cc
kis_bookmarked_configurations_editor.cc
diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp
--- a/libs/ui/KisViewManager.cpp
+++ b/libs/ui/KisViewManager.cpp
@@ -187,8 +187,11 @@
canvasResourceManager.addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter));
canvasResourceManager.addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter));
canvasResourceManager.addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter));
+ canvasResourceManager.addDerivedResourceConverter(toQShared(new KisFlowResourceConverter));
+ canvasResourceManager.addDerivedResourceConverter(toQShared(new KisSizeResourceConverter));
canvasResourceManager.addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter));
canvasResourceManager.addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter));
+ canvasResourceManager.addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator));
}
public:
diff --git a/libs/ui/kis_aspect_ratio_locker.h b/libs/ui/brushhud/kis_brush_hud.h
copy from libs/ui/kis_aspect_ratio_locker.h
copy to libs/ui/brushhud/kis_brush_hud.h
--- a/libs/ui/kis_aspect_ratio_locker.h
+++ b/libs/ui/brushhud/kis_brush_hud.h
@@ -16,38 +16,39 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ASPECT_RATIO_LOCKER_H
-#define __KIS_ASPECT_RATIO_LOCKER_H
+#ifndef __KIS_BRUSH_HUD_H
+#define __KIS_BRUSH_HUD_H
#include
-#include
-#include "kritaui_export.h"
+#include
-class QSpinBox;
-class KoAspectButton;
+class KisCanvasResourceProvider;
-class KRITAUI_EXPORT KisAspectRatioLocker : public QObject
+class KisBrushHud : public QWidget
{
Q_OBJECT
public:
- KisAspectRatioLocker(QObject *parent);
- ~KisAspectRatioLocker();
+ KisBrushHud(KisCanvasResourceProvider *provider, QWidget *parent);
+ ~KisBrushHud();
- void connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *apectButton);
+ void updateProperties();
+protected:
+ void paintEvent(QPaintEvent *event);
+ bool event(QEvent *event);
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
private Q_SLOTS:
- void slotSpinOneChanged();
- void slotSpinTwoChanged();
- void slotAspectButtonChanged();
+ void slotCanvasResourceChanged(int key, const QVariant &resource);
+ void slotReloadProperties();
-Q_SIGNALS:
- void sliderValueChanged();
- void aspectButtonChanged();
+private:
+ void clearProperties() const;
private:
struct Private;
const QScopedPointer m_d;
};
-#endif /* __KIS_ASPECT_RATIO_LOCKER_H */
+#endif /* __KIS_BRUSH_HUD_H */
diff --git a/libs/ui/brushhud/kis_brush_hud.cpp b/libs/ui/brushhud/kis_brush_hud.cpp
new file mode 100644
--- /dev/null
+++ b/libs/ui/brushhud/kis_brush_hud.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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_brush_hud.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "kis_uniform_paintop_property.h"
+#include "kis_slider_based_paintop_property.h"
+#include "kis_uniform_paintop_property_widget.h"
+#include "kis_canvas_resource_provider.h"
+#include "kis_paintop_preset.h"
+#include "kis_paintop_settings.h"
+#include "kis_signal_auto_connection.h"
+#include "kis_paintop_settings_update_proxy.h"
+
+#include "kis_debug.h"
+
+
+struct KisBrushHud::Private
+{
+ QPointer lblPresetName;
+ QPointer wdgProperties;
+ QPointer wdgPropertiesArea;
+ QPointer propertiesLayout;
+
+ KisCanvasResourceProvider *provider;
+
+ KisSignalAutoConnectionsStore connections;
+ KisSignalAutoConnectionsStore presetConnections;
+
+ KisPaintOpPresetSP currentPreset;
+};
+
+KisBrushHud::KisBrushHud(KisCanvasResourceProvider *provider, QWidget *parent)
+ : QWidget(parent, Qt::FramelessWindowHint),
+ m_d(new Private)
+{
+ m_d->provider = provider;
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ m_d->lblPresetName = new QLabel("", this);
+ layout->addWidget(m_d->lblPresetName);
+
+ m_d->wdgPropertiesArea = new QScrollArea(this);
+ m_d->wdgPropertiesArea->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ m_d->wdgPropertiesArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ m_d->wdgPropertiesArea->setWidgetResizable(true);
+
+ m_d->wdgProperties = new QWidget(this);
+ m_d->propertiesLayout = new QVBoxLayout(this);
+ m_d->propertiesLayout->setSpacing(0);
+ m_d->propertiesLayout->setContentsMargins(0, 0, 22, 0);
+ m_d->propertiesLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
+
+ // not adding any widgets until explicitly requested
+
+ m_d->wdgProperties->setLayout(m_d->propertiesLayout);
+ m_d->wdgPropertiesArea->setWidget(m_d->wdgProperties);
+ layout->addWidget(m_d->wdgPropertiesArea);
+
+ setLayout(layout);
+ setCursor(Qt::ArrowCursor);
+}
+
+KisBrushHud::~KisBrushHud()
+{
+}
+
+void KisBrushHud::slotReloadProperties()
+{
+ m_d->presetConnections.clear();
+ clearProperties();
+ updateProperties();
+}
+
+void KisBrushHud::clearProperties() const
+{
+ Q_FOREACH (QWidget *w, m_d->wdgProperties->findChildren()) {
+ w->deleteLater();
+ }
+ m_d->currentPreset.clear();
+}
+
+void KisBrushHud::updateProperties()
+{
+ KisPaintOpPresetSP preset = m_d->provider->currentPreset();
+ KisPaintOpSettingsSP settings = preset->settings();
+
+ if (preset == m_d->currentPreset) return;
+
+ m_d->presetConnections.clear();
+ clearProperties();
+
+ m_d->currentPreset = preset;
+ m_d->presetConnections.addConnection(
+ m_d->currentPreset->updateProxy(), SIGNAL(sigUniformPropertiesChanged()),
+ this, SLOT(slotReloadProperties()));
+
+ m_d->lblPresetName->setText(preset->name());
+
+ QList properties = settings->uniformProperties();
+ Q_FOREACH(auto property, properties) {
+ QWidget *w = 0;
+
+ if (!property->isVisible()) continue;
+
+ if (property->type() == KisUniformPaintOpProperty::Int) {
+ w = new KisUniformPaintOpPropertyIntSlider(property, m_d->wdgProperties);
+ } else if (property->type() == KisUniformPaintOpProperty::Double) {
+ w = new KisUniformPaintOpPropertyDoubleSlider(property, m_d->wdgProperties);
+ } else if (property->type() == KisUniformPaintOpProperty::Bool) {
+ w = new KisUniformPaintOpPropertyCheckBox(property, m_d->wdgProperties);
+ } else if (property->type() == KisUniformPaintOpProperty::Combo) {
+ w = new KisUniformPaintOpPropertyComboBox(property, m_d->wdgProperties);
+ }
+
+ if (w) {
+ w->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ m_d->propertiesLayout->addWidget(w);
+ }
+ }
+}
+
+void KisBrushHud::showEvent(QShowEvent *event)
+{
+ m_d->connections.clear();
+ m_d->connections.addUniqueConnection(
+ m_d->provider->resourceManager(), SIGNAL(canvasResourceChanged(int, QVariant)),
+ this, SLOT(slotCanvasResourceChanged(int, QVariant)));
+
+ updateProperties();
+
+ QWidget::showEvent(event);
+}
+
+void KisBrushHud::hideEvent(QHideEvent *event)
+{
+ m_d->connections.clear();
+ QWidget::hideEvent(event);
+
+ clearProperties();
+}
+
+void KisBrushHud::slotCanvasResourceChanged(int key, const QVariant &resource)
+{
+ Q_UNUSED(resource);
+
+ if (key == KisCanvasResourceProvider::CurrentPaintOpPreset) {
+ updateProperties();
+ }
+}
+
+void KisBrushHud::paintEvent(QPaintEvent *event)
+{
+ QColor bgColor = palette().color(QPalette::Window);
+
+ QPainter painter(this);
+ painter.fillRect(rect() & event->rect(), bgColor);
+ painter.end();
+
+ QWidget::paintEvent(event);
+}
+
+bool KisBrushHud::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::TabletPress:
+ case QEvent::TabletMove:
+ case QEvent::TabletRelease:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ case QEvent::Wheel:
+ event->accept();
+ return true;
+ }
+
+ return QWidget::event(event);
+}
diff --git a/libs/ui/kis_aspect_ratio_locker.h b/libs/ui/brushhud/kis_round_hud_button.h
copy from libs/ui/kis_aspect_ratio_locker.h
copy to libs/ui/brushhud/kis_round_hud_button.h
--- a/libs/ui/kis_aspect_ratio_locker.h
+++ b/libs/ui/brushhud/kis_round_hud_button.h
@@ -16,38 +16,32 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ASPECT_RATIO_LOCKER_H
-#define __KIS_ASPECT_RATIO_LOCKER_H
+#ifndef __KIS_ROUND_HUD_BUTTON_H
+#define __KIS_ROUND_HUD_BUTTON_H
#include
-#include
-#include "kritaui_export.h"
+#include
-class QSpinBox;
-class KoAspectButton;
-class KRITAUI_EXPORT KisAspectRatioLocker : public QObject
+
+class KisRoundHudButton : public QAbstractButton
{
- Q_OBJECT
public:
- KisAspectRatioLocker(QObject *parent);
- ~KisAspectRatioLocker();
-
- void connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *apectButton);
+ KisRoundHudButton(QWidget *parent);
+ ~KisRoundHudButton();
+ void setOnOffIcons(const QIcon &on, const QIcon &off);
-private Q_SLOTS:
- void slotSpinOneChanged();
- void slotSpinTwoChanged();
- void slotAspectButtonChanged();
+protected:
+ void paintEvent(QPaintEvent *event);
+ bool hitButton(const QPoint &pos) const;
-Q_SIGNALS:
- void sliderValueChanged();
- void aspectButtonChanged();
+ void mouseMoveEvent(QMouseEvent *event);
+ void leaveEvent(QEvent *event);
private:
struct Private;
const QScopedPointer m_d;
};
-#endif /* __KIS_ASPECT_RATIO_LOCKER_H */
+#endif /* __KIS_ROUND_HUD_BUTTON_H */
diff --git a/libs/ui/brushhud/kis_round_hud_button.cpp b/libs/ui/brushhud/kis_round_hud_button.cpp
new file mode 100644
--- /dev/null
+++ b/libs/ui/brushhud/kis_round_hud_button.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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_round_hud_button.h"
+
+#include
+#include
+
+#include "kis_global.h"
+
+
+
+struct KisRoundHudButton::Private
+{
+ Private() : isHighlighted(false) {}
+
+ bool isHighlighted;
+ QIcon onIcon;
+ QIcon offIcon;
+};
+
+KisRoundHudButton::KisRoundHudButton(QWidget *parent)
+ : QAbstractButton(parent),
+ m_d(new Private)
+{
+ setMouseTracking(true);
+}
+
+KisRoundHudButton::~KisRoundHudButton()
+{
+}
+
+void KisRoundHudButton::setOnOffIcons(const QIcon &on, const QIcon &off)
+{
+ m_d->onIcon = on;
+ m_d->offIcon = off;
+}
+
+void KisRoundHudButton::paintEvent(QPaintEvent *event)
+{
+ const int borderWidth = 3;
+ const QPointF center = QRectF(rect()).center();
+ const qreal radius = 0.5 * (center.x() + center.y()) - borderWidth;
+
+ const QPen fgPen(palette().color(m_d->isHighlighted ? QPalette::Highlight : QPalette::WindowText), borderWidth);
+ const QBrush bgBrush(palette().brush(isDown() || (isCheckable() && isChecked()) ? QPalette::Mid : QPalette::Window));
+
+ QPainter painter(this);
+ painter.setPen(fgPen);
+ painter.setBrush(bgBrush);
+ painter.setRenderHints(QPainter::Antialiasing);
+
+ painter.drawEllipse(center, radius, radius);
+
+ if (!icon().isNull()) {
+ const QIcon::Mode mode = isEnabled() ? QIcon::Normal : QIcon::Disabled;
+ const QIcon::State state = isCheckable() && isChecked() ? QIcon::On : QIcon::Off;
+ const QSize size = iconSize();
+
+ QPixmap pixmap = icon().pixmap(size, mode, state);
+
+ QPointF iconOffset(0.5 * (width() - pixmap.width()),
+ 0.5 * (height() - pixmap.height()));
+
+ painter.drawPixmap(iconOffset, pixmap);
+ }
+
+ if (!m_d->onIcon.isNull() && !m_d->onIcon.isNull()) {
+ const QIcon::Mode mode = isEnabled() ? QIcon::Normal : QIcon::Disabled;
+ const QIcon icon = isCheckable() && isChecked() ? m_d->onIcon : m_d->offIcon;
+ const QSize size = iconSize();
+
+ QPixmap pixmap = icon.pixmap(size, mode);
+ QPointF iconOffset(0.5 * (width() - pixmap.width()),
+ 0.5 * (height() - pixmap.height()));
+
+ painter.drawPixmap(iconOffset, pixmap);
+ }
+}
+
+bool KisRoundHudButton::hitButton(const QPoint &pos) const
+{
+ const int borderWidth = 3;
+ const QPointF center = QRectF(rect()).center();
+ const qreal radius = 0.5 * (center.x() + center.y()) - borderWidth;
+
+ return kisDistance(center, pos) < radius;
+}
+
+void KisRoundHudButton::mouseMoveEvent(QMouseEvent *event)
+{
+ m_d->isHighlighted = hitButton(event->pos());
+ QAbstractButton::mouseMoveEvent(event);
+}
+
+void KisRoundHudButton::leaveEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+ m_d->isHighlighted = false;
+
+ QAbstractButton::leaveEvent(event);
+}
diff --git a/libs/ui/brushhud/kis_uniform_paintop_property_widget.h b/libs/ui/brushhud/kis_uniform_paintop_property_widget.h
new file mode 100644
--- /dev/null
+++ b/libs/ui/brushhud/kis_uniform_paintop_property_widget.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#ifndef __KIS_UNIFORM_PAINTOP_PROPERTY_WIDGET_H
+#define __KIS_UNIFORM_PAINTOP_PROPERTY_WIDGET_H
+
+#include
+#include
+
+#include "kis_uniform_paintop_property.h"
+
+
+class KisUniformPaintOpPropertyWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ KisUniformPaintOpPropertyWidget(KisUniformPaintOpPropertySP property, QWidget *parent);
+ ~KisUniformPaintOpPropertyWidget();
+
+protected:
+ KisUniformPaintOpPropertySP property() const;
+
+protected Q_SLOTS:
+ virtual void setValue(const QVariant &value) = 0;
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &value);
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
+
+class KisSliderSpinBox;
+class KisDoubleSliderSpinBox;
+class QCheckBox;
+
+template class KisSliderBasedPaintOpProperty;
+typedef KisSliderBasedPaintOpProperty KisIntSliderBasedPaintOpProperty;
+typedef KisSliderBasedPaintOpProperty KisDoubleSliderBasedPaintOpProperty;
+
+class KisUniformPaintOpPropertyIntSlider : public KisUniformPaintOpPropertyWidget
+{
+ Q_OBJECT
+public:
+ KisUniformPaintOpPropertyIntSlider(KisUniformPaintOpPropertySP property, QWidget *parent);
+
+ virtual void setValue(const QVariant &value);
+
+private Q_SLOTS:
+ void slotSliderChanged(int value);
+
+private:
+ KisSliderSpinBox *m_slider;
+};
+
+class KisUniformPaintOpPropertyDoubleSlider : public KisUniformPaintOpPropertyWidget
+{
+ Q_OBJECT
+public:
+ KisUniformPaintOpPropertyDoubleSlider(KisUniformPaintOpPropertySP property, QWidget *parent);
+
+ virtual void setValue(const QVariant &value);
+
+private Q_SLOTS:
+ void slotSliderChanged(qreal value);
+
+private:
+ KisDoubleSliderSpinBox *m_slider;
+};
+
+class KisUniformPaintOpPropertyCheckBox : public KisUniformPaintOpPropertyWidget
+{
+ Q_OBJECT
+public:
+ KisUniformPaintOpPropertyCheckBox(KisUniformPaintOpPropertySP property, QWidget *parent);
+
+ virtual void setValue(const QVariant &value);
+
+private Q_SLOTS:
+ void slotCheckBoxChanged(bool value);
+
+private:
+ QCheckBox *m_checkBox;
+};
+
+class QComboBox;
+
+class KisUniformPaintOpPropertyComboBox : public KisUniformPaintOpPropertyWidget
+{
+ Q_OBJECT
+public:
+ KisUniformPaintOpPropertyComboBox(KisUniformPaintOpPropertySP property, QWidget *parent);
+
+ virtual void setValue(const QVariant &value);
+
+private Q_SLOTS:
+ void slotComboBoxChanged(int value);
+
+private:
+ QComboBox *m_comboBox;
+};
+
+#endif /* __KIS_UNIFORM_PAINTOP_PROPERTY_WIDGET_H */
diff --git a/libs/ui/brushhud/kis_uniform_paintop_property_widget.cpp b/libs/ui/brushhud/kis_uniform_paintop_property_widget.cpp
new file mode 100644
--- /dev/null
+++ b/libs/ui/brushhud/kis_uniform_paintop_property_widget.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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_uniform_paintop_property_widget.h"
+
+#include
+#include
+#include
+
+#include "kis_slider_spin_box.h"
+#include "kis_acyclic_signal_connector.h"
+#include "kis_slider_based_paintop_property.h"
+#include "kis_combo_based_paintop_property.h"
+#include "kis_debug.h"
+
+/****************************************************************/
+/* KisUniformPaintOpPropertyWidget */
+/****************************************************************/
+
+struct KisUniformPaintOpPropertyWidget::Private
+{
+ Private(KisUniformPaintOpPropertySP _property)
+ : property(_property) {}
+
+ typedef KisUniformPaintOpProperty::Type Type;
+ KisUniformPaintOpPropertySP property;
+};
+
+KisUniformPaintOpPropertyWidget::KisUniformPaintOpPropertyWidget(KisUniformPaintOpPropertySP property, QWidget *parent)
+ : QWidget(parent),
+ m_d(new Private(property))
+{
+ KisAcyclicSignalConnector *conn = new KisAcyclicSignalConnector(this);
+ conn->connectForwardVariant(property.data(), SIGNAL(valueChanged(const QVariant&)),
+ this, SLOT(setValue(const QVariant&)));
+
+ conn->connectBackwardVariant(this, SIGNAL(valueChanged(const QVariant&)),
+ property.data(), SLOT(setValue(const QVariant&)));
+}
+
+KisUniformPaintOpPropertyWidget::~KisUniformPaintOpPropertyWidget()
+{
+}
+
+KisUniformPaintOpPropertySP KisUniformPaintOpPropertyWidget::property() const
+{
+ return m_d->property;
+}
+
+/****************************************************************/
+/* KisUniformPaintOpPropertyIntSlider */
+/****************************************************************/
+
+KisUniformPaintOpPropertyIntSlider::KisUniformPaintOpPropertyIntSlider(KisUniformPaintOpPropertySP property, QWidget *parent)
+ : KisUniformPaintOpPropertyWidget(property, parent)
+{
+ const QString prefix = QString("%1: ").arg(property->name());
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ KisIntSliderBasedPaintOpProperty *sliderProperty =
+ dynamic_cast(property.data());
+ KIS_ASSERT_RECOVER_RETURN(sliderProperty);
+
+ m_slider = new KisSliderSpinBox(this);
+ m_slider->setBlockUpdateSignalOnDrag(true);
+ m_slider->setRange(sliderProperty->min(), sliderProperty->max());
+ m_slider->setSingleStep(sliderProperty->singleStep());
+ m_slider->setPageStep(sliderProperty->pageStep());
+ m_slider->setPrefix(prefix);
+ m_slider->setSuffix(sliderProperty->suffix());
+ m_slider->setExponentRatio(sliderProperty->exponentRatio());
+
+ m_slider->setValue(sliderProperty->value().toInt());
+ connect(m_slider, SIGNAL(valueChanged(int)), SLOT(slotSliderChanged(int)));
+
+ layout->addWidget(m_slider);
+ setLayout(layout);
+}
+
+void KisUniformPaintOpPropertyIntSlider::setValue(const QVariant &value)
+{
+ m_slider->setValue(value.toInt());
+}
+
+void KisUniformPaintOpPropertyIntSlider::slotSliderChanged(int value)
+{
+ emit valueChanged(value);
+}
+
+/****************************************************************/
+/* KisUniformPaintOpPropertyDoubleSlider */
+/****************************************************************/
+
+KisUniformPaintOpPropertyDoubleSlider::KisUniformPaintOpPropertyDoubleSlider(KisUniformPaintOpPropertySP property, QWidget *parent)
+ : KisUniformPaintOpPropertyWidget(property, parent)
+{
+ const QString prefix = QString("%1: ").arg(property->name());
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ KisDoubleSliderBasedPaintOpProperty *sliderProperty =
+ dynamic_cast(property.data());
+ KIS_ASSERT_RECOVER_RETURN(sliderProperty);
+
+ m_slider = new KisDoubleSliderSpinBox(this);
+ m_slider->setBlockUpdateSignalOnDrag(true);
+ m_slider->setRange(sliderProperty->min(), sliderProperty->max(), sliderProperty->decimals());
+ m_slider->setSingleStep(sliderProperty->singleStep());
+ m_slider->setPrefix(prefix);
+ m_slider->setSuffix(sliderProperty->suffix());
+ m_slider->setExponentRatio(sliderProperty->exponentRatio());
+
+ m_slider->setValue(sliderProperty->value().toReal());
+ connect(m_slider, SIGNAL(valueChanged(qreal)), SLOT(slotSliderChanged(qreal)));
+
+ layout->addWidget(m_slider);
+ setLayout(layout);
+}
+
+void KisUniformPaintOpPropertyDoubleSlider::setValue(const QVariant &value)
+{
+ m_slider->setValue(value.toReal());
+}
+
+void KisUniformPaintOpPropertyDoubleSlider::slotSliderChanged(qreal value)
+{
+ emit valueChanged(value);
+}
+
+/****************************************************************/
+/* KisUniformPaintOpPropertyCheckBox */
+/****************************************************************/
+
+KisUniformPaintOpPropertyCheckBox::KisUniformPaintOpPropertyCheckBox(KisUniformPaintOpPropertySP property, QWidget *parent)
+ : KisUniformPaintOpPropertyWidget(property, parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ m_checkBox = new QCheckBox(property->name(), this);
+ m_checkBox->setChecked(property->value().toBool());
+ connect(m_checkBox, SIGNAL(toggled(bool)), SLOT(slotCheckBoxChanged(bool)));
+
+ layout->addWidget(m_checkBox);
+ setLayout(layout);
+}
+
+void KisUniformPaintOpPropertyCheckBox::setValue(const QVariant &value)
+{
+ m_checkBox->setChecked(value.toBool());
+}
+
+void KisUniformPaintOpPropertyCheckBox::slotCheckBoxChanged(bool value)
+{
+ emit valueChanged(value);
+}
+
+/****************************************************************/
+/* KisUniformPaintOpPropertyComboBox */
+/****************************************************************/
+
+KisUniformPaintOpPropertyComboBox::KisUniformPaintOpPropertyComboBox(KisUniformPaintOpPropertySP property, QWidget *parent)
+ : KisUniformPaintOpPropertyWidget(property, parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ KisComboBasedPaintOpProperty *comboProperty =
+ dynamic_cast(property.data());
+ KIS_ASSERT_RECOVER_RETURN(comboProperty);
+
+ const QList items = comboProperty->items();
+ const QList icons = comboProperty->icons();
+
+ m_comboBox = new QComboBox(this);
+
+ KIS_SAFE_ASSERT_RECOVER_RETURN(icons.isEmpty() ||
+ items.size() == icons.size());
+
+ if (!icons.isEmpty()) {
+ auto itemIt = items.constBegin();
+ auto iconIt = icons.constBegin();
+
+ while (itemIt != items.constEnd() &&
+ iconIt != icons.constEnd()) {
+
+ m_comboBox->addItem(*iconIt, *itemIt);
+
+ ++itemIt;
+ ++iconIt;
+ }
+ } else {
+ Q_FOREACH (const QString &item, items) {
+ m_comboBox->addItem(item);
+ }
+ }
+
+ m_comboBox->setCurrentIndex(property->value().toInt());
+ connect(m_comboBox, SIGNAL(currentIndexChanged(int)), SLOT(slotComboBoxChanged(int)));
+
+ layout->addWidget(m_comboBox);
+ setLayout(layout);
+}
+
+void KisUniformPaintOpPropertyComboBox::setValue(const QVariant &value)
+{
+ m_comboBox->setCurrentIndex(value.toInt());
+}
+
+void KisUniformPaintOpPropertyComboBox::slotComboBoxChanged(int value)
+{
+ emit valueChanged(value);
+}
diff --git a/libs/ui/canvas/kis_canvas2.cpp b/libs/ui/canvas/kis_canvas2.cpp
--- a/libs/ui/canvas/kis_canvas2.cpp
+++ b/libs/ui/canvas/kis_canvas2.cpp
@@ -853,7 +853,7 @@
void KisCanvas2::setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager)
{
- m_d->popupPalette = new KisPopupPalette(favoriteResourceManager, displayColorConverter()->displayRendererInterface(), m_d->canvasWidget->widget());
+ m_d->popupPalette = new KisPopupPalette(favoriteResourceManager, displayColorConverter()->displayRendererInterface(), m_d->view->resourceProvider(), m_d->canvasWidget->widget());
m_d->popupPalette->showPopupPalette(false);
}
diff --git a/libs/ui/kis_aspect_ratio_locker.h b/libs/ui/kis_aspect_ratio_locker.h
--- a/libs/ui/kis_aspect_ratio_locker.h
+++ b/libs/ui/kis_aspect_ratio_locker.h
@@ -24,17 +24,22 @@
#include "kritaui_export.h"
class QSpinBox;
+class QDoubleSpinBox;
+class KisSliderSpinBox;
+class KisDoubleSliderSpinBox;
class KoAspectButton;
class KRITAUI_EXPORT KisAspectRatioLocker : public QObject
{
Q_OBJECT
public:
- KisAspectRatioLocker(QObject *parent);
+ KisAspectRatioLocker(QObject *parent = 0);
~KisAspectRatioLocker();
- void connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *apectButton);
+ template
+ void connectSpinBoxes(SpinBoxType *spinOne, SpinBoxType *spinTwo, KoAspectButton *aspectButton);
+ void setBlockUpdateSignalOnDrag(bool block);
private Q_SLOTS:
void slotSpinOneChanged();
diff --git a/libs/ui/kis_aspect_ratio_locker.cpp b/libs/ui/kis_aspect_ratio_locker.cpp
--- a/libs/ui/kis_aspect_ratio_locker.cpp
+++ b/libs/ui/kis_aspect_ratio_locker.cpp
@@ -19,20 +19,88 @@
#include "kis_aspect_ratio_locker.h"
#include
+#include
+
#include
#include "kis_signals_blocker.h"
+#include "kis_assert.h"
+#include "kis_debug.h"
+#include "kis_slider_spin_box.h"
-struct KisAspectRatioLocker::Private
+struct SliderWrapper
{
- Private() : aspectRatio(1.0) {}
+ template
+ SliderWrapper(Slider *slider)
+ : m_slider(QVariant::fromValue(slider)),
+ m_object(slider) {}
+
+ void setValue(qreal value) {
+
+ if (m_slider.canConvert()) {
+ m_slider.value()->setValue(qRound(value));
+
+ } else if (m_slider.canConvert()) {
+ m_slider.value()->setValue(value);
+
+ } else if (m_slider.canConvert()) {
+ m_slider.value()->setValue(qRound(value));
+
+ } else if (m_slider.canConvert()) {
+ m_slider.value()->setValue(value);
+ }
+ }
+
+ qreal value() const {
+ qreal result = 0.0;
+
+ if (m_slider.canConvert()) {
+ result = m_slider.value()->value();
- QSpinBox *spinOne;
- QSpinBox *spinTwo;
- KoAspectButton *aspectButton;
+ } else if (m_slider.canConvert()) {
+ result = m_slider.value()->value();
+
+ } else if (m_slider.canConvert()) {
+ result = m_slider.value()->value();
+
+ } else if (m_slider.canConvert()) {
+ result = m_slider.value()->value();
+ }
+
+ return result;
+ }
+
+ bool isDragging() const {
+ bool result = false;
+
+ if (m_slider.canConvert()) {
+ result = m_slider.value()->isDragging();
+
+ } else if (m_slider.canConvert()) {
+ result = m_slider.value()->isDragging();
+ }
+
+ return result;
+ }
- qreal aspectRatio;
+ QObject* object() const {
+ return m_object;
+ }
+
+private:
+ QVariant m_slider;
+ QObject *m_object;
+};
+
+struct KisAspectRatioLocker::Private
+{
+ QScopedPointer spinOne;
+ QScopedPointer spinTwo;
+ KoAspectButton *aspectButton = 0;
+
+ qreal aspectRatio = 1.0;
+ bool blockUpdatesOnDrag = false;
};
@@ -46,37 +114,52 @@
{
}
-void KisAspectRatioLocker::connectSpinBoxes(QSpinBox *spinOne,
- QSpinBox *spinTwo,
- KoAspectButton *aspectButton)
+template
+void KisAspectRatioLocker::connectSpinBoxes(SpinBoxType *spinOne, SpinBoxType *spinTwo, KoAspectButton *aspectButton)
{
- m_d->spinOne = spinOne;
- m_d->spinTwo = spinTwo;
+ m_d->spinOne.reset(new SliderWrapper(spinOne));
+ m_d->spinTwo.reset(new SliderWrapper(spinTwo));
m_d->aspectButton = aspectButton;
- connect(m_d->spinOne, SIGNAL(valueChanged(int)), SLOT(slotSpinOneChanged()));
- connect(m_d->spinTwo, SIGNAL(valueChanged(int)), SLOT(slotSpinTwoChanged()));
+ if (QVariant::fromValue(spinOne->value()).type() == QVariant::Double) {
+ connect(spinOne, SIGNAL(valueChanged(qreal)), SLOT(slotSpinOneChanged()));
+ connect(spinTwo, SIGNAL(valueChanged(qreal)), SLOT(slotSpinTwoChanged()));
+ } else {
+ connect(spinOne, SIGNAL(valueChanged(int)), SLOT(slotSpinOneChanged()));
+ connect(spinTwo, SIGNAL(valueChanged(int)), SLOT(slotSpinTwoChanged()));
+ }
+
connect(m_d->aspectButton, SIGNAL(keepAspectRatioChanged(bool)), SLOT(slotAspectButtonChanged()));
slotAspectButtonChanged();
}
+template void KisAspectRatioLocker::connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *aspectButton);
+template void KisAspectRatioLocker::connectSpinBoxes(QDoubleSpinBox *spinOne, QDoubleSpinBox *spinTwo, KoAspectButton *aspectButton);
+template void KisAspectRatioLocker::connectSpinBoxes(KisSliderSpinBox *spinOne, KisSliderSpinBox *spinTwo, KoAspectButton *aspectButton);
+template void KisAspectRatioLocker::connectSpinBoxes(KisDoubleSliderSpinBox *spinOne, KisDoubleSliderSpinBox *spinTwo, KoAspectButton *aspectButton);
+
void KisAspectRatioLocker::slotSpinOneChanged()
{
if (m_d->aspectButton->keepAspectRatio()) {
- KisSignalsBlocker b(m_d->spinTwo);
- m_d->spinTwo->setValue(qRound(m_d->aspectRatio * m_d->spinOne->value()));
+ KisSignalsBlocker b(m_d->spinTwo->object());
+ m_d->spinTwo->setValue(m_d->aspectRatio * m_d->spinOne->value());
+ }
+
+ if (!m_d->blockUpdatesOnDrag || !m_d->spinOne->isDragging()) {
+ emit sliderValueChanged();
}
- emit sliderValueChanged();
}
void KisAspectRatioLocker::slotSpinTwoChanged()
{
if (m_d->aspectButton->keepAspectRatio()) {
- KisSignalsBlocker b(m_d->spinOne);
- m_d->spinOne->setValue(qRound(m_d->spinTwo->value() / m_d->aspectRatio));
+ KisSignalsBlocker b(m_d->spinOne->object());
+ m_d->spinOne->setValue(m_d->spinTwo->value() / m_d->aspectRatio);
}
- emit sliderValueChanged();
+ if (!m_d->blockUpdatesOnDrag || !m_d->spinTwo->isDragging()) {
+ emit sliderValueChanged();
+ }
}
void KisAspectRatioLocker::slotAspectButtonChanged()
@@ -90,5 +173,12 @@
m_d->aspectRatio = 1.0;
}
- emit aspectButtonChanged();
+ if (!m_d->spinTwo->isDragging()) {
+ emit aspectButtonChanged();
+ }
+}
+
+void KisAspectRatioLocker::setBlockUpdateSignalOnDrag(bool value)
+{
+ m_d->blockUpdatesOnDrag = value;
}
diff --git a/libs/ui/kis_canvas_resource_provider.h b/libs/ui/kis_canvas_resource_provider.h
--- a/libs/ui/kis_canvas_resource_provider.h
+++ b/libs/ui/kis_canvas_resource_provider.h
@@ -71,8 +71,11 @@
MirrorHorizontalHideDecorations,
MirrorAxesCenter,
Opacity,
+ Flow,
+ Size,
HdrGamma,
GlobalAlphaLock,
+ DisablePressure,
PreviousPaintOpPreset,
EffectiveZoom, ///<-Used only by painting tools for non-displaying purposes
PresetAllowsLod,
@@ -154,9 +157,17 @@
void setOpacity(qreal opacity);
qreal opacity() const;
+ void setFlow(qreal opacity);
+ qreal flow() const;
+
+ void setSize(qreal size);
+ qreal size() const;
+
void setGlobalAlphaLock(bool lock);
bool globalAlphaLock() const;
+ void setDisablePressure(bool value);
+ bool disablePressure() const;
///Notify that the workspace is saved and settings should be saved to it
void notifySavingWorkspace(KisWorkspaceResource* workspace);
diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp
--- a/libs/ui/kis_canvas_resource_provider.cpp
+++ b/libs/ui/kis_canvas_resource_provider.cpp
@@ -479,6 +479,26 @@
return m_resourceManager->resource(Opacity).toReal();
}
+void KisCanvasResourceProvider::setFlow(qreal flow)
+{
+ m_resourceManager->setResource(Flow, flow);
+}
+
+qreal KisCanvasResourceProvider::flow() const
+{
+ return m_resourceManager->resource(Flow).toReal();
+}
+
+void KisCanvasResourceProvider::setSize(qreal size)
+{
+ m_resourceManager->setResource(Size, size);
+}
+
+qreal KisCanvasResourceProvider::size() const
+{
+ return m_resourceManager->resource(Size).toReal();
+}
+
void KisCanvasResourceProvider::setSelectionAction(int action)
{
m_resourceManager->setResource(SelectionAction, action);
@@ -512,6 +532,16 @@
return m_resourceManager->resource(GlobalAlphaLock).toBool();
}
+void KisCanvasResourceProvider::setDisablePressure(bool value)
+{
+ m_resourceManager->setResource(DisablePressure, value);
+}
+
+bool KisCanvasResourceProvider::disablePressure() const
+{
+ return m_resourceManager->resource(DisablePressure).toBool();
+}
+
void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResource* workspace)
{
emit sigLoadingWorkspace(workspace);
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -479,6 +479,9 @@
QString customFFMpegPath(bool defaultValue = false) const;
void setCustomFFMpegPath(const QString &value) const;
+ bool showBrushHud(bool defaultValue = false) const;
+ void setShowBrushHud(bool value);
+
template
void writeEntry(const QString& name, const T& value) {
m_cfg.writeEntry(name, value);
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1689,3 +1689,13 @@
{
m_cfg.writeEntry("ffmpegExecutablePath", value);
}
+
+bool KisConfig::showBrushHud(bool defaultValue) const
+{
+ return defaultValue ? false : m_cfg.readEntry("showBrushHud", false);
+}
+
+void KisConfig::setShowBrushHud(bool value)
+{
+ m_cfg.writeEntry("showBrushHud", value);
+}
diff --git a/libs/ui/kis_derived_resources.h b/libs/ui/kis_derived_resources.h
--- a/libs/ui/kis_derived_resources.h
+++ b/libs/ui/kis_derived_resources.h
@@ -20,7 +20,24 @@
#define __KIS_DERIVED_RESOURCES_H
#include "KoDerivedResourceConverter.h"
+#include "KoResourceUpdateMediator.h"
+#include
+class KisPresetUpdateMediator : public KoResourceUpdateMediator
+{
+ Q_OBJECT
+public:
+ KisPresetUpdateMediator();
+ ~KisPresetUpdateMediator();
+ void connectResource(QVariant sourceResource);
+
+private Q_SLOTS:
+ void slotSettingsChanged();
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
class KisCompositeOpResourceConverter : public KoDerivedResourceConverter
{
@@ -40,15 +57,33 @@
QVariant toSource(const QVariant &value, const QVariant &sourceValue);
};
-class KisOpacityResourceConverter : public KoDerivedResourceConverter
+class KisOpacityResourceConverter : public KoDerivedResourceConverter, public QObject
{
public:
KisOpacityResourceConverter();
QVariant fromSource(const QVariant &value);
QVariant toSource(const QVariant &value, const QVariant &sourceValue);
};
+class KisFlowResourceConverter : public KoDerivedResourceConverter, public QObject
+{
+public:
+ KisFlowResourceConverter();
+
+ QVariant fromSource(const QVariant &value);
+ QVariant toSource(const QVariant &value, const QVariant &sourceValue);
+};
+
+class KisSizeResourceConverter : public KoDerivedResourceConverter, public QObject
+{
+public:
+ KisSizeResourceConverter();
+
+ QVariant fromSource(const QVariant &value);
+ QVariant toSource(const QVariant &value, const QVariant &sourceValue);
+};
+
class KisLodAvailabilityResourceConverter : public KoDerivedResourceConverter
{
public:
diff --git a/libs/ui/kis_derived_resources.cpp b/libs/ui/kis_derived_resources.cpp
--- a/libs/ui/kis_derived_resources.cpp
+++ b/libs/ui/kis_derived_resources.cpp
@@ -18,9 +18,44 @@
#include "kis_derived_resources.h"
+#include "kis_signal_auto_connection.h"
#include "kis_canvas_resource_provider.h"
#include "kis_paintop_preset.h"
#include "kis_paintop_settings.h"
+#include "kis_paintop_settings_update_proxy.h"
+
+struct KisPresetUpdateMediator::Private
+{
+ KisSignalAutoConnectionsStore connections;
+};
+
+KisPresetUpdateMediator::KisPresetUpdateMediator()
+ : KoResourceUpdateMediator(KisCanvasResourceProvider::CurrentPaintOpPreset),
+ m_d(new Private)
+{
+}
+
+KisPresetUpdateMediator::~KisPresetUpdateMediator()
+{
+}
+
+void KisPresetUpdateMediator::connectResource(QVariant sourceResource)
+{
+ KisPaintOpPresetSP preset = sourceResource.value();
+ if (!preset) return;
+
+ m_d->connections.clear();
+ m_d->connections.addUniqueConnection(
+ preset->updateProxy(),
+ SIGNAL(sigSettingsChanged()),
+ this,
+ SLOT(slotSettingsChanged()));
+}
+
+void KisPresetUpdateMediator::slotSettingsChanged()
+{
+ emit sigResourceChanged(key());
+}
/*********************************************************************/
@@ -103,6 +138,56 @@
}
/*********************************************************************/
+/* KisFlowResourceConverter */
+/*********************************************************************/
+
+KisFlowResourceConverter::KisFlowResourceConverter()
+ : KoDerivedResourceConverter(KisCanvasResourceProvider::Flow,
+ KisCanvasResourceProvider::CurrentPaintOpPreset)
+{
+}
+
+QVariant KisFlowResourceConverter::fromSource(const QVariant &value)
+{
+ KisPaintOpPresetSP preset = value.value();
+ return preset ? preset->settings()->paintOpFlow() : QVariant();
+}
+
+QVariant KisFlowResourceConverter::toSource(const QVariant &value, const QVariant &sourceValue)
+{
+ KisPaintOpPresetSP preset = sourceValue.value();
+ if (!preset) return sourceValue;
+
+ preset->settings()->setPaintOpFlow(value.toReal());
+ return QVariant::fromValue(preset);
+}
+
+/*********************************************************************/
+/* KisSizeResourceConverter */
+/*********************************************************************/
+
+KisSizeResourceConverter::KisSizeResourceConverter()
+ : KoDerivedResourceConverter(KisCanvasResourceProvider::Size,
+ KisCanvasResourceProvider::CurrentPaintOpPreset)
+{
+}
+
+QVariant KisSizeResourceConverter::fromSource(const QVariant &value)
+{
+ KisPaintOpPresetSP preset = value.value();
+ return preset ? preset->settings()->paintOpSize() : QVariant();
+}
+
+QVariant KisSizeResourceConverter::toSource(const QVariant &value, const QVariant &sourceValue)
+{
+ KisPaintOpPresetSP preset = sourceValue.value();
+ if (!preset) return sourceValue;
+
+ preset->settings()->setPaintOpSize(value.toReal());
+ return QVariant::fromValue(preset);
+}
+
+/*********************************************************************/
/* KisLodAvailabilityResourceConverter */
/*********************************************************************/
diff --git a/libs/ui/kis_paintop_box.h b/libs/ui/kis_paintop_box.h
--- a/libs/ui/kis_paintop_box.h
+++ b/libs/ui/kis_paintop_box.h
@@ -25,7 +25,8 @@
#include
#include
#include
-
+#include
+#include
#include
#include
@@ -36,6 +37,9 @@
#include
#include
#include "kritaui_export.h"
+#include "kis_signal_auto_connection.h"
+#include "kis_signal_compressor.h"
+
class QToolButton;
@@ -145,12 +149,12 @@
void slotSlider2Changed();
void slotSlider3Changed();
void slotToolChanged(KoCanvasController* canvas, int toolId);
- void slotOpacityChanged(qreal);
void slotPreviousFavoritePreset();
void slotNextFavoritePreset();
void slotSwitchToPreviousPreset();
void slotUnsetEraseMode();
void slotToggleAlphaLockMode(bool);
+ void slotDisablePressureMode(bool);
void slotReloadPreset();
void slotGuiChangedCurrentPreset();
@@ -167,7 +171,7 @@
void slotHideDecorationMirrorX(bool);
void slotHideDecorationMirrorY(bool);
-
+ void slotUpdateOptionsWidget();
private:
KisCanvasResourceProvider* m_resourceProvider;
@@ -180,6 +184,8 @@
KisCompositeOpComboBox* m_cmbCompositeOp;
QToolButton* m_eraseModeButton;
QToolButton* m_alphaLockButton;
+ QToolButton* m_disablePressureButton;
+ QLabel* m_pressureLabel;
QToolButton* m_hMirrorButton;
QToolButton* m_vMirrorButton;
KisToolOptionsPopup* m_toolOptionsPopup;
@@ -193,6 +199,7 @@
QToolButton* m_reloadButton;
KisAction* m_eraseAction;
KisAction* m_reloadAction;
+ KisAction* m_disablePressureAction;
QString m_currCompositeOpID;
KisNodeWSP m_previousNode;
@@ -240,7 +247,8 @@
bool m_dirtyPresetsEnabled;
bool m_eraserBrushSizeEnabled;
-
+ KisSignalAutoConnectionsStore m_presetConnections;
+ KisSignalCompressor m_presetUpdateCompressor;
};
#endif //KIS_PAINTOP_BOX_H_
diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc
--- a/libs/ui/kis_paintop_box.cc
+++ b/libs/ui/kis_paintop_box.cc
@@ -53,6 +53,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -100,6 +101,7 @@
, m_blockUpdate(false)
, m_dirtyPresetsEnabled(false)
, m_eraserBrushSizeEnabled(false)
+ , m_presetUpdateCompressor(200, KisSignalCompressor::FIRST_ACTIVE)
{
Q_ASSERT(view != 0);
@@ -154,6 +156,13 @@
m_alphaLockButton->setDefaultAction(alphaLockAction);
+ // pen pressure
+ m_disablePressureButton = new KisHighlightedToolButton(this);
+ m_disablePressureButton->setFixedSize(iconsize, iconsize);
+ m_disablePressureButton->setCheckable(true);
+
+ m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure");
+ m_disablePressureButton->setDefaultAction(m_disablePressureAction);
// horizontal and vertical mirror toolbar buttons
@@ -176,8 +185,6 @@
moveToCenterActionX->setText(i18n("Move to Canvas Center"));
toolbarMenuXMirror->addAction(moveToCenterActionX);
-
-
// mirror tool options for the Y Mirror
QMenu *toolbarMenuYMirror = new QMenu();
@@ -332,6 +339,17 @@
action->setText(i18n("Brush composite"));
action->setDefaultWidget(compositeActions);
+ QWidget* compositePressure = new QWidget(this);
+ QHBoxLayout* pressureLayout = new QHBoxLayout(compositePressure);
+ pressureLayout->addWidget(m_disablePressureButton);
+ pressureLayout->setSpacing(4);
+ pressureLayout->setContentsMargins(0, 0, 0, 0);
+
+ action = new QWidgetAction(this);
+ view->actionCollection()->addAction("pressure_action", action);
+ action->setText(i18n("Pressure usage (small button)"));
+ action->setDefaultWidget(compositePressure);
+
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("brushslider1", action);
view->actionCollection()->addAction("brushslider1", action);
@@ -441,9 +459,11 @@
connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResource*)) , SLOT(resourceSelected(KoResource*)));
connect(m_resourceProvider , SIGNAL(sigNodeChanged(const KisNodeSP)) , SLOT(slotNodeChanged(const KisNodeSP)));
connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int)));
- connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool)));
- connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool)));
+ connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool)));
+ connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool)));
+ connect(m_disablePressureAction , SIGNAL(toggled(bool)) , SLOT(slotDisablePressureMode(bool)));
+ m_disablePressureAction->setChecked(true);
connect(m_hMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotHorizontalMirrorChanged(bool)));
connect(m_vMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotVerticalMirrorChanged(bool)));
@@ -464,7 +484,6 @@
connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
//Needed to connect canvas to favorite resource manager
- connect(m_viewManager->resourceProvider(), SIGNAL(sigOpacityChanged(qreal)), SLOT(slotOpacityChanged(qreal)));
connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), SLOT(slotUnsetEraseMode()));
m_favoriteResourceManager = new KisFavoriteResourceManager(this);
@@ -570,23 +589,27 @@
preset = (!preset) ? activePreset(paintop) : preset;
Q_ASSERT(preset && preset->settings());
- m_resourceProvider->setPaintOpPreset(preset);
-
if (!m_paintopOptionWidgets.contains(paintop))
m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this);
m_optionWidget = m_paintopOptionWidgets[paintop];
- preset->settings()->setOptionsWidget(m_optionWidget);
+ KisSignalsBlocker b(m_optionWidget);
+
+ preset->setOptionsWidget(m_optionWidget);
m_optionWidget->setImage(m_viewManager->image());
m_optionWidget->setNode(m_viewManager->activeNode());
- m_optionWidget->setConfiguration(preset->settings());
m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget);
+ m_resourceProvider->setPaintOpPreset(preset);
+
Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton);
+
connect(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset()));
+ connect(&m_presetUpdateCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateOptionsWidget()));
+
connect(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfiguration*)));
connect(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotDropLockedOption(KisPropertiesConfiguration*)));
@@ -604,12 +627,27 @@
dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace";
}
- /**
- * We will get more update signals from the configuration widgets
- * but they might be delayed by some internal deferring timers,
- * so just call the slot directly
- */
- slotUpdatePreset();
+ m_presetConnections.clear();
+
+ // preset -> compressor
+ m_presetConnections.addConnection(
+ preset->updateProxy(), SIGNAL(sigSettingsChanged()),
+ &m_presetUpdateCompressor, SLOT(start()));
+}
+
+void KisPaintopBox::slotUpdateOptionsWidget()
+{
+ KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
+
+ KIS_SAFE_ASSERT_RECOVER_RETURN(preset);
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget);
+
+ KisSignalsBlocker b(m_optionWidget);
+ m_optionWidget->setConfigurationSafe(preset->settings().data());
+
+ m_presetsPopup->resourceSelected(preset.data());
+ m_presetsPopup->updateViewSettings();
+
}
KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp)
@@ -649,14 +687,11 @@
if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID))
compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
- m_cmbCompositeOp->blockSignals(true);
- m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
- m_cmbCompositeOp->blockSignals(false);
-
+ {
+ KisSignalsBlocker b1(m_cmbCompositeOp);
+ m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
+ }
if (compositeOpID != m_currCompositeOpID) {
- m_resourceProvider->currentPreset()->settings()->setPaintOpCompositeOp(compositeOpID);
- m_optionWidget->setConfiguration(m_resourceProvider->currentPreset()->settings().data());
- m_resourceProvider->setCurrentCompositeOp(compositeOpID);
m_currCompositeOpID = compositeOpID;
}
}
@@ -690,9 +725,8 @@
{
for (int i = 0; i < 3; ++i) {
KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget