diff --git a/krita/krita.action b/krita/krita.action
index 04e324e657..1a7c9d04b4 100644
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -1,3706 +1,3585 @@
General
Open Resources Folder
Opens a file browser at the location Krita saves resources such as brushes to.
Opens a file browser at the location Krita saves resources such as brushes to.
Open Resources Folder
0
0
false
C&ascade
Cascade
Cascade
10
0
false
&Tile
Tile
Tile
10
0
false
Create Resource Bundle...
Create Resource Bundle
Create Resource Bundle
0
0
false
Show File Toolbar
Show File Toolbar
Show File Toolbar
false
Show color selector
Show color selector
Show color selector
Shift+I
false
Show MyPaint shade selector
Show MyPaint shade selector
Show MyPaint shade selector
Shift+M
false
Show minimal shade selector
Show minimal shade selector
Show minimal shade selector
Shift+N
false
Show color history
Show color history
Show color history
H
false
Show common colors
Show common colors
Show common colors
U
false
Show Tool Options
Show Tool Options
Show Tool Options
\
false
Show Brush Editor
Show Brush Editor
Show Brush Editor
F5
false
Show Brush Presets
Show Brush Presets
Show Brush Presets
F6
false
Toggle Tablet Debugger
Toggle Tablet Debugger
Toggle Tablet Debugger
0
0
Ctrl+Shift+T
false
Show Krita log for bug reports.
Show Krita log for bug reports.
Show Krita log for bug reports.
false
Show system information for bug reports.
Show system information for bug reports.
Show system information for bug reports.
false
Rename Composition...
Rename Composition
Rename Composition
0
0
false
Update Composition
Update Composition
Update Composition
0
0
false
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
Use multiple of 2 for pixel scale
1
0
true
&Invert Selection
Invert current selection
Invert Selection
10000000000
100
Ctrl+Shift+I
false
Create Snapshot
Create Snapshot
1
0
false
Switch to Selected Snapshot
Switch to selected snapshot
1
0
false
Remove Selected Snapshot
Remove Selected Snapshot
1
0
false
Painting
lightness-increase
Make brush color lighter
Make brush color lighter
Make brush color lighter
0
0
L
false
lightness-decrease
Make brush color darker
Make brush color darker
Make brush color darker
0
0
K
false
Make brush color more saturated
Make brush color more saturated
Make brush color more saturated
false
Make brush color more desaturated
Make brush color more desaturated
Make brush color more desaturated
false
Shift brush color hue clockwise
Shift brush color hue clockwise
Shift brush color hue clockwise
false
Shift brush color hue counter-clockwise
Shift brush color hue counter-clockwise
Shift brush color hue counter-clockwise
false
Make brush color more red
Make brush color more red
Make brush color more red
false
Make brush color more green
Make brush color more green
Make brush color more green
false
Make brush color more blue
Make brush color more blue
Make brush color more blue
false
Make brush color more yellow
Make brush color more yellow
Make brush color more yellow
false
opacity-increase
Increase opacity
Increase opacity
Increase opacity
0
0
O
false
opacity-decrease
Decrease opacity
Decrease opacity
Decrease opacity
0
0
I
false
draw-eraser
Set eraser mode
Set eraser mode
Set eraser mode
10000
0
E
true
view-refresh
Reload Original Preset
Reload Original Preset
Reload Original Preset
10000
false
transparency-unlocked
Preserve Alpha
Preserve Alpha
Preserve Alpha
10000
true
transform_icons_penPressure
Use Pen Pressure
Use Pen Pressure
Use Pen Pressure
10000
true
symmetry-horizontal
Horizontal Mirror Tool
Horizontal Mirror Tool
Horizontal Mirror Tool
0
true
symmetry-vertical
Vertical Mirror Tool
Vertical Mirror Tool
Vertical Mirror Tool
0
true
Hide Mirror X Line
Hide Mirror X Line
Hide Mirror X Line
10000
true
Hide Mirror Y Line
Hide Mirror Y Line
Hide Mirror Y Line
10000
true
Lock
Lock X Line
Lock X Line
10000
true
Lock Y Line
Lock Y Line
Lock Y Line
10000
true
Move to Canvas Center X
Move to Canvas Center X
Move to Canvas Center X
10000
false
Move to Canvas Center Y
Move to Canvas Center Y
Move to Canvas Center Y
10000
false
&Toggle Selection Display Mode
Toggle Selection Display Mode
Toggle Selection Display Mode
0
0
false
Next Favourite Preset
Next Favourite Preset
Next Favourite Preset
,
false
Previous Favourite Preset
Previous Favourite Preset
Previous Favourite Preset
.
false
preset-switcher
Switch to Previous Preset
Switch to Previous Preset
Switch to Previous Preset
/
false
Hide Brushes and Stuff Toolbar
Hide Brushes and Stuff Toolbar
Hide Brushes and Stuff Toolbar
true
Reset Foreground and Background Color
Reset Foreground and Background Color
Reset Foreground and Background Color
D
false
Swap Foreground and Background Color
Swap Foreground and Background Color
Swap Foreground and Background Color
X
false
Selection Mode: Add
Selection Mode: Add
Selection Mode: Add
A
false
Selection Mode: Subtract
Selection Mode: Subtract
Selection Mode: Subtract
S
false
Selection Mode: Intersect
Selection Mode: Intersect
Selection Mode: Intersect
false
Selection Mode: Replace
Selection Mode: Replace
Selection Mode: Replace
R
false
smoothing-weighted
Brush Smoothing: Weighted
Brush Smoothing: Weighted
Brush Smoothing: Weighted
false
smoothing-no
Brush Smoothing: Disabled
Brush Smoothing: Disabled
Brush Smoothing: Disabled
false
smoothing-stabilizer
Brush Smoothing: Stabilizer
Brush Smoothing: Stabilizer
Brush Smoothing: Stabilizer
false
brushsize-decrease
Decrease Brush Size
Decrease Brush Size
Decrease Brush Size
0
0
[
false
smoothing-basic
Brush Smoothing: Basic
Brush Smoothing: Basic
Brush Smoothing: Basic
false
brushsize-increase
Increase Brush Size
Increase Brush Size
Increase Brush Size
0
0
]
false
Toggle Snap To Assistants
Toggle Snap to Assistants
ToggleAssistant
Ctrl+Shift+L
true
Undo Polygon Selection Points
Undo Polygon Selection Points
Undo Polygon Selection Points
Shift+Z
false
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
10000
1
Ctrl+Shift+Backspace
false
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
10000
1
Ctrl+Backspace
false
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
10000
1
false
Convert &to Shape
Convert to Shape
Convert to Shape
10000000000
0
false
&Show Global Selection Mask
Shows global selection as a usual selection mask in <interface>Layers</interface> docker
Show Global Selection Mask
100000
100
true
Filters
color-to-alpha
&Color to Alpha...
Color to Alpha
Color to Alpha
10000
0
false
&Top Edge Detection
Top Edge Detection
Top Edge Detection
10000
0
false
&Index Colors...
Index Colors
Index Colors
10000
0
false
Emboss Horizontal &Only
Emboss Horizontal Only
Emboss Horizontal Only
10000
0
false
D&odge
Dodge
Dodge
10000
0
false
&Sharpen
Sharpen
Sharpen
10000
0
false
B&urn
Burn
Burn
10000
0
false
&Mean Removal
Mean Removal
Mean Removal
10000
0
false
&Gaussian Blur...
Gaussian Blur
Gaussian Blur
10000
0
false
Emboss &in All Directions
Emboss in All Directions
Emboss in All Directions
10000
0
false
&Small Tiles...
Small Tiles
Small Tiles
10000
0
false
&Levels...
Levels
Levels
10000
0
Ctrl+L
false
&Sobel...
Sobel
Sobel
10000
0
false
&Wave...
Wave
Wave
10000
0
false
&Motion Blur...
Motion Blur
Motion Blur
10000
0
false
&Invert
Invert
Invert
10000
0
Ctrl+I
false
&Color Adjustment curves...
Color Adjustment curves
Color Adjustment curves
10000
0
Ctrl+M
false
Pi&xelize...
Pixelize
Pixelize
10000
0
false
Emboss (&Laplacian)
Emboss (Laplacian)
Emboss (Laplacian)
10000
0
false
&Left Edge Detection
Left Edge Detection
Left Edge Detection
10000
0
false
&Blur...
Blur
Blur
10000
0
false
&Raindrops...
Raindrops
Raindrops
10000
0
false
&Bottom Edge Detection
Bottom Edge Detection
Bottom Edge Detection
10000
0
false
&Random Noise...
Random Noise
Random Noise
10000
0
false
&Brightness/Contrast curve...
Brightness/Contrast curve
Brightness/Contrast curve
10000
0
false
Colo&r Balance...
Color Balance
Color Balance
10000
0
Ctrl+B
false
&Phong Bumpmap...
Phong Bumpmap
Phong Bumpmap
10000
0
false
&Desaturate
Desaturate
Desaturate
10000
0
Ctrl+Shift+U
false
Color &Transfer...
Color Transfer
Color Transfer
10000
0
false
Emboss &Vertical Only
Emboss Vertical Only
Emboss Vertical Only
10000
0
false
&Lens Blur...
Lens Blur
Lens Blur
10000
0
false
M&inimize Channel
Minimize Channel
Minimize Channel
10000
0
false
M&aximize Channel
Maximize Channel
Maximize Channel
10000
0
false
&Oilpaint...
Oilpaint
Oilpaint
10000
0
false
&Right Edge Detection
Right Edge Detection
Right Edge Detection
10000
0
false
&Auto Contrast
Auto Contrast
Auto Contrast
10000
0
false
&Round Corners...
Round Corners
Round Corners
10000
0
false
&Unsharp Mask...
Unsharp Mask
Unsharp Mask
10000
0
false
&Emboss with Variable Depth...
Emboss with Variable Depth
Emboss with Variable Depth
10000
0
false
Emboss &Horizontal && Vertical
Emboss Horizontal & Vertical
Emboss Horizontal & Vertical
10000
0
false
Random &Pick...
Random Pick
Random Pick
10000
0
false
&Gaussian Noise Reduction...
Gaussian Noise Reduction
Gaussian Noise Reduction
10000
0
false
&Posterize...
Posterize
Posterize
10000
0
false
&Wavelet Noise Reducer...
Wavelet Noise Reducer
Wavelet Noise Reducer
10000
0
false
&HSV Adjustment...
HSV Adjustment
HSV Adjustment
10000
0
Ctrl+U
false
-
Tool Shortcuts
Dynamic Brush Tool
Dynamic Brush Tool
Dynamic Brush Tool
false
-
-
- Crop Tool
-
- Crop the image to an area
- Crop the image to an area
- C
- false
-
-
-
-
- Polygon Tool
-
- Polygon Tool. Shift-mouseclick ends the polygon.
- Polygon Tool. Shift-mouseclick ends the polygon.
-
- false
-
-
Rectangle Tool
Rectangle Tool
Rectangle Tool
false
Multibrush Tool
Multibrush Tool
Multibrush Tool
Q
false
Colorize Mask Tool
Colorize Mask Tool
Colorize Mask Tool
Smart Patch Tool
Smart Patch Tool
Smart Patch Tool
Pan Tool
Pan Tool
Pan Tool
Select Shapes Tool
Select Shapes Tool
Select Shapes Tool
false
Color Picker
Select a color from the image or current layer
Select a color from the image or current layer
P
false
Outline Selection Tool
Outline Selection Tool
Outline Selection Tool
false
-
-
- Bezier Curve Selection Tool
-
- Bezier Curve Selection Tool
- Bezier Curve Selection Tool
-
- false
-
-
-
-
- Similar Color Selection Tool
-
- Similar Color Selection Tool
- Similar Color Selection Tool
-
- false
-
-
Fill Tool
Fill a contiguous area of color with a color, or fill a selection.
Fill a contiguous area of color with a color, or fill a selection.
F
false
Line Tool
Line Tool
Line Tool
false
-
-
- Freehand Path Tool
-
- Freehand Path Tool
- Freehand Path Tool
-
- false
-
-
-
-
- Bezier Curve Tool
-
- Bezier Curve Tool. Shift-mouseclick or double-click ends the curve.
- Bezier Curve Tool. Shift-mouseclick or double-click ends the curve.
-
- false
-
-
Ellipse Tool
Ellipse Tool
Ellipse Tool
false
Freehand Brush Tool
Freehand Brush Tool
Freehand Brush Tool
B
false
Create object
Create object
Create object
false
-
-
- Elliptical Selection Tool
-
- Elliptical Selection Tool
- Elliptical Selection Tool
- J
- false
-
-
-
-
- Contiguous Selection Tool
-
- Contiguous Selection Tool
- Contiguous Selection Tool
-
- false
-
-
Pattern editing
Pattern editing
Pattern editing
false
Review
Review
Review
false
Draw a gradient.
Draw a gradient.
Draw a gradient.
G
false
-
-
- Polygonal Selection Tool
-
- Polygonal Selection Tool
- Polygonal Selection Tool
-
- false
-
-
Measurement Tool
Measure the distance between two points
Measure the distance between two points
false
-
-
- Rectangular Selection Tool
-
- Rectangular Selection Tool
- Rectangular Selection Tool
- Ctrl+R
- false
-
-
Move Tool
Move a layer
Move a layer
T
false
Vector Image Tool
Vector Image (EMF/WMF/SVM/SVG) tool
Vector Image (EMF/WMF/SVM/SVG) tool
false
Calligraphy
Calligraphy
Calligraphy
false
Edit Shapes Tool
Edit Shapes Tool
Edit Shapes Tool
false
Zoom Tool
Zoom Tool
Zoom Tool
false
-
-
- Polyline Tool
-
- Polyline Tool. Shift-mouseclick ends the polyline.
- Polyline Tool. Shift-mouseclick ends the polyline.
-
- false
-
-
-
-
- Transform Tool
-
- Transform a layer or a selection
- Transform a layer or a selection
- Ctrl+T
- false
-
-
Assistant Tool
Assistant Tool
Assistant Tool
false
Gradient Editing Tool
Gradient editing
Gradient editing
false
Reference Images Tool
Reference Images Tool
Reference Images Tool
false
Blending Modes
Select Normal Blending Mode
Select Normal Blending Mode
Select Normal Blending Mode
0
0
Alt+Shift+N
false
Select Dissolve Blending Mode
Select Dissolve Blending Mode
Select Dissolve Blending Mode
0
0
Alt+Shift+I
false
Select Behind Blending Mode
Select Behind Blending Mode
Select Behind Blending Mode
0
0
Alt+Shift+Q
false
Select Clear Blending Mode
Select Clear Blending Mode
Select Clear Blending Mode
0
0
Alt+Shift+R
false
Select Darken Blending Mode
Select Darken Blending Mode
Select Darken Blending Mode
0
0
Alt+Shift+K
false
Select Multiply Blending Mode
Select Multiply Blending Mode
Select Multiply Blending Mode
0
0
Alt+Shift+M
false
Select Color Burn Blending Mode
Select Color Burn Blending Mode
Select Color Burn Blending Mode
0
0
Alt+Shift+B
false
Select Linear Burn Blending Mode
Select Linear Burn Blending Mode
Select Linear Burn Blending Mode
0
0
Alt+Shift+A
false
Select Lighten Blending Mode
Select Lighten Blending Mode
Select Lighten Blending Mode
0
0
Alt+Shift+G
false
Select Screen Blending Mode
Select Screen Blending Mode
Select Screen Blending Mode
0
0
Alt+Shift+S
false
Select Color Dodge Blending Mode
Select Color Dodge Blending Mode
Select Color Dodge Blending Mode
0
0
Alt+Shift+D
false
Select Linear Dodge Blending Mode
Select Linear Dodge Blending Mode
Select Linear Dodge Blending Mode
0
0
Alt+Shift+W
false
Select Overlay Blending Mode
Select Overlay Blending Mode
Select Overlay Blending Mode
0
0
Alt+Shift+O
false
Select Hard Overlay Blending Mode
Select Hard Overlay Blending Mode
Select Hard Overlay Blending Mode
0
0
Alt+Shift+P
false
Select Soft Light Blending Mode
Select Soft Light Blending Mode
Select Soft Light Blending Mode
0
0
Alt+Shift+F
false
Select Hard Light Blending Mode
Select Hard Light Blending Mode
Select Hard Light Blending Mode
0
0
Alt+Shift+H
false
Select Vivid Light Blending Mode
Select Vivid Light Blending Mode
Select Vivid Light Blending Mode
0
0
Alt+Shift+V
false
Select Linear Light Blending Mode
Select Linear Light Blending Mode
Select Linear Light Blending Mode
0
0
Alt+Shift+J
false
Select Pin Light Blending Mode
Select Pin Light Blending Mode
Select Pin Light Blending Mode
0
0
Alt+Shift+Z
false
Select Hard Mix Blending Mode
Select Hard Mix Blending Mode
Select Hard Mix Blending Mode
0
0
Alt+Shift+L
false
Select Difference Blending Mode
Select Difference Blending Mode
Select Difference Blending Mode
0
0
Alt+Shift+E
false
Select Exclusion Blending Mode
Select Exclusion Blending Mode
Select Exclusion Blending Mode
0
0
Alt+Shift+X
false
Select Hue Blending Mode
Select Hue Blending Mode
Select Hue Blending Mode
0
0
Alt+Shift+U
false
Select Saturation Blending Mode
Select Saturation Blending Mode
Select Saturation Blending Mode
0
0
Alt+Shift+T
false
Select Color Blending Mode
Select Color Blending Mode
Select Color Blending Mode
0
0
Alt+Shift+C
false
Select Luminosity Blending Mode
Select Luminosity Blending Mode
Select Luminosity Blending Mode
0
0
Alt+Shift+Y
false
Animation
Previous frame
Move to previous frame
Move to previous frame
1
0
false
Next frame
Move to next frame
Move to next frame
1
0
false
Play / pause animation
Play / pause animation
Play / pause animation
1
0
false
addblankframe
Create Blank Frame
Add blank frame
Add blank frame
100000
0
false
addduplicateframe
Create Duplicate Frame
Add duplicate frame
Add duplicate frame
100000
0
false
Toggle onion skin
Toggle onion skin
Toggle onion skin
100000
0
false
Previous Keyframe
false
Next Keyframe
false
First Frame
false
Last Frame
false
Auto Frame Mode
true
true
Pin to Timeline
If checked, layer becomes pinned to the timeline, making it visible even when inactive.
true
Insert Keyframe Left
Insert keyframes to the left of selection, moving the tail of animation to the right.
100000
0
false
Insert Keyframe Right
Insert keyframes to the right of selection, moving the tail of animation to the right.
100000
0
false
Insert Multiple Keyframes
Insert several keyframes based on user parameters.
100000
0
false
Remove Frame and Pull
Remove keyframes moving the tail of animation to the left
100000
0
false
deletekeyframe
Remove Keyframe
Remove keyframes without moving anything around
100000
0
false
Insert Column Left
Insert column to the left of selection, moving the tail of animation to the right
100000
0
false
Insert Column Right
Insert column to the right of selection, moving the tail of animation to the right
100000
0
false
Insert Multiple Columns
Insert several columns based on user parameters.
100000
0
false
Remove Column and Pull
Remove columns moving the tail of animation to the left
100000
0
false
Remove Column
Remove columns without moving anything around
100000
0
false
Insert Hold Frame
Insert a hold frame after every keyframe
100000
0
false
Insert Multiple Hold Frames
Insert N hold frames after every keyframe
100000
0
false
Remove Hold Frame
Remove a hold frame after every keyframe
100000
0
false
Remove Multiple Hold Frames
Remove N hold frames after every keyframe
100000
0
false
Insert Hold Column
Insert a hold column into the frame at the current position
100000
0
false
Insert Multiple Hold Columns
Insert N hold columns into the frame at the current position
100000
0
false
Remove Hold Column
Remove a hold column from the frame at the current position
100000
0
false
Remove Multiple Hold Columns
Remove N hold columns from the frame at the current position
100000
0
false
Add opacity keyframe
Adds keyframe to control layer opacity
100000
0
false
Remove opacity keyframe
Removes keyframe to control layer opacity
100000
0
false
Mirror Frames
Mirror frames' position
100000
0
false
Mirror Columns
Mirror columns' position
100000
0
false
Copy to Clipboard
Copy frames to clipboard
100000
0
false
Cut to Clipboard
Cut frames to clipboard
100000
0
false
Paste from Clipboard
Paste frames from clipboard
100000
0
false
Copy Columns to Clipboard
Copy columns to clipboard
100000
0
false
Cut Columns to Clipboard
Cut columns to clipboard
100000
0
false
Paste Columns from Clipboard
Paste columns from clipboard
100000
0
false
Set Start Time
100000
0
false
Set End Time
100000
0
false
Update Playback Range
100000
0
false
Layers
Activate next layer
Activate next layer
Activate next layer
1000
0
PgUp
false
Activate next sibling layer, skipping over groups.
Activate next sibling layer
Activate next sibling layer
1000
0
false
Activate previous layer
Activate previous layer
Activate previous layer
1000
0
PgDown
false
Activate previous sibling layer, skipping over groups.
Activate previous sibling layer
Activate previous sibling layer
1000
0
false
Activate previously selected layer
Activate previously selected layer
Activate previously selected layer
1000
0
;
false
groupLayer
&Group Layer
Group Layer
Group Layer
1000
0
false
cloneLayer
&Clone Layer
Clone Layer
Clone Layer
1000
0
false
vectorLayer
&Vector Layer
Vector Layer
Vector Layer
1000
0
false
filterLayer
&Filter Layer...
Filter Layer
Filter Layer
1000
0
false
fillLayer
&Fill Layer...
Fill Layer
Fill Layer
1000
0
false
fileLayer
&File Layer...
File Layer
File Layer
1000
0
false
transparencyMask
&Transparency Mask
Transparency Mask
Transparency Mask
100000
0
false
filterMask
&Filter Mask...
Filter Mask
Filter Mask
100000
0
false
filterMask
&Colorize Mask
Colorize Mask
Colorize Mask
100000
0
false
transformMask
&Transform Mask...
Transform Mask
Transform Mask
100000
0
false
selectionMask
&Local Selection
Local Selection
Local Selection
100000
0
false
view-filter
&Isolate Active Layer
Isolate Active Layer
Isolate Active Layer
1000
0
true
layer-locked
&Toggle layer lock
Toggle layer lock
Toggle layer lock
1000
0
false
visible
Toggle layer &visibility
Toggle layer visibility
Toggle layer visibility
1000
0
false
transparency-locked
Toggle layer &alpha
Toggle layer alpha
Toggle layer alpha
1000
0
false
transparency-enabled
Toggle layer alpha &inheritance
Toggle layer alpha inheritance
Toggle layer alpha inheritance
1000
0
false
paintLayer
&Paint Layer
Paint Layer
Paint Layer
1000
0
Insert
false
&New Layer From Visible
New layer from visible
New layer from visible
1000
0
false
duplicatelayer
&Duplicate Layer or Mask
Duplicate Layer or Mask
Duplicate Layer or Mask
1000
0
Ctrl+J
false
&Cut Selection to New Layer
Cut Selection to New Layer
Cut Selection to New Layer
100000000
1
Ctrl+Shift+J
false
Copy &Selection to New Layer
Copy Selection to New Layer
Copy Selection to New Layer
100000000
0
Ctrl+Alt+J
false
Copy Layer
Copy layer to clipboard
Copy layer to clipboard
1000
0
false
Cut Layer
Cut layer to clipboard
Cut layer to clipboard
1000
0
false
Paste Layer
Paste layer from clipboard
Paste layer from clipboard
1000
0
false
Quick Group
Create a group layer containing selected layers
Quick Group
1000
0
Ctrl+G
false
Quick Ungroup
Remove grouping of the layers or remove one layer out of the group
Quick Ungroup
100000
0
Ctrl+Alt+G
false
Quick Clipping Group
Group selected layers and add a layer with clipped alpha channel
Quick Clipping Group
100000
0
Ctrl+Shift+G
false
All Layers
Select all layers
Select all layers
10000
0
false
Visible Layers
Select all visible layers
Select all visible layers
10000
0
false
Locked Layers
Select all locked layers
Select all locked layers
10000
0
false
Invisible Layers
Select all invisible layers
Select all invisible layers
10000
0
false
Unlocked Layers
Select all unlocked layers
Select all unlocked layers
10000
0
false
document-save
&Save Layer/Mask...
Save Layer/Mask
Save Layer/Mask
1000
0
false
document-save
Save Vector Layer as SVG...
Save Vector Layer as SVG
Save Vector Layer as SVG
1000
0
false
document-save
Save &Group Layers...
Save Group Layers
Save Group Layers
100000
0
false
Convert group to &animated layer
Convert child layers into animation frames
Convert child layers into animation frames
100000
0
false
Convert to &animated layer
Convert layer into animation frames
Convert layer into animation frames
100000
0
false
fileLayer
to &File Layer
Saves out the layers into a new image and then references that image.
Convert to File Layer
100000
0
false
I&mport Layer...
Import Layer
Import Layer
100000
0
false
paintLayer
&as Paint Layer...
as Paint Layer
as Paint Layer
1000
0
false
transparencyMask
as &Transparency Mask...
as Transparency Mask
as Transparency Mask
1000
0
false
filterMask
as &Filter Mask...
as Filter Mask
as Filter Mask
1000
0
false
selectionMask
as &Selection Mask...
as Selection Mask
as Selection Mask
1000
0
false
paintLayer
to &Paint Layer
to Paint Layer
to Paint Layer
1000
0
false
transparencyMask
to &Transparency Mask
to Transparency Mask
to Transparency Mask
1000
0
false
filterMask
to &Filter Mask...
to Filter Mask
to Filter Mask
1000
0
false
selectionMask
to &Selection Mask
to Selection Mask
to Selection Mask
1000
0
false
transparencyMask
&Alpha into Mask
Alpha into Mask
Alpha into Mask
100000
10
false
transparency-enabled
&Write as Alpha
Write as Alpha
Write as Alpha
1000000
1
false
document-save
&Save Merged...
Save Merged
Save Merged
1000000
0
false
split-layer
Split Layer...
Split Layer
Split Layer
1000
0
false
Wavelet Decompose ...
Wavelet Decompose
Wavelet Decompose
1000
1
false
symmetry-horizontal
Mirror Layer Hori&zontally
Mirror Layer Horizontally
Mirror Layer Horizontally
1000
1
false
symmetry-vertical
Mirror Layer &Vertically
Mirror Layer Vertically
Mirror Layer Vertically
1000
1
false
&Rotate Layer...
Rotate Layer
Rotate Layer
1000
1
false
object-rotate-right
Rotate &Layer 90° to the Right
Rotate Layer 90° to the Right
Rotate Layer 90° to the Right
1000
1
false
object-rotate-left
Rotate Layer &90° to the Left
Rotate Layer 90° to the Left
Rotate Layer 90° to the Left
1000
1
false
Rotate Layer &180°
Rotate Layer 180°
Rotate Layer 180°
1000
1
false
Scale &Layer to new Size...
Scale Layer to new Size
Scale Layer to new Size
100000
1
false
&Shear Layer...
Shear Layer
Shear Layer
1000
1
false
symmetry-horizontal
Mirror All Layers Hori&zontally
Mirror All Layers Horizontally
Mirror All Layers Horizontally
1000
1
false
symmetry-vertical
Mirror All Layers &Vertically
Mirror All Layers Vertically
Mirror All Layers Vertically
1000
1
false
&Rotate All Layers...
Rotate All Layers
Rotate All Layers
1000
1
false
object-rotate-right
Rotate All &Layers 90° to the Right
Rotate All Layers 90° to the Right
Rotate All Layers 90° to the Right
1000
1
false
object-rotate-left
Rotate All Layers &90° to the Left
Rotate All Layers 90° to the Left
Rotate All Layers 90° to the Left
1000
1
false
Rotate All Layers &180°
Rotate All Layers 180°
Rotate All Layers 180°
1000
1
false
Scale All &Layers to new Size...
Scale All Layers to new Size
Scale All Layers to new Size
100000
1
false
&Shear All Layers...
Shear All Layers
Shear All Layers
1000
1
false
&Offset Layer...
Offset Layer
Offset Layer
100000
1
false
Clones &Array...
Clones Array
Clones Array
100000
0
false
&Edit metadata...
Edit metadata
Edit metadata
100000
1
false
&Histogram...
Histogram
Histogram
100000
0
false
&Convert Layer Color Space...
Convert Layer Color Space
Convert Layer Color Space
100000
1
false
merge-layer-below
&Merge with Layer Below
Merge with Layer Below
Merge with Layer Below
100000
0
Ctrl+E
false
&Flatten Layer
Flatten Layer
Flatten Layer
100000
0
false
Ras&terize Layer
Rasterize Layer
Rasterize Layer
10000000
1
false
Flatten ima&ge
Flatten image
Flatten image
100000
0
Ctrl+Shift+E
false
La&yer Style...
Layer Style
Layer Style
100000
1
false
Move into previous group
Move into previous group
Move into previous group
0
0
false
Move into next group
Move into next group
Move into next group
0
0
false
Rename current layer
Rename current layer
Rename current layer
100000
0
F2
false
deletelayer
&Remove Layer
Remove Layer
Remove Layer
1000
1
Shift+Delete
false
arrowupblr
Move Layer or Mask Up
Move Layer or Mask Up
Ctrl+PgUp
false
arrowdown
Move Layer or Mask Down
Move Layer or Mask Down
Ctrl+PgDown
false
properties
&Properties...
Properties
Properties
1000
1
F3
false
Set Copy F&rom...
Set the source for the selected clone layer(s).
Set Copy From
1000
1
false
diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp
index 7689a6b282..6d3dd42cdd 100644
--- a/libs/ui/kis_canvas_resource_provider.cpp
+++ b/libs/ui/kis_canvas_resource_provider.cpp
@@ -1,567 +1,561 @@
/*
* Copyright (c) 2006 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_canvas_resource_provider.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_favorite_resource_manager.h"
#include "kis_config.h"
#include "KisViewManager.h"
#include "canvas/kis_canvas2.h"
KisCanvasResourceProvider::KisCanvasResourceProvider(KisViewManager * view)
: m_view(view)
{
m_fGChanged = true;
- m_enablefGChange = true; // default to true, so that colour history is working without popup palette
}
KisCanvasResourceProvider::~KisCanvasResourceProvider()
{
disconnect(); // in case Qt gets confused
}
KoCanvasResourceProvider* KisCanvasResourceProvider::resourceManager()
{
return m_resourceManager;
}
void KisCanvasResourceProvider::setResourceManager(KoCanvasResourceProvider *resourceManager)
{
m_resourceManager = resourceManager;
QVariant v;
v.setValue(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8()));
m_resourceManager->setResource(KoCanvasResourceProvider::ForegroundColor, v);
v.setValue(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8()));
m_resourceManager->setResource(KoCanvasResourceProvider::BackgroundColor, v);
setCurrentCompositeOp(COMPOSITE_OVER);
setMirrorHorizontal(false);
setMirrorVertical(false);
m_resourceManager->setResource(HdrExposure, 0.0);
m_resourceManager->setResource(HdrGamma, 1.0);
m_resourceManager->setResource(EffectiveZoom, 1.0);
connect(m_resourceManager, SIGNAL(canvasResourceChanged(int,QVariant)),
this, SLOT(slotCanvasResourceChanged(int,QVariant)));
m_resourceManager->setResource(KoCanvasResourceProvider::ApplicationSpeciality, KoCanvasResourceProvider::NoAdvancedText);
m_resourceManager->setResource(GamutMaskActive, false);
}
KoCanvasBase * KisCanvasResourceProvider::canvas() const
{
return m_view->canvasBase();
}
KoColor KisCanvasResourceProvider::bgColor() const
{
return m_resourceManager->resource(KoCanvasResourceProvider::BackgroundColor).value();
}
KoColor KisCanvasResourceProvider::fgColor() const
{
return m_resourceManager->resource(KoCanvasResourceProvider::ForegroundColor).value();
}
float KisCanvasResourceProvider::HDRExposure() const
{
return static_cast(m_resourceManager->resource(HdrExposure).toDouble());
}
void KisCanvasResourceProvider::setHDRExposure(float exposure)
{
m_resourceManager->setResource(HdrExposure, static_cast(exposure));
}
float KisCanvasResourceProvider::HDRGamma() const
{
return static_cast(m_resourceManager->resource(HdrGamma).toDouble());
}
void KisCanvasResourceProvider::setHDRGamma(float gamma)
{
m_resourceManager->setResource(HdrGamma, static_cast(gamma));
}
KoPatternSP KisCanvasResourceProvider::currentPattern() const
{
if (m_resourceManager->hasResource(CurrentPattern)) {
return m_resourceManager->resource(CurrentPattern).value();
}
else {
return 0;
}
}
KoAbstractGradientSP KisCanvasResourceProvider::currentGradient() const
{
if (m_resourceManager->hasResource(CurrentGradient)) {
return m_resourceManager->resource(CurrentGradient).value();
}
else {
return 0;
}
}
KisImageWSP KisCanvasResourceProvider::currentImage() const
{
return m_view->image();
}
KisNodeSP KisCanvasResourceProvider::currentNode() const
{
return m_view->activeNode();
}
KoGamutMaskSP KisCanvasResourceProvider::currentGamutMask() const
{
if (m_resourceManager->hasResource(CurrentGamutMask)) {
return m_resourceManager->resource(CurrentGamutMask).value();
}
else {
return nullptr;
}
}
bool KisCanvasResourceProvider::gamutMaskActive() const
{
return m_resourceManager->resource(GamutMaskActive).toBool();
}
KisPaintOpPresetSP KisCanvasResourceProvider::currentPreset() const
{
KisPaintOpPresetSP preset = m_resourceManager->resource(CurrentPaintOpPreset).value();
return preset;
}
void KisCanvasResourceProvider::setPaintOpPreset(const KisPaintOpPresetSP preset)
{
Q_ASSERT(preset->valid());
Q_ASSERT(!preset->paintOp().id().isEmpty());
Q_ASSERT(preset->settings());
if (!preset) return;
dbgUI << "setPaintOpPreset" << preset->paintOp();
QVariant v;
v.setValue(preset);
m_resourceManager->setResource(CurrentPaintOpPreset, v);
}
KisPaintOpPresetSP KisCanvasResourceProvider::previousPreset() const
{
KisPaintOpPresetSP preset = m_resourceManager->resource(PreviousPaintOpPreset).value();
return preset;
}
void KisCanvasResourceProvider::setPreviousPaintOpPreset(const KisPaintOpPresetSP preset)
{
Q_ASSERT(preset->valid());
Q_ASSERT(!preset->paintOp().id().isEmpty());
Q_ASSERT(preset->settings());
if (!preset) return;
dbgUI << "setPreviousPaintOpPreset" << preset->paintOp();
QVariant v;
v.setValue(preset);
m_resourceManager->setResource(PreviousPaintOpPreset, v);
}
void KisCanvasResourceProvider::slotPatternActivated(KoResourceSP res)
{
KoPatternSP pattern = res.dynamicCast();
QVariant v;
v.setValue(pattern);
m_resourceManager->setResource(CurrentPattern, v);
emit sigPatternChanged(pattern);
}
void KisCanvasResourceProvider::slotGradientActivated(KoResourceSP res)
{
KoAbstractGradientSP gradient = res.dynamicCast();
QVariant v;
v.setValue(gradient);
m_resourceManager->setResource(CurrentGradient, v);
emit sigGradientChanged(gradient);
}
void KisCanvasResourceProvider::setBGColor(const KoColor& c)
{
QVariant v;
v.setValue(c);
m_resourceManager->setResource(KoCanvasResourceProvider::BackgroundColor, v);
emit sigBGColorChanged(c);
}
void KisCanvasResourceProvider::setFGColor(const KoColor& c)
{
m_fGChanged = true;
QVariant v;
v.setValue(c);
m_resourceManager->setResource(KoCanvasResourceProvider::ForegroundColor, v);
emit sigFGColorChanged(c);
}
void KisCanvasResourceProvider::slotSetFGColor(const KoColor& c)
{
setFGColor(c);
}
void KisCanvasResourceProvider::slotSetBGColor(const KoColor& c)
{
setBGColor(c);
}
void KisCanvasResourceProvider::slotNodeActivated(const KisNodeSP node)
{
QVariant v;
v.setValue(KisNodeWSP(node));
m_resourceManager->setResource(CurrentKritaNode, v);
emit sigNodeChanged(currentNode());
}
void KisCanvasResourceProvider::slotImageSizeChanged()
{
if (KisImageWSP image = m_view->image()) {
float fw = image->width() / image->xRes();
float fh = image->height() / image->yRes();
QSizeF postscriptSize(fw, fh);
m_resourceManager->setResource(KoCanvasResourceProvider::PageSize, postscriptSize);
}
}
void KisCanvasResourceProvider::slotOnScreenResolutionChanged()
{
KisImageWSP image = m_view->image();
KisCanvas2 *canvas = m_view->canvasBase();
if(!image || !canvas) return;
qreal zoomX, zoomY;
canvas->coordinatesConverter()->zoom(&zoomX, &zoomY);
qreal scaleX = zoomX / image->xRes();
qreal scaleY = zoomY / image->yRes();
emit sigOnScreenResolutionChanged(scaleX, scaleY);
}
void KisCanvasResourceProvider::slotCanvasResourceChanged(int key, const QVariant & res)
{
if (key == KoCanvasResourceProvider::ForegroundColor || key == KoCanvasResourceProvider::BackgroundColor) {
KoAbstractGradientSP resource = KoResourceServerProvider::instance()->gradientServer()->resourceByFilename("Foreground to Background");
if (resource) {
KoStopGradientSP stopGradient = resource.dynamicCast();
if (stopGradient) {
QList stops;
stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), fgColor().colorSpace()));
stopGradient->setStops(stops);
KoResourceServerProvider::instance()->gradientServer()->updateResource(resource);
}
}
resource = KoResourceServerProvider::instance()->gradientServer()->resourceByFilename("Foreground to Transparent");
if (resource){
KoStopGradientSP stopGradient = resource.dynamicCast();
if (stopGradient) {
QList stops;
stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, bgColor());
stopGradient->setStops(stops);
KoResourceServerProvider::instance()->gradientServer()->updateResource(resource);
}
}
}
switch (key) {
case(KoCanvasResourceProvider::ForegroundColor):
m_fGChanged = true;
emit sigFGColorChanged(res.value());
break;
case(KoCanvasResourceProvider::BackgroundColor):
emit sigBGColorChanged(res.value());
break;
case(CurrentPattern):
emit sigPatternChanged(res.value());
break;
case(CurrentGradient):
emit sigGradientChanged(res.value());
break;
case(CurrentKritaNode) :
emit sigNodeChanged(currentNode());
break;
case (Opacity):
{
emit sigOpacityChanged(res.toDouble());
}
default:
;
// Do nothing
};
}
void KisCanvasResourceProvider::setCurrentCompositeOp(const QString& compositeOp)
{
m_resourceManager->setResource(CurrentCompositeOp,
QVariant::fromValue(compositeOp));
}
QString KisCanvasResourceProvider::currentCompositeOp() const
{
return m_resourceManager->resource(CurrentCompositeOp).value();
}
bool KisCanvasResourceProvider::eraserMode() const
{
return m_resourceManager->resource(EraserMode).toBool();
}
void KisCanvasResourceProvider::setEraserMode(bool value)
{
m_resourceManager->setResource(EraserMode,
QVariant::fromValue(value));
}
void KisCanvasResourceProvider::slotPainting()
{
- if (m_fGChanged && m_enablefGChange) {
+ if (m_fGChanged) {
emit sigFGColorUsed(fgColor());
m_fGChanged = false;
}
}
void KisCanvasResourceProvider::slotGamutMaskActivated(KoGamutMaskSP mask)
{
QVariant v;
v.setValue(mask);
m_resourceManager->setResource(CurrentGamutMask, v);
m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(true));
emit sigGamutMaskChanged(mask);
}
void KisCanvasResourceProvider::slotGamutMaskUnset()
{
m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(false));
m_resourceManager->clearResource(CurrentGamutMask);
emit sigGamutMaskUnset();
}
void KisCanvasResourceProvider::slotGamutMaskPreviewUpdate()
{
emit sigGamutMaskPreviewUpdate();
}
void KisCanvasResourceProvider::slotGamutMaskDeactivate()
{
m_resourceManager->setResource(GamutMaskActive, QVariant::fromValue(false));
emit sigGamutMaskDeactivated();
}
-void KisCanvasResourceProvider::slotResetEnableFGChange(bool b)
-{
- m_enablefGChange = b;
-}
-
QList > KisCanvasResourceProvider::perspectiveGrids() const
{
return m_perspectiveGrids;
}
void KisCanvasResourceProvider::addPerspectiveGrid(KisAbstractPerspectiveGrid* grid)
{
m_perspectiveGrids.append(grid);
}
void KisCanvasResourceProvider::removePerspectiveGrid(KisAbstractPerspectiveGrid* grid)
{
m_perspectiveGrids.removeOne(grid);
}
void KisCanvasResourceProvider::clearPerspectiveGrids()
{
m_perspectiveGrids.clear();
}
void KisCanvasResourceProvider::setMirrorHorizontal(bool mirrorHorizontal)
{
m_resourceManager->setResource(MirrorHorizontal, mirrorHorizontal);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorHorizontal() const
{
return m_resourceManager->resource(MirrorHorizontal).toBool();
}
void KisCanvasResourceProvider::setMirrorVertical(bool mirrorVertical)
{
m_resourceManager->setResource(MirrorVertical, mirrorVertical);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorVertical() const
{
return m_resourceManager->resource(MirrorVertical).toBool();
}
void KisCanvasResourceProvider::setMirrorHorizontalLock(bool isLocked)
{
m_resourceManager->setResource(MirrorHorizontalLock, isLocked);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorHorizontalLock() {
return m_resourceManager->resource(MirrorHorizontalLock).toBool();
}
void KisCanvasResourceProvider::setMirrorVerticalLock(bool isLocked)
{
m_resourceManager->setResource(MirrorVerticalLock, isLocked);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorVerticalHideDecorations() {
return m_resourceManager->resource(MirrorVerticalHideDecorations).toBool();
}
void KisCanvasResourceProvider::setMirrorVerticalHideDecorations(bool hide)
{
m_resourceManager->setResource(MirrorVerticalHideDecorations, hide);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorHorizontalHideDecorations() {
return m_resourceManager->resource(MirrorHorizontalHideDecorations).toBool();
}
void KisCanvasResourceProvider::setMirrorHorizontalHideDecorations(bool hide)
{
m_resourceManager->setResource(MirrorHorizontalHideDecorations, hide);
emit mirrorModeChanged();
}
bool KisCanvasResourceProvider::mirrorVerticalLock() {
return m_resourceManager->resource(MirrorVerticalLock).toBool();
}
void KisCanvasResourceProvider::mirrorVerticalMoveCanvasToCenter() {
emit moveMirrorVerticalCenter();
}
void KisCanvasResourceProvider::mirrorHorizontalMoveCanvasToCenter() {
emit moveMirrorHorizontalCenter();
}
void KisCanvasResourceProvider::setOpacity(qreal opacity)
{
m_resourceManager->setResource(Opacity, opacity);
}
qreal KisCanvasResourceProvider::opacity() const
{
return m_resourceManager->resource(Opacity).toReal();
}
void KisCanvasResourceProvider::setFlow(qreal flow)
{
m_resourceManager->setResource(Flow, flow);
}
qreal KisCanvasResourceProvider::flow() const
{
return m_resourceManager->resource(Flow).toReal();
}
void KisCanvasResourceProvider::setSize(qreal size)
{
m_resourceManager->setResource(Size, size);
}
qreal KisCanvasResourceProvider::size() const
{
return m_resourceManager->resource(Size).toReal();
}
void KisCanvasResourceProvider::setGlobalAlphaLock(bool lock)
{
m_resourceManager->setResource(GlobalAlphaLock, lock);
}
bool KisCanvasResourceProvider::globalAlphaLock() const
{
return m_resourceManager->resource(GlobalAlphaLock).toBool();
}
void KisCanvasResourceProvider::setDisablePressure(bool value)
{
m_resourceManager->setResource(DisablePressure, value);
}
bool KisCanvasResourceProvider::disablePressure() const
{
return m_resourceManager->resource(DisablePressure).toBool();
}
void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResourceSP workspace)
{
emit sigLoadingWorkspace(workspace);
}
void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResourceSP workspace)
{
emit sigSavingWorkspace(workspace);
}
diff --git a/libs/ui/kis_canvas_resource_provider.h b/libs/ui/kis_canvas_resource_provider.h
index 2772f5342a..24e6c57c1d 100644
--- a/libs/ui/kis_canvas_resource_provider.h
+++ b/libs/ui/kis_canvas_resource_provider.h
@@ -1,253 +1,238 @@
/*
* Copyright (c) 2006 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_CANVAS_RESOURCE_PROVIDER_H_
#define KIS_CANVAS_RESOURCE_PROVIDER_H_
#include
#include
#include
#include
#include
#include "kis_types.h"
#include "kritaui_export.h"
#include
#include
#include
#include
class KoColorProfile;
class KoAbstractGradient;
class KoCanvasBase;
class KisViewManager;
class KisFilterConfiguration;
#include
/**
* KisCanvasResourceProvider contains the per-window current settings that
* influence painting, like paintop, color, gradients and so on.
*/
class KRITAUI_EXPORT KisCanvasResourceProvider : public QObject
{
Q_OBJECT
public:
enum Resources {
HdrExposure = KoCanvasResourceProvider::KritaStart + 1,
CurrentPattern,
CurrentGamutMask,
GamutMaskActive,
CurrentGradient,
CurrentDisplayProfile,
CurrentKritaNode,
CurrentPaintOpPreset,
CurrentGeneratorConfiguration,
CurrentCompositeOp,
CurrentEffectiveCompositeOp,
LodAvailability, ///<-user choice
LodSizeThreshold, ///<-user choice
LodSizeThresholdSupported, ///<-paintop property
EffectiveLodAvailablility, ///<- a superposition of user choice, threshold and paintop traits
EraserMode,
MirrorHorizontal,
MirrorVertical,
MirrorHorizontalLock,
MirrorVerticalLock,
MirrorVerticalHideDecorations,
MirrorHorizontalHideDecorations,
Opacity,
Flow,
Size,
HdrGamma,
GlobalAlphaLock,
DisablePressure,
PreviousPaintOpPreset,
EffectiveZoom ///<-Used only by painting tools for non-displaying purposes
};
KisCanvasResourceProvider(KisViewManager * view);
~KisCanvasResourceProvider() override;
void setResourceManager(KoCanvasResourceProvider *resourceManager);
KoCanvasResourceProvider* resourceManager();
KoCanvasBase * canvas() const;
KoColor bgColor() const;
void setBGColor(const KoColor& c);
KoColor fgColor() const;
void setFGColor(const KoColor& c);
float HDRExposure() const;
void setHDRExposure(float exposure);
float HDRGamma() const;
void setHDRGamma(float gamma);
bool eraserMode() const;
void setEraserMode(bool value);
KoPatternSP currentPattern() const;
KoAbstractGradientSP currentGradient() const;
KisImageWSP currentImage() const;
KisNodeSP currentNode() const;
KoGamutMaskSP currentGamutMask() const;
bool gamutMaskActive() const;
KisPaintOpPresetSP currentPreset() const;
void setPaintOpPreset(const KisPaintOpPresetSP preset);
KisPaintOpPresetSP previousPreset() const;
void setPreviousPaintOpPreset(const KisPaintOpPresetSP preset);
void setCurrentCompositeOp(const QString& compositeOp);
QString currentCompositeOp() const;
QList > perspectiveGrids() const;
void addPerspectiveGrid(KisAbstractPerspectiveGrid*);
void removePerspectiveGrid(KisAbstractPerspectiveGrid*);
void clearPerspectiveGrids();
void setMirrorHorizontal(bool mirrorHorizontal);
bool mirrorHorizontal() const;
void setMirrorVertical(bool mirrorVertical);
bool mirrorVertical() const;
// options for horizontal and vertical mirror toolbar
void setMirrorHorizontalLock(bool isLocked);
bool mirrorHorizontalLock();
void setMirrorVerticalLock(bool isLocked);
bool mirrorVerticalLock();
void setMirrorVerticalHideDecorations(bool hide);
bool mirrorVerticalHideDecorations();
void setMirrorHorizontalHideDecorations(bool hide);
bool mirrorHorizontalHideDecorations();
void mirrorVerticalMoveCanvasToCenter();
void mirrorHorizontalMoveCanvasToCenter();
void setOpacity(qreal opacity);
qreal opacity() const;
void setFlow(qreal opacity);
qreal flow() const;
void setSize(qreal size);
qreal size() const;
void setGlobalAlphaLock(bool lock);
bool globalAlphaLock() const;
void setDisablePressure(bool value);
bool disablePressure() const;
///Notify that the workspace is saved and settings should be saved to it
void notifySavingWorkspace(KisWorkspaceResourceSP workspace);
///Notify that the workspace is loaded and settings can be read
void notifyLoadingWorkspace(KisWorkspaceResourceSP workspace);
public Q_SLOTS:
void slotSetFGColor(const KoColor& c);
void slotSetBGColor(const KoColor& c);
void slotPatternActivated(KoResourceSP pattern);
void slotGradientActivated(KoResourceSP gradient);
void slotNodeActivated(const KisNodeSP node);
void slotPainting();
void slotGamutMaskActivated(KoGamutMaskSP mask);
void slotGamutMaskUnset();
void slotGamutMaskPreviewUpdate();
void slotGamutMaskDeactivate();
/**
* Set the image size in pixels. The resource provider will store
* the image size in postscript points.
*/
// FIXME: this slot doesn't catch the case when image resolution is changed
void slotImageSizeChanged();
void slotOnScreenResolutionChanged();
- // This is a flag to handle a bug:
- // If pop up palette is visible and a new colour is selected, the new colour
- // will be added when the user clicks on the canvas to hide the palette
- // In general, we want to be able to store recent color if the pop up palette
- // is not visible
- void slotResetEnableFGChange(bool);
-
private Q_SLOTS:
void slotCanvasResourceChanged(int key, const QVariant & res);
Q_SIGNALS:
void sigFGColorChanged(const KoColor &);
void sigBGColorChanged(const KoColor &);
void sigGradientChanged(KoAbstractGradientSP);
void sigPatternChanged(KoPatternSP);
void sigNodeChanged(const KisNodeSP);
void sigDisplayProfileChanged(const KoColorProfile *);
void sigFGColorUsed(const KoColor&);
void sigOnScreenResolutionChanged(qreal scaleX, qreal scaleY);
void sigOpacityChanged(qreal);
void sigSavingWorkspace(KisWorkspaceResourceSP workspace);
void sigLoadingWorkspace(KisWorkspaceResourceSP workspace);
void mirrorModeChanged();
void moveMirrorVerticalCenter();
void moveMirrorHorizontalCenter();
void sigGamutMaskChanged(KoGamutMaskSP mask);
void sigGamutMaskUnset();
void sigGamutMaskPreviewUpdate();
void sigGamutMaskDeactivated();
private:
KisViewManager * m_view;
KoCanvasResourceProvider *m_resourceManager;
bool m_fGChanged;
QList > m_perspectiveGrids;
-
- // This is a flag to handle a bug:
- // If pop up palette is visible and a new colour is selected, the new colour
- // will be added when the user clicks on the canvas to hide the palette
- // In general, we want to be able to store recent color if the pop up palette
- // is not visible
- bool m_enablefGChange;
-
};
#endif
diff --git a/libs/ui/kis_favorite_resource_manager.h b/libs/ui/kis_favorite_resource_manager.h
index 1d3c75dafb..35a062e97b 100644
--- a/libs/ui/kis_favorite_resource_manager.h
+++ b/libs/ui/kis_favorite_resource_manager.h
@@ -1,134 +1,127 @@
/* This file is part of the KDE project
Copyright 2009 Vera Lukman
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KIS_FAVORITE_RESOURCE_MANAGER_H
#define KIS_FAVORITE_RESOURCE_MANAGER_H
#include
#include
#include
#include
#include "KoResourceServerObserver.h"
#include
#include "KisTagFilterResourceProxyModel.h"
#include
#include
#include
class QString;
class KisPaintopBox;
class KisPaintOpPreset;
class KisFavoriteResourceManager : public QObject, public KoResourceServerObserver
{
Q_OBJECT
public:
KisFavoriteResourceManager(KisPaintopBox *paintopBox);
~KisFavoriteResourceManager() override;
void unsetResourceServer() override;
QList favoritePresetImages();
QVector favoritePresetNamesList();
void setCurrentTag(const KisTagSP tag);
int numFavoritePresets();
void updateFavoritePresets();
int recentColorsTotal();
const KoColor& recentColorAt(int pos);
// Reimplemented from KoResourceServerObserver
void removingResource(QSharedPointer resource) override;
void resourceAdded(QSharedPointer resource) override;
void resourceChanged(QSharedPointer resource) override;
void syncTaggedResourceView() override;
void syncTagAddition(const QString& tag) override;
void syncTagRemoval(const QString& tag) override;
//BgColor;
KoColor bgColor() const;
Q_SIGNALS:
void sigSetFGColor(const KoColor& c);
void sigSetBGColor(const KoColor& c);
- // This is a flag to handle a bug:
- // If pop up palette is visible and a new colour is selected, the new colour
- // will be added when the user clicks on the canvas to hide the palette
- // In general, we want to be able to store recent colours if the pop up palette
- // is not visible
- void sigEnableChangeColor(bool b);
-
void sigChangeFGColorSelector(const KoColor&);
void setSelectedColor(int);
void updatePalettes();
void hidePalettes();
public Q_SLOTS:
void slotChangeActivePaintop(int);
/*update the priority of a colour in m_colorList, used only by m_popupPalette*/
void slotUpdateRecentColor(int);
/*add a colour to m_colorList, used by KisCanvasResourceProvider*/
void slotAddRecentColor(const KoColor&);
void slotChangeFGColorSelector(KoColor c);
void slotSetBGColor(const KoColor c);
private Q_SLOTS:
void configChanged();
private:
void init();
KisPaintopBox *m_paintopBox;
class ColorDataList;
ColorDataList *m_colorList;
void saveFavoritePresets();
KoColor m_bgColor;
KisTagSP m_currentTag;
bool m_initialized;
int m_maxPresets;
KisTagModel* m_tagModel;
KisTagFilterResourceProxyModel* m_resourcesProxyModel;
KisResourceModel* m_resourceModel;
};
#endif
diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc
index 4cb2bb7bc3..234f2c7b5d 100644
--- a/libs/ui/kis_paintop_box.cc
+++ b/libs/ui/kis_paintop_box.cc
@@ -1,1399 +1,1398 @@
/*
* kis_paintop_box.cc - part of KImageShop/Krayon/Krita
*
* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org)
* Copyright (c) 2009-2011 Sven Langkamp (sven.langkamp@gmail.com)
* Copyright (c) 2010 Lukáš Tvrdý
* Copyright (C) 2011 Silvio Heinrich
* Copyright (C) 2011 Srikanth Tiyyagura
* Copyright (c) 2014 Mohit Goyal
*
* 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_paintop_box.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_canvas2.h"
#include "kis_node_manager.h"
#include "KisViewManager.h"
#include "kis_canvas_resource_provider.h"
#include "KisResourceServerProvider.h"
#include "kis_favorite_resource_manager.h"
#include "kis_config.h"
#include "KisPopupButton.h"
#include "widgets/kis_iconwidget.h"
#include "widgets/kis_tool_options_popup.h"
#include "widgets/kis_paintop_presets_popup.h"
#include "widgets/kis_paintop_presets_chooser_popup.h"
#include "widgets/kis_workspace_chooser.h"
#include "widgets/kis_paintop_list_widget.h"
#include "widgets/kis_slider_spin_box.h"
#include "widgets/kis_cmb_composite.h"
#include "widgets/kis_widget_chooser.h"
#include "tool/kis_tool.h"
#include "kis_signals_blocker.h"
#include "kis_action_manager.h"
#include "KisHighlightedToolButton.h"
#include
KisPaintopBox::KisPaintopBox(KisViewManager *view, QWidget *parent, const char *name)
: QWidget(parent)
, m_resourceProvider(view->canvasResourceProvider())
, m_optionWidget(0)
, m_toolOptionsPopupButton(0)
, m_brushEditorPopupButton(0)
, m_presetSelectorPopupButton(0)
, m_toolOptionsPopup(0)
, m_viewManager(view)
, m_previousNode(0)
, m_currTabletToolID(KoInputDevice::invalid())
, m_presetsEnabled(true)
, m_blockUpdate(false)
, m_dirtyPresetsEnabled(false)
, m_eraserBrushSizeEnabled(false)
, m_eraserBrushOpacityEnabled(false)
{
Q_ASSERT(view != 0);
setObjectName(name);
KisConfig cfg(true);
m_dirtyPresetsEnabled = cfg.useDirtyPresets();
m_eraserBrushSizeEnabled = cfg.useEraserBrushSize();
m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity();
KAcceleratorManager::setNoAccel(this);
setWindowTitle(i18n("Painter's Toolchest"));
m_favoriteResourceManager = new KisFavoriteResourceManager(this);
KConfigGroup grp = KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff");
int iconsize = grp.readEntry("IconSize", 32);
if (!cfg.toolOptionsInDocker()) {
m_toolOptionsPopupButton = new KisPopupButton(this);
m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure"));
m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings"));
m_toolOptionsPopupButton->setFixedSize(iconsize, iconsize);
}
m_brushEditorPopupButton = new KisIconWidget(this);
m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02"));
m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings"));
m_brushEditorPopupButton->setFixedSize(iconsize, iconsize);
m_presetSelectorPopupButton = new KisPopupButton(this);
m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01"));
m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset"));
m_presetSelectorPopupButton->setFixedSize(iconsize, iconsize);
m_eraseModeButton = new KisHighlightedToolButton(this);
m_eraseModeButton->setFixedSize(iconsize, iconsize);
m_eraseModeButton->setCheckable(true);
m_eraseAction = m_viewManager->actionManager()->createAction("erase_action");
m_eraseModeButton->setDefaultAction(m_eraseAction);
m_reloadButton = new QToolButton(this);
m_reloadButton->setFixedSize(iconsize, iconsize);
m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action");
m_reloadButton->setDefaultAction(m_reloadAction);
m_alphaLockButton = new KisHighlightedToolButton(this);
m_alphaLockButton->setFixedSize(iconsize, iconsize);
m_alphaLockButton->setCheckable(true);
KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha");
m_alphaLockButton->setDefaultAction(alphaLockAction);
// horizontal and vertical mirror toolbar buttons
// mirror tool options for the X Mirror
QMenu *toolbarMenuXMirror = new QMenu();
hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations");
toolbarMenuXMirror->addAction(hideCanvasDecorationsX);
lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock");
toolbarMenuXMirror->addAction(lockActionX);
moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter");
toolbarMenuXMirror->addAction(moveToCenterActionX);
// mirror tool options for the Y Mirror
QMenu *toolbarMenuYMirror = new QMenu();
hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations");
toolbarMenuYMirror->addAction(hideCanvasDecorationsY);
lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock");
toolbarMenuYMirror->addAction(lockActionY);
moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter");
toolbarMenuYMirror->addAction(moveToCenterActionY);
// create horizontal and vertical mirror buttons
m_hMirrorButton = new KisHighlightedToolButton(this);
int menuPadding = 10;
m_hMirrorButton->setFixedSize(iconsize + menuPadding, iconsize);
m_hMirrorButton->setCheckable(true);
m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action");
m_hMirrorButton->setDefaultAction(m_hMirrorAction);
m_hMirrorButton->setMenu(toolbarMenuXMirror);
m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
m_vMirrorButton = new KisHighlightedToolButton(this);
m_vMirrorButton->setFixedSize(iconsize + menuPadding, iconsize);
m_vMirrorButton->setCheckable(true);
m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action");
m_vMirrorButton->setDefaultAction(m_vMirrorAction);
m_vMirrorButton->setMenu(toolbarMenuYMirror);
m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
// add connections for horizontal and mirrror buttons
connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool)));
connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool)));
connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX()));
connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY()));
connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool)));
connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool)));
const bool sliderLabels = cfg.sliderLabels();
int sliderWidth;
if (sliderLabels) {
sliderWidth = 150 * logicalDpiX() / 96;
}
else {
sliderWidth = 120 * logicalDpiX() / 96;
}
for (int i = 0; i < 3; ++i) {
m_sliderChooser[i] = new KisWidgetChooser(i + 1);
KisDoubleSliderSpinBox* slOpacity;
KisDoubleSliderSpinBox* slFlow;
KisDoubleSliderSpinBox* slSize;
if (sliderLabels) {
slOpacity = m_sliderChooser[i]->addWidget("opacity");
slFlow = m_sliderChooser[i]->addWidget("flow");
slSize = m_sliderChooser[i]->addWidget("size");
slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:")));
slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:")));
slSize->setPrefix(QString("%1 ").arg(i18n("Size:")));
}
else {
slOpacity = m_sliderChooser[i]->addWidget("opacity", i18n("Opacity:"));
slFlow = m_sliderChooser[i]->addWidget("flow", i18n("Flow:"));
slSize = m_sliderChooser[i]->addWidget("size", i18n("Size:"));
}
slOpacity->setRange(0, 100, 0);
slOpacity->setValue(100);
slOpacity->setSingleStep(5);
slOpacity->setSuffix(i18n("%"));
slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width()));
slOpacity->setFixedHeight(iconsize);
slOpacity->setBlockUpdateSignalOnDrag(true);
slFlow->setRange(0, 100, 0);
slFlow->setValue(100);
slFlow->setSingleStep(5);
slFlow->setSuffix(i18n("%"));
slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width()));
slFlow->setFixedHeight(iconsize);
slFlow->setBlockUpdateSignalOnDrag(true);
slSize->setRange(0.01, cfg.readEntry("maximumBrushSize", 1000), 2);
slSize->setValue(100);
slSize->setSingleStep(1);
slSize->setExponentRatio(3.0);
slSize->setSuffix(i18n(" px"));
slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width()));
slSize->setFixedHeight(iconsize);
slSize->setBlockUpdateSignalOnDrag(true);
m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1));
}
m_cmbCompositeOp = new KisCompositeOpComboBox();
m_cmbCompositeOp->setFixedHeight(iconsize);
Q_FOREACH (KisAction * a, m_cmbCompositeOp->createBlendmodeActions()) {
m_viewManager->actionManager()->addAction(a->text(), a);
}
m_workspaceWidget = new KisPopupButton(this);
m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose"));
m_workspaceWidget->setToolTip(i18n("Choose workspace"));
m_workspaceWidget->setFixedSize(iconsize, iconsize);
m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(view));
QHBoxLayout* baseLayout = new QHBoxLayout(this);
m_paintopWidget = new QWidget(this);
baseLayout->addWidget(m_paintopWidget);
baseLayout->setSpacing(4);
baseLayout->setContentsMargins(0, 0, 0, 0);
m_layout = new QHBoxLayout(m_paintopWidget);
if (!cfg.toolOptionsInDocker()) {
m_layout->addWidget(m_toolOptionsPopupButton);
}
m_layout->addWidget(m_brushEditorPopupButton);
m_layout->addWidget(m_presetSelectorPopupButton);
m_layout->setSpacing(4);
m_layout->setContentsMargins(0, 0, 0, 0);
QWidget* compositeActions = new QWidget(this);
QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions);
compositeLayout->addWidget(m_cmbCompositeOp);
compositeLayout->addWidget(m_eraseModeButton);
compositeLayout->addWidget(m_alphaLockButton);
compositeLayout->setSpacing(4);
compositeLayout->setContentsMargins(0, 0, 0, 0);
compositeLayout->addWidget(m_reloadButton);
QWidgetAction * action;
action = new QWidgetAction(this);
view->actionCollection()->addAction("composite_actions", action);
action->setText(i18n("Brush composite"));
action->setDefaultWidget(compositeActions);
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("brushslider1", action);
view->actionCollection()->addAction("brushslider1", action);
action->setDefaultWidget(m_sliderChooser[0]);
connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget()));
connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("brushslider2", action);
view->actionCollection()->addAction("brushslider2", action);
action->setDefaultWidget(m_sliderChooser[1]);
connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget()));
connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("brushslider3", action);
view->actionCollection()->addAction("brushslider3", action);
action->setDefaultWidget(m_sliderChooser[2]);
connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget()));
connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action);
view->actionCollection()->addAction("next_favorite_preset", action);
connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action);
view->actionCollection()->addAction("previous_favorite_preset", action);
connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("previous_preset", action);
view->actionCollection()->addAction("previous_preset", action);
connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset()));
if (!cfg.toolOptionsInDocker()) {
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("show_tool_options", action);
view->actionCollection()->addAction("show_tool_options", action);
connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget()));
}
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("show_brush_editor", action);
view->actionCollection()->addAction("show_brush_editor", action);
connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget()));
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("show_brush_presets", action);
view->actionCollection()->addAction("show_brush_presets", action);
connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget()));
QWidget* mirrorActions = new QWidget(this);
QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions);
mirrorLayout->addWidget(m_hMirrorButton);
mirrorLayout->addWidget(m_vMirrorButton);
mirrorLayout->setSpacing(4);
mirrorLayout->setContentsMargins(0, 0, 0, 0);
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction("mirror_actions", action);
action->setDefaultWidget(mirrorActions);
view->actionCollection()->addAction("mirror_actions", action);
action = new QWidgetAction(this);
KisActionRegistry::instance()->propertizeAction(ResourceType::Workspaces, action);
view->actionCollection()->addAction(ResourceType::Workspaces, action);
action->setDefaultWidget(m_workspaceWidget);
if (!cfg.toolOptionsInDocker()) {
m_toolOptionsPopup = new KisToolOptionsPopup();
m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup);
m_toolOptionsPopup->switchDetached(false);
}
m_savePresetWidget = new KisPresetSaveWidget(this);
m_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget);
m_brushEditorPopupButton->setPopupWidget(m_presetsPopup);
m_presetsPopup->parentWidget()->setWindowTitle(i18n("Brush Editor"));
connect(m_presetsPopup, SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup()));
connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons()));
m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup();
m_presetsChooserPopup->setMinimumHeight(550);
m_presetsChooserPopup->setMinimumWidth(450);
m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup);
m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
slotNodeChanged(view->activeNode());
// Get all the paintops
QList keys = KisPaintOpRegistry::instance()->keys();
QList factoryList;
Q_FOREACH (const QString & paintopId, keys) {
factoryList.append(KisPaintOpRegistry::instance()->get(paintopId));
}
m_presetsPopup->setPaintOpList(factoryList);
connect(m_presetsPopup , SIGNAL(paintopActivated(QString)) , SLOT(slotSetPaintop(QString)));
connect(m_presetsPopup , SIGNAL(defaultPresetClicked()) , SLOT(slotSetupDefaultPreset()));
connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResourceSP )), SLOT(resourceSelected(KoResourceSP )));
connect(m_presetsPopup , SIGNAL(reloadPresetClicked()) , SLOT(slotReloadPreset()));
connect(m_presetsPopup , SIGNAL(dirtyPresetToggled(bool)) , SLOT(slotDirtyPresetToggled(bool)));
connect(m_presetsPopup , SIGNAL(eraserBrushSizeToggled(bool)) , SLOT(slotEraserBrushSizeToggled(bool)));
connect(m_presetsPopup , SIGNAL(eraserBrushOpacityToggled(bool)) , SLOT(slotEraserBrushOpacityToggled(bool)));
connect(m_presetsPopup, SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString)));
connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP )));
connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP )));
connect(m_resourceProvider , SIGNAL(sigNodeChanged(KisNodeSP)) , SLOT(slotNodeChanged(KisNodeSP)));
connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int)));
connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool)));
connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool)));
m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure");
connect(m_disablePressureAction , SIGNAL(toggled(bool)) , SLOT(slotDisablePressureMode(bool)));
m_disablePressureAction->setChecked(true);
connect(m_hMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotHorizontalMirrorChanged(bool)));
connect(m_vMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotVerticalMirrorChanged(bool)));
connect(m_reloadAction , SIGNAL(triggered()) , SLOT(slotReloadPreset()));
connect(m_sliderChooser[0]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
connect(m_sliderChooser[0]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
connect(m_sliderChooser[0]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
connect(m_sliderChooser[1]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
connect(m_sliderChooser[1]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
connect(m_sliderChooser[1]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
connect(m_sliderChooser[2]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
connect(m_sliderChooser[2]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor)));
connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor)));
connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor)));
// cold initialization
m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor());
m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor());
connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor)));
connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor)));
- connect(m_favoriteResourceManager, SIGNAL(sigEnableChangeColor(bool)), m_resourceProvider, SLOT(slotResetEnableFGChange(bool)));
connect(view->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon()));
connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
this, SLOT(slotCanvasResourceChanged(int,QVariant)));
connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChangeAttempted(int,QVariant)),
this, SLOT(slotCanvasResourceChangeAttempted(int,QVariant)));
slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice());
findDefaultPresets();
}
KisPaintopBox::~KisPaintopBox()
{
KisConfig cfg(false);
QMapIterator iter(m_tabletToolMap);
while (iter.hasNext()) {
iter.next();
if ((iter.key().pointer) == QTabletEvent::Eraser) {
cfg.writeEntry(QString("LastEraser") , iter.value().preset->name());
}
else {
cfg.writeEntry(QString("LastPreset"), iter.value().preset->name());
}
}
// Do not delete the widget, since it is global to the application, not owned by the view
m_presetsPopup->setPaintOpSettingsWidget(0);
qDeleteAll(m_paintopOptionWidgets);
delete m_favoriteResourceManager;
for (int i = 0; i < 3; ++i) {
delete m_sliderChooser[i];
}
}
void KisPaintopBox::restoreResource(KoResourceSP resource)
{
KisPaintOpPresetSP preset = resource.dynamicCast();
if (preset) {
setCurrentPaintop(preset);
m_presetsPopup->setPresetImage(preset->image());
m_presetsPopup->resourceSelected(resource);
}
}
void KisPaintopBox::newOptionWidgets(const QList > &optionWidgetList)
{
if (m_toolOptionsPopup) {
m_toolOptionsPopup->newOptionWidgets(optionWidgetList);
}
}
void KisPaintopBox::resourceSelected(KoResourceSP resource)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget);
m_presetsPopup->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating
// qDebug() << ">>>>>>>>>>>>>>>" << resource
// << (resource ? resource->name() : "")
// << (resource ? QString("%1").arg(resource->valid()) : "")
// << (resource ? QString("%1").arg(resource->filename()) : "");
KisPaintOpPresetSP preset = resource.dynamicCast();
if (preset && preset->valid() && preset != m_resourceProvider->currentPreset()) {
qWarning() << "Preset reloading if presets are dirty is broken";
// if (!preset->settings()->isLoadable()) {
// return;
// }
// if (!m_dirtyPresetsEnabled) {
// KisSignalsBlocker blocker(m_optionWidget);
// Q_UNUSED(blocker)
// if (!preset->load()) {
// qWarning() << "failed to load the preset.";
// }
// }
dbgResources << "resourceSelected: preset" << preset << (preset ? QString("%1").arg(preset->valid()) : "");
setCurrentPaintop(preset);
m_presetsPopup->setPresetImage(preset->image());
m_presetsPopup->resourceSelected(resource);
}
}
void KisPaintopBox::setCurrentPaintop(const KoID& paintop)
{
KisPaintOpPresetSP preset = activePreset(paintop);
Q_ASSERT(preset && preset->settings());
//qDebug() << "setCurrentPaintop();" << paintop << preset;
setCurrentPaintop(preset);
}
void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset)
{
//qDebug() << "setCurrentPaintop(); " << preset->name();
if (preset == m_resourceProvider->currentPreset()) {
if (preset == m_tabletToolMap[m_currTabletToolID].preset) {
return;
}
}
Q_ASSERT(preset);
const KoID& paintop = preset->paintOp();
m_presetConnections.clear();
if (m_resourceProvider->currentPreset()) {
m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset());
if (m_optionWidget) {
m_optionWidget->hide();
}
}
if (!m_paintopOptionWidgets.contains(paintop))
m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this);
m_optionWidget = m_paintopOptionWidgets[paintop];
KisSignalsBlocker b(m_optionWidget);
preset->setOptionsWidget(m_optionWidget);
m_optionWidget->setImage(m_viewManager->image());
m_optionWidget->setNode(m_viewManager->activeNode());
m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget);
m_resourceProvider->setPaintOpPreset(preset);
Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton);
m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset()));
m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP)));
m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP)));
// load the current brush engine icon for the brush editor toolbar button
m_brushEditorPopupButton->setThumbnail(preset->image());
m_presetsPopup->setCurrentPaintOpId(paintop.id());
////qDebug() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name();
m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset;
m_tabletToolMap[m_currTabletToolID].preset = preset;
m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp();
if (m_presetsPopup->currentPaintOpId() != paintop.id()) {
// Must change the paintop as the current one is not supported
// by the new colorspace.
dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace";
}
m_currCompositeOpID = preset->settings()->paintOpCompositeOp();
updateCompositeOp(m_currCompositeOpID);
}
void KisPaintopBox::slotUpdateOptionsWidgetPopup()
{
KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
// This happens when we have a new brush engine for which no default preset exists yet.
if (!preset) return;
KIS_SAFE_ASSERT_RECOVER_RETURN(preset);
KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget);
m_optionWidget->setConfigurationSafe(preset->settings());
m_presetsPopup->resourceSelected(preset);
m_presetsPopup->updateViewSettings();
// the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed
// need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation
m_optionWidget->setImage(m_viewManager->image());
}
KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp)
{
QString defaultName = paintOp.id() + ".kpp";
QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName);
KisPaintOpPresetSP preset(new KisPaintOpPreset(path));
if (!preset->load(KisGlobalResourcesInterface::instance())) {
preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp, KisGlobalResourcesInterface::instance());
}
Q_ASSERT(preset);
Q_ASSERT(preset->valid());
return preset;
}
KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp)
{
if (m_paintOpPresetMap[paintOp] == 0) {
m_paintOpPresetMap[paintOp] = defaultPreset(paintOp);
}
return m_paintOpPresetMap[paintOp];
}
void KisPaintopBox::updateCompositeOp(QString compositeOpID)
{
if (!m_optionWidget) return;
KisSignalsBlocker blocker(m_optionWidget);
KisNodeSP node = m_resourceProvider->currentNode();
if (node && node->paintDevice()) {
if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID))
compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
{
KisSignalsBlocker b1(m_cmbCompositeOp);
m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
}
if (compositeOpID != m_currCompositeOpID) {
m_currCompositeOpID = compositeOpID;
}
if (compositeOpID == COMPOSITE_ERASE || m_resourceProvider->eraserMode()) {
m_eraseModeButton->setChecked(true);
}
else {
m_eraseModeButton->setChecked(false);
}
}
else if (!node) {
KisSignalsBlocker b1(m_cmbCompositeOp);
m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
m_currCompositeOpID = compositeOpID;
}
}
void KisPaintopBox::setWidgetState(int flags)
{
if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) {
m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP);
m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP);
}
if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) {
m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS);
m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS);
}
for (int i = 0; i < 3; ++i) {
if (flags & (ENABLE_OPACITY | DISABLE_OPACITY))
m_sliderChooser[i]->getWidget("opacity")->setEnabled(flags & ENABLE_OPACITY);
if (flags & (ENABLE_FLOW | DISABLE_FLOW))
m_sliderChooser[i]->getWidget("flow")->setEnabled(flags & ENABLE_FLOW);
if (flags & (ENABLE_SIZE | DISABLE_SIZE))
m_sliderChooser[i]->getWidget("size")->setEnabled(flags & ENABLE_SIZE);
}
}
void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value)
{
for (int i = 0; i < 3; ++i) {
KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget(sliderID);
KisSignalsBlocker b(slider);
if (sliderID == "opacity" || sliderID == "flow") { // opacity and flows UI stored at 0-100%
slider->setValue(value*100);
} else {
slider->setValue(value); // brush size
}
}
}
void KisPaintopBox::slotSetPaintop(const QString& paintOpId)
{
if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) {
KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name());
//qDebug() << "slotsetpaintop" << id;
setCurrentPaintop(id);
}
}
void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice)
{
TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice);
//qDebug() << "slotInputDeviceChanged()" << inputDevice.device() << inputDevice.uniqueTabletId();
m_currTabletToolID = TabletToolID(inputDevice);
if (toolData == m_tabletToolMap.end()) {
KisConfig cfg(true);
KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
KisPaintOpPresetSP preset;
if (inputDevice.pointer() == QTabletEvent::Eraser) {
preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), m_eraserName));
}
else {
preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), m_defaultPresetName));
//if (preset)
//qDebug() << "found stored preset " << preset->name() << "for" << inputDevice.uniqueTabletId();
//else
//qDebug() << "no preset found for" << inputDevice.uniqueTabletId();
}
if (!preset) {
preset = rserver->resourceByName(m_defaultPresetName);
}
if (preset) {
//qDebug() << "inputdevicechanged 1" << preset;
setCurrentPaintop(preset);
}
}
else {
if (toolData->preset) {
//qDebug() << "inputdevicechanged 2" << toolData->preset;
setCurrentPaintop(toolData->preset);
}
else {
//qDebug() << "inputdevicechanged 3" << toolData->paintOpID;
setCurrentPaintop(toolData->paintOpID);
}
}
}
void KisPaintopBox::slotCreatePresetFromScratch(QString paintop)
{
//First try to select an available default preset for that engine. If it doesn't exist, then
//manually set the engine to use a new preset.
KoID id(paintop, KisPaintOpRegistry::instance()->get(paintop)->name());
KisPaintOpPresetSP preset = defaultPreset(id);
slotSetPaintop(paintop); // change the paintop settings area and update the UI
if (!preset) {
m_presetsPopup->setCreatingBrushFromScratch(true); // disable UI elements while creating from scratch
preset = m_resourceProvider->currentPreset();
} else {
m_resourceProvider->setPaintOpPreset(preset);
preset->setOptionsWidget(m_optionWidget);
}
m_presetsPopup->resourceSelected(preset); // this helps update the UI on the brush editor
}
void KisPaintopBox::slotCanvasResourceChangeAttempted(int key, const QVariant &value)
{
Q_UNUSED(value);
if (key == KoCanvasResourceProvider::ForegroundColor) {
slotUnsetEraseMode();
}
}
void KisPaintopBox::slotCanvasResourceChanged(int key, const QVariant &value)
{
if (m_viewManager) {
sender()->blockSignals(true);
KisPaintOpPresetSP preset = m_viewManager->canvasResourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value();
if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) {
QString compositeOp = preset->settings()->getString("CompositeOp");
updateCompositeOp(compositeOp);
resourceSelected(preset);
}
if (key == KisCanvasResourceProvider::CurrentPaintOpPreset) {
/**
* Update currently selected preset in both the popup widgets
*/
m_presetsChooserPopup->canvasResourceChanged(preset);
m_presetsPopup->currentPresetChanged(preset);
}
if (key == KisCanvasResourceProvider::CurrentCompositeOp) {
if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) {
updateCompositeOp(m_resourceProvider->currentCompositeOp());
}
}
if (key == KisCanvasResourceProvider::Size) {
setSliderValue("size", m_resourceProvider->size());
}
if (key == KisCanvasResourceProvider::Opacity) {
setSliderValue("opacity", m_resourceProvider->opacity());
}
if (key == KisCanvasResourceProvider::Flow) {
setSliderValue("flow", m_resourceProvider->flow());
}
if (key == KisCanvasResourceProvider::EraserMode) {
m_eraseAction->setChecked(value.toBool());
}
if (key == KisCanvasResourceProvider::DisablePressure) {
m_disablePressureAction->setChecked(value.toBool());
}
if (key == KisCanvasResourceProvider::MirrorHorizontal) {
m_hMirrorAction->setChecked(value.toBool());
}
if (key == KisCanvasResourceProvider::MirrorVertical) {
m_vMirrorAction->setChecked(value.toBool());
}
sender()->blockSignals(false);
}
}
void KisPaintopBox::slotSetupDefaultPreset()
{
KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp());
preset->setOptionsWidget(m_optionWidget);
m_resourceProvider->setPaintOpPreset(preset);
// tell the brush editor that the resource has changed
// so it can update everything
m_presetsPopup->resourceSelected(preset);
}
void KisPaintopBox::slotNodeChanged(const KisNodeSP node)
{
if (m_previousNode.isValid() && m_previousNode->paintDevice())
disconnect(m_previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*)));
// Reconnect colorspace change of node
if (node && node->paintDevice()) {
connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*)));
m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID);
m_previousNode = node;
slotColorSpaceChanged(node->colorSpace());
}
if (m_optionWidget) {
m_optionWidget->setNode(node);
}
}
void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace)
{
m_cmbCompositeOp->validate(colorSpace);
}
void KisPaintopBox::slotToggleEraseMode(bool checked)
{
const bool oldEraserMode = m_resourceProvider->eraserMode();
m_resourceProvider->setEraserMode(checked);
if (oldEraserMode != checked && m_eraserBrushSizeEnabled) {
const qreal currentSize = m_resourceProvider->size();
KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings();
// remember brush size. set the eraser size to the normal brush size if not set
if (checked) {
settings->setSavedBrushSize(currentSize);
if (qFuzzyIsNull(settings->savedEraserSize())) {
settings->setSavedEraserSize(currentSize);
}
} else {
settings->setSavedEraserSize(currentSize);
if (qFuzzyIsNull(settings->savedBrushSize())) {
settings->setSavedBrushSize(currentSize);
}
}
//update value in UI (this is the main place the value is 'stored' in memory)
qreal newSize = checked ? settings->savedEraserSize() : settings->savedBrushSize();
m_resourceProvider->setSize(newSize);
}
if (oldEraserMode != checked && m_eraserBrushOpacityEnabled) {
const qreal currentOpacity = m_resourceProvider->opacity();
KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings();
// remember brush opacity. set the eraser opacity to the normal brush opacity if not set
if (checked) {
settings->setSavedBrushOpacity(currentOpacity);
if (qFuzzyIsNull(settings->savedEraserOpacity())) {
settings->setSavedEraserOpacity(currentOpacity);
}
} else {
settings->setSavedEraserOpacity(currentOpacity);
if (qFuzzyIsNull(settings->savedBrushOpacity())) {
settings->setSavedBrushOpacity(currentOpacity);
}
}
//update value in UI (this is the main place the value is 'stored' in memory)
qreal newOpacity = checked ? settings->savedEraserOpacity() : settings->savedBrushOpacity();
m_resourceProvider->setOpacity(newOpacity);
}
}
void KisPaintopBox::slotSetCompositeMode(int index)
{
Q_UNUSED(index);
QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id();
m_resourceProvider->setCurrentCompositeOp(compositeOp);
}
void KisPaintopBox::slotHorizontalMirrorChanged(bool value)
{
m_resourceProvider->setMirrorHorizontal(value);
}
void KisPaintopBox::slotVerticalMirrorChanged(bool value)
{
m_resourceProvider->setMirrorVertical(value);
}
void KisPaintopBox::sliderChanged(int n)
{
if (!m_optionWidget) // widget will not exist if the are no documents open
return;
KisSignalsBlocker blocker(m_optionWidget);
// flow and opacity are shown as 0-100% on the UI, but their data is actually 0-1. Convert those two values
// back for further work
qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value()/100;
qreal flow = m_sliderChooser[n]->getWidget("flow")->value()/100;
qreal size = m_sliderChooser[n]->getWidget("size")->value();
setSliderValue("opacity", opacity);
setSliderValue("flow" , flow);
setSliderValue("size" , size);
if (m_presetsEnabled) {
// IMPORTANT: set the PaintOp size before setting the other properties
// it won't work the other way
// TODO: why?!
m_resourceProvider->setSize(size);
m_resourceProvider->setOpacity(opacity);
m_resourceProvider->setFlow(flow);
KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings());
propertiesProxy->setProperty("OpacityValue", opacity);
propertiesProxy->setProperty("FlowValue", flow);
m_optionWidget->setConfigurationSafe(m_resourceProvider->currentPreset()->settings().data());
} else {
m_resourceProvider->setOpacity(opacity);
}
m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset());
}
void KisPaintopBox::slotSlider1Changed()
{
sliderChanged(0);
}
void KisPaintopBox::slotSlider2Changed()
{
sliderChanged(1);
}
void KisPaintopBox::slotSlider3Changed()
{
sliderChanged(2);
}
void KisPaintopBox::slotToolChanged(KoCanvasController* canvas, int toolId)
{
Q_UNUSED(canvas);
Q_UNUSED(toolId);
if (!m_viewManager->canvasBase()) return;
QString id = KoToolManager::instance()->activeToolId();
KisTool* tool = dynamic_cast(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id));
if (tool) {
int flags = tool->flags();
if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) {
setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY);
} else {
setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY);
}
if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) {
setWidgetState(ENABLE_PRESETS);
if (!m_resourceProvider->currentPreset()) return;
// block updates of avoid some over updating of the option widget
m_blockUpdate = true;
setSliderValue("size", m_resourceProvider->size());
{
qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity();
m_resourceProvider->setOpacity(opacity);
setSliderValue("opacity", opacity);
setWidgetState(ENABLE_OPACITY);
}
{
setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow());
setWidgetState(ENABLE_FLOW);
}
{
updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp());
setWidgetState(ENABLE_COMPOSITEOP);
}
m_blockUpdate = false;
m_presetsEnabled = true;
} else {
setWidgetState(DISABLE_PRESETS);
m_presetsEnabled = false;
}
if (flags & KisTool::FLAG_USES_CUSTOM_SIZE) {
setWidgetState(ENABLE_SIZE | ENABLE_FLOW);
} else {
setWidgetState(DISABLE_SIZE | DISABLE_FLOW);
}
} else setWidgetState(DISABLE_ALL);
}
void KisPaintopBox::slotPreviousFavoritePreset()
{
if (!m_favoriteResourceManager) return;
QVector presets = m_favoriteResourceManager->favoritePresetNamesList();
for (int i=0; i < presets.size(); ++i) {
if (m_resourceProvider->currentPreset() &&
m_resourceProvider->currentPreset()->name() == presets[i]) {
if (i > 0) {
m_favoriteResourceManager->slotChangeActivePaintop(i - 1);
} else {
m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1);
}
//floating message should have least 2 lines, otherwise
//preset thumbnail will be too small to distinguish
//(because size of image on floating message depends on amount of lines in msg)
m_viewManager->showFloatingMessage(
i18n("%1\nselected",
m_resourceProvider->currentPreset()->name()),
QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
return;
}
}
}
void KisPaintopBox::slotNextFavoritePreset()
{
if (!m_favoriteResourceManager) return;
QVector presets = m_favoriteResourceManager->favoritePresetNamesList();
for(int i = 0; i < presets.size(); ++i) {
if (m_resourceProvider->currentPreset()->name() == presets[i]) {
if (i < m_favoriteResourceManager->numFavoritePresets() - 1) {
m_favoriteResourceManager->slotChangeActivePaintop(i + 1);
} else {
m_favoriteResourceManager->slotChangeActivePaintop(0);
}
m_viewManager->showFloatingMessage(
i18n("%1\nselected",
m_resourceProvider->currentPreset()->name()),
QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
return;
}
}
}
void KisPaintopBox::slotSwitchToPreviousPreset()
{
if (m_resourceProvider->previousPreset()) {
//qDebug() << "slotSwitchToPreviousPreset();" << m_resourceProvider->previousPreset();
setCurrentPaintop(m_resourceProvider->previousPreset());
m_viewManager->showFloatingMessage(
i18n("%1\nselected",
m_resourceProvider->currentPreset()->name()),
QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
}
}
void KisPaintopBox::slotUnsetEraseMode()
{
m_eraseAction->setChecked(false);
}
void KisPaintopBox::slotToggleAlphaLockMode(bool checked)
{
if (checked) {
m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-locked"));
} else {
m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-unlocked"));
}
m_resourceProvider->setGlobalAlphaLock(checked);
}
void KisPaintopBox::slotDisablePressureMode(bool checked)
{
if (checked) {
m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure"));
} else {
m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked"));
}
m_resourceProvider->setDisablePressure(checked);
}
void KisPaintopBox::slotReloadPreset()
{
KisSignalsBlocker blocker(m_optionWidget);
// Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading.
KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
QSharedPointer preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name());
if (preset) {
preset->load(KisGlobalResourcesInterface::instance());
}
if (m_resourceProvider->currentPreset() != preset) {
m_resourceProvider->setPaintOpPreset(preset);
} else {
/**
* HACK ALERT: here we emit a private signal from the resource manager to
* ensure that all the subscribers of resource-changed signal got the
* notification. That is especially important for
* KisPaintopTransformationConnector. See bug 392622.
*/
emit m_resourceProvider->resourceManager()->canvasResourceChanged(
KisCanvasResourceProvider::CurrentPaintOpPreset,
QVariant::fromValue(preset));
}
}
void KisPaintopBox::slotGuiChangedCurrentPreset() // Called only when UI is changed and not when preset is changed
{
KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
{
/**
* Here we postpone all the settings updates events until the entire writing
* operation will be finished. As soon as it is finished, the updates will be
* emitted happily (if there were any).
*/
KisPaintOpPreset::UpdatedPostponer postponer(preset);
QStringList preserveProperties;
preserveProperties << "lodUserAllowed";
preserveProperties << "lodSizeThreshold";
// clear all the properties before dumping the stuff into the preset,
// some of the options add the values incrementally
// (e.g. KisPaintOpUtils::RequiredBrushFilesListTag), therefore they
// may add up if we pass the same preset multiple times
preset->settings()->resetSettings(preserveProperties);
m_optionWidget->writeConfigurationSafe(const_cast(preset->settings().data()));
}
// we should also update the preset strip to update the status of the "dirty" mark
m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset());
// TODO!!!!!!!!
//m_presetsPopup->updateViewSettings();
}
void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p)
{
QMapIterator i(p->getProperties());
while (i.hasNext()) {
i.next();
m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value()));
if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) {
m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous");
}
}
slotGuiChangedCurrentPreset();
}
void KisPaintopBox::slotDropLockedOption(KisPropertiesConfigurationSP p)
{
KisSignalsBlocker blocker(m_optionWidget);
KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
{
KisResourceDirtyStateSaver dirtySaver(preset);
QMapIterator i(p->getProperties());
while (i.hasNext()) {
i.next();
if (preset->settings()->hasProperty(i.key() + "_previous")) {
preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous"));
preset->settings()->removeProperty(i.key() + "_previous");
}
}
}
}
void KisPaintopBox::slotDirtyPresetToggled(bool value)
{
if (!value) {
slotReloadPreset();
m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset());
m_presetsPopup->updateViewSettings();
}
m_dirtyPresetsEnabled = value;
KisConfig cfg(false);
cfg.setUseDirtyPresets(m_dirtyPresetsEnabled);
}
void KisPaintopBox::slotEraserBrushSizeToggled(bool value)
{
m_eraserBrushSizeEnabled = value;
KisConfig cfg(false);
cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled);
}
void KisPaintopBox::slotEraserBrushOpacityToggled(bool value)
{
m_eraserBrushOpacityEnabled = value;
KisConfig cfg(false);
cfg.setUseEraserBrushOpacity(m_eraserBrushOpacityEnabled);
}
void KisPaintopBox::slotUpdateSelectionIcon()
{
m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal"));
m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical"));
KisConfig cfg(true);
if (!cfg.toolOptionsInDocker() && m_toolOptionsPopupButton) {
m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure"));
}
m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01"));
m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02"));
m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose"));
m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser"));
m_reloadAction->setIcon(KisIconUtils::loadIcon("view-refresh"));
if (m_disablePressureAction->isChecked()) {
m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure"));
} else {
m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked"));
}
}
void KisPaintopBox::slotLockXMirrorToggle(bool toggleLock) {
m_resourceProvider->setMirrorHorizontalLock(toggleLock);
}
void KisPaintopBox::slotLockYMirrorToggle(bool toggleLock) {
m_resourceProvider->setMirrorVerticalLock(toggleLock);
}
void KisPaintopBox::slotHideDecorationMirrorX(bool toggled) {
m_resourceProvider->setMirrorHorizontalHideDecorations(toggled);
}
void KisPaintopBox::slotHideDecorationMirrorY(bool toggled) {
m_resourceProvider->setMirrorVerticalHideDecorations(toggled);
}
void KisPaintopBox::slotMoveToCenterMirrorX() {
m_resourceProvider->mirrorHorizontalMoveCanvasToCenter();
}
void KisPaintopBox::slotMoveToCenterMirrorY() {
m_resourceProvider->mirrorVerticalMoveCanvasToCenter();
}
void KisPaintopBox::findDefaultPresets()
{
KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
m_eraserName = "eraser_circle";
m_defaultPresetName = "basic_tip_default";
KisResourceModel *resourceModel = rserver->resourceModel();
for (int i = 0; i < resourceModel->rowCount(); i++) {
QModelIndex idx = resourceModel->index(i, 0);
QString resourceName = idx.data(Qt::UserRole + KisResourceModel::Name).toString().toLower();
QString fileName = idx.data(Qt::UserRole + KisResourceModel::Filename).toString().toLower();
if (resourceName.contains("eraser_circle")) {
m_eraserName = resourceName;
}
else if (resourceName.contains("eraser") || fileName.contains("eraser")) {
m_eraserName = resourceName;
}
if (resourceName.contains("basic_tip_default")) {
m_defaultPresetName = resourceName;
}
else if (resourceName.contains("default") || fileName.contains("default")) {
m_defaultPresetName = resourceName;
}
}
}
diff --git a/libs/ui/kis_popup_palette.cpp b/libs/ui/kis_popup_palette.cpp
index 743ddca690..b0a68d6f70 100644
--- a/libs/ui/kis_popup_palette.cpp
+++ b/libs/ui/kis_popup_palette.cpp
@@ -1,1012 +1,989 @@
/* This file is part of the KDE project
Copyright 2009 Vera Lukman
Copyright 2011 Sven Langkamp
Copyright 2016 Scott Petrovic
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include "kis_canvas2.h"
#include "kis_config.h"
#include "kis_popup_palette.h"
#include "kis_favorite_resource_manager.h"
#include "kis_icon_utils.h"
#include
#include
#include
#include
#include "kis_signal_compressor.h"
#include "brushhud/kis_brush_hud.h"
#include "brushhud/kis_round_hud_button.h"
#include "kis_signals_blocker.h"
#include "kis_canvas_controller.h"
#include "kis_acyclic_signal_connector.h"
#include
#include "KisMouseClickEater.h"
class PopupColorTriangle : public KoTriangleColorSelector
{
public:
PopupColorTriangle(const KoColorDisplayRendererInterface *displayRenderer, QWidget* parent)
: KoTriangleColorSelector(displayRenderer, parent)
, m_dragging(false)
{
}
~PopupColorTriangle() override {}
void tabletEvent(QTabletEvent* event) override {
event->accept();
QMouseEvent* mouseEvent = 0;
// this will tell the pop-up palette widget to close
if(event->button() == Qt::RightButton) {
emit requestCloseContainer();
}
// ignore any tablet events that are done with the right click
// Tablet move events don't return a "button", so catch that too
if(event->button() == Qt::LeftButton || event->type() == QEvent::TabletMove)
{
switch (event->type()) {
case QEvent::TabletPress:
mouseEvent = new QMouseEvent(QEvent::MouseButtonPress, event->pos(),
Qt::LeftButton, Qt::LeftButton, event->modifiers());
m_dragging = true;
mousePressEvent(mouseEvent);
break;
case QEvent::TabletMove:
mouseEvent = new QMouseEvent(QEvent::MouseMove, event->pos(),
(m_dragging) ? Qt::LeftButton : Qt::NoButton,
(m_dragging) ? Qt::LeftButton : Qt::NoButton, event->modifiers());
mouseMoveEvent(mouseEvent);
break;
case QEvent::TabletRelease:
mouseEvent = new QMouseEvent(QEvent::MouseButtonRelease, event->pos(),
Qt::LeftButton,
Qt::LeftButton,
event->modifiers());
m_dragging = false;
mouseReleaseEvent(mouseEvent);
break;
default: break;
}
}
delete mouseEvent;
}
private:
bool m_dragging;
};
KisPopupPalette::KisPopupPalette(KisViewManager* viewManager, KisCoordinatesConverter* coordinatesConverter ,KisFavoriteResourceManager* manager,
const KoColorDisplayRendererInterface *displayRenderer, KisCanvasResourceProvider *provider, QWidget *parent)
: QWidget(parent, Qt::FramelessWindowHint)
, m_coordinatesConverter(coordinatesConverter)
, m_viewManager(viewManager)
, m_actionManager(viewManager->actionManager())
, m_resourceManager(manager)
, m_displayRenderer(displayRenderer)
, m_colorChangeCompressor(new KisSignalCompressor(50, KisSignalCompressor::POSTPONE))
, m_actionCollection(viewManager->actionCollection())
, m_acyclicConnector(new KisAcyclicSignalConnector(this))
, m_clicksEater(new KisMouseClickEater(Qt::RightButton, 1, this))
{
// some UI controls are defined and created based off these variables
const int borderWidth = 3;
if (KisConfig(true).readEntry("popuppalette/usevisualcolorselector", false)) {
KisVisualColorSelector *selector = new KisVisualColorSelector(this);
selector->setAcceptTabletEvents(true);
m_triangleColorSelector = selector;
}
else {
m_triangleColorSelector = new PopupColorTriangle(displayRenderer, this);
connect(m_triangleColorSelector, SIGNAL(requestCloseContainer()), this, SLOT(slotHide()));
}
m_triangleColorSelector->setDisplayRenderer(displayRenderer);
m_triangleColorSelector->setConfig(true,false);
m_triangleColorSelector->move(m_popupPaletteSize/2-m_colorHistoryInnerRadius+borderWidth, m_popupPaletteSize/2-m_colorHistoryInnerRadius+borderWidth);
m_triangleColorSelector->resize(m_popupPaletteSize - 2*m_triangleColorSelector->x(), m_popupPaletteSize - 2*m_triangleColorSelector->y());
m_triangleColorSelector->setVisible(true);
KoColor fgcolor(Qt::black, KoColorSpaceRegistry::instance()->rgb8());
if (m_resourceManager) {
fgcolor = provider->fgColor();
}
m_triangleColorSelector->slotSetColor(fgcolor);
/**
* Tablet support code generates a spurious right-click right after opening
* the window, so we should ignore it. Next right-click will be used for
* closing the popup palette
*/
this->installEventFilter(m_clicksEater);
m_triangleColorSelector->installEventFilter(m_clicksEater);
QRegion maskedRegion(0, 0, m_triangleColorSelector->width(), m_triangleColorSelector->height(), QRegion::Ellipse );
m_triangleColorSelector->setMask(maskedRegion);
//setAttribute(Qt::WA_TranslucentBackground, true);
connect(m_triangleColorSelector, SIGNAL(sigNewColor(KoColor)),
m_colorChangeCompressor.data(), SLOT(start()));
connect(m_colorChangeCompressor.data(), SIGNAL(timeout()),
SLOT(slotEmitColorChanged()));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_triangleColorSelector, SLOT(configurationChanged()));
connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()), this, SLOT(slotDisplayConfigurationChanged()));
m_acyclicConnector->connectForwardKoColor(m_resourceManager, SIGNAL(sigChangeFGColorSelector(KoColor)),
this, SLOT(slotExternalFgColorChanged(KoColor)));
m_acyclicConnector->connectBackwardKoColor(this, SIGNAL(sigChangefGColor(KoColor)),
m_resourceManager, SIGNAL(sigSetFGColor(KoColor)));
connect(this, SIGNAL(sigChangeActivePaintop(int)), m_resourceManager, SLOT(slotChangeActivePaintop(int)));
connect(this, SIGNAL(sigUpdateRecentColor(int)), m_resourceManager, SLOT(slotUpdateRecentColor(int)));
connect(m_resourceManager, SIGNAL(setSelectedColor(int)), SLOT(slotSetSelectedColor(int)));
connect(m_resourceManager, SIGNAL(updatePalettes()), SLOT(slotUpdate()));
connect(m_resourceManager, SIGNAL(hidePalettes()), SLOT(slotHide()));
- // This is used to handle a bug:
- // If pop up palette is visible and a new colour is selected, the new colour
- // will be added when the user clicks on the canvas to hide the palette
- // In general, we want to be able to store recent color if the pop up palette
- // is not visible
- m_timer.setSingleShot(true);
- connect(this, SIGNAL(sigTriggerTimer()), this, SLOT(slotTriggerTimer()));
- connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotEnableChangeFGColor()));
- connect(this, SIGNAL(sigEnableChangeFGColor(bool)), m_resourceManager, SIGNAL(sigEnableChangeColor(bool)));
-
setCursor(Qt::ArrowCursor);
setMouseTracking(true);
setHoveredPreset(-1);
setHoveredColor(-1);
setSelectedColor(-1);
m_brushHud = new KisBrushHud(provider, parent);
m_brushHud->setFixedHeight(int(m_popupPaletteSize));
m_brushHud->setVisible(false);
const int auxButtonSize = 35;
m_settingsButton = new KisRoundHudButton(this);
m_settingsButton->setGeometry(m_popupPaletteSize - 2.2 * auxButtonSize, m_popupPaletteSize - auxButtonSize,
auxButtonSize, auxButtonSize);
connect(m_settingsButton, SIGNAL(clicked()), SLOT(slotShowTagsPopup()));
KisConfig cfg(true);
m_brushHudButton = new KisRoundHudButton(this);
m_brushHudButton->setCheckable(true);
m_brushHudButton->setGeometry(m_popupPaletteSize - 1.0 * auxButtonSize, m_popupPaletteSize - auxButtonSize,
auxButtonSize, auxButtonSize);
connect(m_brushHudButton, SIGNAL(toggled(bool)), SLOT(showHudWidget(bool)));
m_brushHudButton->setChecked(cfg.showBrushHud());
// add some stuff below the pop-up palette that will make it easier to use for tablet people
QVBoxLayout* vLayout = new QVBoxLayout(this); // main layout
QSpacerItem* verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding);
vLayout->addSpacerItem(verticalSpacer); // this should push the box to the bottom
QHBoxLayout* hLayout = new QHBoxLayout();
vLayout->addLayout(hLayout);
mirrorMode = new KisHighlightedToolButton(this);
mirrorMode->setFixedSize(35, 35);
mirrorMode->setToolTip(i18n("Mirror Canvas"));
mirrorMode->setDefaultAction(m_actionCollection->action("mirror_canvas"));
canvasOnlyButton = new KisHighlightedToolButton(this);
canvasOnlyButton->setFixedSize(35, 35);
canvasOnlyButton->setToolTip(i18n("Canvas Only"));
canvasOnlyButton->setDefaultAction(m_actionCollection->action("view_show_canvas_only"));
zoomToOneHundredPercentButton = new QPushButton(this);
zoomToOneHundredPercentButton->setText(i18n("100%"));
zoomToOneHundredPercentButton->setFixedHeight(35);
zoomToOneHundredPercentButton->setToolTip(i18n("Zoom to 100%"));
connect(zoomToOneHundredPercentButton, SIGNAL(clicked(bool)), this, SLOT(slotZoomToOneHundredPercentClicked()));
zoomCanvasSlider = new QSlider(Qt::Horizontal, this);
zoomSliderMinValue = 10; // set in %
zoomSliderMaxValue = 200; // set in %
zoomCanvasSlider->setRange(zoomSliderMinValue, zoomSliderMaxValue);
zoomCanvasSlider->setFixedHeight(35);
zoomCanvasSlider->setValue(m_coordinatesConverter->zoomInPercent());
zoomCanvasSlider->setSingleStep(1);
zoomCanvasSlider->setPageStep(1);
connect(zoomCanvasSlider, SIGNAL(valueChanged(int)), this, SLOT(slotZoomSliderChanged(int)));
connect(zoomCanvasSlider, SIGNAL(sliderPressed()), this, SLOT(slotZoomSliderPressed()));
connect(zoomCanvasSlider, SIGNAL(sliderReleased()), this, SLOT(slotZoomSliderReleased()));
slotUpdateIcons();
hLayout->addWidget(mirrorMode);
hLayout->addWidget(canvasOnlyButton);
hLayout->addWidget(zoomToOneHundredPercentButton);
hLayout->addWidget(zoomCanvasSlider);
setVisible(true);
setVisible(false);
opacityChange = new QGraphicsOpacityEffect(this);
setGraphicsEffect(opacityChange);
// Prevent tablet events from being captured by the canvas
setAttribute(Qt::WA_NoMousePropagation, true);
}
void KisPopupPalette::slotDisplayConfigurationChanged()
{
// Visual Color Selector picks up color space from input
KoColor col = m_viewManager->canvasResourceProvider()->fgColor();
const KoColorSpace *paintingCS = m_displayRenderer->getPaintingColorSpace();
//hack to get around cmyk for now.
if (paintingCS->colorChannelCount()>3) {
paintingCS = KoColorSpaceRegistry::instance()->rgb8();
}
m_triangleColorSelector->slotSetColorSpace(paintingCS);
m_triangleColorSelector->slotSetColor(col);
}
void KisPopupPalette::slotExternalFgColorChanged(const KoColor &color)
{
m_triangleColorSelector->slotSetColor(color);
}
void KisPopupPalette::slotEmitColorChanged()
{
if (isVisible()) {
update();
emit sigChangefGColor(m_triangleColorSelector->getCurrentColor());
}
}
//setting KisPopupPalette properties
int KisPopupPalette::hoveredPreset() const
{
return m_hoveredPreset;
}
void KisPopupPalette::setHoveredPreset(int x)
{
m_hoveredPreset = x;
}
int KisPopupPalette::hoveredColor() const
{
return m_hoveredColor;
}
void KisPopupPalette::setHoveredColor(int x)
{
m_hoveredColor = x;
}
int KisPopupPalette::selectedColor() const
{
return m_selectedColor;
}
void KisPopupPalette::setSelectedColor(int x)
{
m_selectedColor = x;
}
-void KisPopupPalette::slotTriggerTimer()
-{
- m_timer.start(750);
-}
-
-void KisPopupPalette::slotEnableChangeFGColor()
-{
- emit sigEnableChangeFGColor(true);
-}
-
void KisPopupPalette::slotZoomSliderChanged(int zoom) {
emit zoomLevelChanged(zoom);
}
void KisPopupPalette::slotZoomSliderPressed()
{
m_isZoomingCanvas = true;
}
void KisPopupPalette::slotZoomSliderReleased()
{
m_isZoomingCanvas = false;
}
void KisPopupPalette::adjustLayout(const QPoint &p)
{
KIS_ASSERT_RECOVER_RETURN(m_brushHud);
if (isVisible() && parentWidget()) {
float hudMargin = 30.0;
const QRect fitRect = kisGrowRect(parentWidget()->rect(), -20.0); // -20 is widget margin
const QPoint paletteCenterOffset(m_popupPaletteSize / 2, m_popupPaletteSize / 2);
QRect paletteRect = rect();
paletteRect.moveTo(p - paletteCenterOffset);
if (m_brushHudButton->isChecked()) {
m_brushHud->updateGeometry();
paletteRect.adjust(0, 0, m_brushHud->width() + hudMargin, 0);
}
paletteRect = kisEnsureInRect(paletteRect, fitRect);
move(paletteRect.topLeft());
m_brushHud->move(paletteRect.topLeft() + QPoint(m_popupPaletteSize + hudMargin, 0));
m_lastCenterPoint = p;
}
}
void KisPopupPalette::slotUpdateIcons()
{
this->setPalette(qApp->palette());
for(int i=0; ichildren().size(); i++) {
QWidget *w = qobject_cast(this->children().at(i));
if (w) {
w->setPalette(qApp->palette());
}
}
zoomToOneHundredPercentButton->setIcon(m_actionCollection->action("zoom_to_100pct")->icon());
m_brushHud->updateIcons();
m_settingsButton->setIcon(KisIconUtils::loadIcon("tag"));
m_brushHudButton->setOnOffIcons(KisIconUtils::loadIcon("arrow-left"), KisIconUtils::loadIcon("arrow-right"));
}
void KisPopupPalette::showHudWidget(bool visible)
{
KIS_ASSERT_RECOVER_RETURN(m_brushHud);
const bool reallyVisible = visible && m_brushHudButton->isChecked();
if (reallyVisible) {
m_brushHud->updateProperties();
}
m_brushHud->setVisible(reallyVisible);
adjustLayout(m_lastCenterPoint);
KisConfig cfg(false);
cfg.setShowBrushHud(visible);
}
void KisPopupPalette::showPopupPalette(const QPoint &p)
{
showPopupPalette(!isVisible());
adjustLayout(p);
}
void KisPopupPalette::showPopupPalette(bool show)
{
if (show) {
// don't set the zoom slider if we are outside of the zoom slider bounds. It will change the zoom level to within
// the bounds and cause the canvas to jump between the slider's min and max
if (m_coordinatesConverter->zoomInPercent() > zoomSliderMinValue &&
m_coordinatesConverter->zoomInPercent() < zoomSliderMaxValue ){
KisSignalsBlocker b(zoomCanvasSlider);
zoomCanvasSlider->setValue(m_coordinatesConverter->zoomInPercent()); // sync the zoom slider
}
- emit sigEnableChangeFGColor(!show);
- } else {
- emit sigTriggerTimer();
}
setVisible(show);
m_brushHud->setVisible(show && m_brushHudButton->isChecked());
}
//redefinition of setVariable function to change the scope to private
void KisPopupPalette::setVisible(bool b)
{
QWidget::setVisible(b);
}
void KisPopupPalette::setParent(QWidget *parent) {
m_brushHud->setParent(parent);
QWidget::setParent(parent);
}
QSize KisPopupPalette::sizeHint() const
{
return QSize(m_popupPaletteSize, m_popupPaletteSize + 50); // last number is the space for the toolbar below
}
void KisPopupPalette::resizeEvent(QResizeEvent*)
{
}
void KisPopupPalette::paintEvent(QPaintEvent* e)
{
Q_UNUSED(e);
QPainter painter(this);
QPen pen(palette().color(QPalette::Text));
pen.setWidth(3);
painter.setPen(pen);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
// painting background color indicator
QPainterPath bgColor;
bgColor.addEllipse(QPoint( 50, 80), 30, 30);
painter.fillPath(bgColor, m_displayRenderer->toQColor(m_resourceManager->bgColor()));
painter.drawPath(bgColor);
// painting foreground color indicator
QPainterPath fgColor;
fgColor.addEllipse(QPoint( 60, 50), 30, 30);
painter.fillPath(fgColor, m_displayRenderer->toQColor(m_triangleColorSelector->getCurrentColor()));
painter.drawPath(fgColor);
// create a circle background that everything else will go into
QPainterPath backgroundContainer;
float shrinkCircleAmount = 3;// helps the circle when the stroke is put around it
QRectF circleRect(shrinkCircleAmount, shrinkCircleAmount,
m_popupPaletteSize - shrinkCircleAmount*2,m_popupPaletteSize - shrinkCircleAmount*2);
backgroundContainer.addEllipse( circleRect );
painter.fillPath(backgroundContainer,palette().brush(QPalette::Background));
painter.drawPath(backgroundContainer);
// create a path slightly inside the container circle. this will create a 'track' to indicate that we can rotate the canvas
// with the indicator
QPainterPath rotationTrackPath;
shrinkCircleAmount = 18;
QRectF circleRect2(shrinkCircleAmount, shrinkCircleAmount,
m_popupPaletteSize - shrinkCircleAmount*2,m_popupPaletteSize - shrinkCircleAmount*2);
rotationTrackPath.addEllipse( circleRect2 );
pen.setWidth(1);
painter.setPen(pen);
painter.drawPath(rotationTrackPath);
// this thing will help indicate where the starting brush preset is at.
// also what direction they go to give sor order to the presets populated
/*
pen.setWidth(6);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
painter.drawArc(circleRect, (16*90), (16*-30)); // span angle (last parameter) is in 16th of degrees
QPainterPath brushDir;
brushDir.arcMoveTo(circleRect, 60);
brushDir.lineTo(brushDir.currentPosition().x()-5, brushDir.currentPosition().y() - 14);
painter.drawPath(brushDir);
brushDir.lineTo(brushDir.currentPosition().x()-2, brushDir.currentPosition().y() + 6);
painter.drawPath(brushDir);
*/
// the following things needs to be based off the center, so let's translate the painter
painter.translate(m_popupPaletteSize / 2, m_popupPaletteSize / 2);
// create the canvas rotation handle
QPainterPath rotationIndicator = drawRotationIndicator(m_coordinatesConverter->rotationAngle(), true);
painter.fillPath(rotationIndicator,palette().brush(QPalette::Text));
// hover indicator for the canvas rotation
if (m_isOverCanvasRotationIndicator == true) {
painter.save();
QPen pen(palette().color(QPalette::Highlight));
pen.setWidth(2);
painter.setPen(pen);
painter.drawPath(rotationIndicator);
painter.restore();
}
// create a reset canvas rotation indicator to bring the canvas back to 0 degrees
QPainterPath resetRotationIndicator = drawRotationIndicator(0, false);
QPen resetPen(palette().color(QPalette::Text));
resetPen.setWidth(1);
painter.save();
painter.setPen(resetPen);
painter.drawPath(resetRotationIndicator);
painter.restore();
// painting favorite brushes
QList images(m_resourceManager->favoritePresetImages());
// painting favorite brushes pixmap/icon
QPainterPath presetPath;
for (int pos = 0; pos < numSlots(); pos++) {
painter.save();
presetPath = createPathFromPresetIndex(pos);
if (pos < images.size()) {
painter.setClipPath(presetPath);
QRect bounds = presetPath.boundingRect().toAlignedRect();
painter.drawImage(bounds.topLeft() , images.at(pos).scaled(bounds.size() , Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
}
else {
painter.fillPath(presetPath, palette().brush(QPalette::Window)); // brush slot that has no brush in it
}
QPen pen = painter.pen();
pen.setWidth(1);
painter.setPen(pen);
painter.drawPath(presetPath);
painter.restore();
}
if (hoveredPreset() > -1) {
presetPath = createPathFromPresetIndex(hoveredPreset());
QPen pen(palette().color(QPalette::Highlight));
pen.setWidth(3);
painter.setPen(pen);
painter.drawPath(presetPath);
}
// paint recent colors area.
painter.setPen(Qt::NoPen);
float rotationAngle = -360.0 / m_resourceManager->recentColorsTotal();
// there might be no recent colors at the start, so paint a placeholder
if (m_resourceManager->recentColorsTotal() == 0) {
painter.setBrush(Qt::transparent);
QPainterPath emptyRecentColorsPath(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius));
painter.setPen(QPen(palette().color(QPalette::Background).lighter(150), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter.drawPath(emptyRecentColorsPath);
} else {
for (int pos = 0; pos < m_resourceManager->recentColorsTotal(); pos++) {
QPainterPath recentColorsPath(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal()));
//accessing recent color of index pos
painter.fillPath(recentColorsPath, m_displayRenderer->toQColor( m_resourceManager->recentColorAt(pos) ));
painter.drawPath(recentColorsPath);
painter.rotate(rotationAngle);
}
}
// painting hovered color
if (hoveredColor() > -1) {
painter.setPen(QPen(palette().color(QPalette::Highlight), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
if (m_resourceManager->recentColorsTotal() == 1) {
QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius));
painter.drawPath(path_ColorDonut);
} else {
painter.rotate((m_resourceManager->recentColorsTotal() + hoveredColor()) *rotationAngle);
QPainterPath path(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal()));
painter.drawPath(path);
painter.rotate(hoveredColor() * -1 * rotationAngle);
}
}
// painting selected color
if (selectedColor() > -1) {
painter.setPen(QPen(palette().color(QPalette::Highlight).darker(130), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
if (m_resourceManager->recentColorsTotal() == 1) {
QPainterPath path_ColorDonut(drawDonutPathFull(0, 0, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius));
painter.drawPath(path_ColorDonut);
} else {
painter.rotate((m_resourceManager->recentColorsTotal() + selectedColor()) *rotationAngle);
QPainterPath path(drawDonutPathAngle(m_colorHistoryInnerRadius, m_colorHistoryOuterRadius, m_resourceManager->recentColorsTotal()));
painter.drawPath(path);
painter.rotate(selectedColor() * -1 * rotationAngle);
}
}
// if we are actively rotating the canvas or zooming, make the panel slightly transparent to see the canvas better
if(m_isRotatingCanvasIndicator || m_isZoomingCanvas) {
opacityChange->setOpacity(0.4);
} else {
opacityChange->setOpacity(1.0);
}
}
QPainterPath KisPopupPalette::drawDonutPathFull(int x, int y, int inner_radius, int outer_radius)
{
QPainterPath path;
path.addEllipse(QPointF(x, y), outer_radius, outer_radius);
path.addEllipse(QPointF(x, y), inner_radius, inner_radius);
path.setFillRule(Qt::OddEvenFill);
return path;
}
QPainterPath KisPopupPalette::drawDonutPathAngle(int inner_radius, int outer_radius, int limit)
{
QPainterPath path;
path.moveTo(-0.999 * outer_radius * sin(M_PI / limit), 0.999 * outer_radius * cos(M_PI / limit));
path.arcTo(-1 * outer_radius, -1 * outer_radius, 2 * outer_radius, 2 * outer_radius, -90.0 - 180.0 / limit,
360.0 / limit);
path.arcTo(-1 * inner_radius, -1 * inner_radius, 2 * inner_radius, 2 * inner_radius, -90.0 + 180.0 / limit,
- 360.0 / limit);
path.closeSubpath();
return path;
}
QPainterPath KisPopupPalette::drawRotationIndicator(qreal rotationAngle, bool canDrag)
{
// used for canvas rotation. This function gets called twice. Once by the canvas rotation indicator,
// and another time by the reset canvas position
float canvasRotationRadians = qDegreesToRadians(rotationAngle - 90); // -90 will make 0 degrees be at the top
float rotationDialXPosition = qCos(canvasRotationRadians) * (m_popupPaletteSize/2 - 10); // m_popupPaletteSize/2 = radius
float rotationDialYPosition = qSin(canvasRotationRadians) * (m_popupPaletteSize/2 - 10);
QPainterPath canvasRotationIndicator;
int canvasIndicatorSize = 15;
int canvasIndicatorMiddle = canvasIndicatorSize / 2;
QRect indicatorRectangle = QRect( rotationDialXPosition - canvasIndicatorMiddle, rotationDialYPosition - canvasIndicatorMiddle,
canvasIndicatorSize, canvasIndicatorSize );
if (canDrag) {
m_canvasRotationIndicatorRect = indicatorRectangle;
} else {
m_resetCanvasRotationIndicatorRect = indicatorRectangle;
}
canvasRotationIndicator.addEllipse(indicatorRectangle.x(), indicatorRectangle.y(),
indicatorRectangle.width(), indicatorRectangle.height() );
return canvasRotationIndicator;
}
void KisPopupPalette::mouseMoveEvent(QMouseEvent *event)
{
QPointF point = event->localPos();
event->accept();
setToolTip(QString());
setHoveredPreset(-1);
setHoveredColor(-1);
// calculate if we are over the canvas rotation knob
// before we started painting, we moved the painter to the center of the widget, so the X/Y positions are offset. we need to
// correct them first before looking for a click event intersection
float rotationCorrectedXPos = m_canvasRotationIndicatorRect.x() + (m_popupPaletteSize / 2);
float rotationCorrectedYPos = m_canvasRotationIndicatorRect.y() + (m_popupPaletteSize / 2);
QRect correctedCanvasRotationIndicator = QRect(rotationCorrectedXPos, rotationCorrectedYPos,
m_canvasRotationIndicatorRect.width(), m_canvasRotationIndicatorRect.height());
if (correctedCanvasRotationIndicator.contains(point.x(), point.y())) {
m_isOverCanvasRotationIndicator = true;
} else {
m_isOverCanvasRotationIndicator = false;
}
if (m_isRotatingCanvasIndicator) {
// we are rotating the canvas, so calculate the rotation angle based off the center
// calculate the angle we are at first
QPoint widgetCenterPoint = QPoint(m_popupPaletteSize/2, m_popupPaletteSize/2);
float dX = point.x() - widgetCenterPoint.x();
float dY = point.y() - widgetCenterPoint.y();
float finalAngle = qAtan2(dY,dX) * 180 / M_PI; // what we need if we have two points, but don't know the angle
finalAngle = finalAngle + 90; // add 90 degrees so 0 degree position points up
float angleDifference = finalAngle - m_coordinatesConverter->rotationAngle(); // the rotation function accepts diffs, so find it out
KisCanvasController *canvasController =
dynamic_cast(m_viewManager->canvasBase()->canvasController());
canvasController->rotateCanvas(angleDifference);
emit sigUpdateCanvas();
}
// don't highlight the presets if we are in the middle of rotating the canvas
if (m_isRotatingCanvasIndicator == false) {
QPainterPath pathColor(drawDonutPathFull(m_popupPaletteSize / 2, m_popupPaletteSize / 2, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius));
{
int pos = calculatePresetIndex(point, m_resourceManager->numFavoritePresets());
if (pos >= 0 && pos < m_resourceManager->numFavoritePresets()) {
setToolTip(m_resourceManager->favoritePresetNamesList().at(pos));
setHoveredPreset(pos);
}
}
if (pathColor.contains(point)) {
int pos = calculateIndex(point, m_resourceManager->recentColorsTotal());
if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) {
setHoveredColor(pos);
}
}
}
update();
}
void KisPopupPalette::mousePressEvent(QMouseEvent *event)
{
QPointF point = event->localPos();
event->accept();
if (event->button() == Qt::LeftButton) {
//in favorite brushes area
int pos = calculateIndex(point, m_resourceManager->numFavoritePresets());
if (pos >= 0 && pos < m_resourceManager->numFavoritePresets()
&& isPointInPixmap(point, pos)) {
//setSelectedBrush(pos);
update();
}
if (m_isOverCanvasRotationIndicator) {
m_isRotatingCanvasIndicator = true;
}
// reset the canvas if we are over the reset canvas rotation indicator
float rotationCorrectedXPos = m_resetCanvasRotationIndicatorRect.x() + (m_popupPaletteSize / 2);
float rotationCorrectedYPos = m_resetCanvasRotationIndicatorRect.y() + (m_popupPaletteSize / 2);
QRect correctedResetCanvasRotationIndicator = QRect(rotationCorrectedXPos, rotationCorrectedYPos,
m_resetCanvasRotationIndicatorRect.width(), m_resetCanvasRotationIndicatorRect.height());
if (correctedResetCanvasRotationIndicator.contains(point.x(), point.y())) {
float angleDifference = -m_coordinatesConverter->rotationAngle(); // the rotation function accepts diffs
KisCanvasController *canvasController =
dynamic_cast(m_viewManager->canvasBase()->canvasController());
canvasController->rotateCanvas(angleDifference);
emit sigUpdateCanvas();
}
}
}
void KisPopupPalette::slotShowTagsPopup()
{
KisTagModel *model = KisTagModelProvider::tagModel(ResourceType::PaintOpPresets);
QVector tags;
for (int i = 0; i < model->rowCount(); ++i) {
QModelIndex idx = model->index(i, 0);
tags << model->data(idx, Qt::DisplayRole).toString();
}
//std::sort(tags.begin(), tags.end());
if (!tags.isEmpty()) {
QMenu menu;
Q_FOREACH (const QString& tag, tags) {
menu.addAction(tag);
}
QAction *action = menu.exec(QCursor::pos());
if (action) {
for (int i = 0; i < model->rowCount(); ++i) {
QModelIndex idx = model->index(i, 0);
if (model->data(idx, Qt::DisplayRole).toString() == action->text()) {
m_resourceManager->setCurrentTag(model->tagForIndex(idx));
break;
}
}
}
} else {
QWhatsThis::showText(QCursor::pos(),
i18n("There are no tags available to show in this popup. To add presets, you need to tag them and then select the tag here."));
}
}
void KisPopupPalette::slotZoomToOneHundredPercentClicked() {
QAction *action = m_actionCollection->action("zoom_to_100pct");
if (action) {
action->trigger();
}
// also move the zoom slider to 100% position so they are in sync
zoomCanvasSlider->setValue(100);
}
void KisPopupPalette::tabletEvent(QTabletEvent *event) {
event->ignore();
}
void KisPopupPalette::showEvent(QShowEvent *event)
{
m_clicksEater->reset();
QWidget::showEvent(event);
}
void KisPopupPalette::mouseReleaseEvent(QMouseEvent *event)
{
QPointF point = event->localPos();
event->accept();
if (event->buttons() == Qt::NoButton &&
event->button() == Qt::RightButton) {
showPopupPalette(false);
return;
}
m_isOverCanvasRotationIndicator = false;
m_isRotatingCanvasIndicator = false;
if (event->button() == Qt::LeftButton) {
QPainterPath pathColor(drawDonutPathFull(m_popupPaletteSize / 2, m_popupPaletteSize / 2, m_colorHistoryInnerRadius, m_colorHistoryOuterRadius));
//in favorite brushes area
if (hoveredPreset() > -1) {
//setSelectedBrush(hoveredBrush());
emit sigChangeActivePaintop(hoveredPreset());
}
if (pathColor.contains(point)) {
int pos = calculateIndex(point, m_resourceManager->recentColorsTotal());
if (pos >= 0 && pos < m_resourceManager->recentColorsTotal()) {
emit sigUpdateRecentColor(pos);
}
}
}
}
int KisPopupPalette::calculateIndex(QPointF point, int n)
{
calculatePresetIndex(point, n);
//translate to (0,0)
point.setX(point.x() - m_popupPaletteSize / 2);
point.setY(point.y() - m_popupPaletteSize / 2);
//rotate
float smallerAngle = M_PI / 2 + M_PI / n - atan2(point.y(), point.x());
float radius = sqrt((float)point.x() * point.x() + point.y() * point.y());
point.setX(radius * cos(smallerAngle));
point.setY(radius * sin(smallerAngle));
//calculate brush index
int pos = floor(acos(point.x() / radius) * n / (2 * M_PI));
if (point.y() < 0) pos = n - pos - 1;
return pos;
}
bool KisPopupPalette::isPointInPixmap(QPointF &point, int pos)
{
if (createPathFromPresetIndex(pos).contains(point + QPointF(-m_popupPaletteSize / 2, -m_popupPaletteSize / 2))) {
return true;
}
return false;
}
KisPopupPalette::~KisPopupPalette()
{
}
QPainterPath KisPopupPalette::createPathFromPresetIndex(int index)
{
qreal angleSlice = 360.0 / numSlots() ; // how many degrees each slice will get
// the starting angle of the slice we need to draw. the negative sign makes us go clockwise.
// adding 90 degrees makes us start at the top. otherwise we would start at the right
qreal startingAngle = -(index * angleSlice) + 90;
// the radius will get smaller as the amount of presets shown increases. 10 slots == 41
qreal radians = qDegreesToRadians((360.0/10)/2);
qreal maxRadius = (m_colorHistoryOuterRadius * qSin(radians) / (1-qSin(radians)))-2;
radians = qDegreesToRadians(angleSlice/2);
qreal presetRadius = m_colorHistoryOuterRadius * qSin(radians) / (1-qSin(radians));
//If we assume that circles will mesh like a hexagonal grid, then 3.5r is the size of two hexagons interlocking.
qreal length = m_colorHistoryOuterRadius + presetRadius;
// can we can fit in a second row? We don't want the preset icons to get too tiny.
if (maxRadius > presetRadius) {
//redo all calculations assuming a second row.
if (numSlots() % 2) {
angleSlice = 360.0/(numSlots()+1);
startingAngle = -(index * angleSlice) + 90;
}
if (numSlots() != m_cachedNumSlots){
qreal tempRadius = presetRadius;
qreal distance = 0;
do{
tempRadius+=0.1;
// Calculate the XY of two adjectant circles using this tempRadius.
qreal length1 = m_colorHistoryOuterRadius + tempRadius;
qreal length2 = m_colorHistoryOuterRadius + ((maxRadius*2)-tempRadius);
qreal pathX1 = length1 * qCos(qDegreesToRadians(startingAngle)) - tempRadius;
qreal pathY1 = -(length1) * qSin(qDegreesToRadians(startingAngle)) - tempRadius;
qreal startingAngle2 = -(index+1 * angleSlice) + 90;
qreal pathX2 = length2 * qCos(qDegreesToRadians(startingAngle2)) - tempRadius;
qreal pathY2 = -(length2) * qSin(qDegreesToRadians(startingAngle2)) - tempRadius;
// Use Pythagorean Theorem to calculate the distance between these two values.
qreal m1 = pathX2-pathX1;
qreal m2 = pathY2-pathY1;
distance = sqrt((m1*m1)+(m2*m2));
}
//As long at there's more distance than the radius of the two presets, continue increasing the radius.
while((tempRadius+1)*2 < distance);
m_cachedRadius = tempRadius;
}
m_cachedNumSlots = numSlots();
presetRadius = m_cachedRadius;
length = m_colorHistoryOuterRadius + presetRadius;
if (index % 2) {
length = m_colorHistoryOuterRadius + ((maxRadius*2)-presetRadius);
}
}
QPainterPath path;
qreal pathX = length * qCos(qDegreesToRadians(startingAngle)) - presetRadius;
qreal pathY = -(length) * qSin(qDegreesToRadians(startingAngle)) - presetRadius;
qreal pathDiameter = 2 * presetRadius; // distance is used to calculate the X/Y in addition to the preset circle size
path.addEllipse(pathX, pathY, pathDiameter, pathDiameter);
return path;
}
int KisPopupPalette::calculatePresetIndex(QPointF point, int /*n*/)
{
for(int i = 0; i < numSlots(); i++)
{
QPointF adujustedPoint = point - QPointF(m_popupPaletteSize/2, m_popupPaletteSize/2);
if(createPathFromPresetIndex(i).contains(adujustedPoint))
{
return i;
}
}
return -1;
}
int KisPopupPalette::numSlots()
{
KisConfig config(true);
return qMax(config.favoritePresets(), 10);
}
diff --git a/libs/ui/kis_popup_palette.h b/libs/ui/kis_popup_palette.h
index 51732f0e29..8938c7732b 100644
--- a/libs/ui/kis_popup_palette.h
+++ b/libs/ui/kis_popup_palette.h
@@ -1,191 +1,179 @@
/* This file is part of the KDE project
Copyright 2009 Vera Lukman
Copyright 2016 Scott Petrovic
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KIS_POPUP_PALETTE_H
#define KIS_POPUP_PALETTE_H
#include
#include
#include
#include
#include "KisViewManager.h"
#include "kactioncollection.h"
#include "kis_tool_button.h"
#include "KisHighlightedToolButton.h"
#include
class KisFavoriteResourceManager;
class QWidget;
class KoColor;
class KoTriangleColorSelector;
class KisSignalCompressor;
class KisBrushHud;
class KisRoundHudButton;
class KisCanvasResourceProvider;
class KisVisualColorSelector;
class KisAcyclicSignalConnector;
class KisMouseClickEater;
class KisPopupPalette : public QWidget
{
Q_OBJECT
Q_PROPERTY(int hoveredPreset READ hoveredPreset WRITE setHoveredPreset)
Q_PROPERTY(int hoveredColor READ hoveredColor WRITE setHoveredColor)
Q_PROPERTY(int selectedColor READ selectedColor WRITE setSelectedColor)
public:
KisPopupPalette(KisViewManager*, KisCoordinatesConverter* ,KisFavoriteResourceManager*, const KoColorDisplayRendererInterface *displayRenderer,
KisCanvasResourceProvider *provider, QWidget *parent = 0);
~KisPopupPalette() override;
QSize sizeHint() const override;
void showPopupPalette(const QPoint&);
void showPopupPalette(bool b);
//functions to set up selectedBrush
void setSelectedBrush(int x);
int selectedBrush() const;
//functions to set up selectedColor
void setSelectedColor(int x);
int selectedColor() const;
void setParent(QWidget *parent);
void tabletEvent(QTabletEvent *event) override;
protected:
void showEvent(QShowEvent *event) override;
void paintEvent(QPaintEvent*) override;
void resizeEvent(QResizeEvent*) override;
void mouseReleaseEvent(QMouseEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void mousePressEvent(QMouseEvent*) override;
//functions to calculate index of favorite brush or recent color in array
//n is the total number of favorite brushes or recent colors
int calculateIndex(QPointF, int n);
int calculatePresetIndex(QPointF, int n);
//functions to set up hoveredBrush
void setHoveredPreset(int x);
int hoveredPreset() const;
//functions to set up hoveredColor
void setHoveredColor(int x);
int hoveredColor() const;
private:
void setVisible(bool b) override;
QPainterPath drawDonutPathFull(int, int, int, int);
QPainterPath drawDonutPathAngle(int, int, int);
QPainterPath drawRotationIndicator(qreal rotationAngle, bool canDrag);
bool isPointInPixmap(QPointF&, int pos);
QPainterPath createPathFromPresetIndex(int index);
int numSlots();
void adjustLayout(const QPoint &p);
private:
int m_hoveredPreset {0};
int m_hoveredColor {0};
int m_selectedColor {0};
KisCoordinatesConverter *m_coordinatesConverter;
KisViewManager *m_viewManager;
KisActionManager *m_actionManager;
KisFavoriteResourceManager *m_resourceManager;
KisColorSelectorInterface *m_triangleColorSelector {0};
const KoColorDisplayRendererInterface *m_displayRenderer;
QScopedPointer m_colorChangeCompressor;
KActionCollection *m_actionCollection;
- QTimer m_timer;
-
KisBrushHud *m_brushHud {0};
float m_popupPaletteSize {385.0};
float m_colorHistoryInnerRadius {72.0};
qreal m_colorHistoryOuterRadius {92.0};
KisRoundHudButton *m_settingsButton {0};
KisRoundHudButton *m_brushHudButton {0};
QPoint m_lastCenterPoint;
QRect m_canvasRotationIndicatorRect;
QRect m_resetCanvasRotationIndicatorRect;
bool m_isOverCanvasRotationIndicator {false};
bool m_isRotatingCanvasIndicator {false};
bool m_isZoomingCanvas {false};
KisHighlightedToolButton *mirrorMode {0};
KisHighlightedToolButton *canvasOnlyButton {0};
QPushButton *zoomToOneHundredPercentButton {0};
QSlider *zoomCanvasSlider {0};
int zoomSliderMinValue {10};
int zoomSliderMaxValue {200};
KisAcyclicSignalConnector *m_acyclicConnector = 0;
int m_cachedNumSlots {0};
qreal m_cachedRadius {0.0};
// updates the transparency and effects of the whole widget
QGraphicsOpacityEffect *opacityChange {0};
KisMouseClickEater *m_clicksEater;
Q_SIGNALS:
void sigChangeActivePaintop(int);
void sigUpdateRecentColor(int);
void sigChangefGColor(const KoColor&);
void sigUpdateCanvas();
void zoomLevelChanged(int);
- // These are used to handle a bug:
- // If pop up palette is visible and a new colour is selected, the new colour
- // will be added when the user clicks on the canvas to hide the palette
- // In general, we want to be able to store recent color if the pop up palette
- // is not visible
- void sigEnableChangeFGColor(bool);
- void sigTriggerTimer();
-
public Q_SLOTS:
void slotUpdateIcons();
private Q_SLOTS:
void slotDisplayConfigurationChanged();
void slotExternalFgColorChanged(const KoColor &color);
void slotEmitColorChanged();
void slotSetSelectedColor(int x) { setSelectedColor(x); update(); }
- void slotTriggerTimer();
- void slotEnableChangeFGColor();
void slotUpdate() { update(); }
void slotHide() { showPopupPalette(false); }
void slotShowTagsPopup();
void showHudWidget(bool visible);
void slotZoomToOneHundredPercentClicked();
void slotZoomSliderChanged(int zoom);
void slotZoomSliderPressed();
void slotZoomSliderReleased();
};
#endif // KIS_POPUP_PALETTE_H
diff --git a/libs/ui/tool/kis_resources_snapshot.cpp b/libs/ui/tool/kis_resources_snapshot.cpp
index d42043ebab..3fe531e363 100644
--- a/libs/ui/tool/kis_resources_snapshot.cpp
+++ b/libs/ui/tool/kis_resources_snapshot.cpp
@@ -1,446 +1,450 @@
/*
* Copyright (c) 2011 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_resources_snapshot.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_canvas_resource_provider.h"
#include "filter/kis_filter_configuration.h"
#include "kis_image.h"
#include "kis_paint_device.h"
#include "kis_paint_layer.h"
#include "kis_selection.h"
#include "kis_selection_mask.h"
#include "kis_algebra_2d.h"
struct KisResourcesSnapshot::Private {
Private()
: currentPattern(0)
, currentGradient(0)
, currentGenerator(0)
, compositeOp(0)
{
}
KisImageSP image;
KisDefaultBoundsBaseSP bounds;
KoColor currentFgColor;
KoColor currentBgColor;
KoPatternSP currentPattern;
KoAbstractGradientSP currentGradient;
KisPaintOpPresetSP currentPaintOpPreset;
KisNodeSP currentNode;
qreal currentExposure;
KisFilterConfigurationSP currentGenerator;
QPointF axesCenter;
bool mirrorMaskHorizontal = false;
bool mirrorMaskVertical = false;
quint8 opacity = OPACITY_OPAQUE_U8;
QString compositeOpId = COMPOSITE_OVER;
const KoCompositeOp *compositeOp;
KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush;
KisPainter::FillStyle fillStyle = KisPainter::FillStyleForegroundColor;
QTransform fillTransform = QTransform();
bool globalAlphaLock = false;
qreal effectiveZoom = 1.0;
bool presetAllowsLod = false;
KisSelectionSP selectionOverride;
bool hasOverrideSelection = false;
};
KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceProvider *resourceManager, KisDefaultBoundsBaseSP bounds)
: m_d(new Private())
{
m_d->image = image;
if (!bounds) {
bounds = new KisDefaultBounds(m_d->image);
}
m_d->bounds = bounds;
m_d->currentFgColor = resourceManager->resource(KoCanvasResourceProvider::ForegroundColor).value();
m_d->currentBgColor = resourceManager->resource(KoCanvasResourceProvider::BackgroundColor).value();
m_d->currentPattern = resourceManager->resource(KisCanvasResourceProvider::CurrentPattern).value();
m_d->currentGradient = resourceManager->resource(KisCanvasResourceProvider::CurrentGradient).value();
/**
* We should deep-copy the preset, so that long-running actions
* will have correct brush parameters. Theoretically this cloning
* can be expensive, but according to measurements, it takes
* something like 0.1 ms for an average preset.
*/
KisPaintOpPresetSP p = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value();
if (p) {
m_d->currentPaintOpPreset = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value()->cloneWithResourcesSnapshot();
}
#ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND
KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset);
#endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */
m_d->currentExposure = resourceManager->resource(KisCanvasResourceProvider::HdrExposure).toDouble();
m_d->currentGenerator = resourceManager->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value();
if (m_d->currentGenerator) {
m_d->currentGenerator = m_d->currentGenerator->cloneWithResourcesSnapshot();
}
QPointF relativeAxesCenter(0.5, 0.5);
if (m_d->image) {
relativeAxesCenter = m_d->image->mirrorAxesCenter();
}
m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds());
m_d->mirrorMaskHorizontal = resourceManager->resource(KisCanvasResourceProvider::MirrorHorizontal).toBool();
m_d->mirrorMaskVertical = resourceManager->resource(KisCanvasResourceProvider::MirrorVertical).toBool();
qreal normOpacity = resourceManager->resource(KisCanvasResourceProvider::Opacity).toDouble();
m_d->opacity = quint8(normOpacity * OPACITY_OPAQUE_U8);
m_d->compositeOpId = resourceManager->resource(KisCanvasResourceProvider::CurrentEffectiveCompositeOp).toString();
setCurrentNode(currentNode);
/**
* Fill and Stroke styles are not a part of the resource manager
* so the tools should set them manually
* TODO: port stroke and fill styles to be a part
* of the resource manager
*/
m_d->strokeStyle = KisPainter::StrokeStyleBrush;
m_d->fillStyle = KisPainter::FillStyleNone;
m_d->globalAlphaLock = resourceManager->resource(KisCanvasResourceProvider::GlobalAlphaLock).toBool();
m_d->effectiveZoom = resourceManager->resource(KisCanvasResourceProvider::EffectiveZoom).toDouble();
m_d->presetAllowsLod = resourceManager->resource(KisCanvasResourceProvider::EffectiveLodAvailablility).toBool();
}
KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds)
: m_d(new Private())
{
m_d->image = image;
if (!bounds) {
bounds = new KisDefaultBounds(m_d->image);
}
m_d->bounds = bounds;
#ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND
KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset);
#endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */
QPointF relativeAxesCenter(0.5, 0.5);
if (m_d->image) {
relativeAxesCenter = m_d->image->mirrorAxesCenter();
}
m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds());
m_d->opacity = OPACITY_OPAQUE_U8;
setCurrentNode(currentNode);
/**
* Fill and Stroke styles are not a part of the resource manager
* so the tools should set them manually
* TODO: port stroke and fill styles to be a part
* of the resource manager
*/
m_d->strokeStyle = KisPainter::StrokeStyleBrush;
m_d->fillStyle = KisPainter::FillStyleNone;
}
KisResourcesSnapshot::~KisResourcesSnapshot()
{
delete m_d;
}
void KisResourcesSnapshot::setupPainter(KisPainter* painter)
{
painter->setPaintColor(m_d->currentFgColor);
painter->setBackgroundColor(m_d->currentBgColor);
painter->setGenerator(m_d->currentGenerator);
painter->setPattern(m_d->currentPattern);
painter->setGradient(m_d->currentGradient);
QBitArray lockflags = channelLockFlags();
if (lockflags.size() > 0) {
painter->setChannelFlags(lockflags);
}
painter->setOpacity(m_d->opacity);
painter->setCompositeOp(m_d->compositeOp);
painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical);
painter->setStrokeStyle(m_d->strokeStyle);
painter->setFillStyle(m_d->fillStyle);
painter->setPatternTransform(m_d->fillTransform);
/**
* The paintOp should be initialized the last, because it may
* ask the painter for some options while initialization
*/
painter->setPaintOpPreset(m_d->currentPaintOpPreset, m_d->currentNode, m_d->image);
}
void KisResourcesSnapshot::setupMaskingBrushPainter(KisPainter *painter)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(painter->device());
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->currentPaintOpPreset->hasMaskingPreset());
painter->setPaintColor(KoColor(Qt::white, painter->device()->colorSpace()));
painter->setBackgroundColor(KoColor(Qt::black, painter->device()->colorSpace()));
painter->setOpacity(OPACITY_OPAQUE_U8);
painter->setChannelFlags(QBitArray());
// masked brush always paints in indirect mode
painter->setCompositeOp(COMPOSITE_ALPHA_DARKEN);
painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical);
painter->setStrokeStyle(m_d->strokeStyle);
/**
* The paintOp should be initialized the last, because it may
* ask the painter for some options while initialization
*/
painter->setPaintOpPreset(m_d->currentPaintOpPreset->createMaskingPreset(),
m_d->currentNode, m_d->image);
}
KisPostExecutionUndoAdapter* KisResourcesSnapshot::postExecutionUndoAdapter() const
{
return m_d->image ? m_d->image->postExecutionUndoAdapter() : 0;
}
void KisResourcesSnapshot::setCurrentNode(KisNodeSP node)
{
m_d->currentNode = node;
KisPaintDeviceSP device;
if(m_d->currentNode && (device = m_d->currentNode->paintDevice())) {
m_d->compositeOp = device->colorSpace()->compositeOp(m_d->compositeOpId);
if(!m_d->compositeOp) {
m_d->compositeOp = device->colorSpace()->compositeOp(COMPOSITE_OVER);
}
}
}
void KisResourcesSnapshot::setStrokeStyle(KisPainter::StrokeStyle strokeStyle)
{
m_d->strokeStyle = strokeStyle;
}
void KisResourcesSnapshot::setFillStyle(KisPainter::FillStyle fillStyle)
{
m_d->fillStyle = fillStyle;
}
void KisResourcesSnapshot::setFillTransform(QTransform transform)
{
m_d->fillTransform = transform;
}
KisNodeSP KisResourcesSnapshot::currentNode() const
{
return m_d->currentNode;
}
KisImageSP KisResourcesSnapshot::image() const
{
return m_d->image;
}
bool KisResourcesSnapshot::needsIndirectPainting() const
{
return !m_d->currentPaintOpPreset->settings()->paintIncremental();
}
QString KisResourcesSnapshot::indirectPaintingCompositeOp() const
{
return m_d->currentPaintOpPreset ?
m_d->currentPaintOpPreset->settings()->indirectPaintingCompositeOp()
: COMPOSITE_ALPHA_DARKEN;
}
bool KisResourcesSnapshot::needsMaskingBrushRendering() const
{
return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->hasMaskingPreset();
}
KisSelectionSP KisResourcesSnapshot::activeSelection() const
{
/**
* It is possible to have/use the snapshot without the image. Such
* usecase is present for example in the scratchpad.
*/
if (m_d->hasOverrideSelection) {
return m_d->selectionOverride;
}
KisSelectionSP selection = m_d->image ? m_d->image->globalSelection() : 0;
KisLayerSP layer = qobject_cast(m_d->currentNode.data());
KisSelectionMaskSP mask;
if((layer = qobject_cast(m_d->currentNode.data()))) {
selection = layer->selection();
} else if ((mask = dynamic_cast(m_d->currentNode.data())) &&
mask->selection() == selection) {
selection = 0;
}
return selection;
}
bool KisResourcesSnapshot::needsAirbrushing() const
{
return ( m_d->currentPaintOpPreset
&& m_d->currentPaintOpPreset->settings()
&& m_d->currentPaintOpPreset->settings()->isAirbrushing());
}
qreal KisResourcesSnapshot::airbrushingInterval() const
{
return ( m_d->currentPaintOpPreset
&& m_d->currentPaintOpPreset->settings()
&& m_d->currentPaintOpPreset->settings()->airbrushInterval());
}
bool KisResourcesSnapshot::needsSpacingUpdates() const
{
return ( m_d->currentPaintOpPreset
&& m_d->currentPaintOpPreset->settings()
&& m_d->currentPaintOpPreset->settings()->useSpacingUpdates());
}
void KisResourcesSnapshot::setOpacity(qreal opacity)
{
m_d->opacity = opacity * OPACITY_OPAQUE_U8;
}
quint8 KisResourcesSnapshot::opacity() const
{
return m_d->opacity;
}
const KoCompositeOp* KisResourcesSnapshot::compositeOp() const
{
return m_d->compositeOp;
}
QString KisResourcesSnapshot::compositeOpId() const
{
return m_d->compositeOpId;
}
KoPatternSP KisResourcesSnapshot::currentPattern() const
{
return m_d->currentPattern;
}
KoColor KisResourcesSnapshot::currentFgColor() const
{
return m_d->currentFgColor;
}
KoColor KisResourcesSnapshot::currentBgColor() const
{
return m_d->currentBgColor;
}
KisPaintOpPresetSP KisResourcesSnapshot::currentPaintOpPreset() const
{
return m_d->currentPaintOpPreset;
}
QTransform KisResourcesSnapshot::fillTransform() const
{
return m_d->fillTransform;
}
+KoAbstractGradientSP KisResourcesSnapshot::currentGradient() const
+{
+ return m_d->currentGradient;
+}
QBitArray KisResourcesSnapshot::channelLockFlags() const
{
QBitArray channelFlags;
KisPaintLayer *paintLayer;
if ((paintLayer = dynamic_cast(m_d->currentNode.data()))) {
channelFlags = paintLayer->channelLockFlags();
if (m_d->globalAlphaLock) {
if (channelFlags.isEmpty()) {
channelFlags = paintLayer->colorSpace()->channelFlags(true, true);
}
channelFlags &= paintLayer->colorSpace()->channelFlags(true, false);
}
}
return channelFlags;
}
qreal KisResourcesSnapshot::effectiveZoom() const
{
return m_d->effectiveZoom;
}
bool KisResourcesSnapshot::presetAllowsLod() const
{
return m_d->presetAllowsLod;
}
bool KisResourcesSnapshot::presetNeedsAsynchronousUpdates() const
{
return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->settings()->needsAsynchronousUpdates();
}
void KisResourcesSnapshot::setFGColorOverride(const KoColor &color)
{
m_d->currentFgColor = color;
}
void KisResourcesSnapshot::setBGColorOverride(const KoColor &color)
{
m_d->currentBgColor = color;
}
void KisResourcesSnapshot::setSelectionOverride(KisSelectionSP selection)
{
m_d->selectionOverride = selection;
m_d->hasOverrideSelection = true; // needed if selection passed is null to ignore selection
}
void KisResourcesSnapshot::setBrush(const KisPaintOpPresetSP &brush)
{
m_d->currentPaintOpPreset = brush->cloneWithResourcesSnapshot();
#ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND
KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset);
#endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */
}
diff --git a/libs/ui/tool/kis_resources_snapshot.h b/libs/ui/tool/kis_resources_snapshot.h
index 8dbf87fe6a..53935f01fa 100644
--- a/libs/ui/tool/kis_resources_snapshot.h
+++ b/libs/ui/tool/kis_resources_snapshot.h
@@ -1,109 +1,110 @@
/*
* Copyright (c) 2011 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_RESOURCES_SNAPSHOT_H
#define __KIS_RESOURCES_SNAPSHOT_H
#include "kis_shared.h"
#include "kis_shared_ptr.h"
#include "kis_types.h"
#include "kritaui_export.h"
#include "kis_painter.h"
#include "kis_default_bounds.h"
class KoCanvasResourceProvider;
class KoCompositeOp;
class KisPainter;
class KisPostExecutionUndoAdapter;
class KoPattern;
/**
* @brief The KisResourcesSnapshot class takes a snapshot of the various resources
* like colors and settings used at the begin of a stroke so subsequent
* changes don't impact the running stroke. The main reason for the snapshot is that the
* user can *change* the options while the stroke is being executed in the background.
*/
class KRITAUI_EXPORT KisResourcesSnapshot : public KisShared
{
public:
KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceProvider *resourceManager, KisDefaultBoundsBaseSP bounds = 0);
KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds = 0);
~KisResourcesSnapshot();
void setupPainter(KisPainter *painter);
void setupMaskingBrushPainter(KisPainter *painter);
KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const;
void setCurrentNode(KisNodeSP node);
void setStrokeStyle(KisPainter::StrokeStyle strokeStyle);
void setFillStyle(KisPainter::FillStyle fillStyle);
void setFillTransform(QTransform transform);
KisNodeSP currentNode() const;
KisImageSP image() const;
bool needsIndirectPainting() const;
QString indirectPaintingCompositeOp() const;
bool needsMaskingBrushRendering() const;
/**
* \return currently active selection. Note that it will return
* null if current node *is* the current selection. This
* is done to avoid recursive selection application when
* painting on selectgion masks.
*/
KisSelectionSP activeSelection() const;
bool needsAirbrushing() const;
qreal airbrushingInterval() const;
bool needsSpacingUpdates() const;
void setOpacity(qreal opacity);
quint8 opacity() const;
const KoCompositeOp* compositeOp() const;
QString compositeOpId() const;
KoPatternSP currentPattern() const;
KoColor currentFgColor() const;
KoColor currentBgColor() const;
KisPaintOpPresetSP currentPaintOpPreset() const;
+ KoAbstractGradientSP currentGradient() const;
QTransform fillTransform() const;
/// @return the channel lock flags of the current node with the global override applied
QBitArray channelLockFlags() const;
qreal effectiveZoom() const;
bool presetAllowsLod() const;
bool presetNeedsAsynchronousUpdates() const;
void setFGColorOverride(const KoColor &color);
void setBGColorOverride(const KoColor &color);
void setSelectionOverride(KisSelectionSP selection);
void setBrush(const KisPaintOpPresetSP &brush);
private:
struct Private;
Private * const m_d;
};
typedef KisSharedPtr KisResourcesSnapshotSP;
#endif /* __KIS_RESOURCES_SNAPSHOT_H */
diff --git a/libs/ui/widgets/kis_paintop_presets_popup.cpp b/libs/ui/widgets/kis_paintop_presets_popup.cpp
index c74a69315b..54ab4a3725 100644
--- a/libs/ui/widgets/kis_paintop_presets_popup.cpp
+++ b/libs/ui/widgets/kis_paintop_presets_popup.cpp
@@ -1,845 +1,845 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Boudewijn Rempt
* Copyright (C) 2010 Lukáš Tvrdý
* Copyright (C) 2011 Silvio Heinrich
*
* 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 "widgets/kis_paintop_presets_popup.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 "kis_config.h"
#include "KisResourceServerProvider.h"
#include "kis_lod_availability_widget.h"
#include "kis_signal_auto_connection.h"
#include
// ones from brush engine selector
#include
#include
struct KisPaintOpPresetsPopup::Private
{
public:
Ui_WdgPaintOpSettings uiWdgPaintOpPresetSettings;
QGridLayout *layout;
KisPaintOpConfigWidget *settingsWidget;
QFont smallFont;
KisCanvasResourceProvider *resourceProvider;
KisFavoriteResourceManager *favoriteResManager;
bool detached;
bool ignoreHideEvents;
bool isCreatingBrushFromScratch = false;
QSize minimumSettingsWidgetSize;
QRect detachedGeometry;
KisSignalAutoConnectionsStore widgetConnections;
};
KisPaintOpPresetsPopup::KisPaintOpPresetsPopup(KisCanvasResourceProvider * resourceProvider,
KisFavoriteResourceManager* favoriteResourceManager,
KisPresetSaveWidget* savePresetWidget,
QWidget * parent)
: QWidget(parent)
, m_d(new Private())
{
setObjectName("KisPaintOpPresetsPopup");
setFont(KoDockRegistry::dockFont());
current_paintOpId = "";
m_d->resourceProvider = resourceProvider;
m_d->favoriteResManager = favoriteResourceManager;
m_d->uiWdgPaintOpPresetSettings.setupUi(this);
m_d->layout = new QGridLayout(m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer);
m_d->layout->setSizeConstraint(QLayout::SetFixedSize);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setupScratchPad(resourceProvider, Qt::white);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setCutoutOverlayRect(QRect(25, 25, 200, 200));
m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setToolTip(i18n("The settings for this preset have changed from their default."));
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setToolTip(i18n("Toggle showing presets"));
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setToolTip(i18n("Toggle showing scratchpad"));
m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setToolTip(i18n("Reload the brush preset"));
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setToolTip(i18n("Rename the brush preset"));
// creating a new preset from scratch. Part of the brush presets area
// the menu options will get filled up later when we are generating all available paintops
// in the filter drop-down
newPresetBrushEnginesMenu = new QMenu();
// overwrite existing preset and saving a new preset use the same dialog
saveDialog = savePresetWidget;
saveDialog->scratchPadSetup(resourceProvider);
saveDialog->setFavoriteResourceManager(m_d->favoriteResManager); // this is needed when saving the preset
saveDialog->hide();
// the area on the brush editor for renaming the brush. make sure edit fields are hidden by default
toggleBrushRenameUIActive(false);
// DETAIL and THUMBNAIL view changer
QMenu* menu = new QMenu(this);
menu->setStyleSheet("margin: 6px");
menu->addSection(i18nc("@title Which elements to display (e.g., thumbnails or details)", "Display"));
QActionGroup *actionGroup = new QActionGroup(this);
KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig(true).presetChooserViewMode();
QAction* action = menu->addAction(KisIconUtils::loadIcon("view-preview"), i18n("Thumbnails"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotThumbnailMode()));
action->setCheckable(true);
action->setChecked(mode == KisPresetChooser::THUMBNAIL);
action->setActionGroup(actionGroup);
action = menu->addAction(KisIconUtils::loadIcon("view-list-details"), i18n("Details"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotDetailMode()));
action->setCheckable(true);
action->setChecked(mode == KisPresetChooser::DETAIL);
action->setActionGroup(actionGroup);
// add horizontal slider for the icon size
QSlider* iconSizeSlider = new QSlider(this);
iconSizeSlider->setOrientation(Qt::Horizontal);
iconSizeSlider->setRange(30, 80);
iconSizeSlider->setValue(m_d->uiWdgPaintOpPresetSettings.presetWidget->iconSize());
iconSizeSlider->setMinimumHeight(20);
iconSizeSlider->setMinimumWidth(40);
iconSizeSlider->setTickInterval(10);
QWidgetAction *sliderAction= new QWidgetAction(this);
sliderAction->setDefaultWidget(iconSizeSlider);
menu->addSection(i18n("Icon Size"));
menu->addAction(sliderAction);
// configure the button and assign menu
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setMenu(menu);
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setPopupMode(QToolButton::InstantPopup);
// loading preset from scratch option
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setPopupMode(QToolButton::InstantPopup);
// show/hide buttons
KisConfig cfg(true);
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setCheckable(true);
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setChecked(cfg.scratchpadVisible());
if (cfg.scratchpadVisible()) {
slotSwitchScratchpad(true); // show scratchpad
} else {
slotSwitchScratchpad(false);
}
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setCheckable(true);
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setChecked(false);
slotSwitchShowPresets(false); // hide presets by default
// Connections
connect(m_d->uiWdgPaintOpPresetSettings.paintPresetIcon, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(paintPresetImage()));
connect(saveDialog, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(resourceSelected(KoResourceSP )));
connect (m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton, SIGNAL(clicked(bool)),
this, SLOT(slotRenameBrushActivated()));
connect (m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton, SIGNAL(clicked(bool)),
this, SLOT(slotRenameBrushDeactivated()));
connect(m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton, SIGNAL(clicked(bool)),
this, SLOT(slotSaveRenameCurrentBrush()));
connect(m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField, SIGNAL(returnPressed()),
SLOT(slotSaveRenameCurrentBrush()));
connect(iconSizeSlider, SIGNAL(sliderMoved(int)),
m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSetIconSize(int)));
connect(iconSizeSlider, SIGNAL(sliderReleased()),
m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSaveIconSize()));
connect(m_d->uiWdgPaintOpPresetSettings.showScratchpadButton, SIGNAL(clicked(bool)),
this, SLOT(slotSwitchScratchpad(bool)));
connect(m_d->uiWdgPaintOpPresetSettings.showPresetsButton, SIGNAL(clicked(bool)), this, SLOT(slotSwitchShowPresets(bool)));
connect(m_d->uiWdgPaintOpPresetSettings.eraseScratchPad, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillDefault()));
connect(m_d->uiWdgPaintOpPresetSettings.fillLayer, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillLayer()));
connect(m_d->uiWdgPaintOpPresetSettings.fillGradient, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillGradient()));
connect(m_d->uiWdgPaintOpPresetSettings.fillSolid, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillBackground()));
m_d->settingsWidget = 0;
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
connect(m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton, SIGNAL(clicked()),
this, SLOT(slotSaveBrushPreset()));
connect(m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton, SIGNAL(clicked()),
this, SLOT(slotSaveNewBrushPreset()));
connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()),
this, SIGNAL(reloadPresetClicked()));
connect(m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox, SIGNAL(toggled(bool)),
this, SIGNAL(dirtyPresetToggled(bool)));
connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox, SIGNAL(toggled(bool)),
this, SIGNAL(eraserBrushSizeToggled(bool)));
connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox, SIGNAL(toggled(bool)),
this, SIGNAL(eraserBrushOpacityToggled(bool)));
// preset widget connections
connect(m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SIGNAL(resourceSelected(KoResourceSP )),
this, SIGNAL(signalResourceSelected(KoResourceSP )));
connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SLOT(updateViewSettings()));
connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), SLOT(slotUpdatePresetSettings()));
m_d->detached = false;
m_d->ignoreHideEvents = false;
m_d->minimumSettingsWidgetSize = QSize(0, 0);
m_d->detachedGeometry = QRect(100, 100, 0, 0);
m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox->setChecked(cfg.useDirtyPresets());
m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox->setChecked(cfg.useEraserBrushSize());
m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox->setChecked(cfg.useEraserBrushOpacity());
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setCanvasResourceManager(resourceProvider->resourceManager());
connect(resourceProvider->resourceManager(),
SIGNAL(canvasResourceChanged(int,QVariant)),
SLOT(slotResourceChanged(int,QVariant)));
connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability,
SIGNAL(sigUserChangedLodAvailability(bool)),
SLOT(slotLodAvailabilityChanged(bool)));
connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability,
SIGNAL(sigUserChangedLodThreshold(qreal)),
SLOT(slotLodThresholdChanged(qreal)));
slotResourceChanged(KisCanvasResourceProvider::LodAvailability,
resourceProvider->resourceManager()->
resource(KisCanvasResourceProvider::LodAvailability));
slotResourceChanged(KisCanvasResourceProvider::LodSizeThreshold,
resourceProvider->resourceManager()->
resource(KisCanvasResourceProvider::LodSizeThreshold));
connect(m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatePaintOpFilter()));
connect(m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset, SIGNAL(clicked()), this, SLOT(slotBlackListCurrentPreset()));
updateThemedIcons();
// setup things like the scene construct images, layers, etc that is a one-time thing
- m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setup();
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setup(resourceProvider->resourceManager());
}
void KisPaintOpPresetsPopup::slotBlackListCurrentPreset()
{
KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer();
KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset();
if (rServer->resourceByName(curPreset->name())) {
rServer->removeResourceFromServer(curPreset);
}
}
void KisPaintOpPresetsPopup::slotRenameBrushActivated()
{
toggleBrushRenameUIActive(true);
}
void KisPaintOpPresetsPopup::slotRenameBrushDeactivated()
{
toggleBrushRenameUIActive(false);
}
void KisPaintOpPresetsPopup::toggleBrushRenameUIActive(bool isRenaming)
{
// This function doesn't really do anything except get the UI in a state to rename a brush preset
m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setVisible(isRenaming);
m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton->setVisible(isRenaming);
m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton->setVisible(isRenaming);
// hide these below areas while renaming
m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setVisible(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setEnabled(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setVisible(!isRenaming);
// if the presets area is shown, only then can you show/hide the load default brush
// need to think about weird state when you are in the middle of renaming a brush
// what happens if you try to change presets. maybe we should auto-hide (or disable)
// the presets area in this case
if (m_d->uiWdgPaintOpPresetSettings.presetWidget->isVisible()) {
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(!isRenaming);
}
}
void KisPaintOpPresetsPopup::slotSaveRenameCurrentBrush()
{
// if you are renaming a brush, that is different than updating the settings
// make sure we are in a clean state before renaming. This logic might change,
// but that is what we are going with for now
emit reloadPresetClicked();
// get a reference to the existing (and new) file name and path that we are working with
KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset();
if (!curPreset)
return;
KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer();
QString originalPresetName = curPreset->name();
QString renamedPresetName = m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->text();
QString renamedPresetPathAndFile = renamedPresetName + curPreset->defaultFileExtension();
// create a new brush preset with the name specified and add to resource provider
KisPaintOpPresetSP newPreset = curPreset->clone().dynamicCast();
newPreset->setFilename(renamedPresetPathAndFile); // this also contains the path
newPreset->setName(renamedPresetName);
newPreset->setImage(curPreset->image()); // use existing thumbnail (might not need to do this)
newPreset->setDirty(false);
newPreset->setValid(true);
rServer->addResource(newPreset);
resourceSelected(newPreset); // refresh and select our freshly renamed resource
// Now blacklist the original file
if (rServer->resourceByName(originalPresetName)) {
rServer->removeResourceFromServer(curPreset);
}
m_d->favoriteResManager->updateFavoritePresets();
toggleBrushRenameUIActive(false); // this returns the UI to its original state after saving
slotUpdatePresetSettings(); // update visibility of dirty preset and icon
}
void KisPaintOpPresetsPopup::slotResourceChanged(int key, const QVariant &value)
{
if (key == KisCanvasResourceProvider::LodAvailability) {
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodAvailability(value.toBool());
} else if (key == KisCanvasResourceProvider::LodSizeThreshold) {
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodThreshold(value.toDouble());
} else if (key == KisCanvasResourceProvider::Size) {
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedSize(value.toDouble());
}
}
void KisPaintOpPresetsPopup::slotLodAvailabilityChanged(bool value)
{
m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodAvailability, QVariant(value));
}
void KisPaintOpPresetsPopup::slotLodThresholdChanged(qreal value)
{
m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodSizeThreshold, QVariant(value));
}
KisPaintOpPresetsPopup::~KisPaintOpPresetsPopup()
{
if (m_d->settingsWidget) {
m_d->layout->removeWidget(m_d->settingsWidget);
m_d->settingsWidget->hide();
m_d->settingsWidget->setParent(0);
m_d->settingsWidget = 0;
}
delete m_d;
delete newPresetBrushEnginesMenu;
}
void KisPaintOpPresetsPopup::setPaintOpSettingsWidget(QWidget * widget)
{
if (m_d->settingsWidget) {
m_d->layout->removeWidget(m_d->settingsWidget);
m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer->updateGeometry();
}
m_d->layout->update();
updateGeometry();
m_d->widgetConnections.clear();
m_d->settingsWidget = 0;
if (widget) {
m_d->settingsWidget = dynamic_cast(widget);
KIS_ASSERT_RECOVER_RETURN(m_d->settingsWidget);
KisConfig cfg(true);
if (m_d->settingsWidget->supportScratchBox() && cfg.scratchpadVisible()) {
slotSwitchScratchpad(true);
} else {
slotSwitchScratchpad(false);
}
m_d->widgetConnections.addConnection(m_d->settingsWidget, SIGNAL(sigConfigurationItemChanged()),
this, SLOT(slotUpdateLodAvailability()));
widget->setFont(m_d->smallFont);
QSize hint = widget->sizeHint();
m_d->minimumSettingsWidgetSize = QSize(qMax(hint.width(), m_d->minimumSettingsWidgetSize.width()),
qMax(hint.height(), m_d->minimumSettingsWidgetSize.height()));
widget->setMinimumSize(m_d->minimumSettingsWidgetSize);
m_d->layout->addWidget(widget);
// hook up connections that will monitor if our preset is dirty or not. Show a notification if it is
if (m_d->resourceProvider && m_d->resourceProvider->currentPreset() ) {
KisPaintOpPresetSP preset = m_d->resourceProvider->currentPreset();
m_d->widgetConnections.addConnection(preset->updateProxy(), SIGNAL(sigSettingsChanged()),
this, SLOT(slotUpdatePresetSettings()));
}
m_d->layout->update();
widget->show();
}
slotUpdateLodAvailability();
}
void KisPaintOpPresetsPopup::slotUpdateLodAvailability()
{
if (!m_d->settingsWidget) return;
KisPaintopLodLimitations l = m_d->settingsWidget->lodLimitations();
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setLimitations(l);
}
QImage KisPaintOpPresetsPopup::cutOutOverlay()
{
return m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay();
}
void KisPaintOpPresetsPopup::contextMenuEvent(QContextMenuEvent *e)
{
Q_UNUSED(e);
}
void KisPaintOpPresetsPopup::switchDetached(bool show)
{
if (parentWidget()) {
m_d->detached = !m_d->detached;
if (m_d->detached) {
m_d->ignoreHideEvents = true;
if (show) {
parentWidget()->show();
}
m_d->ignoreHideEvents = false;
}
else {
parentWidget()->hide();
}
KisConfig cfg(false);
cfg.setPaintopPopupDetached(m_d->detached);
}
}
void KisPaintOpPresetsPopup::setCreatingBrushFromScratch(bool enabled)
{
m_d->isCreatingBrushFromScratch = enabled;
}
void KisPaintOpPresetsPopup::resourceSelected(KoResourceSP resource)
{
// this gets called every time the brush editor window is opened
// TODO: this gets called multiple times whenever the preset is changed in the presets area
// the connections probably need to be thought about with this a bit more to keep things in sync
m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(resource);
// find the display name of the brush engine and append it to the selected preset display
QString currentBrushEngineName;
QPixmap currentBrushEngineIcon = QPixmap(26, 26);
currentBrushEngineIcon.fill(Qt::transparent);
for(int i=0; i < sortedBrushEnginesList.length(); i++) {
if (sortedBrushEnginesList.at(i).id == currentPaintOpId() ) {
currentBrushEngineName = sortedBrushEnginesList.at(i).name;
currentBrushEngineIcon = sortedBrushEnginesList.at(i).icon.pixmap(26, 26);
}
}
// brush names have underscores as part of the file name (to help with building). We don't really need underscores
// when viewing the names, so replace them with spaces
QString formattedBrushName = resource->name().replace("_", " ");
m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setText(formattedBrushName);
m_d->uiWdgPaintOpPresetSettings.currentBrushEngineLabel->setText(i18nc("%1 is the name of a brush engine", "%1 Engine", currentBrushEngineName));
m_d->uiWdgPaintOpPresetSettings.currentBrushEngineIcon->setPixmap(currentBrushEngineIcon);
m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setText(resource->name()); // use file name
// get the preset image and pop it into the thumbnail area on the top of the brush editor
m_d->uiWdgPaintOpPresetSettings.presetThumbnailicon->setPixmap(QPixmap::fromImage(resource->image().scaled(55, 55, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
toggleBrushRenameUIActive(false); // reset the UI state of renaming a brush if we are changing brush presets
slotUpdatePresetSettings(); // check to see if the dirty preset icon needs to be shown
}
bool variantLessThan(const KisPaintOpInfo v1, const KisPaintOpInfo v2)
{
return v1.priority < v2.priority;
}
void KisPaintOpPresetsPopup::setPaintOpList(const QList< KisPaintOpFactory* >& list)
{
m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->clear(); // reset combobox list just in case
// create a new list so we can sort it and populate the brush engine combo box
sortedBrushEnginesList.clear(); // just in case this function is called again, don't keep adding to the list
for(int i=0; i < list.length(); i++) {
KisPaintOpInfo paintOpInfo;
paintOpInfo.id = list.at(i)->id();
paintOpInfo.name = list.at(i)->name();
paintOpInfo.icon = list.at(i)->icon();
paintOpInfo.priority = list.at(i)->priority();
sortedBrushEnginesList.append(paintOpInfo);
}
std::stable_sort(sortedBrushEnginesList.begin(), sortedBrushEnginesList.end(), variantLessThan );
// add an "All" option at the front to show all presets
QPixmap emptyPixmap = QPixmap(22,22);
emptyPixmap.fill(Qt::transparent);
// if we create a new brush from scratch, we need a full list of paintops to choose from
// we don't want "All", so populate the list before that is added
newPresetBrushEnginesMenu->actions().clear(); // clean out list in case we run this again
newBrushEngineOptions.clear();
for (int j = 0; j < sortedBrushEnginesList.length(); j++) {
KisAction * newEngineAction = static_cast( newPresetBrushEnginesMenu->addAction(sortedBrushEnginesList[j].name));
newEngineAction->setObjectName(sortedBrushEnginesList[j].id); // we need the ID for changing the paintop when action triggered
newEngineAction->setIcon(sortedBrushEnginesList[j].icon);
newBrushEngineOptions.append(newEngineAction);
connect(newEngineAction, SIGNAL(triggered()), this, SLOT(slotCreateNewBrushPresetEngine()));
}
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setMenu(newPresetBrushEnginesMenu);
// fill the list into the brush combo box
sortedBrushEnginesList.push_front(KisPaintOpInfo(QString("all_options"), i18n("All"), QString(""), QIcon(emptyPixmap), 0 ));
for (int m = 0; m < sortedBrushEnginesList.length(); m++) {
m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->addItem(sortedBrushEnginesList[m].icon, sortedBrushEnginesList[m].name, QVariant(sortedBrushEnginesList[m].id));
}
}
void KisPaintOpPresetsPopup::setCurrentPaintOpId(const QString& paintOpId)
{
current_paintOpId = paintOpId;
}
QString KisPaintOpPresetsPopup::currentPaintOpId() {
return current_paintOpId;
}
void KisPaintOpPresetsPopup::setPresetImage(const QImage& image)
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->setPresetImage(image);
saveDialog->brushPresetThumbnailWidget->setPresetImage(image);
}
void KisPaintOpPresetsPopup::hideEvent(QHideEvent *event)
{
if (m_d->ignoreHideEvents) {
return;
}
if (m_d->detached) {
m_d->detachedGeometry = window()->geometry();
}
QWidget::hideEvent(event);
}
void KisPaintOpPresetsPopup::showEvent(QShowEvent *)
{
if (m_d->detached) {
window()->setGeometry(m_d->detachedGeometry);
}
emit brushEditorShown();
}
void KisPaintOpPresetsPopup::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
if (parentWidget()) {
// Make sure resizing doesn't push this widget out of the screen
QRect screenRect = QApplication::desktop()->availableGeometry(this);
QRect newPositionRect = kisEnsureInRect(parentWidget()->geometry(), screenRect);
parentWidget()->setGeometry(newPositionRect);
}
}
bool KisPaintOpPresetsPopup::detached() const
{
return m_d->detached;
}
void KisPaintOpPresetsPopup::slotSwitchScratchpad(bool visible)
{
// hide all the internal controls except the toggle button
m_d->uiWdgPaintOpPresetSettings.scratchPad->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.fillGradient->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.fillLayer->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.fillSolid->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.scratchpadSidebarLabel->setVisible(visible);
if (visible) {
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left"));
} else {
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right"));
}
KisConfig cfg(false);
cfg.setScratchpadVisible(visible);
}
void KisPaintOpPresetsPopup::slotSwitchShowEditor(bool visible) {
m_d->uiWdgPaintOpPresetSettings.brushEditorSettingsControls->setVisible(visible);
}
void KisPaintOpPresetsPopup::slotSwitchShowPresets(bool visible) {
m_d->uiWdgPaintOpPresetSettings.presetWidget->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.engineFilterLabel->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(visible);
m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(visible);
// we only want a spacer to work when the toggle icon is present. Otherwise the list of presets will shrink
// which is something we don't want
if (visible) {
m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored);
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right"));
} else {
m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left"));
}
}
void KisPaintOpPresetsPopup::slotUpdatePaintOpFilter() {
QVariant userData = m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->currentData(); // grab paintOpID from data
QString filterPaintOpId = userData.toString();
if (filterPaintOpId == "all_options") {
filterPaintOpId = "";
}
m_d->uiWdgPaintOpPresetSettings.presetWidget->setPresetFilter(filterPaintOpId);
}
void KisPaintOpPresetsPopup::slotSaveBrushPreset() {
// here we are assuming that people want to keep their existing preset icon. We will just update the
// settings and save a new copy with the same name.
// there is a dialog with save options, but we don't need to show it in this situation
saveDialog->useNewBrushDialog(false); // this mostly just makes sure we keep the existing brush preset name when saving
saveDialog->loadExistingThumbnail(); // This makes sure we use the existing preset icon when updating the existing brush preset
saveDialog->savePreset();
// refresh the view settings so the brush doesn't appear dirty
slotUpdatePresetSettings();
}
void KisPaintOpPresetsPopup::slotSaveNewBrushPreset() {
saveDialog->useNewBrushDialog(true);
saveDialog->saveScratchPadThumbnailArea(m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay());
saveDialog->showDialog();
}
void KisPaintOpPresetsPopup::slotCreateNewBrushPresetEngine()
{
emit createPresetFromScratch(sender()->objectName());
}
void KisPaintOpPresetsPopup::updateViewSettings()
{
m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->updateViewSettings();
}
void KisPaintOpPresetsPopup::currentPresetChanged(KisPaintOpPresetSP preset)
{
if (preset) {
m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(preset);
setCurrentPaintOpId(preset->paintOp().id());
}
}
void KisPaintOpPresetsPopup::updateThemedIcons()
{
m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setIcon(KisIconUtils::loadIcon("krita_tool_freehand"));
m_d->uiWdgPaintOpPresetSettings.fillLayer->setIcon(KisIconUtils::loadIcon("document-new"));
m_d->uiWdgPaintOpPresetSettings.fillLayer->hide();
m_d->uiWdgPaintOpPresetSettings.fillGradient->setIcon(KisIconUtils::loadIcon("krita_tool_gradient"));
m_d->uiWdgPaintOpPresetSettings.fillSolid->setIcon(KisIconUtils::loadIcon("krita_tool_color_fill"));
m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setIcon(KisIconUtils::loadIcon("edit-delete"));
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer"));
m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer"));
m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setIcon(KisIconUtils::loadIcon("updateColorize")); // refresh icon
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setIcon(KisIconUtils::loadIcon("dirty-preset")); // edit icon
m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setIcon(KisIconUtils::loadIcon("warning"));
m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer"));
m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer"));
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setIcon(KisIconUtils::loadIcon("configure"));
// if we cannot see the "Preset label", we know it is not visible
// maybe this can also be stored in the config like the scratchpad?
if (m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->isVisible()) {
m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored);
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right"));
} else {
m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left"));
}
// we store whether the scratchpad if visible in the config.
KisConfig cfg(true);
if (cfg.scratchpadVisible()) {
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left"));
} else {
m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right"));
}
}
void KisPaintOpPresetsPopup::slotUpdatePresetSettings()
{
if (!m_d->resourceProvider) {
return;
}
if (!m_d->resourceProvider->currentPreset()) {
return;
}
// hide options on UI if we are creating a brush preset from scratch to prevent confusion
if (m_d->isCreatingBrushFromScratch) {
m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(false);
m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(false);
m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(false);
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(false);
} else {
bool isPresetDirty = m_d->resourceProvider->currentPreset()->isDirty();
// don't need to reload or overwrite a clean preset
m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(isPresetDirty);
m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(isPresetDirty);
m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(isPresetDirty);
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(true);
}
// update live preview area in here...
// don't update the live preview if the widget is not visible.
if (m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->isVisible()) {
m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setCurrentPreset(m_d->resourceProvider->currentPreset());
m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->requestUpdateStroke();
}
}
diff --git a/libs/ui/widgets/kis_preset_live_preview_view.cpp b/libs/ui/widgets/kis_preset_live_preview_view.cpp
index 9e08e804bc..56586d4bf2 100644
--- a/libs/ui/widgets/kis_preset_live_preview_view.cpp
+++ b/libs/ui/widgets/kis_preset_live_preview_view.cpp
@@ -1,391 +1,384 @@
/*
* Copyright (c) 2017 Scott Petrovic
*
* 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 "kis_paintop_settings.h"
#include
#include
#include "KisAsyncronousStrokeUpdateHelper.h"
#include
#include
#include "kis_transaction.h"
+#include
KisPresetLivePreviewView::KisPresetLivePreviewView(QWidget *parent)
: QGraphicsView(parent),
m_updateCompressor(100, KisSignalCompressor::FIRST_ACTIVE)
{
connect(&m_updateCompressor, SIGNAL(timeout()), SLOT(updateStroke()));
}
KisPresetLivePreviewView::~KisPresetLivePreviewView()
{
delete m_noPreviewText;
delete m_brushPreviewScene;
}
-void KisPresetLivePreviewView::setup()
+void KisPresetLivePreviewView::setup(KoCanvasResourceProvider* resourceManager)
{
+ m_resourceManager = resourceManager;
+
// initializing to 0 helps check later if they actually have something in them
m_noPreviewText = 0;
m_sceneImageItem = 0;
setHorizontalScrollBarPolicy ( Qt::ScrollBarAlwaysOff );
setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOff );
// layer image needs to be big enough to get an entire stroke of data
m_canvasSize.setWidth(this->width());
m_canvasSize.setHeight(this->height());
m_canvasCenterPoint.setX(m_canvasSize.width()*0.5);
m_canvasCenterPoint.setY(m_canvasSize.height()*0.5);
m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
m_image = new KisImage(0, m_canvasSize.width(), m_canvasSize.height(), m_colorSpace, "stroke sample image");
m_layer = new KisPaintLayer(m_image, "livePreviewStrokeSample", OPACITY_OPAQUE_U8, m_colorSpace);
// set scene for the view
m_brushPreviewScene = new QGraphicsScene();
setScene(m_brushPreviewScene);
}
void KisPresetLivePreviewView::setCurrentPreset(KisPaintOpPresetSP preset)
{
m_currentPreset = preset;
}
void KisPresetLivePreviewView::requestUpdateStroke()
{
m_updateCompressor.start();
}
void KisPresetLivePreviewView::updateStroke()
{
// do not paint a stroke if we are any of these engines (they have some issue currently)
if (m_currentPreset->paintOp().id() == "roundmarker" ||
m_currentPreset->paintOp().id() == "experimentbrush" ||
m_currentPreset->paintOp().id() == "duplicate") {
paintBackground();
slotPreviewGenerationCompleted();
return;
}
if (!m_previewGenerationInProgress) {
paintBackground();
setupAndPaintStroke();
} else {
m_updateCompressor.start();
}
}
void KisPresetLivePreviewView::slotPreviewGenerationCompleted()
{
m_previewGenerationInProgress = false;
QImage m_temp_image;
m_temp_image = m_layer->paintDevice()->convertToQImage(0, m_image->bounds());
// only add the object once...then just update the pixmap so we can move the preview around
if (!m_sceneImageItem) {
m_sceneImageItem = m_brushPreviewScene->addPixmap(QPixmap::fromImage(m_temp_image));
} else {
m_sceneImageItem->setPixmap(QPixmap::fromImage(m_temp_image));
}
}
void KisPresetLivePreviewView::paintBackground()
{
// clean up "no preview" text object if it exists. we will add it later if we need it
if (m_noPreviewText) {
this->scene()->removeItem(m_noPreviewText);
m_noPreviewText = 0;
}
if (m_currentPreset->paintOp().id() == "colorsmudge" ||
m_currentPreset->paintOp().id() == "deformbrush" ||
m_currentPreset->paintOp().id() == "filter") {
// easier to see deformations and smudging with alternating stripes in the background
// paint the whole background with alternating stripes
// filter engine may or may not show things depending on the filter...but it is better than nothing
int grayStrips = 20;
for (int i=0; i < grayStrips; i++ ) {
float sectionPercent = 1.0 / (float)grayStrips;
bool isAlternating = i % 2;
KoColor fillColor(m_layer->paintDevice()->colorSpace());
if (isAlternating) {
fillColor.fromQColor(QColor(80,80,80));
} else {
fillColor.fromQColor(QColor(140,140,140));
}
const QRect fillRect(m_layer->image()->width()*sectionPercent*i,
0,
m_layer->image()->width()*(sectionPercent*i +sectionPercent),
m_layer->image()->height());
KisTransaction t(m_layer->paintDevice());
m_layer->paintDevice()->fill(fillRect, fillColor);
t.end();
}
m_paintColor = KoColor(Qt::white, m_colorSpace);
}
else if (m_currentPreset->paintOp().id() == "roundmarker" ||
m_currentPreset->paintOp().id() == "experimentbrush" ||
m_currentPreset->paintOp().id() == "duplicate" ) {
// cases where we will not show a preview for now
// roundbrush (quick) -- this isn't showing anything, disable showing preview
// experimentbrush -- this creates artifacts that carry over to other previews and messes up their display
// duplicate (clone) brush doesn't have a preview as it doesn't show anything)
if(m_sceneImageItem) {
this->scene()->removeItem(m_sceneImageItem);
m_sceneImageItem = 0;
}
QFont font;
font.setPixelSize(14);
font.setBold(false);
m_noPreviewText = this->scene()->addText(i18n("No Preview for this engine"),font);
m_noPreviewText->setPos(50, this->height()/4);
return;
}
else {
// fill with gray first to clear out what existed from previous preview
KisTransaction t(m_layer->paintDevice());
m_layer->paintDevice()->fill(m_image->bounds(), KoColor(palette().color(QPalette::Background) , m_colorSpace));
t.end();
m_paintColor = KoColor(palette().color(QPalette::Text), m_colorSpace);
}
}
class NotificationStroke : public QObject, public KisSimpleStrokeStrategy
{
Q_OBJECT
public:
NotificationStroke()
: KisSimpleStrokeStrategy(QLatin1String("NotificationStroke"))
{
setClearsRedoOnStart(false);
this->enableJob(JOB_INIT, true, KisStrokeJobData::BARRIER);
this->enableJob(JOB_CANCEL, true, KisStrokeJobData::BARRIER);
}
void initStrokeCallback() override {
emit timeout();
}
void cancelStrokeCallback() override {
emit cancelled();
}
Q_SIGNALS:
void timeout();
void cancelled();
};
void KisPresetLivePreviewView::setupAndPaintStroke()
{
// limit the brush stroke size. larger brush strokes just don't look good and are CPU intensive
// we are making a proxy preset and setting it to the painter...otherwise setting the brush size of the original preset
// will fire off signals that make this run in an infinite loop
qreal previewSize = qBound(3.0, m_currentPreset->settings()->paintOpSize(), 25.0 ); // constrain live preview brush size
//Except for the sketchbrush where it determine sthe history.
if (m_currentPreset->paintOp().id() == "sketchbrush" ||
m_currentPreset->paintOp().id() == "spraybrush") {
previewSize = qMax(3.0, m_currentPreset->settings()->paintOpSize());
}
KisPaintOpPresetSP proxy_preset = m_currentPreset->clone().dynamicCast();
KisPaintOpSettingsSP settings = proxy_preset->settings();
settings->setPaintOpSize(previewSize);
int maxTextureSize = 200;
int textureOffsetX = settings->getInt("Texture/Pattern/MaximumOffsetX")*2;
int textureOffsetY = settings->getInt("Texture/Pattern/MaximumOffsetY")*2;
double textureScale = settings->getDouble("Texture/Pattern/Scale");
if ( textureOffsetX*textureScale> maxTextureSize || textureOffsetY*textureScale > maxTextureSize) {
int maxSize = qMax(textureOffsetX, textureOffsetY);
double result = qreal(maxTextureSize) / maxSize;
settings->setProperty("Texture/Pattern/Scale", result);
}
if (proxy_preset->paintOp().id() == "spraybrush") {
QDomElement element;
QDomDocument d;
QString brushDefinition = settings->getString("brush_definition");
if (!brushDefinition.isEmpty()) {
d.setContent(brushDefinition, false);
element = d.firstChildElement("Brush");
KisBrushSP brush = KisBrush::fromXML(element, KisGlobalResourcesInterface::instance());
qreal width = brush->image().width();
qreal scale = brush->scale();
qreal diameterToBrushRatio = 1.0;
qreal diameter = settings->getInt("Spray/diameter");
//hack, 1000 being the maximum possible brushsize.
if (brush->filename().endsWith(".svg")) {
diameterToBrushRatio = diameter/(1000.0*scale);
scale = 25.0 / 1000.0;
} else {
if (width * scale > 25.0) {
diameterToBrushRatio = diameter / (width * scale);
scale = 25.0 / width;
}
}
settings->setProperty("Spray/diameter", int(25.0 * diameterToBrushRatio));
brush->setScale(scale);
d.clear();
element = d.createElement("Brush");
brush->toXML(d, element);
d.appendChild(element);
settings->setProperty("brush_definition", d.toString());
}
}
- // Preset preview cannot display gradient color source: there is
- // no resource manager for KisResourcesSnapshot, therefore gradient is nullptr.
- // BUG: 385521 (Selecting "Gradient" in brush editor crashes krita)
- if (proxy_preset->paintOp().id() == "paintbrush") {
- QString colorSourceType = settings->getString("ColorSource/Type", "plain");
- if (colorSourceType == "gradient") {
- settings->setProperty("ColorSource/Type", "plain");
- }
- }
-
proxy_preset->setSettings(settings);
KisResourcesSnapshotSP resources =
new KisResourcesSnapshot(m_image,
- m_layer);
+ m_layer, m_resourceManager);
resources->setOpacity(settings->paintOpOpacity());
resources->setBrush(proxy_preset);
resources->setFGColorOverride(m_paintColor);
KisFreehandStrokeInfo *strokeInfo = new KisFreehandStrokeInfo();
KisStrokeStrategy *stroke =
new FreehandStrokeStrategy(resources, strokeInfo, kundo2_noi18n("temp_stroke"));
KisStrokeId strokeId = m_image->startStroke(stroke);
// paint the stroke. The sketchbrush gets a different shape than the others to show how it works
if (proxy_preset->paintOp().id() == "sketchbrush"
|| proxy_preset->paintOp().id() == "curvebrush"
|| proxy_preset->paintOp().id() == "particlebrush") {
qreal startX = m_canvasCenterPoint.x() - (this->width()*0.4);
qreal endX = m_canvasCenterPoint.x() + (this->width()*0.4);
qreal middle = m_canvasCenterPoint.y();
KisPaintInformation pointOne;
pointOne.setPressure(0.0);
pointOne.setPos(QPointF(startX, middle));
KisPaintInformation pointTwo;
pointTwo.setPressure(0.0);
pointTwo.setPos(QPointF(startX, middle));
int repeats = 8;
for (int i = 0; i < repeats; i++) {
pointOne.setPos(pointTwo.pos());
pointOne.setPressure(pointTwo.pressure());
pointTwo.setPressure((1.0/repeats)*(i+1));
qreal xPos = ((1.0/repeats) * (i+1) * (endX-startX) )+startX;
pointTwo.setPos(QPointF(xPos, middle));
qreal offset = (this->height()/(repeats*1.5))*(i+1);
qreal handleY = middle + offset;
if (i%2 == 0) {
handleY = middle - offset;
}
m_image->addJob(strokeId,
new FreehandStrokeStrategy::Data(0,
pointOne,
QPointF(pointOne.pos().x(),
handleY),
QPointF(pointTwo.pos().x(),
handleY),
pointTwo));
m_image->addJob(strokeId, new KisAsyncronousStrokeUpdateHelper::UpdateData(true));
}
} else {
// paint an S curve
m_curvePointPI1.setPos(QPointF(m_canvasCenterPoint.x() - (this->width()*0.45),
m_canvasCenterPoint.y() + (this->height()*0.2)));
m_curvePointPI1.setPressure(0.0);
m_curvePointPI2.setPos(QPointF(m_canvasCenterPoint.x() + (this->width()*0.4),
m_canvasCenterPoint.y() - (this->height()*0.2) ));
m_curvePointPI2.setPressure(1.0);
m_image->addJob(strokeId,
new FreehandStrokeStrategy::Data(0,
m_curvePointPI1,
QPointF(m_canvasCenterPoint.x(),
m_canvasCenterPoint.y()-this->height()),
QPointF(m_canvasCenterPoint.x(),
m_canvasCenterPoint.y()+this->height()),
m_curvePointPI2));
m_image->addJob(strokeId, new KisAsyncronousStrokeUpdateHelper::UpdateData(true));
}
m_image->endStroke(strokeId);
m_previewGenerationInProgress = true;
NotificationStroke *notificationStroke = new NotificationStroke();
connect(notificationStroke, SIGNAL(timeout()), SLOT(slotPreviewGenerationCompleted()));
KisStrokeId notificationId = m_image->startStroke(notificationStroke);
m_image->endStroke(notificationId);
// TODO: if we don't have any regressions because of it until 4.2.8, then
// just remove this code.
// even though the brush is cloned, the proxy_preset still has some connection to the original preset which will mess brush sizing
// we need to return brush size to normal.The normal brush sends out a lot of extra signals, so keeping the proxy for now
//proxy_preset->settings()->setPaintOpSize(originalPresetSize);
}
#include "kis_preset_live_preview_view.moc"
diff --git a/libs/ui/widgets/kis_preset_live_preview_view.h b/libs/ui/widgets/kis_preset_live_preview_view.h
index abace25032..0e42323465 100644
--- a/libs/ui/widgets/kis_preset_live_preview_view.h
+++ b/libs/ui/widgets/kis_preset_live_preview_view.h
@@ -1,157 +1,162 @@
/*
* Copyright (c) 2017 Scott Petrovic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _KIS_PRESET_LIVE_PREVIEW_
#define _KIS_PRESET_LIVE_PREVIEW_
#include
#include
#include
#include
#include
#include "kis_paintop_preset.h"
#include "KoColorSpaceRegistry.h"
#include "kis_paint_layer.h"
#include "kis_painter.h"
#include "kis_distance_information.h"
#include "kis_painting_information_builder.h"
#include
#include
#include
#include "kis_signal_compressor.h"
+class KoCanvasResourceProvider;
+
/**
* Widget for displaying a live brush preview of your
* selected brush. It listens for signalsetting changes
* that the brush preset outputs and updates the preview
* accordingly. This class can be added to a UI file
* similar to how a QGraphicsView is added
*/
class KisPresetLivePreviewView : public QGraphicsView
{
Q_OBJECT
public:
KisPresetLivePreviewView(QWidget *parent);
~KisPresetLivePreviewView();
/**
* @brief one time setup for initialization of many variables.
* This live preview might be in a UI file, so make sure to
* call this before starting to use it
*/
- void setup();
+ void setup(KoCanvasResourceProvider* resourceManager);
/**
* @brief set the current preset from resource manager for the live preview to use.
* Good to call this every stroke update in case the preset has changed
* @param preset the current preset from the resource manager
*/
void setCurrentPreset(KisPaintOpPresetSP preset);
void requestUpdateStroke();
private Q_SLOTS:
void updateStroke();
void slotPreviewGenerationCompleted();
private:
+ ///internally sets the Resource Provider for brush preview (allowing gradients in preview)
+ KoCanvasResourceProvider* m_resourceManager;
+
/// internally sets the image area for brush preview
KisImageSP m_image;
/// internally sets the layer area for brush preview
KisLayerSP m_layer;
/// internally sets the color space for brush preview
const KoColorSpace *m_colorSpace;
/// the color which is used for rendering the stroke
KoColor m_paintColor;
/// the scene that can add items like text and the brush stroke image
QGraphicsScene *m_brushPreviewScene;
/// holds the preview brush stroke data
QGraphicsPixmapItem *m_sceneImageItem;
/// holds the 'no preview available' text object
QGraphicsTextItem *m_noPreviewText;
/// holds the width and height of the image of the brush preview
/// Probably can later add set functions to make this customizable
/// It is hard-coded to 1200 x 400 for right now for image size
QRect m_canvasSize;
/// convenience variable used internally when positioning the objects
/// and points in the scene
QPointF m_canvasCenterPoint;
/// internal variables for constructing the stroke start and end shape
/// there are two points that construct the "S" curve with this
KisDistanceInformation m_currentDistance;
QPainterPath m_curvedLine;
KisPaintInformation m_curvePointPI1;
KisPaintInformation m_curvePointPI2;
/// internally stores the current preset.
/// See setCurrentPreset(KisPaintOpPresetSP preset)
/// for setting this externally
KisPaintOpPresetSP m_currentPreset;
/// holds the current zoom(scale) level of scene
float m_scaleFactor;
/// internal reference for internal brush size
/// used to check if our brush size has changed
/// do zooming and other things internally if it has changed
float m_currentBrushSize = 1.0;
bool m_previewGenerationInProgress = false;
KisSignalCompressor m_updateCompressor;
/// the range of brush sizes that will control zooming in/out
const float m_minBrushVal = 10.0;
const float m_maxBrushVal = 100.0;
/// range of scale values. 1.0 == 100%
const qreal m_minScale = 1.0;
const qreal m_maxScale = 0.3;
/// multiplier that is used for lengthening the brush stroke points
const float m_minStrokeScale = 0.4; // for smaller brush stroke
const float m_maxStrokeScale = 1.0; // for larger brush stroke
/**
* @brief works as both clearing the previous stroke, providing
* striped backgrounds for smudging brushes, and text if there is no preview
*/
void paintBackground();
/**
* @brief creates and performs the actual stroke that goes on top of the background
* this is internally and should always be called after the paintBackground()
*/
void setupAndPaintStroke();
};
#endif
diff --git a/libs/widgetutils/kis_action_registry.cpp b/libs/widgetutils/kis_action_registry.cpp
index f1d9887c91..60e8411310 100644
--- a/libs/widgetutils/kis_action_registry.cpp
+++ b/libs/widgetutils/kis_action_registry.cpp
@@ -1,426 +1,430 @@
/*
* Copyright (c) 2015 Michael Abrahams
*
* 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 3 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