diff --git a/krita/data/gamutmasks/Atmosphere_With_Accent.kgm b/krita/data/gamutmasks/Atmosphere_With_Accent.kgm
new file mode 100644
index 0000000000..8bea9a5673
Binary files /dev/null and b/krita/data/gamutmasks/Atmosphere_With_Accent.kgm differ
diff --git a/krita/data/gamutmasks/Atmospheric_Triad.kgm b/krita/data/gamutmasks/Atmospheric_Triad.kgm
new file mode 100644
index 0000000000..638fc6a49d
Binary files /dev/null and b/krita/data/gamutmasks/Atmospheric_Triad.kgm differ
diff --git a/krita/data/gamutmasks/CMakeLists.txt b/krita/data/gamutmasks/CMakeLists.txt
index 2f0494c79e..39a055e18d 100644
--- a/krita/data/gamutmasks/CMakeLists.txt
+++ b/krita/data/gamutmasks/CMakeLists.txt
@@ -1,9 +1,14 @@
########### install files ###############
-install( FILES
- testing1.kgm
- testing2.kgm
- GamutMaskTemplate.kra
- new_mask.kgm
+install( FILES
+ GamutMaskTemplate.kra
+ empty_mask_preview.png
+ Atmosphere_With_Accent.kgm
+ Atmospheric_Triad.kgm
+ Complementary.kgm
+ Dominant_Hue_With_Accent.kgm
+ Shifted_Triad.kgm
+ Split_Complementary.kgm
+
DESTINATION ${DATA_INSTALL_DIR}/krita/gamutmasks)
diff --git a/krita/data/gamutmasks/Complementary.kgm b/krita/data/gamutmasks/Complementary.kgm
new file mode 100644
index 0000000000..801df35332
Binary files /dev/null and b/krita/data/gamutmasks/Complementary.kgm differ
diff --git a/krita/data/gamutmasks/Dominant_Hue_With_Accent.kgm b/krita/data/gamutmasks/Dominant_Hue_With_Accent.kgm
new file mode 100644
index 0000000000..1bfecf468e
Binary files /dev/null and b/krita/data/gamutmasks/Dominant_Hue_With_Accent.kgm differ
diff --git a/krita/data/gamutmasks/GamutMaskTemplate.kra b/krita/data/gamutmasks/GamutMaskTemplate.kra
index 3cd7e677eb..b2994bd54e 100644
Binary files a/krita/data/gamutmasks/GamutMaskTemplate.kra and b/krita/data/gamutmasks/GamutMaskTemplate.kra differ
diff --git a/krita/data/gamutmasks/Shifted_Triad.kgm b/krita/data/gamutmasks/Shifted_Triad.kgm
new file mode 100644
index 0000000000..4939b02bff
Binary files /dev/null and b/krita/data/gamutmasks/Shifted_Triad.kgm differ
diff --git a/krita/data/gamutmasks/Split_Complementary.kgm b/krita/data/gamutmasks/Split_Complementary.kgm
new file mode 100644
index 0000000000..5744fa6cdb
Binary files /dev/null and b/krita/data/gamutmasks/Split_Complementary.kgm differ
diff --git a/krita/data/gamutmasks/empty_mask_preview.png b/krita/data/gamutmasks/empty_mask_preview.png
new file mode 100644
index 0000000000..03e96215a7
Binary files /dev/null and b/krita/data/gamutmasks/empty_mask_preview.png differ
diff --git a/krita/data/gamutmasks/new_mask.kgm b/krita/data/gamutmasks/new_mask.kgm
deleted file mode 100644
index 7bb45f3a30..0000000000
Binary files a/krita/data/gamutmasks/new_mask.kgm and /dev/null differ
diff --git a/krita/data/gamutmasks/testing1.kgm b/krita/data/gamutmasks/testing1.kgm
deleted file mode 100644
index 0905c2a192..0000000000
Binary files a/krita/data/gamutmasks/testing1.kgm and /dev/null differ
diff --git a/krita/data/gamutmasks/testing2.kgm b/krita/data/gamutmasks/testing2.kgm
deleted file mode 100644
index 2da5b4a6cd..0000000000
Binary files a/krita/data/gamutmasks/testing2.kgm and /dev/null differ
diff --git a/krita/data/kritarc b/krita/data/kritarc
index 80f1c19618..16ce4b018a 100644
--- a/krita/data/kritarc
+++ b/krita/data/kritarc
@@ -1,479 +1,478 @@
favoriteCompositeOps=normal,erase,multiply,burn,darken,add,dodge,screen,overlay,soft_light_svg,luminize,lighten,saturation,color
ArtColorSel.ColorSpace=0
ArtColorSel.InversedSaturation=false
ArtColorSel.Light=0.5
-ArtColorSel.LightPieces=19
-ArtColorSel.NumRings=11
-ArtColorSel.RelativeLight=false
+ArtColorSel.LightPieces=11
+ArtColorSel.NumRings=7
ArtColorSel.RingAngles=0,0,0,0,0,0,0,0,0,0,0
ArtColorSel.RingPieces=12
ArtColorSel.SelColorA=1
ArtColorSel.SelColorH=0
ArtColorSel.SelColorS=0
ArtColorSel.SelColorX=0.5
BackgroundColorForNewImage=255,255,255
BackgroundOpacityForNewImage=255
BackgroundStyleForNewImage=0
Krita/Ocio/OcioColorManagementMode=0
Krita/Ocio/OcioLockColorVisualRepresentation=false
Krita/Ocio/UseOcio=false
LastBackGroundColor=\n\n \n\n
LastForeGroundColor=\n\n \n\n
LastPreset=Basic_circle
LastPreset_-1=Basic_circle
LineSmoothingDelayDistance=50
LineSmoothingDistance=50
LineSmoothingFinishStabilizedCurve=true
LineSmoothingStabilizeSensors=true
LineSmoothingTailAggressiveness=0.14999999999999999
LineSmoothingType=1
LineSmoothingUseDelayDistance=true
NumberOfLayersForNewImage=2
PaintopPopupDetached=false
SpecificColorSelector/ShowColorSpaceSelector=false
baseLength=50
colorDepthDef=U8
colorModelDef=RGBA
colorProfileDef=sRGB-elle-V2-srgbtrc.icc
favoritePresetsTag=★ My Favorites
internal_selector_active_color_set=Default
globalSnapBoundingBox=false
globalSnapExtension=false
globalSnapImageBounds=true
globalSnapImageCenter=true
globalSnapIntersection=false
globalSnapNode=false
globalSnapOrthogonal=false
gridmaincolor=99,99,99
gridmainstyle=0
gridsubdivisioncolor=150,150,150
gridsubdivisionstyle=1
guidesColor=99,99,99
guidesLineStyle=0
imageHeightDef=1200
imageResolutionDef=300
imageWidthDef=1600
levelOfDetailEnabled=true
numberOfOnionSkins=10
oninSkinTintColorForward=0,255,0
onionSkinOpacity_-1=173
onionSkinOpacity_-10=22
onionSkinOpacity_-2=163
onionSkinOpacity_-3=147
onionSkinOpacity_-4=127
onionSkinOpacity_-5=107
onionSkinOpacity_-6=84
onionSkinOpacity_-7=63
onionSkinOpacity_-8=48
onionSkinOpacity_-9=33
onionSkinOpacity_0=175
onionSkinOpacity_1=173
onionSkinOpacity_10=22
onionSkinOpacity_2=163
onionSkinOpacity_3=147
onionSkinOpacity_4=127
onionSkinOpacity_5=107
onionSkinOpacity_6=84
onionSkinOpacity_7=63
onionSkinOpacity_8=48
onionSkinOpacity_9=33
onionSkinState_-1=true
onionSkinState_-10=false
onionSkinState_-2=true
onionSkinState_-3=false
onionSkinState_-4=false
onionSkinState_-5=false
onionSkinState_-6=false
onionSkinState_-7=false
onionSkinState_-8=false
onionSkinState_-9=false
onionSkinState_0=true
onionSkinState_1=true
onionSkinState_10=false
onionSkinState_2=true
onionSkinState_3=false
onionSkinState_4=false
onionSkinState_5=false
onionSkinState_6=false
onionSkinState_7=false
onionSkinState_8=false
onionSkinState_9=false
onionSkinTintColorBackward=255,0,0
onionSkinTintFactor=191
presethistory=Basic_tip_default
showAdditionalOnionSkinsSettings=true
toolbarslider_1=opacity
toolbarslider_2=size
toolbarslider_3=flow
[advancedColorSelector]
allowHorizontalLayout=true
colorSelectorConfiguration=3|0|5|0
commonColorsAlignment=false
commonColorsAutoUpdate=false
commonColorsCount=12
commonColorsHeight=16
commonColorsNumCols=1
commonColorsNumRows=1
commonColorsScrolling=false
commonColorsShow=true
commonColorsWidth=16
customColorSpaceDepthID=U8
customColorSpaceModel=RGBA
customColorSpaceProfile=sRGB built-in
lastUsedColorsAlignment=true
lastUsedColorsCount=20
lastUsedColorsHeight=16
lastUsedColorsNumCols=1
lastUsedColorsNumRows=1
lastUsedColorsScrolling=true
lastUsedColorsShow=true
lastUsedColorsWidth=16
minimalShadeSelectorAsGradient=true
minimalShadeSelectorLineConfig=0|0.2|0|0|0|0|0;1|0|1|1|0|0|0;2|0|-1|1|0|0|0;
minimalShadeSelectorLineHeight=10
minimalShadeSelectorPatchCount=10
popupOnMouseClick=true
popupOnMouseOver=false
shadeSelectorHideable=false
shadeSelectorType=Minimal
shadeSelectorUpdateOnBackground=true
shadeSelectorUpdateOnForeground=true
shadeSelectorUpdateOnLeftClick=false
shadeSelectorUpdateOnRightClick=false
useCustomColorSpace=false
zoomSize=280
[DockWidget sharedtooldocker]
TabbedMode=false
[KisToolTransform]
filterId=Bicubic
[MainWindow]
State=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AAAAFABHAHIAaQBkAEQAbwBjAGsAZQByAAAAAAD/////AAABLQD////7AAAAHgBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAAA/////wAAAEcA////+wAAACoAQQBuAGkAbQBhAHQAaQBvAG4AQwB1AHIAdgBlAHMARABvAGMAawBlAHIAAAAAAP////8AAACMAP////sAAAAyAFMAdgBnAFMAeQBtAGIAbwBsAEMAbwBsAGwAZQBjAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAACMAP////sAAAAWAFQAbwB1AGMAaABEAG8AYwBrAGUAcgAAAAJMAAABMQAAABMA////+wAAABoAQQByAHIAYQBuAGcAZQBEAG8AYwBrAGUAcgAAAAAA/////wAAAHoA////+wAAADoAYwBvAG0AaQBjAHMAXwBwAHIAbwBqAGUAYwB0AF8AbQBhAG4AYQBnAGUAcgBfAGQAbwBjAGsAZQByAAAAAAD/////AAAAuQD////7AAAAKgBxAHUAaQBjAGsAXwBzAGUAdAB0AGkAbgBnAHMAXwBkAG8AYwBrAGUAcgAAAAAA/////wAAAIwA////+wAAABYAUABhAGcAZQByAEQAbwBjAGsAZQByAAAAAAD/////AAAALQD////7AAAAJgBsAGEAcwB0AGQAbwBjAHUAbQBlAG4AdABzAGQAbwBjAGsAZQByAAAAAAD/////AAAAiQD///8AAAACAAAKAAAAALz8AQAAAAH7AAAAGgBUAG8AbwBsAEIAYQByAEQAbwBjAGsAZQByAAAAAAD/////AAAAAAAAAAAAAAADAAAAAAAAAAD8AQAAAAT7AAAAHABGAGwAaQBwAGIAbwBvAGsARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAeAEEAbgBpAG0AYQB0AGkAbwBuAEQAbwBjAGsAZQByAAAAAAD/////AAABBQD////7AAAAIABPAG4AaQBvAG4AUwBrAGkAbgBzAEQAbwBjAGsAZQByAAAAAAD/////AAABNgD////7AAAAHABUAGkAbQBlAGwAaQBuAGUARABvAGMAawBlAHIAAAAAAP////8AAABVAP///wAABU0AAAPNAAAABAAAAAQAAAAIAAAACPwAAAABAAAAAgAAAAIAAAAWAG0AYQBpAG4AVABvAG8AbABCAGEAcgEAAAAA/////wAAAAAAAAAAAAAAHgBCAHIAdQBzAGgAZQBzAEEAbgBkAFMAdAB1AGYAZgEAAAC5/////wAAAAAAAAAA
[advancedColorSelector]
gamma=2.2000000000000002
hidePopupOnClickCheck=false
hsxSettingType=0
lumaB=0.0722
lumaG=0.71519999999999995
lumaR=0.21260000000000001
onDockerResize=0
shadeMyPaintType=HSV
zoomSelectorOptions=0
[calligra]
ColorSpaceExtensionsPlugins=\\0
ColorSpaceExtensionsPluginsDisabled=
ColorSpacePlugins=\\0
ColorSpacePluginsDisabled=
DockerPlugins=\\0
DockerPluginsDisabled=textdocumentinspection
FlakePlugins=,
ShapePlugins=,
ToolsBlacklist=CreatePathTool,KoPencilTool,ConnectionTool,KarbonFilterEffectsTool,KritaShape/KisToolText,ArtisticTextTool,TextTool
ToolPlugins=,,
ToolPluginsDisabled=
[KoShapeCollection]
QuickShapes=ArtisticText,TextShapeID,EllipseShape,RectangleShape
[colorhotkeys]
steps_blueyellow=10
steps_hue=36
steps_lightness=10
steps_redgreen=10
steps_saturation=10
[crashprevention]
CreatingCanvas=false
[hsxColorSlider]
hsiH=false
hsiI=false
hsiS=false
hslH=true
hslL=true
hslS=true
hsvH=false
hsvS=false
hsvV=false
hsyH=false
hsyS=false
hsyY=false
[krita]
State=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
ToolBarsMovable=Enabled
[krita][DockWidget AnimationCurvesDocker]
Collapsed=false
DockArea=2
Locked=false
height=421
width=448
xPosition=0
yPosition=0
[krita][DockWidget AnimationDocker]
Collapsed=false
DockArea=8
Locked=false
height=160
width=280
xPosition=0
yPosition=0
[krita][DockWidget ArtisticColorSelector]
Collapsed=false
DockArea=2
Locked=false
height=294
width=337
xPosition=0
yPosition=0
[krita][DockWidget ChannelDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ColorSelectorNg]
Collapsed=false
DockArea=2
Locked=false
height=176
width=281
xPosition=0
yPosition=20
[krita][DockWidget ColorSlider]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget CompositionDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget DigitalMixer]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget GridDocker]
Collapsed=false
DockArea=2
Locked=false
height=342
width=441
xPosition=0
yPosition=0
[krita][DockWidget HistogramDocker]
Collapsed=false
DockArea=2
Locked=false
height=91
width=281
xPosition=0
yPosition=20
[krita][DockWidget History]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget ImageDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=399
xPosition=0
yPosition=0
[krita][DockWidget KisLayerBox]
DockArea=2
Locked=false
height=358
width=281
xPosition=0
yPosition=20
[krita][DockWidget LutDocker]
Collapsed=false
DockArea=2
Locked=false
height=286
width=357
xPosition=0
yPosition=0
[krita][DockWidget OnionSkinsDocker]
Collapsed=false
DockArea=8
Locked=false
height=210
width=356
xPosition=0
yPosition=0
[krita][DockWidget OverviewDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PaletteDocker]
Collapsed=false
DockArea=2
Locked=false
height=219
width=256
xPosition=0
yPosition=0
[krita][DockWidget PatternDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PresetDocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget PresetHistory]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget Shape Properties]
DockArea=2
Locked=false
height=480
width=640
xPosition=0
yPosition=0
[krita][DockWidget ShapeCollectionDocker]
Collapsed=false
DockArea=2
Locked=false
height=0
width=0
xPosition=0
yPosition=20
[krita][DockWidget SmallColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget SpecificColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget TasksetDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget TimelineDocker]
Collapsed=false
DockArea=8
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ToolBox]
DockArea=1
Locked=false
height=610
width=63
xPosition=0
yPosition=20
[krita][DockWidget sharedtooldocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][Toolbar mainToolBar]
ToolButtonStyle=IconOnly
[TemplateChooserDialog]
ShowCustomDocumentWidgetByDefault=true
LastReturnType=Custom Document
[theme]
Theme=Krita dark
[python]
enable_colorspace=true
enable_comics_project_management_tools=true
enable_documenttools=true
enable_exportlayers=true
enable_filtermanager=true
enable_lastdocumentsdocker=true
enable_quick_settings_docker=true
enable_scripter=true
enable_tenbrushes=true
enable_tenscripts=true
diff --git a/krita/pics/svg/dark_gamut-mask-off.svg b/krita/pics/svg/dark_gamut-mask-off.svg
new file mode 100644
index 0000000000..4ab54f6056
--- /dev/null
+++ b/krita/pics/svg/dark_gamut-mask-off.svg
@@ -0,0 +1,1563 @@
+
+
+
+
diff --git a/krita/pics/svg/dark_gamut-mask-on.svg b/krita/pics/svg/dark_gamut-mask-on.svg
new file mode 100644
index 0000000000..a095462f2d
--- /dev/null
+++ b/krita/pics/svg/dark_gamut-mask-on.svg
@@ -0,0 +1,1535 @@
+
+
+
+
diff --git a/krita/pics/svg/light_gamut-mask-off.svg b/krita/pics/svg/light_gamut-mask-off.svg
new file mode 100644
index 0000000000..8a69b44344
--- /dev/null
+++ b/krita/pics/svg/light_gamut-mask-off.svg
@@ -0,0 +1,1563 @@
+
+
+
+
diff --git a/krita/pics/svg/light_gamut-mask-on.svg b/krita/pics/svg/light_gamut-mask-on.svg
new file mode 100644
index 0000000000..fdce9a6afc
--- /dev/null
+++ b/krita/pics/svg/light_gamut-mask-on.svg
@@ -0,0 +1,1535 @@
+
+
+
+
diff --git a/krita/pics/svg/svg-icons.qrc b/krita/pics/svg/svg-icons.qrc
index 27f3ef82a4..0418ee66a3 100644
--- a/krita/pics/svg/svg-icons.qrc
+++ b/krita/pics/svg/svg-icons.qrc
@@ -1,151 +1,155 @@
broken-preset.svgz
dark_addblankframe.svg
dark_addcolor.svg
dark_addduplicateframe.svg
dark_deletekeyframe.svg
dark_docker_lock_a.svg
dark_docker_lock_b.svg
dark_layer-locked.svg
dark_layer-unlocked.svg
dark_nextframe.svg
dark_nextkeyframe.svg
dark_lastframe.svg
dark_prevkeyframe.svg
dark_firstframe.svg
dark_pallete_librarysvg.svg
dark_passthrough-disabled.svg
dark_passthrough-enabled.svg
dark_prevframe.svg
dark_selection-mode_ants.svg
dark_selection-mode_invisible.svg
dark_selection-mode_mask.svg
dark_transparency-disabled.svg
dark_transparency-enabled.svg
dark_trim-to-image.svg
dark_warning.svg
delete.svgz
layer-style-disabled.svg
layer-style-enabled.svg
light_addblankframe.svg
light_addcolor.svg
light_addduplicateframe.svg
light_deletekeyframe.svg
light_docker_lock_a.svg
light_docker_lock_b.svg
light_layer-locked.svg
light_layer-unlocked.svg
light_nextframe.svg
light_pallete_library.svg
light_passthrough-disabled.svgz
light_passthrough-enabled.svgz
light_prevframe.svg
light_nextkeyframe.svg
light_lastframe.svg
light_prevkeyframe.svg
light_firstframe.svg
light_selection-mode_ants.svg
light_selection-mode_invisible.svg
light_selection-mode_mask.svg
light_timeline_keyframe.svg
light_transparency-disabled.svg
light_transparency-enabled.svg
light_trim-to-image.svg
light_warning.svg
paintop_presets_disabled.svgz
paintop_settings_01.svgz
selection-info.svg
selection-mode_invisible.svg
svg-icons.qrc
transparency-locked.svg
transparency-unlocked.svg
workspace-chooser.svg
light_lazyframeOn.svg
light_lazyframeOff.svg
dark_lazyframeOn.svg
dark_lazyframeOff.svg
dark_mirror-view.svg
light_mirror-view.svg
dark_rotation-reset.svg
light_rotation-reset.svg
light_smoothing-basic.svg
light_smoothing-no.svg
light_smoothing-stabilizer.svg
light_smoothing-weighted.svg
dark_smoothing-basic.svg
dark_smoothing-no.svg
dark_smoothing-stabilizer.svg
dark_smoothing-weighted.svg
light_merge-layer-below.svg
dark_merge-layer-below.svg
light_rotate-canvas-left.svg
light_rotate-canvas-right.svg
dark_rotate-canvas-left.svg
dark_rotate-canvas-right.svg
light_gmic.svg
dark_gmic.svg
light_split-layer.svg
dark_split-layer.svg
light_color-to-alpha.svg
dark_color-to-alpha.svg
light_preset-switcher.svg
dark_preset-switcher.svg
dark_animation_play.svg
dark_animation_stop.svg
dark_dropframe.svg
dark_droppedframes.svg
light_animation_play.svg
light_animation_stop.svg
light_dropframe.svg
light_droppedframes.svg
dark_landscape.svg
dark_portrait.svg
light_landscape.svg
light_portrait.svg
dark_interpolation_constant.svg
dark_interpolation_linear.svg
dark_interpolation_bezier.svg
dark_interpolation_sharp.svg
dark_interpolation_smooth.svg
light_interpolation_bezier.svg
light_interpolation_constant.svg
light_interpolation_linear.svg
light_interpolation_sharp.svg
light_interpolation_smooth.svg
dark_audio-none.svg
dark_audio-volume-high.svg
dark_audio-volume-mute.svg
dark_keyframe-add.svg
dark_keyframe-remove.svg
dark_zoom-fit.svg
dark_zoom-horizontal.svg
dark_zoom-vertical.svg
light_audio-none.svg
light_audio-volume-high.svg
light_audio-volume-mute.svg
light_keyframe-add.svg
light_keyframe-remove.svg
light_zoom-fit.svg
light_zoom-horizontal.svg
light_zoom-vertical.svg
dark_showColoring.svg
dark_showMarks.svg
dark_showColoringOff.svg
dark_showMarksOff.svg
dark_updateColorize.svg
light_showColoring.svg
light_showMarks.svg
light_showColoringOff.svg
light_showMarksOff.svg
light_updateColorize.svg
light_wheel-light.svg
light_wheel-rings.svg
light_wheel-sectors.svg
dark_wheel-light.svg
dark_wheel-rings.svg
dark_wheel-sectors.svg
dark_infinity.svg
light_infinity.svg
+ dark_gamut-mask-on.svg
+ dark_gamut-mask-off.svg
+ light_gamut-mask-off.svg
+ light_gamut-mask-on.svg
diff --git a/libs/flake/KisGamutMaskViewConverter.cpp b/libs/flake/KisGamutMaskViewConverter.cpp
index 79012d0170..e5c22e8b74 100644
--- a/libs/flake/KisGamutMaskViewConverter.cpp
+++ b/libs/flake/KisGamutMaskViewConverter.cpp
@@ -1,152 +1,169 @@
+/*
+ * Copyright (c) 2018 Anna Medonosova
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
#include "KisGamutMaskViewConverter.h"
#include
#include
#include
#include
//#define DEBUG_GAMUT_MASK_CONVERTER
KisGamutMaskViewConverter::KisGamutMaskViewConverter()
: m_viewSize(1.0)
, m_maskSize(QSizeF(1,1))
, m_maskResolution(1)
{
computeAndSetZoom();
}
KisGamutMaskViewConverter::~KisGamutMaskViewConverter()
{
}
QPointF KisGamutMaskViewConverter::documentToView(const QPointF &documentPoint) const
{
return QPointF(documentToViewX(documentPoint.x()), documentToViewY(documentPoint.y()));
}
QPointF KisGamutMaskViewConverter::viewToDocument(const QPointF &viewPoint) const
{
return QPointF(viewToDocumentX(viewPoint.x()), viewToDocumentY(viewPoint.y()));
}
QRectF KisGamutMaskViewConverter::documentToView(const QRectF &documentRect) const
{
return QRectF(documentToView(documentRect.topLeft()), documentToView(documentRect.size()));
}
QRectF KisGamutMaskViewConverter::viewToDocument(const QRectF &viewRect) const
{
return QRectF(viewToDocument(viewRect.topLeft()), viewToDocument(viewRect.size()));
}
QSizeF KisGamutMaskViewConverter::documentToView(const QSizeF &documentSize) const
{
return QSizeF(documentToViewX(documentSize.width()), documentToViewY(documentSize.height()));
}
QSizeF KisGamutMaskViewConverter::viewToDocument(const QSizeF &viewSize) const
{
return QSizeF(viewToDocumentX(viewSize.width()), viewToDocumentY(viewSize.height()));
}
qreal KisGamutMaskViewConverter::documentToViewX(qreal documentX) const
{
qreal translated = documentX * m_zoomLevel;
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::DocumentToViewX: "
<< "documentX: " << documentX
<< " -> translated: " << translated;
#endif
return translated;
}
qreal KisGamutMaskViewConverter::documentToViewY(qreal documentY) const
{
qreal translated = documentY * m_zoomLevel;
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::DocumentToViewY: "
<< "documentY: " << documentY
<< " -> translated: " << translated;
#endif
return translated;
}
qreal KisGamutMaskViewConverter::viewToDocumentX(qreal viewX) const
{
qreal translated = viewX / m_zoomLevel;
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::viewToDocumentX: "
<< "viewX: " << viewX
<< " -> translated: " << translated;
#endif
return translated;
}
qreal KisGamutMaskViewConverter::viewToDocumentY(qreal viewY) const
{
qreal translated = viewY / m_zoomLevel;
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::viewToDocumentY: "
<< "viewY: " << viewY
<< " -> translated: " << translated;
#endif
return translated;
}
void KisGamutMaskViewConverter::setZoom(qreal zoom)
{
if (qFuzzyCompare(zoom, qreal(0.0)) || qFuzzyCompare(zoom, qreal(1.0))) {
zoom = 1;
}
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::setZoom: setting to " << zoom;
#endif
m_zoomLevel = zoom;
}
void KisGamutMaskViewConverter::zoom(qreal *zoomX, qreal *zoomY) const
{
*zoomX = m_zoomLevel;
*zoomY = m_zoomLevel;
}
void KisGamutMaskViewConverter::setViewSize(QSize viewSize)
{
m_viewSize = viewSize.width();
computeAndSetZoom();
}
void KisGamutMaskViewConverter::setMaskSize(QSizeF maskSize)
{
m_maskSize = maskSize;
m_maskResolution = maskSize.width();
computeAndSetZoom();
}
void KisGamutMaskViewConverter::computeAndSetZoom()
{
qreal zoom = m_viewSize / m_maskResolution;
#ifdef DEBUG_GAMUT_MASK_CONVERTER
debugFlake << "KisGamutMaskViewConverter::computeAndSetZoom: "
<< "m_viewSize: " << m_viewSize
<< " m_maskSize: " << m_maskResolution;
#endif
setZoom(zoom);
}
diff --git a/libs/flake/KisGamutMaskViewConverter.h b/libs/flake/KisGamutMaskViewConverter.h
index ce66b9a2e7..447a785cc5 100644
--- a/libs/flake/KisGamutMaskViewConverter.h
+++ b/libs/flake/KisGamutMaskViewConverter.h
@@ -1,51 +1,68 @@
+/*
+ * Copyright (c) 2018 Anna Medonosova
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
#ifndef KISGAMUTMASKVIEWCONVERTER_H
#define KISGAMUTMASKVIEWCONVERTER_H
#include "kritaflake_export.h"
#include
#include
#include
class QPointF;
class QRectF;
/**
- * @brief view convertor for gamut mask calculations and painting; 0,0 in the center
+ * @brief view convertor for gamut mask calculations and painting
*/
class KRITAFLAKE_EXPORT KisGamutMaskViewConverter : public KoViewConverter
{
public:
KisGamutMaskViewConverter();
~KisGamutMaskViewConverter();
void setViewSize(QSize viewSize);
void setMaskSize(QSizeF maskSize);
QPointF documentToView(const QPointF &documentPoint) const override;
QPointF viewToDocument(const QPointF &viewPoint) const override;
QRectF documentToView(const QRectF &documentRect) const override;
QRectF viewToDocument(const QRectF &viewRect) const override;
QSizeF documentToView(const QSizeF& documentSize) const override;
QSizeF viewToDocument(const QSizeF& viewSize) const override;
qreal documentToViewX(qreal documentX) const override;
qreal documentToViewY(qreal documentY) const override;
qreal viewToDocumentX(qreal viewX) const override;
qreal viewToDocumentY(qreal viewY) const override;
void setZoom(qreal zoom) override;
void zoom(qreal *zoomX, qreal *zoomY) const override;
private:
void computeAndSetZoom();
qreal m_zoomLevel; // 1.0 is 100%
int m_viewSize;
QSizeF m_maskSize;
qreal m_maskResolution;
};
#endif // KISGAMUTMASKVIEWCONVERTER_H
diff --git a/libs/flake/resources/KoGamutMask.cpp b/libs/flake/resources/KoGamutMask.cpp
index eaa6c94635..80fd9de3f6 100644
--- a/libs/flake/resources/KoGamutMask.cpp
+++ b/libs/flake/resources/KoGamutMask.cpp
@@ -1,350 +1,391 @@
-#include "KoGamutMask.h"
+/*
+ * Copyright (c) 2018 Anna Medonosova
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KoGamutMask.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
KoGamutMaskShape::KoGamutMaskShape(KoShape* shape)
: m_maskShape(shape)
, m_shapePaintingContext(KoShapePaintingContext())
{
}
KoGamutMaskShape::KoGamutMaskShape() {};
KoGamutMaskShape::~KoGamutMaskShape() {};
KoShape* KoGamutMaskShape::koShape()
{
return m_maskShape;
}
bool KoGamutMaskShape::coordIsClear(const QPointF& coord, const KoViewConverter& viewConverter) const
{
QPointF translatedPoint = viewConverter.viewToDocument(coord);
bool isClear = m_maskShape->hitTest(translatedPoint);
return isClear;
}
void KoGamutMaskShape::paint(QPainter &painter, const KoViewConverter& viewConverter)
{
painter.save();
painter.setTransform(m_maskShape->absoluteTransformation(&viewConverter) * painter.transform());
m_maskShape->paint(painter, viewConverter, m_shapePaintingContext);
painter.restore();
}
+void KoGamutMaskShape::paintStroke(QPainter &painter, const KoViewConverter &viewConverter)
+{
+ painter.save();
+ painter.setTransform(m_maskShape->absoluteTransformation(&viewConverter) * painter.transform());
+ m_maskShape->paintStroke(painter, viewConverter, m_shapePaintingContext);
+ painter.restore();
+
+}
struct Q_DECL_HIDDEN KoGamutMask::Private {
QString name;
QString title;
QString description;
QByteArray data;
QVector maskShapes;
QVector previewShapes;
- QSizeF maskSize; // at 100DPI
+ QSizeF maskSize;
};
KoGamutMask::KoGamutMask(const QString& filename)
: KoResource(filename)
, d(new Private())
{
-
+ d->maskSize = QSizeF(144.0,144.0);
}
KoGamutMask::KoGamutMask()
: KoResource(QString())
, d(new Private())
{
+ d->maskSize = QSizeF(144.0,144.0);
}
KoGamutMask::KoGamutMask(KoGamutMask* rhs)
: QObject(0)
, KoResource(QString())
, d(new Private())
{
setFilename(rhs->filename());
setTitle(rhs->title());
setDescription(rhs->description());
d->maskSize = rhs->d->maskSize;
QList newShapes;
- for(KoGamutMaskShape* sh: d->maskShapes) {
- KoShape* shape = sh->koShape();
- newShapes.append(shape);
+ for(KoShape* sh: rhs->koShapes()) {
+ newShapes.append(sh->cloneShape());
}
setMaskShapes(newShapes);
setValid(true);
}
bool KoGamutMask::coordIsClear(const QPointF& coord, KoViewConverter &viewConverter, bool preview)
{
QVector* shapeVector;
if (preview && !d->previewShapes.isEmpty()) {
shapeVector = &d->previewShapes;
} else {
shapeVector = &d->maskShapes;
}
for(KoGamutMaskShape* shape: *shapeVector) {
if (shape->coordIsClear(coord, viewConverter) == true) {
return true;
}
}
return false;
}
void KoGamutMask::paint(QPainter &painter, KoViewConverter& viewConverter, bool preview)
{
QVector* shapeVector;
if (preview && !d->previewShapes.isEmpty()) {
shapeVector = &d->previewShapes;
} else {
shapeVector = &d->maskShapes;
}
for(KoGamutMaskShape* shape: *shapeVector) {
shape->paint(painter, viewConverter);
}
}
+void KoGamutMask::paintStroke(QPainter &painter, KoViewConverter &viewConverter, bool preview)
+{
+ QVector* shapeVector;
+
+ if (preview && !d->previewShapes.isEmpty()) {
+ shapeVector = &d->previewShapes;
+ } else {
+ shapeVector = &d->maskShapes;
+ }
+
+ for(KoGamutMaskShape* shape: *shapeVector) {
+ shape->paintStroke(painter, viewConverter);
+ }
+}
+
bool KoGamutMask::load()
{
QFile file(filename());
if (file.size() == 0) return false;
if (!file.open(QIODevice::ReadOnly)) {
warnFlake << "Can't open file " << filename();
return false;
}
bool res = loadFromDevice(&file);
- setValid(res);
file.close();
return res;
}
bool KoGamutMask::loadFromDevice(QIODevice *dev)
{
if (!dev->isOpen()) dev->open(QIODevice::ReadOnly);
d->data = dev->readAll();
- Q_ASSERT(d->data.size() != 0);
+ // TODO: test
+ KIS_ASSERT_RECOVER_RETURN_VALUE(d->data.size() != 0, false);
if (filename().isNull()) {
warnFlake << "Cannot load gamut mask" << name() << "there is no filename set";
return false;
}
if (d->data.isNull()) {
QFile file(filename());
if (file.size() == 0) {
warnFlake << "Cannot load gamut mask" << name() << "there is no data available";
return false;
}
file.open(QIODevice::ReadOnly);
d->data = file.readAll();
file.close();
}
QBuffer buf(&d->data);
buf.open(QBuffer::ReadOnly);
KoStore* store(KoStore::createStore(&buf, KoStore::Read, "application/x-krita-gamutmask", KoStore::Zip));
if (!store || store->bad()) return false;
bool storeOpened = store->open("gamutmask.svg");
if (!storeOpened) { return false; }
QByteArray data;
data.resize(store->size());
QByteArray ba = store->read(store->size());
store->close();
KoXmlDocument xmlDocument;
QString errorMsg;
int errorLine = 0;
- int errorColumn;
+ int errorColumn = 0;
bool ok = xmlDocument.setContent(ba, false, &errorMsg, &errorLine, &errorColumn);
if (!ok) {
errorFlake << "Parsing error in " << filename() << "! Aborting!" << endl
<< " In line: " << errorLine << ", column: " << errorColumn << endl
<< " Error message: " << errorMsg << endl;
errorFlake << "Parsing error in the main document at line" << errorLine
<< ", column" << errorColumn << endl
<< "Error message: " << errorMsg;
return false;
}
KoDocumentResourceManager manager;
SvgParser parser(&manager);
parser.setResolution(QRectF(0,0,100,100), 72); // initialize with default values
QSizeF fragmentSize;
QList shapes = parser.parseSvg(xmlDocument.documentElement(), &fragmentSize);
d->maskSize = fragmentSize;
d->title = parser.documentTitle();
setName(d->title);
d->description = parser.documentDescription();
setMaskShapes(shapes);
if (store->open("preview.png")) {
KoStoreDevice previewDev(store);
previewDev.open(QIODevice::ReadOnly);
QImage preview = QImage();
preview.load(&previewDev, "PNG");
setImage(preview);
(void)store->close();
}
buf.close();
+ setValid(true);
+
return true;
}
void KoGamutMask::setMaskShapes(QList shapes)
{
setMaskShapesToVector(shapes, d->maskShapes);
}
bool KoGamutMask::save()
{
QFile file(filename());
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return false;
}
saveToDevice(&file);
file.close();
return true;
}
QList KoGamutMask::koShapes() const
{
QList shapes;
for(KoGamutMaskShape* maskShape: d->maskShapes) {
shapes.append(maskShape->koShape());
}
return shapes;
}
bool KoGamutMask::saveToDevice(QIODevice *dev) const
{
KoStore* store(KoStore::createStore(dev, KoStore::Write, "application/x-krita-gamutmask", KoStore::Zip));
if (!store || store->bad()) return false;
QList shapes = koShapes();
std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
if (!store->open("gamutmask.svg")) {
return false;
}
KoStoreDevice storeDev(store);
storeDev.open(QIODevice::WriteOnly);
SvgWriter writer(shapes);
writer.setDocumentTitle(d->title);
writer.setDocumentDescription(d->description);
writer.save(storeDev, d->maskSize);
if (!store->close()) { return false; }
if (!store->open("preview.png")) {
return false;
}
KoStoreDevice previewDev(store);
previewDev.open(QIODevice::WriteOnly);
image().save(&previewDev, "PNG");
if (!store->close()) { return false; }
return store->finalize();
}
QString KoGamutMask::title()
{
return d->title;
}
void KoGamutMask::setTitle(QString title)
{
d->title = title;
setName(title);
}
QString KoGamutMask::description()
{
return d->description;
}
void KoGamutMask::setDescription(QString description)
{
d->description = description;
}
QSizeF KoGamutMask::maskSize()
{
return d->maskSize;
}
-// TODO: rethink preview
void KoGamutMask::setPreviewMaskShapes(QList shapes)
{
setMaskShapesToVector(shapes, d->previewShapes);
}
void KoGamutMask::setMaskShapesToVector(QList shapes, QVector &targetVector)
{
targetVector.clear();
for(KoShape* sh: shapes) {
KoGamutMaskShape* maskShape = new KoGamutMaskShape(sh);
targetVector.append(maskShape);
}
}
// clean up when ending mask preview
void KoGamutMask::clearPreview()
{
d->previewShapes.clear();
}
diff --git a/libs/flake/resources/KoGamutMask.h b/libs/flake/resources/KoGamutMask.h
index 74a31e2398..e55af16541 100644
--- a/libs/flake/resources/KoGamutMask.h
+++ b/libs/flake/resources/KoGamutMask.h
@@ -1,88 +1,97 @@
+/*
+ * Copyright (c) 2018 Anna Medonosova
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
#ifndef KOGAMUTMASK_H
#define KOGAMUTMASK_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
class KoViewConverter;
class KoGamutMaskShape
{
public:
KoGamutMaskShape(KoShape* shape);
KoGamutMaskShape();
~KoGamutMaskShape();
bool coordIsClear(const QPointF& coord, const KoViewConverter& viewConverter) const;
QPainterPath outline();
void paint(QPainter &painter, const KoViewConverter& viewConverter);
+ void paintStroke(QPainter &painter, const KoViewConverter& viewConverter);
KoShape* koShape();
private:
KoShape* m_maskShape;
KoShapePaintingContext m_shapePaintingContext;
};
/**
* @brief The resource type for gamut masks used by the artistic color selector
*/
class KRITAFLAKE_EXPORT KoGamutMask : public QObject, public KoResource
{
Q_OBJECT
public:
- /**
- * @brief load a gamut mask from given file
- * @param filename
- */
KoGamutMask(const QString &filename);
-
- /**
- * @brief create KoGamutMask from polygons
- * @param polygons
- */
KoGamutMask();
-
- // TODO: copy constructor, for duplicating masks
KoGamutMask(KoGamutMask *rhs);
bool coordIsClear(const QPointF& coord, KoViewConverter& viewConverter, bool preview);
bool load() override __attribute__((optimize(0)));
bool loadFromDevice(QIODevice *dev) override;
bool save() override;
bool saveToDevice(QIODevice* dev) const override;
void paint(QPainter &painter, KoViewConverter& viewConverter, bool preview);
+ void paintStroke(QPainter &painter, KoViewConverter& viewConverter, bool preview);
QString title();
void setTitle(QString title);
QString description();
void setDescription(QString description);
QSizeF maskSize();
void setMaskShapes(QList shapes);
void setPreviewMaskShapes(QList shapes);
- void setMaskShapesToVector(QList shapes, QVector& targetVector);
QList koShapes() const;
- // switch back to loaded shapes when ending mask preview
void clearPreview();
+
private:
+ void setMaskShapesToVector(QList shapes, QVector& targetVector);
+
struct Private;
Private* const d;
};
#endif // KOGAMUTMASK_H
diff --git a/libs/ui/KisResourceBundle.cpp b/libs/ui/KisResourceBundle.cpp
index cb0bdbfe45..bf27fb279e 100644
--- a/libs/ui/KisResourceBundle.cpp
+++ b/libs/ui/KisResourceBundle.cpp
@@ -1,1018 +1,1093 @@
/*
* Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KisResourceBundle.h"
#include "KisResourceBundleManifest.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
KisResourceBundle::KisResourceBundle(QString const& fileName)
: KoResource(fileName),
m_bundleVersion("1")
{
setName(QFileInfo(fileName).baseName());
m_metadata["generator"] = "Krita (" + KritaVersionWrapper::versionString(true) + ")";
}
KisResourceBundle::~KisResourceBundle()
{
}
QString KisResourceBundle::defaultFileExtension() const
{
return QString(".bundle");
}
bool KisResourceBundle::load()
{
if (filename().isEmpty()) return false;
QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip));
if (!resourceStore || resourceStore->bad()) {
warnKrita << "Could not open store on bundle" << filename();
m_installed = false;
setValid(false);
return false;
} else {
m_metadata.clear();
bool toRecreate = false;
if (resourceStore->open("META-INF/manifest.xml")) {
if (!m_manifest.load(resourceStore->device())) {
warnKrita << "Could not open manifest for bundle" << filename();
return false;
}
resourceStore->close();
Q_FOREACH (KisResourceBundleManifest::ResourceReference ref, m_manifest.files()) {
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Bundle is broken. File" << ref.resourcePath << "is missing";
toRecreate = true;
}
else {
resourceStore->close();
}
}
if(toRecreate) {
warnKrita << "Due to missing files and wrong entries in the manifest, " << filename() << " will be recreated.";
}
} else {
warnKrita << "Could not load META-INF/manifest.xml";
return false;
}
bool versionFound = false;
if (resourceStore->open("meta.xml")) {
KoXmlDocument doc;
if (!doc.setContent(resourceStore->device())) {
warnKrita << "Could not parse meta.xml for" << filename();
return false;
}
// First find the manifest:manifest node.
KoXmlNode n = doc.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (!n.isElement()) {
continue;
}
if (n.toElement().tagName() == "meta:meta") {
break;
}
}
if (n.isNull()) {
warnKrita << "Could not find manifest node for bundle" << filename();
return false;
}
const KoXmlElement metaElement = n.toElement();
for (n = metaElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
if (n.isElement()) {
KoXmlElement e = n.toElement();
if (e.tagName() == "meta:generator") {
m_metadata.insert("generator", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:author") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:title") {
m_metadata.insert("title", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:description") {
m_metadata.insert("description", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:initial-creator") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:creator") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:creation-date") {
m_metadata.insert("created", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:dc-date") {
m_metadata.insert("updated", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:meta-userdefined") {
if (e.attribute("meta:name") == "tag") {
m_bundletags << e.attribute("meta:value");
}
else {
m_metadata.insert(e.attribute("meta:name"), e.attribute("meta:value"));
}
}
else if(e.tagName() == "meta:bundle-version") {
m_metadata.insert("bundle-version", e.firstChild().toText().data());
versionFound = true;
}
}
}
resourceStore->close();
}
else {
warnKrita << "Could not load meta.xml";
return false;
}
if (resourceStore->open("preview.png")) {
// Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice
// fails with "libpng error: IDAT: CRC error"
QByteArray data = resourceStore->device()->readAll();
QBuffer buffer(&data);
m_thumbnail.load(&buffer, "PNG");
resourceStore->close();
}
else {
warnKrita << "Could not open preview.png";
}
/*
* If no version is found it's an old bundle with md5 hashes to fix, or if some manifest resource entry
* doesn't not correspond to a file the bundle is "broken", in both cases we need to recreate the bundle.
*/
if (!versionFound) {
m_metadata.insert("bundle-version", "1");
warnKrita << filename() << " has an old version and possibly wrong resources md5, so it will be recreated.";
toRecreate = true;
}
if (toRecreate) {
recreateBundle(resourceStore);
}
m_installed = true;
setValid(true);
setImage(m_thumbnail);
}
return true;
}
bool KisResourceBundle::loadFromDevice(QIODevice *)
{
return false;
}
bool saveResourceToStore(KoResource *resource, KoStore *store, const QString &resType)
{
if (!resource) {
warnKrita << "No Resource";
return false;
}
if (!resource->valid()) {
warnKrita << "Resource is not valid";
return false;
}
if (!store || store->bad()) {
warnKrita << "No Store or Store is Bad";
return false;
}
QByteArray ba;
QBuffer buf;
QFileInfo fi(resource->filename());
if (fi.exists() && fi.isReadable()) {
QFile f(resource->filename());
if (!f.open(QFile::ReadOnly)) {
warnKrita << "Could not open resource" << resource->filename();
return false;
}
ba = f.readAll();
if (ba.size() == 0) {
warnKrita << "Resource is empty" << resource->filename();
return false;
}
f.close();
buf.setBuffer(&ba);
}
else {
warnKrita << "Could not find the resource " << resource->filename() << " or it isn't readable";
return false;
}
if (!buf.open(QBuffer::ReadOnly)) {
warnKrita << "Could not open buffer";
return false;
}
Q_ASSERT(!store->hasFile(resType + "/" + resource->shortFilename()));
if (!store->open(resType + "/" + resource->shortFilename())) {
warnKrita << "Could not open file in store for resource";
return false;
}
bool res = (store->write(buf.data()) == buf.size());
store->close();
return res;
}
bool KisResourceBundle::save()
{
if (filename().isEmpty()) return false;
addMeta("updated", QDate::currentDate().toString("dd/MM/yyyy"));
QDir bundleDir = KoResourcePaths::saveLocation("data", "bundles");
bundleDir.cdUp();
QScopedPointer store(KoStore::createStore(filename(), KoStore::Write, "application/x-krita-resourcebundle", KoStore::Zip));
if (!store || store->bad()) return false;
Q_FOREACH (const QString &resType, m_manifest.types()) {
if (resType == "ko_gradients") {
KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KoResource *res = gradientServer->resourceByMD5(ref.md5sum);
if (!res) res = gradientServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
if (!saveResourceToStore(res, store.data(), "gradients")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
else if (resType == "ko_patterns") {
KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KoResource *res = patternServer->resourceByMD5(ref.md5sum);
if (!res) res = patternServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
if (!saveResourceToStore(res, store.data(), "patterns")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
else if (resType == "kis_brushes") {
KisBrushResourceServer* brushServer = KisBrushServer::instance()->brushServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KisBrushSP brush = brushServer->resourceByMD5(ref.md5sum);
if (!brush) brush = brushServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
KoResource *res = brush.data();
if (!saveResourceToStore(res, store.data(), "brushes")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
else if (resType == "ko_palettes") {
KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KoResource *res = paletteServer->resourceByMD5(ref.md5sum);
if (!res) res = paletteServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
if (!saveResourceToStore(res, store.data(), "palettes")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
else if (resType == "kis_workspaces") {
KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KoResource *res = workspaceServer->resourceByMD5(ref.md5sum);
if (!res) res = workspaceServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
if (!saveResourceToStore(res, store.data(), "workspaces")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
else if (resType == "kis_paintoppresets") {
KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum);
if (!res) res = paintoppresetServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
if (!saveResourceToStore(res.data(), store.data(), "paintoppresets")) {
if (res) {
warnKrita << "Could not save resource" << resType << res->name();
}
else {
warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
}
}
}
}
+ else if (resType == "ko_gamutmasks") {
+ KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer();
+ Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
+ KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum);
+ if (!res) res = gamutMaskServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName());
+ if (!saveResourceToStore(res, store.data(), "gamutmasks")) {
+ if (res) {
+ warnKrita << "Could not save resource" << resType << res->name();
+ }
+ else {
+ warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName();
+ }
+ }
+ }
+ }
}
if (!m_thumbnail.isNull()) {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_thumbnail.save(&buffer, "PNG");
if (!store->open("preview.png")) warnKrita << "Could not open preview.png";
if (store->write(byteArray) != buffer.size()) warnKrita << "Could not write preview.png";
store->close();
}
saveManifest(store);
saveMetadata(store);
store->finalize();
return true;
}
bool KisResourceBundle::saveToDevice(QIODevice */*dev*/) const
{
return false;
}
bool KisResourceBundle::install()
{
QStringList md5Mismatch;
if (filename().isEmpty()) {
warnKrita << "Cannot install bundle: no file name" << this;
return false;
}
QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip));
if (!resourceStore || resourceStore->bad()) {
warnKrita << "Cannot open the resource bundle: invalid zip file?";
return false;
}
Q_FOREACH (const QString &resType, m_manifest.types()) {
dbgResources << "Installing resource type" << resType;
if (resType == "gradients") {
KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KoAbstractGradient *res = gradientServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
if (!res->loadFromDevice(resourceStore->device())) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name();
KoAbstractGradient *res2 = gradientServer->resourceByName(res->name());
if (!res2) {//if it doesn't exist...
gradientServer->addResource(res, false);//add it!
if (!m_gradientsMd5Installed.contains(res->md5())) {
m_gradientsMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
gradientServer->addTag(res, tag);
}
//gradientServer->addTag(res, name());
}
else {
//warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
}
}
}
else if (resType == "patterns") {
KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KoPattern *res = patternServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
if (!res->loadFromDevice(resourceStore->device())) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name();
KoPattern *res2 = patternServer->resourceByName(res->name());
if (!res2) {//if it doesn't exist...
patternServer->addResource(res, false);//add it!
if (!m_patternsMd5Installed.contains(res->md5())) {
m_patternsMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
patternServer->addTag(res, tag);
}
//patternServer->addTag(res, name());
}
}
}
else if (resType == "brushes") {
KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KisBrushSP res = brushServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
if (!res->loadFromDevice(resourceStore->device())) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name();
//find the resource on the server
KisBrushSP res2 = brushServer->resourceByName(res->name());
if (res2) {
res->setName(res->name()+"("+res->shortFilename()+")");
}
// file name is more important than the regular name because the
// it is the way how it is called up from the brushpreset settings.
// Therefore just adjust the resource name and only refuse to load
// when the filename is different.
res2 = brushServer->resourceByFilename(res->shortFilename());
if (!res2) {//if it doesn't exist...
brushServer->addResource(res, false);//add it!
if (!m_brushesMd5Installed.contains(res->md5())) {
m_brushesMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
brushServer->addTag(res.data(), tag);
}
//brushServer->addTag(res.data(), name());
}
else {
//warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
}
}
}
else if (resType == "palettes") {
KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KoColorSet *res = paletteServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
if (!res->loadFromDevice(resourceStore->device())) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name();
//find the resource on the server
KoColorSet *res2 = paletteServer->resourceByName(res->name());
if (!res2) {//if it doesn't exist...
paletteServer->addResource(res, false);//add it!
if (!m_palettesMd5Installed.contains(res->md5())) {
m_palettesMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
paletteServer->addTag(res, tag);
}
//paletteServer->addTag(res, name());
}
else {
//warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
}
}
}
else if (resType == "workspaces") {
KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KisWorkspaceResource *res = workspaceServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
if (!res->loadFromDevice(resourceStore->device())) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name();
//the following tries to find the resource by name.
KisWorkspaceResource *res2 = workspaceServer->resourceByName(res->name());
if (!res2) {//if it doesn't exist...
workspaceServer->addResource(res, false);//add it!
if (!m_workspacesMd5Installed.contains(res->md5())) {
m_workspacesMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
workspaceServer->addTag(res, tag);
}
//workspaceServer->addTag(res, name());
}
else {
//warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
}
}
}
else if (resType == "paintoppresets") {
KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer();
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
if (resourceStore->isOpen()) resourceStore->close();
dbgResources << "\tInstalling" << ref.resourcePath;
KisPaintOpPresetSP res = paintoppresetServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
if (!res) {
warnKrita << "Could not create resource for" << ref.resourcePath;
continue;
}
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
continue;
}
// Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice
// fails with "libpng error: IDAT: CRC error"
QByteArray data = resourceStore->device()->readAll();
QBuffer buffer(&data);
if (!res->loadFromDevice(&buffer)) {
warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
continue;
}
dbgResources << "\t\tresource:" << res->name() << "File:" << res->filename();
//the following tries to find the resource by name.
KisPaintOpPresetSP res2 = paintoppresetServer->resourceByName(res->name());
if (!res2) {//if it doesn't exist...
paintoppresetServer->addResource(res, false);//add it!
if (!m_presetsMd5Installed.contains(res->md5())){
m_presetsMd5Installed.append(res->md5());
}
if (ref.md5sum!=res->md5()) {
md5Mismatch.append(res->name());
}
Q_FOREACH (const QString &tag, ref.tagList) {
paintoppresetServer->addTag(res.data(), tag);
}
//paintoppresetServer->addTag(res.data(), name());
}
else {
//warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
}
}
}
+ else if (resType == "gamutmasks") {
+ KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer();
+ Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) {
+
+ if (resourceStore->isOpen()) resourceStore->close();
+
+ dbgResources << "\tInstalling" << ref.resourcePath;
+ KoGamutMask *res = gamutMaskServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath));
+
+ if (!res) {
+ warnKrita << "Could not create resource for" << ref.resourcePath;
+ continue;
+ }
+ if (!resourceStore->open(ref.resourcePath)) {
+ warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename();
+ continue;
+ }
+ if (!res->loadFromDevice(resourceStore->device())) {
+ warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename();
+ continue;
+ }
+ dbgResources << "\t\tresource:" << res->name();
+
+ //find the resource on the server
+ KoGamutMask *res2 = gamutMaskServer->resourceByName(res->name());
+ if (!res2) {//if it doesn't exist...
+ gamutMaskServer->addResource(res, false);//add it!
+
+ if (!m_gamutMasksMd5Installed.contains(res->md5())) {
+ m_gamutMasksMd5Installed.append(res->md5());
+ }
+ if (ref.md5sum!=res->md5()) {
+ md5Mismatch.append(res->name());
+ }
+
+ Q_FOREACH (const QString &tag, ref.tagList) {
+ gamutMaskServer->addTag(res, tag);
+ }
+ //gamutMaskServer->addTag(res, name());
+ }
+ else {
+ //warnKrita << "Didn't install" << res->name()<<"It already exists on the server";
+ }
+ }
+ }
}
m_installed = true;
if(!md5Mismatch.isEmpty()){
QString message = i18n("The following resources had mismatching MD5 sums. They may have gotten corrupted, for example, during download.");
QMessageBox bundleFeedback;
bundleFeedback.setIcon(QMessageBox::Warning);
Q_FOREACH (QString name, md5Mismatch) {
message.append("\n");
message.append(name);
}
bundleFeedback.setText(message);
bundleFeedback.exec();
}
return true;
}
bool KisResourceBundle::uninstall()
{
m_installed = false;
QStringList tags = getTagsList();
tags << m_manifest.tags();
//tags << name();
KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("gradients")) {
Q_FOREACH (const QByteArray md5, m_gradientsMd5Installed) {
KoAbstractGradient *res = gradientServer->resourceByMD5(md5);
if (res) {
gradientServer->removeResourceFromServer(res);
}
}
KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("patterns")) {
Q_FOREACH (const QByteArray md5, m_patternsMd5Installed) {
KoPattern *res = patternServer->resourceByMD5(md5);
if (res) {
patternServer->removeResourceFromServer(res);
}
}
KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("brushes")) {
Q_FOREACH (const QByteArray md5, m_brushesMd5Installed) {
KisBrushSP res = brushServer->resourceByMD5(md5);
if (res) {
brushServer->removeResourceFromServer(res);
}
}
KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("palettes")) {
Q_FOREACH (const QByteArray md5, m_palettesMd5Installed) {
KoColorSet *res = paletteServer->resourceByMD5(md5);
if (res) {
paletteServer->removeResourceFromServer(res);
}
}
KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("workspaces")) {
Q_FOREACH (const QByteArray md5, m_workspacesMd5Installed) {
KisWorkspaceResource *res = workspaceServer->resourceByMD5(md5);
if (res) {
workspaceServer->removeResourceFromServer(res);
}
}
KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer();
//Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("paintoppresets")) {
Q_FOREACH (const QByteArray md5, m_presetsMd5Installed) {
KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(md5);
if (res) {
paintoppresetServer->removeResourceFromServer(res);
}
}
+ KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer();
+ //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("gamutmasks")) {
+ Q_FOREACH (const QByteArray md5, m_gamutMasksMd5Installed) {
+ KoGamutMask *res = gamutMaskServer->resourceByMD5(md5);
+ if (res) {
+ gamutMaskServer->removeResourceFromServer(res);
+ }
+ }
+
Q_FOREACH(const QString &tag, tags) {
paintoppresetServer->tagCategoryRemoved(tag);
workspaceServer->tagCategoryRemoved(tag);
paletteServer->tagCategoryRemoved(tag);
brushServer->tagCategoryRemoved(tag);
patternServer->tagCategoryRemoved(tag);
gradientServer->tagCategoryRemoved(tag);
+ gamutMaskServer->tagCategoryRemoved(tag);
}
return true;
}
void KisResourceBundle::addMeta(const QString &type, const QString &value)
{
m_metadata.insert(type, value);
}
const QString KisResourceBundle::getMeta(const QString &type, const QString &defaultValue) const
{
if (m_metadata.contains(type)) {
return m_metadata[type];
}
else {
return defaultValue;
}
}
void KisResourceBundle::addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum)
{
m_manifest.addResource(fileType, filePath, fileTagList, md5sum);
}
QList KisResourceBundle::getTagsList()
{
return QList::fromSet(m_bundletags);
}
bool KisResourceBundle::isInstalled()
{
return m_installed;
}
QStringList KisResourceBundle::resourceTypes() const
{
return m_manifest.types();
}
QList KisResourceBundle::resources(const QString &resType) const
{
QList references = m_manifest.files(resType);
QList ret;
Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, references) {
if (resType == "gradients") {
KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer();
KoResource *res = gradientServer->resourceByMD5(ref.md5sum);
if (res) ret << res;
}
else if (resType == "patterns") {
KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer();
KoResource *res = patternServer->resourceByMD5(ref.md5sum);
if (res) ret << res;
}
else if (resType == "brushes") {
KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer();
KoResource *res = brushServer->resourceByMD5(ref.md5sum).data();
if (res) ret << res;
}
else if (resType == "palettes") {
KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer();
KoResource *res = paletteServer->resourceByMD5(ref.md5sum);
if (res) ret << res;
}
else if (resType == "workspaces") {
KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer();
KoResource *res = workspaceServer->resourceByMD5(ref.md5sum);
if (res) ret << res;
}
else if (resType == "paintoppresets") {
KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer();
KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum);
if (res) ret << res.data();
}
+ else if (resType == "gamutmasks") {
+ KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer();
+ KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum);
+ if (res) ret << res;
+ }
}
return ret;
}
void KisResourceBundle::setThumbnail(QString filename)
{
if (QFileInfo(filename).exists()) {
m_thumbnail = QImage(filename);
m_thumbnail = m_thumbnail.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
else {
m_thumbnail = QImage(256, 256, QImage::Format_ARGB32);
QPainter gc(&m_thumbnail);
gc.fillRect(0, 0, 256, 256, Qt::red);
gc.end();
}
setImage(m_thumbnail);
}
void KisResourceBundle::writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer)
{
if (m_metadata.contains(metaKey)) {
writer->startElement(metaTag);
writer->addTextNode(m_metadata[metaKey].toUtf8());
writer->endElement();
}
}
void KisResourceBundle::writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer)
{
if (m_metadata.contains(metaKey)) {
writer->startElement("meta:meta-userdefined");
writer->addAttribute("meta:name", metaKey);
writer->addAttribute("meta:value", m_metadata[metaKey]);
writer->endElement();
}
}
void KisResourceBundle::setInstalled(bool install)
{
m_installed = install;
}
void KisResourceBundle::saveMetadata(QScopedPointer &store)
{
QBuffer buf;
store->open("meta.xml");
buf.open(QBuffer::WriteOnly);
KoXmlWriter metaWriter(&buf);
metaWriter.startDocument("office:document-meta");
metaWriter.startElement("meta:meta");
writeMeta("meta:generator", "generator", &metaWriter);
metaWriter.startElement("meta:bundle-version");
metaWriter.addTextNode(m_bundleVersion.toUtf8());
metaWriter.endElement();
writeMeta("dc:author", "author", &metaWriter);
writeMeta("dc:title", "filename", &metaWriter);
writeMeta("dc:description", "description", &metaWriter);
writeMeta("meta:initial-creator", "author", &metaWriter);
writeMeta("dc:creator", "author", &metaWriter);
writeMeta("meta:creation-date", "created", &metaWriter);
writeMeta("meta:dc-date", "updated", &metaWriter);
writeUserDefinedMeta("email", &metaWriter);
writeUserDefinedMeta("license", &metaWriter);
writeUserDefinedMeta("website", &metaWriter);
Q_FOREACH (const QString &tag, m_bundletags) {
metaWriter.startElement("meta:meta-userdefined");
metaWriter.addAttribute("meta:name", "tag");
metaWriter.addAttribute("meta:value", tag);
metaWriter.endElement();
}
metaWriter.endElement(); // meta:meta
metaWriter.endDocument();
buf.close();
store->write(buf.data());
store->close();
}
void KisResourceBundle::saveManifest(QScopedPointer &store)
{
store->open("META-INF/manifest.xml");
QBuffer buf;
buf.open(QBuffer::WriteOnly);
m_manifest.save(&buf);
buf.close();
store->write(buf.data());
store->close();
}
void KisResourceBundle::recreateBundle(QScopedPointer &oldStore)
{
// Save a copy of the unmodified bundle, so that if anything goes bad the user doesn't lose it
QFile file(filename());
file.copy(filename() + ".old");
QString newStoreName = filename() + ".tmp";
QScopedPointer store(KoStore::createStore(newStoreName, KoStore::Write, "application/x-krita-resourcebundle", KoStore::Zip));
KoHashGenerator *generator = KoHashGeneratorProvider::instance()->getGenerator("MD5");
KisResourceBundleManifest newManifest;
addMeta("updated", QDate::currentDate().toString("dd/MM/yyyy"));
Q_FOREACH (KisResourceBundleManifest::ResourceReference ref, m_manifest.files()) {
// Wrong manifest entry found, skip it
if(!oldStore->open(ref.resourcePath))
continue;
store->open(ref.resourcePath);
QByteArray data = oldStore->device()->readAll();
oldStore->close();
store->write(data);
store->close();
QByteArray result = generator->generateHash(data);
newManifest.addResource(ref.fileTypeName, ref.resourcePath, ref.tagList, result);
}
m_manifest = newManifest;
if (!m_thumbnail.isNull()) {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_thumbnail.save(&buffer, "PNG");
if (!store->open("preview.png")) warnKrita << "Could not open preview.png";
if (store->write(byteArray) != buffer.size()) warnKrita << "Could not write preview.png";
store->close();
}
saveManifest(store);
saveMetadata(store);
store->finalize();
// Remove the current bundle and then move the tmp one to be the correct one
file.setFileName(filename());
file.remove();
file.setFileName(newStoreName);
file.rename(filename());
}
int KisResourceBundle::resourceCount() const
{
return m_manifest.files().count();
}
diff --git a/libs/ui/KisResourceBundle.h b/libs/ui/KisResourceBundle.h
index 5a5f26f3ad..3ffc188b26 100644
--- a/libs/ui/KisResourceBundle.h
+++ b/libs/ui/KisResourceBundle.h
@@ -1,159 +1,160 @@
/*
* Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KORESOURCEBUNDLE_H
#define KORESOURCEBUNDLE_H
#include
#include
#include
#include
#include "KisResourceBundleManifest.h"
#include "kritaui_export.h"
class KoStore;
/**
* @brief The ResourceBundle class
* @details Describe the resource bundles as KoResources
*/
class KRITAUI_EXPORT KisResourceBundle : public KoResource
{
public:
/**
* @brief ResourceBundle : Ctor * @param bundlePath the path of the bundle
*/
KisResourceBundle(QString const& fileName);
/**
* @brief ~ResourceBundle : Dtor
*/
~KisResourceBundle() override;
/**
* @brief defaultFileExtension
* @return the default file extension which should be when saving the resource
*/
QString defaultFileExtension() const override;
/**
* @brief load : Load this resource.
* @return true if succeed, false otherwise.
*/
bool load() override;
bool loadFromDevice(QIODevice *dev) override;
/**
* @brief save : Save this resource.
* @return true if succeed, false otherwise.
*/
bool save() override;
bool saveToDevice(QIODevice* dev) const override;
/**
* @brief install : Install the contents of the resource bundle.
*/
bool install();
/**
* @brief uninstall : Uninstall the resource bundle.
*/
bool uninstall();
/**
* @brief addMeta : Add a Metadata to the resource
* @param type type of the metadata
* @param value value of the metadata
*/
void addMeta(const QString &type, const QString &value);
const QString getMeta(const QString &type, const QString &defaultValue = QString()) const;
/**
* @brief addFile : Add a file to the bundle
* @param fileType type of the resource file
* @param filePath path of the resource file
*/
void addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum);
QList getTagsList();
/**
* @brief isInstalled
* @return true if the bundle is installed, false otherwise.
*/
bool isInstalled();
/**
* @brief setInstalled
* This allows you to set installed or uninstalled upon loading. This is used with blacklists.
*/
void setInstalled(bool install);
void setThumbnail(QString);
/**
* @brief saveMetadata: saves bundle metadata
* @param store bundle where to save the metadata
*/
void saveMetadata(QScopedPointer &store);
/**
* @brief saveManifest: saves bundle manifest
* @param store bundle where to save the manifest
*/
void saveManifest(QScopedPointer &store);
/**
* @brief recreateBundle
* It recreates the bundle by copying the old bundle information to a new store
* and recalculating the md5 of each resource.
* @param oldStore the old store to be recreated.
*/
void recreateBundle(QScopedPointer &oldStore);
QStringList resourceTypes() const;
QList resources(const QString &resType = QString()) const;
int resourceCount() const;
private:
void writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer);
void writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer);
private:
QImage m_thumbnail;
KisResourceBundleManifest m_manifest;
QMap m_metadata;
QSet m_bundletags;
bool m_installed;
QList m_gradientsMd5Installed;
QList m_patternsMd5Installed;
QList m_brushesMd5Installed;
QList m_palettesMd5Installed;
QList m_workspacesMd5Installed;
QList m_presetsMd5Installed;
+ QList m_gamutMasksMd5Installed;
QString m_bundleVersion;
};
#endif // KORESOURCEBUNDLE_H
diff --git a/libs/ui/KisResourceBundleManifest.cpp b/libs/ui/KisResourceBundleManifest.cpp
index e9624ae6ec..0b14fc4f77 100644
--- a/libs/ui/KisResourceBundleManifest.cpp
+++ b/libs/ui/KisResourceBundleManifest.cpp
@@ -1,232 +1,232 @@
/* This file is part of the KDE project
Copyright (C) 2014, Victor Lafon
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see .
*/
#include "KisResourceBundleManifest.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_brush_server.h"
#include "KisResourceServerProvider.h"
#include
#include "kis_workspace_resource.h"
QString resourceTypeToManifestType(const QString &type) {
if (type.startsWith("ko_")) {
return type.mid(3);
}
else if (type.startsWith("kis_")) {
return type.mid(4);
}
else {
return type;
}
}
QString manifestTypeToResourceType(const QString &type) {
- if (type == "patterns" || type == "gradients" || type == "palettes") {
+ if (type == "patterns" || type == "gradients" || type == "palettes" || type == "gamutmasks") {
return "ko_" + type;
}
else {
return "kis_" + type;
}
}
KisResourceBundleManifest::KisResourceBundleManifest()
{
}
KisResourceBundleManifest::~KisResourceBundleManifest()
{
}
bool KisResourceBundleManifest::load(QIODevice *device)
{
m_resources.clear();
if (!device->isOpen()) {
if (!device->open(QIODevice::ReadOnly)) {
return false;
}
}
KoXmlDocument manifestDocument;
QString errorMessage;
int errorLine;
int errorColumn;
if (!manifestDocument.setContent(device, true, &errorMessage, &errorLine, &errorColumn)) {
return false;
}
if (!errorMessage.isEmpty()) {
warnKrita << "Error parsing manifest" << errorMessage << "line" << errorLine << "column" << errorColumn;
return false;
}
// First find the manifest:manifest node.
KoXmlNode n = manifestDocument.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (!n.isElement()) {
continue;
}
if (n.toElement().localName() == "manifest" && n.toElement().namespaceURI() == KoXmlNS::manifest) {
break;
}
}
if (n.isNull()) {
// "Could not find manifest:manifest";
return false;
}
// Now loop through the children of the manifest:manifest and
// store all the manifest:file-entry elements.
const KoXmlElement manifestElement = n.toElement();
for (n = manifestElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
if (!n.isElement())
continue;
KoXmlElement el = n.toElement();
if (!(el.localName() == "file-entry" && el.namespaceURI() == KoXmlNS::manifest))
continue;
QString fullPath = el.attributeNS(KoXmlNS::manifest, "full-path", QString());
QString mediaType = el.attributeNS(KoXmlNS::manifest, "media-type", QString());
QString md5sum = el.attributeNS(KoXmlNS::manifest, "md5sum", QString());
QString version = el.attributeNS(KoXmlNS::manifest, "version", QString());
QStringList tagList;
KoXmlNode tagNode = n.firstChildElement().firstChildElement();
while (!tagNode.isNull()) {
if (tagNode.firstChild().isText()) {
tagList.append(tagNode.firstChild().toText().data());
}
tagNode = tagNode.nextSibling();
}
// Only if fullPath is valid, should we store this entry.
// If not, we don't bother to find out exactly what is wrong, we just skip it.
if (!fullPath.isNull() && !mediaType.isEmpty() && !md5sum.isEmpty()) {
addResource(mediaType, fullPath, tagList, QByteArray::fromHex(md5sum.toLatin1()));
}
}
return true;
}
bool KisResourceBundleManifest::save(QIODevice *device)
{
if (!device->isOpen()) {
if (!device->open(QIODevice::WriteOnly)) {
return false;
}
}
KoXmlWriter manifestWriter(device);
manifestWriter.startDocument("manifest:manifest");
manifestWriter.startElement("manifest:manifest");
manifestWriter.addAttribute("xmlns:manifest", KoXmlNS::manifest);
manifestWriter.addAttribute("manifest:version", "1.2");
manifestWriter.addManifestEntry("/", "application/x-krita-resourcebundle");
Q_FOREACH (QString resourceType, m_resources.uniqueKeys()) {
Q_FOREACH (const ResourceReference &resource, m_resources[resourceType].values()) {
manifestWriter.startElement("manifest:file-entry");
manifestWriter.addAttribute("manifest:media-type", resourceTypeToManifestType(resourceType));
manifestWriter.addAttribute("manifest:full-path", resourceTypeToManifestType(resourceType) + "/" + QFileInfo(resource.resourcePath).fileName());
manifestWriter.addAttribute("manifest:md5sum", QString(resource.md5sum.toHex()));
if (!resource.tagList.isEmpty()) {
manifestWriter.startElement("manifest:tags");
Q_FOREACH (const QString tag, resource.tagList) {
manifestWriter.startElement("manifest:tag");
manifestWriter.addTextNode(tag);
manifestWriter.endElement();
}
manifestWriter.endElement();
}
manifestWriter.endElement();
}
}
manifestWriter.endElement();
manifestWriter.endDocument();
return true;
}
void KisResourceBundleManifest::addResource(const QString &fileTypeName, const QString &fileName, const QStringList &fileTagList, const QByteArray &md5)
{
ResourceReference ref(fileName, fileTagList, fileTypeName, md5);
if (!m_resources.contains(fileTypeName)) {
m_resources[fileTypeName] = QMap();
}
m_resources[fileTypeName].insert(fileName, ref);
}
QStringList KisResourceBundleManifest::types() const
{
return m_resources.keys();
}
QStringList KisResourceBundleManifest::tags() const
{
QSet tags;
Q_FOREACH (const QString &type, m_resources.keys()) {
Q_FOREACH (const ResourceReference &ref, m_resources[type].values()) {
tags += ref.tagList.toSet();
}
}
return QStringList::fromSet(tags);
}
QList KisResourceBundleManifest::files(const QString &type) const
{
// If no type is specified we return all the resources
if(type.isEmpty()) {
QList resources;
QList >::iterator i;
QList > values = m_resources.values();
for(i = values.begin(); i != values.end(); ++i) {
resources.append(i->values());
}
return resources;
}
else if (!m_resources.contains(type)) {
return QList();
}
return m_resources[type].values();
}
void KisResourceBundleManifest::removeFile(QString fileName)
{
QList tags;
Q_FOREACH (const QString &type, m_resources.keys()) {
if (m_resources[type].contains(fileName)) {
m_resources[type].remove(fileName);
}
}
}
diff --git a/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp b/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp
index 12657278a5..5e69de6d95 100644
--- a/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp
+++ b/libs/ui/dialogs/kis_dlg_blacklist_cleanup.cpp
@@ -1,66 +1,69 @@
/*
*
* Copyright (c) 2012 Sven Langkamp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_dlg_blacklist_cleanup.h"
#include
#include
#include
#include
#include
#include
#include
#include
KisDlgBlacklistCleanup::KisDlgBlacklistCleanup()
{
setCaption(i18n("Cleanup resource files"));
setButtons(Ok | Cancel);
setDefaultButton(Ok);
QWidget* page = new QWidget(this);
setupUi(page);
setMainWidget(page);
labelWarning->setPixmap(KisIconUtils::loadIcon("warning").pixmap(32, 32));
}
void KisDlgBlacklistCleanup::accept()
{
QDialog::accept();
if (cbRemovePresets->isChecked()) {
KisResourceServerProvider::instance()->paintOpPresetServer()->removeBlackListedFiles();
}
if (cbRemoveBrushes->isChecked()) {
KisResourceServerProvider::instance()->brushBlacklistCleanup();
}
if (cbRemoveWorkspaces->isChecked()) {
KisResourceServerProvider::instance()->workspaceServer()->removeBlackListedFiles();
}
if (cbRemoveColorsets->isChecked()) {
KoResourceServerProvider::instance()->paletteServer()->removeBlackListedFiles();
}
if (cbRemoveGradients->isChecked()) {
KoResourceServerProvider::instance()->gradientServer()->removeBlackListedFiles();
}
if (cbRemovePattern->isChecked()) {
KoResourceServerProvider::instance()->patternServer()->removeBlackListedFiles();
}
+ if (cbRemoveGamutMasks->isChecked()) {
+ KoResourceServerProvider::instance()->gamutMaskServer()->removeBlackListedFiles();
+ }
}
diff --git a/libs/ui/forms/wdgdlgblacklistcleanup.ui b/libs/ui/forms/wdgdlgblacklistcleanup.ui
index afa3a12bb7..c871b39a0b 100644
--- a/libs/ui/forms/wdgdlgblacklistcleanup.ui
+++ b/libs/ui/forms/wdgdlgblacklistcleanup.ui
@@ -1,124 +1,134 @@
WdgDisplayBlacklist
0
0
457
200
0
0
Display
-
Workspaces
true
-
-
-
400
0
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'Ubuntu'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Warning</span>: Cleanup will remove resource files permanently.</p></body></html>
Qt::RichText
true
-
Use trilinear filtering when zooming. Disabling this may improve painting performance.
Gradients
true
-
Pattern
true
-
Presets
true
-
Colorsets
true
-
Brushes
true
+ -
+
+
+ Gamut Masks
+
+
+ true
+
+
+
diff --git a/plugins/dockers/artisticcolorselector/CMakeLists.txt b/plugins/dockers/artisticcolorselector/CMakeLists.txt
index a74c3c9ae4..4491ed7013 100644
--- a/plugins/dockers/artisticcolorselector/CMakeLists.txt
+++ b/plugins/dockers/artisticcolorselector/CMakeLists.txt
@@ -1,16 +1,16 @@
set(kritaartisticcolorselector_SOURCES
artisticcolorselector_plugin.cpp
artisticcolorselector_dock.cpp
kis_color.cpp
kis_color_selector.cpp
)
ki18n_wrap_ui(kritaartisticcolorselector_SOURCES
forms/wdgArtisticColorSelector.ui
forms/wdgARCSSettings.ui
forms/wdgWheelPreferencesPopup.ui
)
add_library(kritaartisticcolorselector MODULE ${kritaartisticcolorselector_SOURCES})
-target_link_libraries(kritaartisticcolorselector kritalibkis kritaui)
+target_link_libraries(kritaartisticcolorselector kritaui)
install(TARGETS kritaartisticcolorselector DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp
index a8004d5ef4..210023409d 100644
--- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp
+++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp
@@ -1,491 +1,471 @@
/*
* Copyright (c) 2009 Cyrille Berger
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include "artisticcolorselector_dock.h"
#include
#include
#include
#include "ui_wdgArtisticColorSelector.h"
#include "ui_wdgARCSSettings.h"
#include "ui_wdgWheelPreferencesPopup.h"
class KisMainWindow;
struct ArtisticColorSelectorUI: public QWidget, public Ui_wdgArtisticColorSelector
{
ArtisticColorSelectorUI() {
setupUi(this);
}
};
struct ARCSSettingsUI: public QWidget, public Ui_wdgARCSSettings
{
ARCSSettingsUI() {
setupUi(this);
}
};
struct WheelPreferencesPopupUI: public QWidget, public Ui_wdgWheelPreferencesPopup
{
WheelPreferencesPopupUI() {
setupUi(this);
}
};
ArtisticColorSelectorDock::ArtisticColorSelectorDock()
: QDockWidget(i18n("Artistic Color Selector"))
, m_resourceProvider(0)
, m_selectedMask(nullptr)
{
m_hsxButtons = new QButtonGroup();
m_preferencesUI = new ARCSSettingsUI();
m_wheelPrefsUI = new WheelPreferencesPopupUI();
m_selectorUI = new ArtisticColorSelectorUI();
QPixmap hueStepsPixmap = KisIconUtils::loadIcon("wheel-sectors").pixmap(16,16);
QPixmap saturationStepsPixmap = KisIconUtils::loadIcon("wheel-rings").pixmap(16,16);
QPixmap valueScaleStepsPixmap = KisIconUtils::loadIcon("wheel-light").pixmap(16,16);
QIcon infinityIcon = KisIconUtils::loadIcon("infinity");
m_infinityPixmap = infinityIcon.pixmap(16,16);
+ m_iconMaskOff = KisIconUtils::loadIcon("gamut-mask-off");
+ m_iconMaskOn = KisIconUtils::loadIcon("gamut-mask-on");
m_selectorUI->colorSelector->loadSettings();
+ m_selectorUI->bnWheelPrefs->setIcon(KisIconUtils::loadIcon("wheel-sectors"));
m_selectorUI->bnWheelPrefs->setPopupWidget(m_wheelPrefsUI);
- // TODO: make it into separate window
m_selectorUI->bnDockerPrefs->setPopupWidget(m_preferencesUI);
m_selectorUI->bnDockerPrefs->setIcon(KisIconUtils::loadIcon("configure"));
m_selectorUI->bnToggleMask->setChecked(false);
- m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("novisible"));
- m_selectorUI->labelMaskToolbar->setPixmap(KisIconUtils::loadIcon("media-playback-stop").pixmap(16,16));
-
- m_selectorUI->labelHueStepsIcon->setPixmap(hueStepsPixmap);
- m_selectorUI->labelSaturationStepsIcon->setPixmap(saturationStepsPixmap);
- m_selectorUI->labelValueScaleStepsIcon->setPixmap(valueScaleStepsPixmap);
-
- m_selectorUI->labelHueSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
- m_selectorUI->labelSaturationSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
- m_selectorUI->labelValueScaleSteps->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ m_selectorUI->bnToggleMask->setIcon(m_iconMaskOff);
//preferences
m_hsxButtons->addButton(m_preferencesUI->bnHsy, KisColor::HSY);
m_hsxButtons->addButton(m_preferencesUI->bnHsi, KisColor::HSI);
m_hsxButtons->addButton(m_preferencesUI->bnHsl, KisColor::HSL);
m_hsxButtons->addButton(m_preferencesUI->bnHsv, KisColor::HSV);
m_wheelPrefsUI->bnInverseSat->setChecked(m_selectorUI->colorSelector->isSaturationInverted());
m_wheelPrefsUI->labelHueSteps->setPixmap(hueStepsPixmap);
m_wheelPrefsUI->labelSaturationSteps->setPixmap(saturationStepsPixmap);
m_wheelPrefsUI->labelValueScaleSteps->setPixmap(valueScaleStepsPixmap);
m_wheelPrefsUI->numHueSteps->setRange(MIN_NUM_UI_HUE_PIECES, MAX_NUM_HUE_PIECES);
m_wheelPrefsUI->numSaturationSteps->setRange(MIN_NUM_SATURATION_RINGS, MAX_NUM_SATURATION_RINGS);
m_wheelPrefsUI->numValueScaleSteps->setRange(MIN_NUM_UI_LIGHT_PIECES, MAX_NUM_LIGHT_PIECES);
m_wheelPrefsUI->bnInfHueSteps->setIcon(infinityIcon);
m_wheelPrefsUI->bnInfValueScaleSteps->setIcon(infinityIcon);
int selectorHueSteps = m_selectorUI->colorSelector->getNumPieces();
if (selectorHueSteps == 1) {
m_wheelPrefsUI->bnInfHueSteps->setChecked(true);
} else {
m_wheelPrefsUI->bnInfHueSteps->setChecked(false);
}
m_wheelPrefsUI->numHueSteps->setValue(selectorHueSteps);
m_wheelPrefsUI->numSaturationSteps->setValue(m_selectorUI->colorSelector->getNumRings());
int selectorValueScaleSteps = m_selectorUI->colorSelector->getNumLightPieces();
if (selectorValueScaleSteps == 1) {
m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(true);
} else {
m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(false);
}
m_wheelPrefsUI->numValueScaleSteps->setValue(m_selectorUI->colorSelector->getNumLightPieces());
m_preferencesUI->bnDefInfHueSteps->setIcon(infinityIcon);
m_preferencesUI->bnDefInfValueScaleSteps->setIcon(infinityIcon);
m_preferencesUI->labelDefHueSteps->setPixmap(hueStepsPixmap);
m_preferencesUI->labelDefSaturationSteps->setPixmap(saturationStepsPixmap);
m_preferencesUI->labelDefValueScaleSteps->setPixmap(valueScaleStepsPixmap);
m_preferencesUI->defaultHueSteps->setRange(MIN_NUM_HUE_PIECES, MAX_NUM_HUE_PIECES);
m_preferencesUI->defaultSaturationSteps->setRange(MIN_NUM_SATURATION_RINGS, MAX_NUM_SATURATION_RINGS);
m_preferencesUI->defaultValueScaleSteps->setRange(MIN_NUM_LIGHT_PIECES, MAX_NUM_LIGHT_PIECES);
m_preferencesUI->defaultHueSteps->setValue(m_selectorUI->colorSelector->getDefaultHueSteps());
m_preferencesUI->defaultSaturationSteps->setValue(m_selectorUI->colorSelector->getDefaultSaturationSteps());
m_preferencesUI->defaultValueScaleSteps->setValue(m_selectorUI->colorSelector->getDefaultValueScaleSteps());
m_preferencesUI->showColorBlip->setChecked(m_selectorUI->colorSelector->getShowColorBlip());
m_preferencesUI->showBgColor->setChecked(m_selectorUI->colorSelector->getShowBgColor());
m_preferencesUI->showValueScaleNumbers->setChecked(m_selectorUI->colorSelector->getShowValueScaleNumbers());
- m_preferencesUI->bnAbsLight->setChecked(m_selectorUI->colorSelector->islightRelative());
m_preferencesUI->enforceGamutMask->setChecked(m_selectorUI->colorSelector->enforceGamutMask());
m_preferencesUI->permissiveGamutMask->setChecked(!m_selectorUI->colorSelector->enforceGamutMask());
m_preferencesUI->showMaskPreview->setChecked(m_selectorUI->colorSelector->maskPreviewActive());
+ m_preferencesUI->valueScaleGamma->setValue(m_selectorUI->colorSelector->gamma());
+
switch(m_selectorUI->colorSelector->getColorSpace())
{
case KisColor::HSV: { m_preferencesUI->bnHsv->setChecked(true); } break;
case KisColor::HSI: { m_preferencesUI->bnHsi->setChecked(true); } break;
case KisColor::HSL: { m_preferencesUI->bnHsl->setChecked(true); } break;
case KisColor::HSY: { m_preferencesUI->bnHsy->setChecked(true); } break;
}
+ if (m_selectorUI->colorSelector->getColorSpace() == KisColor::HSY) {
+ m_preferencesUI->valueScaleGammaBox->show();
+ } else {
+ m_preferencesUI->valueScaleGammaBox->hide();
+ }
+
connect(m_wheelPrefsUI->numValueScaleSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->numHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->numSaturationSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->bnInverseSat , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->bnInfHueSteps , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->bnInfValueScaleSteps, SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged()));
connect(m_wheelPrefsUI->bnDefault , SIGNAL(clicked(bool)) , SLOT(slotResetDefaultSettings()));
- connect(m_wheelPrefsUI->bnResetPosition , SIGNAL(clicked(bool)) , SLOT(slotResetRingPositions()));
connect(m_preferencesUI->defaultHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->defaultSaturationSteps, SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->defaultValueScaleSteps, SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->bnDefInfHueSteps , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->bnDefInfValueScaleSteps, SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->showColorBlip , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->showBgColor , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->showValueScaleNumbers, SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged()));
connect(m_preferencesUI->enforceGamutMask , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged()));
- connect(m_preferencesUI->bnAbsLight , SIGNAL(toggled(bool)) , SLOT(slotLightModeChanged(bool)));
connect(m_preferencesUI->showMaskPreview , SIGNAL(toggled(bool)), SLOT(slotGamutMaskActivatePreview(bool)));
+ connect(m_preferencesUI->valueScaleGamma , SIGNAL(valueChanged(qreal)), SLOT(slotSetGamma(qreal)));
connect(m_selectorUI->colorSelector , SIGNAL(sigFgColorChanged(const KisColor&)) , SLOT(slotFgColorChanged(const KisColor&)));
connect(m_selectorUI->colorSelector , SIGNAL(sigBgColorChanged(const KisColor&)) , SLOT(slotBgColorChanged(const KisColor&)));
// gamut mask connections
connect(m_selectorUI->bnToggleMask , SIGNAL(toggled(bool)) , SLOT(slotGamutMaskToggle(bool)));
connect(m_hsxButtons , SIGNAL(buttonClicked(int)) , SLOT(slotColorSpaceSelected(int)));
- updateWheelInfoStrip();
-
setWidget(m_selectorUI);
}
ArtisticColorSelectorDock::~ArtisticColorSelectorDock()
{
m_selectorUI->colorSelector->saveSettings();
delete m_hsxButtons;
}
void ArtisticColorSelectorDock::setMainWindow(KisViewManager* kisview)
{
m_resourceProvider = kisview->resourceProvider();
m_selectorUI->colorSelector->setFgColor(m_resourceProvider->resourceManager()->foregroundColor().toQColor());
m_selectorUI->colorSelector->setBgColor(m_resourceProvider->resourceManager()->backgroundColor().toQColor());
connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int, const QVariant&)),
SLOT(slotCanvasResourceChanged(int, const QVariant&)));
connect(m_resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMask*)),
this, SLOT(slotGamutMaskSet(KoGamutMask*)));
connect(m_resourceProvider, SIGNAL(sigGamutMaskUnset()),
this, SLOT(slotGamutMaskUnset()));
if (m_selectorUI->colorSelector->maskPreviewActive()) {
connect(m_resourceProvider, SIGNAL(sigGamutMaskPreviewUpdate()),
this, SLOT(slotGamutMaskPreviewUpdate()));
}
}
void ArtisticColorSelectorDock::slotCanvasResourceChanged(int key, const QVariant& value)
{
if(key == KoCanvasResourceManager::ForegroundColor)
m_selectorUI->colorSelector->setFgColor(value.value().toQColor());
if(key == KoCanvasResourceManager::BackgroundColor)
m_selectorUI->colorSelector->setBgColor(value.value().toQColor());
}
void ArtisticColorSelectorDock::slotFgColorChanged(const KisColor& color)
{
m_resourceProvider->resourceManager()->setForegroundColor(
KoColor(color.getQColor(), m_resourceProvider->resourceManager()->foregroundColor().colorSpace())
);
}
void ArtisticColorSelectorDock::slotBgColorChanged(const KisColor& color)
{
m_resourceProvider->resourceManager()->setBackgroundColor(
KoColor(color.getQColor(), m_resourceProvider->resourceManager()->backgroundColor().colorSpace())
);
}
void ArtisticColorSelectorDock::slotColorSpaceSelected(int type)
{
- m_selectorUI->colorSelector->setColorSpace(static_cast(type));
+ m_selectorUI->colorSelector->setColorSpace(static_cast(type), m_preferencesUI->valueScaleGamma->value());
+
+ if (m_selectorUI->colorSelector->getColorSpace() == KisColor::HSY) {
+ m_preferencesUI->valueScaleGammaBox->show();
+ } else {
+ m_preferencesUI->valueScaleGammaBox->hide();
+ }
+}
+
+void ArtisticColorSelectorDock::slotSetGamma(qreal gamma)
+{
+ m_selectorUI->colorSelector->setGamma(gamma);
}
void ArtisticColorSelectorDock::slotPreferenceChanged()
{
- int hueSteps;
+ int hueSteps = DEFAULT_HUE_STEPS;
if (m_wheelPrefsUI->bnInfHueSteps->isChecked()) {
m_wheelPrefsUI->numHueSteps->setEnabled(false);
hueSteps = 1;
} else {
m_wheelPrefsUI->numHueSteps->setEnabled(true);
hueSteps = m_wheelPrefsUI->numHueSteps->value();
}
m_selectorUI->colorSelector->setNumPieces(hueSteps);
m_selectorUI->colorSelector->setNumRings(m_wheelPrefsUI->numSaturationSteps->value());
int valueScaleSteps;
if (m_wheelPrefsUI->bnInfValueScaleSteps->isChecked()) {
m_wheelPrefsUI->numValueScaleSteps->setEnabled(false);
valueScaleSteps = 1;
} else {
valueScaleSteps = m_wheelPrefsUI->numValueScaleSteps->value();
m_wheelPrefsUI->numValueScaleSteps->setEnabled(true);
}
m_selectorUI->colorSelector->setNumLightPieces(valueScaleSteps);
int defHueSteps;
if (m_preferencesUI->bnDefInfHueSteps->isChecked()) {
m_preferencesUI->defaultHueSteps->setEnabled(false);
defHueSteps = 1;
} else {
m_preferencesUI->defaultHueSteps->setEnabled(true);
defHueSteps = m_preferencesUI->defaultHueSteps->value();
}
m_selectorUI->colorSelector->setDefaultHueSteps(defHueSteps);
m_selectorUI->colorSelector->setDefaultSaturationSteps(m_preferencesUI->defaultSaturationSteps->value());
int defValueScaleSteps;
if (m_preferencesUI->bnDefInfValueScaleSteps->isChecked()) {
m_preferencesUI->defaultValueScaleSteps->setEnabled(false);
defValueScaleSteps = 1;
} else {
m_preferencesUI->defaultValueScaleSteps->setEnabled(true);
defValueScaleSteps = m_preferencesUI->defaultValueScaleSteps->value();
}
m_selectorUI->colorSelector->setDefaultValueScaleSteps(defValueScaleSteps);
m_selectorUI->colorSelector->setShowColorBlip(m_preferencesUI->showColorBlip->isChecked());
m_selectorUI->colorSelector->setShowBgColor(m_preferencesUI->showBgColor->isChecked());
m_selectorUI->colorSelector->setShowValueScaleNumbers(m_preferencesUI->showValueScaleNumbers->isChecked());
m_selectorUI->colorSelector->setEnforceGamutMask(m_preferencesUI->enforceGamutMask->isChecked());
// the selector wheel forbids saturation inversion in some cases,
// reflecting that in the ui
if (m_selectorUI->colorSelector->saturationIsInvertible()) {
m_wheelPrefsUI->bnInverseSat->setEnabled(true);
m_selectorUI->colorSelector->setInverseSaturation(m_wheelPrefsUI->bnInverseSat->isChecked());
} else {
m_wheelPrefsUI->bnInverseSat->setEnabled(false);
m_wheelPrefsUI->bnInverseSat->setChecked(false);
m_selectorUI->colorSelector->setInverseSaturation(false);
}
- updateWheelInfoStrip();
-}
-
-void ArtisticColorSelectorDock::slotResetRingPositions()
-{
- m_selectorUI->colorSelector->resetRings();
}
void ArtisticColorSelectorDock::slotResetDefaultSettings()
{
quint32 hueSteps = m_selectorUI->colorSelector->getDefaultHueSteps();
quint32 saturationSteps = m_selectorUI->colorSelector->getDefaultSaturationSteps();
quint32 valueScaleSteps = m_selectorUI->colorSelector->getDefaultValueScaleSteps();
m_selectorUI->colorSelector->setNumRings(saturationSteps);
m_wheelPrefsUI->numSaturationSteps->blockSignals(true);
m_wheelPrefsUI->numSaturationSteps->setValue(saturationSteps);
m_wheelPrefsUI->numSaturationSteps->blockSignals(false);
m_selectorUI->colorSelector->setNumPieces(hueSteps);
m_wheelPrefsUI->numHueSteps->blockSignals(true);
m_wheelPrefsUI->numHueSteps->setValue(hueSteps);
m_wheelPrefsUI->numHueSteps->blockSignals(false);
if (hueSteps == 1) {
m_wheelPrefsUI->numHueSteps->setEnabled(false);
m_wheelPrefsUI->bnInfHueSteps->setChecked(true);
} else {
m_wheelPrefsUI->numHueSteps->setEnabled(true);
m_wheelPrefsUI->bnInfHueSteps->setChecked(false);
}
m_selectorUI->colorSelector->setNumLightPieces(valueScaleSteps);
m_wheelPrefsUI->numValueScaleSteps->blockSignals(true);
m_wheelPrefsUI->numValueScaleSteps->setValue(valueScaleSteps);
m_wheelPrefsUI->numValueScaleSteps->blockSignals(false);
if (valueScaleSteps == 1) {
m_wheelPrefsUI->numValueScaleSteps->setEnabled(false);
m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(true);
} else {
m_wheelPrefsUI->numValueScaleSteps->setEnabled(true);
m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(false);
}
-
- updateWheelInfoStrip();
-}
-
-void ArtisticColorSelectorDock::slotLightModeChanged(bool setToAbsolute)
-{
- m_selectorUI->colorSelector->setLight(m_selectorUI->colorSelector->getLight(), setToAbsolute);
-}
-
-void ArtisticColorSelectorDock::updateWheelInfoStrip()
-{
- int hueSteps = m_selectorUI->colorSelector->getNumPieces();
- if (hueSteps == 1) {
- m_selectorUI->labelHueSteps->setPixmap(m_infinityPixmap);
- } else {
- m_selectorUI->labelHueSteps->setNum(hueSteps);
- }
-
- m_selectorUI->labelSaturationSteps->setNum(m_wheelPrefsUI->numSaturationSteps->value());
-
- int valueScaleSteps = m_selectorUI->colorSelector->getNumLightPieces();
- if (valueScaleSteps == 1) {
- m_selectorUI->labelValueScaleSteps->setPixmap(m_infinityPixmap);
- } else {
- m_selectorUI->labelValueScaleSteps->setNum(valueScaleSteps);
- }
}
void ArtisticColorSelectorDock::slotGamutMaskActivatePreview(bool value)
{
m_selectorUI->colorSelector->setMaskPreviewActive(value);
if (value) {
connect(m_resourceProvider, SIGNAL(sigGamutMaskPreviewUpdate()),
this, SLOT(slotGamutMaskPreviewUpdate()));
} else {
disconnect(m_resourceProvider, SIGNAL(sigGamutMaskPreviewUpdate()),
this, SLOT(slotGamutMaskPreviewUpdate()));
}
m_selectorUI->colorSelector->update();
}
void ArtisticColorSelectorDock::slotGamutMaskToggle(bool checked)
{
bool b = (!m_selectedMask) ? false : checked;
m_selectorUI->bnToggleMask->setChecked(b);
if (b == true) {
m_selectorUI->colorSelector->setGamutMask(m_selectedMask);
- m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("visible"));
+ m_selectorUI->bnToggleMask->setIcon(m_iconMaskOn);
} else {
- m_selectorUI->bnToggleMask->setIcon(KisIconUtils::loadIcon("novisible"));
+ m_selectorUI->bnToggleMask->setIcon(m_iconMaskOff);
}
m_selectorUI->colorSelector->setGamutMaskOn(b);
// TODO: HACK
// the selector wheel forbids saturation inversion in some cases,
// reflecting that in the ui
if (m_selectorUI->colorSelector->saturationIsInvertible()) {
m_wheelPrefsUI->bnInverseSat->setEnabled(true);
m_selectorUI->colorSelector->setInverseSaturation(m_wheelPrefsUI->bnInverseSat->isChecked());
} else {
m_wheelPrefsUI->bnInverseSat->setEnabled(false);
m_wheelPrefsUI->bnInverseSat->setChecked(false);
m_selectorUI->colorSelector->setInverseSaturation(false);
}
}
void ArtisticColorSelectorDock::setCanvas(KoCanvasBase *canvas)
{
setEnabled(canvas != 0);
}
void ArtisticColorSelectorDock::unsetCanvas()
{
setEnabled(false);
}
void ArtisticColorSelectorDock::slotGamutMaskSet(KoGamutMask *mask)
{
+ if (!mask) {
+ return;
+ }
+
m_selectedMask = mask;
if (m_selectedMask) {
m_selectorUI->colorSelector->setGamutMask(m_selectedMask);
m_selectorUI->labelMaskName->setText(m_selectedMask->title());
slotGamutMaskToggle(true);
} else {
slotGamutMaskToggle(false);
m_selectorUI->labelMaskName->setText(i18n("Select a mask in \"Gamut Masks\" docker"));
}
}
void ArtisticColorSelectorDock::slotGamutMaskUnset()
{
if (!m_selectedMask) {
return;
}
m_selectedMask = nullptr;
slotGamutMaskToggle(false);
m_selectorUI->labelMaskName->setText(i18n("Select a mask in \"Gamut Masks\" docker"));
m_selectorUI->colorSelector->setGamutMask(m_selectedMask);
}
void ArtisticColorSelectorDock::slotGamutMaskPreviewUpdate()
{
m_selectorUI->colorSelector->update();
}
diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h
index 68b471f0a6..b3983a68a3 100644
--- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h
+++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h
@@ -1,90 +1,86 @@
/*
* Copyright (c) 2009 Cyrille Berger
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef H_ARTISTIC_COLOR_SELECTOR_DOCK_H
#define H_ARTISTIC_COLOR_SELECTOR_DOCK_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
-//#include
#include
#include
#include
class KisCanvasResourceProvider;
class KisColor;
class QButtonGroup;
class QMenu;
struct ArtisticColorSelectorUI;
struct ARCSSettingsUI;
struct WheelPreferencesPopupUI;
class ArtisticColorSelectorDock: public QDockWidget, public KisMainwindowObserver
{
Q_OBJECT
public:
ArtisticColorSelectorDock();
~ArtisticColorSelectorDock() override;
QString observerName() override { return "ArtisticColorSelectorDock"; }
void setMainWindow(KisViewManager* kisview) override;
void setCanvas(KoCanvasBase *canvas) override;
void unsetCanvas() override;
-//Q_SIGNALS:
-// void sigGamutMaskChanged();
-
private Q_SLOTS:
void slotCanvasResourceChanged(int key, const QVariant& value);
void slotFgColorChanged(const KisColor& color);
void slotBgColorChanged(const KisColor& color);
void slotColorSpaceSelected(int type);
+ void slotSetGamma(qreal gamma);
void slotPreferenceChanged();
- void slotResetRingPositions();
void slotResetDefaultSettings();
- void slotLightModeChanged(bool setToAbsolute);
void slotGamutMaskToggle(bool value);
void slotGamutMaskActivatePreview(bool value);
void slotGamutMaskSet(KoGamutMask* mask);
void slotGamutMaskUnset();
void slotGamutMaskPreviewUpdate();
private:
KisCanvasResourceProvider* m_resourceProvider;
QButtonGroup* m_hsxButtons;
ArtisticColorSelectorUI* m_selectorUI;
ARCSSettingsUI* m_preferencesUI;
WheelPreferencesPopupUI* m_wheelPrefsUI;
KoGamutMask* m_selectedMask;
- QPixmap m_infinityPixmap;
+ QIcon m_iconMaskOff;
+ QIcon m_iconMaskOn;
- void updateWheelInfoStrip();
+ QPixmap m_infinityPixmap;
};
#endif // H_ARTISTIC_COLOR_SELECTOR_DOCK_H
diff --git a/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui b/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui
index 406db9eeaf..53e899a9f9 100644
--- a/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui
+++ b/plugins/dockers/artisticcolorselector/forms/wdgARCSSettings.ui
@@ -1,263 +1,304 @@
wdgARCSSettings
0
0
358
- 520
+ 472
-
Selector Appearance
-
Show color blip
-
Show background color indicator
-
- Show lightness numbers on the value scale
+ Show numbered value scale
-
Color Space
-
-
HS&Y
true
true
-
HS&V
true
-
HSL
true
-
HSI
true
-
-
-
- Use HSV saturation component
+
+
+ QFrame::NoFrame
+
+
-
+
+
+ Value Scale Gamma
+
+
+
+ -
+
+
+ 1
+
+
+ 0.100000000000000
+
+
+ 50.000000000000000
+
+
+ 0.100000000000000
+
+
+ 1.000000000000000
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
-
Gamut Mask Behavior
-
-
Enforce gamut &mask
-
&Just show the shapes
-
Show preview while editing a mask
false
-
Default Selector Steps Settings
-
0
0
-
0
0
Hue Steps
-
0
0
Saturation Rings
-
true
-
0
0
-
0
0
Value Scale Steps
-
0
0
-
true
KisSliderSpinBox
QWidget
1
diff --git a/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui b/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui
index 5e53cf9a9f..a030c0203f 100644
--- a/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui
+++ b/plugins/dockers/artisticcolorselector/forms/wdgArtisticColorSelector.ui
@@ -1,235 +1,143 @@
wdgArtisticColorSelector
0
0
- 360
- 279
+ 334
+ 284
100
100
-
+
-
-
-
-
-
- 1
- 0
-
-
-
- V
-
-
-
- -
-
-
-
- 2
- 0
-
-
-
- QFrame::StyledPanel
+
+
+ Toggle gamut mask
- 0
-
-
-
- -
-
-
-
- 1
- 0
-
+
-
- H
+
+ true
-
-
+
-
- 2
+
+ 0
0
-
- QFrame::StyledPanel
-
- 0
-
-
-
- -
-
-
-
- 1
- 0
-
+ Select a mask in "Gamut Masks" docker
-
- S
+
+ true
-
-
-
-
- 2
- 0
-
+
+
+ QFrame::Sunken
-
- QFrame::StyledPanel
-
-
- 0
+
+ Qt::Vertical
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
0
1
- -
-
-
-
-
-
- M
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Select a mask in "Gamut Masks" docker
-
-
- true
-
-
-
-
-
KisPopupButton
QPushButton
KisColorSelector
QWidget
1
diff --git a/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui b/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui
index 6b4ccb6649..83f4a4a8b4 100644
--- a/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui
+++ b/plugins/dockers/artisticcolorselector/forms/wdgWheelPreferencesPopup.ui
@@ -1,166 +1,156 @@
wdgWheelPreferencesPopup
0
0
325
127
-
-
0
0
-
true
-
0
0
-
true
-
0
0
-
Saturation Rings
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
Hue Steps
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
Value Scale Steps
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Invert Saturation
true
-
Qt::Horizontal
40
20
-
- Reset Steps
-
-
- false
-
-
-
- -
-
-
- Reset Rings
+ Reset to default
false
KisSliderSpinBox
QWidget
1
diff --git a/plugins/dockers/artisticcolorselector/kis_arcs_constants.h b/plugins/dockers/artisticcolorselector/kis_arcs_constants.h
index 6eb9386ad5..0c3be3bdbc 100644
--- a/plugins/dockers/artisticcolorselector/kis_arcs_constants.h
+++ b/plugins/dockers/artisticcolorselector/kis_arcs_constants.h
@@ -1,21 +1,49 @@
+/*
+ * Copyright (c) 2018 Anna Medonosova
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
#ifndef KIS_ARCS_CONSTANTS_H
#define KIS_ARCS_CONSTANTS_H
#include
+#include
static const int MIN_NUM_HUE_PIECES = 1;
static const int MIN_NUM_UI_HUE_PIECES = 2;
static const int MAX_NUM_HUE_PIECES = 48;
static const int MIN_NUM_LIGHT_PIECES = 1;
static const int MIN_NUM_UI_LIGHT_PIECES = 2;
static const int MAX_NUM_LIGHT_PIECES = 30;
static const int MIN_NUM_SATURATION_RINGS = 1;
static const int MAX_NUM_SATURATION_RINGS = 20;
static const int DEFAULT_HUE_STEPS = 12;
static const int DEFAULT_SATURATION_STEPS = 7;
static const int DEFAULT_VALUE_SCALE_STEPS = 11;
-static const QString UTF_INF_CHAR = "\u221E";
+// color scheme for the selector
+static const QColor COLOR_MIDDLE_GRAY = QColor(128,128,128,255);
+static const QColor COLOR_DARK = QColor(20,20,20,255);
+static const QColor COLOR_LIGHT = QColor(232,232,232,255);
+static const QColor COLOR_ACCENT = QColor(255,60,60,255);
+
+static const QColor COLOR_MASK_FILL = COLOR_MIDDLE_GRAY;
+static const QColor COLOR_MASK_OUTLINE = COLOR_LIGHT;
+static const QColor COLOR_MASK_CLEAR = COLOR_LIGHT;
+static const QColor COLOR_SELECTED = COLOR_ACCENT;
+static const QColor COLOR_NORMAL_OUTLINE = COLOR_MIDDLE_GRAY;
#endif // KIS_ARCS_CONSTANTS_H
diff --git a/plugins/dockers/artisticcolorselector/kis_color.cpp b/plugins/dockers/artisticcolorselector/kis_color.cpp
index 2fbcefe1e8..51145c6bcd 100644
--- a/plugins/dockers/artisticcolorselector/kis_color.cpp
+++ b/plugins/dockers/artisticcolorselector/kis_color.cpp
@@ -1,177 +1,168 @@
/*
Copyright (C) 2011 Silvio Heinrich
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include
#include "kis_color.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
// --------- CoreImpl ------------------------------------------------------------------------ //
template
struct CoreImpl: public KisColor::Core
{
void setRGB(float r, float g, float b, float a) override {
rgb(0) = r;
rgb(1) = g;
rgb(2) = b;
hsx(3) = a;
updateHSX();
}
void setHSX(float h, float s, float x, float a) override {
hsx(0) = h;
hsx(1) = s;
hsx(2) = x;
hsx(3) = a;
updateRGB();
}
void updateRGB() override {
float h = qBound(0.0f, hsx(0), 1.0f);
float s = qBound(0.0f, hsx(1), 1.0f);
float x = qBound(0.0f, hsx(2), 1.0f);
KisColor::VecRGB gray(x, x, x);
::getRGB(rgb(0), rgb(1), rgb(2), h);
::setLightness(rgb(0), rgb(1), rgb(2), x);
rgb = gray + (rgb - gray) * s;
}
void updateHSX() override {
float r = qBound(0.0f, rgb(0), 1.0f);
float g = qBound(0.0f, rgb(1), 1.0f);
float b = qBound(0.0f, rgb(2), 1.0f);
float h = ::getHue(r, g, b);
float x = ::getLightness(r, g, b);
KisColor::VecRGB hue(0.0, 0.0, 0.0);
::getRGB(hue(0), hue(1), hue(2), h);
::setLightness(hue(0), hue(1), hue(2), x);
KisColor::VecRGB diff1 = hue - KisColor::VecRGB(x,x,x);
KisColor::VecRGB diff2 = rgb - KisColor::VecRGB(x,x,x);
hsx(0) = h;
hsx(1) = diff1.dot(diff2) / diff1.squaredNorm(); // project rgb onto (VecRGB(x,x,x) - hue)
hsx(2) = x;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
// --------- KisColor ------------------------------------------------------------------------ //
KisColor::KisColor(Type type)
{
- initRGB(type, 0.0f, 0.0f, 0.0f, 0.0f);
+ initRGB(type, 0.0f, 0.0f, 0.0f, 1.0f);
}
KisColor::KisColor(float hue, float a, Type type)
{
float r = 0;
float g = 0;
float b = 0;
::getRGB(r, g, b, hue);
initRGB(type, r, g, b, a);
}
KisColor::KisColor(float r, float g, float b, float a, Type type)
{
initRGB(type, r, g, b, a);
}
KisColor::KisColor(const QColor& color, Type type)
{
initRGB(type, color.redF(), color.greenF(), color.blueF(), color.alphaF());
}
KisColor::KisColor(Qt::GlobalColor color, Type type)
{
QColor c(color);
initRGB(type, c.redF(), c.greenF(), c.blueF(), c.alphaF());
}
KisColor::KisColor(const KisColor& color)
{
initHSX(color.getType(), color.getH(), color.getS(), color.getX(), color.getA());
}
KisColor::KisColor(const KisColor& color, KisColor::Type type)
{
if(color.getType() == type)
initHSX(type, color.getH(), color.getS(), color.getX(), color.getA());
else
initRGB(type, color.getR(), color.getG(), color.getB(), color.getA());
}
KisColor::~KisColor()
{
core()->~Core();
}
void KisColor::initRGB(Type type, float r, float g, float b, float a)
{
// an offset that is added to the m_coreData buffer to make sure
// the struct created with the placement new operator is aligned at 16 bytes
// this is required by Eigen for vectorization
m_offset = quint8(16 - (reinterpret_cast(m_coreData) % 16)) % 16;
switch(type)
{
case HSY: { new (m_coreData + m_offset) CoreImpl; } break;
case HSV: { new (m_coreData + m_offset) CoreImpl; } break;
case HSL: { new (m_coreData + m_offset) CoreImpl; } break;
case HSI: { new (m_coreData + m_offset) CoreImpl; } break;
}
core()->type = type;
core()->setRGB(r, g, b, a);
}
void KisColor::initHSX(Type type, float h, float s, float x, float a)
{
// an offset that is added to the m_coreData buffer to make sure
// the struct created with the placement new operator is aligned at 16 bytes
// this is required by Eigen for vectorization
m_offset = quint8(16 - (reinterpret_cast(m_coreData) % 16)) % 16;
switch(type)
{
case HSY: { new (m_coreData + m_offset) CoreImpl; } break;
case HSV: { new (m_coreData + m_offset) CoreImpl; } break;
case HSL: { new (m_coreData + m_offset) CoreImpl; } break;
case HSI: { new (m_coreData + m_offset) CoreImpl; } break;
}
core()->type = type;
core()->setHSX(h, s, x, a);
}
-void KisColor::setRGBfromHue(float hue, float alpha)
-{
- float r = 0;
- float g = 0;
- float b = 0;
- ::getRGB(r, g, b, hue);
- core()->setRGB(r, g, b, alpha);
-}
-
KisColor& KisColor::operator=(const KisColor& color)
{
initHSX(color.getType(), color.getH(), color.getS(), color.getX(), color.getA());
return *this;
}
diff --git a/plugins/dockers/artisticcolorselector/kis_color.h b/plugins/dockers/artisticcolorselector/kis_color.h
index 97a088e5f4..a715fb0913 100644
--- a/plugins/dockers/artisticcolorselector/kis_color.h
+++ b/plugins/dockers/artisticcolorselector/kis_color.h
@@ -1,138 +1,127 @@
/*
Copyright (C) 2011 Silvio Heinrich
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef H_KIS_COLOR_H
#define H_KIS_COLOR_H
#include
#include
#include
class KisColor
{
public:
enum Type { HSY, HSV, HSL, HSI };
typedef Eigen::Vector4f VecHSXA;
typedef Eigen::Vector3f VecRGB;
struct Core
{
virtual ~Core() { }
virtual void setRGB(float r, float g, float b, float a) = 0;
virtual void setHSX(float h, float s, float x, float a) = 0;
virtual void updateRGB() = 0;
virtual void updateHSX() = 0;
VecRGB rgb;
VecHSXA hsx;
Type type;
};
public:
KisColor(Type type=HSY);
KisColor(float hue, float a=1.0f, Type type=HSY);
KisColor(float r, float g, float b, float a=1.0f, Type type=HSY);
KisColor(const QColor& color, Type type=HSY);
KisColor(Qt::GlobalColor color, Type type=HSY);
KisColor(const KisColor& color);
KisColor(const KisColor& color, Type type);
~KisColor();
inline Type getType() const { return core()->type; }
inline bool hasUndefHue() const { return getS() == 0.0f; }
inline float getR() const { return core()->rgb(0); }
inline float getG() const { return core()->rgb(1); }
inline float getB() const { return core()->rgb(2); }
inline float getH() const { return core()->hsx(0); }
inline float getS() const { return core()->hsx(1); }
- inline float getX() const { return core()->hsx(2); }
+ inline float getX(float gamma=1.0f) const { return pow(core()->hsx(2), 1/gamma); }
inline float getA() const { return core()->hsx(3); }
inline void setR(float v) { setRGB(v, core()->rgb(1), core()->rgb(2), core()->hsx(3)); }
inline void setG(float v) { setRGB(core()->rgb(0), v, core()->rgb(2), core()->hsx(3)); }
inline void setB(float v) { setRGB(core()->rgb(0), core()->rgb(1), v, core()->hsx(3)); }
inline void setH(float v) { setHSX(v, core()->hsx(1), core()->hsx(2), core()->hsx(3)); }
inline void setS(float v) { setHSX(core()->hsx(0), v, core()->hsx(2), core()->hsx(3)); }
- inline void setX(float v) { setHSX(core()->hsx(0), core()->hsx(1), v, core()->hsx(3)); }
+ inline void setX(float v, float gamma=1.0f) {
+ setHSX(core()->hsx(0), core()->hsx(1), v, core()->hsx(3), gamma);
+ }
inline void setA(float v) { core()->hsx(3) = qBound(0.0f, v, 1.0f); }
inline QColor getQColor() const { return QColor(getR()*255, getG()*255, getB()*255, getA()*255); }
- inline const VecHSXA& getHSX () const { return core()->hsx; }
- inline const VecRGB& getRGB () const { return core()->rgb; }
inline void setRGB(float r, float g, float b, float a=1.0f) { core()->setRGB(r, g, b, a); }
- inline void setHSX(float h, float s, float x, float a=1.0f) { core()->setHSX(h, s, x, a); }
-
- inline void setRGB(const VecRGB& rgb) {
- core()->rgb = rgb;
- core()->updateHSX();
- }
-
- inline void setHSX(const VecHSXA& hsx) {
- core()->hsx = hsx;
- core()->updateRGB();
+ inline void setHSX(float h, float s, float x, float a=1.0f, float gamma=1.0f) {
+ core()->setHSX(h, s, pow(x, gamma), a);
}
-
- void setRGBfromHue(float hue, float alpha=1.0f);
-
+
KisColor& operator = (const KisColor& color);
friend KisColor operator - (const KisColor& a, const KisColor& b) {
KisColor result;
result.core()->hsx = a.core()->hsx - b.core()->hsx;
result.core()->updateRGB();
if(a.hasUndefHue() || b.hasUndefHue())
result.setH(0.0f);
return result;
}
friend KisColor operator + (const KisColor& a, const KisColor& b) {
KisColor result;
result.core()->hsx = a.core()->hsx + b.core()->hsx;
result.core()->updateRGB();
return result;
}
friend KisColor operator * (const KisColor& a, float b) {
KisColor result;
result.core()->hsx = a.core()->hsx * b;
result.core()->updateRGB();
-// result.setH(a.getH());
return result;
}
friend KisColor operator * (float a, const KisColor& b) {
return b * a;
}
private:
void initRGB(Type type, float r, float g, float b, float a);
void initHSX(Type type, float h, float s, float x, float a);
inline Core* core() { return reinterpret_cast (m_coreData + m_offset); }
inline const Core* core() const { return reinterpret_cast(m_coreData + m_offset); }
private:
quint8 m_coreData[sizeof(Core) + 15];
quint8 m_offset;
};
#endif // H_KIS_COLOR_H
diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp
index a3daaf4230..938c8a7fcf 100644
--- a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp
+++ b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp
@@ -1,1058 +1,1078 @@
/*
Copyright (C) 2011 Silvio Heinrich
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_color_selector.h"
+//#define DEBUG_ARC_SELECTOR
+
KisColorSelector::KisColorSelector(QWidget* parent, KisColor::Type type)
: QWidget(parent)
, m_colorSpace(type)
, m_inverseSaturation(false)
- , m_relativeLight(true)
- , m_light(0.5f)
- , m_selectedColorRole(Acs::Foreground)
+ , m_gamma(1.0f)
, m_clickedRing(-1)
, m_gamutMaskOn(false)
- , m_widgetUpdatesSelf(false)
- , m_grayColor(QColor(128,128,128,255))
- , m_gamutMaskColor(QColor(128,128,128,255))
, m_currentGamutMask(nullptr)
, m_maskPreviewActive(true)
-{
+ , m_widgetUpdatesSelf(false)
+{
m_viewConverter = new KisGamutMaskViewConverter();
- recalculateRings(9, 12);
- recalculateAreas(9);
+ recalculateRings(DEFAULT_SATURATION_STEPS, DEFAULT_HUE_STEPS);
+ recalculateAreas(DEFAULT_VALUE_SCALE_STEPS);
selectColor(KisColor(Qt::red, KisColor::HSY));
using namespace std::placeholders; // For _1 placeholder
auto function = std::bind(&KisColorSelector::slotUpdateColorAndPreview, this, _1);
m_updateColorCompressor.reset(new ColorCompressorType(20 /* ms */, function));
}
-void KisColorSelector::setColorSpace(KisColor::Type type)
+void KisColorSelector::setColorSpace(KisColor::Type type, float valueScaleGamma)
{
m_colorSpace = type;
+ setGamma(valueScaleGamma);
m_selectedColor = KisColor(m_selectedColor, m_colorSpace);
+
+#ifdef DEBUG_ARC_SELECTOR
+ dbgPlugins << "KisColorSelector::setColorSpace: set to:" << m_colorSpace;
+#endif
+
update();
}
void KisColorSelector::setNumLightPieces(int num)
{
num = qBound(MIN_NUM_LIGHT_PIECES, num, MAX_NUM_LIGHT_PIECES);
recalculateAreas(quint8(num));
if (m_selectedLightPiece >= 0)
- m_selectedLightPiece = getLightIndex(m_selectedColor.getX());
+ m_selectedLightPiece = getLightIndex(m_selectedColor.getX(m_gamma));
update();
}
void KisColorSelector::setNumPieces(int num)
{
num = qBound(MIN_NUM_HUE_PIECES, num, MAX_NUM_HUE_PIECES);
recalculateRings(quint8(getNumRings()), quint8(num));
if (m_selectedPiece >= 0)
m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2);
update();
}
void KisColorSelector::setNumRings(int num)
{
num = qBound(MIN_NUM_SATURATION_RINGS, num, MAX_NUM_SATURATION_RINGS);
recalculateRings(quint8(num), quint8(getNumPieces()));
if (m_selectedRing >= 0)
m_selectedRing = getSaturationIndex(m_selectedColor.getS());
update();
}
void KisColorSelector::selectColor(const KisColor& color)
{
m_selectedColor = KisColor(color, m_colorSpace);
m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2);
m_selectedRing = getSaturationIndex(m_selectedColor.getS());
- m_selectedLightPiece = getLightIndex(m_selectedColor.getX());
+ m_selectedLightPiece = getLightIndex(m_selectedColor.getX(m_gamma));
update();
}
void KisColorSelector::setFgColor(const KisColor& fgColor)
{
if (!m_widgetUpdatesSelf) {
m_fgColor = KisColor(fgColor, m_colorSpace);
+ m_selectedColor = KisColor(fgColor, m_colorSpace);
+
+#ifdef DEBUG_ARC_SELECTOR
dbgPlugins << "KisColorSelector::setFgColor: m_fgColor set to:"
<< "H:" << m_fgColor.getH()
<< "S:" << m_fgColor.getS()
- << "X:" << m_fgColor.getX();
+ << "X:" << m_fgColor.getX(m_gamma);
- m_selectedColor = KisColor(fgColor, m_colorSpace);
dbgPlugins << "KisColorSelector::setFgColor: m_selectedColor set to:"
<< "H:" << m_selectedColor.getH()
<< "S:" << m_selectedColor.getS()
- << "X:" << m_selectedColor.getX();
+ << "X:" << m_selectedColor.getX(m_gamma);
+#endif
update();
- } else {
- dbgPlugins << "KisColorSelector::setFgColor: m_widgetUpdatesSelf == true, not updating color";
}
}
void KisColorSelector::setBgColor(const KisColor& bgColor)
{
if (!m_widgetUpdatesSelf) {
m_bgColor = KisColor(bgColor, m_colorSpace);
+#ifdef DEBUG_ARC_SELECTOR
dbgPlugins << "KisColorSelector::setBgColor: m_bgColor set to:"
<< "H:" << m_bgColor.getH()
<< "S:" << m_bgColor.getS()
- << "X:" << m_bgColor.getX();
+ << "X:" << m_bgColor.getX(m_gamma);
+#endif
update();
- } else {
- dbgPlugins << "KisColorSelector::setBgColor: m_widgetUpdatesSelf == true, not updating color";
}
}
-void KisColorSelector::resetRings()
+void KisColorSelector::setLight(float light)
{
- for(int i=0; i= 0) {
- m_colorRings[m_selectedRing].angle = 0.0f;
- update();
+void KisColorSelector::setGamma(float gamma) {
+ if (m_colorSpace == KisColor::HSY) {
+ m_gamma = gamma;
+ } else {
+ m_gamma = 1.0f;
}
-}
-void KisColorSelector::setLight(float light, bool relative)
-{
- m_light = qBound(0.0f, light, 1.0f);
+#ifdef DEBUG_ARC_SELECTOR
+ dbgPlugins << "KisColorSelector::setGamma: set to:" << m_gamma;
+#endif
- m_selectedColor.setX(getLight(m_light, m_selectedColor.getH(), relative));
- m_relativeLight = relative;
- m_selectedLightPiece = getLightIndex(m_selectedColor.getX());
update();
}
void KisColorSelector::setInverseSaturation(bool inverse)
{
if (m_inverseSaturation != inverse) {
m_selectedRing = (getNumRings()-1) - m_selectedRing;
m_inverseSaturation = inverse;
recalculateRings(quint8(getNumRings()), quint8(getNumPieces()));
update();
}
}
void KisColorSelector::setGamutMask(KoGamutMask* gamutMask)
{
if (!gamutMask) {
return;
}
m_currentGamutMask = gamutMask;
m_viewConverter->setViewSize(m_renderAreaSize);
m_viewConverter->setMaskSize(m_currentGamutMask->maskSize());
update();
}
KoGamutMask* KisColorSelector::gamutMask()
{
return m_currentGamutMask;
}
bool KisColorSelector::maskPreviewActive()
{
return m_maskPreviewActive;
}
void KisColorSelector::setMaskPreviewActive(bool value)
{
m_maskPreviewActive = value;
}
bool KisColorSelector::gamutMaskOn()
{
return m_gamutMaskOn;
}
void KisColorSelector::setGamutMaskOn(bool gamutMaskOn)
{
- // do not allow the mask on, if it is a nullptr
if (m_currentGamutMask) {
m_gamutMaskOn = gamutMaskOn;
update();
}
}
void KisColorSelector::setEnforceGamutMask(bool enforce)
{
m_enforceGamutMask = enforce;
update();
}
QPointF KisColorSelector::mapCoordToView(const QPointF& pt, const QRectF& viewRect) const
{
qreal w = viewRect.width() / 2.0;
qreal h = viewRect.height() / 2.0;
qreal x = pt.x() + 1.0;
qreal y = (pt.y()) + 1.0;
return QPointF(x*w, y*h);
}
QPointF KisColorSelector::mapCoordToUnit(const QPointF& pt, const QRectF& viewRect) const
{
qreal w = viewRect.width() / 2.0;
qreal h = viewRect.height() / 2.0;
qreal x = pt.x() - (viewRect.x() + w);
qreal y = pt.y() - (viewRect.y() + h);
return QPointF(x/w, y/h);
}
QPointF KisColorSelector::mapColorToUnit(const KisColor& color, bool invertSaturation) const
{
- qreal angle = color.getH() * 2.0 * M_PI;
-
qreal radius;
if (invertSaturation && m_inverseSaturation) {
radius = 1.0 - color.getS();
} else {
radius = color.getS();
}
- qreal x = std::cos(angle)*radius;
- qreal y = std::sin(-angle)*radius;
+ QPointF hueCoord = mapHueToAngle(color.getH());
+ qreal x = hueCoord.x()*radius;
+ qreal y = hueCoord.y()*radius;
+
+ return QPointF(x,y);
+}
+
+KisColorSelector::Radian KisColorSelector::mapCoordToAngle(qreal x, qreal y) const
+{
+ float angle = std::atan2(-y, -x);
+
+#ifdef DEBUG_ARC_SELECTOR
+ dbgPlugins << "KisColorSelector::mapCoordToAngle: "
+ << "X:" << x
+ << "Y:" << y
+ << "angle:" << angle;
+#endif
+
+ return angle;
+}
+
+QPointF KisColorSelector::mapHueToAngle(float hue) const
+{
+ float angle = hue * 2.0 * M_PI - M_PI;
+ float x = std::cos(angle);
+ float y = std::sin(angle);
return QPointF(x,y);
}
qint8 KisColorSelector::getLightIndex(const QPointF& pt) const
{
if (m_lightStripArea.contains(pt.toPoint(), true)) {
qreal t = (pt.x() - m_lightStripArea.x()) / qreal(m_lightStripArea.width());
t = (pt.y() - m_lightStripArea.y()) / qreal(m_lightStripArea.height());
return qint8(t * getNumLightPieces());
}
return -1;
}
qint8 KisColorSelector::getLightIndex(qreal light) const
{
light = qreal(1) - qBound(qreal(0), light, qreal(1));
return qint8(qRound(light * (getNumLightPieces()-1)));
}
-qreal KisColorSelector::getLight(qreal light, qreal hue, bool relative) const
-{
- if (relative) {
- KisColor color(hue, 1.0f, m_colorSpace);
- qreal cl = color.getX();
- light = (light * 2.0f) - 1.0f;
- return (light < 0.0f) ? (cl + cl*light) : (cl + (1.0f-cl)*light);
- }
-
- return light;
-}
-
qreal KisColorSelector::getLight(const QPointF& pt) const
{
qint8 clickedLightPiece = getLightIndex(pt);
if (clickedLightPiece >= 0) {
if (getNumLightPieces() > 1) {
return 1.0 - (qreal(clickedLightPiece) / qreal(getNumLightPieces()-1));
}
return 1.0 - (qreal(pt.y()) / qreal(m_lightStripArea.height()));
}
return qreal(0);
}
-qint8 KisColorSelector::getHueIndex(Radian hue, Radian shift) const
+qint8 KisColorSelector::getHueIndex(Radian hue) const
{
- hue -= shift;
qreal partSize = 1.0 / qreal(getNumPieces());
return qint8(qRound(hue.scaled(0.0f, 1.0f) / partSize) % getNumPieces());
}
qreal KisColorSelector::getHue(int hueIdx, Radian shift) const
{
Radian hue = (qreal(hueIdx) / qreal(getNumPieces())) * PI2;
hue += shift;
return hue.scaled(0.0f, 1.0f);
}
qint8 KisColorSelector::getSaturationIndex(qreal saturation) const
{
saturation = qBound(qreal(0), saturation, qreal(1));
saturation = m_inverseSaturation ? (qreal(1) - saturation) : saturation;
return qint8(saturation * qreal(getNumRings() - 1));
}
qint8 KisColorSelector::getSaturationIndex(const QPointF& pt) const
{
qreal length = std::sqrt(pt.x()*pt.x() + pt.y()*pt.y());
for(int i=0; i= m_colorRings[i].innerRadius && length < m_colorRings[i].outerRadius)
return qint8(i);
}
return -1;
}
qreal KisColorSelector::getSaturation(int saturationIdx) const
{
qreal sat = qreal(saturationIdx) / qreal(getNumRings()-1);
return m_inverseSaturation ? (1.0 - sat) : sat;
}
void KisColorSelector::recalculateAreas(quint8 numLightPieces)
{
- const qreal LIGHT_STRIP_RATIO = 0.075;
+
+ qreal LIGHT_STRIP_RATIO = 0.075;
+ if (m_showValueScaleNumbers) {
+ LIGHT_STRIP_RATIO = 0.25;
+ }
int width = QWidget::width();
int height = QWidget::height();
int size = qMin(width, height);
int stripThick = int(size * LIGHT_STRIP_RATIO);
width -= stripThick;
size = qMin(width, height);
int x = (width - size) / 2;
int y = (height - size) / 2;
m_renderAreaSize = QSize(size,size);
m_viewConverter->setViewSize(m_renderAreaSize);
m_renderArea = QRect(x+stripThick, y, size, size);
m_lightStripArea = QRect(0, 0, stripThick, QWidget::height());
m_renderBuffer = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
m_maskBuffer = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
m_numLightPieces = numLightPieces;
}
void KisColorSelector::recalculateRings(quint8 numRings, quint8 numPieces)
{
m_colorRings.resize(numRings);
m_numPieces = numPieces;
for(int i=0; i(numPieces, 1);
ring.innerRadius = innerRadius;
ring.outerRadius = outerRadius;
ring.pieced.resize(numParts);
qreal partSize = 360.0 / qreal(numParts);
QRectF outerRect(-outerRadius, -outerRadius, outerRadius*2.0, outerRadius*2.0);
QRectF innerRect(-innerRadius, -innerRadius, innerRadius*2.0, innerRadius*2.0);
for(int i=0; icoordIsClear(colorCoord, *m_viewConverter, m_maskPreviewActive);
if (isClear) {
return true;
} else {
return false;
}
} else {
return true;
}
return false;
}
void KisColorSelector::requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role)
{
+#ifdef DEBUG_ARC_SELECTOR
dbgPlugins << "KisColorSelector::requestUpdateColorAndPreview: requesting update to: "
<< "H:" << color.getH()
<< "S:" << color.getS()
- << "X:" << color.getX();
-
+ << "X:" << color.getX(m_gamma);
+#endif
m_updateColorCompressor->start(qMakePair(color, role));
}
void KisColorSelector::slotUpdateColorAndPreview(QPair color)
{
const bool selectAsFgColor = color.second == Acs::Foreground;
if (selectAsFgColor) { m_fgColor = color.first; }
else { m_bgColor = color.first; }
- m_selectedColor = color.first;
- m_selectedColorRole = color.second;
+ m_selectedColor = color.first;
+#ifdef DEBUG_ARC_SELECTOR
dbgPlugins << "KisColorSelector::slotUpdateColorAndPreview: m_selectedColor set to:"
<< "H:" << m_selectedColor.getH()
<< "S:" << m_selectedColor.getS()
- << "X:" << m_selectedColor.getX()
- << "role:" << m_selectedColorRole;
-
+ << "X:" << m_selectedColor.getX(m_gamma);
+#endif
if (selectAsFgColor) { emit sigFgColorChanged(m_selectedColor); }
else { emit sigBgColorChanged(m_selectedColor); }
}
-void KisColorSelector::drawRing(QPainter& painter, int ringIndex, KisColorSelector::ColorRing& ring, const QRect& rect)
+void KisColorSelector::drawRing(QPainter& painter, KisColorSelector::ColorRing& ring, const QRect& rect)
{
painter.save();
painter.setRenderHint(QPainter::Antialiasing, true);
painter.resetTransform();
painter.translate(rect.width()/2, rect.height()/2);
if (ring.pieced.size() > 1) {
- painter.rotate(-ring.getShift().degrees());
+ QTransform mirror;
+ mirror.rotate(180, Qt::YAxis);
+ painter.setTransform(mirror, true);
painter.scale(rect.width()/2, rect.height()/2);
-// painter.setPen(Qt::NoPen);
- QPen normalPen = QPen(QBrush(m_grayColor), 0.005);
- QPen clearMaskPen = QPen(QBrush(Qt::white), 0.005);
+ QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005);
+ QPen clearMaskPen = QPen(QBrush(COLOR_MASK_CLEAR), 0.005);
QBrush brush(Qt::SolidPattern);
for(int i=0; i= 1.0f) ? (hue - 1.0f) : hue;
hue = (hue < 0.0f) ? (hue + 1.0f) : hue;
KisColor color(hue, 1.0f, m_colorSpace);
color.setS(ring.saturation);
- color.setX(getLight(m_light, hue, m_relativeLight));
+ color.setX(m_selectedColor.getX(m_gamma), m_gamma);
if(m_gamutMaskOn && m_enforceGamutMask && colorIsClear(color)) {
painter.setPen(clearMaskPen);
} else {
painter.setPen(normalPen);
}
if ((m_enforceGamutMask) && (!colorIsClear(color))) {
- brush.setColor(m_gamutMaskColor);
+ brush.setColor(COLOR_MASK_FILL);
} else {
brush.setColor(color.getQColor());
}
painter.setBrush(brush);
painter.drawPath(ring.pieced[i]);
}
}
else {
KisColor colors[7] = {
- KisColor(Qt::red , m_colorSpace),
- KisColor(Qt::yellow , m_colorSpace),
- KisColor(Qt::green , m_colorSpace),
KisColor(Qt::cyan , m_colorSpace),
- KisColor(Qt::blue , m_colorSpace),
+ KisColor(Qt::green , m_colorSpace),
+ KisColor(Qt::yellow , m_colorSpace),
+ KisColor(Qt::red , m_colorSpace),
KisColor(Qt::magenta, m_colorSpace),
- KisColor(Qt::red , m_colorSpace)
+ KisColor(Qt::blue , m_colorSpace),
+ KisColor(Qt::cyan , m_colorSpace)
};
QConicalGradient gradient(0, 0, 0);
for(int i=0; i<=6; ++i) {
qreal hue = float(i) / 6.0f;
colors[i].setS(ring.saturation);
- colors[i].setX(getLight(m_light, hue, m_relativeLight));
+ colors[i].setX(m_selectedColor.getX(m_gamma), m_gamma);
gradient.setColorAt(hue, colors[i].getQColor());
}
painter.scale(rect.width()/2, rect.height()/2);
painter.fillPath(ring.pieced[0], QBrush(gradient));
}
-// painter.resetTransform();
painter.restore();
}
void KisColorSelector::drawOutline(QPainter& painter, const QRect& rect)
{
painter.setRenderHint(QPainter::Antialiasing, true);
painter.resetTransform();
painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2);
painter.scale(rect.width()/2, rect.height()/2);
- QPen normalPen = QPen(QBrush(m_grayColor), 0.005);
- QPen selectedPen = QPen(QBrush(Qt::red), 0.01);
+ QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005);
+ QPen selectedPen = QPen(QBrush(COLOR_SELECTED), 0.01);
painter.setPen(normalPen);
if (getNumPieces() > 1) {
-// for(int i=0; i