diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
index 6ec34e9c2a..9335072cd2 100644
--- a/benchmarks/CMakeLists.txt
+++ b/benchmarks/CMakeLists.txt
@@ -1,93 +1,93 @@
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
include_directories(
${CMAKE_SOURCE_DIR}/sdk/tests
${CMAKE_SOURCE_DIR}/libs/pigment
${CMAKE_SOURCE_DIR}/libs/pigment/compositeops
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
)
set(LINK_VC_LIB)
if(HAVE_VC)
include_directories(${Vc_INCLUDE_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}")
set(LINK_VC_LIB ${Vc_LIBRARIES})
endif()
macro_add_unittest_definitions()
########### next target ###############
set(kis_datamanager_benchmark_SRCS kis_datamanager_benchmark.cpp)
set(kis_hiterator_benchmark_SRCS kis_hline_iterator_benchmark.cpp)
set(kis_viterator_benchmark_SRCS kis_vline_iterator_benchmark.cpp)
set(kis_random_iterator_benchmark_SRCS kis_random_iterator_benchmark.cpp)
set(kis_projection_benchmark_SRCS kis_projection_benchmark.cpp)
set(kis_bcontrast_benchmark_SRCS kis_bcontrast_benchmark.cpp)
set(kis_blur_benchmark_SRCS kis_blur_benchmark.cpp)
set(kis_level_filter_benchmark_SRCS kis_level_filter_benchmark.cpp)
set(kis_painter_benchmark_SRCS kis_painter_benchmark.cpp)
set(kis_stroke_benchmark_SRCS kis_stroke_benchmark.cpp)
set(kis_fast_math_benchmark_SRCS kis_fast_math_benchmark.cpp)
set(kis_floodfill_benchmark_SRCS kis_floodfill_benchmark.cpp)
set(kis_gradient_benchmark_SRCS kis_gradient_benchmark.cpp)
set(kis_mask_generator_benchmark_SRCS kis_mask_generator_benchmark.cpp)
set(kis_low_memory_benchmark_SRCS kis_low_memory_benchmark.cpp)
set(KisAnimationRenderingBenchmark_SRCS KisAnimationRenderingBenchmark.cpp)
set(kis_filter_selections_benchmark_SRCS kis_filter_selections_benchmark.cpp)
if (UNIX)
- set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp)
+ set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp)
endif()
set(kis_thumbnail_benchmark_SRCS kis_thumbnail_benchmark.cpp)
krita_add_benchmark(KisDatamanagerBenchmark TESTNAME krita-benchmarks-KisDataManager ${kis_datamanager_benchmark_SRCS})
krita_add_benchmark(KisHLineIteratorBenchmark TESTNAME krita-benchmarks-KisHLineIterator ${kis_hiterator_benchmark_SRCS})
krita_add_benchmark(KisVLineIteratorBenchmark TESTNAME krita-benchmarks-KisVLineIterator ${kis_viterator_benchmark_SRCS})
krita_add_benchmark(KisRandomIteratorBenchmark TESTNAME krita-benchmarks-KisRandomIterator ${kis_random_iterator_benchmark_SRCS})
krita_add_benchmark(KisProjectionBenchmark TESTNAME krita-benchmarks-KisProjectionBenchmark ${kis_projection_benchmark_SRCS})
krita_add_benchmark(KisBContrastBenchmark TESTNAME krita-benchmarks-KisBContrastBenchmark ${kis_bcontrast_benchmark_SRCS})
krita_add_benchmark(KisBlurBenchmark TESTNAME krita-benchmarks-KisBlurBenchmark ${kis_blur_benchmark_SRCS})
krita_add_benchmark(KisLevelFilterBenchmark TESTNAME krita-benchmarks-KisLevelFilterBenchmark ${kis_level_filter_benchmark_SRCS})
krita_add_benchmark(KisPainterBenchmark TESTNAME krita-benchmarks-KisPainterBenchmark ${kis_painter_benchmark_SRCS})
krita_add_benchmark(KisStrokeBenchmark TESTNAME krita-benchmarks-KisStrokeBenchmark ${kis_stroke_benchmark_SRCS})
krita_add_benchmark(KisFastMathBenchmark TESTNAME krita-benchmarks-KisFastMath ${kis_fast_math_benchmark_SRCS})
krita_add_benchmark(KisFloodfillBenchmark TESTNAME krita-benchmarks-KisFloodFill ${kis_floodfill_benchmark_SRCS})
krita_add_benchmark(KisGradientBenchmark TESTNAME krita-benchmarks-KisGradientFill ${kis_gradient_benchmark_SRCS})
krita_add_benchmark(KisMaskGeneratorBenchmark TESTNAME krita-benchmarks-KisMaskGenerator ${kis_mask_generator_benchmark_SRCS})
krita_add_benchmark(KisLowMemoryBenchmark TESTNAME krita-benchmarks-KisLowMemory ${kis_low_memory_benchmark_SRCS})
krita_add_benchmark(KisAnimationRenderingBenchmark TESTNAME krita-benchmarks-KisAnimationRenderingBenchmark ${KisAnimationRenderingBenchmark_SRCS})
krita_add_benchmark(KisFilterSelectionsBenchmark TESTNAME krita-image-KisFilterSelectionsBenchmark ${kis_filter_selections_benchmark_SRCS})
if(UNIX)
- krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS})
+ krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS})
endif()
krita_add_benchmark(KisThumbnailBenchmark TESTNAME krita-benchmarks-KisThumbnail ${kis_thumbnail_benchmark_SRCS})
target_link_libraries(KisDatamanagerBenchmark kritaimage Qt5::Test)
target_link_libraries(KisHLineIteratorBenchmark kritaimage Qt5::Test)
target_link_libraries(KisVLineIteratorBenchmark kritaimage Qt5::Test)
target_link_libraries(KisRandomIteratorBenchmark kritaimage Qt5::Test)
target_link_libraries(KisProjectionBenchmark kritaimage kritaui Qt5::Test)
target_link_libraries(KisBContrastBenchmark kritaimage Qt5::Test)
target_link_libraries(KisBlurBenchmark kritaimage Qt5::Test)
target_link_libraries(KisLevelFilterBenchmark kritaimage Qt5::Test)
target_link_libraries(KisPainterBenchmark kritaimage Qt5::Test)
target_link_libraries(KisStrokeBenchmark kritaimage Qt5::Test)
target_link_libraries(KisFastMathBenchmark kritaimage Qt5::Test)
target_link_libraries(KisFloodfillBenchmark kritaimage Qt5::Test)
target_link_libraries(KisGradientBenchmark kritaimage Qt5::Test)
target_link_libraries(KisLowMemoryBenchmark kritaimage Qt5::Test)
target_link_libraries(KisAnimationRenderingBenchmark kritaimage kritaui Qt5::Test)
target_link_libraries(KisFilterSelectionsBenchmark kritaimage Qt5::Test)
if(UNIX)
target_link_libraries(KisCompositionBenchmark kritaimage Qt5::Test ${LINK_VC_LIB})
if(HAVE_VC)
set_property(TARGET KisCompositionBenchmark APPEND PROPERTY COMPILE_OPTIONS "${Vc_ARCHITECTURE_FLAGS}")
endif()
endif()
target_link_libraries(KisMaskGeneratorBenchmark kritaimage Qt5::Test)
target_link_libraries(KisThumbnailBenchmark kritaimage Qt5::Test)
diff --git a/krita/krita4.xmlgui b/krita/krita4.xmlgui
index 8428761ff2..bd7b25ab07 100644
--- a/krita/krita4.xmlgui
+++ b/krita/krita4.xmlgui
@@ -1,404 +1,405 @@
&View
&Canvas
&Snap To
+
&Image
&Rotate
&Layer
New
&Import/Export
Import
&Convert
&Select
&Group
&Transform
&Rotate
Transform &All Layers
&Rotate
S&plit
S&plit Alpha
&Select
Select &Opaque
Filte&r
&Tools
Scripts
Setti&ngs
&Help
File
Brushes and Stuff
diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index 9783320af3..3aa7b9886e 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1806 +1,1817 @@
File
document-new
&New
Create new document
New
0
0
Ctrl+N
false
document-open
&Open...
Open an existing document
Open
0
0
Ctrl+O
false
document-open-recent
Open &Recent
Open a document which was recently opened
Open Recent
1
0
false
document-save
&Save
Save
Save
1
0
Ctrl+S
false
document-save-as
Save &As...
Save document under a new name
Save As
1
0
Ctrl+Shift+S
false
Sessions...
Open session manager
Sessions
0
0
false
document-import
Open ex&isting Document as Untitled Document...
Open existing Document as Untitled Document
Open existing Document as Untitled Document
0
0
false
document-export
E&xport...
Export
Export
1
0
false
Import animation frames...
Import animation frames
Import animation frames
1
0
false
&Render Animation...
Render Animation to GIF, Image Sequence or Video
Render Animation
1000
0
false
&Render Animation Again
Render Animation Again
Render Animation
1000
0
false
Save Incremental &Version
Save Incremental Version
Save Incremental Version
1
0
Ctrl+Alt+S
false
Save Incremental &Backup
Save Incremental Backup
Save Incremental Backup
1
0
F4
false
&Create Template From Image...
Create Template From Image
Create Template From Image
1
0
false
Create Copy &From Current Image
Create Copy From Current Image
Create Copy From Current Image
1
0
false
document-print
&Print...
Print document
Print
1
0
Ctrl+P
false
document-print-preview
Print Previe&w
Show a print preview of document
Print Preview
1
0
false
configure
&Document Information
Document Information
Document Information
1
0
false
&Close All
Close All
Close All
1
0
Ctrl+Shift+W
false
C&lose
Close
Close
1
0
Ctrl+W
false
&Quit
Quit application
Quit
0
0
Ctrl+Q
false
Edit
edit-undo
Undo
Undo last action
Undo
1
0
Ctrl+Z
false
edit-redo
Redo
Redo last undone action
Redo
1
0
Ctrl+Shift+Z
false
edit-cut
Cu&t
Cut selection to clipboard
Cut
0
0
Ctrl+X
false
edit-copy
&Copy
Copy selection to clipboard
Copy
0
0
Ctrl+C
false
C&opy (sharp)
Copy (sharp)
Copy (sharp)
100000000
0
false
Cut (&sharp)
Cut (sharp)
Cut (sharp)
100000000
0
false
Copy &merged
Copy merged
Copy merged
100000000
0
Ctrl+Shift+C
false
edit-paste
&Paste
Paste clipboard content
Paste
0
0
Ctrl+V
false
Paste at Cursor
Paste at cursor
Paste at cursor
0
0
Ctrl+Alt+V
false
Paste into &New Image
Paste into New Image
Paste into New Image
0
0
Ctrl+Shift+N
false
edit-clear
C&lear
Clear
Clear
1
0
Del
false
&Fill with Foreground Color
Fill with Foreground Color
Fill with Foreground Color
10000
1
Shift+Backspace
false
Fill &with Background Color
Fill with Background Color
Fill with Background Color
10000
1
Backspace
false
F&ill with Pattern
Fill with Pattern
Fill with Pattern
10000
1
false
Fill Special
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
Stro&ke selected shapes
Stroke selected shapes
Stroke selected shapes
1000000000
0
false
Stroke Selec&tion...
Stroke selection
Stroke selection
10000000000
0
false
Delete keyframe
Delete keyframe
Delete keyframe
100000
0
false
Window
window-new
&New Window
New Window
New Window
0
0
false
N&ext
Next
Next
10
0
false
Previous
Previous
Previous
false
View
document-new
&Show Canvas Only
Show just the canvas or the whole window
Show Canvas Only
0
0
Tab
true
view-fullscreen
F&ull Screen Mode
Display the window in full screen
Full Screen Mode
0
0
Ctrl+Shift+F
true
&Wrap Around Mode
Wrap Around Mode
Wrap Around Mode
1
0
true
&Instant Preview Mode
Instant Preview Mode
Instant Preview Mode
1
0
Shift+L
true
Soft Proofing
Turns on Soft Proofing
Turns on Soft Proofing
Ctrl+Y
true
Out of Gamut Warnings
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Ctrl+Shift+Y
true
mirror-view
Mirror View
Mirror View
Mirror View
M
false
zoom-original
&Reset zoom
Reset zoom
Reset zoom
1
0
Ctrl+0
false
zoom-in
Zoom &In
Zoom In
0
0
Ctrl++
false
zoom-out
Zoom &Out
Zoom Out
0
0
Ctrl+-
false
rotate-canvas-right
Rotate &Canvas Right
Rotate Canvas Right
Rotate Canvas Right
1
0
Ctrl+]
false
rotate-canvas-left
Rotate Canvas &Left
Rotate Canvas Left
Rotate Canvas Left
1
0
Ctrl+[
false
rotation-reset
Reset Canvas Rotation
Reset Canvas Rotation
Reset Canvas Rotation
1
0
false
Show &Rulers
The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p>
Show Rulers
Show Rulers
1
0
true
Rulers Track Pointer
The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown
Rulers Track Pointer
Rulers Track Pointer
1
0
true
Show Guides
Show or hide guides
Show Guides
1
0
true
Lock Guides
Lock or unlock guides
Lock Guides
1
0
true
Snap to Guides
Snap cursor to guides position
Snap to Guides
1
0
true
Show Status &Bar
Show or hide the status bar
Show Status Bar
0
0
true
Show Pixel Grid
Show Pixel Grid
Show Pixel Grid
1000
1000
true
view-grid
Show &Grid
Show Grid
Show Grid
1000
0
Ctrl+Shift+'
true
Snap To Grid
Snap To Grid
Snap To Grid
1000
Ctrl+Shift+;
true
Show Snap Options Popup
Show Snap Options Popup
Show Snap Options Popup
1000
Shift+s
false
Snap Orthogonal
Snap Orthogonal
Snap Orthogonal
1000
true
Snap Node
Snap Node
Snap Node
1000
true
Snap Extension
Snap Extension
Snap Extension
1000
true
+
+
+ Snap Pixel
+
+ Snap Pixel
+ Snap Pixel
+ 1000
+
+ true
+
+
Snap Intersection
Snap Intersection
Snap Intersection
1000
true
Snap Bounding Box
Snap Bounding Box
Snap Bounding Box
1000
true
Snap Image Bounds
Snap Image Bounds
Snap Image Bounds
1000
true
Snap Image Center
Snap Image Center
Snap Image Center
1000
true
S&how Painting Assistants
Show Painting Assistants
Show Painting Assistants
1000
0
true
Show &Assistant Previews
Show Assistant Previews
Show Assistant Previews
1000
0
true
S&how Reference Images
Show Reference Images
Show Reference Images
1000
0
true
Image
document-properties
&Properties...
Properties
Properties
1000
0
false
format-stroke-color
&Image Background Color and Transparency...
Change the background color of the image
Image Background Color and Transparency
1000
0
false
&Convert Image Color Space...
Convert Image Color Space
Convert Image Color Space
1000
0
false
trim-to-image
&Trim to Image Size
Trim to Image Size
Trim to Image Size
1
0
false
Trim to Current &Layer
Trim to Current Layer
Trim to Current Layer
100000
0
false
Trim to S&election
Trim to Selection
Trim to Selection
100000000
0
false
&Rotate Image...
Rotate Image
Rotate Image
1000
0
false
object-rotate-right
Rotate &Image 90° to the Right
Rotate Image 90° to the Right
Rotate Image 90° to the Right
1000
0
false
object-rotate-left
Rotate Image &90° to the Left
Rotate Image 90° to the Left
Rotate Image 90° to the Left
1000
0
false
Rotate Image &180°
Rotate Image 180°
Rotate Image 180°
1000
0
false
&Shear Image...
Shear Image
Shear Image
1000
0
false
symmetry-horizontal
&Mirror Image Horizontally
Mirror Image Horizontally
Mirror Image Horizontally
1000
0
false
symmetry-vertical
Mirror Image &Vertically
Mirror Image Vertically
Mirror Image Vertically
1000
0
false
Scale Image To &New Size...
Scale Image To New Size
Scale Image To New Size
1000
0
Ctrl+Alt+I
false
&Offset Image...
Offset Image
Offset Image
1000
0
false
R&esize Canvas...
Resize Canvas
Resize Canvas
1000
0
Ctrl+Alt+C
false
Im&age Split
Image Split
Image Split
1000
0
false
Separate Ima&ge...
Separate Image
Separate Image
1000
0
false
Select
edit-select-all
Select &All
Select All
Select All
0
0
Ctrl+A
false
edit-select-all
&Deselect
Deselect
Deselect
1100000000
0
Ctrl+Shift+A
false
&Reselect
Reselect
Reselect
0
0
Ctrl+Shift+D
false
&Convert to Vector Selection
Convert to Vector Selection
Convert to Vector Selection
100000000000000000
0
false
&Convert to Raster Selection
Convert to Raster Selection
Convert to Raster Selection
10000000000000000
0
false
Edit Selection
Edit Selection
Edit Selection
10000000000
100
false
Convert Shapes to &Vector Selection
Convert Shapes to Vector Selection
Convert Shapes to Vector Selection
1000000000
0
false
&Feather Selection...
Feather Selection
Feather Selection
10000000000
100
Shift+F6
false
Dis&play Selection
Display Selection
Display Selection
1000
0
Ctrl+H
true
Sca&le...
Scale
Scale
100000000
100
false
S&elect from Color Range...
Select from Color Range
Select from Color Range
10000
100
false
Select &Opaque (Replace)
Select Opaque
Select Opaque
10000
100
false
Select Opaque (&Add)
Select Opaque (Add)
Select Opaque (Add)
10000
100
false
Select Opaque (&Subtract)
Select Opaque (Subtract)
Select Opaque (Subtract)
10000
100
false
Select Opaque (&Intersect)
Select Opaque (Intersect)
Select Opaque (Intersect)
10000
100
false
&Grow Selection...
Grow Selection
Grow Selection
10000000000
100
false
S&hrink Selection...
Shrink Selection
Shrink Selection
10000000000
100
false
&Border Selection...
Border Selection
Border Selection
10000000000
100
false
S&mooth
Smooth
Smooth
10000000000
100
false
Filter
&Apply Filter Again
Apply Filter Again
Apply Filter Again
0
0
Ctrl+F
false
Adjust
Adjust
Adjust
false
Artistic
Artistic
Artistic
false
Blur
Blur
Blur
false
Colors
Colors
Colors
false
Edge Detection
Edge Detection
Edge Detection
false
Enhance
Enhance
Enhance
false
Emboss
Emboss
Emboss
false
Map
Map
Map
false
Other
Other
Other
false
gmic
Start G'MIC-Qt
Start G'Mic-Qt
Start G'Mic-Qt
false
gmic
Re-apply the last G'MIC filter
Apply the last G'Mic-Qt action again
Apply the last G'Mic-Qt action again
false
Settings
configure
&Configure Krita...
Configure Krita
Configure Krita
0
0
false
&Manage Resources...
Manage Resources
Manage Resources
0
0
false
preferences-desktop-locale
Switch Application &Language...
Switch Application Language
Switch Application Language
false
&Show Dockers
Show Dockers
Show Dockers
0
0
true
configure
Configure Tool&bars...
Configure Toolbars
Configure Toolbars
0
0
false
Dockers
Dockers
Dockers
false
&Themes
Themes
Themes
false
im-user
Active Author Profile
Active Author Profile
Active Author Profile
configure-shortcuts
Configure S&hortcuts...
Configure Shortcuts
Configure Shortcuts
0
0
false
&Window
Window
Window
false
Help
help-contents
Krita &Handbook
Krita Handbook
Krita Handbook
F1
false
tools-report-bug
&Report Bug...
Report Bug
Report Bug
false
calligrakrita
&About Krita
About Krita
About Krita
false
kde
About &KDE
About KDE
About KDE
false
Brushes and Stuff
&Gradients
Gradients
Gradients
false
&Patterns
Patterns
Patterns
false
&Color
Color
Color
false
&Painter's Tools
Painter's Tools
Painter's Tools
false
Brush composite
Brush composite
Brush composite
false
Brush option slider 1
Brush option slider 1
Brush option slider 1
false
Brush option slider 2
Brush option slider 2
Brush option slider 2
false
Brush option slider 3
Brush option slider 3
Brush option slider 3
false
Mirror
Mirror
Mirror
false
Layouts
Select layout
false
Workspaces
Workspaces
Workspaces
false
diff --git a/libs/flake/KoCanvasBase.h b/libs/flake/KoCanvasBase.h
index 2650f5c7f5..1acfe0fe2a 100644
--- a/libs/flake/KoCanvasBase.h
+++ b/libs/flake/KoCanvasBase.h
@@ -1,254 +1,262 @@
/* This file is part of the KDE project
Copyright (C) 2006, 2010 Boudewijn Rempt
Copyright (C) 2006, 2010 Thomas Zander
Copyright (C) 2006 Thorsten Zachmann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KOCANVASBASE_H
#define KOCANVASBASE_H
#include
#include "kritaflake_export.h"
class KUndo2Command;
class KoUnit;
class KoCanvasResourceProvider;
class KoShapeManager;
class KoToolProxy;
class KoViewConverter;
class KoShapeController;
class KoShapeControllerBase;
class KoCanvasController;
class KoShape;
class KoSnapGuide;
class KoSelectedShapesProxy;
class QWidget;
class QCursor;
class QPointF;
class QRectF;
class QSizeF;
#include
/**
* KoCanvasBase is the interface actual application canvas classes
* should implement. Flake tools know about the canvas, so they can
* do things like scroll, redraw, set a cursor etc.
*/
class KRITAFLAKE_EXPORT KoCanvasBase : public QObject
{
Q_OBJECT
public:
/**
* The constructor.
* @param shapeController the implementation of the shapeController that the
* application provides to allow shapes to be added in multiple views.
*/
explicit KoCanvasBase(KoShapeControllerBase *shapeController, KoCanvasResourceProvider *sharedResourceManager = 0);
~KoCanvasBase() override;
public:
/**
* @return true if opengl can be used directly on the canvas
*/
virtual bool canvasIsOpenGL() const { return false; }
/**
* retrieve the grid size setting.
* The grid spacing will be provided in pt.
* @param horizontal a pointer to a qreal that will be filled with the horizontal grid-spacing
* @param vertical a pointer to a qreal that will be filled with the vertical grid-spacing
*/
virtual void gridSize(QPointF *offset, QSizeF *spacing) const = 0;
/**
* return if snap to grid is enabled.
* @return if snap to grid is enabled.
*/
virtual bool snapToGrid() const = 0;
/**
* set the specified cursor on this canvas
*
* @param cursor the new cursor
* @return the old cursor
*/
virtual void setCursor(const QCursor &cursor) = 0;
+ /**
+ * converts image coordinates to document one
+ *
+ * @param point the point to be converted
+ * @return the converted point
+ */
+ virtual QPointF mapImageToDocument(const QPointF &point) { return point; }
+
/**
* Adds a command to the history. Call this for each @p command you create.
* This will also execute the command.
* This means, most of the application's code will look like
* MyCommand * cmd = new MyCommand( parameters );
* canvas.addCommand( cmd );
*
* Note that the command history takes ownership of the command, it will delete
* it when the undo limit is reached, or when deleting the command history itself.
* @param command the command to add
*/
virtual void addCommand(KUndo2Command *command) = 0;
/**
* Return the current shapeManager. WARNING: the shape manager can switch
* in time, e.g. when a layer is changed. Please don't keep any persistent
* connections to it. Instead please use selectedShapesProxy(),
* which is guaranteed to be the same throughout the life of the canvas.
*
* @return the current shapeManager
*/
virtual KoShapeManager *shapeManager() const = 0;
/**
* @brief selectedShapesProxy() is a special interface for keeping a persistent connections
* to selectionChanged() and selectionContentChanged() signals. While shapeManager() can change
* throughout the life time of the cavas, selectedShapesProxy() is guaranteed to stay the same.
* @return persistent KoSelectedShapesProxy object
*/
virtual KoSelectedShapesProxy *selectedShapesProxy() const = 0;
/**
* Tell the canvas to repaint the specified rectangle. The coordinates
* are document coordinates, not view coordinates.
*/
virtual void updateCanvas(const QRectF &rc) = 0;
/**
* Return the proxy to the active tool (determining which tool
* is really, really active is hard when tablets are involved,
* so leave that to others.
*/
virtual KoToolProxy *toolProxy() const = 0;
/**
* Return the viewConverter for this view.
* @return the viewConverter for this view.
*/
virtual KoViewConverter *viewConverter() const = 0;
/**
* Convert a coordinate in pixels to pt.
* @param viewPoint the point in the coordinate system of the widget, or window.
*/
virtual QPointF viewToDocument(const QPointF &viewPoint) const;
/**
* Return the widget that will be added to the scrollArea.
*/
virtual QWidget *canvasWidget() = 0;
/**
* Return the widget that will be added to the scrollArea.
*/
virtual const QWidget *canvasWidget() const = 0;
/**
* Return the unit of the current document for initialization of the widgets created
* by the flake framework.
* @see KoDocument::unit()
*/
virtual KoUnit unit() const = 0;
/**
* Called when the user tries to move the argument shape to allow the application to limit the
* users movement to stay within the document bounds.
* An implementation can alter the parameter move to make sure that if the distance moved
* is applied to the shape it will not become unreachable for the user.
* The default implementation does not restrict movement.
* @param shape the shape that will be moved soon.
* @param move the distance the caller intends to move the shape.
*/
virtual void clipToDocument(const KoShape *shape, QPointF &move) const;
/**
* Return the position of the document origin inside the canvas widget, in pixels.
* By default the origin of the canvas widget and the position of the
* document origin are coincident, thus an empty point is returned.
*/
virtual QPoint documentOrigin() const {
return QPoint(0, 0);
}
/**
* This method should somehow call QWidget::updateMicroFocus() on the canvas widget.
*/
virtual void updateInputMethodInfo() = 0;
/**
* disconnect the given QObject completely and utterly from any and all
* connections it has to any QObject owned by the canvas. Do this in
* the setCanvas of every KoCanvasObserver.
*/
virtual void disconnectCanvasObserver(QObject *object);
/**
* Return a pointer to the resource manager associated with this
* canvas. The resource manager contains per-canvas settings such
* as current foreground and background color.
* If instead of per-canvas resources you need per-document resources
* you can by going via the shapeController instead;
* @code
* canvasBase->shapeController()->resourceManager();
* @endcode
* @see KoShapeController::resourceManager()
*/
KoCanvasResourceProvider *resourceManager() const;
/**
* Return the shape controller for this canvas.
* A shape controller is used to create or delete shapes and show the relevant dialogs to the user.
*/
KoShapeController *shapeController() const;
/**
* Return the canvas controller for this canvas.
*/
KoCanvasController *canvasController() const;
/**
* @brief Scrolls the content of the canvas so that the given rect is visible.
*
* The rect is to be specified in document coordinates.
*
* @param rect the rectangle to make visible
*/
virtual void ensureVisible(const QRectF &rect);
/**
* Returns the snap guide of the canvas
*/
KoSnapGuide *snapGuide() const;
/// called by KoCanvasController to set the controller that handles this canvas.
void setCanvasController(KoCanvasController *controller);
private:
// we need a KoShapeControllerBase so that it can work
KoCanvasBase();
class Private;
Private * const d;
};
#endif // KOCANVASBASE_H
diff --git a/libs/flake/KoSnapGuide.cpp b/libs/flake/KoSnapGuide.cpp
index da7f7709a5..cc73912c09 100644
--- a/libs/flake/KoSnapGuide.cpp
+++ b/libs/flake/KoSnapGuide.cpp
@@ -1,281 +1,282 @@
/* This file is part of the KDE project
* Copyright (C) 2008-2009 Jan Hambrecht
*
* 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 "KoSnapGuide.h"
#include "KoSnapProxy.h"
#include "KoSnapStrategy.h"
#include
#include
#include
#include
#include
#include
template
inline QSharedPointer toQShared(T* ptr) {
return QSharedPointer(ptr);
}
class Q_DECL_HIDDEN KoSnapGuide::Private
{
public:
Private(KoCanvasBase *parentCanvas)
: canvas(parentCanvas), additionalEditedShape(0), currentStrategy(0),
active(true),
snapDistance(10)
{
}
~Private()
{
strategies.clear();
}
KoCanvasBase *canvas;
KoShape *additionalEditedShape;
typedef QSharedPointer KoSnapStrategySP;
typedef QList StrategiesList;
StrategiesList strategies;
KoSnapStrategySP currentStrategy;
KoSnapGuide::Strategies usedStrategies;
bool active;
int snapDistance;
QList ignoredPoints;
QList ignoredShapes;
};
KoSnapGuide::KoSnapGuide(KoCanvasBase *canvas)
: d(new Private(canvas))
{
d->strategies.append(toQShared(new GridSnapStrategy()));
d->strategies.append(toQShared(new NodeSnapStrategy()));
d->strategies.append(toQShared(new OrthogonalSnapStrategy()));
d->strategies.append(toQShared(new ExtensionSnapStrategy()));
d->strategies.append(toQShared(new IntersectionSnapStrategy()));
d->strategies.append(toQShared(new BoundingBoxSnapStrategy()));
+ d->strategies.append(toQShared(new PixelSnapStrategy()));
}
KoSnapGuide::~KoSnapGuide()
{
}
void KoSnapGuide::setAdditionalEditedShape(KoShape *shape)
{
d->additionalEditedShape = shape;
}
KoShape *KoSnapGuide::additionalEditedShape() const
{
return d->additionalEditedShape;
}
void KoSnapGuide::enableSnapStrategy(Strategy type, bool value)
{
if (value) {
d->usedStrategies |= type;
} else {
d->usedStrategies &= ~type;
}
}
bool KoSnapGuide::isStrategyEnabled(Strategy type) const
{
return d->usedStrategies & type;
}
void KoSnapGuide::enableSnapStrategies(Strategies strategies)
{
d->usedStrategies = strategies;
}
KoSnapGuide::Strategies KoSnapGuide::enabledSnapStrategies() const
{
return d->usedStrategies;
}
bool KoSnapGuide::addCustomSnapStrategy(KoSnapStrategy *customStrategy)
{
if (!customStrategy || customStrategy->type() != CustomSnapping)
return false;
d->strategies.append(toQShared(customStrategy));
return true;
}
void KoSnapGuide::overrideSnapStrategy(Strategy type, KoSnapStrategy *strategy)
{
for (auto it = d->strategies.begin(); it != d->strategies.end(); /*noop*/) {
if ((*it)->type() == type) {
if (strategy) {
*it = toQShared(strategy);
} else {
it = d->strategies.erase(it);
}
return;
} else {
++it;
}
}
if (strategy) {
d->strategies.append(toQShared(strategy));
}
}
void KoSnapGuide::enableSnapping(bool on)
{
d->active = on;
}
bool KoSnapGuide::isSnapping() const
{
return d->active;
}
void KoSnapGuide::setSnapDistance(int distance)
{
d->snapDistance = qAbs(distance);
}
int KoSnapGuide::snapDistance() const
{
return d->snapDistance;
}
QPointF KoSnapGuide::snap(const QPointF &mousePosition, const QPointF &dragOffset, Qt::KeyboardModifiers modifiers)
{
QPointF pos = mousePosition + dragOffset;
pos = snap(pos, modifiers);
return pos - dragOffset;
}
QPointF KoSnapGuide::snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
{
d->currentStrategy.clear();
if (! d->active || (modifiers & Qt::ShiftModifier))
return mousePosition;
KoSnapProxy proxy(this);
qreal minDistance = HUGE_VAL;
qreal maxSnapDistance = d->canvas->viewConverter()->viewToDocument(QSizeF(d->snapDistance,
d->snapDistance)).width();
foreach (Private::KoSnapStrategySP strategy, d->strategies) {
if (d->usedStrategies & strategy->type() ||
strategy->type() == GridSnapping ||
strategy->type() == CustomSnapping) {
if (! strategy->snap(mousePosition, &proxy, maxSnapDistance))
continue;
QPointF snapCandidate = strategy->snappedPosition();
qreal distance = KoSnapStrategy::squareDistance(snapCandidate, mousePosition);
if (distance < minDistance) {
d->currentStrategy = strategy;
minDistance = distance;
}
}
}
if (! d->currentStrategy)
return mousePosition;
return d->currentStrategy->snappedPosition();
}
QRectF KoSnapGuide::boundingRect()
{
QRectF rect;
if (d->currentStrategy) {
rect = d->currentStrategy->decoration(*d->canvas->viewConverter()).boundingRect();
return rect.adjusted(-2, -2, 2, 2);
} else {
return rect;
}
}
void KoSnapGuide::paint(QPainter &painter, const KoViewConverter &converter)
{
if (! d->currentStrategy || ! d->active)
return;
QPainterPath decoration = d->currentStrategy->decoration(converter);
painter.setBrush(Qt::NoBrush);
QPen whitePen(Qt::white, 0);
whitePen.setStyle(Qt::SolidLine);
painter.setPen(whitePen);
painter.drawPath(decoration);
QPen redPen(Qt::red, 0);
redPen.setStyle(Qt::DotLine);
painter.setPen(redPen);
painter.drawPath(decoration);
}
KoCanvasBase *KoSnapGuide::canvas() const
{
return d->canvas;
}
void KoSnapGuide::setIgnoredPathPoints(const QList &ignoredPoints)
{
d->ignoredPoints = ignoredPoints;
}
QList KoSnapGuide::ignoredPathPoints() const
{
return d->ignoredPoints;
}
void KoSnapGuide::setIgnoredShapes(const QList &ignoredShapes)
{
d->ignoredShapes = ignoredShapes;
}
QList KoSnapGuide::ignoredShapes() const
{
return d->ignoredShapes;
}
void KoSnapGuide::reset()
{
d->currentStrategy.clear();
d->additionalEditedShape = 0;
d->ignoredPoints.clear();
d->ignoredShapes.clear();
// remove all custom strategies
int strategyCount = d->strategies.count();
for (int i = strategyCount-1; i >= 0; --i) {
if (d->strategies[i]->type() == CustomSnapping) {
d->strategies.removeAt(i);
}
}
}
diff --git a/libs/flake/KoSnapGuide.h b/libs/flake/KoSnapGuide.h
index f13f2fb651..3ddda87cc9 100644
--- a/libs/flake/KoSnapGuide.h
+++ b/libs/flake/KoSnapGuide.h
@@ -1,159 +1,160 @@
/* This file is part of the KDE project
* Copyright (C) 2008-2009 Jan Hambrecht
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KOSNAPGUIDE_H
#define KOSNAPGUIDE_H
#include "kritaflake_export.h"
#include
#include
#include
class KoSnapStrategy;
class KoShape;
class KoPathPoint;
class KoViewConverter;
class KoCanvasBase;
class QPainter;
class QPointF;
class QRectF;
/**
* This class is the place where all the snapping (i.e. snap to grid) is handled.
*
* What this class does is snapping a given position (i.e. mouse position) to various
* snapping targets like grid, boundbox etc.
* The snap guide does not know anything about the specific snapping target. This
* is handled by the different snapping strategies which are derived from KoSnapStrategy.
* Snapping strategies can be enabled/disabled by passing a mask of corresponding
* snapping ids to KoSnapGuide::enableSnapStrategies. There can be one or more snapping
* strategies enabled at the same time. The best result (with the nearest distance to the
* original position) is then returned to the caller of KoSnapGuide::snap.
*
* The snap guide is part of the KoCanvasBase class and thus can be accessed by any tool
* or application via the canvas pointer.
* For letting the user manage which snap stratgies to enable, there is a snap guide config
* widget in guiutils.
*
*/
class KRITAFLAKE_EXPORT KoSnapGuide
{
public:
/// the different possible snap Strategies
enum Strategy
{
OrthogonalSnapping = 1,
NodeSnapping = 2,
ExtensionSnapping = 4,
IntersectionSnapping = 8,
GridSnapping = 0x10,
BoundingBoxSnapping = 0x20,
GuideLineSnapping = 0x40,
DocumentBoundsSnapping = 0x80,
DocumentCenterSnapping = 0x100,
- CustomSnapping = 0x200
+ CustomSnapping = 0x200,
+ PixelSnapping = 0x400
};
Q_DECLARE_FLAGS(Strategies, Strategy)
/// Creates the snap guide to work on the given canvas
explicit KoSnapGuide(KoCanvasBase *canvas);
virtual ~KoSnapGuide();
/// snaps the mouse position, returns if mouse was snapped
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers);
QPointF snap(const QPointF &mousePosition, const QPointF &dragOffset, Qt::KeyboardModifiers modifiers);
/// paints the guide
void paint(QPainter &painter, const KoViewConverter &converter);
/// returns the bounding rect of the guide
QRectF boundingRect();
/// Adds an additional shape to snap to (useful when creating a path)
void setAdditionalEditedShape(KoShape *shape);
/// returns the extra shapes to use
KoShape *additionalEditedShape() const;
void enableSnapStrategy(Strategy type, bool value);
bool isStrategyEnabled(Strategy type) const;
/// enables the strategies used for snapping
void enableSnapStrategies(Strategies strategies);
/// returns the enabled snap strategies
KoSnapGuide::Strategies enabledSnapStrategies() const;
/**
* Adds a custom snap strategy
*
* The snap guide take ownership of the strategy. All custom strategies
* are destroyed when calling reset().
*/
bool addCustomSnapStrategy(KoSnapStrategy *customStrategy);
/**
* Overrides the first entry of a strategy \p type with a strategy
* \p strategy. Note that basically strategy->type() may not be equal
* to type and that is ok. \p strategy may also be null.
*/
void overrideSnapStrategy(Strategy type, KoSnapStrategy *strategy);
/// enables the snapping guides
void enableSnapping(bool on);
/// returns if snapping is enabled
bool isSnapping() const;
/// sets the snap distances in pixels
void setSnapDistance(int distance);
/// returns the snap distance in pixels
int snapDistance() const;
/// returns the canvas the snap guide is working on
KoCanvasBase *canvas() const;
/// Sets a list of path points to ignore
void setIgnoredPathPoints(const QList &ignoredPoints);
/// Returns list of ignored points
QList ignoredPathPoints() const;
/// Sets list of ignored shapes
void setIgnoredShapes(const QList &ignoredShapes);
/// Returns list of ignored shapes
QList ignoredShapes() const;
/// Resets the snap guide
void reset();
private:
class Private;
const QScopedPointer d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KoSnapGuide::Strategies)
#endif // KOSNAPGUIDE_H
diff --git a/libs/flake/KoSnapStrategy.cpp b/libs/flake/KoSnapStrategy.cpp
index f18c1dd23d..222a925ba0 100644
--- a/libs/flake/KoSnapStrategy.cpp
+++ b/libs/flake/KoSnapStrategy.cpp
@@ -1,641 +1,708 @@
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht
*
* 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 "KoSnapStrategy.h"
#include "KoSnapProxy.h"
#include "KoSnapGuide.h"
#include
#include
#include
#include
#include
#include
#include
#if defined(_MSC_VER) && (_MSC_VER < 1800)
#define isfinite(x) (double)(x)
#endif
KoSnapStrategy::KoSnapStrategy(KoSnapGuide::Strategy type)
: m_snapType(type)
{
}
QPointF KoSnapStrategy::snappedPosition() const
{
return m_snappedPosition;
}
void KoSnapStrategy::setSnappedPosition(const QPointF &position)
{
m_snappedPosition = position;
}
KoSnapGuide::Strategy KoSnapStrategy::type() const
{
return m_snapType;
}
qreal KoSnapStrategy::squareDistance(const QPointF &p1, const QPointF &p2)
{
const qreal dx = p1.x() - p2.x();
const qreal dy = p1.y() - p2.y();
return dx*dx + dy*dy;
}
qreal KoSnapStrategy::scalarProduct(const QPointF &p1, const QPointF &p2)
{
return p1.x() * p2.x() + p1.y() * p2.y();
}
OrthogonalSnapStrategy::OrthogonalSnapStrategy()
: KoSnapStrategy(KoSnapGuide::OrthogonalSnapping)
{
}
bool OrthogonalSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
QPointF horzSnap, vertSnap;
qreal minVertDist = HUGE_VAL;
qreal minHorzDist = HUGE_VAL;
QList shapes = proxy->shapes();
Q_FOREACH (KoShape * shape, shapes) {
QList points = proxy->pointsFromShape(shape);
foreach (const QPointF &point, points) {
qreal dx = fabs(point.x() - mousePosition.x());
if (dx < minHorzDist && dx < maxSnapDistance) {
minHorzDist = dx;
horzSnap = point;
}
qreal dy = fabs(point.y() - mousePosition.y());
if (dy < minVertDist && dy < maxSnapDistance) {
minVertDist = dy;
vertSnap = point;
}
}
}
QPointF snappedPoint = mousePosition;
if (minHorzDist < HUGE_VAL)
snappedPoint.setX(horzSnap.x());
if (minVertDist < HUGE_VAL)
snappedPoint.setY(vertSnap.y());
if (minHorzDist < HUGE_VAL)
m_hLine = QLineF(horzSnap, snappedPoint);
else
m_hLine = QLineF();
if (minVertDist < HUGE_VAL)
m_vLine = QLineF(vertSnap, snappedPoint);
else
m_vLine = QLineF();
setSnappedPosition(snappedPoint);
return (minHorzDist < HUGE_VAL || minVertDist < HUGE_VAL);
}
QPainterPath OrthogonalSnapStrategy::decoration(const KoViewConverter &/*converter*/) const
{
QPainterPath decoration;
if (! m_hLine.isNull()) {
decoration.moveTo(m_hLine.p1());
decoration.lineTo(m_hLine.p2());
}
if (! m_vLine.isNull()) {
decoration.moveTo(m_vLine.p1());
decoration.lineTo(m_vLine.p2());
}
return decoration;
}
NodeSnapStrategy::NodeSnapStrategy()
: KoSnapStrategy(KoSnapGuide::NodeSnapping)
{
}
bool NodeSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
const qreal maxDistance = maxSnapDistance * maxSnapDistance;
qreal minDistance = HUGE_VAL;
QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
rect.moveCenter(mousePosition);
QList points = proxy->pointsInRect(rect, false);
QPointF snappedPoint = mousePosition;
foreach (const QPointF &point, points) {
qreal distance = squareDistance(mousePosition, point);
if (distance < maxDistance && distance < minDistance) {
snappedPoint = point;
minDistance = distance;
}
}
setSnappedPosition(snappedPoint);
return (minDistance < HUGE_VAL);
}
QPainterPath NodeSnapStrategy::decoration(const KoViewConverter &converter) const
{
QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11));
unzoomedRect.moveCenter(snappedPosition());
QPainterPath decoration;
decoration.addEllipse(unzoomedRect);
return decoration;
}
ExtensionSnapStrategy::ExtensionSnapStrategy()
: KoSnapStrategy(KoSnapGuide::ExtensionSnapping)
{
}
bool ExtensionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
const qreal maxDistance = maxSnapDistance * maxSnapDistance;
qreal minDistances[2] = { HUGE_VAL, HUGE_VAL };
QPointF snappedPoints[2] = { mousePosition, mousePosition };
QPointF startPoints[2];
QList shapes = proxy->shapes(true);
Q_FOREACH (KoShape * shape, shapes) {
KoPathShape * path = dynamic_cast(shape);
if (! path) {
continue;
}
QTransform matrix = path->absoluteTransformation(0);
const int subpathCount = path->subpathCount();
for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
if (path->isClosedSubpath(subpathIndex))
continue;
int pointCount = path->subpathPointCount(subpathIndex);
// check the extension from the start point
KoPathPoint * first = path->pointByIndex(KoPathPointIndex(subpathIndex, 0));
QPointF firstSnapPosition = mousePosition;
if (snapToExtension(firstSnapPosition, first, matrix)) {
qreal distance = squareDistance(firstSnapPosition, mousePosition);
if (distance < maxDistance) {
if (distance < minDistances[0]) {
minDistances[1] = minDistances[0];
snappedPoints[1] = snappedPoints[0];
startPoints[1] = startPoints[0];
minDistances[0] = distance;
snappedPoints[0] = firstSnapPosition;
startPoints[0] = matrix.map(first->point());
}
else if (distance < minDistances[1]) {
minDistances[1] = distance;
snappedPoints[1] = firstSnapPosition;
startPoints[1] = matrix.map(first->point());
}
}
}
// now check the extension from the last point
KoPathPoint * last = path->pointByIndex(KoPathPointIndex(subpathIndex, pointCount - 1));
QPointF lastSnapPosition = mousePosition;
if (snapToExtension(lastSnapPosition, last, matrix)) {
qreal distance = squareDistance(lastSnapPosition, mousePosition);
if (distance < maxDistance) {
if (distance < minDistances[0]) {
minDistances[1] = minDistances[0];
snappedPoints[1] = snappedPoints[0];
startPoints[1] = startPoints[0];
minDistances[0] = distance;
snappedPoints[0] = lastSnapPosition;
startPoints[0] = matrix.map(last->point());
}
else if (distance < minDistances[1]) {
minDistances[1] = distance;
snappedPoints[1] = lastSnapPosition;
startPoints[1] = matrix.map(last->point());
}
}
}
}
}
m_lines.clear();
// if we have to extension near our mouse position, they might have an intersection
// near our mouse position which we want to use as the snapped position
if (minDistances[0] < HUGE_VAL && minDistances[1] < HUGE_VAL) {
// check if intersection of extension lines is near mouse position
KoPathSegment s1(startPoints[0], snappedPoints[0] + snappedPoints[0]-startPoints[0]);
KoPathSegment s2(startPoints[1], snappedPoints[1] + snappedPoints[1]-startPoints[1]);
QList isects = s1.intersections(s2);
if (isects.count() == 1 && squareDistance(isects[0], mousePosition) < maxDistance) {
// add both extension lines
m_lines.append(QLineF(startPoints[0], isects[0]));
m_lines.append(QLineF(startPoints[1], isects[0]));
setSnappedPosition(isects[0]);
}
else {
// only add nearest extension line of both
uint index = minDistances[0] < minDistances[1] ? 0 : 1;
m_lines.append(QLineF(startPoints[index], snappedPoints[index]));
setSnappedPosition(snappedPoints[index]);
}
}
else if (minDistances[0] < HUGE_VAL) {
m_lines.append(QLineF(startPoints[0], snappedPoints[0]));
setSnappedPosition(snappedPoints[0]);
}
else if (minDistances[1] < HUGE_VAL) {
m_lines.append(QLineF(startPoints[1], snappedPoints[1]));
setSnappedPosition(snappedPoints[1]);
}
else {
// none of the extension lines is near our mouse position
return false;
}
return true;
}
QPainterPath ExtensionSnapStrategy::decoration(const KoViewConverter &/*converter*/) const
{
QPainterPath decoration;
foreach (const QLineF &line, m_lines) {
decoration.moveTo(line.p1());
decoration.lineTo(line.p2());
}
return decoration;
}
bool ExtensionSnapStrategy::snapToExtension(QPointF &position, KoPathPoint * point, const QTransform &matrix)
{
Q_ASSERT(point);
QPointF direction = extensionDirection(point, matrix);
if (direction.isNull())
return false;
QPointF extensionStart = matrix.map(point->point());
QPointF extensionStop = matrix.map(point->point()) + direction;
float posOnExtension = project(extensionStart, extensionStop, position);
if (posOnExtension < 0.0)
return false;
position = extensionStart + posOnExtension * direction;
return true;
}
qreal ExtensionSnapStrategy::project(const QPointF &lineStart, const QPointF &lineEnd, const QPointF &point)
{
// This is how the returned value should be used to get the
// projectionPoint: ProjectionPoint = lineStart(1-resultingReal) + resultingReal*lineEnd;
QPointF diff = lineEnd - lineStart;
QPointF relPoint = point - lineStart;
qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
if (diffLength == 0.0)
return 0.0;
diff /= diffLength;
// project mouse position relative to stop position on extension line
qreal scalar = relPoint.x() * diff.x() + relPoint.y() * diff.y();
return scalar /= diffLength;
}
QPointF ExtensionSnapStrategy::extensionDirection(KoPathPoint * point, const QTransform &matrix)
{
Q_ASSERT(point);
KoPathShape * path = point->parent();
KoPathPointIndex index = path->pathPointIndex(point);
// check if it is a start point
if (point->properties() & KoPathPoint::StartSubpath) {
if (point->activeControlPoint2()) {
return matrix.map(point->point()) - matrix.map(point->controlPoint2());
} else {
KoPathPoint * next = path->pointByIndex(KoPathPointIndex(index.first, index.second + 1));
if (! next){
return QPointF();
}
else if (next->activeControlPoint1()) {
return matrix.map(point->point()) - matrix.map(next->controlPoint1());
}
else {
return matrix.map(point->point()) - matrix.map(next->point());
}
}
}
else {
if (point->activeControlPoint1()) {
return matrix.map(point->point()) - matrix.map(point->controlPoint1());
}
else {
KoPathPoint * prev = path->pointByIndex(KoPathPointIndex(index.first, index.second - 1));
if (! prev){
return QPointF();
}
else if (prev->activeControlPoint2()) {
return matrix.map(point->point()) - matrix.map(prev->controlPoint2());
}
else {
return matrix.map(point->point()) - matrix.map(prev->point());
}
}
}
}
IntersectionSnapStrategy::IntersectionSnapStrategy()
: KoSnapStrategy(KoSnapGuide::IntersectionSnapping)
{
}
bool IntersectionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
const qreal maxDistance = maxSnapDistance * maxSnapDistance;
qreal minDistance = HUGE_VAL;
QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
rect.moveCenter(mousePosition);
QPointF snappedPoint = mousePosition;
QList segments = proxy->segmentsInRect(rect, false);
int segmentCount = segments.count();
for (int i = 0; i < segmentCount; ++i) {
const KoPathSegment &s1 = segments[i];
for (int j = i + 1; j < segmentCount; ++j) {
QList isects = s1.intersections(segments[j]);
Q_FOREACH (const QPointF &point, isects) {
if (! rect.contains(point))
continue;
qreal distance = squareDistance(mousePosition, point);
if (distance < maxDistance && distance < minDistance) {
snappedPoint = point;
minDistance = distance;
}
}
}
}
setSnappedPosition(snappedPoint);
return (minDistance < HUGE_VAL);
}
QPainterPath IntersectionSnapStrategy::decoration(const KoViewConverter &converter) const
{
QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11));
unzoomedRect.moveCenter(snappedPosition());
QPainterPath decoration;
decoration.addRect(unzoomedRect);
return decoration;
}
GridSnapStrategy::GridSnapStrategy()
: KoSnapStrategy(KoSnapGuide::GridSnapping)
{
}
bool GridSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
if (! proxy->canvas()->snapToGrid())
return false;
// The 1e-10 here is a workaround for some weird division problem.
// 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a qreal,
// but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 !
QPointF offset;
QSizeF spacing;
proxy->canvas()->gridSize(&offset, &spacing);
// we want to snap to the nearest grid point, so calculate
// the grid rows/columns before and after the points position
int col = static_cast((mousePosition.x() - offset.x()) / spacing.width() + 1e-10);
int nextCol = col + 1;
int row = static_cast((mousePosition.y() - offset.y()) / spacing.height() + 1e-10);
int nextRow = row + 1;
// now check which grid line has less distance to the point
qreal distToCol = qAbs(offset.x() + col * spacing.width() - mousePosition.x());
qreal distToNextCol = qAbs(offset.x() + nextCol * spacing.width() - mousePosition.x());
if (distToCol > distToNextCol) {
col = nextCol;
distToCol = distToNextCol;
}
qreal distToRow = qAbs(offset.y() + row * spacing.height() - mousePosition.y());
qreal distToNextRow = qAbs(offset.y() + nextRow * spacing.height() - mousePosition.y());
if (distToRow > distToNextRow) {
row = nextRow;
distToRow = distToNextRow;
}
QPointF snappedPoint = mousePosition;
bool pointIsSnapped = false;
const qreal sqDistance = distToCol * distToCol + distToRow * distToRow;
const qreal maxSqDistance = maxSnapDistance * maxSnapDistance;
// now check if we are inside the snap distance
if (sqDistance < maxSqDistance) {
snappedPoint = QPointF(offset.x() + col * spacing.width(), offset.y() + row * spacing.height());
pointIsSnapped = true;
} else if (distToRow < maxSnapDistance) {
snappedPoint.ry() = offset.y() + row * spacing.height();
pointIsSnapped = true;
} else if (distToCol < maxSnapDistance) {
snappedPoint.rx() = offset.x() + col * spacing.width();
pointIsSnapped = true;
}
setSnappedPosition(snappedPoint);
return pointIsSnapped;
}
QPainterPath GridSnapStrategy::decoration(const KoViewConverter &converter) const
{
QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
QPainterPath decoration;
decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
return decoration;
}
BoundingBoxSnapStrategy::BoundingBoxSnapStrategy()
: KoSnapStrategy(KoSnapGuide::BoundingBoxSnapping)
{
}
bool BoundingBoxSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
const qreal maxDistance = maxSnapDistance * maxSnapDistance;
qreal minDistance = HUGE_VAL;
QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
rect.moveCenter(mousePosition);
QPointF snappedPoint = mousePosition;
KoFlake::AnchorPosition pointId[5] = {
KoFlake::TopLeft,
KoFlake::TopRight,
KoFlake::BottomRight,
KoFlake::BottomLeft,
KoFlake::Center
};
QList shapes = proxy->shapesInRect(rect, true);
Q_FOREACH (KoShape * shape, shapes) {
qreal shapeMinDistance = HUGE_VAL;
// first check the corner and center points
for (int i = 0; i < 5; ++i) {
m_boxPoints[i] = shape->absolutePosition(pointId[i]);
qreal d = squareDistance(mousePosition, m_boxPoints[i]);
if (d < minDistance && d < maxDistance) {
shapeMinDistance = d;
minDistance = d;
snappedPoint = m_boxPoints[i];
}
}
// prioritize points over edges
if (shapeMinDistance < maxDistance)
continue;
// now check distances to edges of bounding box
for (int i = 0; i < 4; ++i) {
QPointF pointOnLine;
qreal d = squareDistanceToLine(m_boxPoints[i], m_boxPoints[(i+1)%4], mousePosition, pointOnLine);
if (d < minDistance && d < maxDistance) {
minDistance = d;
snappedPoint = pointOnLine;
}
}
}
setSnappedPosition(snappedPoint);
return (minDistance < maxDistance);
}
qreal BoundingBoxSnapStrategy::squareDistanceToLine(const QPointF &lineA, const QPointF &lineB, const QPointF &point, QPointF &pointOnLine)
{
QPointF diff = lineB - lineA;
if(lineA == lineB)
return HUGE_VAL;
const qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
// project mouse position relative to start position on line
const qreal scalar = KoSnapStrategy::scalarProduct(point - lineA, diff / diffLength);
if (scalar < 0.0 || scalar > diffLength)
return HUGE_VAL;
// calculate vector between relative mouse position and projected mouse position
pointOnLine = lineA + scalar / diffLength * diff;
QPointF distVec = pointOnLine - point;
return distVec.x()*distVec.x() + distVec.y()*distVec.y();
}
QPainterPath BoundingBoxSnapStrategy::decoration(const KoViewConverter &converter) const
{
QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
QPainterPath decoration;
decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), unzoomedSize.height()));
decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), unzoomedSize.height()));
decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), -unzoomedSize.height()));
decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), -unzoomedSize.height()));
return decoration;
}
+PixelSnapStrategy::PixelSnapStrategy()
+ : KoSnapStrategy(KoSnapGuide::PixelSnapping)
+{
+}
+
+bool PixelSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
+{
+ Q_ASSERT(std::isfinite(maxSnapDistance));
+
+ QPointF p = proxy->canvas()->mapImageToDocument(QPointF(1,1));
+ QSizeF spacing(p.x(),p.y());
+
+ int col = static_cast((mousePosition.x()) / spacing.width() + 1e-10);
+ int nextCol = col + 1;
+ int row = static_cast((mousePosition.y()) / spacing.height() + 1e-10);
+ int nextRow = row + 1;
+
+ // now check which grid line has less distance to the point
+ qreal distToCol = qAbs(col * spacing.width() - mousePosition.x());
+ qreal distToNextCol = qAbs(nextCol * spacing.width() - mousePosition.x());
+
+ if (distToCol > distToNextCol) {
+ col = nextCol;
+ distToCol = distToNextCol;
+ }
+
+ qreal distToRow = qAbs(row * spacing.height() - mousePosition.y());
+ qreal distToNextRow = qAbs(nextRow * spacing.height() - mousePosition.y());
+ if (distToRow > distToNextRow) {
+ row = nextRow;
+ distToRow = distToNextRow;
+ }
+
+ QPointF snappedPoint = mousePosition;
+
+ bool pointIsSnapped = false;
+
+ const qreal sqDistance = distToCol * distToCol + distToRow * distToRow;
+ const qreal maxSqDistance = maxSnapDistance * maxSnapDistance;
+ // now check if we are inside the snap distance
+ if (sqDistance < maxSqDistance) {
+ snappedPoint = QPointF(col * spacing.width(), row * spacing.height());
+ pointIsSnapped = true;
+ } else if (distToRow < maxSnapDistance) {
+ snappedPoint.ry() = row * spacing.height();
+ pointIsSnapped = true;
+ } else if (distToCol < maxSnapDistance) {
+ snappedPoint.rx() = col * spacing.width();
+ pointIsSnapped = true;
+ }
+
+ setSnappedPosition(snappedPoint);
+
+ return pointIsSnapped;
+}
+
+QPainterPath PixelSnapStrategy::decoration(const KoViewConverter &converter) const
+{
+ QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
+ QPainterPath decoration;
+ decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
+ decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
+ decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
+ decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
+ return decoration;
+}
+
// KoGuidesData has been moved into Krita. Please port this class!
// LineGuideSnapStrategy::LineGuideSnapStrategy()
// : KoSnapStrategy(KoSnapGuide::GuideLineSnapping)
// {
// }
// bool LineGuideSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
// {
// Q_ASSERT(std::isfinite(maxSnapDistance));
// KoGuidesData * guidesData = proxy->canvas()->guidesData();
// if (!guidesData || !guidesData->showGuideLines())
// return false;
// QPointF snappedPoint = mousePosition;
// m_orientation = 0;
// qreal minHorzDistance = maxSnapDistance;
// Q_FOREACH (qreal guidePos, guidesData->horizontalGuideLines()) {
// qreal distance = qAbs(guidePos - mousePosition.y());
// if (distance < minHorzDistance) {
// snappedPoint.setY(guidePos);
// minHorzDistance = distance;
// m_orientation |= Qt::Horizontal;
// }
// }
// qreal minVertSnapDistance = maxSnapDistance;
// Q_FOREACH (qreal guidePos, guidesData->verticalGuideLines()) {
// qreal distance = qAbs(guidePos - mousePosition.x());
// if (distance < minVertSnapDistance) {
// snappedPoint.setX(guidePos);
// minVertSnapDistance = distance;
// m_orientation |= Qt::Vertical;
// }
// }
// setSnappedPosition(snappedPoint);
// return (minHorzDistance < maxSnapDistance || minVertSnapDistance < maxSnapDistance);
// }
// QPainterPath LineGuideSnapStrategy::decoration(const KoViewConverter &converter) const
// {
// QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
// Q_ASSERT(unzoomedSize.isValid());
// QPainterPath decoration;
// if (m_orientation & Qt::Horizontal) {
// decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
// decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
// }
// if (m_orientation & Qt::Vertical) {
// decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
// decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
// }
// return decoration;
// }
diff --git a/libs/flake/KoSnapStrategy.h b/libs/flake/KoSnapStrategy.h
index 3102755294..af031c52f4 100644
--- a/libs/flake/KoSnapStrategy.h
+++ b/libs/flake/KoSnapStrategy.h
@@ -1,144 +1,153 @@
/* This file is part of the KDE project
* Copyright (C) 2008-2009 Jan Hambrecht
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KOSNAPSTRATEGY_H
#define KOSNAPSTRATEGY_H
#include "KoSnapGuide.h"
#include
class TestSnapStrategy;
class KoPathPoint;
class KoSnapProxy;
class KoViewConverter;
class QTransform;
class QPainterPath;
class KRITAFLAKE_EXPORT KoSnapStrategy
{
public:
KoSnapStrategy(KoSnapGuide::Strategy type);
virtual ~KoSnapStrategy() {};
virtual bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) = 0;
/// returns the strategies type
KoSnapGuide::Strategy type() const;
static qreal squareDistance(const QPointF &p1, const QPointF &p2);
static qreal scalarProduct(const QPointF &p1, const QPointF &p2);
/// returns the snapped position form the last call to snapToPoints
QPointF snappedPosition() const;
/// returns the current snap strategy decoration
virtual QPainterPath decoration(const KoViewConverter &converter) const = 0;
protected:
/// sets the current snapped position
void setSnappedPosition(const QPointF &position);
private:
KoSnapGuide::Strategy m_snapType;
QPointF m_snappedPosition;
};
/// snaps to x- or y-coordinates of path points
class KRITAFLAKE_EXPORT OrthogonalSnapStrategy : public KoSnapStrategy
{
public:
OrthogonalSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
private:
QLineF m_hLine;
QLineF m_vLine;
};
/// snaps to path points
class KRITAFLAKE_EXPORT NodeSnapStrategy : public KoSnapStrategy
{
public:
NodeSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
};
/// snaps extension lines of path shapes
class KRITAFLAKE_EXPORT ExtensionSnapStrategy : public KoSnapStrategy
{
friend class TestSnapStrategy;
public:
ExtensionSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
private:
qreal project(const QPointF &lineStart , const QPointF &lineEnd, const QPointF &point);
QPointF extensionDirection(KoPathPoint * point, const QTransform &matrix);
bool snapToExtension(QPointF &position, KoPathPoint * point, const QTransform &matrix);
QList m_lines;
};
/// snaps to intersections of shapes
class KRITAFLAKE_EXPORT IntersectionSnapStrategy : public KoSnapStrategy
{
public:
IntersectionSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
};
/// snaps to the canvas grid
class KRITAFLAKE_EXPORT GridSnapStrategy : public KoSnapStrategy
{
public:
GridSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
};
/// snaps to shape bounding boxes
class KRITAFLAKE_EXPORT BoundingBoxSnapStrategy : public KoSnapStrategy
{
friend class TestSnapStrategy;
public:
BoundingBoxSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
private:
qreal squareDistanceToLine(const QPointF &lineA, const QPointF &lineB, const QPointF &point, QPointF &pointOnLine);
QPointF m_boxPoints[5];
};
+/// snaps to the pixels
+class KRITAFLAKE_EXPORT PixelSnapStrategy : public KoSnapStrategy
+{
+public:
+ PixelSnapStrategy();
+ bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
+ QPainterPath decoration(const KoViewConverter &converter) const override;
+};
+
// KoGuidesData has been moved into Krita. Please port this class!
//
/// snaps to line guides
// class KRITAFLAKE_EXPORT LineGuideSnapStrategy : public KoSnapStrategy
// {
// public:
// LineGuideSnapStrategy();
// virtual bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance);
// virtual QPainterPath decoration(const KoViewConverter &converter) const;
// private:
// int m_orientation;
// };
#endif // KOSNAPSTRATEGY_H
diff --git a/libs/ui/canvas/kis_canvas2.cpp b/libs/ui/canvas/kis_canvas2.cpp
index 8f505a5540..53c39e41cc 100644
--- a/libs/ui/canvas/kis_canvas2.cpp
+++ b/libs/ui/canvas/kis_canvas2.cpp
@@ -1,1278 +1,1284 @@
/* This file is part of the KDE project
*
* Copyright (C) 2006, 2010 Boudewijn Rempt
* Copyright (C) Lukáš Tvrdý , (C) 2010
* Copyright (C) 2011 Silvio Heinrich
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA..
*/
#include "kis_canvas2.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_tool_proxy.h"
#include "kis_coordinates_converter.h"
#include "kis_prescaled_projection.h"
#include "kis_image.h"
#include "kis_image_barrier_locker.h"
#include "kis_undo_adapter.h"
#include "flake/kis_shape_layer.h"
#include "kis_canvas_resource_provider.h"
#include "KisViewManager.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_abstract_canvas_widget.h"
#include "kis_qpainter_canvas.h"
#include "kis_group_layer.h"
#include "flake/kis_shape_controller.h"
#include "kis_node_manager.h"
#include "kis_selection.h"
#include "kis_selection_component.h"
#include "flake/kis_shape_selection.h"
#include "kis_selection_mask.h"
#include "kis_image_config.h"
#include "kis_infinity_manager.h"
#include "kis_signal_compressor.h"
#include "kis_display_color_converter.h"
#include "kis_exposure_gamma_correction_interface.h"
#include "KisView.h"
#include "kis_canvas_controller.h"
#include "kis_grid_config.h"
#include "kis_animation_player.h"
#include "kis_animation_frame_cache.h"
#include "opengl/kis_opengl_canvas2.h"
#include "opengl/kis_opengl.h"
#include "kis_fps_decoration.h"
#include "KoColorConversionTransformation.h"
#include "KisProofingConfiguration.h"
#include
#include
#include "input/kis_input_manager.h"
#include "kis_painting_assistants_decoration.h"
#include "kis_canvas_updates_compressor.h"
#include "KoZoomController.h"
#include
#include "opengl/kis_opengl_canvas_debugger.h"
#include "kis_algebra_2d.h"
#include "kis_image_signal_router.h"
class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private
{
public:
KisCanvas2Private(KoCanvasBase *parent, KisCoordinatesConverter* coordConverter, QPointer view, KoCanvasResourceProvider* resourceManager)
: coordinatesConverter(coordConverter)
, view(view)
, shapeManager(parent)
, selectedShapesProxy(&shapeManager)
, toolProxy(parent)
, displayColorConverter(resourceManager, view)
, regionOfInterestUpdateCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
{
}
KisCoordinatesConverter *coordinatesConverter;
QPointerview;
KisAbstractCanvasWidget *canvasWidget = 0;
KoShapeManager shapeManager;
KisSelectedShapesProxy selectedShapesProxy;
bool currentCanvasIsOpenGL;
int openGLFilterMode;
KisToolProxy toolProxy;
KisPrescaledProjectionSP prescaledProjection;
bool vastScrolling;
KisSignalCompressor canvasUpdateCompressor;
QRect savedUpdateRect;
QBitArray channelFlags;
KisProofingConfigurationSP proofingConfig;
bool softProofing = false;
bool gamutCheck = false;
bool proofingConfigUpdated = false;
KisPopupPalette *popupPalette = 0;
KisDisplayColorConverter displayColorConverter;
KisCanvasUpdatesCompressor projectionUpdatesCompressor;
KisAnimationPlayer *animationPlayer;
KisAnimationFrameCacheSP frameCache;
bool lodAllowedInImage = false;
bool bootstrapLodBlocked;
QPointer currentlyActiveShapeManager;
KisInputActionGroupsMask inputActionGroupsMask = AllActionGroup;
KisSignalCompressor frameRenderStartCompressor;
KisSignalCompressor regionOfInterestUpdateCompressor;
QRect regionOfInterest;
QRect renderingLimit;
int isBatchUpdateActive = 0;
bool effectiveLodAllowedInImage() {
return lodAllowedInImage && !bootstrapLodBlocked;
}
void setActiveShapeManager(KoShapeManager *shapeManager);
};
namespace {
KoShapeManager* fetchShapeManagerFromNode(KisNodeSP node)
{
KoShapeManager *shapeManager = 0;
KisSelectionSP selection;
if (KisLayer *layer = dynamic_cast(node.data())) {
KisShapeLayer *shapeLayer = dynamic_cast(layer);
if (shapeLayer) {
shapeManager = shapeLayer->shapeManager();
}
} else if (KisSelectionMask *mask = dynamic_cast(node.data())) {
selection = mask->selection();
}
if (!shapeManager && selection && selection->hasShapeSelection()) {
KisShapeSelection *shapeSelection = dynamic_cast(selection->shapeSelection());
KIS_ASSERT_RECOVER_RETURN_VALUE(shapeSelection, 0);
shapeManager = shapeSelection->shapeManager();
}
return shapeManager;
}
}
KisCanvas2::KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceProvider *resourceManager, KisView *view, KoShapeControllerBase *sc)
: KoCanvasBase(sc, resourceManager)
, m_d(new KisCanvas2Private(this, coordConverter, view, resourceManager))
{
/**
* While loading LoD should be blocked. Only when GUI has finished
* loading and zoom level settled down, LoD is given a green
* light.
*/
m_d->bootstrapLodBlocked = true;
connect(view->mainWindow(), SIGNAL(guiLoadingFinished()), SLOT(bootstrapFinished()));
connect(view->mainWindow(), SIGNAL(screenChanged()), SLOT(slotConfigChanged()));
KisImageConfig config(false);
m_d->canvasUpdateCompressor.setDelay(1000 / config.fpsLimit());
m_d->canvasUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
m_d->frameRenderStartCompressor.setDelay(1000 / config.fpsLimit());
m_d->frameRenderStartCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
}
void KisCanvas2::setup()
{
// a bit of duplication from slotConfigChanged()
KisConfig cfg(true);
m_d->vastScrolling = cfg.vastScrolling();
m_d->lodAllowedInImage = cfg.levelOfDetailEnabled();
createCanvas(cfg.useOpenGL());
setLodAllowedInCanvas(m_d->lodAllowedInImage);
m_d->animationPlayer = new KisAnimationPlayer(this);
connect(m_d->view->canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SLOT(documentOffsetMoved(QPoint)));
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
/**
* We switch the shape manager every time vector layer or
* shape selection is activated. Flake does not expect this
* and connects all the signals of the global shape manager
* to the clients in the constructor. To workaround this we
* forward the signals of local shape managers stored in the
* vector layers to the signals of global shape manager. So the
* sequence of signal deliveries is the following:
*
* shapeLayer.m_d.canvas.m_shapeManager.selection() ->
* shapeLayer ->
* shapeController ->
* globalShapeManager.selection()
*/
KisShapeController *kritaShapeController = static_cast(shapeController()->documentBase());
connect(kritaShapeController, SIGNAL(selectionChanged()),
this, SLOT(slotSelectionChanged()));
connect(kritaShapeController, SIGNAL(selectionContentChanged()),
selectedShapesProxy(), SIGNAL(selectionContentChanged()));
connect(kritaShapeController, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
selectedShapesProxy(), SIGNAL(currentLayerChanged(const KoShapeLayer*)));
connect(&m_d->canvasUpdateCompressor, SIGNAL(timeout()), SLOT(slotDoCanvasUpdate()));
connect(this, SIGNAL(sigCanvasCacheUpdated()), &m_d->frameRenderStartCompressor, SLOT(start()));
connect(&m_d->frameRenderStartCompressor, SIGNAL(timeout()), SLOT(updateCanvasProjection()));
connect(this, SIGNAL(sigContinueResizeImage(qint32,qint32)), SLOT(finishResizingImage(qint32,qint32)));
connect(&m_d->regionOfInterestUpdateCompressor, SIGNAL(timeout()), SLOT(slotUpdateRegionOfInterest()));
connect(m_d->view->document(), SIGNAL(sigReferenceImagesChanged()), this, SLOT(slotReferenceImagesChanged()));
initializeFpsDecoration();
}
void KisCanvas2::initializeFpsDecoration()
{
KisConfig cfg(true);
const bool shouldShowDebugOverlay =
(canvasIsOpenGL() && cfg.enableOpenGLFramerateLogging()) ||
cfg.enableBrushSpeedLogging();
if (shouldShowDebugOverlay && !decoration(KisFpsDecoration::idTag)) {
addDecoration(new KisFpsDecoration(imageView()));
if (cfg.enableBrushSpeedLogging()) {
connect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
}
} else if (!shouldShowDebugOverlay && decoration(KisFpsDecoration::idTag)) {
m_d->canvasWidget->removeDecoration(KisFpsDecoration::idTag);
disconnect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
}
}
KisCanvas2::~KisCanvas2()
{
if (m_d->animationPlayer->isPlaying()) {
m_d->animationPlayer->forcedStopOnExit();
}
delete m_d;
}
void KisCanvas2::setCanvasWidget(KisAbstractCanvasWidget *widget)
{
if (m_d->popupPalette) {
m_d->popupPalette->setParent(widget->widget());
}
if (m_d->canvasWidget != 0) {
widget->setDecorations(m_d->canvasWidget->decorations());
// Redundant check for the constructor case, see below
if(viewManager() != 0)
viewManager()->inputManager()->removeTrackedCanvas(this);
}
m_d->canvasWidget = widget;
// Either tmp was null or we are being called by KisCanvas2 constructor that is called by KisView
// constructor, so the view manager still doesn't exists.
if(m_d->canvasWidget != 0 && viewManager() != 0)
viewManager()->inputManager()->addTrackedCanvas(this);
if (!m_d->canvasWidget->decoration(INFINITY_DECORATION_ID)) {
KisInfinityManager *manager = new KisInfinityManager(m_d->view, this);
manager->setVisible(true);
m_d->canvasWidget->addDecoration(manager);
}
widget->widget()->setAutoFillBackground(false);
widget->widget()->setAttribute(Qt::WA_OpaquePaintEvent);
widget->widget()->setMouseTracking(true);
widget->widget()->setAcceptDrops(true);
KoCanvasControllerWidget *controller = dynamic_cast(canvasController());
if (controller && controller->canvas() == this) {
controller->changeCanvasWidget(widget->widget());
}
}
bool KisCanvas2::canvasIsOpenGL() const
{
return m_d->currentCanvasIsOpenGL;
}
KisOpenGL::FilterMode KisCanvas2::openGLFilterMode() const
{
return KisOpenGL::FilterMode(m_d->openGLFilterMode);
}
void KisCanvas2::gridSize(QPointF *offset, QSizeF *spacing) const
{
QTransform transform = coordinatesConverter()->imageToDocumentTransform();
const QPoint intSpacing = m_d->view->document()->gridConfig().spacing();
const QPoint intOffset = m_d->view->document()->gridConfig().offset();
QPointF size = transform.map(QPointF(intSpacing));
spacing->rwidth() = size.x();
spacing->rheight() = size.y();
*offset = transform.map(QPointF(intOffset));
}
+QPointF KisCanvas2::mapImageToDocument(const QPointF &point) {
+ QTransform transform = coordinatesConverter()->imageToDocumentTransform();
+ QPointF newPoint = transform.map(point);
+ return newPoint;
+}
+
bool KisCanvas2::snapToGrid() const
{
return m_d->view->document()->gridConfig().snapToGrid();
}
qreal KisCanvas2::rotationAngle() const
{
return m_d->coordinatesConverter->rotationAngle();
}
bool KisCanvas2::xAxisMirrored() const
{
return m_d->coordinatesConverter->xAxisMirrored();
}
bool KisCanvas2::yAxisMirrored() const
{
return m_d->coordinatesConverter->yAxisMirrored();
}
void KisCanvas2::channelSelectionChanged()
{
KisImageSP image = this->image();
m_d->channelFlags = image->rootLayer()->channelFlags();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
image->barrierLock();
m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags);
startUpdateInPatches(image->bounds());
image->unlock();
}
void KisCanvas2::addCommand(KUndo2Command *command)
{
// This method exists to support flake-related operations
m_d->view->document()->addCommand(command);
}
void KisCanvas2::KisCanvas2Private::setActiveShapeManager(KoShapeManager *shapeManager)
{
if (shapeManager != currentlyActiveShapeManager) {
currentlyActiveShapeManager = shapeManager;
selectedShapesProxy.setShapeManager(shapeManager);
}
}
KoShapeManager* KisCanvas2::shapeManager() const
{
KoShapeManager *localShapeManager = this->localShapeManager();
// sanity check for consistency of the local shape manager
KIS_SAFE_ASSERT_RECOVER (localShapeManager == m_d->currentlyActiveShapeManager) {
localShapeManager = globalShapeManager();
}
return localShapeManager ? localShapeManager : globalShapeManager();
}
KoSelectedShapesProxy* KisCanvas2::selectedShapesProxy() const
{
return &m_d->selectedShapesProxy;
}
KoShapeManager* KisCanvas2::globalShapeManager() const
{
return &m_d->shapeManager;
}
KoShapeManager *KisCanvas2::localShapeManager() const
{
KisNodeSP node = m_d->view->currentNode();
KoShapeManager *localShapeManager = fetchShapeManagerFromNode(node);
if (localShapeManager != m_d->currentlyActiveShapeManager) {
m_d->setActiveShapeManager(localShapeManager);
}
return localShapeManager;
}
void KisCanvas2::updateInputMethodInfo()
{
// TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas widget...
}
const KisCoordinatesConverter* KisCanvas2::coordinatesConverter() const
{
return m_d->coordinatesConverter;
}
KoViewConverter* KisCanvas2::viewConverter() const
{
return m_d->coordinatesConverter;
}
KisInputManager* KisCanvas2::globalInputManager() const
{
return m_d->view->globalInputManager();
}
KisInputActionGroupsMask KisCanvas2::inputActionGroupsMask() const
{
return m_d->inputActionGroupsMask;
}
void KisCanvas2::setInputActionGroupsMask(KisInputActionGroupsMask mask)
{
m_d->inputActionGroupsMask = mask;
}
QWidget* KisCanvas2::canvasWidget()
{
return m_d->canvasWidget->widget();
}
const QWidget* KisCanvas2::canvasWidget() const
{
return m_d->canvasWidget->widget();
}
KoUnit KisCanvas2::unit() const
{
KoUnit unit(KoUnit::Pixel);
KisImageWSP image = m_d->view->image();
if (image) {
if (!qFuzzyCompare(image->xRes(), image->yRes())) {
warnKrita << "WARNING: resolution of the image is anisotropic"
<< ppVar(image->xRes())
<< ppVar(image->yRes());
}
const qreal resolution = image->xRes();
unit.setFactor(resolution);
}
return unit;
}
KoToolProxy * KisCanvas2::toolProxy() const
{
return &m_d->toolProxy;
}
void KisCanvas2::createQPainterCanvas()
{
m_d->currentCanvasIsOpenGL = false;
KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->coordinatesConverter, m_d->view);
m_d->prescaledProjection = new KisPrescaledProjection();
m_d->prescaledProjection->setCoordinatesConverter(m_d->coordinatesConverter);
m_d->prescaledProjection->setMonitorProfile(m_d->displayColorConverter.monitorProfile(),
m_d->displayColorConverter.renderingIntent(),
m_d->displayColorConverter.conversionFlags());
m_d->prescaledProjection->setDisplayFilter(m_d->displayColorConverter.displayFilter());
canvasWidget->setPrescaledProjection(m_d->prescaledProjection);
setCanvasWidget(canvasWidget);
}
void KisCanvas2::createOpenGLCanvas()
{
KisConfig cfg(true);
m_d->openGLFilterMode = cfg.openGLFilteringMode();
m_d->currentCanvasIsOpenGL = true;
KisOpenGLCanvas2 *canvasWidget = new KisOpenGLCanvas2(this, m_d->coordinatesConverter, 0, m_d->view->image(), &m_d->displayColorConverter);
m_d->frameCache = KisAnimationFrameCache::getFrameCache(canvasWidget->openGLImageTextures());
setCanvasWidget(canvasWidget);
}
void KisCanvas2::createCanvas(bool useOpenGL)
{
// deinitialize previous canvas structures
m_d->prescaledProjection = 0;
m_d->frameCache = 0;
KisConfig cfg(true);
QDesktopWidget dw;
const KoColorProfile *profile = cfg.displayProfile(dw.screenNumber(imageView()));
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(useOpenGL && KisOpenGL::hasOpenGL());
m_d->displayColorConverter.setMonitorProfile(profile);
if (useOpenGL && !KisOpenGL::hasOpenGL()) {
warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
useOpenGL = false;
}
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(useOpenGL);
if (useOpenGL) {
createOpenGLCanvas();
if (cfg.canvasState() == "OPENGL_FAILED") {
// Creating the opengl canvas failed, fall back
warnKrita << "OpenGL Canvas initialization returned OPENGL_FAILED. Falling back to QPainter.";
m_d->displayColorConverter.notifyOpenGLCanvasIsActive(false);
createQPainterCanvas();
}
} else {
createQPainterCanvas();
}
if (m_d->popupPalette) {
m_d->popupPalette->setParent(m_d->canvasWidget->widget());
}
}
void KisCanvas2::initializeImage()
{
KisImageSP image = m_d->view->image();
m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
m_d->coordinatesConverter->setImage(image);
m_d->toolProxy.initializeImage(image);
connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateStarted()), SLOT(slotBeginUpdatesBatch()), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateEnded()), SLOT(slotEndUpdatesBatch()), Qt::DirectConnection);
connect(image->signalRouter(), SIGNAL(sigRequestLodPlanesSyncBlocked(bool)), SLOT(slotSetLodUpdatesBlocked(bool)), Qt::DirectConnection);
connect(image, SIGNAL(sigProofingConfigChanged()), SLOT(slotChangeProofingConfig()));
connect(image, SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(startResizingImage()), Qt::DirectConnection);
connect(image->undoAdapter(), SIGNAL(selectionChanged()), SLOT(slotTrySwitchShapeManager()));
connect(image, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), SLOT(slotImageColorSpaceChanged()));
connect(image, SIGNAL(sigProfileChanged(const KoColorProfile*)), SLOT(slotImageColorSpaceChanged()));
connectCurrentCanvas();
}
void KisCanvas2::connectCurrentCanvas()
{
KisImageWSP image = m_d->view->image();
if (!m_d->currentCanvasIsOpenGL) {
Q_ASSERT(m_d->prescaledProjection);
m_d->prescaledProjection->setImage(image);
}
startResizingImage();
setLodAllowedInCanvas(m_d->lodAllowedInImage);
emit sigCanvasEngineChanged();
}
void KisCanvas2::resetCanvas(bool useOpenGL)
{
// we cannot reset the canvas before it's created, but this method might be called,
// for instance when setting the monitor profile.
if (!m_d->canvasWidget) {
return;
}
KisConfig cfg(true);
bool needReset = (m_d->currentCanvasIsOpenGL != useOpenGL) ||
(m_d->currentCanvasIsOpenGL &&
m_d->openGLFilterMode != cfg.openGLFilteringMode());
if (needReset) {
createCanvas(useOpenGL);
connectCurrentCanvas();
notifyZoomChanged();
}
updateCanvasWidgetImpl();
}
void KisCanvas2::startUpdateInPatches(const QRect &imageRect)
{
/**
* We don't do patched loading for openGL canvas, becasue it loads
* the tiles, which are bascially "patches". Therefore, big chunks
* of memory are never allocated.
*/
if (m_d->currentCanvasIsOpenGL) {
startUpdateCanvasProjection(imageRect);
} else {
KisImageConfig imageConfig(true);
int patchWidth = imageConfig.updatePatchWidth();
int patchHeight = imageConfig.updatePatchHeight();
for (int y = 0; y < imageRect.height(); y += patchHeight) {
for (int x = 0; x < imageRect.width(); x += patchWidth) {
QRect patchRect(x, y, patchWidth, patchHeight);
startUpdateCanvasProjection(patchRect);
}
}
}
}
void KisCanvas2::setDisplayFilter(QSharedPointer displayFilter)
{
m_d->displayColorConverter.setDisplayFilter(displayFilter);
KisImageSP image = this->image();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
image->barrierLock();
m_d->canvasWidget->setDisplayFilter(displayFilter);
image->unlock();
}
QSharedPointer KisCanvas2::displayFilter() const
{
return m_d->displayColorConverter.displayFilter();
}
void KisCanvas2::slotImageColorSpaceChanged()
{
KisImageSP image = this->image();
m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
image->barrierLock();
m_d->canvasWidget->notifyImageColorSpaceChanged(image->colorSpace());
image->unlock();
}
KisDisplayColorConverter* KisCanvas2::displayColorConverter() const
{
return &m_d->displayColorConverter;
}
KisExposureGammaCorrectionInterface* KisCanvas2::exposureGammaCorrectionInterface() const
{
QSharedPointer displayFilter = m_d->displayColorConverter.displayFilter();
return displayFilter ?
displayFilter->correctionInterface() :
KisDumbExposureGammaCorrectionInterface::instance();
}
void KisCanvas2::setProofingOptions(bool softProof, bool gamutCheck)
{
m_d->proofingConfig = this->image()->proofingConfiguration();
if (!m_d->proofingConfig) {
KisImageConfig cfg(false);
m_d->proofingConfig = cfg.defaultProofingconfiguration();
}
KoColorConversionTransformation::ConversionFlags conversionFlags = m_d->proofingConfig->conversionFlags;
#if QT_VERSION >= 0x050700
if (this->image()->colorSpace()->colorDepthId().id().contains("U")) {
conversionFlags.setFlag(KoColorConversionTransformation::SoftProofing, softProof);
if (softProof) {
conversionFlags.setFlag(KoColorConversionTransformation::GamutCheck, gamutCheck);
}
}
#else
if (this->image()->colorSpace()->colorDepthId().id().contains("U")) {
conversionFlags |= KoColorConversionTransformation::SoftProofing;
} else {
conversionFlags = conversionFlags & ~KoColorConversionTransformation::SoftProofing;
}
if (gamutCheck && softProof && this->image()->colorSpace()->colorDepthId().id().contains("U")) {
conversionFlags |= KoColorConversionTransformation::GamutCheck;
} else {
conversionFlags = conversionFlags & ~KoColorConversionTransformation::GamutCheck;
}
#endif
m_d->proofingConfig->conversionFlags = conversionFlags;
m_d->proofingConfigUpdated = true;
startUpdateInPatches(this->image()->bounds());
}
void KisCanvas2::slotSoftProofing(bool softProofing)
{
m_d->softProofing = softProofing;
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::slotGamutCheck(bool gamutCheck)
{
m_d->gamutCheck = gamutCheck;
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::slotChangeProofingConfig()
{
setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}
void KisCanvas2::setProofingConfigUpdated(bool updated)
{
m_d->proofingConfigUpdated = updated;
}
bool KisCanvas2::proofingConfigUpdated()
{
return m_d->proofingConfigUpdated;
}
KisProofingConfigurationSP KisCanvas2::proofingConfiguration() const
{
if (!m_d->proofingConfig) {
m_d->proofingConfig = this->image()->proofingConfiguration();
if (!m_d->proofingConfig) {
m_d->proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
}
}
return m_d->proofingConfig;
}
void KisCanvas2::startResizingImage()
{
KisImageWSP image = this->image();
qint32 w = image->width();
qint32 h = image->height();
emit sigContinueResizeImage(w, h);
QRect imageBounds(0, 0, w, h);
startUpdateInPatches(imageBounds);
}
void KisCanvas2::finishResizingImage(qint32 w, qint32 h)
{
m_d->canvasWidget->finishResizingImage(w, h);
}
void KisCanvas2::startUpdateCanvasProjection(const QRect & rc)
{
KisUpdateInfoSP info = m_d->canvasWidget->startUpdateCanvasProjection(rc, m_d->channelFlags);
if (m_d->projectionUpdatesCompressor.putUpdateInfo(info)) {
emit sigCanvasCacheUpdated();
}
}
void KisCanvas2::updateCanvasProjection()
{
auto tryIssueCanvasUpdates = [this](const QRect &vRect) {
if (!m_d->isBatchUpdateActive) {
// TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
if (m_d->currentCanvasIsOpenGL) {
m_d->savedUpdateRect = QRect();
// we already had a compression in frameRenderStartCompressor, so force the update directly
slotDoCanvasUpdate();
} else if (/* !m_d->currentCanvasIsOpenGL && */ !vRect.isEmpty()) {
m_d->savedUpdateRect = m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect();
// we already had a compression in frameRenderStartCompressor, so force the update directly
slotDoCanvasUpdate();
}
}
};
auto uploadData = [this, tryIssueCanvasUpdates](const QVector &infoObjects) {
QVector viewportRects = m_d->canvasWidget->updateCanvasProjection(infoObjects);
const QRect vRect = std::accumulate(viewportRects.constBegin(), viewportRects.constEnd(),
QRect(), std::bit_or());
tryIssueCanvasUpdates(vRect);
};
bool shouldExplicitlyIssueUpdates = false;
QVector infoObjects;
KisUpdateInfoList originalInfoObjects;
m_d->projectionUpdatesCompressor.takeUpdateInfo(originalInfoObjects);
for (auto it = originalInfoObjects.constBegin();
it != originalInfoObjects.constEnd();
++it) {
KisUpdateInfoSP info = *it;
const KisMarkerUpdateInfo *batchInfo = dynamic_cast(info.data());
if (batchInfo) {
if (!infoObjects.isEmpty()) {
uploadData(infoObjects);
infoObjects.clear();
}
if (batchInfo->type() == KisMarkerUpdateInfo::StartBatch) {
m_d->isBatchUpdateActive++;
} else if (batchInfo->type() == KisMarkerUpdateInfo::EndBatch) {
m_d->isBatchUpdateActive--;
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->isBatchUpdateActive >= 0);
if (m_d->isBatchUpdateActive == 0) {
shouldExplicitlyIssueUpdates = true;
}
} else if (batchInfo->type() == KisMarkerUpdateInfo::BlockLodUpdates) {
m_d->canvasWidget->setLodResetInProgress(true);
} else if (batchInfo->type() == KisMarkerUpdateInfo::UnblockLodUpdates) {
m_d->canvasWidget->setLodResetInProgress(false);
shouldExplicitlyIssueUpdates = true;
}
} else {
infoObjects << info;
}
}
if (!infoObjects.isEmpty()) {
uploadData(infoObjects);
} else if (shouldExplicitlyIssueUpdates) {
tryIssueCanvasUpdates(m_d->coordinatesConverter->imageRectInImagePixels());
}
}
void KisCanvas2::slotBeginUpdatesBatch()
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(KisMarkerUpdateInfo::StartBatch,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotEndUpdatesBatch()
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(KisMarkerUpdateInfo::EndBatch,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotSetLodUpdatesBlocked(bool value)
{
KisUpdateInfoSP info =
new KisMarkerUpdateInfo(value ?
KisMarkerUpdateInfo::BlockLodUpdates :
KisMarkerUpdateInfo::UnblockLodUpdates,
m_d->coordinatesConverter->imageRectInImagePixels());
m_d->projectionUpdatesCompressor.putUpdateInfo(info);
emit sigCanvasCacheUpdated();
}
void KisCanvas2::slotDoCanvasUpdate()
{
/**
* WARNING: in isBusy() we access openGL functions without making the painting
* context current. We hope that currently active context will be Qt's one,
* which is shared with our own.
*/
if (m_d->canvasWidget->isBusy()) {
// just restarting the timer
updateCanvasWidgetImpl(m_d->savedUpdateRect);
return;
}
if (m_d->savedUpdateRect.isEmpty()) {
m_d->canvasWidget->widget()->update();
emit updateCanvasRequested(m_d->canvasWidget->widget()->rect());
} else {
emit updateCanvasRequested(m_d->savedUpdateRect);
m_d->canvasWidget->widget()->update(m_d->savedUpdateRect);
}
m_d->savedUpdateRect = QRect();
}
void KisCanvas2::updateCanvasWidgetImpl(const QRect &rc)
{
if (!m_d->canvasUpdateCompressor.isActive() ||
!m_d->savedUpdateRect.isEmpty()) {
m_d->savedUpdateRect |= rc;
}
m_d->canvasUpdateCompressor.start();
}
void KisCanvas2::updateCanvas()
{
updateCanvasWidgetImpl();
}
void KisCanvas2::updateCanvas(const QRectF& documentRect)
{
if (m_d->currentCanvasIsOpenGL && m_d->canvasWidget->decorations().size() > 0) {
updateCanvasWidgetImpl();
}
else {
// updateCanvas is called from tools, never from the projection
// updates, so no need to prescale!
QRect widgetRect = m_d->coordinatesConverter->documentToWidget(documentRect).toAlignedRect();
widgetRect.adjust(-2, -2, 2, 2);
if (!widgetRect.isEmpty()) {
updateCanvasWidgetImpl(widgetRect);
}
}
}
void KisCanvas2::disconnectCanvasObserver(QObject *object)
{
KoCanvasBase::disconnectCanvasObserver(object);
m_d->view->disconnect(object);
}
void KisCanvas2::notifyZoomChanged()
{
if (!m_d->currentCanvasIsOpenGL) {
Q_ASSERT(m_d->prescaledProjection);
m_d->prescaledProjection->notifyZoomChanged();
}
notifyLevelOfDetailChange();
updateCanvas(); // update the canvas, because that isn't done when zooming using KoZoomAction
m_d->regionOfInterestUpdateCompressor.start();
}
QRect KisCanvas2::regionOfInterest() const
{
return m_d->regionOfInterest;
}
void KisCanvas2::slotUpdateRegionOfInterest()
{
const QRect oldRegionOfInterest = m_d->regionOfInterest;
const qreal ratio = 0.25;
const QRect proposedRoi = KisAlgebra2D::blowRect(m_d->coordinatesConverter->widgetRectInImagePixels(), ratio).toAlignedRect();
const QRect imageRect = m_d->coordinatesConverter->imageRectInImagePixels();
m_d->regionOfInterest = imageRect.contains(proposedRoi) ? proposedRoi : imageRect;
if (m_d->regionOfInterest != oldRegionOfInterest) {
emit sigRegionOfInterestChanged(m_d->regionOfInterest);
}
}
void KisCanvas2::slotReferenceImagesChanged()
{
canvasController()->resetScrollBars();
}
void KisCanvas2::setRenderingLimit(const QRect &rc)
{
m_d->renderingLimit = rc;
}
QRect KisCanvas2::renderingLimit() const
{
return m_d->renderingLimit;
}
void KisCanvas2::slotTrySwitchShapeManager()
{
KisNodeSP node = m_d->view->currentNode();
QPointer newManager;
newManager = fetchShapeManagerFromNode(node);
m_d->setActiveShapeManager(newManager);
}
void KisCanvas2::notifyLevelOfDetailChange()
{
if (!m_d->effectiveLodAllowedInImage()) return;
const qreal effectiveZoom = m_d->coordinatesConverter->effectiveZoom();
KisConfig cfg(true);
const int maxLod = cfg.numMipmapLevels();
const int lod = KisLodTransform::scaleToLod(effectiveZoom, maxLod);
if (m_d->effectiveLodAllowedInImage()) {
KisImageSP image = this->image();
image->setDesiredLevelOfDetail(lod);
}
}
const KoColorProfile * KisCanvas2::monitorProfile()
{
return m_d->displayColorConverter.monitorProfile();
}
KisViewManager* KisCanvas2::viewManager() const
{
if (m_d->view) {
return m_d->view->viewManager();
}
return 0;
}
QPointerKisCanvas2::imageView() const
{
return m_d->view;
}
KisImageWSP KisCanvas2::image() const
{
return m_d->view->image();
}
KisImageWSP KisCanvas2::currentImage() const
{
return m_d->view->image();
}
void KisCanvas2::documentOffsetMoved(const QPoint &documentOffset)
{
QPointF offsetBefore = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
qreal devicePixelRatio = m_d->coordinatesConverter->devicePixelRatio();
// The given offset is in widget logical pixels. In order to prevent fuzzy
// canvas rendering at 100% pixel-perfect zoom level when devicePixelRatio
// is not integral, we adjusts the offset to map to whole device pixels.
// We use qFloor here since the offset can be negative.
int deviceOffsetX = qFloor(documentOffset.x() * devicePixelRatio);
int deviceOffsetY = qFloor(documentOffset.y() * devicePixelRatio);
// These adjusted offsets will be in logical pixel but is aligned in device
// pixel space for pixel-perfect rendering.
qreal pixelPerfectOffsetX = deviceOffsetX / devicePixelRatio;
qreal pixelPerfectOffsetY = deviceOffsetY / devicePixelRatio;
// FIXME: This is a temporary hack for fixing the canvas under fractional
// DPI scaling before a new coordinate system is introduced.
QPointF offsetAdjusted(pixelPerfectOffsetX, pixelPerfectOffsetY);
m_d->coordinatesConverter->setDocumentOffset(offsetAdjusted);
QPointF offsetAfter = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
QPointF moveOffset = offsetAfter - offsetBefore;
if (!m_d->currentCanvasIsOpenGL)
m_d->prescaledProjection->viewportMoved(moveOffset);
emit documentOffsetUpdateFinished();
updateCanvas();
m_d->regionOfInterestUpdateCompressor.start();
}
void KisCanvas2::slotConfigChanged()
{
KisConfig cfg(true);
m_d->vastScrolling = cfg.vastScrolling();
resetCanvas(cfg.useOpenGL());
setDisplayProfile(cfg.displayProfile(QApplication::desktop()->screenNumber(this->canvasWidget())));
initializeFpsDecoration();
}
void KisCanvas2::refetchDataFromImage()
{
KisImageSP image = this->image();
KisImageBarrierLocker l(image);
startUpdateInPatches(image->bounds());
}
void KisCanvas2::setDisplayProfile(const KoColorProfile *monitorProfile)
{
if (m_d->displayColorConverter.monitorProfile() == monitorProfile) return;
m_d->displayColorConverter.setMonitorProfile(monitorProfile);
{
KisImageSP image = this->image();
KisImageBarrierLocker l(image);
m_d->canvasWidget->setDisplayColorConverter(&m_d->displayColorConverter);
}
refetchDataFromImage();
}
void KisCanvas2::addDecoration(KisCanvasDecorationSP deco)
{
m_d->canvasWidget->addDecoration(deco);
}
KisCanvasDecorationSP KisCanvas2::decoration(const QString& id) const
{
return m_d->canvasWidget->decoration(id);
}
QPoint KisCanvas2::documentOrigin() const
{
/**
* In Krita we don't use document origin anymore.
* All the centering when needed (vastScrolling < 0.5) is done
* automatically by the KisCoordinatesConverter.
*/
return QPoint();
}
QPoint KisCanvas2::documentOffset() const
{
return m_d->coordinatesConverter->documentOffset();
}
void KisCanvas2::setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager)
{
m_d->popupPalette = new KisPopupPalette(viewManager(), m_d->coordinatesConverter, favoriteResourceManager, displayColorConverter()->displayRendererInterface(),
m_d->view->resourceProvider(), m_d->canvasWidget->widget());
connect(m_d->popupPalette, SIGNAL(zoomLevelChanged(int)), this, SLOT(slotPopupPaletteRequestedZoomChange(int)));
connect(m_d->popupPalette, SIGNAL(sigUpdateCanvas()), this, SLOT(updateCanvas()));
connect(m_d->view->mainWindow(), SIGNAL(themeChanged()), m_d->popupPalette, SLOT(slotUpdateIcons()));
m_d->popupPalette->showPopupPalette(false);
}
void KisCanvas2::slotPopupPaletteRequestedZoomChange(int zoom ) {
m_d->view->viewManager()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, (qreal)(zoom/100.0)); // 1.0 is 100% zoom
notifyZoomChanged();
}
void KisCanvas2::setCursor(const QCursor &cursor)
{
canvasWidget()->setCursor(cursor);
}
KisAnimationFrameCacheSP KisCanvas2::frameCache() const
{
return m_d->frameCache;
}
KisAnimationPlayer *KisCanvas2::animationPlayer() const
{
return m_d->animationPlayer;
}
void KisCanvas2::slotSelectionChanged()
{
KisShapeLayer* shapeLayer = dynamic_cast(viewManager()->activeLayer().data());
if (!shapeLayer) {
return;
}
m_d->shapeManager.selection()->deselectAll();
Q_FOREACH (KoShape* shape, shapeLayer->shapeManager()->selection()->selectedShapes()) {
m_d->shapeManager.selection()->select(shape);
}
}
bool KisCanvas2::isPopupPaletteVisible() const
{
if (!m_d->popupPalette) {
return false;
}
return m_d->popupPalette->isVisible();
}
void KisCanvas2::setWrapAroundViewingMode(bool value)
{
KisCanvasDecorationSP infinityDecoration =
m_d->canvasWidget->decoration(INFINITY_DECORATION_ID);
if (infinityDecoration) {
infinityDecoration->setVisible(!value);
}
m_d->canvasWidget->setWrapAroundViewingMode(value);
}
bool KisCanvas2::wrapAroundViewingMode() const
{
KisCanvasDecorationSP infinityDecoration =
m_d->canvasWidget->decoration(INFINITY_DECORATION_ID);
if (infinityDecoration) {
return !(infinityDecoration->visible());
}
return false;
}
void KisCanvas2::bootstrapFinished()
{
if (!m_d->bootstrapLodBlocked) return;
m_d->bootstrapLodBlocked = false;
setLodAllowedInCanvas(m_d->lodAllowedInImage);
}
void KisCanvas2::setLodAllowedInCanvas(bool value)
{
if (!KisOpenGL::supportsLoD()) {
qWarning() << "WARNING: Level of Detail functionality is available only with openGL + GLSL 1.3 support";
}
m_d->lodAllowedInImage =
value &&
m_d->currentCanvasIsOpenGL &&
KisOpenGL::supportsLoD() &&
(m_d->openGLFilterMode == KisOpenGL::TrilinearFilterMode ||
m_d->openGLFilterMode == KisOpenGL::HighQualityFiltering);
KisImageSP image = this->image();
if (m_d->effectiveLodAllowedInImage() != !image->levelOfDetailBlocked()) {
image->setLevelOfDetailBlocked(!m_d->effectiveLodAllowedInImage());
}
notifyLevelOfDetailChange();
KisConfig cfg(false);
cfg.setLevelOfDetailEnabled(m_d->lodAllowedInImage);
}
bool KisCanvas2::lodAllowedInCanvas() const
{
return m_d->lodAllowedInImage;
}
void KisCanvas2::slotShowPopupPalette(const QPoint &p)
{
if (!m_d->popupPalette) {
return;
}
m_d->popupPalette->showPopupPalette(p);
}
KisPaintingAssistantsDecorationSP KisCanvas2::paintingAssistantsDecoration() const
{
KisCanvasDecorationSP deco = decoration("paintingAssistantsDecoration");
return qobject_cast(deco.data());
}
KisReferenceImagesDecorationSP KisCanvas2::referenceImagesDecoration() const
{
KisCanvasDecorationSP deco = decoration("referenceImagesDecoration");
return qobject_cast(deco.data());
}
diff --git a/libs/ui/canvas/kis_canvas2.h b/libs/ui/canvas/kis_canvas2.h
index c2fa2b4b0e..2fd0884555 100644
--- a/libs/ui/canvas/kis_canvas2.h
+++ b/libs/ui/canvas/kis_canvas2.h
@@ -1,352 +1,354 @@
/* This file is part of the KDE project
* Copyright (C) 2006, 2010 Boudewijn Rempt
* Copyright (C) 2011 Silvio Heinrich
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_CANVAS_H
#define KIS_CANVAS_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "opengl/kis_opengl.h"
#include "kis_ui_types.h"
#include "kis_coordinates_converter.h"
#include "kis_canvas_decoration.h"
#include "kis_painting_assistants_decoration.h"
#include "input/KisInputActionGroup.h"
#include "KisReferenceImagesDecoration.h"
class KoToolProxy;
class KoColorProfile;
class KisViewManager;
class KisFavoriteResourceManager;
class KisDisplayFilter;
class KisDisplayColorConverter;
struct KisExposureGammaCorrectionInterface;
class KisView;
class KisInputManager;
class KisAnimationPlayer;
class KisShapeController;
class KisCoordinatesConverter;
class KoViewConverter;
class KisAbstractCanvasWidget;
/**
* KisCanvas2 is not an actual widget class, but rather an adapter for
* the widget it contains, which may be either a QPainter based
* canvas, or an OpenGL based canvas: that are the real widgets.
*/
class KRITAUI_EXPORT KisCanvas2 : public KoCanvasBase, public KisInputActionGroupsMaskInterface
{
Q_OBJECT
public:
/**
* Create a new canvas. The canvas manages a widget that will do
* the actual painting: the canvas itself is not a widget.
*
* @param viewConverter the viewconverter for converting between
* window and document coordinates.
*/
KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceProvider *resourceManager, KisView *view, KoShapeControllerBase *sc);
~KisCanvas2() override;
void notifyZoomChanged();
void disconnectCanvasObserver(QObject *object) override;
public: // KoCanvasBase implementation
bool canvasIsOpenGL() const override;
KisOpenGL::FilterMode openGLFilterMode() const;
void gridSize(QPointF *offset, QSizeF *spacing) const override;
bool snapToGrid() const override;
+ QPointF mapImageToDocument(const QPointF &point) override;
+
// This method only exists to support flake-related operations
void addCommand(KUndo2Command *command) override;
QPoint documentOrigin() const override;
QPoint documentOffset() const;
/**
* Return the right shape manager for the current layer. That is
* to say, if the current layer is a vector layer, return the shape
* layer's canvas' shapemanager, else the shapemanager associated
* with the global krita canvas.
*/
KoShapeManager * shapeManager() const override;
/**
* Since shapeManager() may change, we need a persistent object where we can
* connect to and thack the selection. See more comments in KoCanvasBase.
*/
KoSelectedShapesProxy *selectedShapesProxy() const override;
/**
* Return the shape manager associated with this canvas
*/
KoShapeManager *globalShapeManager() const;
/**
* Return shape manager associated with the currently active node.
* If current node has no internal shape manager, return null.
*/
KoShapeManager *localShapeManager() const;
void updateCanvas(const QRectF& rc) override;
void updateInputMethodInfo() override;
const KisCoordinatesConverter* coordinatesConverter() const;
KoViewConverter *viewConverter() const override;
QWidget* canvasWidget() override;
const QWidget* canvasWidget() const override;
KoUnit unit() const override;
KoToolProxy* toolProxy() const override;
const KoColorProfile* monitorProfile();
// FIXME:
// Temporary! Either get the current layer and image from the
// resource provider, or use this, which gets them from the
// current shape selection.
KisImageWSP currentImage() const;
/**
* Filters events and sends them to canvas actions. Shared
* among all the views/canvases
*
* NOTE: May be null while initialization!
*/
KisInputManager* globalInputManager() const;
/**
* Return the mask of currently available input action groups
* Note: Override from KisInputActionGroupsMaskInterface
*/
KisInputActionGroupsMask inputActionGroupsMask() const override;
/**
* Set the mask of currently available action groups
* Note: Override from KisInputActionGroupsMaskInterface
*/
void setInputActionGroupsMask(KisInputActionGroupsMask mask) override;
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration() const;
KisReferenceImagesDecorationSP referenceImagesDecoration() const;
public: // KisCanvas2 methods
KisImageWSP image() const;
KisViewManager* viewManager() const;
QPointer imageView() const;
/// @return true if the canvas image should be displayed in vertically mirrored mode
void addDecoration(KisCanvasDecorationSP deco);
KisCanvasDecorationSP decoration(const QString& id) const;
void setDisplayFilter(QSharedPointer displayFilter);
QSharedPointer displayFilter() const;
KisDisplayColorConverter *displayColorConverter() const;
KisExposureGammaCorrectionInterface* exposureGammaCorrectionInterface() const;
/**
* @brief setProofingOptions
* set the options for softproofing, without affecting the proofing options as stored inside the image.
*/
void setProofingOptions(bool softProof, bool gamutCheck);
KisProofingConfigurationSP proofingConfiguration() const;
/**
* @brief setProofingConfigUpdated This function is to set whether the proofing config is updated,
* this is needed for determining whether or not to generate a new proofing transform.
* @param updated whether it's updated. Just set it to false in normal usage.
*/
void setProofingConfigUpdated(bool updated);
/**
* @brief proofingConfigUpdated ask the canvas whether or not it updated the proofing config.
* @return whether or not the proofing config is updated, if so, a new proofing transform needs to be made
* in KisOpenGL canvas.
*/
bool proofingConfigUpdated();
void setCursor(const QCursor &cursor) override;
KisAnimationFrameCacheSP frameCache() const;
KisAnimationPlayer *animationPlayer() const;
void refetchDataFromImage();
/**
* @return area of the image (in image coordinates) that is visible on the canvas
* with a small margin selected by the user
*/
QRect regionOfInterest() const;
/**
* Set artificial limit outside which the image will not be rendered
* \p rc is measured in image pixels
*/
void setRenderingLimit(const QRect &rc);
/**
* @return aftificial limit outside which the image will not be rendered
*/
QRect renderingLimit() const;
Q_SIGNALS:
void sigCanvasEngineChanged();
void sigCanvasCacheUpdated();
void sigContinueResizeImage(qint32 w, qint32 h);
void documentOffsetUpdateFinished();
// emitted whenever the canvas widget thinks sketch should update
void updateCanvasRequested(const QRect &rc);
void sigRegionOfInterestChanged(const QRect &roi);
public Q_SLOTS:
/// Update the entire canvas area
void updateCanvas();
void startResizingImage();
void finishResizingImage(qint32 w, qint32 h);
/// canvas rotation in degrees
qreal rotationAngle() const;
/// Bools indicating canvasmirroring.
bool xAxisMirrored() const;
bool yAxisMirrored() const;
void slotSoftProofing(bool softProofing);
void slotGamutCheck(bool gamutCheck);
void slotChangeProofingConfig();
void slotPopupPaletteRequestedZoomChange(int zoom);
void channelSelectionChanged();
void startUpdateInPatches(const QRect &imageRect);
void slotTrySwitchShapeManager();
/**
* Called whenever the configuration settings change.
*/
void slotConfigChanged();
private Q_SLOTS:
/// The image projection has changed, now start an update
/// of the canvas representation.
void startUpdateCanvasProjection(const QRect & rc);
void updateCanvasProjection();
void slotBeginUpdatesBatch();
void slotEndUpdatesBatch();
void slotSetLodUpdatesBlocked(bool value);
/**
* Called whenever the view widget needs to show a different part of
* the document
*
* @param documentOffset the offset in widget pixels
*/
void documentOffsetMoved(const QPoint &documentOffset);
void slotSelectionChanged();
void slotDoCanvasUpdate();
void bootstrapFinished();
void slotUpdateRegionOfInterest();
void slotReferenceImagesChanged();
void slotImageColorSpaceChanged();
public:
bool isPopupPaletteVisible() const;
void slotShowPopupPalette(const QPoint& = QPoint(0,0));
// interface for KisCanvasController only
void setWrapAroundViewingMode(bool value);
bool wrapAroundViewingMode() const;
void setLodAllowedInCanvas(bool value);
bool lodAllowedInCanvas() const;
void initializeImage();
void setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager);
private:
Q_DISABLE_COPY(KisCanvas2)
void connectCurrentCanvas();
void createCanvas(bool useOpenGL);
void createQPainterCanvas();
void createOpenGLCanvas();
void updateCanvasWidgetImpl(const QRect &rc = QRect());
void setCanvasWidget(KisAbstractCanvasWidget *widget);
void resetCanvas(bool useOpenGL);
void setDisplayProfile(const KoColorProfile *profile);
void notifyLevelOfDetailChange();
// Completes construction of canvas.
// To be called by KisView in its constructor, once it has been setup enough
// (to be defined what that means) for things KisCanvas2 expects from KisView
// TODO: see to avoid that
void setup();
void initializeFpsDecoration();
private:
friend class KisView; // calls setup()
class KisCanvas2Private;
KisCanvas2Private * const m_d;
};
#endif
diff --git a/libs/ui/canvas/kis_guides_manager.cpp b/libs/ui/canvas/kis_guides_manager.cpp
index fa05b65afd..b6e1246435 100644
--- a/libs/ui/canvas/kis_guides_manager.cpp
+++ b/libs/ui/canvas/kis_guides_manager.cpp
@@ -1,802 +1,814 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_guides_manager.h"
#include
#include
#include "kis_guides_decoration.h"
#include
#include "kis_guides_config.h"
#include "kis_action_manager.h"
#include "kis_action.h"
#include "kis_signals_blocker.h"
#include "input/kis_input_manager.h"
#include "kis_coordinates_converter.h"
#include "kis_zoom_manager.h"
#include "kis_signal_auto_connection.h"
#include "KisViewManager.h"
#include "KisDocument.h"
#include "kis_algebra_2d.h"
#include
#include "kis_snap_line_strategy.h"
#include "kis_change_guides_command.h"
#include "kis_snap_config.h"
#include "kis_canvas2.h"
#include "kis_signal_compressor.h"
struct KisGuidesManager::Private
{
Private(KisGuidesManager *_q)
: q(_q),
decoration(0),
invalidGuide(Qt::Horizontal, -1),
currentGuide(invalidGuide),
cursorSwitched(false),
dragStartGuidePos(0),
updateDocumentCompressor(40, KisSignalCompressor::FIRST_ACTIVE),
shouldSetModified(false) {}
KisGuidesManager *q;
KisGuidesDecoration *decoration;
KisGuidesConfig guidesConfig;
KisSnapConfig snapConfig;
QPointer view;
typedef QPair GuideHandle;
GuideHandle findGuide(const QPointF &docPos);
bool isGuideValid(const GuideHandle &h);
qreal guideValue(const GuideHandle &h);
void setGuideValue(const GuideHandle &h, qreal value);
void deleteGuide(const GuideHandle &h);
const GuideHandle invalidGuide;
bool updateCursor(const QPointF &docPos, bool forceDisableCursor = false);
void initDragStart(const GuideHandle &guide,
const QPointF &dragStart,
qreal guideValue,
bool snapToStart);
bool mouseMoveHandler(const QPointF &docPos, Qt::KeyboardModifiers modifiers);
bool mouseReleaseHandler(const QPointF &docPos);
void updateSnappingStatus(const KisGuidesConfig &value);
QPointF alignToPixels(const QPointF docPoint);
QPointF getDocPointFromEvent(QEvent *event);
Qt::MouseButton getButtonFromEvent(QEvent *event);
QAction* createShortenedAction(const QString &text, const QString &parentId, QObject *parent);
void syncAction(const QString &actionName, bool value);
GuideHandle currentGuide;
bool cursorSwitched;
QCursor oldCursor;
QPointF dragStartDoc;
QPointF dragPointerOffset;
qreal dragStartGuidePos;
KisSignalAutoConnectionsStore viewConnections;
KisSignalCompressor updateDocumentCompressor;
bool shouldSetModified;
};
KisGuidesManager::KisGuidesManager(QObject *parent)
: QObject(parent),
m_d(new Private(this))
{
connect(&m_d->updateDocumentCompressor, SIGNAL(timeout()), SLOT(slotUploadConfigToDocument()));
}
KisGuidesManager::~KisGuidesManager()
{
}
void KisGuidesManager::setGuidesConfig(const KisGuidesConfig &config)
{
if (config == m_d->guidesConfig) return;
setGuidesConfigImpl(config, true);
}
void KisGuidesManager::slotDocumentRequestedConfig(const KisGuidesConfig &config)
{
if (config == m_d->guidesConfig) return;
setGuidesConfigImpl(config, false);
}
void KisGuidesManager::slotUploadConfigToDocument()
{
const KisGuidesConfig &value = m_d->guidesConfig;
KisDocument *doc = m_d->view ? m_d->view->document() : 0;
if (doc) {
KisSignalsBlocker b(doc);
if (m_d->shouldSetModified) {
KUndo2Command *cmd = new KisChangeGuidesCommand(doc, value);
doc->addCommand(cmd);
} else {
doc->setGuidesConfig(value);
}
value.saveStaticData();
}
m_d->shouldSetModified = false;
}
void KisGuidesManager::setGuidesConfigImpl(const KisGuidesConfig &value, bool emitModified)
{
m_d->guidesConfig = value;
if (m_d->decoration && value != m_d->decoration->guidesConfig()) {
m_d->decoration->setVisible(value.showGuides());
m_d->decoration->setGuidesConfig(value);
}
m_d->shouldSetModified |= emitModified;
m_d->updateDocumentCompressor.start();
const bool shouldFilterEvent =
value.showGuides() && !value.lockGuides() && value.hasGuides();
attachEventFilterImpl(shouldFilterEvent);
syncActionsStatus();
if (!m_d->isGuideValid(m_d->currentGuide)) {
m_d->updateSnappingStatus(value);
}
if (m_d->view) {
m_d->view->document()->setUnit(KoUnit(m_d->guidesConfig.unitType()));
m_d->view->viewManager()->actionManager()->actionByName("ruler_pixel_multiple2")->setChecked(value.rulersMultiple2());
}
emit sigRequestUpdateGuidesConfig(m_d->guidesConfig);
}
void KisGuidesManager::attachEventFilterImpl(bool value)
{
if (!m_d->view) return;
KisInputManager *inputManager = m_d->view->globalInputManager();
if (inputManager) {
if (value) {
inputManager->attachPriorityEventFilter(this, 100);
} else {
inputManager->detachPriorityEventFilter(this);
}
}
}
void KisGuidesManager::Private::syncAction(const QString &actionName, bool value)
{
KisActionManager *actionManager = view->viewManager()->actionManager();
KisAction *action = actionManager->actionByName(actionName);
KIS_ASSERT_RECOVER_RETURN(action);
KisSignalsBlocker b(action);
action->setChecked(value);
}
void KisGuidesManager::syncActionsStatus()
{
if (!m_d->view) return;
m_d->syncAction("view_show_guides", m_d->guidesConfig.showGuides());
m_d->syncAction("view_lock_guides", m_d->guidesConfig.lockGuides());
m_d->syncAction("view_snap_to_guides", m_d->guidesConfig.snapToGuides());
m_d->syncAction("view_snap_orthogonal", m_d->snapConfig.orthogonal());
m_d->syncAction("view_snap_node", m_d->snapConfig.node());
m_d->syncAction("view_snap_extension", m_d->snapConfig.extension());
m_d->syncAction("view_snap_intersection", m_d->snapConfig.intersection());
m_d->syncAction("view_snap_bounding_box", m_d->snapConfig.boundingBox());
m_d->syncAction("view_snap_image_bounds", m_d->snapConfig.imageBounds());
m_d->syncAction("view_snap_image_center", m_d->snapConfig.imageCenter());
+ m_d->syncAction("view_snap_to_pixel",m_d->snapConfig.toPixel());
}
void KisGuidesManager::Private::updateSnappingStatus(const KisGuidesConfig &value)
{
if (!view) return;
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
KisSnapLineStrategy *guidesSnap = 0;
if (value.snapToGuides()) {
guidesSnap = new KisSnapLineStrategy(KoSnapGuide::GuideLineSnapping);
guidesSnap->setHorizontalLines(value.horizontalGuideLines());
guidesSnap->setVerticalLines(value.verticalGuideLines());
}
snapGuide->overrideSnapStrategy(KoSnapGuide::GuideLineSnapping, guidesSnap);
snapGuide->enableSnapStrategy(KoSnapGuide::GuideLineSnapping, guidesSnap);
snapGuide->enableSnapStrategy(KoSnapGuide::OrthogonalSnapping, snapConfig.orthogonal());
snapGuide->enableSnapStrategy(KoSnapGuide::NodeSnapping, snapConfig.node());
snapGuide->enableSnapStrategy(KoSnapGuide::ExtensionSnapping, snapConfig.extension());
snapGuide->enableSnapStrategy(KoSnapGuide::IntersectionSnapping, snapConfig.intersection());
snapGuide->enableSnapStrategy(KoSnapGuide::BoundingBoxSnapping, snapConfig.boundingBox());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentBoundsSnapping, snapConfig.imageBounds());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentCenterSnapping, snapConfig.imageCenter());
+ snapGuide->enableSnapStrategy(KoSnapGuide::PixelSnapping, snapConfig.toPixel());
snapConfig.saveStaticData();
}
bool KisGuidesManager::showGuides() const
{
return m_d->guidesConfig.showGuides();
}
void KisGuidesManager::setShowGuides(bool value)
{
m_d->guidesConfig.setShowGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::lockGuides() const
{
return m_d->guidesConfig.lockGuides();
}
void KisGuidesManager::setLockGuides(bool value)
{
m_d->guidesConfig.setLockGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::snapToGuides() const
{
return m_d->guidesConfig.snapToGuides();
}
void KisGuidesManager::setSnapToGuides(bool value)
{
m_d->guidesConfig.setSnapToGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::rulersMultiple2() const
{
return m_d->guidesConfig.rulersMultiple2();
}
void KisGuidesManager::setRulersMultiple2(bool value)
{
m_d->guidesConfig.setRulersMultiple2(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
KoUnit::Type KisGuidesManager::unitType() const
{
return m_d->guidesConfig.unitType();
}
void KisGuidesManager::setUnitType(const KoUnit::Type type)
{
m_d->guidesConfig.setUnitType(type);
setGuidesConfigImpl(m_d->guidesConfig, false);
}
void KisGuidesManager::setup(KisActionManager *actionManager)
{
KisAction *action = 0;
action = actionManager->createAction("view_show_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setShowGuides(bool)));
action = actionManager->createAction("view_lock_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setLockGuides(bool)));
action = actionManager->createAction("view_snap_to_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapToGuides(bool)));
action = actionManager->createAction("show_snap_options_popup");
connect(action, SIGNAL(triggered()), this, SLOT(slotShowSnapOptions()));
action = actionManager->createAction("view_snap_orthogonal");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapOrthogonal(bool)));
action = actionManager->createAction("view_snap_node");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapNode(bool)));
action = actionManager->createAction("view_snap_extension");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapExtension(bool)));
action = actionManager->createAction("view_snap_intersection");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapIntersection(bool)));
action = actionManager->createAction("view_snap_bounding_box");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapBoundingBox(bool)));
action = actionManager->createAction("view_snap_image_bounds");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapImageBounds(bool)));
action = actionManager->createAction("view_snap_image_center");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapImageCenter(bool)));
+ action = actionManager->createAction("view_snap_to_pixel");
+ connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapToPixel(bool)));
+
m_d->updateSnappingStatus(m_d->guidesConfig);
syncActionsStatus();
}
void KisGuidesManager::setView(QPointer view)
{
if (m_d->view) {
KoSnapGuide *snapGuide = m_d->view->canvasBase()->snapGuide();
snapGuide->overrideSnapStrategy(KoSnapGuide::GuideLineSnapping, 0);
snapGuide->enableSnapStrategy(KoSnapGuide::GuideLineSnapping, false);
if (m_d->updateDocumentCompressor.isActive()) {
m_d->updateDocumentCompressor.stop();
slotUploadConfigToDocument();
}
m_d->decoration = 0;
m_d->viewConnections.clear();
attachEventFilterImpl(false);
}
m_d->view = view;
if (m_d->view) {
KisGuidesDecoration* decoration = qobject_cast(m_d->view->canvasBase()->decoration(GUIDES_DECORATION_ID).data());
if (!decoration) {
decoration = new KisGuidesDecoration(m_d->view);
m_d->view->canvasBase()->addDecoration(decoration);
}
m_d->decoration = decoration;
m_d->guidesConfig = m_d->view->document()->guidesConfig();
setGuidesConfigImpl(m_d->guidesConfig, false);
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationInProgress(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationFinished(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationInProgress(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationFinished(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->document(), SIGNAL(sigGuidesConfigChanged(KisGuidesConfig)),
this, SLOT(slotDocumentRequestedConfig(KisGuidesConfig)));
}
}
KisGuidesManager::Private::GuideHandle
KisGuidesManager::Private::findGuide(const QPointF &docPos)
{
const int snapRadius = 16;
GuideHandle nearestGuide = invalidGuide;
qreal nearestRadius = std::numeric_limits::max();
for (int i = 0; i < guidesConfig.horizontalGuideLines().size(); i++) {
const qreal guide = guidesConfig.horizontalGuideLines()[i];
const qreal radius = qAbs(docPos.y() - guide);
if (radius < snapRadius && radius < nearestRadius) {
nearestGuide = GuideHandle(Qt::Horizontal, i);
nearestRadius = radius;
}
}
for (int i = 0; i < guidesConfig.verticalGuideLines().size(); i++) {
const qreal guide = guidesConfig.verticalGuideLines()[i];
const qreal radius = qAbs(docPos.x() - guide);
if (radius < snapRadius && radius < nearestRadius) {
nearestGuide = GuideHandle(Qt::Vertical, i);
nearestRadius = radius;
}
}
return nearestGuide;
}
bool KisGuidesManager::Private::isGuideValid(const GuideHandle &h)
{
return h.second >= 0;
}
qreal KisGuidesManager::Private::guideValue(const GuideHandle &h)
{
return h.first == Qt::Horizontal ?
guidesConfig.horizontalGuideLines()[h.second] :
guidesConfig.verticalGuideLines()[h.second];
}
void KisGuidesManager::Private::setGuideValue(const GuideHandle &h, qreal value)
{
if (h.first == Qt::Horizontal) {
QList guides = guidesConfig.horizontalGuideLines();
guides[h.second] = value;
guidesConfig.setHorizontalGuideLines(guides);
} else {
QList guides = guidesConfig.verticalGuideLines();
guides[h.second] = value;
guidesConfig.setVerticalGuideLines(guides);
}
}
void KisGuidesManager::Private::deleteGuide(const GuideHandle &h)
{
if (h.first == Qt::Horizontal) {
QList guides = guidesConfig.horizontalGuideLines();
guides.removeAt(h.second);
guidesConfig.setHorizontalGuideLines(guides);
} else {
QList guides = guidesConfig.verticalGuideLines();
guides.removeAt(h.second);
guidesConfig.setVerticalGuideLines(guides);
}
}
bool KisGuidesManager::Private::updateCursor(const QPointF &docPos, bool forceDisableCursor)
{
KisCanvas2 *canvas = view->canvasBase();
const GuideHandle guide = findGuide(docPos);
const bool guideValid = isGuideValid(guide) && !forceDisableCursor;
if (guideValid && !cursorSwitched) {
oldCursor = canvas->canvasWidget()->cursor();
}
if (guideValid) {
cursorSwitched = true;
QCursor newCursor = guide.first == Qt::Horizontal ?
Qt::SizeVerCursor : Qt::SizeHorCursor;
canvas->canvasWidget()->setCursor(newCursor);
}
if (!guideValid && cursorSwitched) {
canvas->canvasWidget()->setCursor(oldCursor);
cursorSwitched = false;
}
return guideValid;
}
void KisGuidesManager::Private::initDragStart(const GuideHandle &guide,
const QPointF &dragStart,
qreal guideValue,
bool snapToStart)
{
currentGuide = guide;
dragStartDoc = dragStart;
dragStartGuidePos = guideValue;
dragPointerOffset =
guide.first == Qt::Horizontal ?
QPointF(0, dragStartGuidePos - dragStartDoc.y()) :
QPointF(dragStartGuidePos - dragStartDoc.x(), 0);
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
snapGuide->reset();
if (snapToStart) {
KisSnapLineStrategy *strategy = new KisSnapLineStrategy();
strategy->addLine(guide.first, guideValue);
snapGuide->addCustomSnapStrategy(strategy);
}
}
QPointF KisGuidesManager::Private::alignToPixels(const QPointF docPoint)
{
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
QPoint imagePoint = converter->documentToImage(docPoint).toPoint();
return converter->imageToDocument(imagePoint);
}
bool KisGuidesManager::Private::mouseMoveHandler(const QPointF &docPos, Qt::KeyboardModifiers modifiers)
{
if (isGuideValid(currentGuide)) {
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
const QPointF snappedPos = snapGuide->snap(docPos, dragPointerOffset, modifiers);
const QPointF offset = snappedPos - dragStartDoc;
const qreal newValue = dragStartGuidePos +
(currentGuide.first == Qt::Horizontal ?
offset.y() : offset.x());
setGuideValue(currentGuide, newValue);
q->setGuidesConfigImpl(guidesConfig);
}
return updateCursor(docPos);
}
bool KisGuidesManager::Private::mouseReleaseHandler(const QPointF &docPos)
{
bool result = false;
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
if (isGuideValid(currentGuide)) {
const QRectF docRect = converter->imageRectInDocumentPixels();
// TODO: enable work rect after we fix painting guides
// outside canvas in openGL mode
const QRectF workRect = KisAlgebra2D::blowRect(docRect, 0 /*0.2*/);
if (!workRect.contains(docPos)) {
deleteGuide(currentGuide);
q->setGuidesConfigImpl(guidesConfig);
/**
* When we delete a guide, it might happen that we are
* deleting the last guide. Therefore we should eat the
* corresponding event so that the event filter would stop
* the filter processing.
*/
result = true;
}
currentGuide = invalidGuide;
dragStartDoc = QPointF();
dragPointerOffset = QPointF();
dragStartGuidePos = 0;
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
snapGuide->reset();
updateSnappingStatus(guidesConfig);
}
return updateCursor(docPos) | result;
}
QPointF KisGuidesManager::Private::getDocPointFromEvent(QEvent *event)
{
QPointF result;
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
if (event->type() == QEvent::Enter) {
QEnterEvent *enterEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(enterEvent->pos()));
} else if (event->type() == QEvent::MouseMove ||
event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(mouseEvent->pos()));
} else if (event->type() == QEvent::TabletMove ||
event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
QTabletEvent *tabletEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(tabletEvent->pos()));
} else {
// we shouldn't silently return QPointF(0,0), higher level code may
// snap to some unexpected guide
KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "event type is not supported!");
}
return result;
}
Qt::MouseButton KisGuidesManager::Private::getButtonFromEvent(QEvent *event)
{
Qt::MouseButton button = Qt::NoButton;
if (event->type() == QEvent::MouseMove ||
event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast(event);
button = mouseEvent->button();
} else if (event->type() == QEvent::TabletMove ||
event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
QTabletEvent *tabletEvent = static_cast(event);
button = tabletEvent->button();
}
return button;
}
bool KisGuidesManager::eventFilter(QObject *obj, QEvent *event)
{
if (!m_d->view || obj != m_d->view->canvasBase()->canvasWidget()) return false;
bool retval = false;
switch (event->type()) {
case QEvent::Leave:
m_d->updateCursor(QPointF(), true);
break;
case QEvent::Enter:
case QEvent::TabletMove:
case QEvent::MouseMove: {
const QPointF docPos = m_d->getDocPointFromEvent(event);
const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
// we should never eat Enter events, input manager may get crazy about it
retval = m_d->mouseMoveHandler(docPos, modifiers) && event->type() != QEvent::Enter;
break;
}
case QEvent::TabletPress:
case QEvent::MouseButtonPress: {
if (m_d->getButtonFromEvent(event) != Qt::LeftButton) break;
const QPointF docPos = m_d->getDocPointFromEvent(event);
const Private::GuideHandle guide = m_d->findGuide(docPos);
const bool guideValid = m_d->isGuideValid(guide);
if (guideValid) {
m_d->initDragStart(guide, docPos, m_d->guideValue(guide), true);
}
retval = m_d->updateCursor(docPos);
break;
}
case QEvent::TabletRelease:
case QEvent::MouseButtonRelease: {
if (m_d->getButtonFromEvent(event) != Qt::LeftButton) break;
const QPointF docPos = m_d->getDocPointFromEvent(event);
retval = m_d->mouseReleaseHandler(docPos);
break;
}
default:
break;
}
return !retval ? QObject::eventFilter(obj, event) : true;
}
void KisGuidesManager::slotGuideCreationInProgress(Qt::Orientation orientation, const QPoint &globalPos)
{
if (m_d->guidesConfig.lockGuides()) return;
KisCanvas2 *canvas = m_d->view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
const QPointF widgetPos = canvas->canvasWidget()->mapFromGlobal(globalPos);
const QPointF docPos = m_d->alignToPixels(converter->widgetToDocument(widgetPos));
if (m_d->isGuideValid(m_d->currentGuide)) {
const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
m_d->mouseMoveHandler(docPos, modifiers);
} else {
m_d->guidesConfig.setShowGuides(true);
if (orientation == Qt::Horizontal) {
QList guides = m_d->guidesConfig.horizontalGuideLines();
guides.append(docPos.y());
m_d->currentGuide.first = orientation;
m_d->currentGuide.second = guides.size() - 1;
m_d->guidesConfig.setHorizontalGuideLines(guides);
m_d->initDragStart(m_d->currentGuide, docPos, docPos.y(), false);
} else {
QList guides = m_d->guidesConfig.verticalGuideLines();
guides.append(docPos.x());
m_d->currentGuide.first = orientation;
m_d->currentGuide.second = guides.size() - 1;
m_d->guidesConfig.setVerticalGuideLines(guides);
m_d->initDragStart(m_d->currentGuide, docPos, docPos.x(), false);
}
setGuidesConfigImpl(m_d->guidesConfig);
}
}
void KisGuidesManager::slotGuideCreationFinished(Qt::Orientation orientation, const QPoint &globalPos)
{
Q_UNUSED(orientation);
if (m_d->guidesConfig.lockGuides()) return;
KisCanvas2 *canvas = m_d->view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
const QPointF widgetPos = canvas->canvasWidget()->mapFromGlobal(globalPos);
const QPointF docPos = m_d->alignToPixels(converter->widgetToDocument(widgetPos));
m_d->mouseReleaseHandler(docPos);
}
QAction* KisGuidesManager::Private::createShortenedAction(const QString &text, const QString &parentId, QObject *parent)
{
KisActionManager *actionManager = view->viewManager()->actionManager();
QAction *action = 0;
KisAction *parentAction = 0;
action = new QAction(text, parent);
action->setCheckable(true);
parentAction = actionManager->actionByName(parentId);
action->setChecked(parentAction->isChecked());
connect(action, SIGNAL(toggled(bool)), parentAction, SLOT(setChecked(bool)));
return action;
}
void KisGuidesManager::slotShowSnapOptions()
{
const QPoint pos = QCursor::pos();
QMenu menu;
menu.addSection(i18n("Snap to:"));
menu.addAction(m_d->createShortenedAction(i18n("Grid"), "view_snap_to_grid", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Guides"), "view_snap_to_guides", &menu));
+ menu.addAction(m_d->createShortenedAction(i18n("Pixel"), "view_snap_to_pixel", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Orthogonal"), "view_snap_orthogonal", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Node"), "view_snap_node", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Extension"), "view_snap_extension", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Intersection"), "view_snap_intersection", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Bounding Box"), "view_snap_bounding_box", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Image Bounds"), "view_snap_image_bounds", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Image Center"), "view_snap_image_center", &menu));
menu.exec(pos);
}
void KisGuidesManager::setSnapOrthogonal(bool value)
{
m_d->snapConfig.setOrthogonal(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapNode(bool value)
{
m_d->snapConfig.setNode(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapExtension(bool value)
{
m_d->snapConfig.setExtension(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapIntersection(bool value)
{
m_d->snapConfig.setIntersection(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapBoundingBox(bool value)
{
m_d->snapConfig.setBoundingBox(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapImageBounds(bool value)
{
m_d->snapConfig.setImageBounds(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapImageCenter(bool value)
{
m_d->snapConfig.setImageCenter(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
+
+void KisGuidesManager::setSnapToPixel(bool value)
+{
+ m_d->snapConfig.setToPixel(value);
+ m_d->updateSnappingStatus(m_d->guidesConfig);
+}
diff --git a/libs/ui/canvas/kis_guides_manager.h b/libs/ui/canvas/kis_guides_manager.h
index 9c7aadea61..5d6fa2aba2 100644
--- a/libs/ui/canvas/kis_guides_manager.h
+++ b/libs/ui/canvas/kis_guides_manager.h
@@ -1,90 +1,91 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_GUIDES_MANAGER_H
#define __KIS_GUIDES_MANAGER_H
#include
#include
#include "kritaui_export.h"
#include
class KisView;
class KisActionManager;
class KisCanvasDecoration;
class KisGuidesConfig;
class KRITAUI_EXPORT KisGuidesManager : public QObject
{
Q_OBJECT
public:
KisGuidesManager(QObject *parent = 0);
~KisGuidesManager() override;
void setup(KisActionManager *actionManager);
void setView(QPointer view);
bool showGuides() const;
bool lockGuides() const;
bool snapToGuides() const;
bool rulersMultiple2() const;
KoUnit::Type unitType() const;
bool eventFilter(QObject *obj, QEvent *event) override;
Q_SIGNALS:
void sigRequestUpdateGuidesConfig(const KisGuidesConfig &config);
public Q_SLOTS:
void setGuidesConfig(const KisGuidesConfig &config);
void slotDocumentRequestedConfig(const KisGuidesConfig &config);
void setShowGuides(bool value);
void setLockGuides(bool value);
void setSnapToGuides(bool value);
void setRulersMultiple2(bool value);
void setUnitType(KoUnit::Type type);
void slotGuideCreationInProgress(Qt::Orientation orientation, const QPoint &globalPos);
void slotGuideCreationFinished(Qt::Orientation orientation, const QPoint &globalPos);
void slotShowSnapOptions();
void setSnapOrthogonal(bool value);
void setSnapNode(bool value);
void setSnapExtension(bool value);
void setSnapIntersection(bool value);
void setSnapBoundingBox(bool value);
void setSnapImageBounds(bool value);
void setSnapImageCenter(bool value);
+ void setSnapToPixel(bool value);
void slotUploadConfigToDocument();
private:
void setGuidesConfigImpl(const KisGuidesConfig &value, bool emitModified = true);
void attachEventFilterImpl(bool value);
void syncActionsStatus();
private:
struct Private;
const QScopedPointer m_d;
};
#endif /* __KIS_GUIDES_MANAGER_H */
diff --git a/libs/ui/canvas/kis_snap_config.cpp b/libs/ui/canvas/kis_snap_config.cpp
index 7d582a0056..4dab818821 100644
--- a/libs/ui/canvas/kis_snap_config.cpp
+++ b/libs/ui/canvas/kis_snap_config.cpp
@@ -1,52 +1,53 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_snap_config.h"
#include "kis_config.h"
KisSnapConfig::KisSnapConfig(bool loadValues)
: m_orthogonal(false),
m_node(false),
m_extension(false),
m_intersection(false),
m_boundingBox(false),
m_imageBounds(true),
- m_imageCenter(true)
+ m_imageCenter(true),
+ m_toPixel(false)
{
if (loadValues) {
loadStaticData();
}
}
KisSnapConfig::~KisSnapConfig()
{
}
void KisSnapConfig::saveStaticData() const
{
KisConfig cfg(false);
cfg.saveSnapConfig(*this);
}
void KisSnapConfig::loadStaticData()
{
KisConfig cfg(true);
cfg.loadSnapConfig(this);
}
diff --git a/libs/ui/canvas/kis_snap_config.h b/libs/ui/canvas/kis_snap_config.h
index dbc1adb8fd..16c874900a 100644
--- a/libs/ui/canvas/kis_snap_config.h
+++ b/libs/ui/canvas/kis_snap_config.h
@@ -1,91 +1,99 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_SNAP_CONFIG_H
#define __KIS_SNAP_CONFIG_H
class KisSnapConfig
{
public:
KisSnapConfig(bool loadValues = true);
~KisSnapConfig();
bool orthogonal() const {
return m_orthogonal;
}
void setOrthogonal(bool value) {
m_orthogonal = value;
}
bool node() const {
return m_node;
}
void setNode(bool value) {
m_node = value;
}
bool extension() const {
return m_extension;
}
void setExtension(bool value) {
m_extension = value;
}
bool intersection() const {
return m_intersection;
}
void setIntersection(bool value) {
m_intersection = value;
}
bool boundingBox() const {
return m_boundingBox;
}
void setBoundingBox(bool value) {
m_boundingBox = value;
}
bool imageBounds() const {
return m_imageBounds;
}
void setImageBounds(bool value) {
m_imageBounds = value;
}
bool imageCenter() const {
return m_imageCenter;
}
void setImageCenter(bool value) {
m_imageCenter = value;
}
+ bool toPixel() const {
+ return m_toPixel;
+ }
+ void setToPixel(bool value) {
+ m_toPixel = value;
+ }
+
void saveStaticData() const;
void loadStaticData();
private:
bool m_orthogonal;
bool m_node;
bool m_extension;
bool m_intersection;
bool m_boundingBox;
bool m_imageBounds;
bool m_imageCenter;
+ bool m_toPixel;
};
#endif /* __KIS_SNAP_CONFIG_H */
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index a8dcccb8f9..c960d46a75 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1,2144 +1,2146 @@
/*
* Copyright (c) 2002 Patrick Julien
*
* 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_config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_canvas_resource_provider.h"
#include "kis_config_notifier.h"
#include "kis_snap_config.h"
#include
#include
#include
#ifdef Q_OS_WIN
#include "config_use_qt_tablet_windows.h"
#endif
KisConfig::KisConfig(bool readOnly)
: m_cfg( KSharedConfig::openConfig()->group(""))
, m_readOnly(readOnly)
{
if (!readOnly) {
KIS_SAFE_ASSERT_RECOVER_RETURN(qApp && qApp->thread() == QThread::currentThread());
}
}
KisConfig::~KisConfig()
{
if (m_readOnly) return;
if (qApp && qApp->thread() != QThread::currentThread()) {
dbgKrita << "WARNING: KisConfig: requested config synchronization from nonGUI thread! Called from:" << kisBacktrace();
return;
}
m_cfg.sync();
}
bool KisConfig::disableTouchOnCanvas(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("disableTouchOnCanvas", false));
}
void KisConfig::setDisableTouchOnCanvas(bool value) const
{
m_cfg.writeEntry("disableTouchOnCanvas", value);
}
bool KisConfig::useProjections(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useProjections", true));
}
void KisConfig::setUseProjections(bool useProj) const
{
m_cfg.writeEntry("useProjections", useProj);
}
bool KisConfig::undoEnabled(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("undoEnabled", true));
}
void KisConfig::setUndoEnabled(bool undo) const
{
m_cfg.writeEntry("undoEnabled", undo);
}
int KisConfig::undoStackLimit(bool defaultValue) const
{
return (defaultValue ? 30 : m_cfg.readEntry("undoStackLimit", 30));
}
void KisConfig::setUndoStackLimit(int limit) const
{
m_cfg.writeEntry("undoStackLimit", limit);
}
bool KisConfig::useCumulativeUndoRedo(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useCumulativeUndoRedo",false));
}
void KisConfig::setCumulativeUndoRedo(bool value)
{
m_cfg.writeEntry("useCumulativeUndoRedo", value);
}
qreal KisConfig::stackT1(bool defaultValue) const
{
return (defaultValue ? 5 : m_cfg.readEntry("stackT1",5));
}
void KisConfig::setStackT1(int T1)
{
m_cfg.writeEntry("stackT1", T1);
}
qreal KisConfig::stackT2(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("stackT2",1));
}
void KisConfig::setStackT2(int T2)
{
m_cfg.writeEntry("stackT2", T2);
}
int KisConfig::stackN(bool defaultValue) const
{
return (defaultValue ? 5 : m_cfg.readEntry("stackN",5));
}
void KisConfig::setStackN(int N)
{
m_cfg.writeEntry("stackN", N);
}
qint32 KisConfig::defImageWidth(bool defaultValue) const
{
return (defaultValue ? 1600 : m_cfg.readEntry("imageWidthDef", 1600));
}
qint32 KisConfig::defImageHeight(bool defaultValue) const
{
return (defaultValue ? 1200 : m_cfg.readEntry("imageHeightDef", 1200));
}
qreal KisConfig::defImageResolution(bool defaultValue) const
{
return (defaultValue ? 100.0 : m_cfg.readEntry("imageResolutionDef", 100.0)) / 72.0;
}
QString KisConfig::defColorModel(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->colorModelId().id()
: m_cfg.readEntry("colorModelDef", KoColorSpaceRegistry::instance()->rgb8()->colorModelId().id()));
}
void KisConfig::defColorModel(const QString & model) const
{
m_cfg.writeEntry("colorModelDef", model);
}
QString KisConfig::defaultColorDepth(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->colorDepthId().id()
: m_cfg.readEntry("colorDepthDef", KoColorSpaceRegistry::instance()->rgb8()->colorDepthId().id()));
}
void KisConfig::setDefaultColorDepth(const QString & depth) const
{
m_cfg.writeEntry("colorDepthDef", depth);
}
QString KisConfig::defColorProfile(bool defaultValue) const
{
return (defaultValue ? KoColorSpaceRegistry::instance()->rgb8()->profile()->name() :
m_cfg.readEntry("colorProfileDef",
KoColorSpaceRegistry::instance()->rgb8()->profile()->name()));
}
void KisConfig::defColorProfile(const QString & profile) const
{
m_cfg.writeEntry("colorProfileDef", profile);
}
void KisConfig::defImageWidth(qint32 width) const
{
m_cfg.writeEntry("imageWidthDef", width);
}
void KisConfig::defImageHeight(qint32 height) const
{
m_cfg.writeEntry("imageHeightDef", height);
}
void KisConfig::defImageResolution(qreal res) const
{
m_cfg.writeEntry("imageResolutionDef", res*72.0);
}
int KisConfig::preferredVectorImportResolutionPPI(bool defaultValue) const
{
return defaultValue ? 100.0 : m_cfg.readEntry("preferredVectorImportResolution", 100.0);
}
void KisConfig::setPreferredVectorImportResolutionPPI(int value) const
{
m_cfg.writeEntry("preferredVectorImportResolution", value);
}
void cleanOldCursorStyleKeys(KConfigGroup &cfg)
{
if (cfg.hasKey("newCursorStyle") &&
cfg.hasKey("newOutlineStyle")) {
cfg.deleteEntry("cursorStyleDef");
}
}
CursorStyle KisConfig::newCursorStyle(bool defaultValue) const
{
if (defaultValue) {
return CURSOR_STYLE_NO_CURSOR;
}
int style = m_cfg.readEntry("newCursorStyle", int(-1));
if (style < 0) {
// old style format
style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE));
switch (style) {
case OLD_CURSOR_STYLE_TOOLICON:
style = CURSOR_STYLE_TOOLICON;
break;
case OLD_CURSOR_STYLE_CROSSHAIR:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS:
style = CURSOR_STYLE_CROSSHAIR;
break;
case OLD_CURSOR_STYLE_POINTER:
style = CURSOR_STYLE_POINTER;
break;
case OLD_CURSOR_STYLE_OUTLINE:
case OLD_CURSOR_STYLE_NO_CURSOR:
style = CURSOR_STYLE_NO_CURSOR;
break;
case OLD_CURSOR_STYLE_SMALL_ROUND:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT:
style = CURSOR_STYLE_SMALL_ROUND;
break;
case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED:
style = CURSOR_STYLE_TRIANGLE_RIGHTHANDED;
break;
case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED:
style = CURSOR_STYLE_TRIANGLE_LEFTHANDED;
break;
default:
style = -1;
}
}
cleanOldCursorStyleKeys(m_cfg);
// compatibility with future versions
if (style < 0 || style >= N_CURSOR_STYLE_SIZE) {
style = CURSOR_STYLE_NO_CURSOR;
}
return (CursorStyle) style;
}
void KisConfig::setNewCursorStyle(CursorStyle style)
{
m_cfg.writeEntry("newCursorStyle", (int)style);
}
QColor KisConfig::getCursorMainColor(bool defaultValue) const
{
QColor col;
col.setRgbF(0.501961, 1.0, 0.501961);
return (defaultValue ? col : m_cfg.readEntry("cursorMaincColor", col));
}
void KisConfig::setCursorMainColor(const QColor &v) const
{
m_cfg.writeEntry("cursorMaincColor", v);
}
OutlineStyle KisConfig::newOutlineStyle(bool defaultValue) const
{
if (defaultValue) {
return OUTLINE_FULL;
}
int style = m_cfg.readEntry("newOutlineStyle", int(-1));
if (style < 0) {
// old style format
style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE));
switch (style) {
case OLD_CURSOR_STYLE_TOOLICON:
case OLD_CURSOR_STYLE_CROSSHAIR:
case OLD_CURSOR_STYLE_POINTER:
case OLD_CURSOR_STYLE_NO_CURSOR:
case OLD_CURSOR_STYLE_SMALL_ROUND:
case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED:
style = OUTLINE_NONE;
break;
case OLD_CURSOR_STYLE_OUTLINE:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT:
case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED:
case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED:
style = OUTLINE_FULL;
break;
default:
style = -1;
}
}
cleanOldCursorStyleKeys(m_cfg);
// compatibility with future versions
if (style < 0 || style >= N_OUTLINE_STYLE_SIZE) {
style = OUTLINE_FULL;
}
return (OutlineStyle) style;
}
void KisConfig::setNewOutlineStyle(OutlineStyle style)
{
m_cfg.writeEntry("newOutlineStyle", (int)style);
}
QRect KisConfig::colorPreviewRect() const
{
return m_cfg.readEntry("colorPreviewRect", QVariant(QRect(32, 32, 48, 48))).toRect();
}
void KisConfig::setColorPreviewRect(const QRect &rect)
{
m_cfg.writeEntry("colorPreviewRect", QVariant(rect));
}
bool KisConfig::useDirtyPresets(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useDirtyPresets",false));
}
void KisConfig::setUseDirtyPresets(bool value)
{
m_cfg.writeEntry("useDirtyPresets",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::useEraserBrushSize(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useEraserBrushSize",false));
}
void KisConfig::setUseEraserBrushSize(bool value)
{
m_cfg.writeEntry("useEraserBrushSize",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::useEraserBrushOpacity(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useEraserBrushOpacity",false));
}
void KisConfig::setUseEraserBrushOpacity(bool value)
{
m_cfg.writeEntry("useEraserBrushOpacity",value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
QColor KisConfig::getMDIBackgroundColor(bool defaultValue) const
{
QColor col(77, 77, 77);
return (defaultValue ? col : m_cfg.readEntry("mdiBackgroundColor", col));
}
void KisConfig::setMDIBackgroundColor(const QColor &v) const
{
m_cfg.writeEntry("mdiBackgroundColor", v);
}
QString KisConfig::getMDIBackgroundImage(bool defaultValue) const
{
return (defaultValue ? "" : m_cfg.readEntry("mdiBackgroundImage", ""));
}
void KisConfig::setMDIBackgroundImage(const QString &filename) const
{
m_cfg.writeEntry("mdiBackgroundImage", filename);
}
QString KisConfig::monitorProfile(int screen) const
{
// Note: keep this in sync with the default profile for the RGB colorspaces!
QString profile = m_cfg.readEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), "sRGB-elle-V2-srgbtrc.icc");
//dbgKrita << "KisConfig::monitorProfile()" << profile;
return profile;
}
QString KisConfig::monitorForScreen(int screen, const QString &defaultMonitor, bool defaultValue) const
{
return (defaultValue ? defaultMonitor
: m_cfg.readEntry(QString("monitor_for_screen_%1").arg(screen), defaultMonitor));
}
void KisConfig::setMonitorForScreen(int screen, const QString& monitor)
{
m_cfg.writeEntry(QString("monitor_for_screen_%1").arg(screen), monitor);
}
void KisConfig::setMonitorProfile(int screen, const QString & monitorProfile, bool override) const
{
m_cfg.writeEntry("monitorProfile/OverrideX11", override);
m_cfg.writeEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), monitorProfile);
}
const KoColorProfile *KisConfig::getScreenProfile(int screen)
{
if (screen < 0) return 0;
KisConfig cfg(true);
QString monitorId;
if (KisColorManager::instance()->devices().size() > screen) {
monitorId = cfg.monitorForScreen(screen, KisColorManager::instance()->devices()[screen]);
}
//dbgKrita << "getScreenProfile(). Screen" << screen << "monitor id" << monitorId;
if (monitorId.isEmpty()) {
return 0;
}
QByteArray bytes = KisColorManager::instance()->displayProfile(monitorId);
//dbgKrita << "\tgetScreenProfile()" << bytes.size();
if (bytes.length() > 0) {
const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(RGBAColorModelID.id(), Integer8BitsColorDepthID.id(), bytes);
//dbgKrita << "\tKisConfig::getScreenProfile for screen" << screen << profile->name();
return profile;
}
else {
//dbgKrita << "\tCould not get a system monitor profile";
return 0;
}
}
const KoColorProfile *KisConfig::displayProfile(int screen) const
{
if (screen < 0) return 0;
// if the user plays with the settings, they can override the display profile, in which case
// we don't want the system setting.
bool override = useSystemMonitorProfile();
//dbgKrita << "KisConfig::displayProfile(). Override X11:" << override;
const KoColorProfile *profile = 0;
if (override) {
//dbgKrita << "\tGoing to get the screen profile";
profile = KisConfig::getScreenProfile(screen);
}
// if it fails. check the configuration
if (!profile || !profile->isSuitableForDisplay()) {
//dbgKrita << "\tGoing to get the monitor profile";
QString monitorProfileName = monitorProfile(screen);
//dbgKrita << "\t\tmonitorProfileName:" << monitorProfileName;
if (!monitorProfileName.isEmpty()) {
profile = KoColorSpaceRegistry::instance()->profileByName(monitorProfileName);
}
if (profile) {
//dbgKrita << "\t\tsuitable for display" << profile->isSuitableForDisplay();
}
else {
//dbgKrita << "\t\tstill no profile";
}
}
// if we still don't have a profile, or the profile isn't suitable for display,
// we need to get a last-resort profile. the built-in sRGB is a good choice then.
if (!profile || !profile->isSuitableForDisplay()) {
//dbgKrita << "\tnothing worked, going to get sRGB built-in";
profile = KoColorSpaceRegistry::instance()->profileByName("sRGB Built-in");
}
if (profile) {
//dbgKrita << "\tKisConfig::displayProfile for screen" << screen << "is" << profile->name();
}
else {
//dbgKrita << "\tCouldn't get a display profile at all";
}
return profile;
}
QString KisConfig::workingColorSpace(bool defaultValue) const
{
return (defaultValue ? "RGBA" : m_cfg.readEntry("workingColorSpace", "RGBA"));
}
void KisConfig::setWorkingColorSpace(const QString & workingColorSpace) const
{
m_cfg.writeEntry("workingColorSpace", workingColorSpace);
}
QString KisConfig::printerColorSpace(bool /*defaultValue*/) const
{
//TODO currently only rgb8 is supported
//return (defaultValue ? "RGBA" : m_cfg.readEntry("printerColorSpace", "RGBA"));
return QString("RGBA");
}
void KisConfig::setPrinterColorSpace(const QString & printerColorSpace) const
{
m_cfg.writeEntry("printerColorSpace", printerColorSpace);
}
QString KisConfig::printerProfile(bool defaultValue) const
{
return (defaultValue ? "" : m_cfg.readEntry("printerProfile", ""));
}
void KisConfig::setPrinterProfile(const QString & printerProfile) const
{
m_cfg.writeEntry("printerProfile", printerProfile);
}
bool KisConfig::useBlackPointCompensation(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useBlackPointCompensation", true));
}
void KisConfig::setUseBlackPointCompensation(bool useBlackPointCompensation) const
{
m_cfg.writeEntry("useBlackPointCompensation", useBlackPointCompensation);
}
bool KisConfig::allowLCMSOptimization(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("allowLCMSOptimization", true));
}
void KisConfig::setAllowLCMSOptimization(bool allowLCMSOptimization)
{
m_cfg.writeEntry("allowLCMSOptimization", allowLCMSOptimization);
}
bool KisConfig::forcePaletteColors(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("colorsettings/forcepalettecolors", false));
}
void KisConfig::setForcePaletteColors(bool forcePaletteColors)
{
m_cfg.writeEntry("colorsettings/forcepalettecolors", forcePaletteColors);
}
bool KisConfig::showRulers(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showrulers", false));
}
void KisConfig::setShowRulers(bool rulers) const
{
m_cfg.writeEntry("showrulers", rulers);
}
bool KisConfig::forceShowSaveMessages(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceShowSaveMessages", false));
}
void KisConfig::setForceShowSaveMessages(bool value) const
{
m_cfg.writeEntry("forceShowSaveMessages", value);
}
bool KisConfig::forceShowAutosaveMessages(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceShowAutosaveMessages", false));
}
void KisConfig::setForceShowAutosaveMessages(bool value) const
{
m_cfg.writeEntry("forceShowAutosaveMessages", value);
}
bool KisConfig::rulersTrackMouse(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("rulersTrackMouse", true));
}
void KisConfig::setRulersTrackMouse(bool value) const
{
m_cfg.writeEntry("rulersTrackMouse", value);
}
qint32 KisConfig::pasteBehaviour(bool defaultValue) const
{
return (defaultValue ? 2 : m_cfg.readEntry("pasteBehaviour", 2));
}
void KisConfig::setPasteBehaviour(qint32 renderIntent) const
{
m_cfg.writeEntry("pasteBehaviour", renderIntent);
}
qint32 KisConfig::monitorRenderIntent(bool defaultValue) const
{
qint32 intent = m_cfg.readEntry("renderIntent", INTENT_PERCEPTUAL);
if (intent > 3) intent = 3;
if (intent < 0) intent = 0;
return (defaultValue ? INTENT_PERCEPTUAL : intent);
}
void KisConfig::setRenderIntent(qint32 renderIntent) const
{
if (renderIntent > 3) renderIntent = 3;
if (renderIntent < 0) renderIntent = 0;
m_cfg.writeEntry("renderIntent", renderIntent);
}
bool KisConfig::useOpenGL(bool defaultValue) const
{
if (defaultValue) {
return true;
}
//dbgKrita << "use opengl" << m_cfg.readEntry("useOpenGL", true) << "success" << m_cfg.readEntry("canvasState", "OPENGL_SUCCESS");
QString cs = canvasState();
#ifdef Q_OS_WIN
return (m_cfg.readEntry("useOpenGLWindows", true) && (cs == "OPENGL_SUCCESS" || cs == "TRY_OPENGL"));
#else
return (m_cfg.readEntry("useOpenGL", true) && (cs == "OPENGL_SUCCESS" || cs == "TRY_OPENGL"));
#endif
}
void KisConfig::setUseOpenGL(bool useOpenGL) const
{
#ifdef Q_OS_WIN
m_cfg.writeEntry("useOpenGLWindows", useOpenGL);
#else
m_cfg.writeEntry("useOpenGL", useOpenGL);
#endif
}
int KisConfig::openGLFilteringMode(bool defaultValue) const
{
return (defaultValue ? 3 : m_cfg.readEntry("OpenGLFilterMode", 3));
}
void KisConfig::setOpenGLFilteringMode(int filteringMode)
{
m_cfg.writeEntry("OpenGLFilterMode", filteringMode);
}
bool KisConfig::useOpenGLTextureBuffer(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("useOpenGLTextureBuffer", true));
}
void KisConfig::setUseOpenGLTextureBuffer(bool useBuffer)
{
m_cfg.writeEntry("useOpenGLTextureBuffer", useBuffer);
}
int KisConfig::openGLTextureSize(bool defaultValue) const
{
return (defaultValue ? 256 : m_cfg.readEntry("textureSize", 256));
}
bool KisConfig::disableVSync(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("disableVSync", true));
}
void KisConfig::setDisableVSync(bool disableVSync)
{
m_cfg.writeEntry("disableVSync", disableVSync);
}
bool KisConfig::showAdvancedOpenGLSettings(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showAdvancedOpenGLSettings", false));
}
bool KisConfig::forceOpenGLFenceWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceOpenGLFenceWorkaround", false));
}
int KisConfig::numMipmapLevels(bool defaultValue) const
{
return (defaultValue ? 4 : m_cfg.readEntry("numMipmapLevels", 4));
}
int KisConfig::textureOverlapBorder() const
{
return 1 << qMax(0, numMipmapLevels());
}
quint32 KisConfig::getGridMainStyle(bool defaultValue) const
{
int v = m_cfg.readEntry("gridmainstyle", 0);
v = qBound(0, v, 2);
return (defaultValue ? 0 : v);
}
void KisConfig::setGridMainStyle(quint32 v) const
{
m_cfg.writeEntry("gridmainstyle", v);
}
quint32 KisConfig::getGridSubdivisionStyle(bool defaultValue) const
{
quint32 v = m_cfg.readEntry("gridsubdivisionstyle", 1);
if (v > 2) v = 2;
return (defaultValue ? 1 : v);
}
void KisConfig::setGridSubdivisionStyle(quint32 v) const
{
m_cfg.writeEntry("gridsubdivisionstyle", v);
}
QColor KisConfig::getGridMainColor(bool defaultValue) const
{
QColor col(99, 99, 99);
return (defaultValue ? col : m_cfg.readEntry("gridmaincolor", col));
}
void KisConfig::setGridMainColor(const QColor & v) const
{
m_cfg.writeEntry("gridmaincolor", v);
}
QColor KisConfig::getGridSubdivisionColor(bool defaultValue) const
{
QColor col(150, 150, 150);
return (defaultValue ? col : m_cfg.readEntry("gridsubdivisioncolor", col));
}
void KisConfig::setGridSubdivisionColor(const QColor & v) const
{
m_cfg.writeEntry("gridsubdivisioncolor", v);
}
QColor KisConfig::getPixelGridColor(bool defaultValue) const
{
QColor col(255, 255, 255);
return (defaultValue ? col : m_cfg.readEntry("pixelGridColor", col));
}
void KisConfig::setPixelGridColor(const QColor & v) const
{
m_cfg.writeEntry("pixelGridColor", v);
}
qreal KisConfig::getPixelGridDrawingThreshold(bool defaultValue) const
{
qreal border = 24.0f;
return (defaultValue ? border : m_cfg.readEntry("pixelGridDrawingThreshold", border));
}
void KisConfig::setPixelGridDrawingThreshold(qreal v) const
{
m_cfg.writeEntry("pixelGridDrawingThreshold", v);
}
bool KisConfig::pixelGridEnabled(bool defaultValue) const
{
bool enabled = true;
return (defaultValue ? enabled : m_cfg.readEntry("pixelGridEnabled", enabled));
}
void KisConfig::enablePixelGrid(bool v) const
{
m_cfg.writeEntry("pixelGridEnabled", v);
}
quint32 KisConfig::guidesLineStyle(bool defaultValue) const
{
int v = m_cfg.readEntry("guidesLineStyle", 0);
v = qBound(0, v, 2);
return (defaultValue ? 0 : v);
}
void KisConfig::setGuidesLineStyle(quint32 v) const
{
m_cfg.writeEntry("guidesLineStyle", v);
}
QColor KisConfig::guidesColor(bool defaultValue) const
{
QColor col(99, 99, 99);
return (defaultValue ? col : m_cfg.readEntry("guidesColor", col));
}
void KisConfig::setGuidesColor(const QColor & v) const
{
m_cfg.writeEntry("guidesColor", v);
}
void KisConfig::loadSnapConfig(KisSnapConfig *config, bool defaultValue) const
{
KisSnapConfig defaultConfig(false);
if (defaultValue) {
*config = defaultConfig;
return;
}
config->setOrthogonal(m_cfg.readEntry("globalSnapOrthogonal", defaultConfig.orthogonal()));
config->setNode(m_cfg.readEntry("globalSnapNode", defaultConfig.node()));
config->setExtension(m_cfg.readEntry("globalSnapExtension", defaultConfig.extension()));
config->setIntersection(m_cfg.readEntry("globalSnapIntersection", defaultConfig.intersection()));
config->setBoundingBox(m_cfg.readEntry("globalSnapBoundingBox", defaultConfig.boundingBox()));
config->setImageBounds(m_cfg.readEntry("globalSnapImageBounds", defaultConfig.imageBounds()));
config->setImageCenter(m_cfg.readEntry("globalSnapImageCenter", defaultConfig.imageCenter()));
+ config->setToPixel(m_cfg.readEntry("globalSnapToPixel", defaultConfig.toPixel()));
}
void KisConfig::saveSnapConfig(const KisSnapConfig &config)
{
m_cfg.writeEntry("globalSnapOrthogonal", config.orthogonal());
m_cfg.writeEntry("globalSnapNode", config.node());
m_cfg.writeEntry("globalSnapExtension", config.extension());
m_cfg.writeEntry("globalSnapIntersection", config.intersection());
m_cfg.writeEntry("globalSnapBoundingBox", config.boundingBox());
m_cfg.writeEntry("globalSnapImageBounds", config.imageBounds());
m_cfg.writeEntry("globalSnapImageCenter", config.imageCenter());
+ m_cfg.writeEntry("globalSnapToPixel", config.toPixel());
}
qint32 KisConfig::checkSize(bool defaultValue) const
{
return (defaultValue ? 32 : m_cfg.readEntry("checksize", 32));
}
void KisConfig::setCheckSize(qint32 checksize) const
{
m_cfg.writeEntry("checksize", checksize);
}
bool KisConfig::scrollCheckers(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("scrollingcheckers", false));
}
void KisConfig::setScrollingCheckers(bool sc) const
{
m_cfg.writeEntry("scrollingcheckers", sc);
}
QColor KisConfig::canvasBorderColor(bool defaultValue) const
{
QColor color(QColor(128,128,128));
return (defaultValue ? color : m_cfg.readEntry("canvasBorderColor", color));
}
void KisConfig::setCanvasBorderColor(const QColor& color) const
{
m_cfg.writeEntry("canvasBorderColor", color);
}
bool KisConfig::hideScrollbars(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("hideScrollbars", false));
}
void KisConfig::setHideScrollbars(bool value) const
{
m_cfg.writeEntry("hideScrollbars", value);
}
QColor KisConfig::checkersColor1(bool defaultValue) const
{
QColor col(220, 220, 220);
return (defaultValue ? col : m_cfg.readEntry("checkerscolor", col));
}
void KisConfig::setCheckersColor1(const QColor & v) const
{
m_cfg.writeEntry("checkerscolor", v);
}
QColor KisConfig::checkersColor2(bool defaultValue) const
{
return (defaultValue ? QColor(Qt::white) : m_cfg.readEntry("checkerscolor2", QColor(Qt::white)));
}
void KisConfig::setCheckersColor2(const QColor & v) const
{
m_cfg.writeEntry("checkerscolor2", v);
}
bool KisConfig::antialiasCurves(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("antialiascurves", true));
}
void KisConfig::setAntialiasCurves(bool v) const
{
m_cfg.writeEntry("antialiascurves", v);
}
bool KisConfig::antialiasSelectionOutline(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("AntialiasSelectionOutline", false));
}
void KisConfig::setAntialiasSelectionOutline(bool v) const
{
m_cfg.writeEntry("AntialiasSelectionOutline", v);
}
bool KisConfig::showRootLayer(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ShowRootLayer", false));
}
void KisConfig::setShowRootLayer(bool showRootLayer) const
{
m_cfg.writeEntry("ShowRootLayer", showRootLayer);
}
bool KisConfig::showGlobalSelection(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ShowGlobalSelection", false));
}
void KisConfig::setShowGlobalSelection(bool showGlobalSelection) const
{
m_cfg.writeEntry("ShowGlobalSelection", showGlobalSelection);
}
bool KisConfig::showOutlineWhilePainting(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("ShowOutlineWhilePainting", true));
}
void KisConfig::setShowOutlineWhilePainting(bool showOutlineWhilePainting) const
{
m_cfg.writeEntry("ShowOutlineWhilePainting", showOutlineWhilePainting);
}
bool KisConfig::forceAlwaysFullSizedOutline(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("forceAlwaysFullSizedOutline", false));
}
void KisConfig::setForceAlwaysFullSizedOutline(bool value) const
{
m_cfg.writeEntry("forceAlwaysFullSizedOutline", value);
}
KisConfig::SessionOnStartup KisConfig::sessionOnStartup(bool defaultValue) const
{
int value = defaultValue ? SOS_BlankSession : m_cfg.readEntry("sessionOnStartup", (int)SOS_BlankSession);
return (KisConfig::SessionOnStartup)value;
}
void KisConfig::setSessionOnStartup(SessionOnStartup value)
{
m_cfg.writeEntry("sessionOnStartup", (int)value);
}
bool KisConfig::saveSessionOnQuit(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("saveSessionOnQuit", false);
}
void KisConfig::setSaveSessionOnQuit(bool value)
{
m_cfg.writeEntry("saveSessionOnQuit", value);
}
qreal KisConfig::outlineSizeMinimum(bool defaultValue) const
{
return (defaultValue ? 1.0 : m_cfg.readEntry("OutlineSizeMinimum", 1.0));
}
void KisConfig::setOutlineSizeMinimum(qreal outlineSizeMinimum) const
{
m_cfg.writeEntry("OutlineSizeMinimum", outlineSizeMinimum);
}
qreal KisConfig::selectionViewSizeMinimum(bool defaultValue) const
{
return (defaultValue ? 5.0 : m_cfg.readEntry("SelectionViewSizeMinimum", 5.0));
}
void KisConfig::setSelectionViewSizeMinimum(qreal outlineSizeMinimum) const
{
m_cfg.writeEntry("SelectionViewSizeMinimum", outlineSizeMinimum);
}
int KisConfig::autoSaveInterval(bool defaultValue) const
{
return (defaultValue ? 15 * 60 : m_cfg.readEntry("AutoSaveInterval", 15 * 60));
}
void KisConfig::setAutoSaveInterval(int seconds) const
{
return m_cfg.writeEntry("AutoSaveInterval", seconds);
}
bool KisConfig::backupFile(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("CreateBackupFile", true));
}
void KisConfig::setBackupFile(bool backupFile) const
{
m_cfg.writeEntry("CreateBackupFile", backupFile);
}
bool KisConfig::showFilterGallery(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showFilterGallery", false));
}
void KisConfig::setShowFilterGallery(bool showFilterGallery) const
{
m_cfg.writeEntry("showFilterGallery", showFilterGallery);
}
bool KisConfig::showFilterGalleryLayerMaskDialog(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showFilterGalleryLayerMaskDialog", true));
}
void KisConfig::setShowFilterGalleryLayerMaskDialog(bool showFilterGallery) const
{
m_cfg.writeEntry("setShowFilterGalleryLayerMaskDialog", showFilterGallery);
}
QString KisConfig::canvasState(bool defaultValue) const
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return (defaultValue ? "OPENGL_NOT_TRIED" : kritarc.value("canvasState", "OPENGL_NOT_TRIED").toString());
}
void KisConfig::setCanvasState(const QString& state) const
{
static QStringList acceptableStates;
if (acceptableStates.isEmpty()) {
acceptableStates << "OPENGL_SUCCESS" << "TRY_OPENGL" << "OPENGL_NOT_TRIED" << "OPENGL_FAILED";
}
if (acceptableStates.contains(state)) {
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
kritarc.setValue("canvasState", state);
}
}
bool KisConfig::toolOptionsPopupDetached(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ToolOptionsPopupDetached", false));
}
void KisConfig::setToolOptionsPopupDetached(bool detached) const
{
m_cfg.writeEntry("ToolOptionsPopupDetached", detached);
}
bool KisConfig::paintopPopupDetached(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("PaintopPopupDetached", false));
}
void KisConfig::setPaintopPopupDetached(bool detached) const
{
m_cfg.writeEntry("PaintopPopupDetached", detached);
}
QString KisConfig::pressureTabletCurve(bool defaultValue) const
{
return (defaultValue ? "0,0;1,1" : m_cfg.readEntry("tabletPressureCurve","0,0;1,1;"));
}
void KisConfig::setPressureTabletCurve(const QString& curveString) const
{
m_cfg.writeEntry("tabletPressureCurve", curveString);
}
bool KisConfig::useWin8PointerInput(bool defaultValue) const
{
#ifdef Q_OS_WIN
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return useWin8PointerInputNoApp(&kritarc, defaultValue);
#else
return (defaultValue ? false : m_cfg.readEntry("useWin8PointerInput", false));
#endif
#else
Q_UNUSED(defaultValue);
return false;
#endif
}
void KisConfig::setUseWin8PointerInput(bool value)
{
#ifdef Q_OS_WIN
// Special handling: Only set value if changed
// I don't want it to be set if the user hasn't touched it
if (useWin8PointerInput() != value) {
#ifdef USE_QT_TABLET_WINDOWS
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
setUseWin8PointerInputNoApp(&kritarc, value);
#else
m_cfg.writeEntry("useWin8PointerInput", value);
#endif
}
#else
Q_UNUSED(value)
#endif
}
bool KisConfig::useWin8PointerInputNoApp(QSettings *settings, bool defaultValue)
{
return defaultValue ? false : settings->value("useWin8PointerInput", false).toBool();
}
void KisConfig::setUseWin8PointerInputNoApp(QSettings *settings, bool value)
{
settings->setValue("useWin8PointerInput", value);
}
bool KisConfig::useRightMiddleTabletButtonWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useRightMiddleTabletButtonWorkaround", false));
}
void KisConfig::setUseRightMiddleTabletButtonWorkaround(bool value)
{
m_cfg.writeEntry("useRightMiddleTabletButtonWorkaround", value);
}
qreal KisConfig::vastScrolling(bool defaultValue) const
{
return (defaultValue ? 0.9 : m_cfg.readEntry("vastScrolling", 0.9));
}
void KisConfig::setVastScrolling(const qreal factor) const
{
m_cfg.writeEntry("vastScrolling", factor);
}
int KisConfig::presetChooserViewMode(bool defaultValue) const
{
return (defaultValue ? 0 : m_cfg.readEntry("presetChooserViewMode", 0));
}
void KisConfig::setPresetChooserViewMode(const int mode) const
{
m_cfg.writeEntry("presetChooserViewMode", mode);
}
int KisConfig::presetIconSize(bool defaultValue) const
{
return (defaultValue ? 60 : m_cfg.readEntry("presetIconSize", 60));
}
void KisConfig::setPresetIconSize(const int value) const
{
m_cfg.writeEntry("presetIconSize", value);
}
bool KisConfig::firstRun(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("firstRun", true));
}
void KisConfig::setFirstRun(const bool first) const
{
m_cfg.writeEntry("firstRun", first);
}
int KisConfig::horizontalSplitLines(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("horizontalSplitLines", 1));
}
void KisConfig::setHorizontalSplitLines(const int numberLines) const
{
m_cfg.writeEntry("horizontalSplitLines", numberLines);
}
int KisConfig::verticalSplitLines(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("verticalSplitLines", 1));
}
void KisConfig::setVerticalSplitLines(const int numberLines) const
{
m_cfg.writeEntry("verticalSplitLines", numberLines);
}
bool KisConfig::clicklessSpacePan(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("clicklessSpacePan", true));
}
void KisConfig::setClicklessSpacePan(const bool toggle) const
{
m_cfg.writeEntry("clicklessSpacePan", toggle);
}
bool KisConfig::hideDockersFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideDockersFullScreen", true));
}
void KisConfig::setHideDockersFullscreen(const bool value) const
{
m_cfg.writeEntry("hideDockersFullScreen", value);
}
bool KisConfig::showDockers(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showDockers", true));
}
void KisConfig::setShowDockers(const bool value) const
{
m_cfg.writeEntry("showDockers", value);
}
bool KisConfig::showStatusBar(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showStatusBar", true));
}
void KisConfig::setShowStatusBar(const bool value) const
{
m_cfg.writeEntry("showStatusBar", value);
}
bool KisConfig::hideMenuFullscreen(bool defaultValue) const
{
return (defaultValue ? true: m_cfg.readEntry("hideMenuFullScreen", true));
}
void KisConfig::setHideMenuFullscreen(const bool value) const
{
m_cfg.writeEntry("hideMenuFullScreen", value);
}
bool KisConfig::hideScrollbarsFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideScrollbarsFullScreen", true));
}
void KisConfig::setHideScrollbarsFullscreen(const bool value) const
{
m_cfg.writeEntry("hideScrollbarsFullScreen", value);
}
bool KisConfig::hideStatusbarFullscreen(bool defaultValue) const
{
return (defaultValue ? true: m_cfg.readEntry("hideStatusbarFullScreen", true));
}
void KisConfig::setHideStatusbarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideStatusbarFullScreen", value);
}
bool KisConfig::hideTitlebarFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideTitleBarFullscreen", true));
}
void KisConfig::setHideTitlebarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideTitleBarFullscreen", value);
}
bool KisConfig::hideToolbarFullscreen(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("hideToolbarFullscreen", true));
}
void KisConfig::setHideToolbarFullscreen(const bool value) const
{
m_cfg.writeEntry("hideToolbarFullscreen", value);
}
bool KisConfig::fullscreenMode(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("fullscreenMode", true));
}
void KisConfig::setFullscreenMode(const bool value) const
{
m_cfg.writeEntry("fullscreenMode", value);
}
QStringList KisConfig::favoriteCompositeOps(bool defaultValue) const
{
return (defaultValue ? QStringList() : m_cfg.readEntry("favoriteCompositeOps", QStringList()));
}
void KisConfig::setFavoriteCompositeOps(const QStringList& compositeOps) const
{
m_cfg.writeEntry("favoriteCompositeOps", compositeOps);
}
QString KisConfig::exportConfigurationXML(const QString &filterId, bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("ExportConfiguration-" + filterId, QString()));
}
KisPropertiesConfigurationSP KisConfig::exportConfiguration(const QString &filterId, bool defaultValue) const
{
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
const QString xmlData = exportConfigurationXML(filterId, defaultValue);
cfg->fromXML(xmlData);
return cfg;
}
void KisConfig::setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
{
QString exportConfig = properties->toXML();
m_cfg.writeEntry("ExportConfiguration-" + filterId, exportConfig);
}
QString KisConfig::importConfiguration(const QString &filterId, bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("ImportConfiguration-" + filterId, QString()));
}
void KisConfig::setImportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
{
QString importConfig = properties->toXML();
m_cfg.writeEntry("ImportConfiguration-" + filterId, importConfig);
}
bool KisConfig::useOcio(bool defaultValue) const
{
#ifdef HAVE_OCIO
return (defaultValue ? false : m_cfg.readEntry("Krita/Ocio/UseOcio", false));
#else
Q_UNUSED(defaultValue);
return false;
#endif
}
void KisConfig::setUseOcio(bool useOCIO) const
{
m_cfg.writeEntry("Krita/Ocio/UseOcio", useOCIO);
}
int KisConfig::favoritePresets(bool defaultValue) const
{
return (defaultValue ? 10 : m_cfg.readEntry("numFavoritePresets", 10));
}
void KisConfig::setFavoritePresets(const int value)
{
m_cfg.writeEntry("numFavoritePresets", value);
}
bool KisConfig::levelOfDetailEnabled(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("levelOfDetailEnabled", false));
}
void KisConfig::setLevelOfDetailEnabled(bool value)
{
m_cfg.writeEntry("levelOfDetailEnabled", value);
}
KisOcioConfiguration KisConfig::ocioConfiguration(bool defaultValue) const
{
KisOcioConfiguration cfg;
if (!defaultValue) {
cfg.mode = (KisOcioConfiguration::Mode)m_cfg.readEntry("Krita/Ocio/OcioColorManagementMode", 0);
cfg.configurationPath = m_cfg.readEntry("Krita/Ocio/OcioConfigPath", QString());
cfg.lutPath = m_cfg.readEntry("Krita/Ocio/OcioLutPath", QString());
cfg.inputColorSpace = m_cfg.readEntry("Krita/Ocio/InputColorSpace", QString());
cfg.displayDevice = m_cfg.readEntry("Krita/Ocio/DisplayDevice", QString());
cfg.displayView = m_cfg.readEntry("Krita/Ocio/DisplayView", QString());
cfg.look = m_cfg.readEntry("Krita/Ocio/DisplayLook", QString());
}
return cfg;
}
void KisConfig::setOcioConfiguration(const KisOcioConfiguration &cfg)
{
m_cfg.writeEntry("Krita/Ocio/OcioColorManagementMode", (int) cfg.mode);
m_cfg.writeEntry("Krita/Ocio/OcioConfigPath", cfg.configurationPath);
m_cfg.writeEntry("Krita/Ocio/OcioLutPath", cfg.lutPath);
m_cfg.writeEntry("Krita/Ocio/InputColorSpace", cfg.inputColorSpace);
m_cfg.writeEntry("Krita/Ocio/DisplayDevice", cfg.displayDevice);
m_cfg.writeEntry("Krita/Ocio/DisplayView", cfg.displayView);
m_cfg.writeEntry("Krita/Ocio/DisplayLook", cfg.look);
}
KisConfig::OcioColorManagementMode
KisConfig::ocioColorManagementMode(bool defaultValue) const
{
// FIXME: this option duplicates ocioConfiguration(), please deprecate it
return (OcioColorManagementMode)(defaultValue ? INTERNAL
: m_cfg.readEntry("Krita/Ocio/OcioColorManagementMode", (int) INTERNAL));
}
void KisConfig::setOcioColorManagementMode(OcioColorManagementMode mode) const
{
// FIXME: this option duplicates ocioConfiguration(), please deprecate it
m_cfg.writeEntry("Krita/Ocio/OcioColorManagementMode", (int) mode);
}
int KisConfig::ocioLutEdgeSize(bool defaultValue) const
{
return (defaultValue ? 64 : m_cfg.readEntry("Krita/Ocio/LutEdgeSize", 64));
}
void KisConfig::setOcioLutEdgeSize(int value)
{
m_cfg.writeEntry("Krita/Ocio/LutEdgeSize", value);
}
bool KisConfig::ocioLockColorVisualRepresentation(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("Krita/Ocio/OcioLockColorVisualRepresentation", false));
}
void KisConfig::setOcioLockColorVisualRepresentation(bool value)
{
m_cfg.writeEntry("Krita/Ocio/OcioLockColorVisualRepresentation", value);
}
QString KisConfig::defaultPalette(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("defaultPalette", "Default"));
}
void KisConfig::setDefaultPalette(const QString& name) const
{
m_cfg.writeEntry("defaultPalette", name);
}
QString KisConfig::toolbarSlider(int sliderNumber, bool defaultValue) const
{
QString def = "flow";
if (sliderNumber == 1) {
def = "opacity";
}
if (sliderNumber == 2) {
def = "size";
}
return (defaultValue ? def : m_cfg.readEntry(QString("toolbarslider_%1").arg(sliderNumber), def));
}
void KisConfig::setToolbarSlider(int sliderNumber, const QString &slider)
{
m_cfg.writeEntry(QString("toolbarslider_%1").arg(sliderNumber), slider);
}
int KisConfig::layerThumbnailSize(bool defaultValue) const
{
return (defaultValue ? 20 : m_cfg.readEntry("layerThumbnailSize", 20));
}
void KisConfig::setLayerThumbnailSize(int size)
{
m_cfg.writeEntry("layerThumbnailSize", size);
}
bool KisConfig::sliderLabels(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("sliderLabels", true));
}
void KisConfig::setSliderLabels(bool enabled)
{
m_cfg.writeEntry("sliderLabels", enabled);
}
QString KisConfig::currentInputProfile(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("currentInputProfile", QString()));
}
void KisConfig::setCurrentInputProfile(const QString& name)
{
m_cfg.writeEntry("currentInputProfile", name);
}
bool KisConfig::useSystemMonitorProfile(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("ColorManagement/UseSystemMonitorProfile", false));
}
void KisConfig::setUseSystemMonitorProfile(bool _useSystemMonitorProfile) const
{
m_cfg.writeEntry("ColorManagement/UseSystemMonitorProfile", _useSystemMonitorProfile);
}
bool KisConfig::presetStripVisible(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("presetStripVisible", true));
}
void KisConfig::setPresetStripVisible(bool visible)
{
m_cfg.writeEntry("presetStripVisible", visible);
}
bool KisConfig::scratchpadVisible(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("scratchpadVisible", true));
}
void KisConfig::setScratchpadVisible(bool visible)
{
m_cfg.writeEntry("scratchpadVisible", visible);
}
bool KisConfig::showSingleChannelAsColor(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("showSingleChannelAsColor", false));
}
void KisConfig::setShowSingleChannelAsColor(bool asColor)
{
m_cfg.writeEntry("showSingleChannelAsColor", asColor);
}
bool KisConfig::hidePopups(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("hidePopups", false));
}
void KisConfig::setHidePopups(bool hidepopups)
{
m_cfg.writeEntry("hidePopups", hidepopups);
}
int KisConfig::numDefaultLayers(bool defaultValue) const
{
return (defaultValue ? 2 : m_cfg.readEntry("NumberOfLayersForNewImage", 2));
}
void KisConfig::setNumDefaultLayers(int num)
{
m_cfg.writeEntry("NumberOfLayersForNewImage", num);
}
quint8 KisConfig::defaultBackgroundOpacity(bool defaultValue) const
{
return (defaultValue ? (int)OPACITY_OPAQUE_U8 : m_cfg.readEntry("BackgroundOpacityForNewImage", (int)OPACITY_OPAQUE_U8));
}
void KisConfig::setDefaultBackgroundOpacity(quint8 value)
{
m_cfg.writeEntry("BackgroundOpacityForNewImage", (int)value);
}
QColor KisConfig::defaultBackgroundColor(bool defaultValue) const
{
return (defaultValue ? QColor(Qt::white) : m_cfg.readEntry("BackgroundColorForNewImage", QColor(Qt::white)));
}
void KisConfig::setDefaultBackgroundColor(QColor value)
{
m_cfg.writeEntry("BackgroundColorForNewImage", value);
}
KisConfig::BackgroundStyle KisConfig::defaultBackgroundStyle(bool defaultValue) const
{
return (KisConfig::BackgroundStyle)(defaultValue ? RASTER_LAYER : m_cfg.readEntry("BackgroundStyleForNewImage", (int)RASTER_LAYER));
}
void KisConfig::setDefaultBackgroundStyle(KisConfig::BackgroundStyle value)
{
m_cfg.writeEntry("BackgroundStyleForNewImage", (int)value);
}
int KisConfig::lineSmoothingType(bool defaultValue) const
{
return (defaultValue ? 1 : m_cfg.readEntry("LineSmoothingType", 1));
}
void KisConfig::setLineSmoothingType(int value)
{
m_cfg.writeEntry("LineSmoothingType", value);
}
qreal KisConfig::lineSmoothingDistance(bool defaultValue) const
{
return (defaultValue ? 50.0 : m_cfg.readEntry("LineSmoothingDistance", 50.0));
}
void KisConfig::setLineSmoothingDistance(qreal value)
{
m_cfg.writeEntry("LineSmoothingDistance", value);
}
qreal KisConfig::lineSmoothingTailAggressiveness(bool defaultValue) const
{
return (defaultValue ? 0.15 : m_cfg.readEntry("LineSmoothingTailAggressiveness", 0.15));
}
void KisConfig::setLineSmoothingTailAggressiveness(qreal value)
{
m_cfg.writeEntry("LineSmoothingTailAggressiveness", value);
}
bool KisConfig::lineSmoothingSmoothPressure(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("LineSmoothingSmoothPressure", false));
}
void KisConfig::setLineSmoothingSmoothPressure(bool value)
{
m_cfg.writeEntry("LineSmoothingSmoothPressure", value);
}
bool KisConfig::lineSmoothingScalableDistance(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingScalableDistance", true));
}
void KisConfig::setLineSmoothingScalableDistance(bool value)
{
m_cfg.writeEntry("LineSmoothingScalableDistance", value);
}
qreal KisConfig::lineSmoothingDelayDistance(bool defaultValue) const
{
return (defaultValue ? 50.0 : m_cfg.readEntry("LineSmoothingDelayDistance", 50.0));
}
void KisConfig::setLineSmoothingDelayDistance(qreal value)
{
m_cfg.writeEntry("LineSmoothingDelayDistance", value);
}
bool KisConfig::lineSmoothingUseDelayDistance(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingUseDelayDistance", true));
}
void KisConfig::setLineSmoothingUseDelayDistance(bool value)
{
m_cfg.writeEntry("LineSmoothingUseDelayDistance", value);
}
bool KisConfig::lineSmoothingFinishStabilizedCurve(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingFinishStabilizedCurve", true));
}
void KisConfig::setLineSmoothingFinishStabilizedCurve(bool value)
{
m_cfg.writeEntry("LineSmoothingFinishStabilizedCurve", value);
}
bool KisConfig::lineSmoothingStabilizeSensors(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("LineSmoothingStabilizeSensors", true));
}
void KisConfig::setLineSmoothingStabilizeSensors(bool value)
{
m_cfg.writeEntry("LineSmoothingStabilizeSensors", value);
}
int KisConfig::tabletEventsDelay(bool defaultValue) const
{
return (defaultValue ? 10 : m_cfg.readEntry("tabletEventsDelay", 10));
}
void KisConfig::setTabletEventsDelay(int value)
{
m_cfg.writeEntry("tabletEventsDelay", value);
}
bool KisConfig::trackTabletEventLatency(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("trackTabletEventLatency", false));
}
void KisConfig::setTrackTabletEventLatency(bool value)
{
m_cfg.writeEntry("trackTabletEventLatency", value);
}
bool KisConfig::testingAcceptCompressedTabletEvents(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("testingAcceptCompressedTabletEvents", false));
}
void KisConfig::setTestingAcceptCompressedTabletEvents(bool value)
{
m_cfg.writeEntry("testingAcceptCompressedTabletEvents", value);
}
bool KisConfig::shouldEatDriverShortcuts(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("shouldEatDriverShortcuts", false));
}
bool KisConfig::testingCompressBrushEvents(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("testingCompressBrushEvents", false));
}
void KisConfig::setTestingCompressBrushEvents(bool value)
{
m_cfg.writeEntry("testingCompressBrushEvents", value);
}
int KisConfig::workaroundX11SmoothPressureSteps(bool defaultValue) const
{
return (defaultValue ? 0 : m_cfg.readEntry("workaroundX11SmoothPressureSteps", 0));
}
bool KisConfig::showCanvasMessages(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showOnCanvasMessages", true));
}
void KisConfig::setShowCanvasMessages(bool show)
{
m_cfg.writeEntry("showOnCanvasMessages", show);
}
bool KisConfig::compressKra(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("compressLayersInKra", false));
}
void KisConfig::setCompressKra(bool compress)
{
m_cfg.writeEntry("compressLayersInKra", compress);
}
bool KisConfig::toolOptionsInDocker(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("ToolOptionsInDocker", true));
}
void KisConfig::setToolOptionsInDocker(bool inDocker)
{
m_cfg.writeEntry("ToolOptionsInDocker", inDocker);
}
bool KisConfig::kineticScrollingEnabled(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("KineticScrollingEnabled", true));
}
void KisConfig::setKineticScrollingEnabled(bool value)
{
m_cfg.writeEntry("KineticScrollingEnabled", value);
}
int KisConfig::kineticScrollingGesture(bool defaultValue) const
{
return (defaultValue ? 2 : m_cfg.readEntry("KineticScrollingGesture", 2));
}
void KisConfig::setKineticScrollingGesture(int gesture)
{
m_cfg.writeEntry("KineticScrollingGesture", gesture);
}
int KisConfig::kineticScrollingSensitivity(bool defaultValue) const
{
return (defaultValue ? 75 : m_cfg.readEntry("KineticScrollingSensitivity", 75));
}
void KisConfig::setKineticScrollingSensitivity(int sensitivity)
{
m_cfg.writeEntry("KineticScrollingSensitivity", sensitivity);
}
bool KisConfig::kineticScrollingHiddenScrollbars(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("KineticScrollingHideScrollbar", false));
}
void KisConfig::setKineticScrollingHideScrollbars(bool scrollbar)
{
m_cfg.writeEntry("KineticScrollingHideScrollbar", scrollbar);
}
const KoColorSpace* KisConfig::customColorSelectorColorSpace(bool defaultValue) const
{
const KoColorSpace *cs = 0;
KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
if (defaultValue || cfg.readEntry("useCustomColorSpace", true)) {
KoColorSpaceRegistry* csr = KoColorSpaceRegistry::instance();
QString modelID = cfg.readEntry("customColorSpaceModel", "RGBA");
QString depthID = cfg.readEntry("customColorSpaceDepthID", "U8");
QString profile = cfg.readEntry("customColorSpaceProfile", "sRGB built-in - (lcms internal)");
if (profile == "default") {
// qDebug() << "Falling back to default color profile.";
profile = "sRGB built-in - (lcms internal)";
}
cs = csr->colorSpace(modelID, depthID, profile);
}
return cs;
}
void KisConfig::setCustomColorSelectorColorSpace(const KoColorSpace *cs)
{
KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
cfg.writeEntry("useCustomColorSpace", bool(cs));
if(cs) {
cfg.writeEntry("customColorSpaceModel", cs->colorModelId().id());
cfg.writeEntry("customColorSpaceDepthID", cs->colorDepthId().id());
cfg.writeEntry("customColorSpaceProfile", cs->profile()->name());
}
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::enableOpenGLFramerateLogging(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("enableOpenGLFramerateLogging", false));
}
void KisConfig::setEnableOpenGLFramerateLogging(bool value) const
{
m_cfg.writeEntry("enableOpenGLFramerateLogging", value);
}
bool KisConfig::enableBrushSpeedLogging(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("enableBrushSpeedLogging", false));
}
void KisConfig::setEnableBrushSpeedLogging(bool value) const
{
m_cfg.writeEntry("enableBrushSpeedLogging", value);
}
void KisConfig::setEnableAmdVectorizationWorkaround(bool value)
{
m_cfg.writeEntry("amdDisableVectorWorkaround", value);
}
bool KisConfig::enableAmdVectorizationWorkaround(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("amdDisableVectorWorkaround", false));
}
void KisConfig::setDisableAVXOptimizations(bool value)
{
m_cfg.writeEntry("disableAVXOptimizations", value);
}
bool KisConfig::disableAVXOptimizations(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("disableAVXOptimizations", false));
}
void KisConfig::setAnimationDropFrames(bool value)
{
bool oldValue = animationDropFrames();
if (value == oldValue) return;
m_cfg.writeEntry("animationDropFrames", value);
KisConfigNotifier::instance()->notifyDropFramesModeChanged();
}
bool KisConfig::animationDropFrames(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("animationDropFrames", true));
}
int KisConfig::scrubbingUpdatesDelay(bool defaultValue) const
{
return (defaultValue ? 30 : m_cfg.readEntry("scrubbingUpdatesDelay", 30));
}
void KisConfig::setScrubbingUpdatesDelay(int value)
{
m_cfg.writeEntry("scrubbingUpdatesDelay", value);
}
int KisConfig::scrubbingAudioUpdatesDelay(bool defaultValue) const
{
return (defaultValue ? -1 : m_cfg.readEntry("scrubbingAudioUpdatesDelay", -1));
}
void KisConfig::setScrubbingAudioUpdatesDelay(int value)
{
m_cfg.writeEntry("scrubbingAudioUpdatesDelay", value);
}
int KisConfig::audioOffsetTolerance(bool defaultValue) const
{
return (defaultValue ? -1 : m_cfg.readEntry("audioOffsetTolerance", -1));
}
void KisConfig::setAudioOffsetTolerance(int value)
{
m_cfg.writeEntry("audioOffsetTolerance", value);
}
bool KisConfig::switchSelectionCtrlAlt(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("switchSelectionCtrlAlt", false);
}
void KisConfig::setSwitchSelectionCtrlAlt(bool value)
{
m_cfg.writeEntry("switchSelectionCtrlAlt", value);
KisConfigNotifier::instance()->notifyConfigChanged();
}
bool KisConfig::convertToImageColorspaceOnImport(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("ConvertToImageColorSpaceOnImport", false);
}
void KisConfig::setConvertToImageColorspaceOnImport(bool value)
{
m_cfg.writeEntry("ConvertToImageColorSpaceOnImport", value);
}
int KisConfig::stabilizerSampleSize(bool defaultValue) const
{
#ifdef Q_OS_WIN
const int defaultSampleSize = 50;
#else
const int defaultSampleSize = 15;
#endif
return defaultValue ?
defaultSampleSize : m_cfg.readEntry("stabilizerSampleSize", defaultSampleSize);
}
void KisConfig::setStabilizerSampleSize(int value)
{
m_cfg.writeEntry("stabilizerSampleSize", value);
}
bool KisConfig::stabilizerDelayedPaint(bool defaultValue) const
{
const bool defaultEnabled = true;
return defaultValue ?
defaultEnabled : m_cfg.readEntry("stabilizerDelayedPaint", defaultEnabled);
}
void KisConfig::setStabilizerDelayedPaint(bool value)
{
m_cfg.writeEntry("stabilizerDelayedPaint", value);
}
bool KisConfig::showBrushHud(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("showBrushHud", false);
}
void KisConfig::setShowBrushHud(bool value)
{
m_cfg.writeEntry("showBrushHud", value);
}
QString KisConfig::brushHudSetting(bool defaultValue) const
{
QString defaultDoc = "\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n";
return defaultValue ? defaultDoc : m_cfg.readEntry("brushHudSettings", defaultDoc);
}
void KisConfig::setBrushHudSetting(const QString &value) const
{
m_cfg.writeEntry("brushHudSettings", value);
}
bool KisConfig::calculateAnimationCacheInBackground(bool defaultValue) const
{
return defaultValue ? true : m_cfg.readEntry("calculateAnimationCacheInBackground", true);
}
void KisConfig::setCalculateAnimationCacheInBackground(bool value)
{
m_cfg.writeEntry("calculateAnimationCacheInBackground", value);
}
QColor KisConfig::defaultAssistantsColor(bool defaultValue) const
{
static const QColor defaultColor = QColor(176, 176, 176, 255);
return defaultValue ? defaultColor : m_cfg.readEntry("defaultAssistantsColor", defaultColor);
}
void KisConfig::setDefaultAssistantsColor(const QColor &color) const
{
m_cfg.writeEntry("defaultAssistantsColor", color);
}
bool KisConfig::autoSmoothBezierCurves(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("autoSmoothBezierCurves", false);
}
void KisConfig::setAutoSmoothBezierCurves(bool value)
{
m_cfg.writeEntry("autoSmoothBezierCurves", value);
}
bool KisConfig::activateTransformToolAfterPaste(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("activateTransformToolAfterPaste", false);
}
void KisConfig::setActivateTransformToolAfterPaste(bool value)
{
m_cfg.writeEntry("activateTransformToolAfterPaste", value);
}
KisConfig::RootSurfaceFormat KisConfig::rootSurfaceFormat(bool defaultValue) const
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
return rootSurfaceFormat(&kritarc, defaultValue);
}
void KisConfig::setRootSurfaceFormat(KisConfig::RootSurfaceFormat value)
{
const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
setRootSurfaceFormat(&kritarc, value);
}
KisConfig::RootSurfaceFormat KisConfig::rootSurfaceFormat(QSettings *displayrc, bool defaultValue)
{
QString textValue = "bt709-g22";
if (!defaultValue) {
textValue = displayrc->value("rootSurfaceFormat", textValue).toString();
}
return textValue == "bt709-g10" ? BT709_G10 :
textValue == "bt2020-pq" ? BT2020_PQ :
BT709_G22;
}
void KisConfig::setRootSurfaceFormat(QSettings *displayrc, KisConfig::RootSurfaceFormat value)
{
const QString textValue =
value == BT709_G10 ? "bt709-g10" :
value == BT2020_PQ ? "bt2020-pq" :
"bt709-g22";
displayrc->setValue("rootSurfaceFormat", textValue);
}
bool KisConfig::useZip64(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("UseZip64", false);
}
void KisConfig::setUseZip64(bool value)
{
m_cfg.writeEntry("UseZip64", value);
}
#include
#include
void KisConfig::writeKoColor(const QString& name, const KoColor& color) const
{
QDomDocument doc = QDomDocument(name);
QDomElement el = doc.createElement(name);
doc.appendChild(el);
color.toXML(doc, el);
m_cfg.writeEntry(name, doc.toString());
}
//ported from kispropertiesconfig.
KoColor KisConfig::readKoColor(const QString& name, const KoColor& color) const
{
QDomDocument doc;
if (!m_cfg.readEntry(name).isNull()) {
doc.setContent(m_cfg.readEntry(name));
QDomElement e = doc.documentElement().firstChild().toElement();
return KoColor::fromXML(e, Integer16BitsColorDepthID.id());
} else {
QString blackColor = "\n\n \n\n";
doc.setContent(blackColor);
QDomElement e = doc.documentElement().firstChild().toElement();
return KoColor::fromXML(e, Integer16BitsColorDepthID.id());
}
return color;
}