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 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + image/svg+xml + + + 2016 + + + Timothée Giet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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
kis_slider_spin_box.h
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 0 0 - 20 + 16777215 16777215 + + Color wheel preferences + - Text-align:left + false - - - - Qt::Horizontal - - - - 40 - 20 - - - - 0 0 30 0 + + Docker settings + false 0 1 - - - - - - M - - - - - - - - - - true - - - - - - - - 0 - 0 - - - - Select a mask in "Gamut Masks" docker - - - true - - - - - KisPopupButton QPushButton
kis_popup_button.h
KisColorSelector QWidget
kis_color_selector.h
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
kis_slider_spin_box.h
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= 0 && m_selectedPiece >= 0) { painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); - painter.rotate(-m_colorRings[m_selectedRing].getShift().degrees()); + QTransform mirror; + mirror.rotate(180, Qt::YAxis); + painter.setTransform(mirror, true); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(selectedPen); painter.drawPath(m_colorRings[m_selectedRing].pieced[m_selectedPiece]); } } else { for(int i=0; i= 0) { qreal iRad = m_colorRings[m_selectedRing].innerRadius; qreal oRad = m_colorRings[m_selectedRing].outerRadius; painter.setPen(selectedPen); painter.drawEllipse(QRectF(-iRad, -iRad, iRad*2.0, iRad*2.0)); painter.drawEllipse(QRectF(-oRad, -oRad, oRad*2.0, oRad*2.0)); - float c = std::cos(-m_selectedColor.getH() * PI2); - float s = std::sin(-m_selectedColor.getH() * PI2); - painter.drawLine(QPointF(c*iRad, s*iRad), QPointF(c*oRad, s*oRad)); + QPointF lineCoords = mapHueToAngle(m_selectedColor.getH()); + painter.drawLine(QPointF(lineCoords.x()*iRad, lineCoords.y()*iRad), QPointF(lineCoords.x()*oRad, lineCoords.y()*oRad)); } } } void KisColorSelector::drawLightStrip(QPainter& painter, const QRect& rect) { - bool isVertical = true; qreal penSize = qreal(qMin(QWidget::width(), QWidget::height())) / 200.0; - KisColor color(m_fgColor); + KisColor valueScaleColor(m_selectedColor); + KisColor grayScaleColor(Qt::gray, m_colorSpace); + int rectSize = rect.height(); painter.resetTransform(); + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); - if (getNumLightPieces() > 1) { - painter.setRenderHint(QPainter::Antialiasing, true); - painter.setPen(QPen(QBrush(Qt::red), penSize)); + QTransform matrix; + matrix.translate(rect.x(), rect.y()); + matrix.scale(rect.width(), rect.height()); - QTransform matrix; - matrix.translate(rect.x(), rect.y()); - matrix.scale(rect.width(), rect.height()); + qreal rectColorLeftX; + qreal rectColorWidth; + if (m_showValueScaleNumbers) { + rectColorLeftX = 0.6; + rectColorWidth = 0.4; + } else { + rectColorLeftX = 0.0; + rectColorWidth = 1.0; + } + + if (getNumLightPieces() > 1) { for(int i=0; i coord X:" << fgColorPos.x() << " Y:" << fgColorPos.y(); +#endif - - painter.setPen(QPen(QBrush(Qt::white), 0.01)); + painter.setPen(QPen(QBrush(COLOR_LIGHT), 0.01)); painter.drawEllipse(fgColorPos, 0.05, 0.05); - painter.setPen(QPen(QBrush(Qt::black), 0.01)); + painter.setPen(QPen(QBrush(COLOR_DARK), 0.01)); painter.setBrush(m_fgColor.getQColor()); painter.drawEllipse(fgColorPos, 0.04, 0.04); } void KisColorSelector::drawGamutMaskShape(QPainter &painter, const QRect &rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.width()/2, rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(Qt::NoPen); - painter.setBrush(m_gamutMaskColor); + painter.setBrush(COLOR_MASK_FILL); painter.drawEllipse(QPointF(0,0), 1.0, 1.0); painter.resetTransform(); -// painter.setCompositionMode(QPainter::CompositionMode_Xor); - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); m_currentGamutMask->paint(painter, *m_viewConverter, m_maskPreviewActive); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + m_currentGamutMask->paintStroke(painter, *m_viewConverter, m_maskPreviewActive); + painter.restore(); } void KisColorSelector::paintEvent(QPaintEvent* /*event*/) { // 0 red -> (1,0,0) // 1 yellow -> (1,1,0) // 2 green -> (0,1,0) // 3 cyan -> (0,1,1) // 4 blue -> (0,0,1) // 5 maenta -> (1,0,1) // 6 red -> (1,0,0) m_renderBuffer.fill(0); QPainter imgPainter(&m_renderBuffer); QPainter wdgPainter(this); // draw the fg and bg color previews // QPainter settings must be saved and restored afterwards, otherwise the wheel drawing is totally broken wdgPainter.save(); wdgPainter.setRenderHint(QPainter::Antialiasing, true); QRect fgRect(0, 0, QWidget::width(), QWidget::height()); wdgPainter.fillRect(fgRect, m_fgColor.getQColor()); int bgSide = qMin(QWidget::width()*0.15,QWidget::height()*0.15); if (m_showBgColor) { QPointF bgPolyPoints[3] = { QPointF(QWidget::width(), QWidget::height()), QPointF(QWidget::width()-bgSide, QWidget::height()), QPointF(QWidget::width(), QWidget::height()-bgSide) }; wdgPainter.setBrush(m_bgColor.getQColor()); wdgPainter.setPen(m_bgColor.getQColor()); wdgPainter.drawPolygon(bgPolyPoints, 3); } wdgPainter.restore(); for(int i=0; ilocalPos(), m_renderArea); m_mouseMoved = false; m_pressedButtons = event->buttons(); m_clickedRing = getSaturationIndex(m_clickPos); + Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); qint8 clickedLightPiece = getLightIndex(event->localPos()); if (clickedLightPiece >= 0) { - setLight(getLight(event->localPos()), m_relativeLight); + setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; - requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); + requestUpdateColorAndPreview(m_selectedColor, colorRole); m_mouseMoved = true; } else if (m_clickedRing >= 0) { - if (getNumPieces() > 1) { - for(int i=0; ilocalPos(), m_renderArea); qint8 clickedLightPiece = getLightIndex(event->localPos()); + Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); if (clickedLightPiece >= 0) { - setLight(getLight(event->localPos()), m_relativeLight); + setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; - requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); + requestUpdateColorAndPreview(m_selectedColor, colorRole); } if (m_clickedRing < 0) return; - if (getNumPieces() > 1) { - float angle = std::atan2(dragPos.x(), dragPos.y()) - std::atan2(m_clickPos.x(), m_clickPos.y()); - float dist = std::sqrt(dragPos.x()*dragPos.x() + dragPos.y()*dragPos.y()) * 0.80f; - float threshold = 5.0f * (1.0f-(dist*dist)); - - if (qAbs(angle * TO_DEG) >= threshold || m_mouseMoved) { - bool selectedRingMoved = true; - - if (m_pressedButtons & Qt::RightButton) { - selectedRingMoved = m_clickedRing == m_selectedRing; - m_colorRings[m_clickedRing].angle = m_colorRings[m_clickedRing].tmpAngle + angle; - } - else for(int i=0; i= 0) { - Radian angle = std::atan2(m_clickPos.x(), m_clickPos.y()) - RAD_90; - KisColor color; + Radian angle = mapCoordToAngle(m_clickPos.x(), m_clickPos.y()); + KisColor color(m_colorSpace); - qint8 hueIndex = getHueIndex(angle, m_colorRings[m_clickedRing].getShift()); + qint8 hueIndex = getHueIndex(angle); if (getNumPieces() > 1) { - color.setH(getHue(hueIndex, m_colorRings[m_clickedRing].getShift())); + color.setH(getHue(hueIndex)); } else { color.setH(angle.scaled(0.0f, 1.0f)); } color.setS(getSaturation(m_clickedRing)); - color.setX(getLight(m_light, color.getH(), m_relativeLight)); + color.setX(m_selectedColor.getX(m_gamma), m_gamma); if ((!m_enforceGamutMask) || colorIsClear(color)) { - m_selectedColor.setHSX(color.getH(), color.getS(), color.getX()); + m_selectedColor.setHSX(color.getH(), color.getS(), color.getX(m_gamma), color.getA(), m_gamma); m_selectedPiece = hueIndex; m_selectedRing = m_clickedRing; - requestUpdateColorAndPreview(m_selectedColor, Acs::buttonsToRole(Qt::NoButton, m_pressedButtons)); + requestUpdateColorAndPreview(m_selectedColor, colorRole); } } else if (m_mouseMoved) - requestUpdateColorAndPreview(m_selectedColor, m_selectedColorRole); + requestUpdateColorAndPreview(m_selectedColor, colorRole); m_clickedRing = -1; m_widgetUpdatesSelf = false; +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::ReleasePressEvent: m_widgetUpdatesSelf = false"; +#endif update(); } void KisColorSelector::resizeEvent(QResizeEvent* /*event*/) { recalculateAreas(quint8(getNumLightPieces())); } void KisColorSelector::leaveEvent(QEvent* /*e*/) { m_widgetUpdatesSelf = false; +#ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::leaveEvent: m_widgetUpdatesSelf = false"; +#endif } void KisColorSelector::saveSettings() { KisConfig cfg; cfg.writeEntry("ArtColorSel.ColorSpace" , qint32(m_colorSpace)); cfg.writeEntry("ArtColorSel.NumRings" , m_colorRings.size()); cfg.writeEntry("ArtColorSel.RingPieces" , qint32(m_numPieces)); cfg.writeEntry("ArtColorSel.LightPieces", qint32(m_numLightPieces)); cfg.writeEntry("ArtColorSel.InversedSaturation", m_inverseSaturation); - cfg.writeEntry("ArtColorSel.RelativeLight" , m_relativeLight); - cfg.writeEntry("ArtColorSel.Light" , m_light); + cfg.writeEntry("ArtColorSel.Light" , m_selectedColor.getX(m_gamma)); cfg.writeEntry("ArtColorSel.SelColorH", m_selectedColor.getH()); cfg.writeEntry("ArtColorSel.SelColorS", m_selectedColor.getS()); - cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX()); + cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX(m_gamma)); cfg.writeEntry("ArtColorSel.SelColorA", m_selectedColor.getA()); cfg.writeEntry("ArtColorSel.defaultHueSteps", quint32(m_defaultHueSteps)); cfg.writeEntry("ArtColorSel.defaultSaturationSteps", quint32(m_defaultSaturationSteps)); cfg.writeEntry("ArtColorSel.defaultValueScaleSteps", quint32(m_defaultValueScaleSteps)); cfg.writeEntry("ArtColorSel.showBgColor", m_showBgColor); cfg.writeEntry("ArtColorSel.showColorBlip", m_showColorBlip); - cfg.writeEntry("ArtColorSel.showValueScaleNumber", m_showValueScaleNumbers); + cfg.writeEntry("ArtColorSel.showValueScale", m_showValueScaleNumbers); cfg.writeEntry("ArtColorSel.enforceGamutMask", m_enforceGamutMask); cfg.writeEntry("ArtColorSel.maskPreviewActive", m_maskPreviewActive); - - QList angles; - - for(int i=0; i("ArtColorSel.ColorSpace" , KisColor::HSY))); m_defaultHueSteps = cfg.readEntry("ArtColorSel.defaultHueSteps", DEFAULT_HUE_STEPS); m_defaultSaturationSteps = cfg.readEntry("ArtColorSel.defaultSaturationSteps", DEFAULT_SATURATION_STEPS); m_defaultValueScaleSteps = cfg.readEntry("ArtColorSel.defaultValueScaleSteps", DEFAULT_VALUE_SCALE_STEPS); setNumLightPieces(cfg.readEntry("ArtColorSel.LightPieces", DEFAULT_VALUE_SCALE_STEPS)); + KisColor::Type colorSpace = KisColor::Type(cfg.readEntry("ArtColorSel.ColorSpace" , KisColor::HSY)); + float valueScaleGamma = cfg.readEntry("ArtColorSel.valueScaleGamma", 2.2f); + if (colorSpace == KisColor::HSY) { + setGamma(valueScaleGamma); + + } + + setColorSpace(colorSpace, valueScaleGamma); + m_selectedColor.setH(cfg.readEntry("ArtColorSel.SelColorH", 0.0f)); m_selectedColor.setS(cfg.readEntry("ArtColorSel.SelColorS", 0.0f)); - m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0f)); + m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0f), m_gamma); m_selectedColor.setA(1.0f); setInverseSaturation(cfg.readEntry("ArtColorSel.InversedSaturation", false)); - setLight(cfg.readEntry("ArtColorSel.Light", 0.5f), cfg.readEntry("ArtColorSel.RelativeLight", true)); + setLight(cfg.readEntry("ArtColorSel.Light", 0.5f)); - setNumRings(cfg.readEntry("ArtColorSel.NumRings" , DEFAULT_SATURATION_STEPS)); + setNumRings(cfg.readEntry("ArtColorSel.NumRings", DEFAULT_SATURATION_STEPS)); setNumPieces(cfg.readEntry("ArtColorSel.RingPieces", DEFAULT_HUE_STEPS)); - QList angles = cfg.readList("ArtColorSel.RingAngles"); - - for (int i = 0; i < m_colorRings.size(); ++i) { - if (i < angles.size() && i < m_colorRings.size()) { - m_colorRings[i].angle = angles[i]; - } - } - m_showBgColor = cfg.readEntry("ArtColorSel.showBgColor", true); m_showColorBlip = cfg.readEntry("ArtColorSel.showColorBlip", true); - m_showValueScaleNumbers = cfg.readEntry("ArtColorSel.showValueScaleNumber", false); - m_enforceGamutMask = cfg.readEntry("ArtColorSel.enforceGamutMask", true); + m_showValueScaleNumbers = cfg.readEntry("ArtColorSel.showValueScale", false); + m_enforceGamutMask = cfg.readEntry("ArtColorSel.enforceGamutMask", false); m_maskPreviewActive = cfg.readEntry("ArtColorSel.maskPreviewActive", true); selectColor(m_selectedColor); update(); } void KisColorSelector::setDefaultHueSteps(int num) { num = qBound(MIN_NUM_HUE_PIECES, num, MAX_NUM_HUE_PIECES); m_defaultHueSteps = num; } void KisColorSelector::setDefaultSaturationSteps(int num) { num = qBound(MIN_NUM_SATURATION_RINGS, num, MAX_NUM_SATURATION_RINGS); m_defaultSaturationSteps = num; } void KisColorSelector::setDefaultValueScaleSteps(int num) { num = qBound(MIN_NUM_LIGHT_PIECES, num, MAX_NUM_LIGHT_PIECES); m_defaultValueScaleSteps = num; } void KisColorSelector::setShowColorBlip(bool value) { m_showColorBlip = value; update(); } void KisColorSelector::setShowBgColor(bool value) { m_showBgColor = value; update(); } void KisColorSelector::setShowValueScaleNumbers(bool value) { m_showValueScaleNumbers = value; + recalculateAreas(quint8(getNumLightPieces())); update(); } bool KisColorSelector::saturationIsInvertible() { if (!m_gamutMaskOn) return true; bool b = (m_enforceGamutMask && getNumPieces() == 1) ? false : true; return b; } diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.h b/plugins/dockers/artisticcolorselector/kis_color_selector.h index 4c7165c01a..8014cfaa95 100644 --- a/plugins/dockers/artisticcolorselector/kis_color_selector.h +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.h @@ -1,212 +1,199 @@ /* 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_SELECTOR_H #define H_KIS_COLOR_SELECTOR_H #include #include #include #include #include "kis_color.h" #include "kis_radian.h" #include "kis_acs_types.h" #include "kis_signal_compressor_with_param.h" #include #include class QPainter; class QPainter; class KisColorSelector: public QWidget { Q_OBJECT typedef KisRadian Radian; struct ColorRing { - ColorRing(): angle(0) { } + ColorRing() + : saturation(0) + , outerRadius(0) + , innerRadius(0) + { } - Radian getPieceAngle() const { return RAD_360 / float(pieced.size()); } - Radian getShift () const { return angle % getPieceAngle(); } - Radian getMovedAngel() const { return angle - tmpAngle; } - - void setTemporaries(const KisColor& color) { - tmpAngle = angle; - tmpColor = color; - } - - KisColor tmpColor; - Radian tmpAngle; - Radian angle; float saturation; float outerRadius; float innerRadius; QVector pieced; }; public: KisColorSelector(QWidget* parent, KisColor::Type type=KisColor::HSL); - void setColorSpace(KisColor::Type type); + void setColorSpace(KisColor::Type type, float valueScaleGamma); void setNumPieces(int num); void setNumLightPieces(int num) __attribute__((optimize(0))); void setNumRings(int num); - void resetRings(); - void resetSelectedRing(); - void resetLight(); - void setLight(float light=0.0f, bool relative=true); + + void setLight(float light=0.0f); + + float gamma() const { return m_gamma; } + void setGamma(float gamma); + void setInverseSaturation(bool inverse); void selectColor(const KisColor& color); void setFgColor(const KisColor& fgColor); void setBgColor(const KisColor& bgColor); void setDefaultHueSteps(int num); void setDefaultSaturationSteps(int num); void setDefaultValueScaleSteps(int num); void setShowColorBlip(bool value); void setShowBgColor(bool value); void setShowValueScaleNumbers(bool value); void setGamutMask(KoGamutMask* gamutMask); bool gamutMaskOn(); void setGamutMaskOn(bool gamutMaskOn); void setEnforceGamutMask(bool enforce); KoGamutMask* gamutMask(); bool maskPreviewActive(); void setMaskPreviewActive(bool value); bool saturationIsInvertible(); void saveSettings(); void loadSettings(); KisColor::Type getColorSpace () const { return m_colorSpace; } qint32 getNumRings () const { return m_colorRings.size(); } qint32 getNumPieces () const { return m_numPieces; } qint32 getNumLightPieces () const { return m_numLightPieces; } - qreal getLight () const { return m_light; } bool isSaturationInverted() const { return m_inverseSaturation; } - bool islightRelative () const { return m_relativeLight; } quint32 getDefaultHueSteps () const { return m_defaultHueSteps; } quint32 getDefaultSaturationSteps () const { return m_defaultSaturationSteps; } quint32 getDefaultValueScaleSteps () const { return m_defaultValueScaleSteps; } bool getShowColorBlip () const { return m_showColorBlip; } bool getShowBgColor () const { return m_showBgColor; } bool getShowValueScaleNumbers () const { return m_showValueScaleNumbers; } bool enforceGamutMask () const { return m_enforceGamutMask; } Q_SIGNALS: void sigFgColorChanged(const KisColor& color); void sigBgColorChanged(const KisColor& color); private: void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; void resizeEvent(QResizeEvent* event) override; void paintEvent(QPaintEvent* event) override; void leaveEvent(QEvent* e) override; bool colorIsClear(const KisColor &color); bool colorIsClear(const QPointF &colorPoint); void requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role); void recalculateAreas(quint8 numLightPieces); void recalculateRings(quint8 numRings, quint8 numPieces); void createRing(ColorRing& wheel, quint8 numPieces, qreal innerRadius, qreal outerRadius); - void drawRing(QPainter& painter, int ringIndex, ColorRing& wheel, const QRect& rect); + void drawRing(QPainter& painter, ColorRing& wheel, const QRect& rect); void drawOutline(QPainter& painter, const QRect& rect); void drawBlip(QPainter& painter, const QRect& rect); void drawLightStrip(QPainter& painter, const QRect& rect); void drawGamutMaskShape(QPainter& painter, const QRect& rect); - qint8 getHueIndex(Radian hue, Radian shift=0.0f) const; + qint8 getHueIndex(Radian hue) const; qreal getHue(int hueIdx, Radian shift=0.0f) const; qint8 getLightIndex(const QPointF& pt) const; qint8 getLightIndex(qreal light) const; - qreal getLight(qreal light, qreal hue, bool relative) const; qreal getLight(const QPointF& pt) const; qint8 getSaturationIndex(const QPointF& pt) const; qint8 getSaturationIndex(qreal saturation) const; qreal getSaturation(int saturationIdx) const; -// QPointF mapCoord(const QPointF& pt, const QRectF& rect) const; - QPointF mapCoordToView(const QPointF& pt, const QRectF& viewRect) const; QPointF mapCoordToUnit(const QPointF& pt, const QRectF& viewRect) const; QPointF mapColorToUnit(const KisColor& color, bool invertSaturation = true) const; + Radian mapCoordToAngle(qreal x, qreal y) const; + QPointF mapHueToAngle(float hue) const; public: // This is a private interface for signal compressor, don't use it. // Use requestUpdateColorAndPreview() instead void slotUpdateColorAndPreview(QPair color); private: KisColor::Type m_colorSpace; quint8 m_numPieces; quint8 m_numLightPieces; bool m_inverseSaturation; - bool m_relativeLight; - float m_light; + float m_gamma; qint8 m_selectedRing; qint8 m_selectedPiece; qint8 m_selectedLightPiece; KisColor m_selectedColor; KisColor m_fgColor; KisColor m_bgColor; QImage m_renderBuffer; QImage m_maskBuffer; QRect m_renderArea; QRect m_lightStripArea; bool m_mouseMoved; - Acs::ColorRole m_selectedColorRole; QPointF m_clickPos; qint8 m_clickedRing; QVector m_colorRings; Qt::MouseButtons m_pressedButtons; - const QColor m_grayColor; - const QColor m_gamutMaskColor; // docker settings quint8 m_defaultHueSteps; quint8 m_defaultSaturationSteps; quint8 m_defaultValueScaleSteps; bool m_showColorBlip; bool m_showValueScaleNumbers; bool m_showBgColor; bool m_gamutMaskOn; KoGamutMask* m_currentGamutMask; bool m_enforceGamutMask; QSize m_renderAreaSize; bool m_maskPreviewActive; KisGamutMaskViewConverter* m_viewConverter; bool m_widgetUpdatesSelf; typedef KisSignalCompressorWithParam> ColorCompressorType; QScopedPointer m_updateColorCompressor; }; #endif // H_KIS_COLOR_SELECTOR_H diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp index 05cd1eed15..88a318ed55 100644 --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp @@ -1,81 +1,105 @@ +/* + * 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 "KisGamutMaskChooser.h" #include #include #include #include #include #include #include /// The resource item delegate for rendering the resource preview class KisGamutMaskDelegate: public QAbstractItemDelegate { public: KisGamutMaskDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~KisGamutMaskDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void KisGamutMaskDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { painter->save(); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); if (!index.isValid()) return; KoResource* resource = static_cast(index.internalPointer()); KoGamutMask* mask = static_cast(resource); if (!mask) { return; } QImage preview = mask->image(); if(preview.isNull()) { return; } QRect paintRect = option.rect.adjusted(1, 1, -1, -1); painter->drawImage(paintRect.x(), paintRect.y(), preview.scaled(paintRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); painter->restore(); } KisGamutMaskChooser::KisGamutMaskChooser(QWidget *parent) : QWidget(parent) { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); QSharedPointer adapter(new KoResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setItemDelegate(new KisGamutMaskDelegate(this)); m_itemChooser->showTaggingBar(true); m_itemChooser->showButtons(false); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0,0,0,0); + // TODO: menu for view mode change + layout->addWidget(m_itemChooser); setLayout(layout); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); } KisGamutMaskChooser::~KisGamutMaskChooser() { } +void KisGamutMaskChooser::setCurrentResource(KoResource *resource) +{ + m_itemChooser->setCurrentResource(resource); +} + void KisGamutMaskChooser::resourceSelected(KoResource* resource) { emit sigGamutMaskSelected(static_cast(resource)); } diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.h b/plugins/dockers/gamutmask/KisGamutMaskChooser.h index 16743035b0..951d9e94a1 100644 --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.h +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.h @@ -1,27 +1,46 @@ +/* + * 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 KISGAMUTMASKCHOOSER_H #define KISGAMUTMASKCHOOSER_H #include class KoResourceItemChooser; class KoResource; class KoGamutMask; class KisGamutMaskChooser : public QWidget { Q_OBJECT public: explicit KisGamutMaskChooser(QWidget *parent = nullptr); ~KisGamutMaskChooser() override; + void setCurrentResource(KoResource* resource); + Q_SIGNALS: void sigGamutMaskSelected(KoGamutMask* mask); private Q_SLOTS: void resourceSelected(KoResource* resource); private: KoResourceItemChooser* m_itemChooser; }; #endif // KISGAMUTMASKCHOOSER_H diff --git a/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui b/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui index 51d8a93031..4de5919a58 100644 --- a/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui +++ b/plugins/dockers/gamutmask/forms/wdgGamutMaskChooser.ui @@ -1,214 +1,234 @@ wdgGamutMaskChooser 0 0 - 358 - 336 + 363 + 322 0 0 - - - - - - 0 - 0 - - - - Select a mask - - - - - - - Apply To Selector - - - - - - - - - - Edit - - - - - - - - - - Delete - - - - - - - + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Create new mask + + + + + + + + + + Edit selected mask + + + + + + + + + + Duplicate selected mask + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete selected mask + + + + + + + + 0 0 Edit the gamut mask 6 Title 30 Description 0 0 0 0 16777215 45 0 0 Cancel Qt::Horizontal 40 20 true Preview Save - - - - Save As New - - - - - - KisGamutMaskChooser QWidget
KisGamutMaskChooser.h
1
diff --git a/plugins/dockers/gamutmask/gamutmask_dock.cpp b/plugins/dockers/gamutmask/gamutmask_dock.cpp index a902eae5f8..16605b7a45 100644 --- a/plugins/dockers/gamutmask/gamutmask_dock.cpp +++ b/plugins/dockers/gamutmask/gamutmask_dock.cpp @@ -1,489 +1,603 @@ /* * 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 #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 "gamutmask_dock.h" #include #include +#include +#include + +#include #include "ui_wdgGamutMaskChooser.h" class KisMainWindow; struct GamutMaskChooserUI: public QWidget, public Ui_wdgGamutMaskChooser { GamutMaskChooserUI() { setupUi(this); } }; GamutMaskDock::GamutMaskDock() : QDockWidget(i18n("Gamut Masks")) , m_resourceProvider(0) + , m_selfClosingTemplate(false) + , m_externalTemplateClose(false) + , m_creatingNewMask(false) + , m_templatePrevSaved(false) + , m_selfSelectingMask(false) + , m_selectedMask(nullptr) , m_maskDocument(nullptr) , m_view(nullptr) - , m_selectedMask(nullptr) { m_dockerUI = new GamutMaskChooserUI(); m_dockerUI->bnMaskEditor->setIcon(KisIconUtils::loadIcon("dirty-preset")); - m_dockerUI->bnMaskSet->setIcon(KisIconUtils::loadIcon("dialog-ok")); m_dockerUI->bnMaskDelete->setIcon(KisIconUtils::loadIcon("deletelayer")); - m_dockerUI->maskPropertiesBox->setVisible(false); + m_dockerUI->bnMaskNew->setIcon(KisIconUtils::loadIcon("list-add")); + m_dockerUI->bnMaskDuplicate->setIcon(KisIconUtils::loadIcon("duplicatelayer")); - m_dockerUI->bnSaveMaskNew->setIcon(KisIconUtils::loadIcon("list-add")); + m_dockerUI->maskPropertiesBox->setVisible(false); m_dockerUI->bnSaveMask->setIcon(KisIconUtils::loadIcon("document-save")); m_dockerUI->bnCancelMaskEdit->setIcon(KisIconUtils::loadIcon("dialog-cancel")); m_dockerUI->bnPreviewMask->setIcon(KisIconUtils::loadIcon("visible")); - QRegularExpression maskTitleRegex("^[-_\\sA-Za-z0-9]+$"); + QRegularExpression maskTitleRegex("^[-_\\(\\)\\sA-Za-z0-9]+$"); QRegularExpressionValidator* m_maskTitleValidator = new QRegularExpressionValidator(maskTitleRegex, this); m_dockerUI->maskTitleEdit->setValidator(m_maskTitleValidator); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->addObserver(this); // gamut mask connections connect(m_dockerUI->bnSaveMask , SIGNAL(clicked()) , SLOT(slotGamutMaskSave())); connect(m_dockerUI->bnCancelMaskEdit , SIGNAL(clicked()) , SLOT(slotGamutMaskCancelEdit())); connect(m_dockerUI->bnPreviewMask , SIGNAL(clicked()) , SLOT(slotGamutMaskPreview())); connect(m_dockerUI->bnMaskEditor , SIGNAL(clicked()) , SLOT(slotGamutMaskEdit())); connect(m_dockerUI->maskChooser, SIGNAL(sigGamutMaskSelected(KoGamutMask*)), SLOT(slotGamutMaskSelected(KoGamutMask*))); - connect(m_dockerUI->bnSaveMaskNew , SIGNAL(clicked()) , SLOT(slotGamutMaskSaveNew())); - connect(m_dockerUI->bnMaskSet , SIGNAL(clicked()) , SLOT(slotGamutMaskSet())); + connect(m_dockerUI->bnMaskNew , SIGNAL(clicked()) , SLOT(slotGamutMaskCreateNew())); connect(m_dockerUI->bnMaskDelete , SIGNAL(clicked()) , SLOT(slotGamutMaskDelete())); + connect(m_dockerUI->bnMaskDuplicate , SIGNAL(clicked()) , SLOT(slotGamutMaskDuplicate())); setWidget(m_dockerUI); } GamutMaskDock::~GamutMaskDock() { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeObserver(this); } void GamutMaskDock::setMainWindow(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); - m_selectedMask = m_resourceProvider->currentGamutMask(); + selectMask(m_resourceProvider->currentGamutMask()); connect(this, SIGNAL(sigGamutMaskSet(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); connect(this, SIGNAL(sigGamutMaskUnset()), m_resourceProvider, SLOT(slotGamutMaskUnset())); connect(this, SIGNAL(sigGamutMaskPreviewUpdate()), m_resourceProvider, SLOT(slotGamutMaskPreviewUpdate())); connect(KisPart::instance(), SIGNAL(sigDocumentRemoved(QString)), this, SLOT(slotDocumentRemoved(QString))); } void GamutMaskDock::slotGamutMaskEdit() { if (!m_selectedMask) { return; } openMaskEditor(); } void GamutMaskDock::openMaskEditor() { - m_dockerUI->maskPropertiesBox->setVisible(true); - - //shouldnt be nullptr here if (!m_selectedMask) { return; } + m_dockerUI->maskPropertiesBox->setVisible(true); + m_dockerUI->maskPropertiesBox->setEnabled(true); + m_dockerUI->editControlsBox->setEnabled(false); + m_dockerUI->editControlsBox->setVisible(false); + m_dockerUI->maskTitleEdit->setText(m_selectedMask->title()); m_dockerUI->maskDescriptionEdit->setPlainText(m_selectedMask->description()); // open gamut mask template in the application QString maskTemplateFile = KoResourcePaths::findResource("data", "gamutmasks/GamutMaskTemplate.kra"); - dbgPlugins << "GamutMaskDock::slotGamutMaskEdit: maskTemplateFile" - << maskTemplateFile; - // open template document m_maskDocument = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(m_maskDocument); m_maskDocument->openUrl(QUrl::fromLocalFile(maskTemplateFile), KisDocument::DontAddToRecent); - m_maskDocument->resetURL(); + + // template document needs a proper autogenerated filename, + // to avoid collision with other documents, + // otherwise bugs happen when slotDocumentRemoved is called + // (e.g. user closes another view, the template stays open, but the edit operation is canceled) + m_maskDocument->setInfiniteAutoSaveInterval(); + QString maskPath = QString("%1%2%3_%4.kra") + .arg(QDir::tempPath()) + .arg(QDir::separator()) + .arg("GamutMaskTemplate") + .arg(std::time(nullptr)); + m_maskDocument->setUrl(QUrl::fromLocalFile(maskPath)); + m_maskDocument->setLocalFilePath(maskPath); KisShapeLayerSP shapeLayer = getShapeLayer(); // pass only copies of shapes to the layer, // so the originals don't disappear from the mask later for (KoShape *shape: m_selectedMask->koShapes()) { - shapeLayer->addShape(shape->cloneShape()); + KoShape* newShape = shape->cloneShape(); + newShape->setStroke(KoShapeStrokeModelSP()); + newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255)))); + shapeLayer->addShape(newShape); } m_maskDocument->setPreActivatedNode(shapeLayer); // set document as active KisMainWindow* mainWindow = KisPart::instance()->currentMainwindow(); - Q_ASSERT(mainWindow); + KIS_ASSERT(mainWindow); m_view = mainWindow->addViewAndNotifyLoadingCompleted(m_maskDocument); - Q_ASSERT(m_view); + KIS_ASSERT(m_view); for(KisView *view: KisPart::instance()->views()) { if (view->document() == m_maskDocument) { view->activateWindow(); break; } } + + connect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); + connect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); } void GamutMaskDock::cancelMaskEdit() { + if (m_creatingNewMask) { + deleteMask(); + } + if (m_selectedMask) { m_selectedMask->clearPreview(); - m_dockerUI->maskPropertiesBox->setVisible(false); - if (m_resourceProvider->currentGamutMask() == m_selectedMask) { emit sigGamutMaskChanged(m_selectedMask); } } + + closeMaskDocument(); } -void GamutMaskDock::saveSelectedMaskResource() +void GamutMaskDock::selectMask(KoGamutMask *mask, bool notifyItemChooser) { + if (!mask) { + return; + } + + m_selectedMask = mask; + + if (notifyItemChooser) { + m_selfSelectingMask = true; + m_dockerUI->maskChooser->setCurrentResource(m_selectedMask); + m_selfSelectingMask = false; + } + + emit sigGamutMaskSet(m_selectedMask); +} + +bool GamutMaskDock::saveSelectedMaskResource() +{ + if (!m_selectedMask || !m_maskDocument) { + return false; + } + + bool maskSaved = false; + if (m_selectedMask) { - m_selectedMask->setDescription(m_dockerUI->maskDescriptionEdit->toPlainText()); + QList shapes = getShapesFromLayer(); - m_selectedMask->setMaskShapes(getShapesFromLayer()); + if (shapes.count() > 0) { + m_selectedMask->setMaskShapes(shapes); - m_selectedMask->setImage( - m_maskDocument->image()->convertToQImage(m_maskDocument->image()->bounds() - , m_maskDocument->image()->profile() - ) - ); + m_selectedMask->setImage( + m_maskDocument->image()->convertToQImage(m_maskDocument->image()->bounds() + , m_maskDocument->image()->profile() + ) + ); - m_selectedMask->clearPreview(); - m_selectedMask->save(); + m_selectedMask->setDescription(m_dockerUI->maskDescriptionEdit->toPlainText()); + + m_selectedMask->clearPreview(); + m_selectedMask->save(); + maskSaved = true; + } else { + getUserFeedback(i18n("

Saving of gamut mask '%1' was aborted.

" + "

The mask template is invalid.

" + "

Please check that:" + "

    " + "
  • your template contains a vector layer named 'maskShapesLayer'
  • " + "
  • there are one or more vector shapes on the 'maskShapesLayer'
  • " + "

" + , m_selectedMask->title()), + QMessageBox::Ok, QMessageBox::Ok); + } } + + return maskSaved; } -void GamutMaskDock::finalizeMaskSave() +void GamutMaskDock::deleteMask() { - closeMaskDocument(); - m_dockerUI->maskPropertiesBox->setVisible(false); + KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); + rServer->removeResourceAndBlacklist(m_selectedMask); + m_selectedMask = nullptr; } -KoGamutMask* GamutMaskDock::addDuplicateResource(QString newTitle) +int GamutMaskDock::getUserFeedback(QString message, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - // construct a copy - KoGamutMask* newMask = new KoGamutMask(m_selectedMask); + int res = QMessageBox::warning(this, + i18nc("@title:window", "Krita"), + message, + buttons, defaultButton); + + return res; +} + +int GamutMaskDock::saveOrCancel(QMessageBox::StandardButton defaultAction) +{ + int response = 0; + + if (m_maskDocument->isModified()) { + response = getUserFeedback(i18n("

Gamut mask '%1' has been modified.

Do you want to save it?

" + , m_selectedMask->title()), + QMessageBox::Cancel | QMessageBox::Close | QMessageBox::Save, defaultAction); + + } else if (m_templatePrevSaved && defaultAction != QMessageBox::Close) { + response = QMessageBox::Save; + + } else if (!m_templatePrevSaved) { + response = QMessageBox::Close; + + } else { + response = defaultAction; + } + + switch (response) { + case QMessageBox::Save : { + slotGamutMaskSave(); + break; + } + case QMessageBox::Close : { + cancelMaskEdit(); + break; + } + } + + return response; +} + +KoGamutMask *GamutMaskDock::createMaskResource(KoGamutMask* sourceMask, QString newTitle) +{ + m_creatingNewMask = true; + + KoGamutMask* newMask = nullptr; + if (sourceMask) { + newMask = new KoGamutMask(sourceMask); + newMask->setImage(sourceMask->image()); + } else { + newMask = new KoGamutMask(); + QString defaultPreviewPath = KoResourcePaths::findResource("data", "gamutmasks/empty_mask_preview.png"); + newMask->setImage(QImage(defaultPreviewPath, "PNG")); + } QPair maskFile = resolveMaskTitle(newTitle); QString maskTitle = maskFile.first; QFileInfo fileInfo = maskFile.second; newMask->setTitle(maskTitle); newMask->setFilename(fileInfo.filePath()); newMask->setValid(true); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); + rServer->removeFromBlacklist(newMask); rServer->addResource(newMask, false); - - return newMask; } QPair GamutMaskDock::resolveMaskTitle(QString suggestedTitle) { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); QString saveLocation = rServer->saveLocation(); - QString processedTitle = suggestedTitle.trimmed(); - QString newFilename = saveLocation + processedTitle.replace(QRegularExpression("\\s+"), "_") + ".kgm"; - - QFileInfo fileInfo(newFilename); - QStringList resourceBlacklist = rServer->blackListedFiles(); - - int i = 1; - int lastIndex = 0; - while (fileInfo.exists()) { - if (resourceBlacklist.contains(fileInfo.filePath())) { - // allow to overwrite blacklisted masks - break; - } else { - fileInfo.setFile(saveLocation + processedTitle + QString("%1").arg(i) + ".kgm"); - lastIndex = i; - i++; - } + QString resourceName = processedTitle; + while (rServer->resourceByName(resourceName)) { + resourceName = resourceName + QString(" (Copy)"); } - QString maskTitle = (lastIndex > 0) ? (processedTitle + QString("%1").arg(lastIndex)) : processedTitle; + QString maskTitle = resourceName; + QString maskFile = maskTitle + ".kgm"; + QString path = saveLocation + maskFile.replace(QRegularExpression("\\s+"), "_"); + QFileInfo fileInfo(path); return QPair(maskTitle, fileInfo); } void GamutMaskDock::closeMaskDocument() { - if (m_maskDocument) { - // HACK: set the document to not modified to bypass confirmation dialog - // the close is already confirmed - m_maskDocument->setModified(false); + if (!m_externalTemplateClose) { + if (m_maskDocument) { + // set the document to not modified to bypass confirmation dialog + // the close is already confirmed + m_maskDocument->setModified(false); + + m_maskDocument->closeUrl(); + m_view->closeView(); + m_view->deleteLater(); + + // set a flag that we are doing it ourselves, so the docker does not react to + // removing signal from KisPart + m_selfClosingTemplate = true; + KisPart::instance()->removeView(m_view); + KisPart::instance()->removeDocument(m_maskDocument); + m_selfClosingTemplate = false; + } + } - m_maskDocument->closeUrl(); - m_view->closeView(); - m_view->deleteLater(); + m_dockerUI->maskPropertiesBox->setVisible(false); + m_dockerUI->editControlsBox->setVisible(true); + m_dockerUI->editControlsBox->setEnabled(true); - // HACK: set a flag that we are doing it ourselves, so the docker does not react to - // removing signal from KisPart - m_selfClosingMaskFile = true; - KisPart::instance()->removeView(m_view); - KisPart::instance()->removeDocument(m_maskDocument); - m_selfClosingMaskFile = false; + disconnect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); + disconnect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); - m_maskDocument = nullptr; - m_view = nullptr; + // the template file is meant as temporary, if the user saved it, delete now + if (QFile::exists(m_maskDocument->localFilePath())) { + QFile::remove(m_maskDocument->localFilePath()); } + + m_maskDocument = nullptr; + m_view = nullptr; + m_creatingNewMask = false; + m_templatePrevSaved = false; } QList GamutMaskDock::getShapesFromLayer() { KisShapeLayerSP shapeLayer = getShapeLayer(); // create a deep copy of the shapes to save in the mask, // otherwise they vanish when the template closes QList newShapes; - for (KoShape* sh: shapeLayer->shapes()) { - KoShape* newShape = sh->cloneShape(); - newShapes.append(newShape); + + if (shapeLayer) { + for (KoShape* sh: shapeLayer->shapes()) { + KoShape* newShape = sh->cloneShape(); + KoShapeStrokeSP border(new KoShapeStroke(0.5f, Qt::white)); + newShape->setStroke(border); + newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255,0)))); + newShapes.append(newShape); + } } return newShapes; } KisShapeLayerSP GamutMaskDock::getShapeLayer() { KisNodeSP node = m_maskDocument->image()->rootLayer()->findChildByName("maskShapesLayer"); return KisShapeLayerSP(dynamic_cast(node.data())); } void GamutMaskDock::slotGamutMaskSave() { + if (!m_selectedMask || !m_maskDocument) { + return; + } + QString newTitle = m_dockerUI->maskTitleEdit->text(); - // was this mask previously set to selectors? - bool setToSelectors = (m_resourceProvider->currentGamutMask() == m_selectedMask); if (m_selectedMask->title() != newTitle) { // title has changed, rename - if (!m_selectedMask) { - return; - } - - // construct a copy - KoGamutMask* newMask = addDuplicateResource(newTitle); + KoGamutMask* newMask = createMaskResource(m_selectedMask, newTitle); // delete old mask and select new - slotGamutMaskDelete(); - m_selectedMask = newMask; + deleteMask(); + selectMask(newMask); } - saveSelectedMaskResource(); - finalizeMaskSave(); - - if (setToSelectors) { + bool maskSaved = saveSelectedMaskResource(); + if (maskSaved) { emit sigGamutMaskSet(m_selectedMask); + closeMaskDocument(); } } void GamutMaskDock::slotGamutMaskCancelEdit() { if (!m_selectedMask) { return; } - bool cancelApproved = false; - if (m_maskDocument->isModified()) { - int res = QMessageBox::warning(this, - i18nc("@title:window", "Krita"), - i18n("

Gamut mask '%1' has been modified.

Discard changes?

" - , m_selectedMask->title()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - - switch (res) { - case QMessageBox::Yes : { - cancelApproved = true; - break; - } - case QMessageBox::No : { - cancelApproved = false; - break; - } - } - } else { - cancelApproved = true; - } - - if (cancelApproved) { - cancelMaskEdit(); - closeMaskDocument(); - } + saveOrCancel(QMessageBox::Close); } void GamutMaskDock::slotGamutMaskPreview() { if (!m_selectedMask) { return; } m_selectedMask->setPreviewMaskShapes(getShapesFromLayer()); emit sigGamutMaskPreviewUpdate(); } void GamutMaskDock::slotGamutMaskSelected(KoGamutMask *mask) { - m_selectedMask = mask; + if (!m_selfSelectingMask) { + if (m_maskDocument) { + int res = saveOrCancel(); + if (res == QMessageBox::Cancel) { + return; + } + } - if (m_selectedMask) { - m_dockerUI->labelMaskName->setText(m_selectedMask->title()); - } else { - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); + selectMask(mask, false); } } void GamutMaskDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); } void GamutMaskDock::unsetCanvas() { setEnabled(false); } void GamutMaskDock::unsetResourceServer() { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeObserver(this); } void GamutMaskDock::removingResource(KoGamutMask *resource) { // if deleting previously set mask, notify selectors to unset their mask if (resource == m_resourceProvider->currentGamutMask()) { emit sigGamutMaskUnset(); m_selectedMask = nullptr; - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); } } void GamutMaskDock::resourceChanged(KoGamutMask *resource) { // if currently set mask has been changed, notify selectors - // TODO: is m_resourceProvider->currentGamutMask() == m_selectedMask? if (resource == m_resourceProvider->currentGamutMask()) { - m_selectedMask = resource; - emit sigGamutMaskChanged(resource); + selectMask(resource); } } -void GamutMaskDock::slotGamutMaskSaveNew() +void GamutMaskDock::slotGamutMaskCreateNew() +{ + KoGamutMask* newMask = createMaskResource(nullptr, "new mask"); + selectMask(newMask); + openMaskEditor(); +} + +void GamutMaskDock::slotGamutMaskDuplicate() { if (!m_selectedMask) { return; } - KoGamutMask* newMask = addDuplicateResource(m_dockerUI->maskTitleEdit->text()); - m_selectedMask = newMask; - - saveSelectedMaskResource(); - finalizeMaskSave(); + KoGamutMask* newMask = createMaskResource(m_selectedMask, m_selectedMask->title()); + selectMask(newMask); + openMaskEditor(); } void GamutMaskDock::slotGamutMaskDelete() { if (!m_selectedMask) { return; } - int res = QMessageBox::warning(this, - i18nc("@title:window", "Krita"), - i18n("Are you sure you want to delete mask '%1'?" - , m_selectedMask->title()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + int res = getUserFeedback(i18n("Are you sure you want to delete mask '%1'?" + , m_selectedMask->title())); - // delete only if user confirms if (res == QMessageBox::Yes) { - KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); - // TODO: other resources do it this way, but the files stay on disk - rServer->removeResourceAndBlacklist(m_selectedMask); - - m_selectedMask = nullptr; - m_dockerUI->labelMaskName->setText(i18n("Select a mask")); + deleteMask(); } } -void GamutMaskDock::slotGamutMaskSet() -{ - if (!m_selectedMask) { - return; - } - - emit sigGamutMaskSet(m_selectedMask); -} - void GamutMaskDock::slotDocumentRemoved(QString filename) { if (!m_maskDocument) { return; } - // HACK: we do not want to run this if it is we who close the file - if (!m_selfClosingMaskFile) { + m_externalTemplateClose = true; + + // we do not want to run this if it is we who close the file + if (!m_selfClosingTemplate) { // KisPart called, that a document will be removed // if it's ours, cancel the mask edit operation if (m_maskDocument->url().toLocalFile() == filename) { - cancelMaskEdit(); + m_maskDocument->waitForSavingToComplete(); + saveOrCancel(); } } + + m_externalTemplateClose = false; +} + +void GamutMaskDock::slotViewChanged() +{ + if (!m_maskDocument || !m_view) { + return; + } + + if (m_view->viewManager()->document() == m_maskDocument) { + m_dockerUI->maskPropertiesBox->setEnabled(true); + } else { + m_dockerUI->maskPropertiesBox->setEnabled(false); + } +} + +void GamutMaskDock::slotDocumentSaved() +{ + m_templatePrevSaved = true; } diff --git a/plugins/dockers/gamutmask/gamutmask_dock.h b/plugins/dockers/gamutmask/gamutmask_dock.h index 9cf5451bd5..6e84924927 100644 --- a/plugins/dockers/gamutmask/gamutmask_dock.h +++ b/plugins/dockers/gamutmask/gamutmask_dock.h @@ -1,111 +1,124 @@ /* * 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 H_GAMUT_MASK_DOCK_H #define H_GAMUT_MASK_DOCK_H #include #include #include +#include #include #include #include #include #include #include #include #include #include #include class KisCanvasResourceProvider; -class KisColor; class QButtonGroup; class QMenu; struct GamutMaskChooserUI; class GamutMaskDock: public QDockWidget, public KisMainwindowObserver, public KoResourceServerObserver { Q_OBJECT public: GamutMaskDock(); ~GamutMaskDock() override; QString observerName() override { return "GamutMaskDock"; } void setMainWindow(KisViewManager* kisview) override; void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; public: // KoResourceServerObserver void unsetResourceServer() override; - void resourceAdded(KoGamutMask* resource) override {} + void resourceAdded(KoGamutMask* /*resource*/) override {}; void removingResource(KoGamutMask* resource) override; void resourceChanged(KoGamutMask* resource) override; void syncTaggedResourceView() override {} void syncTagAddition(const QString&) override {} void syncTagRemoval(const QString&) override {} Q_SIGNALS: void sigGamutMaskSet(KoGamutMask* mask); void sigGamutMaskChanged(KoGamutMask* mask); void sigGamutMaskUnset(); void sigGamutMaskPreviewUpdate(); private Q_SLOTS: void slotGamutMaskEdit(); void slotGamutMaskSave(); void slotGamutMaskCancelEdit(); void slotGamutMaskSelected(KoGamutMask* mask); void slotGamutMaskPreview(); - void slotGamutMaskSaveNew(); + void slotGamutMaskCreateNew(); + void slotGamutMaskDuplicate(); void slotGamutMaskDelete(); - void slotGamutMaskSet(); void slotDocumentRemoved(QString filename); + void slotViewChanged(); + void slotDocumentSaved(); private: - KisCanvasResourceProvider* m_resourceProvider; - void closeMaskDocument(); void openMaskEditor(); void cancelMaskEdit(); - void saveSelectedMaskResource(); - void finalizeMaskSave(); + void selectMask(KoGamutMask* mask, bool notifyItemChooser = true); + bool saveSelectedMaskResource(); + void deleteMask(); + int getUserFeedback(QString message + , QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No + , QMessageBox::StandardButton defaultButton = QMessageBox::Yes); + + int saveOrCancel(QMessageBox::StandardButton defaultAction = QMessageBox::Save); - bool m_selfClosingMaskFile; + KoGamutMask* createMaskResource(KoGamutMask* sourceMask, QString newTitle); - KoGamutMask *addDuplicateResource(QString newTitle); QPair resolveMaskTitle(QString suggestedTitle); QList getShapesFromLayer(); KisShapeLayerSP getShapeLayer(); + KisCanvasResourceProvider* m_resourceProvider; + + bool m_selfClosingTemplate; + bool m_externalTemplateClose; + bool m_creatingNewMask; + bool m_templatePrevSaved; + bool m_selfSelectingMask; + GamutMaskChooserUI* m_dockerUI; KoResourceItemChooser* m_maskChooser; KoGamutMask* m_selectedMask; QRegExpValidator* m_maskTitleValidator; KisDocument* m_maskDocument; KisView* m_view; }; #endif // H_GAMUT_MASK_DOCK_H diff --git a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp index c9f8cf63bc..878f6577f0 100644 --- a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp +++ b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp @@ -1,421 +1,425 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_bundle_manager.h" #include "ui_wdgdlgbundlemanager.h" #include "resourcemanager.h" #include "dlg_create_bundle.h" #include #include #include #include #include #include #include #include "kis_action.h" #include #include #include #define ICON_SIZE 48 DlgBundleManager::DlgBundleManager(ResourceManager *resourceManager, KisActionManager* actionMgr, QWidget *parent) : KoDialog(parent) , m_page(new QWidget()) , m_ui(new Ui::WdgDlgBundleManager) , m_currentBundle(0) , m_resourceManager(resourceManager) { setCaption(i18n("Manage Resource Bundles")); m_ui->setupUi(m_page); setMainWidget(m_page); resize(m_page->sizeHint()); setButtons(Ok | Cancel); setDefaultButton(Ok); m_ui->listActive->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->listActive->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_ui->listActive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*))); connect(m_ui->listActive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*))); m_ui->listInactive->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->listInactive->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_ui->listInactive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*))); connect(m_ui->listInactive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*))); m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right")); connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected())); m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left")); connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected())); m_ui->listBundleContents->setHeaderLabel(i18n("Resource")); m_ui->listBundleContents->setSelectionMode(QAbstractItemView::NoSelection); m_actionManager = actionMgr; refreshListData(); connect(m_ui->bnEditBundle, SIGNAL(clicked()), SLOT(editBundle())); connect(m_ui->bnImportBrushes, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportGradients, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPalettes, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPatterns, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPresets, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportWorkspaces, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportBundles, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->createBundleButton, SIGNAL(clicked()), SLOT(slotCreateBundle())); connect(m_ui->deleteBackupFilesButton, SIGNAL(clicked()), SLOT(slotDeleteBackupFiles())); connect(m_ui->openResourceFolderButton, SIGNAL(clicked()), SLOT(slotOpenResourceFolder())); } void DlgBundleManager::refreshListData() { KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); m_ui->listInactive->clear(); m_ui->listActive->clear(); Q_FOREACH (const QString &f, bundleServer->blackListedFiles()) { KisResourceBundle *bundle = new KisResourceBundle(f); bundle->load(); if (bundle->valid()) { bundle->setInstalled(false); m_blacklistedBundles[f] = bundle; } } fillListWidget(m_blacklistedBundles.values(), m_ui->listInactive); Q_FOREACH (KisResourceBundle *bundle, bundleServer->resources()) { if (bundle->valid()) { m_activeBundles[bundle->filename()] = bundle; } } fillListWidget(m_activeBundles.values(), m_ui->listActive); } void DlgBundleManager::accept() { KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); for (int i = 0; i < m_ui->listActive->count(); ++i) { QListWidgetItem *item = m_ui->listActive->item(i); QByteArray ba = item->data(Qt::UserRole).toByteArray(); QString name = item->text(); KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); QMessageBox bundleFeedback; bundleFeedback.setIcon(QMessageBox::Warning); QString feedback = "bundlefeedback"; if (!bundle) { // Get it from the blacklisted bundles Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) { if (b2->md5() == ba) { bundle = b2; break; } } } if (bundle) { bool isKrita3Bundle = false; if (bundle->filename().endsWith("Krita_3_Default_Resources.bundle")) { isKrita3Bundle = true; KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); group.writeEntry("HideKrita3Bundle", false); } else { if (!bundle->isInstalled()) { bundle->install(); //this removes the bundle from the blacklist and add it to the server without saving or putting it in front// if (!bundleServer->addResource(bundle, false, false)){ feedback = QString(i18n("Couldn't add bundle \"%1\" to resource server")).arg(name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } if (!isKrita3Bundle) { if (!bundleServer->removeFromBlacklist(bundle)) { feedback = QString(i18n("Couldn't remove bundle \"%1\" from blacklist")).arg(name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } } } else { if (!isKrita3Bundle) { bundleServer->removeFromBlacklist(bundle); } //let's assume that bundles that exist and are installed have to be removed from the blacklist, and if they were already this returns false, so that's not a problem. } } } else{ QString feedback = QString(i18n("Bundle \"%1\" doesn't exist!")).arg(name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } } for (int i = 0; i < m_ui->listInactive->count(); ++i) { QListWidgetItem *item = m_ui->listInactive->item(i); QByteArray ba = item->data(Qt::UserRole).toByteArray(); KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); bool isKrits3Bundle = false; if (bundle) { if (bundle->filename().contains("Krita_3_Default_Resources.bundle")) { isKrits3Bundle = true; KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); group.writeEntry("HideKrita3Bundle", true); } if (bundle->isInstalled()) { bundle->uninstall(); if (!isKrits3Bundle) { bundleServer->removeResourceAndBlacklist(bundle); } } } } KoDialog::accept(); } void DlgBundleManager::addSelected() { Q_FOREACH (QListWidgetItem *item, m_ui->listActive->selectedItems()) { m_ui->listInactive->addItem(m_ui->listActive->takeItem(m_ui->listActive->row(item))); } } void DlgBundleManager::removeSelected() { Q_FOREACH (QListWidgetItem *item, m_ui->listInactive->selectedItems()) { m_ui->listActive->addItem(m_ui->listInactive->takeItem(m_ui->listInactive->row(item))); } } void DlgBundleManager::itemSelected(QListWidgetItem *current, QListWidgetItem *) { if (!current) { m_ui->lblName->clear(); m_ui->lblAuthor->clear(); m_ui->lblEmail->clear(); m_ui->lblLicense->clear(); m_ui->lblWebsite->clear(); m_ui->lblDescription->clear(); m_ui->lblCreated->clear(); m_ui->lblUpdated->clear(); m_ui->lblPreview->setPixmap(QPixmap::fromImage(QImage())); m_ui->listBundleContents->clear(); m_ui->bnEditBundle->setEnabled(false); m_currentBundle = 0; } else { QByteArray ba = current->data(Qt::UserRole).toByteArray(); KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); if (!bundle) { // Get it from the blacklisted bundles Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) { if (b2->md5() == ba) { bundle = b2; break; } } } if (bundle) { QFontMetrics metrics(this->font()); m_currentBundle = bundle; m_ui->bnEditBundle->setEnabled(true); m_ui->lblName->setText(bundle->name()); m_ui->lblAuthor->setText(metrics.elidedText(bundle->getMeta("author"), Qt::ElideRight, m_ui->lblAuthor->width())); m_ui->lblAuthor->setToolTip(bundle->getMeta("author")); m_ui->lblEmail->setText(metrics.elidedText(bundle->getMeta("email"), Qt::ElideRight, m_ui->lblEmail->width())); m_ui->lblEmail->setToolTip(bundle->getMeta("email")); m_ui->lblLicense->setText(metrics.elidedText(bundle->getMeta("license"), Qt::ElideRight, m_ui->lblLicense->width())); m_ui->lblLicense->setToolTip(bundle->getMeta("license")); m_ui->lblWebsite->setText(metrics.elidedText(bundle->getMeta("website"), Qt::ElideRight, m_ui->lblWebsite->width())); m_ui->lblWebsite->setToolTip(bundle->getMeta("website")); m_ui->lblDescription->setPlainText(bundle->getMeta("description")); m_ui->lblCreated->setText(bundle->getMeta("created")); m_ui->lblUpdated->setText(bundle->getMeta("updated")); m_ui->lblPreview->setPixmap(QPixmap::fromImage(bundle->image().scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation))); m_ui->listBundleContents->clear(); Q_FOREACH (const QString & resType, bundle->resourceTypes()) { QTreeWidgetItem *toplevel = new QTreeWidgetItem(); if (resType == "gradients") { toplevel->setText(0, i18n("Gradients")); } else if (resType == "patterns") { toplevel->setText(0, i18n("Patterns")); } else if (resType == "brushes") { toplevel->setText(0, i18n("Brushes")); } else if (resType == "palettes") { toplevel->setText(0, i18n("Palettes")); } else if (resType == "workspaces") { toplevel->setText(0, i18n("Workspaces")); } else if (resType == "paintoppresets") { toplevel->setText(0, i18n("Brush Presets")); } + else if (resType == "gamutmasks") { + toplevel->setText(0, i18n("Gamut Masks")); + } + m_ui->listBundleContents->addTopLevelItem(toplevel); Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { QTreeWidgetItem *i = new QTreeWidgetItem(); i->setIcon(0, QIcon(QPixmap::fromImage(res->image()))); i->setText(0, res->name()); toplevel->addChild(i); } } } } else { m_currentBundle = 0; } } } void DlgBundleManager::itemSelected(QListWidgetItem *current) { itemSelected(current, 0); } void DlgBundleManager::editBundle() { if (m_currentBundle) { DlgCreateBundle dlg(m_currentBundle); m_activeBundles.remove(m_currentBundle->filename()); m_currentBundle = 0; if (dlg.exec() != QDialog::Accepted) { return; } m_currentBundle = m_resourceManager->saveBundle(dlg); refreshListData(); } } void DlgBundleManager::fillListWidget(QList bundles, QListWidget *w) { w->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); w->setSelectionMode(QAbstractItemView::MultiSelection); Q_FOREACH (KisResourceBundle *bundle, bundles) { QPixmap pixmap(ICON_SIZE, ICON_SIZE); pixmap.fill(Qt::gray); if (!bundle->image().isNull()) { QImage scaled = bundle->image().scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); int x = (ICON_SIZE - scaled.width()) / 2; int y = (ICON_SIZE - scaled.height()) / 2; QPainter gc(&pixmap); gc.drawImage(x, y, scaled); gc.end(); } QListWidgetItem *item = new QListWidgetItem(pixmap, bundle->name()); item->setData(Qt::UserRole, bundle->md5()); w->addItem(item); } } void DlgBundleManager::slotImportResource() { if (m_actionManager) { QObject *button = sender(); QString buttonName = button->objectName(); KisAction *action = 0; if (buttonName == "bnImportBundles") { action = m_actionManager->actionByName("import_bundles"); } else if (buttonName == "bnImportBrushes") { action = m_actionManager->actionByName("import_brushes"); } else if (buttonName == "bnImportGradients") { action = m_actionManager->actionByName("import_gradients"); } else if (buttonName == "bnImportPalettes") { action = m_actionManager->actionByName("import_palettes"); } else if (buttonName == "bnImportPatterns") { action = m_actionManager->actionByName("import_patterns"); } else if (buttonName == "bnImportPresets") { action = m_actionManager->actionByName("import_presets"); } else if (buttonName == "bnImportWorkspaces") { action = m_actionManager->actionByName("import_workspaces"); } else { warnUI << "Unhandled bundle manager import button " << buttonName; return; } action->trigger(); refreshListData(); } } void DlgBundleManager::slotCreateBundle() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("create_bundle"); action->trigger(); refreshListData(); } } void DlgBundleManager::slotDeleteBackupFiles() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("edit_blacklist_cleanup"); action->trigger(); } } void DlgBundleManager::slotOpenResourceFolder() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("open_resources_directory"); action->trigger(); } } diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp index 02f7b3d04f..ed051c7f40 100644 --- a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp @@ -1,438 +1,467 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_create_bundle.h" #include "ui_wdgdlgcreatebundle.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceBundle.h" #define ICON_SIZE 48 DlgCreateBundle::DlgCreateBundle(KisResourceBundle *bundle, QWidget *parent) : KoDialog(parent) , m_ui(new Ui::WdgDlgCreateBundle) , m_bundle(bundle) { m_page = new QWidget(); m_ui->setupUi(m_page); setMainWidget(m_page); setFixedSize(m_page->sizeHint()); setButtons(Ok | Cancel); setDefaultButton(Ok); setButtonText(Ok, i18n("Save")); connect(m_ui->bnSelectSaveLocation, SIGNAL(clicked()), SLOT(selectSaveLocation())); KoDocumentInfo info; info.updateParameters(); if (bundle) { setCaption(i18n("Edit Resource Bundle")); m_ui->lblSaveLocation->setText(QFileInfo(bundle->filename()).absolutePath()); m_ui->editBundleName->setText(bundle->name()); m_ui->editAuthor->setText(bundle->getMeta("author")); m_ui->editEmail->setText(bundle->getMeta("email")); m_ui->editLicense->setText(bundle->getMeta("license")); m_ui->editWebsite->setText(bundle->getMeta("website")); m_ui->editDescription->document()->setPlainText(bundle->getMeta("description")); m_ui->lblPreview->setPixmap(QPixmap::fromImage(bundle->image().scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation))); Q_FOREACH (const QString & resType, bundle->resourceTypes()) { if (resType == "gradients") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedGradients << res->shortFilename(); } } } else if (resType == "patterns") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPatterns << res->shortFilename(); } } } else if (resType == "brushes") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedBrushes << res->shortFilename(); } } } else if (resType == "palettes") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPalettes << res->shortFilename(); } } } else if (resType == "workspaces") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedWorkspaces << res->shortFilename(); } } } else if (resType == "paintoppresets") { Q_FOREACH (const KoResource *res, bundle->resources(resType)) { if (res) { m_selectedPresets << res->shortFilename(); } } } + else if (resType == "gamutmasks") { + Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + if (res) { + m_selectedGamutMasks << res->shortFilename(); + } + } + } } } else { setCaption(i18n("Create Resource Bundle")); KisConfig cfg; m_ui->editAuthor->setText(cfg.readEntry("BundleAuthorName", info.authorInfo("creator"))); m_ui->editEmail->setText(cfg.readEntry("BundleAuthorEmail", info.authorInfo("email"))); m_ui->editWebsite->setText(cfg.readEntry("BundleWebsite", "http://")); m_ui->editLicense->setText(cfg.readEntry("BundleLicense", "CC-BY-SA")); m_ui->lblSaveLocation->setText(cfg.readEntry("BundleExportLocation", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))); } m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right")); connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected())); m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left")); connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected())); m_ui->cmbResourceTypes->addItem(i18n("Brushes"), QString("brushes")); m_ui->cmbResourceTypes->addItem(i18n("Brush Presets"), QString("presets")); m_ui->cmbResourceTypes->addItem(i18n("Gradients"), QString("gradients")); + m_ui->cmbResourceTypes->addItem(i18n("Gamut Masks"), QString("gamutmasks")); m_ui->cmbResourceTypes->addItem(i18n("Patterns"), QString("patterns")); m_ui->cmbResourceTypes->addItem(i18n("Palettes"), QString("palettes")); m_ui->cmbResourceTypes->addItem(i18n("Workspaces"), QString("workspaces")); connect(m_ui->cmbResourceTypes, SIGNAL(activated(int)), SLOT(resourceTypeSelected(int))); m_ui->tableAvailable->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection); m_ui->tableSelected->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableSelected->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(m_ui->bnGetPreview, SIGNAL(clicked()), SLOT(getPreviewImage())); resourceTypeSelected(0); } DlgCreateBundle::~DlgCreateBundle() { delete m_ui; } QString DlgCreateBundle::bundleName() const { return m_ui->editBundleName->text().replace(" ", "_"); } QString DlgCreateBundle::authorName() const { return m_ui->editAuthor->text(); } QString DlgCreateBundle::email() const { return m_ui->editEmail->text(); } QString DlgCreateBundle::website() const { return m_ui->editWebsite->text(); } QString DlgCreateBundle::license() const { return m_ui->editLicense->text(); } QString DlgCreateBundle::description() const { return m_ui->editDescription->document()->toPlainText(); } QString DlgCreateBundle::saveLocation() const { return m_ui->lblSaveLocation->text(); } QString DlgCreateBundle::previewImage() const { return m_previewImage; } void DlgCreateBundle::accept() { QString name = m_ui->editBundleName->text().remove(" "); if (name.isEmpty()) { m_ui->editBundleName->setStyleSheet(QString(" border: 1px solid red")); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The resource bundle name cannot be empty.")); return; } else { QFileInfo fileInfo(m_ui->lblSaveLocation->text() + "/" + name + ".bundle"); if (fileInfo.exists() && !m_bundle) { m_ui->editBundleName->setStyleSheet("border: 1px solid red"); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("A bundle with this name already exists.")); return; } else { if (!m_bundle) { KisConfig cfg; cfg.writeEntry("BunleExportLocation", m_ui->lblSaveLocation->text()); cfg.writeEntry("BundleAuthorName", m_ui->editAuthor->text()); cfg.writeEntry("BundleAuthorEmail", m_ui->editEmail->text()); cfg.writeEntry("BundleWebsite", m_ui->editWebsite->text()); cfg.writeEntry("BundleLicense", m_ui->editLicense->text()); } KoDialog::accept(); } } } void DlgCreateBundle::selectSaveLocation() { KoFileDialog dialog(this, KoFileDialog::OpenDirectory, "resourcebundlesavelocation"); dialog.setDefaultDir(m_ui->lblSaveLocation->text()); dialog.setCaption(i18n("Select a directory to save the bundle")); QString location = dialog.filename(); m_ui->lblSaveLocation->setText(location); } void DlgCreateBundle::addSelected() { int row = m_ui->tableAvailable->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableAvailable->selectedItems()) { m_ui->tableSelected->addItem(m_ui->tableAvailable->takeItem(m_ui->tableAvailable->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.append(item->data(Qt::UserRole).toString()); } + else if (resourceType == "gamutmasks") { + m_selectedGamutMasks.append(item->data(Qt::UserRole).toString()); + } } m_ui->tableAvailable->setCurrentRow(row); } void DlgCreateBundle::removeSelected() { int row = m_ui->tableSelected->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableSelected->selectedItems()) { m_ui->tableAvailable->addItem(m_ui->tableSelected->takeItem(m_ui->tableSelected->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.removeAll(item->data(Qt::UserRole).toString()); } + else if (resourceType == "gamutmasks") { + m_selectedGamutMasks.removeAll(item->data(Qt::UserRole).toString()); + } } m_ui->tableSelected->setCurrentRow(row); } QPixmap imageToIcon(const QImage &img) { QPixmap pixmap(ICON_SIZE, ICON_SIZE); pixmap.fill(); QImage scaled = img.scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); int x = (ICON_SIZE - scaled.width()) / 2; int y = (ICON_SIZE - scaled.height()) / 2; QPainter gc(&pixmap); gc.drawImage(x, y, scaled); gc.end(); return pixmap; } void DlgCreateBundle::resourceTypeSelected(int idx) { QString resourceType = m_ui->cmbResourceTypes->itemData(idx).toString(); m_ui->tableAvailable->clear(); m_ui->tableSelected->clear(); if (resourceType == "brushes") { KisBrushResourceServer *server = KisBrushServer::instance()->brushServer(); Q_FOREACH (KisBrushSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedBrushes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "presets") { KisPaintOpPresetResourceServer* server = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (KisPaintOpPresetSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPresets.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "gradients") { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (KoResource *res, server->resources()) { if (res->filename()!="Foreground to Transparent" && res->filename()!="Foreground to Background") { //technically we should read from the file-name whether or not the file can be opened, but this works for now. The problem is making sure that bundle-resource know where they are stored.// //dbgKrita<filename(); QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedGradients.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } } else if (resourceType == "patterns") { KoResourceServer* server = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPatterns.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "palettes") { KoResourceServer* server = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPalettes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "workspaces") { KoResourceServer* server = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (KoResource *res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedWorkspaces.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } + else if (resourceType == "gamutmasks") { + KoResourceServer* server = KoResourceServerProvider::instance()->gamutMaskServer(); + Q_FOREACH (KoResource *res, server->resources()) { + QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); + item->setData(Qt::UserRole, res->shortFilename()); + + if (m_selectedGamutMasks.contains(res->shortFilename())) { + m_ui->tableSelected->addItem(item); + } + else { + m_ui->tableAvailable->addItem(item); + } + } + } + } void DlgCreateBundle::getPreviewImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BundlePreviewImage"); dialog.setCaption(i18n("Select file to use as bundle icon")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); m_previewImage = dialog.filename(); QImage img(m_previewImage); img = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_ui->lblPreview->setPixmap(QPixmap::fromImage(img)); } diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.h b/plugins/extensions/resourcemanager/dlg_create_bundle.h index 8d58b41537..9253ecd74e 100644 --- a/plugins/extensions/resourcemanager/dlg_create_bundle.h +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.h @@ -1,81 +1,83 @@ /* * 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 KOBUNDLECREATIONWIDGET_H #define KOBUNDLECREATIONWIDGET_H #include class KisResourceBundle; namespace Ui { class WdgDlgCreateBundle; } class DlgCreateBundle : public KoDialog { Q_OBJECT public: explicit DlgCreateBundle(KisResourceBundle *bundle = 0, QWidget *parent = 0); ~DlgCreateBundle() override; QString bundleName() const; QString authorName() const; QString email() const; QString website() const; QString license() const; QString description() const; QString saveLocation() const; QString previewImage() const; QStringList selectedBrushes() const { return m_selectedBrushes; } QStringList selectedPresets() const { return m_selectedPresets; } QStringList selectedGradients() const { return m_selectedGradients; } QStringList selectedPatterns() const { return m_selectedPatterns; } QStringList selectedPalettes() const { return m_selectedPalettes; } QStringList selectedWorkspaces() const { return m_selectedWorkspaces; } + QStringList selectedGamutMasks() const { return m_selectedGamutMasks; } private Q_SLOTS: void accept() override; void selectSaveLocation(); void addSelected(); void removeSelected(); void resourceTypeSelected(int idx); void getPreviewImage(); private: QWidget *m_page; Ui::WdgDlgCreateBundle *m_ui; QStringList m_selectedBrushes; QStringList m_selectedPresets; QStringList m_selectedGradients; QStringList m_selectedPatterns; QStringList m_selectedPalettes; QStringList m_selectedWorkspaces; + QStringList m_selectedGamutMasks; QString m_previewImage; KisResourceBundle *m_bundle; }; #endif // KOBUNDLECREATIONWIDGET_H diff --git a/plugins/extensions/resourcemanager/resourcemanager.cpp b/plugins/extensions/resourcemanager/resourcemanager.cpp index 857daedad7..6f45a01420 100644 --- a/plugins/extensions/resourcemanager/resourcemanager.cpp +++ b/plugins/extensions/resourcemanager/resourcemanager.cpp @@ -1,328 +1,335 @@ /* * resourcemanager.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "resourcemanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_bundle_manager.h" #include "dlg_create_bundle.h" #include #include "krita_container_utils.h" class ResourceManager::Private { public: Private() { brushServer = KisBrushServer::instance()->brushServer(); paintopServer = KisResourceServerProvider::instance()->paintOpPresetServer(); gradientServer = KoResourceServerProvider::instance()->gradientServer(); patternServer = KoResourceServerProvider::instance()->patternServer(); paletteServer = KoResourceServerProvider::instance()->paletteServer(); workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); + gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); } KisBrushResourceServer* brushServer; KisPaintOpPresetResourceServer * paintopServer; KoResourceServer* gradientServer; KoResourceServer *patternServer; KoResourceServer* paletteServer; KoResourceServer* workspaceServer; - + KoResourceServer* gamutMaskServer; }; K_PLUGIN_FACTORY_WITH_JSON(ResourceManagerFactory, "kritaresourcemanager.json", registerPlugin();) ResourceManager::ResourceManager(QObject *parent, const QVariantList &) : KisActionPlugin(parent) , d(new Private()) { KisAction *action = new KisAction(i18n("Import Bundles..."), this); addAction("import_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBundles())); action = new KisAction(i18n("Import Brushes..."), this); addAction("import_brushes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBrushes())); action = new KisAction(i18n("Import Gradients..."), this); addAction("import_gradients", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportGradients())); action = new KisAction(i18n("Import Palettes..."), this); addAction("import_palettes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPalettes())); action = new KisAction(i18n("Import Patterns..."), this); addAction("import_patterns", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPatterns())); action = new KisAction(i18n("Import Presets..."), this); addAction("import_presets", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPresets())); action = new KisAction(i18n("Import Workspaces..."), this); addAction("import_workspaces", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportWorkspaces())); action = new KisAction(i18n("Create Resource Bundle..."), this); addAction("create_bundle", action); connect(action, SIGNAL(triggered()), this, SLOT(slotCreateBundle())); action = new KisAction(i18n("Manage Resources..."), this); addAction("manage_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotManageBundles())); } ResourceManager::~ResourceManager() { } void ResourceManager::slotCreateBundle() { DlgCreateBundle dlgCreateBundle; if (dlgCreateBundle.exec() != QDialog::Accepted) { return; } saveBundle(dlgCreateBundle); } KisResourceBundle *ResourceManager::saveBundle(const DlgCreateBundle &dlgCreateBundle) { QString bundlePath = dlgCreateBundle.saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"; KisResourceBundle *newBundle = new KisResourceBundle(bundlePath); newBundle->addMeta("name", dlgCreateBundle.bundleName()); newBundle->addMeta("author", dlgCreateBundle.authorName()); newBundle->addMeta("email", dlgCreateBundle.email()); newBundle->addMeta("license", dlgCreateBundle.license()); newBundle->addMeta("website", dlgCreateBundle.website()); newBundle->addMeta("description", dlgCreateBundle.description()); newBundle->setThumbnail(dlgCreateBundle.previewImage()); QStringList res = dlgCreateBundle.selectedBrushes(); Q_FOREACH (const QString &r, res) { KoResource *res = d->brushServer->resourceByFilename(r).data(); newBundle->addResource("kis_brushes", res->filename(), d->brushServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGradients(); Q_FOREACH (const QString &r, res) { KoResource *res = d->gradientServer->resourceByFilename(r); newBundle->addResource("ko_gradients", res->filename(), d->gradientServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPalettes(); Q_FOREACH (const QString &r, res) { KoResource *res = d->paletteServer->resourceByFilename(r); newBundle->addResource("ko_palettes", res->filename(), d->paletteServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPatterns(); Q_FOREACH (const QString &r, res) { KoResource *res = d->patternServer->resourceByFilename(r); newBundle->addResource("ko_patterns", res->filename(), d->patternServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPresets(); Q_FOREACH (const QString &r, res) { KisPaintOpPresetSP preset = d->paintopServer->resourceByFilename(r); KoResource *res = preset.data(); newBundle->addResource("kis_paintoppresets", res->filename(), d->paintopServer->assignedTagsList(res), res->md5()); KisPaintOpSettingsSP settings = preset->settings(); QStringList requiredFiles = settings->getStringList(KisPaintOpUtils::RequiredBrushFilesListTag); requiredFiles << settings->getString(KisPaintOpUtils::RequiredBrushFileTag); KritaUtils::makeContainerUnique(requiredFiles); Q_FOREACH (const QString &brushFile, requiredFiles) { KisBrush *brush = d->brushServer->resourceByFilename(brushFile).data(); if (brush) { newBundle->addResource("kis_brushes", brushFile, d->brushServer->assignedTagsList(brush), brush->md5()); } else { qWarning() << "There is no brush with name" << brushFile; } } } res = dlgCreateBundle.selectedWorkspaces(); Q_FOREACH (const QString &r, res) { KoResource *res = d->workspaceServer->resourceByFilename(r); newBundle->addResource("kis_workspaces", res->filename(), d->workspaceServer->assignedTagsList(res), res->md5()); } + res = dlgCreateBundle.selectedGamutMasks(); + Q_FOREACH (const QString &r, res) { + KoResource *res = d->gamutMaskServer->resourceByFilename(r); + newBundle->addResource("ko_gamutmasks", res->filename(), d->gamutMaskServer->assignedTagsList(res), res->md5()); + } + newBundle->addMeta("fileName", bundlePath); newBundle->addMeta("created", QDate::currentDate().toString("dd/MM/yyyy")); if (!newBundle->save()) { QMessageBox::critical(viewManager()->mainWindow(), i18nc("@title:window", "Krita"), i18n("Could not create the new bundle.")); } else { newBundle->setValid(true); if (QDir(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation()) != QDir(QFileInfo(bundlePath).path())) { newBundle->setFilename(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"); } if (KisResourceBundleServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())) { KisResourceBundleServerProvider::instance()->resourceBundleServer()->removeResourceFromServer( KisResourceBundleServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())); } KisResourceBundleServerProvider::instance()->resourceBundleServer()->addResource(newBundle, true); newBundle->load(); } return newBundle; } void ResourceManager::slotManageBundles() { DlgBundleManager* dlg = new DlgBundleManager(this, viewManager()->actionManager()); if (dlg->exec() != QDialog::Accepted) { return; } } QStringList ResourceManager::importResources(const QString &title, const QStringList &mimes) const { KoFileDialog dialog(viewManager()->mainWindow(), KoFileDialog::OpenFiles, "krita_resources"); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setCaption(title); dialog.setMimeTypeFilters(mimes); return dialog.filenames(); } void ResourceManager::slotImportBrushes() { QStringList resources = importResources(i18n("Import Brushes"), QStringList() << "image/x-gimp-brush" << "image/x-gimp-x-gimp-brush-animated" << "image/x-adobe-brushlibrary" << "image/png" << "image/svg+xml"); Q_FOREACH (const QString &res, resources) { d->brushServer->importResourceFile(res); } } void ResourceManager::slotImportPresets() { QStringList resources = importResources(i18n("Import Presets"), QStringList() << "application/x-krita-paintoppreset"); Q_FOREACH (const QString &res, resources) { d->paintopServer->importResourceFile(res); } } void ResourceManager::slotImportGradients() { QStringList resources = importResources(i18n("Import Gradients"), QStringList() << "image/svg+xml" << "application/x-gimp-gradient" << "applicaition/x-karbon-gradient"); Q_FOREACH (const QString &res, resources) { d->gradientServer->importResourceFile(res); } } void ResourceManager::slotImportBundles() { QStringList resources = importResources(i18n("Import Bundles"), QStringList() << "application/x-krita-bundle"); Q_FOREACH (const QString &res, resources) { KisResourceBundle *bundle = KisResourceBundleServerProvider::instance()->resourceBundleServer()->createResource(res); bundle->load(); if (bundle->valid()) { if (!bundle->install()) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not install the resources for bundle %1.").arg(res)); } } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not load bundle %1.").arg(res)); } QFileInfo fi(res); QString newFilename = KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + bundle->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + QString("%1").arg(i) + bundle->defaultFileExtension()); i++; } bundle->setFilename(fileInfo.filePath()); QFile::copy(res, newFilename); KisResourceBundleServerProvider::instance()->resourceBundleServer()->addResource(bundle, false); } } void ResourceManager::slotImportPatterns() { QStringList resources = importResources(i18n("Import Patterns"), QStringList() << "image/png" << "image/svg+xml" << "application/x-gimp-pattern" << "image/jpeg" << "image/tiff" << "image/bmp" << "image/xpg"); Q_FOREACH (const QString &res, resources) { d->patternServer->importResourceFile(res); } } void ResourceManager::slotImportPalettes() { QStringList resources = importResources(i18n("Import Palettes"), QStringList() << "image/x-gimp-color-palette"); Q_FOREACH (const QString &res, resources) { d->paletteServer->importResourceFile(res); } } void ResourceManager::slotImportWorkspaces() { QStringList resources = importResources(i18n("Import Workspaces"), QStringList() << "application/x-krita-workspace"); Q_FOREACH (const QString &res, resources) { d->workspaceServer->importResourceFile(res); } } #include "resourcemanager.moc"