diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt
index 646aa887c4..1ff2ed1841 100644
--- a/3rdparty/CMakeLists.txt
+++ b/3rdparty/CMakeLists.txt
@@ -1,128 +1,132 @@
project (krita-and-all-its-deps)
#
# Build all dependencies for Krita and finally Krita itself.
# Parameters: EXTERNALS_DOWNLOAD_DIR place to download all packages
# INSTALL_ROOT place to install everything to
# MXE_TOOLCHAIN: the toolchain file to cross-compile using MXE
#
# Example usage: cmake ..\kritadeposx -DEXTERNALS_DOWNLOAD_DIR=/dev2/d -DINSTALL_ROOT=/dev2/i -DWIN64_BUILD=TRUE -DBOOST_LIBRARYDIR=/dev2/i/lib -G "Visual Studio 11 Win64"
cmake_minimum_required(VERSION 2.8.6)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "Compiling in the source directory is not supported. Use for example 'mkdir build; cd build; cmake ..'.")
endif (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
# Tools must be obtained to work with:
include (ExternalProject)
# allow specification of a directory with pre-downloaded
# requirements
if(NOT IS_DIRECTORY ${EXTERNALS_DOWNLOAD_DIR})
message(FATAL_ERROR "No externals download dir set. Use -DEXTERNALS_DOWNLOAD_DIR")
endif()
if(NOT IS_DIRECTORY ${INSTALL_ROOT})
message(FATAL_ERROR "No install dir set. Use -DINSTALL_ROOT")
endif()
set(TOP_INST_DIR ${INSTALL_ROOT})
set(EXTPREFIX "${TOP_INST_DIR}")
set(CMAKE_PREFIX_PATH "${EXTPREFIX}")
if (${CMAKE_GENERATOR} STREQUAL "Visual Studio 14 2015 Win64")
SET(GLOBAL_PROFILE
-DCMAKE_MODULE_LINKER_FLAGS=/machine:x64
-DCMAKE_EXE_LINKER_FLAGS=/machine:x64
-DCMAKE_SHARED_LINKER_FLAGS=/machine:x64
-DCMAKE_STATIC_LINKER_FLAGS=/machine:x64
)
endif ()
message( STATUS "CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
message( STATUS "CMAKE_CL_64: ${CMAKE_CL_64}")
set(GLOBAL_BUILD_TYPE RelWithDebInfo)
set(GLOBAL_PROFILE ${GLOBAL_PROFILE} -DBUILD_TESTING=false)
+if (DEFINED EP_PREFIX)
+ set_directory_properties(PROPERTIES EP_PREFIX ${EP_PREFIX})
+endif (DEFINED EP_PREFIX)
+
if (MSVC)
set(GLOBAL_PROFILE ${GLOBAL_PROFILE} -DCMAKE_EXE_LINKER_FLAGS=/PROFILE -DCMAKE_SHARED_LINKER_FLAGS=/PROFILE)
set(PATCH_COMMAND myptch)
endif()
if (MINGW)
set(PATCH_COMMAND myptch)
endif()
if (MSYS)
set(PATCH_COMMAND patch)
set(GLOBAL_PROFILE ${GLOBAL_PROFILE}
-DCMAKE_TOOLCHAIN_FILE=${MXE_TOOLCHAIN}
-DCMAKE_FIND_PREFIX_PATH=${CMAKE_PREFIX_PATH}
-DCMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_PREFIX_PATH}/include
-DCMAKE_INCLUDE_PATH=${CMAKE_PREFIX_PATH}/include
-DCMAKE_LIBRARY_PATH=${CMAKE_PREFIX_PATH}/lib
-DZLIB_ROOT=${CMAKE_PREFIX_PATH}
)
set(GLOBAL_AUTOMAKE_PROFILE --host=i686-pc-mingw32 )
endif()
if (APPLE)
set(GLOBAL_PROFILE ${GLOBAL_PROFILE} -DCMAKE_MACOSX_RPATH=ON -DKDE_SKIP_RPATH_SETTINGS=ON -DBUILD_WITH_INSTALL_RPATH=ON -DAPPLE_SUPPRESS_X11_WARNING=ON)
set(PATCH_COMMAND patch)
endif ()
if (UNIX AND NOT APPLE)
set(LINUX true)
set(PATCH_COMMAND patch)
endif ()
# this list must be dependency-ordered
if (UNIX)
add_subdirectory( ext_python )
add_subdirectory( ext_llvm )
endif ()
if (MSVC)
add_subdirectory( ext_patch )
add_subdirectory( ext_png2ico )
endif (MSVC)
if (MINGW)
add_subdirectory( ext_patch )
add_subdirectory( ext_png2ico )
endif (MINGW)
add_subdirectory( ext_iconv )
add_subdirectory( ext_gettext )
add_subdirectory( ext_zlib )
add_subdirectory( ext_libxml2 )
add_subdirectory( ext_libxslt )
add_subdirectory( ext_boost )
add_subdirectory( ext_jpeg )
add_subdirectory( ext_tiff )
add_subdirectory( ext_png )
add_subdirectory( ext_eigen3 )
add_subdirectory( ext_expat ) # for exiv2
add_subdirectory( ext_exiv2 )
add_subdirectory( ext_ilmbase )
add_subdirectory( ext_lcms2 )
add_subdirectory( ext_openexr )
add_subdirectory( ext_vc )
add_subdirectory( ext_gsl )
add_subdirectory( ext_fftw3 )
add_subdirectory( ext_ocio )
if (MSVC)
add_subdirectory( ext_pthreads )
endif (MSVC)
add_subdirectory( ext_fontconfig)
add_subdirectory( ext_freetype)
add_subdirectory( ext_qt )
add_subdirectory( ext_poppler )
add_subdirectory( ext_libraw )
add_subdirectory( ext_frameworks )
add_subdirectory( ext_sip )
add_subdirectory( ext_pyqt )
if (MSVC OR MINGW)
add_subdirectory( ext_drmingw )
endif (MSVC OR MINGW)
diff --git a/3rdparty/ext_qt/CMakeLists.txt b/3rdparty/ext_qt/CMakeLists.txt
index a7b99bb7a1..81fd754f82 100644
--- a/3rdparty/ext_qt/CMakeLists.txt
+++ b/3rdparty/ext_qt/CMakeLists.txt
@@ -1,186 +1,186 @@
SET(EXTPREFIX_qt "${EXTPREFIX}")
if (WIN32)
ExternalProject_Add(
ext_qt
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.qt.io/official_releases/qt/5.6/5.6.1-1/single/qt-everywhere-opensource-src-5.6.1-1.zip
URL_MD5 9d7ea0cadcec7b5a63e8e83686756978
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/disable-wintab.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/qtgui-private-headers.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/0001-Don-t-request-the-MIME-image-every-time-Windows-asks.patch
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/0002-Hack-always-return-we-support-DIBV5.patch
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/0003-Hack-for-fullscreen-workaround.patch
INSTALL_DIR ${EXTPREFIX_qt}
- CONFIGURE_COMMAND /configure.bat -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -no-libproxy -no-system-proxies -no-nis -no-icu -no-mtdev -opensource -confirm-license -release -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -prefix ${EXTPREFIX_qt} -platform win32-g++
+ CONFIGURE_COMMAND /configure.bat -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -no-libproxy -no-system-proxies -no-nis -no-icu -no-mtdev -opensource -confirm-license -release -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -prefix ${EXTPREFIX_qt} -platform win32-g++
# use this line for building Qt with debugging info enabled
#CONFIGURE_COMMAND /configure.bat -release -force-debug-info -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-angle -no-ssl -no-openssl -no-wmf-backend -no-qml-debug -no-libproxy -no-system-proxies -no-nis -no-icu -no-mtdev -opensource -confirm-license -release -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -prefix ${EXTPREFIX_qt} -platform win32-g++
BUILD_COMMAND mingw32-make
INSTALL_COMMAND mingw32-make install
UPDATE_COMMAND ""
BUILD_IN_SOURCE 1
ALWAYS 0
DEPENDS ext_patch
)
elseif (NOT APPLE)
ExternalProject_Add(
ext_qt
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://download.qt.io/official_releases/qt/5.6/5.6.1-1/single/qt-everywhere-opensource-src-5.6.1-1.tar.gz
URL_MD5 8fdec6d657bc370bd3183d8fe8e9c47a
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/qt-no-motion-compression.diff
INSTALL_DIR ${EXTPREFIX_qt}
CONFIGURE_COMMAND /configure -prefix ${EXTPREFIX_qt} -opensource -confirm-license -nomake examples -no-sql-sqlite -no-openssl -no-qml-debug -no-mtdev -no-journald -no-syslog -no-nis -no-cups -no-tslib -no-directfb -no-linuxfb -no-libproxy -no-pch -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-harfbuzz -qt-freetype -qt-xcb -qt-xkbcommon-x11 -optimized-qmake -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtenginio -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtandroidextras -skip qtserialport
BUILD_COMMAND $(MAKE)
INSTALL_COMMAND $(MAKE) install
UPDATE_COMMAND ""
BUILD_IN_SOURCE 1
ALWAYS 0
)
else( APPLE )
# XCODE_VERSION is set by CMake when using the Xcode generator, otherwise we need
# to detect it manually here.
if (NOT XCODE_VERSION)
execute_process(
COMMAND xcodebuild -version
OUTPUT_VARIABLE xcodebuild_version
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_FILE /dev/null
)
string(REGEX MATCH "Xcode ([0-9]([.][0-9])+)" version_match ${xcodebuild_version})
if (version_match)
message(STATUS "${EXTPREFIX_qt}:Identified Xcode Version: ${CMAKE_MATCH_1}")
set(XCODE_VERSION ${CMAKE_MATCH_1})
else()
# If detecting Xcode version failed, set a crazy high version so we default
# to the newest.
set(XCODE_VERSION 99)
message(WARNING "${EXTPREFIX_qt}:Failed to detect the version of an installed copy of Xcode, falling back to highest supported version. Set XCODE_VERSION to override.")
endif(version_match)
endif(NOT XCODE_VERSION)
# -------------------------------------------------------------------------------
# Verify the Xcode installation on Mac OS like Qt5.7 does/will
# If not stop now, the system isn't configured correctly for Qt.
# No reason to even proceed.
# -------------------------------------------------------------------------------
set(XCSELECT_OUTPUT)
find_program(XCSELECT_PROGRAM "xcode-select")
if(XCSELECT_PROGRAM)
message(STATUS "${EXTPREFIX_qt}:Found XCSELECT_PROGRAM as ${XCSELECT_PROGRAM}")
set(XCSELECT_COMMAND ${XCSELECT_PROGRAM}
"--print-path")
execute_process(
COMMAND ${XCSELECT_COMMAND}
RESULT_VARIABLE XCSELECT_COMMAND_RESULT
OUTPUT_VARIABLE XCSELECT_COMMAND_OUTPUT
ERROR_FILE /dev/null
)
if(NOT XCSELECT_COMMAND_RESULT)
# returned 0, we're ok.
string(REGEX REPLACE
"[ \t]*[\r\n]+[ \t]*" ";"
XCSELECT_COMMAND_OUTPUT ${XCSELECT_COMMAND_OUTPUT})
else()
string(REPLACE ";" " " XCSELECT_COMMAND_STR "${XCSELECT_COMMAND}")
# message(STATUS "${XCSELECT_COMMAND_STR}")
message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} test failed with status ${XCSELECT_COMMAND_RESULT}")
endif()
else()
message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} not found. No Xcode is selected. Use xcode-select -switch to choose an Xcode version")
endif()
# Belts and suspenders
# Beyond all the Xcode and Qt version checking, the proof of the pudding
# lies in the success/failure of this command: xcrun --find xcrun.
# On failure a patch is necessary, otherwise we're ok
# So hard check xcrun now...
set(XCRUN_OUTPUT)
find_program(XCRUN_PROGRAM "xcrun")
if(XCRUN_PROGRAM)
message(STATUS "${EXTPREFIX_qt}:Found XCRUN_PROGRAM as ${XCRUN_PROGRAM}")
set(XCRUN_COMMAND ${XCRUN_PROGRAM}
"--find xcrun")
execute_process(
COMMAND ${XCRUN_COMMAND}
RESULT_VARIABLE XCRUN_COMMAND_RESULT
OUTPUT_VARIABLE XCRUN_COMMAND_OUTPUT
ERROR_FILE /dev/null
)
if(NOT XCRUN_COMMAND_RESULT)
# returned 0, we're ok.
string(REGEX REPLACE
"[ \t]*[\r\n]+[ \t]*" ";"
XCRUN_COMMAND_OUTPUT ${XCRUN_COMMAND_OUTPUT})
else()
string(REPLACE ";" " " XCRUN_COMMAND_STR "${XCRUN_COMMAND}")
# message(STATUS "${XCRUN_COMMAND_STR}")
message(STATUS "${EXTPREFIX_qt}:xcrun test failed with status ${XCRUN_COMMAND_RESULT}")
endif()
else()
message(STATUS "${EXTPREFIX_qt}:xcrun not found -- ${XCRUN_PROGRAM}")
endif()
#
# Now configure ext_qt accordingly
#
if ((XCRUN_COMMAND_RESULT) AND (NOT (XCODE_VERSION VERSION_LESS 8.0.0)))
# Fix Xcode xcrun related issue.
# NOTE: This should be fixed by Qt 5.7.1 see here: http://code.qt.io/cgit/qt/qtbase.git/commit/?h=dev&id=77a71c32c9d19b87f79b208929e71282e8d8b5d9
# NOTE: but no one's holding their breath.
set(ext_qt_PATCH_COMMAND $${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/gerrit-166202.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/macdeploy-qt.diff
COMMAND ${PATCH_COMMAND} -p1 -b -d /qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/qtbase-configure.patch
COMMAND ${PATCH_COMMAND} -p1 -b -d /qtbase/mkspecs/features/mac -i ${CMAKE_CURRENT_SOURCE_DIR}/mac-default.patch)
message(STATUS "${EXTPREFIX_qt}:Additional patches injected.")
else()
# No extra patches will be applied
# NOTE: defaults for some untested scenarios like xcrun fails and xcode_version < 8.
# NOTE: that is uncharted territory and (hopefully) a very unlikely scenario...
set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/gerrit-166202.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/macdeploy-qt.diff)
endif()
# Qt is big - try and parallelize if at all possible
include(ProcessorCount)
ProcessorCount(NUM_CORES)
if(NOT NUM_CORES EQUAL 0)
if (NUM_CORES GREATER 2)
# be nice...
MATH( EXPR NUM_CORES "${NUM_CORES} - 2" )
endif()
set(PARALLEL_MAKE "make;-j${NUM_CORES}")
message(STATUS "${EXTPREFIX_qt}:Parallelized make: ${PARALLEL_MAKE}")
else()
set(PARALLEL_MAKE "make")
endif()
ExternalProject_Add(ext_qt
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
LOG_DOWNLOAD ON
LOG_UPDATE ON
LOG_CONFIGURE ON
LOG_BUILD ON
LOG_TEST ON
LOG_INSTALL ON
BUILD_IN_SOURCE ON
URL https://download.qt.io/official_releases/qt/5.7/5.7.0/single/qt-everywhere-opensource-src-5.7.0.tar.gz
URL_MD5 9a46cce61fc64c20c3ac0a0e0fa41b42
PATCH_COMMAND ${ext_qt_PATCH_COMMAND}
INSTALL_DIR ${EXTPREFIX_qt}
CONFIGURE_COMMAND /configure -confirm-license -opensource -nomake examples -no-openssl -no-compile-examples -qt-freetype -qt-harfbuzz -opengl desktop -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtgraphicaleffects -skip qtlocation -skip qtmultimedia -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -prefix ${EXTPREFIX_qt}
BUILD_COMMAND ${PARALLEL_MAKE}
INSTALL_COMMAND make install
UPDATE_COMMAND ""
BUILD_IN_SOURCE 1
ALWAYS 0
)
endif()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 628f0661d2..e21280a154 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,655 +1,667 @@
project(krita)
message(STATUS "Using CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
set(MIN_QT_VERSION 5.6.0)
option(OVERRIDE_QT_VERSION "Use this to make it possible to build with Qt < 5.6.0. There will be bugs." OFF)
if (OVERRIDE_QT_VERSION)
set(MIN_QT_VERSION 5.4.0)
endif()
set(MIN_FRAMEWORKS_VERSION 5.7.0)
if (POLICY CMP0002)
cmake_policy(SET CMP0002 OLD)
endif()
if (POLICY CMP0017)
cmake_policy(SET CMP0017 NEW)
endif ()
if (POLICY CMP0022)
cmake_policy(SET CMP0022 OLD)
endif ()
if (POLICY CMP0026)
cmake_policy(SET CMP0026 OLD)
endif()
if (POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
if (POLICY CMP0046)
cmake_policy(SET CMP0046 OLD)
endif ()
if (POLICY CMP0059)
cmake_policy(SET CMP0059 OLD)
endif()
if (POLICY CMP0063)
cmake_policy(SET CMP0063 OLD)
endif()
if (POLICY CMP0054)
cmake_policy(SET CMP0054 OLD)
endif()
if (POLICY CMP0064)
cmake_policy(SET CMP0064 OLD)
endif()
if (APPLE)
set(APPLE_SUPPRESS_X11_WARNING TRUE)
set(KDE_SKIP_RPATH_SETTINGS TRUE)
set(CMAKE_MACOSX_RPATH 1)
set(BUILD_WITH_INSTALL_RPATH 1)
add_definitions(-mmacosx-version-min=10.9 -Wno-macro-redefined -Wno-deprecated-register)
endif()
######################
#######################
## Constants defines ##
#######################
######################
# define common versions of Krita applications, used to generate kritaversion.h
# update these version for every release:
set(KRITA_VERSION_STRING "3.1.88")
set(KRITA_STABLE_VERSION_MAJOR 3) # 3 for 3.x, 4 for 4.x, etc.
set(KRITA_STABLE_VERSION_MINOR 1) # 0 for 3.0, 1 for 3.1, etc.
set(KRITA_VERSION_RELEASE 88) # 88 for pre-alpha, 89 for Alpha, increase for next test releases, set 0 for first Stable, etc.
set(KRITA_ALPHA 1) # uncomment only for Alpha
#set(KRITA_BETA 1) # uncomment only for Beta
#set(KRITA_RC 1) # uncomment only for RC
set(KRITA_YEAR 2017) # update every year
if(NOT DEFINED KRITA_ALPHA AND NOT DEFINED KRITA_BETA AND NOT DEFINED KRITA_RC)
set(KRITA_STABLE 1) # do not edit
endif()
message(STATUS "Krita version: ${KRITA_VERSION_STRING}")
# Define the generic version of the Krita libraries here
# This makes it easy to advance it when the next Krita release comes.
# 14 was the last GENERIC_KRITA_LIB_VERSION_MAJOR of the previous Krita series
# (2.x) so we're starting with 15 in 3.x series.
if(KRITA_STABLE_VERSION_MAJOR EQUAL 3)
math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 15")
else()
# let's make sure we won't forget to update the "15"
message(FATAL_ERROR "Reminder: please update offset == 15 used to compute GENERIC_KRITA_LIB_VERSION_MAJOR to something bigger")
endif()
set(GENERIC_KRITA_LIB_VERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}.0.0")
set(GENERIC_KRITA_LIB_SOVERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}")
LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/kde_macro")
# fetch git revision for the current build
set(KRITA_GIT_SHA1_STRING "")
set(KRITA_GIT_BRANCH_STRING "")
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
get_git_branch(GIT_BRANCH)
if(GIT_SHA1 AND GIT_BRANCH)
string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1)
set(KRITA_GIT_SHA1_STRING ${GIT_SHA1})
set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH})
endif()
if(NOT DEFINED RELEASE_BUILD)
# estimate mode by CMAKE_BUILD_TYPE content if not set on cmdline
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER)
set(RELEASE_BUILD_TYPES "release" "relwithdebinfo" "minsizerel")
list(FIND RELEASE_BUILD_TYPES "${CMAKE_BUILD_TYPE_TOLOWER}" INDEX)
if (INDEX EQUAL -1)
set(RELEASE_BUILD FALSE)
else()
set(RELEASE_BUILD TRUE)
endif()
endif()
message(STATUS "Release build: ${RELEASE_BUILD}")
# create test make targets
enable_testing()
# collect list of broken tests, empty here to start fresh with each cmake run
set(KRITA_BROKEN_TESTS "" CACHE INTERNAL "KRITA_BROKEN_TESTS")
############
#############
## Options ##
#############
############
include(FeatureSummary)
option(PACKAGERS_BUILD "Build support of multiple CPU architectures in one binary. Should be used by packagers only or Krita developers. Only switch off when you're an artist optimizing a build for your very own machine." ON)
add_feature_info("Packagers' Build" PACKAGERS_BUILD "Support several CPU arch in one binary. Recommended for packages. Switch this off to make a build for only your machine.")
if (WIN32)
option(USE_DRMINGW "Support the Dr. Mingw crash handler (only on windows)" ON)
add_feature_info("Dr. Mingw" USE_DRMINGW "Enable the Dr. Mingw crash handler")
if (MINGW)
option(USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags (mingw-w64)" ON)
add_feature_info("Linker Security Flags" USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags")
if (USE_MINGW_HARDENING_LINKER)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base")
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
# Enable high-entropy ASLR for 64-bit
# The image base has to be >4GB for HEASLR to be enabled.
# The values used here are kind of arbitrary.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x140000000")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000")
endif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
else (USE_MINGW_HARDENING_LINKER)
message(WARNING "Linker Security Flags not enabled!")
endif (USE_MINGW_HARDENING_LINKER)
endif (MINGW)
endif ()
option(HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal." ON)
configure_file(config-hide-safe-asserts.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hide-safe-asserts.h)
add_feature_info("Safe Asserts" HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal.")
option(FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true." OFF)
add_feature_info("Foundation Build" FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true.")
option(KRITA_ENABLE_BROKEN_TESTS "Enable tests that are marked as broken" OFF)
add_feature_info("Enable Broken Tests" KRITA_ENABLE_BROKEN_TESTS "Runs broken test when \"make test\" is invoked (use -DKRITA_ENABLE_BROKEN_TESTS=ON to enable).")
include(MacroJPEG)
########################
#########################
## Look for KDE and Qt ##
#########################
########################
find_package(ECM 1.7.0 REQUIRED NOMODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(ECMOptionalAddSubdirectory)
include(ECMAddAppIcon)
include(ECMSetupVersion)
include(ECMMarkNonGuiExecutable)
include(ECMGenerateHeaders)
include(GenerateExportHeader)
include(ECMMarkAsTest)
include(ECMInstallIcons)
include(CMakePackageConfigHelpers)
include(WriteBasicConfigVersionFile)
include(CheckFunctionExists)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
# do not reorder to be alphabetical: this is the order in which the frameworks
# depend on each other.
find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS
Archive
Config
WidgetsAddons
Completion
CoreAddons
GuiAddons
I18n
ItemModels
ItemViews
WindowSystem
)
# KConfig deprecated authorizeKAction. In order to be warning free,
# compile with the updated function when the dependency is new enough.
# Remove this (and the uses of the define) when the minimum KF5
# version is >= 5.24.0.
if (${KF5Config_VERSION} VERSION_LESS "5.24.0" )
message("Old KConfig (< 5.24.0) found.")
add_definitions(-DKCONFIG_BEFORE_5_24)
endif()
find_package(Qt5 ${MIN_QT_VERSION}
REQUIRED COMPONENTS
Core
Gui
Widgets
Xml
Network
PrintSupport
Svg
Test
Concurrent
)
include (MacroAddFileDependencies)
include (MacroBoolTo01)
include (MacroEnsureOutOfSourceBuild)
macro_ensure_out_of_source_build("Compiling Krita inside the source directory is not possible. Please refer to the build instruction https://community.kde.org/Krita#Build_Instructions")
# Note: OPTIONAL_COMPONENTS does not seem to be reliable
# (as of ECM 5.15.0, CMake 3.2)
+
+find_package(Qt5Multimedia ${MIN_QT_VERSION})
+set_package_properties(Qt5Multimedia PROPERTIES
+ DESCRIPTION "Qt multimedia integration"
+ URL "http://www.qt.io/"
+ TYPE OPTIONAL
+ PURPOSE "Optionally used to provide sound support for animations")
+
+macro_bool_to_01(Qt5Multimedia_FOUND HAVE_QT_MULTIMEDIA)
+configure_file(config-qtmultimedia.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-qtmultimedia.h )
+
if (NOT WIN32 AND NOT APPLE)
find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras)
- find_package(Qt5DBus ${MIN_QT_VERSION} QUIET)
+ find_package(Qt5DBus ${MIN_QT_VERSION})
set(HAVE_DBUS ${Qt5DBus_FOUND})
set_package_properties(Qt5DBus PROPERTIES
DESCRIPTION "Qt DBUS integration"
URL "http://www.qt.io/"
TYPE OPTIONAL
PURPOSE "Optionally used to provide a dbus api on Linux")
- find_package(KF5KIO ${MIN_FRAMEWORKS_VERSION} QUIET)
+ find_package(KF5KIO ${MIN_FRAMEWORKS_VERSION})
macro_bool_to_01(KF5KIO_FOUND HAVE_KIO)
set_package_properties(KF5KIO PROPERTIES
DESCRIPTION "KDE's KIO Framework"
URL "http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/index.html"
TYPE OPTIONAL
PURPOSE "Optionally used for recent document handling")
- find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION} QUIET)
+ find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION})
macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH)
set_package_properties(KF5Crash PROPERTIES
DESCRIPTION "KDE's Crash Handler"
URL "http://api.kde.org/frameworks-api/frameworks5-apidocs/kcrash/html/index.html"
TYPE OPTIONAL
PURPOSE "Optionally used to provide crash reporting on Linux")
find_package(X11 REQUIRED COMPONENTS Xinput)
set(HAVE_X11 TRUE)
add_definitions(-DHAVE_X11)
find_package(XCB COMPONENTS XCB ATOM)
set(HAVE_XCB ${XCB_FOUND})
else()
set(HAVE_DBUS FALSE)
set(HAVE_X11 FALSE)
set(HAVE_XCB FALSE)
endif()
+
add_definitions(
-DQT_USE_QSTRINGBUILDER
-DQT_STRICT_ITERATORS
-DQT_NO_SIGNALS_SLOTS_KEYWORDS
-DQT_USE_FAST_OPERATOR_PLUS
-DQT_USE_FAST_CONCATENATION
-DQT_NO_URL_CAST_FROM_STRING
-DQT_DISABLE_DEPRECATED_BEFORE=0
)
add_definitions(-DTRANSLATION_DOMAIN=\"krita\")
#
# The reason for this mode is that the Debug mode disable inlining
#
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS_KRITADEVS "-O3 -g" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals")
endif()
if(UNIX)
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m")
endif()
if(WIN32)
if(MSVC)
# C4522: 'class' : multiple assignment operators specified
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4522")
endif()
endif()
# enable exceptions globally
kde_enable_exceptions()
# only with this definition will all the FOO_TEST_EXPORT macro do something
# TODO: check if this can be moved to only those places which make use of it,
# to reduce global compiler definitions that would trigger a recompile of
# everything on a change (like adding/removing tests to/from the build)
if(BUILD_TESTING)
add_definitions(-DCOMPILING_TESTS)
endif()
set(KRITA_DEFAULT_TEST_DATA_DIR ${CMAKE_SOURCE_DIR}/sdk/tests/data/)
macro(macro_add_unittest_definitions)
add_definitions(-DFILES_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data/")
add_definitions(-DFILES_OUTPUT_DIR="${CMAKE_CURRENT_BINARY_DIR}")
add_definitions(-DFILES_DEFAULT_DATA_DIR="${KRITA_DEFAULT_TEST_DATA_DIR}")
add_definitions(-DSYSTEM_RESOURCES_DATA_DIR="${CMAKE_SOURCE_DIR}/krita/data/")
endmacro()
# overcome some platform incompatibilities
if(WIN32)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/winquirks)
add_definitions(-D_USE_MATH_DEFINES)
add_definitions(-DNOMINMAX)
set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib)
endif()
# set custom krita plugin installdir
set(KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins)
###########################
############################
## Required dependencies ##
############################
###########################
find_package(PNG REQUIRED)
if (APPLE)
# this is not added correctly on OSX -- see http://forum.kde.org/viewtopic.php?f=139&t=101867&p=221242#p221242
include_directories(SYSTEM ${PNG_INCLUDE_DIR})
endif()
add_definitions(-DBOOST_ALL_NO_LIB)
find_package(Boost REQUIRED COMPONENTS system) # for pigment and stage
include_directories(${Boost_INCLUDE_DIRS})
##
## Test for GNU Scientific Library
##
find_package(GSL)
set_package_properties(GSL PROPERTIES
URL "http://www.gnu.org/software/gsl"
TYPE RECOMMENDED
PURPOSE "Required by Krita's Transform tool.")
macro_bool_to_01(GSL_FOUND HAVE_GSL)
configure_file(config-gsl.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gsl.h )
###########################
############################
## Optional dependencies ##
############################
###########################
##
## Check for OpenEXR
##
find_package(ZLIB)
set_package_properties(ZLIB PROPERTIES
DESCRIPTION "Compression library"
URL "http://www.zlib.net/"
TYPE OPTIONAL
PURPOSE "Optionally used by the G'Mic and the PSD plugins")
macro_bool_to_01(ZLIB_FOUND HAVE_ZLIB)
find_package(OpenEXR)
set_package_properties(OpenEXR PROPERTIES
DESCRIPTION "High dynamic-range (HDR) image file format"
URL "http://www.openexr.com"
TYPE OPTIONAL
PURPOSE "Required by the Krita OpenEXR filter")
macro_bool_to_01(OPENEXR_FOUND HAVE_OPENEXR)
set(LINK_OPENEXR_LIB)
if(OPENEXR_FOUND)
include_directories(SYSTEM ${OPENEXR_INCLUDE_DIR})
set(LINK_OPENEXR_LIB ${OPENEXR_LIBRARIES})
add_definitions(${OPENEXR_DEFINITIONS})
endif()
find_package(TIFF)
set_package_properties(TIFF PROPERTIES
DESCRIPTION "TIFF Library and Utilities"
URL "http://www.remotesensing.org/libtiff"
TYPE OPTIONAL
PURPOSE "Required by the Krita TIFF filter")
find_package(JPEG)
set_package_properties(JPEG PROPERTIES
DESCRIPTION "Free library for JPEG image compression. Note: libjpeg8 is NOT supported."
URL "http://www.libjpeg-turbo.org"
TYPE OPTIONAL
PURPOSE "Required by the Krita JPEG filter")
set(LIBRAW_MIN_VERSION "0.16")
find_package(LibRaw ${LIBRAW_MIN_VERSION})
set_package_properties(LibRaw PROPERTIES
DESCRIPTION "Library to decode RAW images"
URL "http://www.libraw.org"
TYPE OPTIONAL
PURPOSE "Required to build the raw import plugin")
find_package(FFTW3)
set_package_properties(FFTW3 PROPERTIES
DESCRIPTION "A fast, free C FFT library"
URL "http://www.fftw.org/"
TYPE OPTIONAL
PURPOSE "Required by the Krita for fast convolution operators and some G'Mic features")
macro_bool_to_01(FFTW3_FOUND HAVE_FFTW3)
find_package(OCIO)
set_package_properties(OCIO PROPERTIES
DESCRIPTION "The OpenColorIO Library"
URL "http://www.opencolorio.org"
TYPE OPTIONAL
PURPOSE "Required by the Krita LUT docker")
macro_bool_to_01(OCIO_FOUND HAVE_OCIO)
##
## Look for OpenGL
##
# TODO: see if there is a better check for QtGui being built with opengl support (and thus the QOpenGL* classes)
if(Qt5Gui_OPENGL_IMPLEMENTATION)
message(STATUS "Found QtGui OpenGL support")
else()
message(FATAL_ERROR "Did NOT find QtGui OpenGL support. Check your Qt configuration. You cannot build Krita without Qt OpenGL support.")
endif()
##
## Test for eigen3
##
find_package(Eigen3 REQUIRED "3.0")
set_package_properties(Eigen3 PROPERTIES
DESCRIPTION "C++ template library for linear algebra"
URL "http://eigen.tuxfamily.org"
TYPE REQUIRED)
##
## Test for exiv2
##
set(EXIV2_MIN_VERSION "0.16")
find_package(Exiv2 REQUIRED)
set_package_properties(Exiv2 PROPERTIES
DESCRIPTION "Image metadata library and tools"
URL "http://www.exiv2.org"
PURPOSE "Required by Krita")
##
## Test for lcms
##
find_package(LCMS2 REQUIRED "2.4")
set_package_properties(LCMS2 PROPERTIES
DESCRIPTION "LittleCMS Color management engine"
URL "http://www.littlecms.com"
TYPE REQUIRED
PURPOSE "Will be used for color management and is necessary for Krita")
if(LCMS2_FOUND)
if(NOT ${LCMS2_VERSION} VERSION_LESS 2040 )
set(HAVE_LCMS24 TRUE)
endif()
set(HAVE_REQUIRED_LCMS_VERSION TRUE)
set(HAVE_LCMS2 TRUE)
endif()
##
## Test for Vc
##
set(OLD_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} )
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
set(HAVE_VC FALSE)
if( NOT MSVC)
find_package(Vc 1.1.0)
set_package_properties(Vc PROPERTIES
DESCRIPTION "Portable, zero-overhead SIMD library for C++"
URL "https://github.com/VcDevel/Vc"
TYPE OPTIONAL
PURPOSE "Required by the Krita for vectorization")
macro_bool_to_01(Vc_FOUND HAVE_VC)
macro_bool_to_01(PACKAGERS_BUILD DO_PACKAGERS_BUILD)
endif()
configure_file(config-vc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-vc.h )
if(HAVE_VC)
message(STATUS "Vc found!")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_SOURCE_DIR}/cmake/vc")
include (VcMacros)
if(Vc_COMPILER_IS_CLANG)
set(ADDITIONAL_VC_FLAGS "-Wabi -ffp-contract=fast -fPIC")
elseif (NOT MSVC)
set(ADDITIONAL_VC_FLAGS "-Wabi -fabi-version=0 -ffp-contract=fast -fPIC")
endif()
#Handle Vc master
if(Vc_COMPILER_IS_GCC OR Vc_COMPILER_IS_CLANG)
AddCompilerFlag("-std=c++11" _ok)
if(NOT _ok)
AddCompilerFlag("-std=c++0x" _ok)
endif()
endif()
macro(ko_compile_for_all_implementations_no_scalar _objs _src)
if(PACKAGERS_BUILD)
vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2)
else()
set(${_objs} ${_src})
endif()
endmacro()
macro(ko_compile_for_all_implementations _objs _src)
if(PACKAGERS_BUILD)
vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2)
else()
set(${_objs} ${_src})
endif()
endmacro()
if (NOT PACKAGERS_BUILD)
# Optimize everything for the current architecture
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}")
endif ()
endif()
set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} )
add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS})
if(WIN32)
set(LIB_INSTALL_DIR ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY ${INSTALL_TARGETS_DEFAULT_ARGS}
ARCHIVE ${INSTALL_TARGETS_DEFAULT_ARGS} )
endif()
##
## Test endianess
##
include (TestBigEndian)
test_big_endian(CMAKE_WORDS_BIGENDIAN)
##
## Test for qt-poppler
##
find_package(Poppler)
set_package_properties(Poppler PROPERTIES
DESCRIPTION "A PDF rendering library"
URL "http://poppler.freedesktop.org"
TYPE OPTIONAL
PURPOSE "Required by the Krita PDF filter.")
##
## Test for pthreads (for G'Mic)
##
find_package(Threads)
set_package_properties(Threads PROPERTIES
DESCRIPTION "PThreads - A low-level threading library"
TYPE OPTIONAL
PURPOSE "Optionally used by the G'Mic plugin")
##
## Test for OpenMP (for G'Mic)
##
find_package(OpenMP)
set_package_properties(OpenMP PROPERTIES
DESCRIPTION "A low-level parallel execution library"
URL "http://openmp.org/wp/"
TYPE OPTIONAL
PURPOSE "Optionally used by the G'Mic plugin")
##
## Test for Curl (for G'Mic)
##
find_package(CURL)
set_package_properties(CURL PROPERTIES
DESCRIPTION "A tool to fetch remote data"
URL "http://curl.haxx.se/"
TYPE OPTIONAL
PURPOSE "Optionally used by the G'Mic plugin")
############################
#############################
## Add Krita helper macros ##
#############################
############################
include(MacroKritaAddBenchmark)
####################
#####################
## Define includes ##
#####################
####################
# for config.h and includes (if any?)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/interfaces
)
add_subdirectory(libs)
add_subdirectory(plugins)
add_subdirectory(benchmarks)
add_subdirectory(krita)
configure_file(KoConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/KoConfig.h )
configure_file(config_convolution.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_convolution.h)
configure_file(config-ocio.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ocio.h )
check_function_exists(powf HAVE_POWF)
configure_file(config-powf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-powf.h)
message("\nBroken tests:")
foreach(tst ${KRITA_BROKEN_TESTS})
message(" * ${tst}")
endforeach()
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/config-qtmultimedia.h.cmake b/config-qtmultimedia.h.cmake
new file mode 100644
index 0000000000..ca655089f5
--- /dev/null
+++ b/config-qtmultimedia.h.cmake
@@ -0,0 +1,4 @@
+/* config-qtmultimedia.h. Generated by cmake from config-gsl.h.cmake */
+
+/* Defines if you have Qt Multimedia component */
+#cmakedefine HAVE_QT_MULTIMEDIA 1
diff --git a/krita/data/kritarc b/krita/data/kritarc
index fd0cb3e373..e4685bffb3 100644
--- a/krita/data/kritarc
+++ b/krita/data/kritarc
@@ -1,467 +1,469 @@
ArtColorSel.ColorSpace=0
ArtColorSel.InversedSaturation=false
ArtColorSel.Light=0.5
ArtColorSel.LightPieces=19
ArtColorSel.NumRings=11
ArtColorSel.RelativeLight=false
ArtColorSel.RingAngles=0,0,0,0,0,0,0,0,0,0,0
ArtColorSel.RingPieces=12
ArtColorSel.SelColorA=1
ArtColorSel.SelColorH=0
ArtColorSel.SelColorS=0
ArtColorSel.SelColorX=0.5
BackgroundColorForNewImage=255,255,255
BackgroundOpacityForNewImage=255
BackgroundStyleForNewImage=0
Krita/Ocio/OcioColorManagementMode=0
Krita/Ocio/OcioLockColorVisualRepresentation=false
Krita/Ocio/UseOcio=false
LastBackGroundColor=\n\n \n \n
LastForeGroundColor=\n\n \n \n
LastPreset=Basic_circle
LastPreset_-1=Basic_circle
LineSmoothingDelayDistance=50
LineSmoothingDistance=50
LineSmoothingFinishStabilizedCurve=true
LineSmoothingStabilizeSensors=true
LineSmoothingTailAggressiveness=0.14999999999999999
LineSmoothingType=1
LineSmoothingUseDelayDistance=true
NumberOfLayersForNewImage=2
PaintopPopupDetached=false
SpecificColorSelector/ShowColorSpaceSelector=false
baseLength=50
colorDepthDef=U8
colorModelDef=RGBA
colorProfileDef=sRGB-elle-V2-srgbtrc.icc
favoritePresetsTag=demo
globalSnapBoundingBox=false
globalSnapExtension=false
globalSnapImageBounds=true
globalSnapImageCenter=true
globalSnapIntersection=false
globalSnapNode=false
globalSnapOrthogonal=false
gridmaincolor=99,99,99
gridmainstyle=0
gridsubdivisioncolor=150,150,150
gridsubdivisionstyle=1
guidesColor=99,99,99
guidesLineStyle=0
imageHeightDef=1200
imageResolutionDef=300
imageWidthDef=1600
levelOfDetailEnabled=true
numberOfOnionSkins=10
oninSkinTintColorForward=0,255,0
onionSkinOpacity_-1=173
onionSkinOpacity_-10=22
onionSkinOpacity_-2=163
onionSkinOpacity_-3=147
onionSkinOpacity_-4=127
onionSkinOpacity_-5=107
onionSkinOpacity_-6=84
onionSkinOpacity_-7=63
onionSkinOpacity_-8=48
onionSkinOpacity_-9=33
onionSkinOpacity_0=175
onionSkinOpacity_1=173
onionSkinOpacity_10=22
onionSkinOpacity_2=163
onionSkinOpacity_3=147
onionSkinOpacity_4=127
onionSkinOpacity_5=107
onionSkinOpacity_6=84
onionSkinOpacity_7=63
onionSkinOpacity_8=48
onionSkinOpacity_9=33
onionSkinState_-1=true
onionSkinState_-10=false
onionSkinState_-2=true
onionSkinState_-3=false
onionSkinState_-4=false
onionSkinState_-5=false
onionSkinState_-6=false
onionSkinState_-7=false
onionSkinState_-8=false
onionSkinState_-9=false
onionSkinState_0=true
onionSkinState_1=true
onionSkinState_10=false
onionSkinState_2=true
onionSkinState_3=false
onionSkinState_4=false
onionSkinState_5=false
onionSkinState_6=false
onionSkinState_7=false
onionSkinState_8=false
onionSkinState_9=false
onionSkinTintColorBackward=255,0,0
onionSkinTintFactor=191
presethistory=Basic_tip_default
showAdditionalOnionSkinsSettings=true
toolbarslider_1=opacity
toolbarslider_2=size
toolbarslider_3=flow
[advancedColorSelector]
allowHorizontalLayout=true
colorSelectorConfiguration=3|0|5|0
commonColorsAlignment=false
commonColorsAutoUpdate=false
commonColorsCount=12
commonColorsHeight=16
commonColorsNumCols=1
commonColorsNumRows=1
commonColorsScrolling=false
commonColorsShow=true
commonColorsWidth=16
customColorSpaceDepthID=U8
customColorSpaceModel=RGBA
customColorSpaceProfile=sRGB built-in
lastUsedColorsAlignment=true
lastUsedColorsCount=20
lastUsedColorsHeight=16
lastUsedColorsNumCols=1
lastUsedColorsNumRows=1
lastUsedColorsScrolling=true
lastUsedColorsShow=true
lastUsedColorsWidth=16
minimalShadeSelectorAsGradient=true
minimalShadeSelectorLineConfig=0|0.2|0|0|0|0|0;1|0|1|1|0|0|0;2|0|-1|1|0|0|0;
minimalShadeSelectorLineHeight=10
minimalShadeSelectorPatchCount=10
popupOnMouseClick=true
popupOnMouseOver=false
shadeSelectorHideable=false
shadeSelectorType=Minimal
shadeSelectorUpdateOnBackground=true
shadeSelectorUpdateOnForeground=true
shadeSelectorUpdateOnLeftClick=false
shadeSelectorUpdateOnRightClick=false
useCustomColorSpace=false
zoomSize=280
[DockWidget sharedtooldocker]
TabbedMode=false
[KisToolTransform]
filterId=Bicubic
[MainWindow]
Height 1080=720
Width 1920=1256
ko_geometry=AdnQywACAAAAAAE6AAAAtAAABikAAAOkAAABPgAAANEAAAYlAAADoAAAAAAAAAAAB4A=
ko_windowstate=AAAA/wAAAAD9AAAABAAAAAAAAAA/AAACdvwCAAAAA/sAAAAOAFQAbwBvAGwAQgBvAHgBAAAAPAAAAnYAAAAVAP////sAAAAkAEYAbABvAHcAUwBoAGEAcABlAEIAbwB4AEQAbwBjAGsAZQByAAAAA2oAAADHAAAAAAAAAAD7AAAAKABGAGwAbwB3AFMAdABlAG4AYwBpAGwAQgBvAHgARABvAGMAawBlAHIAAAADfQAAAMcAAAAAAAAAAAAAAAEAAAEZAAACdvwCAAAAOvsAAAAaAEsAaQBzAEIAaQByAGQAZQB5AGUAQgBvAHgAAAAAAP////8AAAAAAAAAAPsAAAAgAEsAaQBzAFAAYQBsAGUAdAB0AGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAaAEsAbwBDAG8AbABvAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAwAEsAaQBzAFQAcgBpAGEAbgBnAGwAZQBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAAAAAAAD7AAAAIgBTAGgAYQBkAG8AdwAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAgAFMAaABhAHAAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAUAP////sAAAAaAFMAaABhAHAAZQBTAGUAbABlAGMAdABvAHIAAAAASAAAAEQAAAAAAAAAAPsAAAAkAFMAaQBtAHAAbABlACAAVABlAHgAdAAgAEUAZABpAHQAbwByAAAAAAD/////AAAAAAAAAAD8AAAAPAAAAN0AAACkAQAAGPoAAAAAAQAAAAX7AAAAHgBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAE4AZwEAAAAA/////wAAANUA////+wAAACoAUwBwAGUAYwBpAGYAaQBjAEMAbwBsAG8AcgBTAGUAbABlAGMAdABvAHIBAAAAAP////8AAADKAP////sAAAAWAEMAbwBsAG8AcgBTAGwAaQBkAGUAcgEAAAAA/////wAAAJMA////+wAAABYASQBtAGEAZwBlAEQAbwBjAGsAZQByAAAAAAD/////AAAAwAD////7AAAAKgBTAGgAYQBwAGUAQwBvAGwAbABlAGMAdABpAG8AbgBEAG8AYwBrAGUAcgAAAAZIAAABKAAAAIkAAACJ+wAAAEYASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwARAB5AG4AYQBvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAFIAAAASAAAAAAAAAAD7AAAALABLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABMAGkAbgBlAQAAADwAAABpAAAAAAAAAAD7AAAAMgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABFAGwAbABpAHAAcwBlAQAAAJEAAAASAAAAAAAAAAD7AAAAHABLAGkAcwBUAG8AbwBsAFAAbwBsAHkAZwBvAG4BAAAApgAAABIAAAAAAAAAAPsAAAAeAEsAaQBzAFQAbwBvAGwAUABvAGwAeQBsAGkAbgBlAQAAALsAAAASAAAAAAAAAAD7AAAAFgBLAGkAcwBUAG8AbwBsAFMAdABhAHIBAAAA0AAAABMAAAAAAAAAAPsAAAAqAFMAbgBhAHAARwB1AGkAZABlAEMAbwBuAGYAaQBnAFcAaQBkAGcAZQB0AAAAAO8AAABxAAAAAAAAAAD7AAAAMgBLAGkAcwBUAG8AbwBsAEMAcgBvAHAAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAPsAAAASAAAAAAAAAAD7AAAAUABLAHIAaQB0AGEAVAByAGEAbgBzAGYAbwByAG0ALwBLAGkAcwBUAG8AbwBsAE0AbwB2AGUAIABPAHAAdABpAG8AbgAgAFcAaQBkAGcAZQB0AQAAARAAAAASAAAAAAAAAAD7AAAAPABLAGkAcwBUAG8AbwBsAFQAcgBhAG4AcwBmAG8AcgBtACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAALwAAAAAAAAAA+wAAAE4ASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwATQBlAGEAcwB1AHIAZQAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAPAAAAEIAAAAAAAAAAPsAAABcAEsAcgBpAHQAYQBTAGUAbABlAGMAdABlAGQALwBLAGkAcwBUAG8AbwBsAEMAbwBsAG8AcgBQAGkAYwBrAGUAcgAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAPAAAAP8AAAAAAAAAAPsAAABGAEsAaQBzAFIAdQBsAGUAcgBBAHMAcwBpAHMAdABhAG4AdABUAG8AbwBsACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAA8AAAAEgAAAAAAAAAA+wAAAEgASwBpAHMAVABvAG8AbABQAGUAcgBzAHAAZQBjAHQAaQB2AGUARwByAGkAZAAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABowAAABIAAAAAAAAAAPsAAAAyAEsAaQBzAFQAbwBvAGwARwByAGkAZAAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABuAAAABMAAAAAAAAAAPsAAABMAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAUgBlAGMAdABhAG4AZwB1AGwAYQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAHOAAAAEgAAAAAAAAAA+wAAAEoASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABFAGwAbABpAHAAdABpAGMAYQBsACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAHjAAAAEgAAAAAAAAAA+wAAAEgASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABQAG8AbAB5AGcAbwBuAGEAbAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAB+AAAABIAAAAAAAAAAPsAAABEAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQATwB1AHQAbABpAG4AZQAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACDQAAABIAAAAAAAAAAPsAAABKAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAQwBvAG4AdABpAGcAdQBvAHUAcwAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACIgAAABIAAAAAAAAAAPsAAABEAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAUwBpAG0AaQBsAGEAcgAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACNwAAABIAAAAAAAAAAPwAAAG2AAAAWgAAAAAA////+gAAAAABAAAAAvsAAAAuAEsAbwBTAGgAYQBwAGUAQwBvAGwAbABlAGMAdABpAG8AbgBEAG8AYwBrAGUAcgEAAAAA/////wAAAAAAAAAA+wAAACQAUwBtAGEAbABsAEMAbwBsAG8AcgBTAGUAbABlAGMAdABvAHIAAAADbgAAAQQAAAC9AP////wAAAEfAAABkwAAAL4BAAAY+gAAAAABAAAABfsAAAAWAEsAaQBzAEwAYQB5AGUAcgBCAG8AeAEAAAAA/////wAAAQIA////+wAAABoAQwBoAGEAbgBuAGUAbABEAG8AYwBrAGUAcgAAAAAA/////wAAAIEA////+wAAABgAUAByAGUAcwBlAHQARABvAGMAawBlAHIBAAAAAP////8AAACaAP////sAAAAgAHMAaABhAHIAZQBkAHQAbwBvAGwAZABvAGMAawBlAHIBAAAAAP////8AAACBAP////sAAAAuAEsAaQBzAFAAYQBpAG4AdABlAHIAbAB5AE0AaQB4AGUAcgBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAAEgASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwAQgByAHUAcwBoAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAD3AAAAGgAAAAAAAAAAPsAAAAiAFMAdAByAG8AawBlACAAUAByAG8AcABlAHIAdABpAGUAcwAAAAAA/////wAAAAAAAAAA+wAAABYAUwB0AHkAbABlAEQAbwBjAGsAZQByAAAAAAD/////AAAAAAAAAAD7AAAAIABLAGkAcwBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAAAAAAD/////AAAAAAAAAAD7AAAAEgBTAGMAcgBpAHAAdABpAG4AZwAAAAAA/////wAAAAAAAAAA+wAAADAARABlAGYAYQB1AGwAdABUAG8AbwBsAEEAcgByAGEAbgBnAGUAVwBpAGQAZwBlAHQAAAACvAAAAFIAAAAAAAAAAPsAAAAiAEQAZQBmAGEAdQBsAHQAVABvAG8AbABXAGkAZABnAGUAdAAAAAMRAAAAWwAAAAAAAAAA+wAAACQASwBpAHMASABpAHMAdABvAGcAcgBhAG0ARABvAGMAawBlAHIAAAACQgAAAHsAAAAAAAAAAPsAAAAYAEQAaQBnAGkAdABhAGwATQBpAHgAZQByAAAAAAD/////AAAAkQD////7AAAADgBIAGkAcwB0AG8AcgB5AAAAA5AAAAC0AAAAWgD////7AAAATgBLAHIAaQB0AGEARgBpAGwAbAAvAEsAaQBzAFQAbwBvAGwARwByAGEAZABpAGUAbgB0ACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAAAAAQoAAAAHAAAAAAAAAAA+wAAAEYASwByAGkAdABhAEYAaQBsAGwALwBLAGkAcwBUAG8AbwBsAEYAaQBsAGwAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AAAAA1AAAAAcAAAAAAAAAAD7AAAANgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABSAGUAYwB0AGEAbgBnAGwAZQAAAAMFAAAAZwAAAAAAAAAA+wAAACIAQwBvAG0AcABvAHMAaQB0AGkAbwBuAEQAbwBjAGsAZQByAAAAAAD/////AAAAegD////7AAAAKgBBAHIAdABpAHMAdABpAGMAQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgAAAAAA/////wAAAHgA////+wAAABoAUABhAHQAdABlAHIAbgBEAG8AYwBrAGUAcgAAAALZAAABSQAAAT8A////+wAAABoAVABhAHMAawBzAGUAdABEAG8AYwBrAGUAcgAAAAAA/////wAAAHoA////+wAAACgAUwBuAGEAcABHAHUAaQBkAGUAIABQAHIAbwBwAGUAcgB0AGkAZQBzAAAAAAD/////AAAAAAAAAAD7AAAAOABUAGUAeAB0AEQAbwBjAHUAbQBlAG4AdABJAG4AcwBwAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAgAABJoAAAIVAAABKgAAAK77AAAAEgBMAHUAdABEAG8AYwBrAGUAcgAAAAAA/////wAAATkA////+wAAABwATwB2AGUAcgB2AGkAZQB3AEQAbwBjAGsAZQByAAAAAAD/////AAAASAD////7AAAAGgBQAGEAbABlAHQAdABlAEQAbwBjAGsAZQByAAAAAAD/////AAAAPwD////7AAAAGgBQAHIAZQBzAGUAdABIAGkAcwB0AG8AcgB5AAAAAAD/////AAAAWgD////7AAAAFABHAHIAaQBkAEQAbwBjAGsAZQByAAAAAAD/////AAABLgD////7AAAAHgBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAAA/////wAAAEgA////+wAAACoAQQBuAGkAbQBhAHQAaQBvAG4AQwB1AHIAdgBlAHMARABvAGMAawBlAHIAAAAAAP////8AAAB5AP///wAAAAIAAAeAAAAAvPwBAAAAAfsAAAAaAFQAbwBvAGwAQgBhAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAAAAAAMAAAAAAAAAAPwBAAAABPsAAAAcAEYAbABpAHAAYgBvAG8AawBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAAB4AQQBuAGkAbQBhAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAAELAP////sAAAAgAE8AbgBpAG8AbgBTAGsAaQBuAHMARABvAGMAawBlAHIAAAAAAP////8AAAEtAP////sAAAAcAFQAaQBtAGUAbABpAG4AZQBEAG8AYwBrAGUAcgAAAAAA/////wAAAH0A////AAADhAAAAnYAAAAEAAAABAAAAAgAAAAI/AAAAAEAAAACAAAAAgAAABYAbQBhAGkAbgBUAG8AbwBsAEIAYQByAAAAAAD/////AAAAAAAAAAAAAAAeAEIAcgB1AHMAaABlAHMAQQBuAGQAUwB0AHUAZgBmAQAAAAD/////AAAAAAAAAAA=
[advancedColorSelector]
gamma=2.2000000000000002
hidePopupOnClickCheck=false
hsxSettingType=0
lumaB=0.0722
lumaG=0.71519999999999995
lumaR=0.21260000000000001
onDockerResize=0
shadeMyPaintType=HSV
zoomSelectorOptions=0
[calligra]
ColorSpaceExtensionsPlugins=\\0
ColorSpaceExtensionsPluginsDisabled=
ColorSpacePlugins=\\0
ColorSpacePluginsDisabled=
DockerPlugins=\\0
DockerPluginsDisabled=textdocumentinspection
FlakePlugins=,
ShapePlugins=,
ToolsBlacklist=CreatePathTool,KoPencilTool,ConnectionTool,KarbonFilterEffectsTool
ToolPlugins=,,
ToolPluginsDisabled=
[KoShapeCollection]
QuickShapes=ArtisticText,TextShapeID,EllipseShape,RectangleShape
[colorhotkeys]
steps_blueyellow=10
steps_hue=36
steps_lightness=10
steps_redgreen=10
steps_saturation=10
[crashprevention]
CreatingCanvas=false
[hsxColorSlider]
hsiH=false
hsiI=false
hsiS=false
hslH=true
hslL=true
hslS=true
hsvH=false
hsvS=false
hsvV=false
hsyH=false
hsyS=false
hsyY=false
[krita]
State=AAAA/wAAAAD9AAAABAAAAAAAAAA/AAACdvwCAAAAA/sAAAAOAFQAbwBvAGwAQgBvAHgBAAAAPAAAAnYAAAAVAP////sAAAAkAEYAbABvAHcAUwBoAGEAcABlAEIAbwB4AEQAbwBjAGsAZQByAAAAA2oAAADHAAAAAAAAAAD7AAAAKABGAGwAbwB3AFMAdABlAG4AYwBpAGwAQgBvAHgARABvAGMAawBlAHIAAAADfQAAAMcAAAAAAAAAAAAAAAEAAAEZAAACdvwCAAAAOvsAAAAaAEsAaQBzAEIAaQByAGQAZQB5AGUAQgBvAHgAAAAAAP////8AAAAAAAAAAPsAAAAgAEsAaQBzAFAAYQBsAGUAdAB0AGUARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAaAEsAbwBDAG8AbABvAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAPsAAAAwAEsAaQBzAFQAcgBpAGEAbgBnAGwAZQBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAAAAAAD/////AAAAAAAAAAD7AAAAIgBTAGgAYQBkAG8AdwAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAAAAAAAPsAAAAgAFMAaABhAHAAZQAgAFAAcgBvAHAAZQByAHQAaQBlAHMAAAAAAP////8AAAAUAP////sAAAAaAFMAaABhAHAAZQBTAGUAbABlAGMAdABvAHIAAAAASAAAAEQAAAAAAAAAAPsAAAAkAFMAaQBtAHAAbABlACAAVABlAHgAdAAgAEUAZABpAHQAbwByAAAAAAD/////AAAAAAAAAAD8AAAAPAAAAN0AAACkAQAAGPoAAAAAAQAAAAX7AAAAHgBDAG8AbABvAHIAUwBlAGwAZQBjAHQAbwByAE4AZwEAAAAA/////wAAANUA////+wAAACoAUwBwAGUAYwBpAGYAaQBjAEMAbwBsAG8AcgBTAGUAbABlAGMAdABvAHIBAAAAAP////8AAADKAP////sAAAAWAEMAbwBsAG8AcgBTAGwAaQBkAGUAcgEAAAAA/////wAAAJMA////+wAAABYASQBtAGEAZwBlAEQAbwBjAGsAZQByAAAAAAD/////AAAAwAD////7AAAAKgBTAGgAYQBwAGUAQwBvAGwAbABlAGMAdABpAG8AbgBEAG8AYwBrAGUAcgAAAAZIAAABKAAAAIkAAACJ+wAAAEYASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwARAB5AG4AYQBvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAFIAAAASAAAAAAAAAAD7AAAALABLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABMAGkAbgBlAQAAADwAAABpAAAAAAAAAAD7AAAAMgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABFAGwAbABpAHAAcwBlAQAAAJEAAAASAAAAAAAAAAD7AAAAHABLAGkAcwBUAG8AbwBsAFAAbwBsAHkAZwBvAG4BAAAApgAAABIAAAAAAAAAAPsAAAAeAEsAaQBzAFQAbwBvAGwAUABvAGwAeQBsAGkAbgBlAQAAALsAAAASAAAAAAAAAAD7AAAAFgBLAGkAcwBUAG8AbwBsAFMAdABhAHIBAAAA0AAAABMAAAAAAAAAAPsAAAAqAFMAbgBhAHAARwB1AGkAZABlAEMAbwBuAGYAaQBnAFcAaQBkAGcAZQB0AAAAAO8AAABxAAAAAAAAAAD7AAAAMgBLAGkAcwBUAG8AbwBsAEMAcgBvAHAAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AQAAAPsAAAASAAAAAAAAAAD7AAAAUABLAHIAaQB0AGEAVAByAGEAbgBzAGYAbwByAG0ALwBLAGkAcwBUAG8AbwBsAE0AbwB2AGUAIABPAHAAdABpAG8AbgAgAFcAaQBkAGcAZQB0AQAAARAAAAASAAAAAAAAAAD7AAAAPABLAGkAcwBUAG8AbwBsAFQAcgBhAG4AcwBmAG8AcgBtACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAA8AAAALwAAAAAAAAAA+wAAAE4ASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwATQBlAGEAcwB1AHIAZQAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAPAAAAEIAAAAAAAAAAPsAAABcAEsAcgBpAHQAYQBTAGUAbABlAGMAdABlAGQALwBLAGkAcwBUAG8AbwBsAEMAbwBsAG8AcgBQAGkAYwBrAGUAcgAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAAPAAAAP8AAAAAAAAAAPsAAABGAEsAaQBzAFIAdQBsAGUAcgBBAHMAcwBpAHMAdABhAG4AdABUAG8AbwBsACAATwBwAHQAaQBvAG4AIABXAGkAZABnAGUAdAEAAAA8AAAAEgAAAAAAAAAA+wAAAEgASwBpAHMAVABvAG8AbABQAGUAcgBzAHAAZQBjAHQAaQB2AGUARwByAGkAZAAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABowAAABIAAAAAAAAAAPsAAAAyAEsAaQBzAFQAbwBvAGwARwByAGkAZAAgAE8AcAB0AGkAbwBuACAAVwBpAGQAZwBlAHQBAAABuAAAABMAAAAAAAAAAPsAAABMAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAUgBlAGMAdABhAG4AZwB1AGwAYQByACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAHOAAAAEgAAAAAAAAAA+wAAAEoASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABFAGwAbABpAHAAdABpAGMAYQBsACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAEAAAHjAAAAEgAAAAAAAAAA+wAAAEgASwBpAHMAVABvAG8AbABTAGUAbABlAGMAdABQAG8AbAB5AGcAbwBuAGEAbAAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAB+AAAABIAAAAAAAAAAPsAAABEAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQATwB1AHQAbABpAG4AZQAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACDQAAABIAAAAAAAAAAPsAAABKAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAQwBvAG4AdABpAGcAdQBvAHUAcwAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACIgAAABIAAAAAAAAAAPsAAABEAEsAaQBzAFQAbwBvAGwAUwBlAGwAZQBjAHQAUwBpAG0AaQBsAGEAcgAgAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAACNwAAABIAAAAAAAAAAPwAAAG2AAAAWgAAAAAA////+gAAAAABAAAAAvsAAAAuAEsAbwBTAGgAYQBwAGUAQwBvAGwAbABlAGMAdABpAG8AbgBEAG8AYwBrAGUAcgEAAAAA/////wAAAAAAAAAA+wAAACQAUwBtAGEAbABsAEMAbwBsAG8AcgBTAGUAbABlAGMAdABvAHIAAAADbgAAAQQAAAC9AP////wAAAEfAAABkwAAAL4BAAAY+gAAAAABAAAABfsAAAAWAEsAaQBzAEwAYQB5AGUAcgBCAG8AeAEAAAAA/////wAAAQIA////+wAAABoAQwBoAGEAbgBuAGUAbABEAG8AYwBrAGUAcgAAAAAA/////wAAAIEA////+wAAABgAUAByAGUAcwBlAHQARABvAGMAawBlAHIBAAAAAP////8AAACaAP////sAAAAgAHMAaABhAHIAZQBkAHQAbwBvAGwAZABvAGMAawBlAHIBAAAAAP////8AAACBAP////sAAAAuAEsAaQBzAFAAYQBpAG4AdABlAHIAbAB5AE0AaQB4AGUAcgBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAAEgASwByAGkAdABhAFMAaABhAHAAZQAvAEsAaQBzAFQAbwBvAGwAQgByAHUAcwBoAG8AcAB0AGkAbwBuACAAdwBpAGQAZwBlAHQBAAAD3AAAAGgAAAAAAAAAAPsAAAAiAFMAdAByAG8AawBlACAAUAByAG8AcABlAHIAdABpAGUAcwAAAAAA/////wAAAAAAAAAA+wAAABYAUwB0AHkAbABlAEQAbwBjAGsAZQByAAAAAAD/////AAAAAAAAAAD7AAAAIABLAGkAcwBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAAAAAAD/////AAAAAAAAAAD7AAAAEgBTAGMAcgBpAHAAdABpAG4AZwAAAAAA/////wAAAAAAAAAA+wAAADAARABlAGYAYQB1AGwAdABUAG8AbwBsAEEAcgByAGEAbgBnAGUAVwBpAGQAZwBlAHQAAAACvAAAAFIAAAAAAAAAAPsAAAAiAEQAZQBmAGEAdQBsAHQAVABvAG8AbABXAGkAZABnAGUAdAAAAAMRAAAAWwAAAAAAAAAA+wAAACQASwBpAHMASABpAHMAdABvAGcAcgBhAG0ARABvAGMAawBlAHIAAAACQgAAAHsAAAAAAAAAAPsAAAAYAEQAaQBnAGkAdABhAGwATQBpAHgAZQByAAAAAAD/////AAAAkQD////7AAAADgBIAGkAcwB0AG8AcgB5AAAAA5AAAAC0AAAAWgD////7AAAATgBLAHIAaQB0AGEARgBpAGwAbAAvAEsAaQBzAFQAbwBvAGwARwByAGEAZABpAGUAbgB0ACAAbwBwAHQAaQBvAG4AIAB3AGkAZABnAGUAdAAAAAQoAAAAHAAAAAAAAAAA+wAAAEYASwByAGkAdABhAEYAaQBsAGwALwBLAGkAcwBUAG8AbwBsAEYAaQBsAGwAIABvAHAAdABpAG8AbgAgAHcAaQBkAGcAZQB0AAAAA1AAAAAcAAAAAAAAAAD7AAAANgBLAHIAaQB0AGEAUwBoAGEAcABlAC8ASwBpAHMAVABvAG8AbABSAGUAYwB0AGEAbgBnAGwAZQAAAAMFAAAAZwAAAAAAAAAA+wAAACIAQwBvAG0AcABvAHMAaQB0AGkAbwBuAEQAbwBjAGsAZQByAAAAAAD/////AAAAegD////7AAAAKgBBAHIAdABpAHMAdABpAGMAQwBvAGwAbwByAFMAZQBsAGUAYwB0AG8AcgAAAAAA/////wAAAHgA////+wAAABoAUABhAHQAdABlAHIAbgBEAG8AYwBrAGUAcgAAAALZAAABSQAAAT8A////+wAAABoAVABhAHMAawBzAGUAdABEAG8AYwBrAGUAcgAAAAAA/////wAAAHoA////+wAAACgAUwBuAGEAcABHAHUAaQBkAGUAIABQAHIAbwBwAGUAcgB0AGkAZQBzAAAAAAD/////AAAAAAAAAAD7AAAAOABUAGUAeAB0AEQAbwBjAHUAbQBlAG4AdABJAG4AcwBwAGUAYwB0AGkAbwBuAEQAbwBjAGsAZQByAgAABJoAAAIVAAABKgAAAK77AAAAEgBMAHUAdABEAG8AYwBrAGUAcgAAAAAA/////wAAATkA////+wAAABwATwB2AGUAcgB2AGkAZQB3AEQAbwBjAGsAZQByAAAAAAD/////AAAASAD////7AAAAGgBQAGEAbABlAHQAdABlAEQAbwBjAGsAZQByAAAAAAD/////AAAAPwD////7AAAAGgBQAHIAZQBzAGUAdABIAGkAcwB0AG8AcgB5AAAAAAD/////AAAAWgD////7AAAAFABHAHIAaQBkAEQAbwBjAGsAZQByAAAAAAD/////AAABLgD////7AAAAHgBIAGkAcwB0AG8AZwByAGEAbQBEAG8AYwBrAGUAcgAAAAAA/////wAAAEgA////+wAAACoAQQBuAGkAbQBhAHQAaQBvAG4AQwB1AHIAdgBlAHMARABvAGMAawBlAHIAAAAAAP////8AAAB5AP///wAAAAIAAAeAAAAAvPwBAAAAAfsAAAAaAFQAbwBvAGwAQgBhAHIARABvAGMAawBlAHIAAAAAAP////8AAAAAAAAAAAAAAAMAAAAAAAAAAPwBAAAABPsAAAAcAEYAbABpAHAAYgBvAG8AawBEAG8AYwBrAGUAcgAAAAAA/////wAAAAAAAAAA+wAAAB4AQQBuAGkAbQBhAHQAaQBvAG4ARABvAGMAawBlAHIAAAAAAP////8AAAELAP////sAAAAgAE8AbgBpAG8AbgBTAGsAaQBuAHMARABvAGMAawBlAHIAAAAAAP////8AAAEtAP////sAAAAcAFQAaQBtAGUAbABpAG4AZQBEAG8AYwBrAGUAcgAAAAAA/////wAAAH0A////AAADhAAAAnYAAAAEAAAABAAAAAgAAAAI/AAAAAEAAAACAAAAAgAAABYAbQBhAGkAbgBUAG8AbwBsAEIAYQByAAAAAAD/////AAAAAAAAAAAAAAAeAEIAcgB1AHMAaABlAHMAQQBuAGQAUwB0AHUAZgBmAQAAAAD/////AAAAAAAAAAA=
ToolBarsMovable=Disabled
[krita][DockWidget AnimationCurvesDocker]
Collapsed=false
DockArea=2
Locked=false
height=421
width=448
xPosition=0
yPosition=0
[krita][DockWidget AnimationDocker]
Collapsed=false
DockArea=8
Locked=false
height=160
width=280
xPosition=0
yPosition=0
[krita][DockWidget ArtisticColorSelector]
Collapsed=false
DockArea=2
Locked=false
height=294
width=337
xPosition=0
yPosition=0
[krita][DockWidget ChannelDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ColorSelectorNg]
Collapsed=false
DockArea=2
Locked=false
height=176
width=281
xPosition=0
yPosition=20
[krita][DockWidget ColorSlider]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget CompositionDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget DigitalMixer]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget GridDocker]
Collapsed=false
DockArea=2
Locked=false
height=342
width=441
xPosition=0
yPosition=0
[krita][DockWidget HistogramDocker]
Collapsed=false
DockArea=2
Locked=false
height=91
width=281
xPosition=0
yPosition=20
[krita][DockWidget History]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget ImageDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=399
xPosition=0
yPosition=0
[krita][DockWidget KisLayerBox]
DockArea=2
Locked=false
height=358
width=281
xPosition=0
yPosition=20
[krita][DockWidget LutDocker]
Collapsed=false
DockArea=2
Locked=false
height=286
width=357
xPosition=0
yPosition=0
[krita][DockWidget OnionSkinsDocker]
Collapsed=false
DockArea=8
Locked=false
height=210
width=356
xPosition=0
yPosition=0
[krita][DockWidget OverviewDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PaletteDocker]
Collapsed=false
DockArea=2
Locked=false
height=219
width=256
xPosition=0
yPosition=0
[krita][DockWidget PatternDocker]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget PresetDocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget PresetHistory]
Collapsed=false
DockArea=2
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget Shape Properties]
DockArea=2
Locked=false
height=480
width=640
xPosition=0
yPosition=0
[krita][DockWidget ShapeCollectionDocker]
Collapsed=false
DockArea=2
Locked=false
height=0
width=0
xPosition=0
yPosition=20
[krita][DockWidget SmallColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget SpecificColorSelector]
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][DockWidget TasksetDocker]
Collapsed=false
DockArea=2
Locked=false
height=300
width=400
xPosition=0
yPosition=0
[krita][DockWidget TimelineDocker]
Collapsed=false
DockArea=8
Locked=false
height=30
width=100
xPosition=0
yPosition=0
[krita][DockWidget ToolBox]
DockArea=1
Locked=false
height=610
width=63
xPosition=0
yPosition=20
[krita][DockWidget sharedtooldocker]
Collapsed=false
DockArea=2
Locked=false
height=460
width=640
xPosition=0
yPosition=20
[krita][Toolbar mainToolBar]
ToolButtonStyle=IconOnly
[TemplateChooserDialog]
ShowCustomDocumentWidgetByDefault=true
LastReturnType=Custom Document
[theme]
Theme=Krita dark
+
+favoriteCompositeOps=normal,erase,multiply,burn,darken,add,dodge,screen,overlay,soft_light_svg,luminize,lighten,saturation,color
diff --git a/krita/data/paintoppresets/kis_paintoppresets_tags.xml b/krita/data/paintoppresets/kis_paintoppresets_tags.xml
index 9ea6708fa7..cc7337730a 100644
--- a/krita/data/paintoppresets/kis_paintoppresets_tags.xml
+++ b/krita/data/paintoppresets/kis_paintoppresets_tags.xml
@@ -1,62 +1,227 @@
ink
paint
sketch
sketch
sketch
demo
ink
demo
demo
demo
demo
paint
demo
demo
demo
ink
paint
demo
paint
demo
+
+ Block
+
+
+ Block
+ Wet
+
+
+ Block
+ Mix
+
+
+ FX
+
+
+ Mix
+
+
+ FX
+
+
+ Ink
+
+
+ Erasers
+
+
+ Erasers
+
+
+ Wet
+
+
+ Circle
+
+
+ Ink
+
+
+ Block
+
+
+ Block
+ Smudge
+
+
+ Mix
+
+
+ Circle
+
+
+ Wet
+
+
+ FX
+
+
+ Mix
+
+
+ FX
+
+
+ Circle
+
+
+ Smudge
+
+
+ Block
+
+
+ Mix
+
+
+ Circle
+
+
+ Block
+
+
+ Block
+
+
+ Ink
+
+
+ Wet
+
+
+ Ink
+
+
+ Erasers
+
+
+ Ink
+
+
+ Smudge
+
+
+ Smudge
+
+
+ Block
+
+
+ Ink
+
+
+ Circle
+ Ink
+
+
+ Circle
+ Ink
+
+
+ Wet
+
+
+ Erasers
+
+
+ Erasers
+
+
+ Smudge
+
+
+ Wet
+
+
+ Circle
+
+
+ FX
+
+
+ Ink
+
+
+ Wet
+
+
+ Circle
+
+
+ FX
+
+
+ PixelArt
+
+
+ PixelArt
+
+
+ PixelArt
+
+
+ PixelArt
+
+
diff --git a/krita/pics/svg/dark_audio-none.svg b/krita/pics/svg/dark_audio-none.svg
new file mode 100644
index 0000000000..6b08d8c5e7
--- /dev/null
+++ b/krita/pics/svg/dark_audio-none.svg
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/dark_audio-volume-high.svg b/krita/pics/svg/dark_audio-volume-high.svg
new file mode 100644
index 0000000000..5b9d6cb5b6
--- /dev/null
+++ b/krita/pics/svg/dark_audio-volume-high.svg
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/dark_audio-volume-mute.svg b/krita/pics/svg/dark_audio-volume-mute.svg
new file mode 100644
index 0000000000..315644bb39
--- /dev/null
+++ b/krita/pics/svg/dark_audio-volume-mute.svg
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/light_audio-none.svg b/krita/pics/svg/light_audio-none.svg
new file mode 100644
index 0000000000..00358b4844
--- /dev/null
+++ b/krita/pics/svg/light_audio-none.svg
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/light_audio-volume-high.svg b/krita/pics/svg/light_audio-volume-high.svg
new file mode 100644
index 0000000000..e9a282df99
--- /dev/null
+++ b/krita/pics/svg/light_audio-volume-high.svg
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/light_audio-volume-mute.svg b/krita/pics/svg/light_audio-volume-mute.svg
new file mode 100644
index 0000000000..e1f9c7ba15
--- /dev/null
+++ b/krita/pics/svg/light_audio-volume-mute.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
diff --git a/krita/pics/svg/svg-icons.qrc b/krita/pics/svg/svg-icons.qrc
index c579ff9085..68f4046f84 100644
--- a/krita/pics/svg/svg-icons.qrc
+++ b/krita/pics/svg/svg-icons.qrc
@@ -1,118 +1,124 @@
broken-preset.svgz
dark_addblankframe.svg
dark_addcolor.svg
dark_addduplicateframe.svg
dark_deletekeyframe.svg
dark_docker_lock_a.svg
dark_docker_lock_b.svg
dark_layer-locked.svg
dark_layer-unlocked.svg
dark_nextframe.svg
dark_nextkeyframe.svg
dark_lastframe.svg
dark_prevkeyframe.svg
dark_firstframe.svg
dark_pallete_librarysvg.svg
dark_passthrough-disabled.svg
dark_passthrough-enabled.svg
dark_prevframe.svg
dark_selection-mode_ants.svg
dark_selection-mode_invisible.svg
dark_selection-mode_mask.svg
dark_transparency-disabled.svg
dark_transparency-enabled.svg
dark_trim-to-image.svg
delete.svgz
layer-style-disabled.svg
layer-style-enabled.svg
light_addblankframe.svg
light_addcolor.svg
light_addduplicateframe.svg
light_deletekeyframe.svg
light_docker_lock_a.svg
light_docker_lock_b.svg
light_layer-locked.svg
light_layer-unlocked.svg
light_nextframe.svg
light_pallete_library.svg
light_passthrough-disabled.svgz
light_passthrough-enabled.svgz
light_prevframe.svg
light_nextkeyframe.svg
light_lastframe.svg
light_prevkeyframe.svg
light_firstframe.svg
light_selection-mode_ants.svg
light_selection-mode_invisible.svg
light_selection-mode_mask.svg
light_timeline_keyframe.svg
light_transparency-disabled.svg
light_transparency-enabled.svg
light_trim-to-image.svg
paintop_presets_disabled.svgz
paintop_settings_01.svgz
selection-info.svg
selection-mode_invisible.svg
svg-icons.qrc
transparency-locked.svg
transparency-unlocked.svg
workspace-chooser.svg
light_lazyframeOn.svg
light_lazyframeOff.svg
dark_lazyframeOn.svg
dark_lazyframeOff.svg
dark_animation_play.svg
dark_animation_stop.svg
dark_dropframe.svg
dark_droppedframes.svg
light_animation_play.svg
light_animation_stop.svg
light_dropframe.svg
light_droppedframes.svg
dark_landscape.svg
dark_portrait.svg
light_landscape.svg
light_portrait.svg
dark_interpolation_constant.svg
dark_interpolation_linear.svg
dark_interpolation_bezier.svg
dark_interpolation_sharp.svg
dark_interpolation_smooth.svg
light_interpolation_bezier.svg
light_interpolation_constant.svg
light_interpolation_linear.svg
light_interpolation_sharp.svg
light_interpolation_smooth.svg
+ dark_audio-none.svg
+ dark_audio-volume-high.svg
+ dark_audio-volume-mute.svg
dark_keyframe-add.svg
dark_keyframe-remove.svg
dark_zoom-fit.svg
dark_zoom-horizontal.svg
dark_zoom-vertical.svg
+ light_audio-none.svg
+ light_audio-volume-high.svg
+ light_audio-volume-mute.svg
light_keyframe-add.svg
light_keyframe-remove.svg
light_zoom-fit.svg
light_zoom-horizontal.svg
light_zoom-vertical.svg
dark_showColoring.svg
dark_showMarks.svg
dark_showColoringOff.svg
dark_showMarksOff.svg
dark_updateColorize.svg
light_showColoring.svg
light_showMarks.svg
light_showColoringOff.svg
light_showMarksOff.svg
light_updateColorize.svg
diff --git a/libs/image/kis_image_animation_interface.cpp b/libs/image/kis_image_animation_interface.cpp
index 09cdc21f3e..5d2cd3fd29 100644
--- a/libs/image/kis_image_animation_interface.cpp
+++ b/libs/image/kis_image_animation_interface.cpp
@@ -1,354 +1,401 @@
/*
* Copyright (c) 2015 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_image_animation_interface.h"
+#include
+
#include "kis_global.h"
#include "kis_image.h"
#include "kis_regenerate_frame_stroke_strategy.h"
#include "kis_switch_time_stroke_strategy.h"
#include "kis_keyframe_channel.h"
#include "kis_time_range.h"
#include "kis_post_execution_undo_adapter.h"
#include "commands_new/kis_switch_current_time_command.h"
#include "kis_layer_utils.h"
struct KisImageAnimationInterface::Private
{
Private()
: image(0),
externalFrameActive(false),
frameInvalidationBlocked(false),
cachedLastFrameValue(-1),
+ audioChannelMuted(false),
+ audioChannelVolume(0.5),
m_currentTime(0),
m_currentUITime(0)
{
}
Private(const Private &rhs, KisImage *newImage)
: image(newImage),
externalFrameActive(false),
frameInvalidationBlocked(false),
fullClipRange(rhs.fullClipRange),
playbackRange(rhs.playbackRange),
framerate(rhs.framerate),
cachedLastFrameValue(-1),
+ audioChannelFileName(rhs.audioChannelFileName),
+ audioChannelMuted(rhs.audioChannelMuted),
+ audioChannelVolume(rhs.audioChannelVolume),
m_currentTime(rhs.m_currentTime),
m_currentUITime(rhs.m_currentUITime)
{
}
KisImage *image;
bool externalFrameActive;
bool frameInvalidationBlocked;
KisTimeRange fullClipRange;
KisTimeRange playbackRange;
int framerate;
int cachedLastFrameValue;
+ QString audioChannelFileName;
+ bool audioChannelMuted;
+ qreal audioChannelVolume;
KisSwitchTimeStrokeStrategy::SharedTokenWSP switchToken;
inline int currentTime() const {
return m_currentTime;
}
inline int currentUITime() const {
return m_currentUITime;
}
inline void setCurrentTime(int value) {
m_currentTime = value;
}
inline void setCurrentUITime(int value) {
m_currentUITime = value;
}
private:
int m_currentTime;
int m_currentUITime;
};
KisImageAnimationInterface::KisImageAnimationInterface(KisImage *image)
: m_d(new Private)
{
m_d->image = image;
m_d->framerate = 24;
m_d->fullClipRange = KisTimeRange::fromTime(0, 100);
connect(this, SIGNAL(sigInternalRequestTimeSwitch(int, bool)), SLOT(switchCurrentTimeAsync(int, bool)));
}
KisImageAnimationInterface::KisImageAnimationInterface(const KisImageAnimationInterface &rhs, KisImage *newImage)
: m_d(new Private(*rhs.m_d, newImage))
{
connect(this, SIGNAL(sigInternalRequestTimeSwitch(int, bool)), SLOT(switchCurrentTimeAsync(int, bool)));
}
KisImageAnimationInterface::~KisImageAnimationInterface()
{
}
bool KisImageAnimationInterface::hasAnimation() const
{
bool hasAnimation = false;
KisLayerUtils::recursiveApplyNodes(
m_d->image->root(),
[&hasAnimation](KisNodeSP node) {
hasAnimation |= node->isAnimated();
});
return hasAnimation;
}
int KisImageAnimationInterface::currentTime() const
{
return m_d->currentTime();
}
int KisImageAnimationInterface::currentUITime() const
{
return m_d->currentUITime();
}
const KisTimeRange& KisImageAnimationInterface::fullClipRange() const
{
return m_d->fullClipRange;
}
void KisImageAnimationInterface::setFullClipRange(const KisTimeRange range) {
m_d->fullClipRange = range;
emit sigFullClipRangeChanged();
}
const KisTimeRange& KisImageAnimationInterface::playbackRange() const
{
return m_d->playbackRange.isValid() ? m_d->playbackRange : m_d->fullClipRange;
}
void KisImageAnimationInterface::setPlaybackRange(const KisTimeRange range)
{
m_d->playbackRange = range;
emit sigPlaybackRangeChanged();
}
int KisImageAnimationInterface::framerate() const
{
return m_d->framerate;
}
+QString KisImageAnimationInterface::audioChannelFileName() const
+{
+ return m_d->audioChannelFileName;
+}
+
+void KisImageAnimationInterface::setAudioChannelFileName(const QString &fileName)
+{
+ QFileInfo info(fileName);
+
+ KIS_SAFE_ASSERT_RECOVER_NOOP(fileName.isEmpty() || info.isAbsolute());
+ m_d->audioChannelFileName = fileName.isEmpty() ? fileName : info.absoluteFilePath();
+
+ emit sigAudioChannelChanged();
+}
+
+bool KisImageAnimationInterface::isAudioMuted() const
+{
+ return m_d->audioChannelMuted;
+}
+
+void KisImageAnimationInterface::setAudioMuted(bool value)
+{
+ m_d->audioChannelMuted = value;
+ emit sigAudioChannelChanged();
+}
+
+qreal KisImageAnimationInterface::audioVolume() const
+{
+ return m_d->audioChannelVolume;
+}
+
+void KisImageAnimationInterface::setAudioVolume(qreal value)
+{
+ m_d->audioChannelVolume = value;
+ emit sigAudioVolumeChanged();
+}
+
void KisImageAnimationInterface::setFramerate(int fps)
{
m_d->framerate = fps;
emit sigFramerateChanged();
}
KisImageWSP KisImageAnimationInterface::image() const
{
return m_d->image;
}
bool KisImageAnimationInterface::externalFrameActive() const
{
return m_d->externalFrameActive;
}
void KisImageAnimationInterface::requestTimeSwitchWithUndo(int time)
{
if (currentUITime() == time) return;
requestTimeSwitchNonGUI(time, true);
}
void KisImageAnimationInterface::setDefaultProjectionColor(const KoColor &color)
{
int savedTime = 0;
saveAndResetCurrentTime(currentTime(), &savedTime);
m_d->image->setDefaultProjectionColor(color);
restoreCurrentTime(&savedTime);
}
void KisImageAnimationInterface::requestTimeSwitchNonGUI(int time, bool useUndo)
{
emit sigInternalRequestTimeSwitch(time, useUndo);
}
void KisImageAnimationInterface::explicitlySetCurrentTime(int frameId)
{
m_d->setCurrentTime(frameId);
}
void KisImageAnimationInterface::switchCurrentTimeAsync(int frameId, bool useUndo)
{
if (currentUITime() == frameId) return;
KisTimeRange range = KisTimeRange::infinite(0);
KisTimeRange::calculateTimeRangeRecursive(m_d->image->root(), currentUITime(), range, true);
const bool needsRegeneration = !range.contains(frameId);
KisSwitchTimeStrokeStrategy::SharedTokenSP token =
m_d->switchToken.toStrongRef();
if (!token || !token->tryResetDestinationTime(frameId, needsRegeneration)) {
{
KisPostExecutionUndoAdapter *undoAdapter = useUndo ?
m_d->image->postExecutionUndoAdapter() : 0;
KisSwitchTimeStrokeStrategy *strategy =
new KisSwitchTimeStrokeStrategy(frameId, needsRegeneration,
this, undoAdapter);
m_d->switchToken = strategy->token();
KisStrokeId stroke = m_d->image->startStroke(strategy);
m_d->image->endStroke(stroke);
}
if (needsRegeneration) {
KisStrokeStrategy *strategy =
new KisRegenerateFrameStrokeStrategy(this);
KisStrokeId strokeId = m_d->image->startStroke(strategy);
m_d->image->endStroke(strokeId);
}
}
m_d->setCurrentUITime(frameId);
emit sigUiTimeChanged(frameId);
}
void KisImageAnimationInterface::requestFrameRegeneration(int frameId, const QRegion &dirtyRegion)
{
KisStrokeStrategy *strategy =
new KisRegenerateFrameStrokeStrategy(frameId,
dirtyRegion,
this);
QList jobs = KisRegenerateFrameStrokeStrategy::createJobsData(m_d->image);
KisStrokeId stroke = m_d->image->startStroke(strategy);
Q_FOREACH (KisStrokeJobData* job, jobs) {
m_d->image->addJob(stroke, job);
}
m_d->image->endStroke(stroke);
}
void KisImageAnimationInterface::saveAndResetCurrentTime(int frameId, int *savedValue)
{
m_d->externalFrameActive = true;
*savedValue = m_d->currentTime();
m_d->setCurrentTime(frameId);
}
void KisImageAnimationInterface::restoreCurrentTime(int *savedValue)
{
m_d->setCurrentTime(*savedValue);
m_d->externalFrameActive = false;
}
void KisImageAnimationInterface::notifyFrameReady()
{
emit sigFrameReady(m_d->currentTime());
}
void KisImageAnimationInterface::notifyFrameCancelled()
{
emit sigFrameCancelled();
}
KisUpdatesFacade* KisImageAnimationInterface::updatesFacade() const
{
return m_d->image;
}
void KisImageAnimationInterface::notifyNodeChanged(const KisNode *node,
const QRect &rect,
bool recursive)
{
if (externalFrameActive() || m_d->frameInvalidationBlocked) return;
if (node->inherits("KisSelectionMask")) return;
KisKeyframeChannel *channel =
node->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (recursive) {
KisTimeRange affectedRange;
KisTimeRange::calculateTimeRangeRecursive(node, currentTime(), affectedRange, false);
invalidateFrames(affectedRange, rect);
} else if (channel) {
const int currentTime = m_d->currentTime();
invalidateFrames(channel->affectedFrames(currentTime), rect);
} else {
invalidateFrames(KisTimeRange::infinite(0), rect);
}
}
void KisImageAnimationInterface::invalidateFrames(const KisTimeRange &range, const QRect &rect)
{
m_d->cachedLastFrameValue = -1;
emit sigFramesChanged(range, rect);
}
void KisImageAnimationInterface::blockFrameInvalidation(bool value)
{
m_d->frameInvalidationBlocked = value;
}
int findLastKeyframeTimeRecursive(KisNodeSP node)
{
int time = 0;
KisKeyframeChannel *channel;
Q_FOREACH (channel, node->keyframeChannels()) {
KisKeyframeSP keyframe = channel->lastKeyframe();
if (keyframe) {
time = std::max(time, keyframe->time());
}
}
KisNodeSP child = node->firstChild();
while (child) {
time = std::max(time, findLastKeyframeTimeRecursive(child));
child = child->nextSibling();
}
return time;
}
int KisImageAnimationInterface::totalLength()
{
if (m_d->cachedLastFrameValue < 0) {
m_d->cachedLastFrameValue = findLastKeyframeTimeRecursive(m_d->image->root());
}
int lastKey = m_d->cachedLastFrameValue;
lastKey = std::max(lastKey, m_d->fullClipRange.end());
lastKey = std::max(lastKey, m_d->currentUITime());
return lastKey + 1;
}
diff --git a/libs/image/kis_image_animation_interface.h b/libs/image/kis_image_animation_interface.h
index b596c69292..f9af07ccff 100644
--- a/libs/image/kis_image_animation_interface.h
+++ b/libs/image/kis_image_animation_interface.h
@@ -1,166 +1,208 @@
/*
* Copyright (c) 2015 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_IMAGE_ANIMATION_INTERFACE_H
#define __KIS_IMAGE_ANIMATION_INTERFACE_H
#include
#include
#include "kis_types.h"
#include "kritaimage_export.h"
class KisUpdatesFacade;
class KisTimeRange;
class KoColor;
namespace KisLayerUtils {
struct SwitchFrameCommand;
}
class KRITAIMAGE_EXPORT KisImageAnimationInterface : public QObject
{
Q_OBJECT
public:
KisImageAnimationInterface(KisImage *image);
KisImageAnimationInterface(const KisImageAnimationInterface &rhs, KisImage *newImage);
~KisImageAnimationInterface();
/**
* Returns true of the image has at least one animated layer
*/
bool hasAnimation() const;
/**
* Returns currently active frame of the underlying image. Some strokes
* can override this value and it will report a different value.
*/
int currentTime() const;
/**
* Same as currentTime, except it isn't changed when background strokes
* are running.
*/
int currentUITime() const;
/**
* While any non-current frame is being regenerated by the
* strategy, the image is kept in a special state, named
* 'externalFrameActive'. Is this state the following applies:
*
* 1) All the animated paint devices switch its state into
* frameId() defined by global time.
*
* 2) All animation-not-capable devices switch to a temporary
* content device, which *is in undefined state*. The stroke
* should regenerate the image projection manually.
*/
bool externalFrameActive() const;
void requestTimeSwitchWithUndo(int time);
void requestTimeSwitchNonGUI(int time, bool useUndo = false);
public Q_SLOTS:
/**
* Switches current frame (synchronously) and starts an
* asynchronous regeneration of the entire image.
*/
void switchCurrentTimeAsync(int frameId, bool useUndo = false);
public:
/**
* Start a backgroud thread that will recalculate some extra frame.
* The result will be reported using two types of signals:
*
* 1) KisImage::sigImageUpdated() will be emitted for every chunk
* of updated area.
*
* 2) sigFrameReady() will be emitted in the end of the operation.
* IMPORTANT: to get the result you must connect to this signal
* with Qt::DirectConnection and fetch the result from
* frameProjection(). After the signal handler is exited, the
* data will no longer be available.
*/
void requestFrameRegeneration(int frameId, const QRegion &dirtyRegion);
void notifyNodeChanged(const KisNode *node, const QRect &rect, bool recursive);
void invalidateFrames(const KisTimeRange &range, const QRect &rect);
/**
* Changes the default color of the "external frame" projection of
* the image's root layer. Please note that this command should be
* executed from a context of an exclusive job!
*/
void setDefaultProjectionColor(const KoColor &color);
/**
* The current time range selected by user.
* @return current time range
*/
const KisTimeRange& fullClipRange() const;
void setFullClipRange(const KisTimeRange range);
const KisTimeRange &playbackRange() const;
void setPlaybackRange(const KisTimeRange range);
int framerate() const;
+ /**
+ * @return **absolute** file name of the audio channel file
+ */
+ QString audioChannelFileName() const;
+
+ /**
+ * Sets **absolute** file name of the audio channel file. Dont' try to pass
+ * a relative path, it'll assert!
+ */
+ void setAudioChannelFileName(const QString &fileName);
+
+ /**
+ * @return is the audio channel is currently muted
+ */
+ bool isAudioMuted() const;
+
+ /**
+ * Mutes the audio channel
+ */
+ void setAudioMuted(bool value);
+
+ /**
+ * Returns the preferred audio value in rangle [0, 1]
+ */
+ qreal audioVolume() const;
+
+ /**
+ * Set the preferred volume for the audio channel in range [0, 1]
+ */
+ void setAudioVolume(qreal value);
+
public Q_SLOTS:
void setFramerate(int fps);
public:
KisImageWSP image() const;
int totalLength();
private:
// interface for:
friend class KisRegenerateFrameStrokeStrategy;
friend class KisAnimationFrameCacheTest;
friend struct KisLayerUtils::SwitchFrameCommand;
friend class KisImageTest;
void saveAndResetCurrentTime(int frameId, int *savedValue);
void restoreCurrentTime(int *savedValue);
void notifyFrameReady();
void notifyFrameCancelled();
KisUpdatesFacade* updatesFacade() const;
void blockFrameInvalidation(bool value);
friend class KisSwitchTimeStrokeStrategy;
void explicitlySetCurrentTime(int frameId);
Q_SIGNALS:
void sigFrameReady(int time);
void sigFrameCancelled();
void sigUiTimeChanged(int newTime);
void sigFramesChanged(const KisTimeRange &range, const QRect &rect);
void sigInternalRequestTimeSwitch(int frameId, bool useUndo);
void sigFramerateChanged();
void sigFullClipRangeChanged();
void sigPlaybackRangeChanged();
+ /**
+ * Emitted when the audio channel of the document is changed
+ */
+ void sigAudioChannelChanged();
+
+ /**
+ * Emitted when audion volume changes. Please note that it doesn't change
+ * when you mute the channel! When muting, sigAudioChannelChanged() is used instead!
+ */
+ void sigAudioVolumeChanged();
+
private:
struct Private;
const QScopedPointer m_d;
};
#endif /* __KIS_IMAGE_ANIMATION_INTERFACE_H */
diff --git a/libs/image/kis_signal_compressor_with_param.h b/libs/image/kis_signal_compressor_with_param.h
index 94c751a8ff..6b01235345 100644
--- a/libs/image/kis_signal_compressor_with_param.h
+++ b/libs/image/kis_signal_compressor_with_param.h
@@ -1,136 +1,140 @@
/*
* Copyright (c) 2014 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_SIGNAL_COMPRESSOR_WITH_PARAM_H
#define __KIS_SIGNAL_COMPRESSOR_WITH_PARAM_H
#include
#include
/**
* A special class that converts a Qt signal into a std::function call.
*
* Example:
*
* std::function destinationFunctionCall(std::bind(someNiceFunc, firstParam, secondParam));
* SignalToFunctionProxy proxy(destinationFunctionCall);
* connect(srcObject, SIGNAL(sigSomethingChanged()), &proxy, SLOT(start()));
*
* Now every time sigSomethingChanged() is emitted, someNiceFunc is
* called. std::bind allows us to call any method of any class without
* changing signature of the class or creating special wrappers.
*/
class KRITAIMAGE_EXPORT SignalToFunctionProxy : public QObject
{
Q_OBJECT
public:
using TrivialFunction = std::function;
public:
SignalToFunctionProxy(TrivialFunction function)
: m_function(function)
{
}
public Q_SLOTS:
void start() {
m_function();
}
private:
TrivialFunction m_function;
};
/**
* A special class for deferring and comressing events with one
* parameter of type T. This works like KisSignalCompressor but can
* handle events with one parameter. Due to limitation of the Qt this
* doesn't allow signal/slots, so it uses std::function instead.
*
* In the end (after a timeout) the latest param value is returned to
* the callback.
*
* Usage:
*
* \code{.cpp}
*
* using namespace std::placeholders; // For _1 placeholder
*
* // prepare the callback function
* std::function callback(
* std::bind(&LutDockerDock::setCurrentExposureImpl, this, _1));
*
* // Create the compressor object
* KisSignalCompressorWithParam compressor(40, callback);
*
* // When event comes:
* compressor.start(0.123456);
*
* \endcode
*/
template
class KisSignalCompressorWithParam
{
public:
using CallbackFunction = std::function;
public:
KisSignalCompressorWithParam(int delay, CallbackFunction function, KisSignalCompressor::Mode mode = KisSignalCompressor::FIRST_ACTIVE)
: m_compressor(delay, mode),
m_function(function)
{
std::function callback(
std::bind(&KisSignalCompressorWithParam::fakeSlotTimeout, this));
m_signalProxy.reset(new SignalToFunctionProxy(callback));
m_compressor.connect(&m_compressor, SIGNAL(timeout()), m_signalProxy.data(), SLOT(start()));
}
~KisSignalCompressorWithParam()
{
}
void start(T param) {
m_currentParamValue = param;
m_compressor.start();
}
void stop() {
m_compressor.stop();
}
bool isActive() const {
return m_compressor.isActive();
}
+ void setDelay(int value) {
+ m_compressor.setDelay(value);
+ }
+
private:
void fakeSlotTimeout() {
m_function(m_currentParamValue);
}
private:
KisSignalCompressor m_compressor;
CallbackFunction m_function;
QScopedPointer m_signalProxy;
T m_currentParamValue;
};
#endif /* __KIS_SIGNAL_COMPRESSOR_WITH_PARAM_H */
diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt
index 31c0dd1d3f..3cf92dbe6e 100644
--- a/libs/ui/CMakeLists.txt
+++ b/libs/ui/CMakeLists.txt
@@ -1,533 +1,539 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile
${EXIV2_INCLUDE_DIR}
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
${OCIO_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
add_subdirectory( tests )
if (APPLE)
find_library(FOUNDATION_LIBRARY Foundation)
endif ()
set(kritaui_LIB_SRCS
canvas/kis_canvas_widget_base.cpp
canvas/kis_canvas2.cpp
canvas/kis_canvas_updates_compressor.cpp
canvas/kis_canvas_controller.cpp
canvas/kis_paintop_transformation_connector.cpp
canvas/kis_display_color_converter.cpp
canvas/kis_display_filter.cpp
canvas/kis_exposure_gamma_correction_interface.cpp
canvas/kis_tool_proxy.cpp
canvas/kis_canvas_decoration.cc
canvas/kis_coordinates_converter.cpp
canvas/kis_grid_manager.cpp
canvas/kis_grid_decoration.cpp
canvas/kis_grid_config.cpp
canvas/kis_prescaled_projection.cpp
canvas/kis_qpainter_canvas.cpp
canvas/kis_projection_backend.cpp
canvas/kis_update_info.cpp
canvas/kis_image_patch.cpp
canvas/kis_image_pyramid.cpp
canvas/kis_infinity_manager.cpp
canvas/kis_change_guides_command.cpp
canvas/kis_guides_decoration.cpp
canvas/kis_guides_manager.cpp
canvas/kis_guides_config.cpp
canvas/kis_snap_config.cpp
canvas/kis_snap_line_strategy.cpp
dialogs/kis_about_application.cpp
dialogs/kis_dlg_adj_layer_props.cc
dialogs/kis_dlg_adjustment_layer.cc
dialogs/kis_dlg_filter.cpp
dialogs/kis_dlg_generator_layer.cpp
dialogs/kis_dlg_file_layer.cpp
dialogs/kis_dlg_filter.cpp
dialogs/kis_dlg_stroke_selection_properties.cpp
dialogs/kis_dlg_image_properties.cc
dialogs/kis_dlg_layer_properties.cc
dialogs/kis_dlg_preferences.cc
dialogs/slider_and_spin_box_sync.cpp
dialogs/kis_dlg_blacklist_cleanup.cpp
dialogs/kis_dlg_layer_style.cpp
dialogs/kis_dlg_png_import.cpp
dialogs/kis_dlg_import_image_sequence.cpp
dialogs/kis_delayed_save_dialog.cpp
dialogs/kis_dlg_internal_color_selector.cpp
flake/kis_node_dummies_graph.cpp
flake/kis_dummies_facade_base.cpp
flake/kis_dummies_facade.cpp
flake/kis_node_shapes_graph.cpp
flake/kis_node_shape.cpp
flake/kis_shape_controller.cpp
flake/kis_shape_layer.cc
flake/kis_shape_layer_canvas.cpp
flake/kis_shape_selection.cpp
flake/kis_shape_selection_canvas.cpp
flake/kis_shape_selection_model.cpp
flake/kis_take_all_shapes_command.cpp
brushhud/kis_uniform_paintop_property_widget.cpp
brushhud/kis_brush_hud.cpp
brushhud/kis_round_hud_button.cpp
brushhud/kis_dlg_brush_hud_config.cpp
brushhud/kis_brush_hud_properties_list.cpp
brushhud/kis_brush_hud_properties_config.cpp
kis_aspect_ratio_locker.cpp
kis_autogradient.cc
kis_bookmarked_configurations_editor.cc
kis_bookmarked_configurations_model.cc
kis_bookmarked_filter_configurations_model.cc
kis_base_option.cpp
kis_canvas_resource_provider.cpp
kis_derived_resources.cpp
kis_categories_mapper.cpp
kis_categorized_list_model.cpp
kis_categorized_item_delegate.cpp
kis_clipboard.cc
kis_config.cc
kis_config_notifier.cpp
kis_control_frame.cpp
kis_composite_ops_model.cc
kis_paint_ops_model.cpp
kis_cursor.cc
kis_cursor_cache.cpp
kis_custom_pattern.cc
kis_file_layer.cpp
kis_safe_document_loader.cpp
kis_splash_screen.cpp
kis_filter_manager.cc
kis_filters_model.cc
kis_histogram_view.cc
kis_image_manager.cc
kis_image_view_converter.cpp
kis_import_catcher.cc
kis_layer_manager.cc
kis_mask_manager.cc
kis_mimedata.cpp
kis_node_commands_adapter.cpp
kis_node_manager.cpp
kis_node_juggler_compressed.cpp
kis_node_selection_adapter.cpp
kis_node_insertion_adapter.cpp
kis_node_model.cpp
kis_node_filter_proxy_model.cpp
kis_model_index_converter_base.cpp
kis_model_index_converter.cpp
kis_model_index_converter_show_all.cpp
kis_painting_assistant.cc
kis_painting_assistants_decoration.cpp
kis_painting_assistants_manager.cpp
kis_paintop_box.cc
kis_paintop_option.cpp
kis_paintop_options_model.cpp
kis_paintop_settings_widget.cpp
kis_popup_palette.cpp
kis_png_converter.cpp
kis_preference_set_registry.cpp
kis_script_manager.cpp
kis_resource_server_provider.cpp
kis_selection_decoration.cc
kis_selection_manager.cc
kis_statusbar.cc
kis_zoom_manager.cc
kis_favorite_resource_manager.cpp
kis_workspace_resource.cpp
kis_action.cpp
kis_action_manager.cpp
kis_view_plugin.cpp
kis_canvas_controls_manager.cpp
kis_tooltip_manager.cpp
kis_multinode_property.cpp
kis_stopgradient_editor.cpp
kisexiv2/kis_exif_io.cpp
kisexiv2/kis_exiv2.cpp
kisexiv2/kis_iptc_io.cpp
kisexiv2/kis_xmp_io.cpp
opengl/kis_opengl.cpp
opengl/kis_opengl_canvas2.cpp
opengl/kis_opengl_canvas_debugger.cpp
opengl/kis_opengl_image_textures.cpp
opengl/kis_texture_tile.cpp
opengl/kis_opengl_shader_loader.cpp
kis_fps_decoration.cpp
recorder/kis_node_query_path_editor.cc
recorder/kis_recorded_action_creator.cc
recorder/kis_recorded_action_creator_factory.cc
recorder/kis_recorded_action_creator_factory_registry.cc
recorder/kis_recorded_action_editor_factory.cc
recorder/kis_recorded_action_editor_factory_registry.cc
recorder/kis_recorded_filter_action_editor.cc
recorder/kis_recorded_filter_action_creator.cpp
recorder/kis_recorded_paint_action_editor.cc
tool/kis_selection_tool_helper.cpp
tool/kis_selection_tool_config_widget_helper.cpp
tool/kis_rectangle_constraint_widget.cpp
tool/kis_shape_tool_helper.cpp
tool/kis_tool.cc
tool/kis_delegated_tool_policies.cpp
tool/kis_tool_freehand.cc
tool/kis_speed_smoother.cpp
tool/kis_painting_information_builder.cpp
tool/kis_stabilized_events_sampler.cpp
tool/kis_tool_freehand_helper.cpp
tool/kis_tool_multihand_helper.cpp
tool/kis_figure_painting_tool_helper.cpp
tool/kis_recording_adapter.cpp
tool/kis_tool_paint.cc
tool/kis_tool_shape.cc
tool/kis_tool_ellipse_base.cpp
tool/kis_tool_rectangle_base.cpp
tool/kis_tool_polyline_base.cpp
tool/kis_tool_utils.cpp
tool/kis_resources_snapshot.cpp
tool/kis_smoothing_options.cpp
tool/KisStabilizerDelayedPaintHelper.cpp
tool/strokes/freehand_stroke.cpp
tool/strokes/kis_painter_based_stroke_strategy.cpp
tool/strokes/kis_filter_stroke_strategy.cpp
tool/strokes/kis_color_picker_stroke_strategy.cpp
widgets/kis_cmb_composite.cc
widgets/kis_cmb_contour.cpp
widgets/kis_cmb_gradient.cpp
widgets/kis_paintop_list_widget.cpp
widgets/kis_cmb_idlist.cc
widgets/kis_color_space_selector.cc
widgets/kis_advanced_color_space_selector.cc
widgets/kis_cie_tongue_widget.cpp
widgets/kis_tone_curve_widget.cpp
widgets/kis_curve_widget.cpp
widgets/kis_custom_image_widget.cc
widgets/kis_image_from_clipboard_widget.cpp
widgets/kis_double_widget.cc
widgets/kis_filter_selector_widget.cc
widgets/kis_gradient_chooser.cc
widgets/kis_gradient_slider_widget.cc
widgets/kis_gradient_slider.cpp
widgets/kis_iconwidget.cc
widgets/kis_mask_widgets.cpp
widgets/kis_meta_data_merge_strategy_chooser_widget.cc
widgets/kis_multi_bool_filter_widget.cc
widgets/kis_multi_double_filter_widget.cc
widgets/kis_multi_integer_filter_widget.cc
widgets/kis_multipliers_double_slider_spinbox.cpp
widgets/kis_paintop_presets_popup.cpp
widgets/kis_tool_options_popup.cpp
widgets/kis_paintop_presets_chooser_popup.cpp
widgets/kis_pattern_chooser.cc
widgets/kis_popup_button.cc
widgets/kis_preset_chooser.cpp
widgets/kis_progress_widget.cpp
widgets/kis_selection_options.cc
widgets/kis_scratch_pad.cpp
widgets/kis_scratch_pad_event_filter.cpp
widgets/kis_preset_selector_strip.cpp
widgets/kis_slider_spin_box.cpp
widgets/kis_size_group.cpp
widgets/kis_size_group_p.cpp
widgets/kis_wdg_generator.cpp
widgets/kis_workspace_chooser.cpp
widgets/squeezedcombobox.cpp
widgets/kis_categorized_list_view.cpp
widgets/kis_widget_chooser.cpp
widgets/kis_tool_button.cpp
widgets/kis_floating_message.cpp
widgets/kis_lod_availability_widget.cpp
widgets/kis_color_label_selector_widget.cpp
widgets/kis_color_filter_combo.cpp
widgets/kis_elided_label.cpp
widgets/kis_stopgradient_slider_widget.cpp
widgets/kis_spinbox_color_selector.cpp
widgets/kis_screen_color_picker.cpp
widgets/KoDualColorButton.cpp
widgets/kis_color_input.cpp
widgets/kis_color_button.cpp
widgets/KisVisualColorSelector.cpp
widgets/KisVisualColorSelectorShape.cpp
widgets/KisVisualEllipticalSelectorShape.cpp
widgets/KisVisualRectangleSelectorShape.cpp
widgets/KisVisualTriangleSelectorShape.cpp
input/kis_input_manager.cpp
input/kis_input_manager_p.cpp
input/kis_extended_modifiers_mapper.cpp
input/kis_abstract_input_action.cpp
input/kis_tool_invocation_action.cpp
input/kis_pan_action.cpp
input/kis_alternate_invocation_action.cpp
input/kis_rotate_canvas_action.cpp
input/kis_zoom_action.cpp
input/kis_change_frame_action.cpp
input/kis_gamma_exposure_action.cpp
input/kis_show_palette_action.cpp
input/kis_change_primary_setting_action.cpp
input/kis_abstract_shortcut.cpp
input/kis_single_action_shortcut.cpp
input/kis_stroke_shortcut.cpp
input/kis_shortcut_matcher.cpp
input/kis_select_layer_action.cpp
operations/kis_operation.cpp
operations/kis_operation_configuration.cpp
operations/kis_operation_registry.cpp
operations/kis_operation_ui_factory.cpp
operations/kis_operation_ui_widget.cpp
operations/kis_filter_selection_operation.cpp
actions/kis_selection_action_factories.cpp
input/kis_touch_shortcut.cpp
kis_document_undo_store.cpp
kis_transaction_based_command.cpp
kis_gui_context_command.cpp
kis_gui_context_command_p.cpp
input/kis_tablet_debugger.cpp
input/kis_input_profile_manager.cpp
input/kis_input_profile.cpp
input/kis_shortcut_configuration.cpp
input/config/kis_input_configuration_page.cpp
input/config/kis_edit_profiles_dialog.cpp
input/config/kis_input_profile_model.cpp
input/config/kis_input_configuration_page_item.cpp
input/config/kis_action_shortcuts_model.cpp
input/config/kis_input_type_delegate.cpp
input/config/kis_input_mode_delegate.cpp
input/config/kis_input_button.cpp
input/config/kis_input_editor_delegate.cpp
input/config/kis_mouse_input_editor.cpp
input/config/kis_wheel_input_editor.cpp
input/config/kis_key_input_editor.cpp
processing/fill_processing_visitor.cpp
kis_asl_layer_style_serializer.cpp
kis_psd_layer_style_resource.cpp
canvas/kis_mirror_axis.cpp
kis_abstract_perspective_grid.cpp
KisApplication.cpp
KisAutoSaveRecoveryDialog.cpp
KisDetailsPane.cpp
KisDocument.cpp
KisNodeDelegate.cpp
kis_node_view_visibility_delegate.cpp
KisNodeToolTip.cpp
KisNodeView.cpp
kis_node_view_color_scheme.cpp
KisImportExportFilter.cpp
KisFilterEntry.cpp
KisImportExportManager.cpp
KisMainWindow.cpp
KisOpenPane.cpp
KisPart.cpp
KisPrintJob.cpp
KisTemplate.cpp
KisTemplateCreateDia.cpp
KisTemplateGroup.cpp
KisTemplates.cpp
KisTemplatesPane.cpp
KisTemplateTree.cpp
KisUndoStackAction.cpp
KisView.cpp
thememanager.cpp
kis_mainwindow_observer.cpp
KisViewManager.cpp
kis_mirror_manager.cpp
qtlockedfile/qtlockedfile.cpp
qtsingleapplication/qtlocalpeer.cpp
qtsingleapplication/qtsingleapplication.cpp
KisResourceBundle.cpp
KisResourceBundleManifest.cpp
kis_md5_generator.cpp
KisApplicationArguments.cpp
KisNetworkAccessManager.cpp
KisMultiFeedRSSModel.cpp
KisRemoteFileFetcher.cpp
KisPaletteModel.cpp
kis_palette_delegate.cpp
kis_palette_view.cpp
KisColorsetChooser.cpp
KisSaveGroupVisitor.cpp
)
if(WIN32)
if (NOT Qt5Gui_PRIVATE_INCLUDE_DIRS)
message(FATAL_ERROR "Qt5Gui Private header are missing!")
endif()
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/kis_tablet_event.cpp
input/wintab/kis_tablet_support_win.cpp
input/wintab/kis_screen_size_choice_dialog.cpp
qtlockedfile/qtlockedfile_win.cpp
)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
+
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
kis_animation_frame_cache.cpp
kis_animation_cache_populator.cpp
canvas/kis_animation_player.cpp
kis_animation_exporter.cpp
kis_animation_importer.cpp
+ KisSyncedAudioPlayback.cpp
)
if(UNIX)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/kis_tablet_event.cpp
input/wintab/kis_tablet_support.cpp
qtlockedfile/qtlockedfile_unix.cpp
)
if(NOT APPLE)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/wintab/kis_tablet_support_x11.cpp
input/wintab/qxcbconnection_xi2.cpp
input/wintab/qxcbconnection.cpp
input/wintab/kis_xi2_event_filter.cpp
)
endif()
endif()
ki18n_wrap_ui(kritaui_LIB_SRCS
forms/wdgdlgpngimport.ui
forms/wdgfullscreensettings.ui
forms/wdgautogradient.ui
forms/wdggeneralsettings.ui
forms/wdgperformancesettings.ui
forms/wdggenerators.ui
forms/wdgbookmarkedconfigurationseditor.ui
forms/wdgapplyprofile.ui
forms/wdgcustompattern.ui
forms/wdglayerproperties.ui
forms/wdgcolorsettings.ui
forms/wdgtabletsettings.ui
forms/wdgcolorspaceselector.ui
forms/wdgcolorspaceselectoradvanced.ui
forms/wdgdisplaysettings.ui
forms/kis_previewwidgetbase.ui
forms/kis_matrix_widget.ui
forms/wdgselectionoptions.ui
forms/wdggeometryoptions.ui
forms/wdgnewimage.ui
forms/wdgimageproperties.ui
forms/wdgmaskfromselection.ui
forms/wdgmasksource.ui
forms/wdgfilterdialog.ui
forms/wdgmetadatamergestrategychooser.ui
forms/wdgpaintoppresets.ui
forms/wdgpaintopsettings.ui
forms/wdgdlggeneratorlayer.ui
forms/wdgdlgfilelayer.ui
forms/wdgfilterselector.ui
forms/wdgfilternodecreation.ui
forms/wdgpaintactioneditor.ui
forms/wdgmultipliersdoublesliderspinbox.ui
forms/wdgnodequerypatheditor.ui
forms/wdgpresetselectorstrip.ui
forms/wdgdlgblacklistcleanup.ui
forms/wdgrectangleconstraints.ui
forms/wdgimportimagesequence.ui
forms/wdgstrokeselectionproperties.ui
forms/KisDetailsPaneBase.ui
forms/KisOpenPaneBase.ui
forms/wdgstopgradienteditor.ui
brushhud/kis_dlg_brush_hud_config.ui
forms/wdgdlginternalcolorselector.ui
dialogs/kis_delayed_save_dialog.ui
input/config/kis_input_configuration_page.ui
input/config/kis_edit_profiles_dialog.ui
input/config/kis_input_configuration_page_item.ui
input/config/kis_mouse_input_editor.ui
input/config/kis_wheel_input_editor.ui
input/config/kis_key_input_editor.ui
layerstyles/wdgBevelAndEmboss.ui
layerstyles/wdgblendingoptions.ui
layerstyles/WdgColorOverlay.ui
layerstyles/wdgContour.ui
layerstyles/wdgdropshadow.ui
layerstyles/WdgGradientOverlay.ui
layerstyles/wdgInnerGlow.ui
layerstyles/wdglayerstyles.ui
layerstyles/WdgPatternOverlay.ui
layerstyles/WdgSatin.ui
layerstyles/WdgStroke.ui
layerstyles/wdgstylesselector.ui
layerstyles/wdgTexture.ui
wdgsplash.ui
input/wintab/kis_screen_size_choice_dialog.ui
)
QT5_WRAP_CPP(kritaui_HEADERS_MOC KisNodePropertyAction_p.h)
add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} )
generate_export_header(kritaui BASE_NAME kritaui)
target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network
kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES}
)
+if (HAVE_QT_MULTIMEDIA)
+ target_link_libraries(kritaui Qt5::Multimedia)
+endif()
+
if (HAVE_KIO)
target_link_libraries(kritaui KF5::KIOCore)
endif()
if (NOT WIN32 AND NOT APPLE)
target_link_libraries(kritaui ${X11_X11_LIB}
${X11_Xinput_LIB}
${XCB_LIBRARIES})
endif()
if(APPLE)
target_link_libraries(kritaui ${FOUNDATION_LIBRARY})
endif ()
target_link_libraries(kritaui ${OPENEXR_LIBRARIES})
# Add VSync disable workaround
if(NOT WIN32 AND NOT APPLE)
target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras)
endif()
if(X11_FOUND)
target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES})
endif()
target_include_directories(kritaui
PUBLIC
$
$
$
$
$
$
$
)
set_target_properties(kritaui
PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS})
if (APPLE)
install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita)
endif ()
diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp
index 36b6c2e278..bd2772370f 100644
--- a/libs/ui/KisImportExportManager.cpp
+++ b/libs/ui/KisImportExportManager.cpp
@@ -1,434 +1,456 @@
/*
* Copyright (C) 2016 Boudewijn Rempt
*
* 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 "KisImportExportManager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_config.h"
#include "KisImportExportFilter.h"
#include "KisDocument.h"
#include
#include
#include "kis_guides_config.h"
#include "kis_grid_config.h"
#include "kis_popup_button.h"
#include
// static cache for import and export mimetypes
QStringList KisImportExportManager::m_importMimeTypes;
QStringList KisImportExportManager::m_exportMimeTypes;
class Q_DECL_HIDDEN KisImportExportManager::Private
{
public:
bool batchMode {false};
QPointer progressUpdater {0};
};
KisImportExportManager::KisImportExportManager(KisDocument* document)
: m_document(document)
, d(new Private)
{
}
KisImportExportManager::~KisImportExportManager()
{
delete d;
}
KisImportExportFilter::ConversionStatus KisImportExportManager::importDocument(const QString& location, const QString& mimeType)
{
return convert(Import, location, location, mimeType, false, 0);
}
KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, const QString& realLocation, QByteArray& mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
return convert(Export, location, realLocation, mimeType, showWarnings, exportConfiguration);
}
// The static method to figure out to which parts of the
// graph this mimetype has a connection to.
QStringList KisImportExportManager::mimeFilter(Direction direction)
{
// Find the right mimetype by the extension
QSet mimeTypes;
// mimeTypes << KisDocument::nativeFormatMimeType() << "application/x-krita-paintoppreset" << "image/openraster";
if (direction == KisImportExportManager::Import) {
if (m_importMimeTypes.isEmpty()) {
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
Q_FOREACH(const QString &mimetype, json.value("X-KDE-Import").toString().split(",", QString::SkipEmptyParts)) {
//qDebug() << "Adding import mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader;
mimeTypes << mimetype;
}
}
qDeleteAll(list);
m_importMimeTypes = mimeTypes.toList();
}
return m_importMimeTypes;
}
else if (direction == KisImportExportManager::Export) {
if (m_exportMimeTypes.isEmpty()) {
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
Q_FOREACH(const QString &mimetype, json.value("X-KDE-Export").toString().split(",", QString::SkipEmptyParts)) {
//qDebug() << "Adding export mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader;
mimeTypes << mimetype;
}
}
qDeleteAll(list);
m_exportMimeTypes = mimeTypes.toList();
}
return m_exportMimeTypes;
}
return QStringList();
}
KisImportExportFilter *KisImportExportManager::filterForMimeType(const QString &mimetype, KisImportExportManager::Direction direction)
{
int weight = -1;
KisImportExportFilter *filter = 0;
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
QString directionKey = direction == Export ? "X-KDE-Export" : "X-KDE-Import";
if (json.value(directionKey).toString().split(",", QString::SkipEmptyParts).contains(mimetype)) {
KLibFactory *factory = qobject_cast(loader->instance());
if (!factory) {
warnUI << loader->errorString();
continue;
}
QObject* obj = factory->create(0);
if (!obj || !obj->inherits("KisImportExportFilter")) {
delete obj;
continue;
}
KisImportExportFilter *f = qobject_cast(obj);
if (!f) {
delete obj;
continue;
}
int w = json.value("X-KDE-Weight").toInt();
if (w > weight) {
delete filter;
filter = f;
f->setObjectName(loader->fileName());
weight = w;
}
}
}
qDeleteAll(list);
filter->setMimeType(mimetype);
return filter;
}
void KisImportExportManager::setBatchMode(const bool batch)
{
d->batchMode = batch;
}
bool KisImportExportManager::batchMode(void) const
{
return d->batchMode;
}
void KisImportExportManager::setProgresUpdater(KoProgressUpdater *updater)
{
d->progressUpdater = updater;
}
+QString KisImportExportManager::askForAudioFileName(const QString &defaultDir, QWidget *parent)
+{
+ KoFileDialog dialog(parent, KoFileDialog::ImportFiles, "ImportAudio");
+
+ if (!defaultDir.isEmpty()) {
+ dialog.setDefaultDir(defaultDir);
+ }
+
+ QStringList mimeTypes;
+ mimeTypes << "audio/mpeg";
+ mimeTypes << "audio/ogg";
+ mimeTypes << "audio/vorbis";
+ mimeTypes << "audio/vnd.wave";
+ mimeTypes << "audio/flac";
+
+ dialog.setMimeTypeFilters(mimeTypes);
+ dialog.setCaption(i18nc("@titile:window", "Open Audio"));
+
+ return dialog.filename();
+}
+
KisImportExportFilter::ConversionStatus KisImportExportManager::convert(KisImportExportManager::Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
QString typeName = mimeType;
if (typeName.isEmpty()) {
typeName = KisMimeDatabase::mimeTypeForFile(location);
}
QSharedPointer filter(filterForMimeType(typeName, direction));
if (!filter) {
return KisImportExportFilter::FilterCreationError;
}
filter->setFilename(location);
filter->setRealFilename(realLocation);
filter->setBatchMode(batchMode());
filter->setMimeType(typeName);
if (d->progressUpdater) {
filter->setUpdater(d->progressUpdater->startSubtask());
}
QByteArray from, to;
if (direction == Export) {
from = m_document->nativeFormatMimeType();
to = mimeType.toLatin1();
}
else {
from = mimeType.toLatin1();
to = m_document->nativeFormatMimeType();
}
if (!exportConfiguration) {
exportConfiguration = filter->lastSavedConfiguration(from, to);
if (exportConfiguration) {
// Fill with some meta information about the image
KisImageWSP image = m_document->image();
KisPaintDeviceSP pd = image->projection();
bool isThereAlpha = false;
KisSequentialConstIterator it(pd, image->bounds());
const KoColorSpace* cs = pd->colorSpace();
do {
if (cs->opacityU8(it.oldRawData()) != OPACITY_OPAQUE_U8) {
isThereAlpha = true;
break;
}
} while (it.nextPixel());
exportConfiguration->setProperty("ImageContainsTransparency", isThereAlpha);
exportConfiguration->setProperty("ColorModelID", cs->colorModelId().id());
exportConfiguration->setProperty("ColorDepthID", cs->colorDepthId().id());
bool sRGB = (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) && !cs->profile()->name().contains(QLatin1String("g10")));
exportConfiguration->setProperty("sRGB", sRGB);
}
}
KisPreExportChecker checker;
if (direction == Export) {
checker.check(m_document->image(), filter->exportChecks());
}
KisConfigWidget *wdg = filter->createConfigurationWidget(0, from, to);
bool alsoAsKra = false;
QStringList warnings = checker.warnings();
QStringList errors = checker.errors();
// Extra checks that cannot be done by the checker, because the checker only has access to the image.
if (!m_document->assistants().isEmpty() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains assistants . The assistants will not be saved."));
}
if (m_document->guidesConfig().hasGuides() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains guides . The guides will not be saved."));
}
if (!m_document->gridConfig().isDefault() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains a custom grid configuration . The configuration will not be saved."));
}
if (!batchMode() && !errors.isEmpty()) {
QString error = ""
+ i18n("Error: cannot save this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName))
+ " Reasons:
"
+ "
";
Q_FOREACH(const QString &w, errors) {
error += "\n" + w + " ";
}
error += " ";
QMessageBox::critical(KisPart::instance()->currentMainwindow(), i18nc("@title:window", "Krita: Export Error"), error);
return KisImportExportFilter::UserCancelled;
}
if (!batchMode() && (wdg || !warnings.isEmpty())) {
KoDialog dlg;
dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
dlg.setWindowTitle(KisMimeDatabase::descriptionForMimeType(mimeType));
QWidget *page = new QWidget(&dlg);
QVBoxLayout *layout = new QVBoxLayout(page);
if (!checker.warnings().isEmpty()) {
if (showWarnings) {
QHBoxLayout *hLayout = new QHBoxLayout();
QLabel *labelWarning = new QLabel();
labelWarning->setPixmap(KisIconUtils::loadIcon("dialog-warning").pixmap(32, 32));
hLayout->addWidget(labelWarning);
KisPopupButton *bn = new KisPopupButton(0);
bn->setText(i18nc("Keep the extra space at the end of the sentence, please", "Warning: saving as %1 will lose information from your image. ", KisMimeDatabase::descriptionForMimeType(mimeType)));
hLayout->addWidget(bn);
layout->addLayout(hLayout);
QTextBrowser *browser = new QTextBrowser();
browser->setMinimumWidth(bn->width());
bn->setPopupWidget(browser);
QString warning = ""
+ i18n("You will lose information when saving this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName));
if (warnings.size() == 1) {
warning += " Reason:
";
}
else {
warning += " Reasons:
";
}
warning += "
";
Q_FOREACH(const QString &w, warnings) {
warning += "\n" + w + " ";
}
warning += " ";
browser->setHtml(warning);
}
}
if (wdg) {
QGroupBox *box = new QGroupBox(i18n("Options"));
QVBoxLayout *boxLayout = new QVBoxLayout(box);
wdg->setConfiguration(exportConfiguration);
boxLayout->addWidget(wdg);
layout->addWidget(box);
}
QCheckBox *chkAlsoAsKra = 0;
if (showWarnings) {
if (!checker.warnings().isEmpty()) {
chkAlsoAsKra = new QCheckBox(i18n("Also save your image as a Krita file."));
chkAlsoAsKra->setChecked(KisConfig().readEntry("AlsoSaveAsKra", false));
layout->addWidget(chkAlsoAsKra);
}
}
dlg.setMainWidget(page);
dlg.resize(dlg.minimumSize());
if (showWarnings || wdg) {
if (!dlg.exec()) {
return KisImportExportFilter::UserCancelled;
}
}
if (chkAlsoAsKra) {
KisConfig().writeEntry("AlsoSaveAsKra", chkAlsoAsKra->isChecked());
alsoAsKra = chkAlsoAsKra->isChecked();
}
if (wdg) {
exportConfiguration = wdg->configuration();
}
}
QFile io(location);
if (direction == Import) {
if (!io.exists()) {
return KisImportExportFilter::FileNotFound;
}
if (!io.open(QFile::ReadOnly)) {
return KisImportExportFilter::FileNotFound;
}
}
else if (direction == Export) {
if (!io.open(QFile::WriteOnly)) {
return KisImportExportFilter::CreationError;
}
}
else {
return KisImportExportFilter::BadConversionGraph;
}
if (!batchMode()) {
QApplication::setOverrideCursor(Qt::WaitCursor);
}
KisImportExportFilter::ConversionStatus status = filter->convert(m_document, &io, exportConfiguration);
io.close();
if (exportConfiguration) {
KisConfig().setExportConfiguration(typeName, exportConfiguration);
}
if (alsoAsKra) {
QString l = location + ".kra";
QByteArray ba = m_document->nativeFormatMimeType();
KisImportExportFilter *filter = filterForMimeType(QString::fromLatin1(ba), Export);
QFile f(l);
f.open(QIODevice::WriteOnly);
if (filter) {
filter->setFilename(l);
filter->convert(m_document, &f);
}
f.close();
delete filter;
}
if (!batchMode()) {
QApplication::restoreOverrideCursor();
}
return status;
}
#include
diff --git a/libs/ui/KisImportExportManager.h b/libs/ui/KisImportExportManager.h
index 2535d29882..bd07d42ad7 100644
--- a/libs/ui/KisImportExportManager.h
+++ b/libs/ui/KisImportExportManager.h
@@ -1,144 +1,146 @@
/*
* Copyright (C) 2016 Boudewijn Rempt
*
* 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 KIS_IMPORT_EXPORT_MANAGER_H
#define KIS_IMPORT_EXPORT_MANAGER_H
#include
#include
#include
#include
#include "KisImportExportFilter.h"
#include "kritaui_export.h"
class KisDocument;
class KoProgressUpdater;
/**
* @brief The class managing all the filters.
*
* This class manages all filters for a %Calligra application. Normally
* you will not have to use it, since KisMainWindow takes care of loading
* and saving documents.
*
* @ref KisFilter
*
* @author Kalle Dalheimer
* @author Torben Weis
* @author Werner Trobin
*/
class KRITAUI_EXPORT KisImportExportManager : public QObject
{
Q_OBJECT
public:
/**
* This enum is used to distinguish the import/export cases
*/
enum Direction { Import = 1, Export = 2 };
/**
* Create a filter manager for a document
*/
explicit KisImportExportManager(KisDocument *document);
public:
virtual ~KisImportExportManager();
/**
* Imports the specified document and returns the resultant filename
* (most likely some file in /tmp).
* @p path can be either a URL or a filename.
* @p documentMimeType gives importDocument a hint about what type
* the document may be. It can be left empty.
*
* @return status signals the success/error of the conversion.
* If the QString which is returned isEmpty() and the status is OK,
* then we imported the file directly into the document.
*/
KisImportExportFilter::ConversionStatus importDocument(const QString &location, const QString &mimeType);
/**
* @brief Exports the given file/document to the specified URL/mimetype.
*
* If @p mimeType is empty, then the closest matching Calligra part is searched
* and when the method returns @p mimeType contains this mimetype.
* Oh, well, export is a C++ keyword ;)
*/
KisImportExportFilter::ConversionStatus exportDocument(const QString &location, const QString& realLocation, QByteArray &mimeType, bool showWarnings = true, KisPropertiesConfigurationSP exportConfiguration = 0);
///@name Static API
//@{
/**
* Suitable for passing to KoFileDialog::setMimeTypeFilters. The default mime
* gets set by the "users" of this method, as we do not have enough
* information here.
* Optionally, @p extraNativeMimeTypes are added after the native mimetype.
*/
static QStringList mimeFilter(Direction direction);
/**
* @brief filterForMimeType loads the relevant import/export plugin and returns it. The caller
* is responsible for deleting it!
* @param mimetype the mimetype we want to import/export. If there's more than one plugin, the one
* with the highest weight as defined in the json description will be taken
* @param direction import or export
* @return a pointer to the filter plugin or 0 if none could be found
*/
static KisImportExportFilter *filterForMimeType(const QString &mimetype, Direction direction);
/**
* Set the filter manager is batch mode (no dialog shown)
* instead of the interactive mode (dialog shown)
*/
void setBatchMode(const bool batch);
/**
* Get if the filter manager is batch mode (true)
* or in interactive mode (true)
*/
bool batchMode(void) const;
void setProgresUpdater(KoProgressUpdater *updater);
+ static QString askForAudioFileName(const QString &defaultDir, QWidget *parent);
+
private Q_SLOTS:
private:
KisImportExportFilter::ConversionStatus convert(Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration);
// Private API
KisImportExportManager(const KisImportExportManager& rhs);
KisImportExportManager &operator=(const KisImportExportManager& rhs);
KisDocument *m_document;
/// A static cache for the availability checks of filters
static QStringList m_importMimeTypes;
static QStringList m_exportMimeTypes;
class Private;
Private * const d;
};
#endif // __KO_FILTER_MANAGER_H__
diff --git a/libs/ui/KisSyncedAudioPlayback.cpp b/libs/ui/KisSyncedAudioPlayback.cpp
new file mode 100644
index 0000000000..8a3b815b65
--- /dev/null
+++ b/libs/ui/KisSyncedAudioPlayback.cpp
@@ -0,0 +1,143 @@
+#include "KisSyncedAudioPlayback.h"
+
+#include "config-qtmultimedia.h"
+
+#ifdef HAVE_QT_MULTIMEDIA
+#include
+#else
+class QIODevice;
+
+#include
+
+namespace {
+
+ class QMediaPlayer : public QObject {
+ Q_OBJECT
+ public:
+
+ enum Error
+ {
+ NoError,
+ ResourceError,
+ FormatError,
+ NetworkError,
+ AccessDeniedError,
+ ServiceMissingError,
+ MediaIsPlaylist
+ };
+
+ enum State
+ {
+ StoppedState,
+ PlayingState,
+ PausedState
+ };
+
+ State state() const { return StoppedState; }
+
+ void play() {}
+ void stop() {}
+
+ qint64 position() const { return 0; }
+ qreal playbackRate() const { return 1.0; }
+ void setPosition(qint64) {}
+ void setPlaybackRate(qreal) {}
+ void setVolume(int) {}
+ void setMedia(const QUrl&, QIODevice * device = 0) { Q_UNUSED(device);}
+ QString errorString() const { return QString(); }
+
+ Q_SIGNALS:
+ void error(Error value);
+ };
+}
+#endif
+
+
+
+#include
+
+
+
+struct KisSyncedAudioPlayback::Private
+{
+ QMediaPlayer player;
+ qint64 tolerance = 200;
+};
+
+
+KisSyncedAudioPlayback::KisSyncedAudioPlayback(const QString &fileName)
+ : QObject(0),
+ m_d(new Private)
+{
+ QFileInfo fileInfo(fileName);
+ Q_ASSERT(fileInfo.exists());
+
+ m_d->player.setMedia(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
+ m_d->player.setVolume(50);
+
+ connect(&m_d->player, SIGNAL(error(QMediaPlayer::Error)), SLOT(slotOnError()));
+}
+
+KisSyncedAudioPlayback::~KisSyncedAudioPlayback()
+{
+}
+
+void KisSyncedAudioPlayback::setSoundOffsetTolerance(qint64 value)
+{
+ m_d->tolerance = value;
+}
+
+void KisSyncedAudioPlayback::syncWithVideo(qint64 position)
+{
+ if (qAbs(position - m_d->player.position()) > m_d->tolerance) {
+ m_d->player.setPosition(position);
+ }
+}
+
+bool KisSyncedAudioPlayback::isPlaying() const
+{
+ return m_d->player.state() == QMediaPlayer::PlayingState;
+}
+
+void KisSyncedAudioPlayback::setVolume(qreal value)
+{
+ m_d->player.setVolume(qRound(100.0 * value));
+}
+
+void KisSyncedAudioPlayback::setSpeed(qreal value)
+{
+ if (qFuzzyCompare(value, m_d->player.playbackRate())) return;
+
+ if (m_d->player.state() == QMediaPlayer::PlayingState) {
+ const qint64 oldPosition = m_d->player.position();
+
+ m_d->player.stop();
+ m_d->player.setPlaybackRate(value);
+ m_d->player.setPosition(oldPosition);
+ m_d->player.play();
+ } else {
+ m_d->player.setPlaybackRate(value);
+ }
+}
+
+void KisSyncedAudioPlayback::play(qint64 startPosition)
+{
+ m_d->player.setPosition(startPosition);
+ m_d->player.play();
+}
+
+void KisSyncedAudioPlayback::stop()
+{
+ m_d->player.stop();
+}
+
+void KisSyncedAudioPlayback::slotOnError()
+{
+#ifdef HAVE_QT_MULTIMEDIA
+ emit error(m_d->player.media().canonicalUrl().toLocalFile(), m_d->player.errorString());
+#endif
+}
+
+#ifndef HAVE_QT_MULTIMEDIA
+#include "KisSyncedAudioPlayback.moc"
+#endif
diff --git a/libs/ui/KisSyncedAudioPlayback.h b/libs/ui/KisSyncedAudioPlayback.h
new file mode 100644
index 0000000000..2286a934f0
--- /dev/null
+++ b/libs/ui/KisSyncedAudioPlayback.h
@@ -0,0 +1,37 @@
+#ifndef KISSYNCEDAUDIOPLAYBACK_H
+#define KISSYNCEDAUDIOPLAYBACK_H
+
+#include
+#include
+
+class KisSyncedAudioPlayback : public QObject
+{
+ Q_OBJECT
+public:
+ KisSyncedAudioPlayback(const QString &fileName);
+ virtual ~KisSyncedAudioPlayback();
+
+ void setSoundOffsetTolerance(qint64 value);
+ void syncWithVideo(qint64 position);
+
+ bool isPlaying() const;
+
+ void setVolume(qreal value);
+
+public Q_SLOTS:
+ void setSpeed(qreal value);
+ void play(qint64 startPosition);
+ void stop();
+
+Q_SIGNALS:
+ void error(const QString &filename, const QString &message);
+
+private Q_SLOTS:
+ void slotOnError();
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
+};
+
+#endif // KISSYNCEDAUDIOPLAYBACK_H
diff --git a/libs/ui/canvas/kis_animation_player.cpp b/libs/ui/canvas/kis_animation_player.cpp
index 116a7f3569..5641c603de 100644
--- a/libs/ui/canvas/kis_animation_player.cpp
+++ b/libs/ui/canvas/kis_animation_player.cpp
@@ -1,383 +1,529 @@
/*
* Copyright (c) 2015 Jouni Pentikäinen
*
* 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_animation_player.h"
#include
#include
#include
//#define PLAYER_DEBUG_FRAMERATE
#include "kis_global.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_image.h"
#include "kis_canvas2.h"
#include "kis_animation_frame_cache.h"
#include "kis_signal_auto_connection.h"
#include "kis_image_animation_interface.h"
#include "kis_time_range.h"
#include "kis_signal_compressor.h"
+#include
+#include
#include
#include
#include
+#include "KisSyncedAudioPlayback.h"
+#include "kis_signal_compressor_with_param.h"
+
+#include "KisViewManager.h"
+#include "kis_icon_utils.h"
+
+
using namespace boost::accumulators;
typedef accumulator_set > FpsAccumulator;
struct KisAnimationPlayer::Private
{
public:
Private(KisAnimationPlayer *_q)
: q(_q),
realFpsAccumulator(tag::rolling_window::window_size = 24),
droppedFpsAccumulator(tag::rolling_window::window_size = 24),
droppedFramesPortion(tag::rolling_window::window_size = 24),
dropFramesMode(true),
nextFrameExpectedTime(0),
expectedInterval(0),
expectedFrame(0),
lastTimerInterval(0),
lastPaintedFrame(0),
- playbackStatisticsCompressor(1000, KisSignalCompressor::FIRST_INACTIVE)
+ playbackStatisticsCompressor(1000, KisSignalCompressor::FIRST_INACTIVE),
+ stopAudioOnScrubbingCompressor(100, KisSignalCompressor::POSTPONE),
+ audioOffsetTolerance(-1)
{}
KisAnimationPlayer *q;
bool useFastFrameUpload;
bool playing;
QTimer *timer;
int initialFrame;
int firstFrame;
int lastFrame;
- int fps;
qreal playbackSpeed;
KisCanvas2 *canvas;
KisSignalAutoConnectionsStore cancelStrokeConnections;
QElapsedTimer realFpsTimer;
FpsAccumulator realFpsAccumulator;
FpsAccumulator droppedFpsAccumulator;
FpsAccumulator droppedFramesPortion;
bool dropFramesMode;
QElapsedTimer playbackTime;
int nextFrameExpectedTime;
int expectedInterval;
int expectedFrame;
int lastTimerInterval;
int lastPaintedFrame;
KisSignalCompressor playbackStatisticsCompressor;
+ QScopedPointer syncedAudio;
+ QScopedPointer > audioSyncScrubbingCompressor;
+ KisSignalCompressor stopAudioOnScrubbingCompressor;
+
+ int audioOffsetTolerance;
+
void stopImpl(bool doUpdates);
int incFrame(int frame, int inc) {
frame += inc;
if (frame > lastFrame) {
frame = firstFrame + frame - lastFrame - 1;
}
return frame;
}
+
+ qint64 frameToMSec(int value, int fps) {
+ return qreal(value) / fps * 1000.0;
+ }
+ int msecToFrame(qint64 value, int fps) {
+ return qreal(value) * fps / 1000.0;
+ }
};
KisAnimationPlayer::KisAnimationPlayer(KisCanvas2 *canvas)
: QObject(canvas)
, m_d(new Private(this))
{
m_d->useFastFrameUpload = false;
m_d->playing = false;
- m_d->fps = 15;
m_d->canvas = canvas;
m_d->playbackSpeed = 1.0;
m_d->timer = new QTimer(this);
connect(m_d->timer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
m_d->timer->setSingleShot(true);
connect(KisConfigNotifier::instance(),
SIGNAL(dropFramesModeChanged()),
SLOT(slotUpdateDropFramesMode()));
slotUpdateDropFramesMode();
connect(&m_d->playbackStatisticsCompressor, SIGNAL(timeout()),
this, SIGNAL(sigPlaybackStatisticsUpdated()));
+
+ using namespace std::placeholders;
+ std::function callback(
+ std::bind(&KisAnimationPlayer::slotSyncScrubbingAudio, this, _1));
+
+ const int defaultScrubbingUdpatesDelay = 40; /* 40 ms == 25 fps */
+
+ m_d->audioSyncScrubbingCompressor.reset(
+ new KisSignalCompressorWithParam(defaultScrubbingUdpatesDelay, callback, KisSignalCompressor::FIRST_ACTIVE));
+
+ m_d->stopAudioOnScrubbingCompressor.setDelay(defaultScrubbingUdpatesDelay);
+ connect(&m_d->stopAudioOnScrubbingCompressor, SIGNAL(timeout()), SLOT(slotTryStopScrubbingAudio()));
+
+ connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigFramerateChanged()), SLOT(slotUpdateAudioChunkLength()));
+ slotUpdateAudioChunkLength();
+
+ connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioChannelChanged()), SLOT(slotAudioChannelChanged()));
+ connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SLOT(slotAudioVolumeChanged()));
+ slotAudioChannelChanged();
}
KisAnimationPlayer::~KisAnimationPlayer()
{}
void KisAnimationPlayer::slotUpdateDropFramesMode()
{
KisConfig cfg;
m_d->dropFramesMode = cfg.animationDropFrames();
}
+void KisAnimationPlayer::slotSyncScrubbingAudio(int msecTime)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->syncedAudio);
+
+ if (!m_d->syncedAudio->isPlaying()) {
+ m_d->syncedAudio->play(msecTime);
+ } else {
+ m_d->syncedAudio->syncWithVideo(msecTime);
+ }
+
+ if (!isPlaying()) {
+ m_d->stopAudioOnScrubbingCompressor.start();
+ }
+}
+
+void KisAnimationPlayer::slotTryStopScrubbingAudio()
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->syncedAudio);
+ if (m_d->syncedAudio && !isPlaying()) {
+ m_d->syncedAudio->stop();
+ }
+}
+
+void KisAnimationPlayer::slotAudioChannelChanged()
+{
+
+ KisImageAnimationInterface *interface = m_d->canvas->image()->animationInterface();
+ QString fileName = interface->audioChannelFileName();
+ QFileInfo info(fileName);
+ if (info.exists() && !interface->isAudioMuted()) {
+ m_d->syncedAudio.reset(new KisSyncedAudioPlayback(info.absoluteFilePath()));
+ m_d->syncedAudio->setVolume(interface->audioVolume());
+ m_d->syncedAudio->setSoundOffsetTolerance(m_d->audioOffsetTolerance);
+
+ connect(m_d->syncedAudio.data(), SIGNAL(error(const QString &, const QString &)), SLOT(slotOnAudioError(const QString &, const QString &)));
+ } else {
+ m_d->syncedAudio.reset();
+ }
+}
+
+void KisAnimationPlayer::slotAudioVolumeChanged()
+{
+ KisImageAnimationInterface *interface = m_d->canvas->image()->animationInterface();
+ if (m_d->syncedAudio) {
+ m_d->syncedAudio->setVolume(interface->audioVolume());
+ }
+}
+
+void KisAnimationPlayer::slotOnAudioError(const QString &fileName, const QString &message)
+{
+ QString errorMessage(i18nc("floating on-canvas message", "Cannot open audio: \"%1\"\nError: %2", fileName, message));
+ m_d->canvas->viewManager()->showFloatingMessage(errorMessage, KisIconUtils::loadIcon("dialog-warning"));
+}
+
void KisAnimationPlayer::connectCancelSignals()
{
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image().data(), SIGNAL(sigUndoDuringStrokeRequested()),
this, SLOT(slotCancelPlayback()));
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image().data(), SIGNAL(sigStrokeCancellationRequested()),
this, SLOT(slotCancelPlayback()));
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image().data(), SIGNAL(sigStrokeEndRequested()),
this, SLOT(slotCancelPlaybackSafe()));
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image()->animationInterface(), SIGNAL(sigFramerateChanged()),
this, SLOT(slotUpdatePlaybackTimer()));
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image()->animationInterface(), SIGNAL(sigFullClipRangeChanged()),
this, SLOT(slotUpdatePlaybackTimer()));
m_d->cancelStrokeConnections.addConnection(
m_d->canvas->image()->animationInterface(), SIGNAL(sigPlaybackRangeChanged()),
this, SLOT(slotUpdatePlaybackTimer()));
}
void KisAnimationPlayer::disconnectCancelSignals()
{
m_d->cancelStrokeConnections.clear();
}
+void KisAnimationPlayer::slotUpdateAudioChunkLength()
+{
+ const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface();
+ const int animationFramePeriod = qMax(1, 1000 / animation->framerate());
+
+ KisConfig cfg;
+ int scrubbingAudioUdpatesDelay = cfg.scrubbingAudioUpdatesDelay();
+
+ if (scrubbingAudioUdpatesDelay < 0) {
+
+ scrubbingAudioUdpatesDelay = qMax(1, animationFramePeriod);
+ }
+
+ m_d->audioSyncScrubbingCompressor->setDelay(scrubbingAudioUdpatesDelay);
+ m_d->stopAudioOnScrubbingCompressor.setDelay(scrubbingAudioUdpatesDelay);
+
+ m_d->audioOffsetTolerance = cfg.audioOffsetTolerance();
+ if (m_d->audioOffsetTolerance < 0) {
+ m_d->audioOffsetTolerance = animationFramePeriod;
+ }
+
+ if (m_d->syncedAudio) {
+ m_d->syncedAudio->setSoundOffsetTolerance(m_d->audioOffsetTolerance);
+ }
+}
+
void KisAnimationPlayer::slotUpdatePlaybackTimer()
{
m_d->timer->stop();
const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface();
const KisTimeRange &range = animation->playbackRange();
if (!range.isValid()) return;
- m_d->fps = animation->framerate();
+ const int fps = animation->framerate();
m_d->initialFrame = animation->currentUITime();
m_d->firstFrame = range.start();
m_d->lastFrame = range.end();
m_d->expectedFrame = qBound(m_d->firstFrame, m_d->expectedFrame, m_d->lastFrame);
- m_d->expectedInterval = qreal(1000) / m_d->fps / m_d->playbackSpeed;
+ m_d->expectedInterval = qreal(1000) / fps / m_d->playbackSpeed;
m_d->lastTimerInterval = m_d->expectedInterval;
+
+ if (m_d->syncedAudio) {
+ m_d->syncedAudio->setSpeed(m_d->playbackSpeed);
+ }
+
m_d->timer->start(m_d->expectedInterval);
if (m_d->playbackTime.isValid()) {
m_d->playbackTime.restart();
} else {
m_d->playbackTime.start();
}
m_d->nextFrameExpectedTime = m_d->playbackTime.elapsed() + m_d->expectedInterval;
}
void KisAnimationPlayer::play()
{
m_d->playing = true;
slotUpdatePlaybackTimer();
m_d->expectedFrame = m_d->firstFrame;
m_d->lastPaintedFrame = m_d->firstFrame;
connectCancelSignals();
+
+ if (m_d->syncedAudio) {
+ KisImageAnimationInterface *animationInterface = m_d->canvas->image()->animationInterface();
+ m_d->syncedAudio->play(m_d->frameToMSec(m_d->firstFrame, animationInterface->framerate()));
+ }
}
void KisAnimationPlayer::Private::stopImpl(bool doUpdates)
{
+ if (syncedAudio) {
+ syncedAudio->stop();
+ }
+
q->disconnectCancelSignals();
timer->stop();
playing = false;
if (doUpdates) {
KisImageAnimationInterface *animation = canvas->image()->animationInterface();
if (animation->currentUITime() == initialFrame) {
canvas->refetchDataFromImage();
} else {
animation->switchCurrentTimeAsync(initialFrame);
}
}
emit q->sigPlaybackStopped();
}
void KisAnimationPlayer::stop()
{
m_d->stopImpl(true);
}
void KisAnimationPlayer::forcedStopOnExit()
{
m_d->stopImpl(false);
}
bool KisAnimationPlayer::isPlaying()
{
return m_d->playing;
}
int KisAnimationPlayer::currentTime()
{
return m_d->lastPaintedFrame;
}
void KisAnimationPlayer::displayFrame(int time)
{
uploadFrame(time);
}
void KisAnimationPlayer::slotUpdate()
{
uploadFrame(-1);
}
void KisAnimationPlayer::uploadFrame(int frame)
{
+ KisImageAnimationInterface *animationInterface = m_d->canvas->image()->animationInterface();
+
if (frame < 0) {
const int currentTime = m_d->playbackTime.elapsed();
const int framesDiff = currentTime - m_d->nextFrameExpectedTime;
const qreal framesDiffNorm = qreal(framesDiff) / m_d->expectedInterval;
// qDebug() << ppVar(framesDiff)
// << ppVar(m_d->expectedFrame)
// << ppVar(framesDiffNorm)
// << ppVar(m_d->lastTimerInterval);
if (m_d->dropFramesMode) {
const int numDroppedFrames = qMax(0, qRound(framesDiffNorm));
frame = m_d->incFrame(m_d->expectedFrame, numDroppedFrames);
} else {
frame = m_d->expectedFrame;
}
m_d->nextFrameExpectedTime = currentTime + m_d->expectedInterval;
m_d->lastTimerInterval = qMax(0.0, m_d->lastTimerInterval - 0.5 * framesDiff);
m_d->expectedFrame = m_d->incFrame(frame, 1);
m_d->timer->start(m_d->lastTimerInterval);
m_d->playbackStatisticsCompressor.start();
}
+ if (m_d->syncedAudio) {
+ const int msecTime = m_d->frameToMSec(frame, animationInterface->framerate());
+ if (isPlaying()) {
+ slotSyncScrubbingAudio(msecTime);
+ } else {
+ m_d->audioSyncScrubbingCompressor->start(msecTime);
+ }
+ }
+
if (m_d->canvas->frameCache() && m_d->canvas->frameCache()->uploadFrame(frame)) {
m_d->canvas->updateCanvas();
m_d->useFastFrameUpload = true;
emit sigFrameChanged();
} else {
m_d->useFastFrameUpload = false;
m_d->canvas->image()->barrierLock(true);
m_d->canvas->image()->unlock();
// no OpenGL cache or the frame just not cached yet
- m_d->canvas->image()->animationInterface()->switchCurrentTimeAsync(frame);
+ animationInterface->switchCurrentTimeAsync(frame);
emit sigFrameChanged();
}
if (!m_d->realFpsTimer.isValid()) {
m_d->realFpsTimer.start();
} else {
const int elapsed = m_d->realFpsTimer.restart();
m_d->realFpsAccumulator(elapsed);
int numFrames = frame - m_d->lastPaintedFrame;
if (numFrames < 0) {
numFrames += m_d->lastFrame - m_d->firstFrame + 1;
}
m_d->droppedFramesPortion(qreal(int(numFrames != 1)));
if (numFrames > 0) {
m_d->droppedFpsAccumulator(qreal(elapsed) / numFrames);
}
#ifdef PLAYER_DEBUG_FRAMERATE
qDebug() << " RFPS:" << 1000.0 / rolling_mean(m_d->realFpsAccumulator)
<< "DFPS:" << 1000.0 / rolling_mean(m_d->droppedFpsAccumulator) << ppVar(numFrames);
#endif /* PLAYER_DEBUG_FRAMERATE */
}
m_d->lastPaintedFrame = frame;
}
qreal KisAnimationPlayer::effectiveFps() const
{
return 1000.0 / rolling_mean(m_d->droppedFpsAccumulator);
}
qreal KisAnimationPlayer::realFps() const
{
return 1000.0 / rolling_mean(m_d->realFpsAccumulator);
}
qreal KisAnimationPlayer::framesDroppedPortion() const
{
return rolling_mean(m_d->droppedFramesPortion);
}
void KisAnimationPlayer::slotCancelPlayback()
{
stop();
}
void KisAnimationPlayer::slotCancelPlaybackSafe()
{
/**
* If there is no openGL support, then we have no (!) cache at
* all. Therefore we should regenerate frame on every time switch,
* which, yeah, can be very slow. What is more important, when
* regenerating a frame animation interface will emit a
* sigStrokeEndRequested() signal and we should ignore it. That is
* not an ideal solution, because the user will be able to paint
* on random frames while playing, but it lets users with faulty
* GPUs see at least some preview of their animation.
*/
if (m_d->useFastFrameUpload) {
stop();
}
}
qreal KisAnimationPlayer::playbackSpeed()
{
return m_d->playbackSpeed;
}
void KisAnimationPlayer::slotUpdatePlaybackSpeed(double value)
{
m_d->playbackSpeed = value;
if (m_d->playing) {
slotUpdatePlaybackTimer();
}
}
diff --git a/libs/ui/canvas/kis_animation_player.h b/libs/ui/canvas/kis_animation_player.h
index 06e1d35716..a7374eb0dd 100644
--- a/libs/ui/canvas/kis_animation_player.h
+++ b/libs/ui/canvas/kis_animation_player.h
@@ -1,77 +1,85 @@
/*
* Copyright (c) 2015 Jouni Pentikäinen
*
* 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_ANIMATION_PLAYER_H
#define KIS_ANIMATION_PLAYER_H
#include
#include
#include "kritaui_export.h"
class KisCanvas2;
class KRITAUI_EXPORT KisAnimationPlayer : public QObject
{
Q_OBJECT
public:
KisAnimationPlayer(KisCanvas2 *canvas);
~KisAnimationPlayer();
void play();
void stop();
void displayFrame(int time);
bool isPlaying();
int currentTime();
qreal playbackSpeed();
void forcedStopOnExit();
qreal effectiveFps() const;
qreal realFps() const;
qreal framesDroppedPortion() const;
public Q_SLOTS:
void slotUpdate();
void slotCancelPlayback();
void slotCancelPlaybackSafe();
void slotUpdatePlaybackSpeed(double value);
void slotUpdatePlaybackTimer();
void slotUpdateDropFramesMode();
+private Q_SLOTS:
+ void slotSyncScrubbingAudio(int msecTime);
+ void slotTryStopScrubbingAudio();
+ void slotUpdateAudioChunkLength();
+ void slotAudioChannelChanged();
+ void slotAudioVolumeChanged();
+ void slotOnAudioError(const QString &fileName, const QString &message);
+
Q_SIGNALS:
void sigFrameChanged();
void sigPlaybackStopped();
void sigPlaybackStatisticsUpdated();
private:
void connectCancelSignals();
void disconnectCancelSignals();
void uploadFrame(int time);
private:
struct Private;
QScopedPointer m_d;
};
#endif
diff --git a/libs/ui/dialogs/kis_dlg_import_image_sequence.cpp b/libs/ui/dialogs/kis_dlg_import_image_sequence.cpp
index ba565435da..d518cfbc09 100644
--- a/libs/ui/dialogs/kis_dlg_import_image_sequence.cpp
+++ b/libs/ui/dialogs/kis_dlg_import_image_sequence.cpp
@@ -1,158 +1,163 @@
/*
* Copyright (c) 2016 Jouni Pentikäinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_dlg_import_image_sequence.h"
#include "KisDocument.h"
#include "KisMainWindow.h"
#include "kis_image.h"
#include "kis_image_animation_interface.h"
#include "KisImportExportManager.h"
#include "KoFileDialog.h"
#include
class KisDlgImportImageSequence::ListItem : QListWidgetItem {
public:
ListItem(const QString &text, QListWidget *view, QCollator *collator)
: QListWidgetItem(text, view),
collator(collator)
{}
bool operator <(const QListWidgetItem &other) const override
{
int cmp = collator->compare(this->text(), other.text());
return cmp < 0;
}
private:
QCollator *collator;
};
KisDlgImportImageSequence::KisDlgImportImageSequence(KisMainWindow *mainWindow, KisDocument *document) :
KoDialog(mainWindow),
m_mainWindow(mainWindow),
m_document(document)
{
setButtons(Ok | Cancel);
setDefaultButton(Ok);
QWidget * page = new QWidget(this);
m_ui.setupUi(page);
setMainWidget(page);
enableButtonOk(false);
m_ui.cmbOrder->addItem(i18n("Ascending"), Ascending);
m_ui.cmbOrder->addItem(i18n("Descending"), Descending);
m_ui.cmbOrder->setCurrentIndex(0);
m_ui.cmbSortMode->addItem(i18n("Alphabetical"), Natural);
m_ui.cmbSortMode->addItem(i18n("Numerical"), Numerical);
m_ui.cmbSortMode->setCurrentIndex(1);
m_ui.lstFiles->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(m_ui.btnAddImages, &QAbstractButton::clicked, this, &KisDlgImportImageSequence::slotAddFiles);
connect(m_ui.btnRemove, &QAbstractButton::clicked, this, &KisDlgImportImageSequence::slotRemoveFiles);
connect(m_ui.spinStep, SIGNAL(valueChanged(int)), this, SLOT(slotSkipChanged(int)));
connect(m_ui.cmbOrder, SIGNAL(currentIndexChanged(int)), this, SLOT(slotOrderOptionsChanged(int)));
connect(m_ui.cmbSortMode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotOrderOptionsChanged(int)));
+
+ // cold initialization of the controls
+ slotSkipChanged(m_ui.spinStep->value());
+ slotOrderOptionsChanged(m_ui.cmbOrder->currentIndex());
+ slotOrderOptionsChanged(m_ui.cmbSortMode->currentIndex());
}
QStringList KisDlgImportImageSequence::files()
{
QStringList list;
for (int i=0; i < m_ui.lstFiles->count(); i++) {
list.append(m_ui.lstFiles->item(i)->text());
}
return list;
}
int KisDlgImportImageSequence::firstFrame()
{
return m_ui.spinFirstFrame->value();
}
int KisDlgImportImageSequence::step()
{
return m_ui.spinStep->value();
}
void KisDlgImportImageSequence::slotAddFiles()
{
QStringList urls = showOpenFileDialog();
if (!urls.isEmpty()) {
Q_FOREACH(QString url, urls) {
new ListItem(url, m_ui.lstFiles, &m_collator);
}
sortFileList();
}
enableButtonOk(m_ui.lstFiles->count() > 0);
}
QStringList KisDlgImportImageSequence::showOpenFileDialog()
{
KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument");
dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import));
dialog.setCaption(i18n("Import Images"));
return dialog.filenames();
}
void KisDlgImportImageSequence::slotRemoveFiles()
{
QList selected = m_ui.lstFiles->selectedItems();
Q_FOREACH(QListWidgetItem *item, selected) {
delete item;
}
enableButtonOk(m_ui.lstFiles->count() > 0);
}
void KisDlgImportImageSequence::slotSkipChanged(int)
{
int documentFps = m_document->image()->animationInterface()->framerate();
float sourceFps = 1.0f * documentFps / m_ui.spinStep->value();
m_ui.lblFramerate->setText(i18n("Source fps: %1", sourceFps));
}
void KisDlgImportImageSequence::slotOrderOptionsChanged(int)
{
sortFileList();
}
void KisDlgImportImageSequence::sortFileList()
{
int order = m_ui.cmbOrder->currentData().toInt();
bool numeric = m_ui.cmbSortMode->currentData().toInt() == Numerical;
m_collator.setNumericMode(numeric);
m_ui.lstFiles->sortItems((order == Ascending) ? Qt::AscendingOrder : Qt::DescendingOrder);
}
diff --git a/libs/ui/kis_animation_exporter.cpp b/libs/ui/kis_animation_exporter.cpp
index 513a826ec6..1aed326ac1 100644
--- a/libs/ui/kis_animation_exporter.cpp
+++ b/libs/ui/kis_animation_exporter.cpp
@@ -1,334 +1,385 @@
/*
* Copyright (c) 2015 Jouni Pentikäinen
*
* 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_animation_exporter.h"
#include
#include
#include
#include
+#include
#include "KoFileDialog.h"
#include "KisDocument.h"
#include "kis_image.h"
#include "KisImportExportManager.h"
#include "kis_image_animation_interface.h"
#include "KisPart.h"
#include "KisMainWindow.h"
#include "kis_paint_layer.h"
#include "kis_group_layer.h"
#include "kis_time_range.h"
#include "kis_painter.h"
#include "kis_image_lock_hijacker.h"
struct KisAnimationExporterUI::Private
{
QWidget *parentWidget;
KisAnimationExportSaver *exporter;
Private(QWidget *parent)
: parentWidget(parent),
exporter(0)
{}
};
KisAnimationExporterUI::KisAnimationExporterUI(QWidget *parent)
: m_d(new Private(parent))
{
}
KisAnimationExporterUI::~KisAnimationExporterUI()
{
if (m_d->exporter) {
delete m_d->exporter;
}
}
KisImportExportFilter::ConversionStatus KisAnimationExporterUI::exportSequence(KisDocument *document)
{
KoFileDialog dialog(m_d->parentWidget, KoFileDialog::SaveFile, "exportsequence");
dialog.setCaption(i18n("Export sequence"));
dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Export));
QString filename = dialog.filename();
// if the user presses cancel, it returns empty
if (filename.isEmpty()) return KisImportExportFilter::UserCancelled;
const KisTimeRange fullClipRange = document->image()->animationInterface()->fullClipRange();
int firstFrame = fullClipRange.start();
int lastFrame = fullClipRange.end();
m_d->exporter = new KisAnimationExportSaver(document, filename, firstFrame, lastFrame);
return m_d->exporter->exportAnimation();
}
struct KisAnimationExporter::Private
{
Private(KisDocument *document, int fromTime, int toTime)
: document(document)
, image(document->image())
, firstFrame(fromTime)
, lastFrame(toTime)
, currentFrame(-1)
, batchMode(document->fileBatchMode())
, isCancelled(false)
, status(KisImportExportFilter::OK)
, tmpDevice(new KisPaintDevice(image->colorSpace()))
{
}
KisDocument *document;
KisImageWSP image;
int firstFrame;
int lastFrame;
int currentFrame;
bool batchMode;
bool isCancelled;
KisImportExportFilter::ConversionStatus status;
SaveFrameCallback saveFrameCallback;
KisPaintDeviceSP tmpDevice;
KisPropertiesConfigurationSP exportConfiguration;
};
KisAnimationExporter::KisAnimationExporter(KisDocument *document, int fromTime, int toTime)
: m_d(new Private(document, fromTime, toTime))
{
connect(m_d->image->animationInterface(), SIGNAL(sigFrameReady(int)),
this, SLOT(frameReadyToCopy(int)), Qt::DirectConnection);
connect(this, SIGNAL(sigFrameReadyToSave()),
this, SLOT(frameReadyToSave()), Qt::QueuedConnection);
}
KisAnimationExporter::~KisAnimationExporter()
{
}
void KisAnimationExporter::setExportConfiguration(KisPropertiesConfigurationSP exportConfiguration)
{
m_d->exportConfiguration = exportConfiguration;
}
void KisAnimationExporter::setSaveFrameCallback(SaveFrameCallback func)
{
m_d->saveFrameCallback = func;
}
KisImportExportFilter::ConversionStatus KisAnimationExporter::exportAnimation()
{
QScopedPointer progress;
if (!m_d->batchMode) {
QString message = i18n("Export frames...");
progress.reset(new QProgressDialog(message, "", 0, 0, KisPart::instance()->currentMainwindow()));
progress->setWindowModality(Qt::ApplicationModal);
progress->setCancelButton(0);
progress->setMinimumDuration(0);
progress->setValue(0);
emit m_d->document->statusBarMessage(message);
emit m_d->document->sigProgress(0);
connect(m_d->document, SIGNAL(sigProgressCanceled()), this, SLOT(cancel()));
}
/**
* HACK ALERT: Here we remove the image lock! We do it in a GUI
* thread under the barrier lock held, so it is
* guaranteed no other stroke will accidentally be
* started by this. And showing an app-modal dialog to
* the user will prevent him from doing anything
* nasty.
*/
KisImageLockHijacker badGuy(m_d->image);
Q_UNUSED(badGuy);
KIS_ASSERT_RECOVER(!m_d->image->locked()) { return KisImportExportFilter::InternalError; }
m_d->status = KisImportExportFilter::OK;
m_d->currentFrame = m_d->firstFrame;
m_d->image->animationInterface()->requestFrameRegeneration(m_d->currentFrame, m_d->image->bounds());
QEventLoop loop;
loop.connect(this, SIGNAL(sigFinished()), SLOT(quit()));
loop.exec();
if (!m_d->batchMode) {
disconnect(m_d->document, SIGNAL(sigProgressCanceled()), this, SLOT(cancel()));
emit m_d->document->sigProgress(100);
emit m_d->document->clearStatusBarMessage();
progress.reset();
}
return m_d->status;
}
void KisAnimationExporter::cancel()
{
m_d->isCancelled = true;
}
void KisAnimationExporter::frameReadyToCopy(int time)
{
if (time != m_d->currentFrame) return;
QRect rc = m_d->image->bounds();
KisPainter::copyAreaOptimized(rc.topLeft(), m_d->image->projection(), m_d->tmpDevice, rc);
emit sigFrameReadyToSave();
}
void KisAnimationExporter::frameReadyToSave()
{
KIS_ASSERT_RECOVER(m_d->saveFrameCallback) {
m_d->status = KisImportExportFilter::InternalError;
emit sigFinished();
return;
}
if (m_d->isCancelled) {
m_d->status = KisImportExportFilter::UserCancelled;
emit sigFinished();
return;
}
KisImportExportFilter::ConversionStatus result =
KisImportExportFilter::OK;
int time = m_d->currentFrame;
result = m_d->saveFrameCallback(time, m_d->tmpDevice, m_d->exportConfiguration);
if (!m_d->batchMode) {
emit m_d->document->sigProgress((time - m_d->firstFrame) * 100 /
(m_d->lastFrame - m_d->firstFrame));
}
qDebug() << result << time << m_d->lastFrame;
if (result == KisImportExportFilter::OK && time < m_d->lastFrame) {
m_d->currentFrame = time + 1;
m_d->image->animationInterface()->requestFrameRegeneration(m_d->currentFrame, m_d->image->bounds());
} else {
emit sigFinished();
}
}
struct KisAnimationExportSaver::Private
{
Private(KisDocument *document, int fromTime, int toTime, int _sequenceNumberingOffset)
: document(document)
, image(document->image())
, firstFrame(fromTime)
, lastFrame(toTime)
, sequenceNumberingOffset(_sequenceNumberingOffset)
, tmpDoc(KisPart::instance()->createDocument())
, exporter(document, fromTime, toTime)
{
tmpDoc->setAutoSaveDelay(0);
tmpImage = new KisImage(tmpDoc->createUndoStore(),
image->bounds().width(),
image->bounds().height(),
image->colorSpace(),
QString());
tmpImage->setResolution(image->xRes(), image->yRes());
tmpDoc->setCurrentImage(tmpImage);
KisPaintLayer* paintLayer = new KisPaintLayer(tmpImage, "paint device", 255);
tmpImage->addNode(paintLayer, tmpImage->rootLayer(), KisLayerSP(0));
tmpDevice = paintLayer->paintDevice();
}
KisDocument *document;
KisImageWSP image;
int firstFrame;
int lastFrame;
int sequenceNumberingOffset;
QScopedPointer tmpDoc;
KisImageSP tmpImage;
KisPaintDeviceSP tmpDevice;
KisAnimationExporter exporter;
QString filenamePrefix;
QString filenameSuffix;
};
KisAnimationExportSaver::KisAnimationExportSaver(KisDocument *document, const QString &baseFilename, int fromTime, int toTime, int sequenceNumberingOffset)
: m_d(new Private(document, fromTime, toTime, sequenceNumberingOffset))
{
int baseLength = baseFilename.lastIndexOf(".");
if (baseLength > -1) {
m_d->filenamePrefix = baseFilename.left(baseLength);
m_d->filenameSuffix = baseFilename.right(baseFilename.length() - baseLength);
} else {
m_d->filenamePrefix = baseFilename;
}
QString mimefilter = KisMimeDatabase::mimeTypeForFile(baseFilename);
m_d->tmpDoc->setOutputMimeType(mimefilter.toLatin1());
m_d->tmpDoc->setFileBatchMode(true);
using namespace std::placeholders; // For _1 placeholder
m_d->exporter.setSaveFrameCallback(std::bind(&KisAnimationExportSaver::saveFrameCallback, this, _1, _2, _3));
}
KisAnimationExportSaver::~KisAnimationExportSaver()
{
}
KisImportExportFilter::ConversionStatus KisAnimationExportSaver::exportAnimation(KisPropertiesConfigurationSP cfg)
{
+ QFileInfo info(savedFilesMask());
+
+ QDir dir(info.absolutePath());
+ QStringList filesList = dir.entryList({ info.fileName() });
+
+ if (!filesList.isEmpty()) {
+ if (m_d->document->fileBatchMode()) {
+ return KisImportExportFilter::CreationError;
+ }
+
+ QStringList truncatedList = filesList;
+
+ while (truncatedList.size() > 3) {
+ truncatedList.takeLast();
+ }
+
+ QString exampleFiles = truncatedList.join(", ");
+ if (truncatedList.size() != filesList.size()) {
+ exampleFiles += QString(", ...");
+ }
+
+ QMessageBox::StandardButton result =
+ QMessageBox::warning(0,
+ i18n("Delete old frames?"),
+ i18n("Frames with the same naming "
+ "scheme exist in the destination "
+ "directory. They are going to be "
+ "deleted, continue?\n\n"
+ "Directory: %1\n"
+ "Files: %2",
+ info.absolutePath(), exampleFiles),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+
+ if (result == QMessageBox::Yes) {
+ Q_FOREACH (const QString &file, filesList) {
+ if (!dir.remove(file)) {
+ QMessageBox::critical(0,
+ i18n("Failed to delete"),
+ i18n("Failed to delete an old frame file:\n\n"
+ "%1\n\n"
+ "Rendering cancelled.", dir.absoluteFilePath(file)));
+ return KisImportExportFilter::CreationError;
+ }
+ }
+ } else {
+ return KisImportExportFilter::UserCancelled;
+ }
+ }
+
m_d->exporter.setExportConfiguration(cfg);
return m_d->exporter.exportAnimation();
}
KisImportExportFilter::ConversionStatus KisAnimationExportSaver::saveFrameCallback(int time, KisPaintDeviceSP frame, KisPropertiesConfigurationSP exportConfiguration)
{
KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK;
- QString frameNumber = QString("%1").arg(time + m_d->sequenceNumberingOffset, 4, 10, QChar('0'));
+ QString frameNumber = QString("%1").arg(time - m_d->firstFrame + m_d->sequenceNumberingOffset, 4, 10, QChar('0'));
QString filename = m_d->filenamePrefix + frameNumber + m_d->filenameSuffix;
QRect rc = m_d->image->bounds();
KisPainter::copyAreaOptimized(rc.topLeft(), frame, m_d->tmpDevice, rc);
if (!m_d->tmpDoc->exportDocument(QUrl::fromLocalFile(filename), exportConfiguration)) {
status = KisImportExportFilter::InternalError;
}
return status;
}
QString KisAnimationExportSaver::savedFilesMask() const
{
- return m_d->filenamePrefix + "%04d" + m_d->filenameSuffix;
+ return m_d->filenamePrefix + "????" + m_d->filenameSuffix;
}
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index 4aa7b7c960..b419827e05 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1,1798 +1,1818 @@
/*
* 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 "kis_canvas_resource_provider.h"
#include "kis_config_notifier.h"
#include "kis_snap_config.h"
#include
#include
KisConfig::KisConfig()
: m_cfg( KSharedConfig::openConfig()->group(""))
{
}
KisConfig::~KisConfig()
{
if (qApp->thread() != QThread::currentThread()) {
//dbgKrita << "WARNING: KisConfig: requested config synchronization from nonGUI thread! Skipping...";
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);
}
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);
}
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;
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::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::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 canvasState = m_cfg.readEntry("canvasState", "OPENGL_SUCCESS");
return (m_cfg.readEntry("useOpenGL", true) && (canvasState == "OPENGL_SUCCESS" || canvasState == "TRY_OPENGL"));
}
void KisConfig::setUseOpenGL(bool useOpenGL) const
{
m_cfg.writeEntry("useOpenGL", useOpenGL);
}
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());
}
qint32 KisConfig::maxNumberOfThreads(bool defaultValue) const
{
return (defaultValue ? QThread::idealThreadCount() : m_cfg.readEntry("maxthreads", QThread::idealThreadCount()));
}
void KisConfig::setMaxNumberOfThreads(qint32 maxThreads)
{
m_cfg.writeEntry("maxthreads", maxThreads);
}
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);
}
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()));
}
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());
}
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);
}
QColor KisConfig::selectionOverlayMaskColor(bool defaultValue) const
{
QColor def(255, 0, 0, 220);
return (defaultValue ? def : m_cfg.readEntry("selectionOverlayMaskColor", def));
}
void KisConfig::setSelectionOverlayMaskColor(const QColor &color)
{
m_cfg.writeEntry("selectionOverlayMaskColor", color);
}
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::hideSplashScreen(bool defaultValue) const
{
KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen");
return (defaultValue ? true : cfg.readEntry("HideSplashAfterStartup", true));
}
void KisConfig::setHideSplashScreen(bool hideSplashScreen) const
{
KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen");
cfg.writeEntry("HideSplashAfterStartup", hideSplashScreen);
}
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
{
return (defaultValue ? "OPENGL_NOT_TRIED" : m_cfg.readEntry("canvasState", "OPENGL_NOT_TRIED"));
}
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)) {
m_cfg.writeEntry("canvasState", state);
m_cfg.sync();
}
}
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);
}
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 ? 30 : m_cfg.readEntry("presetIconSize", 30));
}
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::showDockerTitleBars(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("showDockerTitleBars", true));
}
void KisConfig::setShowDockerTitleBars(const bool value) const
{
m_cfg.writeEntry("showDockerTitleBars", 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::exportConfiguration(const QString &filterId, bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("ExportConfiguration-" + filterId, QString()));
}
void KisConfig::setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
{
QString exportConfig = properties->toXML();
m_cfg.writeEntry("ExportConfiguration-" + filterId, exportConfig);
}
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);
}
KisConfig::OcioColorManagementMode
KisConfig::ocioColorManagementMode(bool defaultValue) const
{
return (OcioColorManagementMode)(defaultValue ? INTERNAL
: m_cfg.readEntry("Krita/Ocio/OcioColorManagementMode", (int) INTERNAL));
}
void KisConfig::setOcioColorManagementMode(OcioColorManagementMode mode) const
{
m_cfg.writeEntry("Krita/Ocio/OcioColorManagementMode", (int) mode);
}
QString KisConfig::ocioConfigurationPath(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("Krita/Ocio/OcioConfigPath", QString()));
}
void KisConfig::setOcioConfigurationPath(const QString &path) const
{
m_cfg.writeEntry("Krita/Ocio/OcioConfigPath", path);
}
QString KisConfig::ocioLutPath(bool defaultValue) const
{
return (defaultValue ? QString() : m_cfg.readEntry("Krita/Ocio/OcioLutPath", QString()));
}
void KisConfig::setOcioLutPath(const QString &path) const
{
m_cfg.writeEntry("Krita/Ocio/OcioLutPath", path);
}
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", QString()));
}
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);
}
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 ? LAYER : m_cfg.readEntry("BackgroundStyleForNewImage", (int)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::paletteDockerPaletteViewSectionSize(bool defaultValue) const
{
return (defaultValue ? 12 : m_cfg.readEntry("paletteDockerPaletteViewSectionSize", 12));
}
void KisConfig::setPaletteDockerPaletteViewSectionSize(int value) const
{
m_cfg.writeEntry("paletteDockerPaletteViewSectionSize", 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::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);
}
bool KisConfig::useVerboseOpenGLDebugOutput(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("useVerboseOpenGLDebugOutput", false));
}
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);
}
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::enableOpenGLDebugging(bool defaultValue) const
{
return (defaultValue ? false : m_cfg.readEntry("enableOpenGLDebugging", false));
}
void KisConfig::setEnableOpenGLDebugging(bool value) const
{
m_cfg.writeEntry("enableOpenGLDebugging", 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::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::scribbingUpdatesDelay(bool defaultValue) const
+int KisConfig::scrubbingUpdatesDelay(bool defaultValue) const
{
- return (defaultValue ? 30 : m_cfg.readEntry("scribbingUpdatesDelay", 30));
+ return (defaultValue ? 30 : m_cfg.readEntry("scrubbingUpdatesDelay", 30));
}
-void KisConfig::setScribbingUpdatesDelay(int value)
+void KisConfig::setScrubbingUpdatesDelay(int value)
{
- m_cfg.writeEntry("scribbingUpdatesDelay", 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);
}
int KisConfig::stabilizerDelayedPaintInterval(bool defaultValue) const
{
const int defaultInterval = 20;
return defaultValue ?
defaultInterval : m_cfg.readEntry("stabilizerDelayedPaintInterval", defaultInterval);
}
void KisConfig::setStabilizerDelayedPaintInterval(int value)
{
m_cfg.writeEntry("stabilizerDelayedPaintInterval", value);
}
QString KisConfig::customFFMpegPath(bool defaultValue) const
{
return defaultValue ? QString() : m_cfg.readEntry("ffmpegExecutablePath", QString());
}
void KisConfig::setCustomFFMpegPath(const QString &value) const
{
m_cfg.writeEntry("ffmpegExecutablePath", value);
}
bool KisConfig::showBrushHud(bool defaultValue) const
{
return defaultValue ? false : m_cfg.readEntry("showBrushHud", false);
}
void KisConfig::setShowBrushHud(bool value)
{
m_cfg.writeEntry("showBrushHud", value);
}
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 \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);
}
#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(), QHash());
} else {
QString blackColor = "\n\n \n \n";
doc.setContent(blackColor);
QDomElement e = doc.documentElement().firstChild().toElement();
return KoColor::fromXML(e, Integer16BitsColorDepthID.id(), QHash());
}
return color;
}
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
index 0854cd3d0c..f8dffd6221 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -1,540 +1,546 @@
/*
* 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.
*/
#ifndef KIS_CONFIG_H_
#define KIS_CONFIG_H_
#include
#include
#include
#include
#include
#include
#include "kis_global.h"
#include "kis_properties_configuration.h"
#include "kritaui_export.h"
class KoColorProfile;
class KoColorSpace;
class KisSnapConfig;
class KRITAUI_EXPORT KisConfig
{
public:
KisConfig();
~KisConfig();
bool disableTouchOnCanvas(bool defaultValue = false) const;
void setDisableTouchOnCanvas(bool value) const;
bool useProjections(bool defaultValue = false) const;
void setUseProjections(bool useProj) const;
bool undoEnabled(bool defaultValue = false) const;
void setUndoEnabled(bool undo) const;
int undoStackLimit(bool defaultValue = false) const;
void setUndoStackLimit(int limit) const;
bool useCumulativeUndoRedo(bool defaultValue = false) const;
void setCumulativeUndoRedo(bool value);
double stackT1(bool defaultValue = false) const;
void setStackT1(int T1);
double stackT2(bool defaultValue = false) const;
void setStackT2(int T2);
int stackN(bool defaultValue = false) const;
void setStackN(int N);
qint32 defImageWidth(bool defaultValue = false) const;
void defImageWidth(qint32 width) const;
qint32 defImageHeight(bool defaultValue = false) const;
void defImageHeight(qint32 height) const;
qreal defImageResolution(bool defaultValue = false) const;
void defImageResolution(qreal res) const;
/**
* @return the id of the default color model used for creating new images.
*/
QString defColorModel(bool defaultValue = false) const;
/**
* set the id of the default color model used for creating new images.
*/
void defColorModel(const QString & model) const;
/**
* @return the id of the default color depth used for creating new images.
*/
QString defaultColorDepth(bool defaultValue = false) const;
/**
* set the id of the default color depth used for creating new images.
*/
void setDefaultColorDepth(const QString & depth) const;
/**
* @return the id of the default color profile used for creating new images.
*/
QString defColorProfile(bool defaultValue = false) const;
/**
* set the id of the default color profile used for creating new images.
*/
void defColorProfile(const QString & depth) const;
CursorStyle newCursorStyle(bool defaultValue = false) const;
void setNewCursorStyle(CursorStyle style);
OutlineStyle newOutlineStyle(bool defaultValue = false) const;
void setNewOutlineStyle(OutlineStyle style);
QRect colorPreviewRect() const;
void setColorPreviewRect(const QRect &rect);
/// get the profile the user has selected for the given screen
QString monitorProfile(int screen) const;
void setMonitorProfile(int screen, const QString & monitorProfile, bool override) const;
QString monitorForScreen(int screen, const QString &defaultMonitor, bool defaultValue = true) const;
void setMonitorForScreen(int screen, const QString& monitor);
/// Get the actual profile to be used for the given screen, which is
/// either the screen profile set by the color management system or
/// the custom monitor profile set by the user, depending on the configuration
const KoColorProfile *displayProfile(int screen) const;
QString workingColorSpace(bool defaultValue = false) const;
void setWorkingColorSpace(const QString & workingColorSpace) const;
QString importProfile(bool defaultValue = false) const;
void setImportProfile(const QString & importProfile) const;
QString printerColorSpace(bool defaultValue = false) const;
void setPrinterColorSpace(const QString & printerColorSpace) const;
QString printerProfile(bool defaultValue = false) const;
void setPrinterProfile(const QString & printerProfile) const;
bool useBlackPointCompensation(bool defaultValue = false) const;
void setUseBlackPointCompensation(bool useBlackPointCompensation) const;
bool allowLCMSOptimization(bool defaultValue = false) const;
void setAllowLCMSOptimization(bool allowLCMSOptimization);
void writeKoColor(const QString& name, const KoColor& color) const;
KoColor readKoColor(const QString& name, const KoColor& color = KoColor()) const;
bool showRulers(bool defaultValue = false) const;
void setShowRulers(bool rulers) const;
bool rulersTrackMouse(bool defaultValue = false) const;
void setRulersTrackMouse(bool value) const;
qint32 pasteBehaviour(bool defaultValue = false) const;
void setPasteBehaviour(qint32 behaviour) const;
qint32 monitorRenderIntent(bool defaultValue = false) const;
void setRenderIntent(qint32 monitorRenderIntent) const;
bool useOpenGL(bool defaultValue = false) const;
void setUseOpenGL(bool useOpenGL) const;
int openGLFilteringMode(bool defaultValue = false) const;
void setOpenGLFilteringMode(int filteringMode);
bool useOpenGLTextureBuffer(bool defaultValue = false) const;
void setUseOpenGLTextureBuffer(bool useBuffer);
bool disableVSync(bool defaultValue = false) const;
void setDisableVSync(bool disableVSync);
bool showAdvancedOpenGLSettings(bool defaultValue = false) const;
bool forceOpenGLFenceWorkaround(bool defaultValue = false) const;
int numMipmapLevels(bool defaultValue = false) const;
int openGLTextureSize(bool defaultValue = false) const;
int textureOverlapBorder() const;
qint32 maxNumberOfThreads(bool defaultValue = false) const;
void setMaxNumberOfThreads(qint32 numberOfThreads);
quint32 getGridMainStyle(bool defaultValue = false) const;
void setGridMainStyle(quint32 v) const;
quint32 getGridSubdivisionStyle(bool defaultValue = false) const;
void setGridSubdivisionStyle(quint32 v) const;
QColor getGridMainColor(bool defaultValue = false) const;
void setGridMainColor(const QColor & v) const;
QColor getGridSubdivisionColor(bool defaultValue = false) const;
void setGridSubdivisionColor(const QColor & v) const;
quint32 guidesLineStyle(bool defaultValue = false) const;
void setGuidesLineStyle(quint32 v) const;
QColor guidesColor(bool defaultValue = false) const;
void setGuidesColor(const QColor & v) const;
void loadSnapConfig(KisSnapConfig *config, bool defaultValue = false) const;
void saveSnapConfig(const KisSnapConfig &config);
qint32 checkSize(bool defaultValue = false) const;
void setCheckSize(qint32 checkSize) const;
bool scrollCheckers(bool defaultValue = false) const;
void setScrollingCheckers(bool scollCheckers) const;
QColor checkersColor1(bool defaultValue = false) const;
void setCheckersColor1(const QColor & v) const;
QColor checkersColor2(bool defaultValue = false) const;
void setCheckersColor2(const QColor & v) const;
QColor canvasBorderColor(bool defaultValue = false) const;
void setCanvasBorderColor(const QColor &color) const;
bool hideScrollbars(bool defaultValue = false) const;
void setHideScrollbars(bool value) const;
bool antialiasCurves(bool defaultValue = false) const;
void setAntialiasCurves(bool v) const;
QColor selectionOverlayMaskColor(bool defaultValue = false) const;
void setSelectionOverlayMaskColor(const QColor &color);
bool antialiasSelectionOutline(bool defaultValue = false) const;
void setAntialiasSelectionOutline(bool v) const;
bool showRootLayer(bool defaultValue = false) const;
void setShowRootLayer(bool showRootLayer) const;
bool showGlobalSelection(bool defaultValue = false) const;
void setShowGlobalSelection(bool showGlobalSelection) const;
bool showOutlineWhilePainting(bool defaultValue = false) const;
void setShowOutlineWhilePainting(bool showOutlineWhilePainting) const;
bool hideSplashScreen(bool defaultValue = false) const;
void setHideSplashScreen(bool hideSplashScreen) const;
qreal outlineSizeMinimum(bool defaultValue = false) const;
void setOutlineSizeMinimum(qreal outlineSizeMinimum) const;
qreal selectionViewSizeMinimum(bool defaultValue = false) const;
void setSelectionViewSizeMinimum(qreal outlineSizeMinimum) const;
int autoSaveInterval(bool defaultValue = false) const;
void setAutoSaveInterval(int seconds) const;
bool backupFile(bool defaultValue = false) const;
void setBackupFile(bool backupFile) const;
bool showFilterGallery(bool defaultValue = false) const;
void setShowFilterGallery(bool showFilterGallery) const;
bool showFilterGalleryLayerMaskDialog(bool defaultValue = false) const;
void setShowFilterGalleryLayerMaskDialog(bool showFilterGallery) const;
// OPENGL_SUCCESS, TRY_OPENGL, OPENGL_NOT_TRIED, OPENGL_FAILED
QString canvasState(bool defaultValue = false) const;
void setCanvasState(const QString& state) const;
bool toolOptionsPopupDetached(bool defaultValue = false) const;
void setToolOptionsPopupDetached(bool detached) const;
bool paintopPopupDetached(bool defaultValue = false) const;
void setPaintopPopupDetached(bool detached) const;
QString pressureTabletCurve(bool defaultValue = false) const;
void setPressureTabletCurve(const QString& curveString) const;
qreal vastScrolling(bool defaultValue = false) const;
void setVastScrolling(const qreal factor) const;
int presetChooserViewMode(bool defaultValue = false) const;
void setPresetChooserViewMode(const int mode) const;
int presetIconSize(bool defaultValue = false) const;
void setPresetIconSize(const int value) const;
bool firstRun(bool defaultValue = false) const;
void setFirstRun(const bool firstRun) const;
bool clicklessSpacePan(bool defaultValue = false) const;
void setClicklessSpacePan(const bool toggle) const;
int horizontalSplitLines(bool defaultValue = false) const;
void setHorizontalSplitLines(const int numberLines) const;
int verticalSplitLines(bool defaultValue = false) const;
void setVerticalSplitLines(const int numberLines) const;
bool hideDockersFullscreen(bool defaultValue = false) const;
void setHideDockersFullscreen(const bool value) const;
bool showDockerTitleBars(bool defaultValue = false) const;
void setShowDockerTitleBars(const bool value) const;
bool showDockers(bool defaultValue = false) const;
void setShowDockers(const bool value) const;
bool showStatusBar(bool defaultValue = false) const;
void setShowStatusBar(const bool value) const;
bool hideMenuFullscreen(bool defaultValue = false) const;
void setHideMenuFullscreen(const bool value) const;
bool hideScrollbarsFullscreen(bool defaultValue = false) const;
void setHideScrollbarsFullscreen(const bool value) const;
bool hideStatusbarFullscreen(bool defaultValue = false) const;
void setHideStatusbarFullscreen(const bool value) const;
bool hideTitlebarFullscreen(bool defaultValue = false) const;
void setHideTitlebarFullscreen(const bool value) const;
bool hideToolbarFullscreen(bool defaultValue = false) const;
void setHideToolbarFullscreen(const bool value) const;
bool fullscreenMode(bool defaultValue = false) const;
void setFullscreenMode(const bool value) const;
QStringList favoriteCompositeOps(bool defaultValue = false) const;
void setFavoriteCompositeOps(const QStringList& compositeOps) const;
QString exportConfiguration(const QString &filterId, bool defaultValue = false) const;
void setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const;
bool useOcio(bool defaultValue = false) const;
void setUseOcio(bool useOCIO) const;
int favoritePresets(bool defaultValue = false) const;
void setFavoritePresets(const int value);
bool levelOfDetailEnabled(bool defaultValue = false) const;
void setLevelOfDetailEnabled(bool value);
enum OcioColorManagementMode {
INTERNAL = 0,
OCIO_CONFIG,
OCIO_ENVIRONMENT
};
OcioColorManagementMode ocioColorManagementMode(bool defaultValue = false) const;
void setOcioColorManagementMode(OcioColorManagementMode mode) const;
QString ocioConfigurationPath(bool defaultValue = false) const;
void setOcioConfigurationPath(const QString &path) const;
QString ocioLutPath(bool defaultValue = false) const;
void setOcioLutPath(const QString &path) const;
int ocioLutEdgeSize(bool defaultValue = false) const;
void setOcioLutEdgeSize(int value);
bool ocioLockColorVisualRepresentation(bool defaultValue = false) const;
void setOcioLockColorVisualRepresentation(bool value);
bool useSystemMonitorProfile(bool defaultValue = false) const;
void setUseSystemMonitorProfile(bool _useSystemMonitorProfile) const;
QString defaultPalette(bool defaultValue = false) const;
void setDefaultPalette(const QString& name) const;
QString toolbarSlider(int sliderNumber, bool defaultValue = false) const;
void setToolbarSlider(int sliderNumber, const QString &slider);
bool sliderLabels(bool defaultValue = false) const;
void setSliderLabels(bool enabled);
QString currentInputProfile(bool defaultValue = false) const;
void setCurrentInputProfile(const QString& name);
bool presetStripVisible(bool defaultValue = false) const;
void setPresetStripVisible(bool visible);
bool scratchpadVisible(bool defaultValue = false) const;
void setScratchpadVisible(bool visible);
bool showSingleChannelAsColor(bool defaultValue = false) const;
void setShowSingleChannelAsColor(bool asColor);
bool hidePopups(bool defaultValue = false) const;
void setHidePopups(bool hidepopups);
int numDefaultLayers(bool defaultValue = false) const;
void setNumDefaultLayers(int num);
quint8 defaultBackgroundOpacity(bool defaultValue = false) const;
void setDefaultBackgroundOpacity(quint8 value);
QColor defaultBackgroundColor(bool defaultValue = false) const;
void setDefaultBackgroundColor(QColor value);
enum BackgroundStyle {
LAYER = 0,
PROJECTION = 1
};
BackgroundStyle defaultBackgroundStyle(bool defaultValue = false) const;
void setDefaultBackgroundStyle(BackgroundStyle value);
int lineSmoothingType(bool defaultValue = false) const;
void setLineSmoothingType(int value);
qreal lineSmoothingDistance(bool defaultValue = false) const;
void setLineSmoothingDistance(qreal value);
qreal lineSmoothingTailAggressiveness(bool defaultValue = false) const;
void setLineSmoothingTailAggressiveness(qreal value);
bool lineSmoothingSmoothPressure(bool defaultValue = false) const;
void setLineSmoothingSmoothPressure(bool value);
bool lineSmoothingScalableDistance(bool defaultValue = false) const;
void setLineSmoothingScalableDistance(bool value);
qreal lineSmoothingDelayDistance(bool defaultValue = false) const;
void setLineSmoothingDelayDistance(qreal value);
bool lineSmoothingUseDelayDistance(bool defaultValue = false) const;
void setLineSmoothingUseDelayDistance(bool value);
bool lineSmoothingFinishStabilizedCurve(bool defaultValue = false) const;
void setLineSmoothingFinishStabilizedCurve(bool value);
bool lineSmoothingStabilizeSensors(bool defaultValue = false) const;
void setLineSmoothingStabilizeSensors(bool value);
int paletteDockerPaletteViewSectionSize(bool defaultValue = false) const;
void setPaletteDockerPaletteViewSectionSize(int value) const;
int tabletEventsDelay(bool defaultValue = false) const;
void setTabletEventsDelay(int value);
bool testingAcceptCompressedTabletEvents(bool defaultValue = false) const;
void setTestingAcceptCompressedTabletEvents(bool value);
bool shouldEatDriverShortcuts(bool defaultValue = false) const;
bool testingCompressBrushEvents(bool defaultValue = false) const;
void setTestingCompressBrushEvents(bool value);
const KoColorSpace* customColorSelectorColorSpace(bool defaultValue = false) const;
void setCustomColorSelectorColorSpace(const KoColorSpace *cs);
bool useDirtyPresets(bool defaultValue = false) const;
void setUseDirtyPresets(bool value);
bool useEraserBrushSize(bool defaultValue = false) const;
void setUseEraserBrushSize(bool value);
bool useEraserBrushOpacity(bool defaultValue = false) const;
void setUseEraserBrushOpacity(bool value);
QColor getMDIBackgroundColor(bool defaultValue = false) const;
void setMDIBackgroundColor(const QColor & v) const;
QString getMDIBackgroundImage(bool defaultValue = false) const;
void setMDIBackgroundImage(const QString & fileName) const;
bool useVerboseOpenGLDebugOutput(bool defaultValue = false) const;
int workaroundX11SmoothPressureSteps(bool defaultValue = false) const;
bool showCanvasMessages(bool defaultValue = false) const;
void setShowCanvasMessages(bool show);
bool compressKra(bool defaultValue = false) const;
void setCompressKra(bool compress);
bool toolOptionsInDocker(bool defaultValue = false) const;
void setToolOptionsInDocker(bool inDocker);
void setEnableOpenGLDebugging(bool value) const;
bool enableOpenGLDebugging(bool defaultValue = false) const;
void setEnableAmdVectorizationWorkaround(bool value);
bool enableAmdVectorizationWorkaround(bool defaultValue = false) const;
bool animationDropFrames(bool defaultValue = false) const;
void setAnimationDropFrames(bool value);
- int scribbingUpdatesDelay(bool defaultValue = false) const;
- void setScribbingUpdatesDelay(int value);
+ int scrubbingUpdatesDelay(bool defaultValue = false) const;
+ void setScrubbingUpdatesDelay(int value);
+
+ int scrubbingAudioUpdatesDelay(bool defaultValue = false) const;
+ void setScrubbingAudioUpdatesDelay(int value);
+
+ int audioOffsetTolerance(bool defaultValue = false) const;
+ void setAudioOffsetTolerance(int value);
bool switchSelectionCtrlAlt(bool defaultValue = false) const;
void setSwitchSelectionCtrlAlt(bool value);
bool convertToImageColorspaceOnImport(bool defaultValue = false) const;
void setConvertToImageColorspaceOnImport(bool value);
int stabilizerSampleSize(bool defaultValue = false) const;
void setStabilizerSampleSize(int value);
int stabilizerDelayedPaintInterval(bool defaultValue = false) const;
void setStabilizerDelayedPaintInterval(int value);
QString customFFMpegPath(bool defaultValue = false) const;
void setCustomFFMpegPath(const QString &value) const;
bool showBrushHud(bool defaultValue = false) const;
void setShowBrushHud(bool value);
QString brushHudSetting(bool defaultValue = false) const;
void setBrushHudSetting(const QString &value) const;
template
void writeEntry(const QString& name, const T& value) {
m_cfg.writeEntry(name, value);
}
template
void writeList(const QString& name, const QList& value) {
m_cfg.writeEntry(name, value);
}
template
T readEntry(const QString& name, const T& defaultValue=T()) {
return m_cfg.readEntry(name, defaultValue);
}
template
QList readList(const QString& name, const QList& defaultValue=QList()) {
return m_cfg.readEntry(name, defaultValue);
}
/// get the profile the color managment system has stored for the given screen
static const KoColorProfile* getScreenProfile(int screen);
private:
KisConfig(const KisConfig&);
KisConfig& operator=(const KisConfig&) const;
private:
mutable KConfigGroup m_cfg;
};
#endif // KIS_CONFIG_H_
diff --git a/libs/widgets/kis_file_name_requester.cpp b/libs/widgets/kis_file_name_requester.cpp
index b957c54f70..db21da770e 100644
--- a/libs/widgets/kis_file_name_requester.cpp
+++ b/libs/widgets/kis_file_name_requester.cpp
@@ -1,99 +1,103 @@
/*
* Copyright (c) 2015 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_file_name_requester.h"
#include "ui_wdg_file_name_requester.h"
#include
#include
#include "KoIcon.h"
KisFileNameRequester::KisFileNameRequester(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::WdgFileNameRequester)
, m_mode(KoFileDialog::OpenFile)
{
m_ui->setupUi(this);
m_ui->btnSelectFile->setIcon(kisIcon("folder"));
connect(m_ui->btnSelectFile, SIGNAL(clicked()), SLOT(slotSelectFile()));
connect(m_ui->txtFileName, SIGNAL(textChanged(const QString&)), SIGNAL(textChanged(const QString&)));
}
KisFileNameRequester::~KisFileNameRequester()
{
}
void KisFileNameRequester::setStartDir(const QString &path)
{
m_basePath = path;
}
void KisFileNameRequester::setFileName(const QString &path)
{
m_ui->txtFileName->setText(path);
emit fileSelected(path);
}
QString KisFileNameRequester::fileName() const
{
return m_ui->txtFileName->text();
}
void KisFileNameRequester::setMode(KoFileDialog::DialogType mode)
{
m_mode = mode;
}
KoFileDialog::DialogType KisFileNameRequester::mode() const
{
return m_mode;
}
void KisFileNameRequester::setMimeTypeFilters(const QStringList &filterList,
QString defaultFilter)
{
m_mime_filter_list = filterList;
m_mime_default_filter = defaultFilter;
}
void KisFileNameRequester::slotSelectFile()
{
KoFileDialog dialog(this, m_mode, "OpenDocument");
if (m_mode == KoFileDialog::OpenFile)
{
dialog.setCaption(i18n("Select a file to load..."));
}
else if (m_mode == KoFileDialog::OpenDirectory)
{
dialog.setCaption(i18n("Select a directory to load..."));
}
if (m_basePath.isEmpty()) {
dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
}
else {
dialog.setDefaultDir(m_basePath);
}
Q_ASSERT(!m_mime_filter_list.isEmpty());
dialog.setMimeTypeFilters(m_mime_filter_list, m_mime_default_filter);
- setFileName(dialog.filename());
+ QString newFileName = dialog.filename();
+
+ if (!newFileName.isEmpty()) {
+ setFileName(newFileName);
+ }
}
diff --git a/packaging/language_tarball/create-l10n-symlink b/packaging/language_tarball/create-l10n-symlink
deleted file mode 100755
index a0b74167a7..0000000000
--- a/packaging/language_tarball/create-l10n-symlink
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-if [ -z $1 ]; then
- echo "Usage: $0 NEW_I18N_FILENAME"
- exit 1
-fi
-
-
-CURRENT_FILE=~/web/build/krita-3.0-l10n-win-current.tar.gz
-NEW_FILE=~/web/build/$1
-
-if [ ! -f $NEW_FILE ]; then
- echo "File not exists: $NEW_FILE"
- exit 2
-fi
-
-if [ -e $CURRENT_FILE ]; then
- rm $CURRENT_FILE
-fi
-
-ln -s $NEW_FILE $CURRENT_FILE
-
diff --git a/packaging/language_tarball/l10n-gen b/packaging/language_tarball/l10n-gen
deleted file mode 100755
index 71e98b8cd7..0000000000
--- a/packaging/language_tarball/l10n-gen
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import os
-import optparse
-import subprocess
-import re
-import requests
-import fnmatch
-import shutil
-import tarfile
-import datetime
-import subprocess
-from tempfile import TemporaryDirectory
-
-class OptionParser(optparse.OptionParser):
- def __init__(self):
- super().__init__(self.usage)
-
- self.add_option('--ppa-testing', action="store_true", dest='ppa_testing')
- self.add_option('--ppa-2.9', action="store_true", dest='ppa_2_9')
- self.add_option('--win-2.9', action="store_true", dest='win_2_9')
- self.add_option('--win-3.0', action="store_true", dest='win_3_0')
-
- def parse(self):
- (self.options, self.args) = self.parse_args()
-
- usage = ''
-
-
-def get(filename, target, branch, base = 'svn://anonsvn.kde.org/home/kde'):
- print('GET: ' + os.path.join(target, filename), end='')
- url = os.path.join(base, branch, filename)
-
-
- with TemporaryDirectory() as temp_dir:
- error_code = subprocess.call(['svn', 'export', url, temp_dir],
- stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
-
- if (not error_code):
- target_path = os.path.join(target, os.path.dirname(filename))
- target_filename = os.path.join(target, filename)
- os.makedirs(target_path, exist_ok=True)
- shutil.move(os.path.join(temp_dir, os.path.basename(filename)), target_filename)
- print(' [OK]')
- else:
- print(' [NA]')
- #import pdb; pdb.set_trace()
- return False
-
- return True
-
-def get_translations(target, branch = 'branches/stable/l10n-kde4', build = False):
- shutil.rmtree(target)
-
- if get('subdirs', target, branch):
- with open(os.path.join(target, 'subdirs'), 'r') as subdirs_file:
- subdirs = subdirs_file.read()
-
- if target.endswith('win'):
- all_languages = 'https://quickgit.kde.org/?o=plain&a=blob&p=kdelibs.git&f=kdecore/localization/all_languages.desktop'
- print('GET: ' + all_languages, end='')
- req = requests.get(all_languages)
- if (req.status_code == 200):
- os.makedirs(os.path.join(target, 'locale'), exist_ok=True)
- with open(os.path.join(target, 'locale', 'all_languages'), 'wb') as file_all_languages:
- file_all_languages.write(req.content)
- print(' [OK]')
- else:
- print(' [NA]')
- return False
-
- languages = []
- if build and target.endswith('win'):
- os.makedirs(os.path.join(target, 'locale'), exist_ok=True)
-
- for lang in subdirs.split('\n'):
- if lang in ['', 'x-test']:
- continue
-
- if not get(lang + '/messages/calligra/krita.po', target, branch):
- continue
-
- if build:
- if not msgfmt(os.path.join(target, lang, 'messages/calligra/krita.po'), target, lang):
- return False
-
- ## these files are prepared by scripty
- #
- #po_files = [ 'calligra/desktop_calligra_krita.po',
- # 'calligra/krita.appdata.po',
- #]
-
- po_files = []
-
- if target.endswith('win'):
- ## these files are now installed by the 'ext_*' scripts
- # po_files.append('frameworks/desktop_frameworks_kconfig.po')
- # po_files.append('frameworks/kconfig5_qt.po')
- # po_files.append('frameworks/kwidgetsaddons5_qt.po')
- # po_files.append('frameworks/kcompletion5_qt.po')
- # po_files.append('frameworks/kcoreaddons5_qt.po')
- # po_files.append('frameworks/kitemviews5_qt.po')
- # po_files.append('frameworks/kwindowsystem5_qt.po')
- # po_files.append('frameworks/kwidgetsaddons5_qt.po')
-
- if get(os.path.join(lang, 'messages', 'entry.desktop'), target, branch) and build:
- os.rename(os.path.join(target, lang, 'messages', 'entry.desktop'), os.path.join(target, 'locale', lang, 'entry.desktop'))
-
- for po_file in po_files:
- if get(os.path.join(lang, 'messages', po_file), target, branch) and build:
- if not msgfmt(os.path.join(target, lang, 'messages', po_file), target, lang):
- return False
-
- if build:
- shutil.rmtree(os.path.join(target, lang))
-
- languages.append(lang)
-
- if target.endswith('win'):
- os.remove(os.path.join(target, 'subdirs'))
- if build:
- now = datetime.datetime.now()
- packagename = '{0}-{1}_{2}_{3}.tar.gz'.format(target, now.year, now.month, now.day)
- with tarfile.open(packagename, "w:gz") as tar:
- tar.add(os.path.join(target, 'locale'), arcname='locale')
- else:
- with open(os.path.join(target, 'subdirs'), 'w') as subdirs_file:
- subdirs_file.write('\n'.join(languages))
-
- else:
- print('\nCouldn\'t fetch subdirs. Aborting')
- return False
-
- return True
-
-def msgfmt(po_filename, target, lang):
- mo_filename = os.path.splitext(os.path.basename(po_filename))[0] + '.mo'
- mo_dirname = os.path.join(target, 'locale', lang, 'LC_MESSAGES')
- print('BLD: ' + os.path.join(mo_dirname, mo_filename), end = '')
- os.makedirs(mo_dirname, exist_ok=True)
- ret = subprocess.call(['msgfmt','-o', os.path.join(mo_dirname, mo_filename), po_filename])
- if (ret == 0):
- os.remove(po_filename)
- print(' [OK]')
- else:
- print(' [FAILED]')
- return False
- return True
-
-if __name__ == '__main__':
- parser = OptionParser()
- parser.parse()
-
- if len(sys.argv) == 1:
- parser.print_help()
- sys.exit(0)
-
-
- if parser.options.ppa_testing:
- get_translations('krita-testing-l10n')
-
- elif parser.options.ppa_2_9:
- get_translations('krita-2.9-l10n')
-
- elif parser.options.win_2_9:
- get_translations('krita-2.9-l10n-win', build=True)
-
- elif parser.options.win_3_0:
- get_translations('krita-3.0-l10n-win', branch = 'trunk/l10n-kf5', build = True)
-
- else:
- parser.print_help()
diff --git a/packaging/windows/build_krita.bat b/packaging/windows/build_krita.bat
new file mode 100644
index 0000000000..c7285a5176
--- /dev/null
+++ b/packaging/windows/build_krita.bat
@@ -0,0 +1,20 @@
+set DLLTOOL_EXE=c:\TDM-GCC-64\x86_64-w64-mingw32\bin\dlltool.exe
+set MINGW_GCC_BIN=c:\TDM-GCC-64\bin\
+set BUILDROOT=c:\dev
+set BUILDDIR_INSTALL=%BUILDROOT%\i
+set PATH=c:\dev\i\bin;c:\dev\i\lib;c:\python35;%MINGW_GCC_BIN%;%PATH%
+cd c:\dev\build2
+
+set /P pkg_root=Insert krita source location:
+
+if [%pkg_root%] == [] (
+echo You entered an empty name!
+pause
+exit /B
+)
+
+cmake ..\%pkg_root% -G "MinGW Makefiles" -DBoost_DEBUG=OFF -DBOOST_INCLUDEDIR=c:\dev\i\include -DBOOST_DEBUG=ON -DBOOST_ROOT=c:\dev\i -DBOOST_LIBRARYDIR=c:\dev\i\lib -DCMAKE_INSTALL_PREFIX=c:\dev\i -DCMAKE_PREFIX_PATH=c:\dev\i -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DHAVE_MEMORY_LEAK_TRACKER=OFF -DPACKAGERS_BUILD=ON -Wno-dev -DDEFINE_NO_DEPRECATED=1 -DFOUNDATION_BUILD=1
+
+mingw32-make -j4 install
+
+cd ..
diff --git a/packaging/windows/package_2.cmd b/packaging/windows/package_2.cmd
index a1536b5501..5cbf0da2f4 100644
--- a/packaging/windows/package_2.cmd
+++ b/packaging/windows/package_2.cmd
@@ -1,331 +1,331 @@
@echo off
:: This batch script is meant to prepare a Krita package folder to be zipped or
:: to be a base for the installer.
::
:: Just drop it next to the "i" install folder where the dependencies and Krita
:: binaries are.
::
:: Also copy filelist_bin_dll.txt and filelist_lib_dll.txt if you want more
:: fine-grained DLL dependencies copying.
::
:: You may want to review the following parameters.
::
:: Configuration parameters:
::
:: MINGW_GCC_BIN: Path to the mingw-w64/bin dir
:: SEVENZIP_EXE: Path to 7-Zip executable (either 7z.exe or 7zG.exe)
:: BUILDDIR_SRC: Path to krita source dir (for package shortcut)
:: BUILDDIR_INSTALL: Path to INSTALL prefix of the build
::
:: Note that paths should only contain alphanumeric, _ and -, except for the
:: path to 7-Zip, which is fine if quoted.
::
set MINGW_GCC_BIN=C:\TDM-GCC-64\bin\
set SEVENZIP_EXE="C:\Program Files\7-Zip\7z.exe"
rem set BUILDDIR_SRC=%CD%\krita
set BUILDDIR_SRC=%CD%\krita
set BUILDDIR_INSTALL=%CD%\i
:: --------
set PATH=%MINGW_GCC_BIN%;%PATH%
echo Krita Windows packaging script
echo.
echo Configurations:
echo MINGW_GCC_BIN: %MINGW_GCC_BIN%
echo SEVENZIP_EXE: %SEVENZIP_EXE%
echo BUILDDIR_SRC: %BUILDDIR_SRC%
echo BUILDDIR_INSTALL: %BUILDDIR_INSTALL%
echo.
if "%1" == "" (
set PAUSE=pause
) else (
set "PAUSE= "
)
:: Simple checking
if not exist %BUILDDIR_INSTALL% (
echo ERROR: Cannot find the install folder!
%PAUSE%
exit /B 1
)
if not "%BUILDDIR_INSTALL: =%" == "%BUILDDIR_INSTALL%" (
echo ERROR: Install path contains space, which will not work properly!
%PAUSE%
exit /B 1
)
:: Decide package name to use
if "%1" == "" (
echo Please input a package name. It will be used for the output directory, package
echo file name and as the top-level directory of the package.
echo Alternatively, you can pass it as the first argument to this script.
echo You should only use alphanumeric, _ and -
echo.
set /P pkg_name=Package name^>
setlocal
if "!pkg_name!" == "" (
echo ERROR: You cannot choose an empty name!
%PAUSE%
exit /B 1
)
endlocal
) else (
set pkg_name=%1
)
echo Package name is "%pkg_name%"
set pkg_root=%CD%\%pkg_name%
echo Packaging dir is %pkg_root%
echo.
if exist %pkg_root% (
echo ERROR: Packaging dir already exists! Please remove or rename it first.
%PAUSE%
exit /B 1
)
echo.
echo Trying to guess GCC version...
g++ --version > NUL
if errorlevel 1 (
echo ERROR: g++ is not working.
%PAUSE%
exit /B 1
)
for /f "delims=" %%a in ('g++ --version ^| find "g++"') do set GCC_VERSION_LINE=%%a
echo -- %GCC_VERSION_LINE%
if "%GCC_VERSION_LINE:tdm64=%" == "%GCC_VERSION_LINE%" (
echo Compiler doesn't look like TDM64-GCC, assuming simple mingw-w64
set IS_TDM=
) else (
echo Compiler looks like TDM64-GCC
set IS_TDM=1
)
echo.
echo Trying to guess target architecture...
objdump --version > NUL
if errorlevel 1 (
echo ERROR: objdump is not working.
%PAUSE%
exit /B 1
)
for /f "delims=, tokens=1" %%a in ('objdump -f %BUILDDIR_INSTALL%\bin\krita.exe ^| find "architecture"') do set TARGET_ARCH_LINE=%%a
echo -- %TARGET_ARCH_LINE%
if "%TARGET_ARCH_LINE:x86-64=%" == "%TARGET_ARCH_LINE%" (
echo Target looks like x86
set IS_X64=
) else (
echo Target looks like x64
set IS_x64=1
)
echo.
echo Testing for objcopy...
objcopy --version > NUL
if errorlevel 1 (
echo ERROR: objcopy is not working.
%PAUSE%
exit /B 1
)
echo.
echo Testing for strip...
strip --version > NUL
if errorlevel 1 (
echo ERROR: strip is not working.
%PAUSE%
exit /B 1
)
echo.
echo Creating base directories...
mkdir %pkg_root% && ^
mkdir %pkg_root%\bin && ^
mkdir %pkg_root%\lib && ^
mkdir %pkg_root%\share
if errorlevel 1 (
echo ERROR: Cannot create packaging dir tree!
%PAUSE%
exit /B 1
)
echo.
echo Copying GCC libraries...
if x%IS_TDM% == x (
if x%is_x64% == x (
:: mingw-w64 x86
set "STDLIBS=gcc_s_dw2-1 gomp-1 stdc++-6 winpthread-1"
) else (
:: mingw-w64 x64
set "STDLIBS=gcc_s_seh-1 gomp-1 stdc++-6 winpthread-1"
)
) else (
if x%is_x64% == x (
:: TDM-GCC x86
set "STDLIBS=gomp-1"
) else (
:: TDM-GCC x64
set "STDLIBS=gomp_64-1"
)
)
for %%L in (%STDLIBS%) do copy "%MINGW_GCC_BIN%\lib%%L.dll" %pkg_root%\bin
echo.
echo Copying files...
:: krita.exe
copy %BUILDDIR_INSTALL%\bin\krita.exe %pkg_root%\bin
:: DLLs from bin/
if exist filelist_bin_dll.txt (
for /f %%F in (filelist_bin_dll.txt) do copy %BUILDDIR_INSTALL%\bin\%%F %pkg_root%\bin
) else (
echo INFO: filelist_bin_dll.txt not found, copying all DLLs except Qt5 from bin/
setlocal enableextensions enabledelayedexpansion
for /f "delims=" %%F in ('dir /b "%BUILDDIR_INSTALL%\bin\*.dll"') do (
set file=%%F
set file=!file:~0,3!
if not x!file! == xQt5 copy %BUILDDIR_INSTALL%\bin\%%F %pkg_root%\bin
)
endlocal
)
:: symsrv.yes for Dr. Mingw
copy %BUILDDIR_INSTALL%\bin\symsrv.yes %pkg_root%\bin
:: DLLs from lib/
if exist filelist_lib_dll.txt (
for /f %%F in (filelist_lib_dll.txt) do copy %BUILDDIR_INSTALL%\lib\%%F %pkg_root%\bin
) else (
echo INFO: filelist_lib_dll.txt not found, copying all DLLs from lib/
copy %BUILDDIR_INSTALL%\lib\*.dll %pkg_root%\bin
)
:: Boost, there might be more than one leftover but we can't really do much
copy %BUILDDIR_INSTALL%\bin\libboost_system-*.dll %pkg_root%\bin
:: KF5 plugins may be placed at different locations depending on how Qt is built
xcopy /S /Y /I %BUILDDIR_INSTALL%\lib\plugins\imageformats %pkg_root%\bin\imageformats
xcopy /S /Y /I %BUILDDIR_INSTALL%\plugins\imageformats %pkg_root%\bin\imageformats
xcopy /S /Y /I %BUILDDIR_INSTALL%\lib\plugins\kf5 %pkg_root%\bin\kf5
xcopy /S /Y /I %BUILDDIR_INSTALL%\plugins\kf5 %pkg_root%\bin\kf5
:: Qt Translations
:: it seems that windeployqt does these, but only *some* of these???
mkdir %pkg_root%\bin\translations
setlocal enableextensions enabledelayedexpansion
for /f "delims=" %%F in ('dir /b "%BUILDDIR_INSTALL%\translations\qt_*.qm"') do (
:: Exclude qt_help_*.qm
set temp=%%F
set temp2=!temp:_help=!
if x!temp2! == x!temp! copy %BUILDDIR_INSTALL%\translations\!temp! %pkg_root%\bin\translations\!temp!
)
endlocal
:: Krita plugins
xcopy /Y %BUILDDIR_INSTALL%\lib\kritaplugins\*.dll %pkg_root%\lib\kritaplugins\
:: Share
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\color %pkg_root%\share\color
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\color-schemes %pkg_root%\share\color-schemes
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\icons %pkg_root%\share\icons
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\kf5 %pkg_root%\share\kf5
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\krita %pkg_root%\share\krita
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\kritaplugins %pkg_root%\share\kritaplugins
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\mime %pkg_root%\share\mime
:: Not useful on Windows it seems
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\appdata %pkg_root%\share\appdata
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\applications %pkg_root%\share\applications
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\doc %pkg_root%\share\doc
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\kservices5 %pkg_root%\share\kservices5
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\man %pkg_root%\share\man
rem xcopy /Y /S /I %BUILDDIR_INSTALL%\share\ocio %pkg_root%\share\ocio
:: Copy locale to bin
xcopy /Y /S /I %BUILDDIR_INSTALL%\share\locale %pkg_root%\bin\locale
:: Copy shortcut link from source (can't create it dynamically)
copy %BUILDDIR_SRC%\packaging\windows\krita.lnk %pkg_root%
:: windeployqt
-%BUILDDIR_INSTALL%\bin\windeployqt.exe --release -concurrent -network -printsupport -svg -xml %pkg_root%\bin\krita.exe
+%BUILDDIR_INSTALL%\bin\windeployqt.exe --release -concurrent -network -printsupport -svg -xml -multimedia %pkg_root%\bin\krita.exe
:: For chopping relative path
:: 512 should be enough
:: n+2 to also account for a trailing backslash
setlocal enableextensions enabledelayedexpansion
for /L %%n in (1 1 512) do if "!pkg_root:~%%n,1!" neq "" set /a "pkg_root_len_plus_one=%%n+2"
endlocal & set pkg_root_len_plus_one=%pkg_root_len_plus_one%
echo.
echo Splitting debug info from binaries...
call :split-debug "%pkg_root%\bin\krita.exe" bin\krita.exe
setlocal enableextensions enabledelayedexpansion
:: Find all DLLs
for /r "%pkg_root%" %%F in (*.dll) do (
set relpath=%%F
set relpath=!relpath:~%pkg_root_len_plus_one%!
call :split-debug "%%F" !relpath!
)
endlocal
echo.
echo Packaging debug info...
:: (note that the top-level package dir is not included)
%SEVENZIP_EXE% a -tzip %pkg_name%-dbg.zip -r %pkg_root%\*.debug
echo --------
echo.
echo Packaging stripped binaries...
%SEVENZIP_EXE% a -tzip %pkg_name%.zip %pkg_root%\ -xr!.debug
echo --------
echo.
echo.
echo Krita packaged as %pkg_name%.zip
if exist %pkg_name%-dbg.zip echo Debug info packaged as %pkg_name%-dbg.zip
echo Packaging dir is %pkg_root%
echo NOTE: Do not create installer with packaging dir unless you removed all debug
echo info from it!
echo.
echo Please remember to actually test the package before releasing it.
echo.
%PAUSE%
exit /b
:split-debug
echo Splitting debug info of %2
objcopy --only-keep-debug %~1 %~1.debug
if ERRORLEVEL 1 exit /b %ERRORLEVEL%
:: If the debug file is small enough then consider there being no debug info.
:: Discard these files since they somehow make gdb crash.
call :getfilesize %~1.debug
if /i %getfilesize_retval% LEQ 2048 (
echo Discarding %2.debug
del %~1.debug
exit /b 0
)
if not exist %~dp1.debug mkdir %~dp1.debug
move %~1.debug %~dp1.debug\ > NUL
strip %~1
:: Add debuglink
:: FIXME: There is a problem with gdb that cause it to output this warning
:: FIXME: "warning: section .gnu_debuglink not found in xxx.debug"
:: FIXME: I tried adding a link to itself but this kills drmingw :(
objcopy --add-gnu-debuglink="%~dp1.debug\%~nx1.debug" %~1
exit /b %ERRORLEVEL%
:getfilesize
set getfilesize_retval=%~z1
goto :eof
:relpath_dirpath
call :relpath_dirpath_internal "" "%~1"
goto :eof
:relpath_dirpath_internal
for /f "tokens=1* delims=\" %%a in ("%~2") do (
:: If part 2 is empty, it means part 1 is probably the file name
if x%%b==x (
set relpath_dirpath_retval=%~1
) else (
call :relpath_dirpath_internal "%~1%%a\" %%b
)
)
goto :eof
diff --git a/plugins/dockers/animation/kis_time_based_item_model.cpp b/plugins/dockers/animation/kis_time_based_item_model.cpp
index 99ff688ca1..74f133b854 100644
--- a/plugins/dockers/animation/kis_time_based_item_model.cpp
+++ b/plugins/dockers/animation/kis_time_based_item_model.cpp
@@ -1,435 +1,434 @@
/*
* Copyright (c) 2016 Jouni Pentikäinen
*
* 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_time_based_item_model.h"
#include
#include
#include "kis_animation_frame_cache.h"
#include "kis_animation_player.h"
#include "kis_signal_compressor_with_param.h"
#include "kis_image.h"
#include "kis_image_animation_interface.h"
#include "kis_time_range.h"
#include "kis_animation_utils.h"
#include "kis_keyframe_channel.h"
struct KisTimeBasedItemModel::Private
{
Private()
: animationPlayer(0)
, numFramesOverride(0)
, activeFrameIndex(0)
, scrubInProgress(false)
, scrubStartFrame(-1)
{}
KisImageWSP image;
KisAnimationFrameCacheWSP framesCache;
QPointer animationPlayer;
QVector cachedFrames;
int numFramesOverride;
int activeFrameIndex;
bool scrubInProgress;
int scrubStartFrame;
QScopedPointer > scrubbingCompressor;
-
int baseNumFrames() const {
if (image.isNull()) return 0;
KisImageAnimationInterface *i = image->animationInterface();
if (!i) return 1;
return i->totalLength();
}
int effectiveNumFrames() const {
if (image.isNull()) return 0;
return qMax(baseNumFrames(), numFramesOverride);
}
int framesPerSecond() {
return image->animationInterface()->framerate();
}
};
KisTimeBasedItemModel::KisTimeBasedItemModel(QObject *parent)
: QAbstractTableModel(parent)
, m_d(new Private())
{
KisConfig cfg;
using namespace std::placeholders;
std::function callback(
std::bind(&KisTimeBasedItemModel::slotInternalScrubPreviewRequested, this, _1));
m_d->scrubbingCompressor.reset(
- new KisSignalCompressorWithParam(cfg.scribbingUpdatesDelay(), callback, KisSignalCompressor::FIRST_ACTIVE));
+ new KisSignalCompressorWithParam(cfg.scrubbingUpdatesDelay(), callback, KisSignalCompressor::FIRST_ACTIVE));
}
KisTimeBasedItemModel::~KisTimeBasedItemModel()
{}
void KisTimeBasedItemModel::setImage(KisImageWSP image)
{
KisImageWSP oldImage = m_d->image;
m_d->image = image;
if (image) {
KisImageAnimationInterface *ai = image->animationInterface();
slotCurrentTimeChanged(ai->currentUITime());
connect(ai, SIGNAL(sigFramerateChanged()), SLOT(slotFramerateChanged()));
connect(ai, SIGNAL(sigUiTimeChanged(int)), SLOT(slotCurrentTimeChanged(int)));
}
if (image != oldImage) {
reset();
}
}
void KisTimeBasedItemModel::setFrameCache(KisAnimationFrameCacheSP cache)
{
if (KisAnimationFrameCacheSP(m_d->framesCache) == cache) return;
if (m_d->framesCache) {
m_d->framesCache->disconnect(this);
}
m_d->framesCache = cache;
if (m_d->framesCache) {
connect(m_d->framesCache, SIGNAL(changed()), SLOT(slotCacheChanged()));
}
}
void KisTimeBasedItemModel::setAnimationPlayer(KisAnimationPlayer *player)
{
if (m_d->animationPlayer == player) return;
if (m_d->animationPlayer) {
m_d->animationPlayer->disconnect(this);
}
m_d->animationPlayer = player;
if (m_d->animationPlayer) {
connect(m_d->animationPlayer, SIGNAL(sigPlaybackStopped()), SLOT(slotPlaybackStopped()));
connect(m_d->animationPlayer, SIGNAL(sigFrameChanged()), SLOT(slotPlaybackFrameChanged()));
}
}
void KisTimeBasedItemModel::setLastVisibleFrame(int time)
{
const int growThreshold = m_d->effectiveNumFrames() - 3;
const int growValue = time + 8;
const int shrinkThreshold = m_d->effectiveNumFrames() - 12;
const int shrinkValue = qMax(m_d->baseNumFrames(), qMin(growValue, shrinkThreshold));
const bool canShrink = m_d->effectiveNumFrames() > m_d->baseNumFrames();
if (time >= growThreshold) {
beginInsertColumns(QModelIndex(), m_d->effectiveNumFrames(), growValue - 1);
m_d->numFramesOverride = growValue;
endInsertColumns();
} else if (time < shrinkThreshold && canShrink) {
beginRemoveColumns(QModelIndex(), shrinkValue, m_d->effectiveNumFrames() - 1);
m_d->numFramesOverride = shrinkValue;
endRemoveColumns();
}
}
int KisTimeBasedItemModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_d->effectiveNumFrames();
}
QVariant KisTimeBasedItemModel::data(const QModelIndex &index, int role) const
{
switch (role) {
case ActiveFrameRole: {
return index.column() == m_d->activeFrameIndex;
}
}
return QVariant();
}
bool KisTimeBasedItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid()) return false;
switch (role) {
case ActiveFrameRole: {
setHeaderData(index.column(), Qt::Horizontal, value, role);
break;
}
}
return false;
}
QVariant KisTimeBasedItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
switch (role) {
case ActiveFrameRole:
return section == m_d->activeFrameIndex;
case FrameCachedRole:
return m_d->cachedFrames.size() > section ? m_d->cachedFrames[section] : false;
case FramesPerSecondRole:
return m_d->framesPerSecond();
}
}
return QVariant();
}
bool KisTimeBasedItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
if (orientation == Qt::Horizontal) {
switch (role) {
case ActiveFrameRole:
if (value.toBool() &&
section != m_d->activeFrameIndex) {
int prevFrame = m_d->activeFrameIndex;
m_d->activeFrameIndex = section;
scrubTo(m_d->activeFrameIndex, m_d->scrubInProgress);
/**
* Optimization Hack Alert:
*
* ideally, we should emit all four signals, but... The
* point is this code is used in a tight loop during
* playback, so it should run as fast as possible. To tell
* the story short, commenting out these three lines makes
* playback run 15% faster ;)
*/
if (m_d->scrubInProgress) {
//emit dataChanged(this->index(0, prevFrame), this->index(rowCount() - 1, prevFrame));
emit dataChanged(this->index(0, m_d->activeFrameIndex), this->index(rowCount() - 1, m_d->activeFrameIndex));
//emit headerDataChanged (Qt::Horizontal, prevFrame, prevFrame);
//emit headerDataChanged (Qt::Horizontal, m_d->activeFrameIndex, m_d->activeFrameIndex);
} else {
emit dataChanged(this->index(0, prevFrame), this->index(rowCount() - 1, prevFrame));
emit dataChanged(this->index(0, m_d->activeFrameIndex), this->index(rowCount() - 1, m_d->activeFrameIndex));
emit headerDataChanged (Qt::Horizontal, prevFrame, prevFrame);
emit headerDataChanged (Qt::Horizontal, m_d->activeFrameIndex, m_d->activeFrameIndex);
}
}
}
}
return false;
}
bool KisTimeBasedItemModel::removeFrames(const QModelIndexList &indexes)
{
KisAnimationUtils::FrameItemList frameItems;
Q_FOREACH (const QModelIndex &index, indexes) {
int time = index.column();
QList channels = channelsAt(index);
Q_FOREACH(KisKeyframeChannel *channel, channels) {
if (channel->keyframeAt(time)) {
frameItems << KisAnimationUtils::FrameItem(channel->node(), channel->id(), index.column());
}
}
}
if (frameItems.isEmpty()) return false;
KisAnimationUtils::removeKeyframes(m_d->image, frameItems);
Q_FOREACH (const QModelIndex &index, indexes) {
if (index.isValid()) {
emit dataChanged(index, index);
}
}
return true;
}
bool KisTimeBasedItemModel::offsetFrames(QModelIndexList srcIndexes, const QPoint &offset, bool copyFrames, KUndo2Command *parentCommand)
{
bool result = false;
if (srcIndexes.isEmpty()) return result;
if (offset.isNull()) return result;
KisAnimationUtils::sortPointsForSafeMove(&srcIndexes, offset);
KisAnimationUtils::FrameItemList srcFrameItems;
KisAnimationUtils::FrameItemList dstFrameItems;
QModelIndexList updateIndexes;
Q_FOREACH (const QModelIndex &srcIndex, srcIndexes) {
QModelIndex dstIndex = index(
srcIndex.row() + offset.y(),
srcIndex.column() + offset.x());
KisNodeSP srcNode = nodeAt(srcIndex);
KisNodeSP dstNode = nodeAt(dstIndex);
if (!srcNode || !dstNode) {
return false;
}
QList channels = channelsAt(srcIndex);
Q_FOREACH(KisKeyframeChannel *channel, channels) {
if (channel->keyframeAt(srcIndex.column())) {
srcFrameItems << KisAnimationUtils::FrameItem(srcNode, channel->id(), srcIndex.column());
dstFrameItems << KisAnimationUtils::FrameItem(dstNode, channel->id(), dstIndex.column());
}
}
if (!copyFrames) {
updateIndexes << srcIndex;
}
updateIndexes << dstIndex;
}
result = KisAnimationUtils::moveKeyframes(m_d->image,
srcFrameItems,
dstFrameItems,
copyFrames,
parentCommand);
Q_FOREACH (const QModelIndex &index, updateIndexes) {
emit dataChanged(index, index);
}
return result;
}
void KisTimeBasedItemModel::slotInternalScrubPreviewRequested(int time)
{
if (m_d->animationPlayer && !m_d->animationPlayer->isPlaying()) {
m_d->animationPlayer->displayFrame(time);
}
}
void KisTimeBasedItemModel::setScrubState(bool active)
{
if (!m_d->scrubInProgress && active) {
m_d->scrubStartFrame = m_d->activeFrameIndex;
m_d->scrubInProgress = true;
}
if (m_d->scrubInProgress && !active) {
m_d->scrubInProgress = false;
if (m_d->scrubStartFrame >= 0 &&
m_d->scrubStartFrame != m_d->activeFrameIndex) {
scrubTo(m_d->activeFrameIndex, false);
}
m_d->scrubStartFrame = -1;
}
}
void KisTimeBasedItemModel::scrubTo(int time, bool preview)
{
if (m_d->animationPlayer && m_d->animationPlayer->isPlaying()) return;
KIS_ASSERT_RECOVER_RETURN(m_d->image);
if (preview) {
if (m_d->animationPlayer) {
m_d->scrubbingCompressor->start(time);
}
} else {
m_d->image->animationInterface()->requestTimeSwitchWithUndo(time);
}
}
void KisTimeBasedItemModel::slotFramerateChanged()
{
emit headerDataChanged(Qt::Horizontal, 0, columnCount() - 1);
}
void KisTimeBasedItemModel::slotCurrentTimeChanged(int time)
{
if (time != m_d->activeFrameIndex) {
setHeaderData(time, Qt::Horizontal, true, ActiveFrameRole);
}
}
void KisTimeBasedItemModel::slotCacheChanged()
{
const int numFrames = columnCount();
m_d->cachedFrames.resize(numFrames);
for (int i = 0; i < numFrames; i++) {
m_d->cachedFrames[i] =
m_d->framesCache->frameStatus(i) == KisAnimationFrameCache::Cached;
}
emit headerDataChanged(Qt::Horizontal, 0, numFrames);
}
void KisTimeBasedItemModel::slotPlaybackFrameChanged()
{
if (!m_d->animationPlayer->isPlaying()) return;
setData(index(0, m_d->animationPlayer->currentTime()), true, ActiveFrameRole);
}
void KisTimeBasedItemModel::slotPlaybackStopped()
{
setData(index(0, m_d->image->animationInterface()->currentUITime()), true, ActiveFrameRole);
}
void KisTimeBasedItemModel::setPlaybackRange(const KisTimeRange &range)
{
if (m_d->image.isNull()) return;
KisImageAnimationInterface *i = m_d->image->animationInterface();
i->setPlaybackRange(range);
}
bool KisTimeBasedItemModel::isPlaybackActive() const
{
return m_d->animationPlayer && m_d->animationPlayer->isPlaying();
}
int KisTimeBasedItemModel::currentTime() const
{
return m_d->image->animationInterface()->currentUITime();
}
KisImageWSP KisTimeBasedItemModel::image() const
{
return m_d->image;
}
diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp
index dc5d4ef97e..4ba41261fe 100644
--- a/plugins/dockers/animation/timeline_frames_model.cpp
+++ b/plugins/dockers/animation/timeline_frames_model.cpp
@@ -1,646 +1,685 @@
/*
* Copyright (c) 2015 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 "timeline_frames_model.h"
#include
#include
#include
#include
#include
#include "kis_layer.h"
#include "kis_config.h"
#include "kis_global.h"
#include "kis_debug.h"
#include "kis_image.h"
#include "kis_image_animation_interface.h"
#include "kis_undo_adapter.h"
#include "kis_node_dummies_graph.h"
#include "kis_dummies_facade_base.h"
#include "kis_signal_compressor.h"
#include "kis_signal_compressor_with_param.h"
#include "kis_keyframe_channel.h"
#include "kundo2command.h"
#include "kis_post_execution_undo_adapter.h"
#include
#include "kis_animation_utils.h"
#include "timeline_color_scheme.h"
#include "kis_node_model.h"
#include "kis_projection_leaf.h"
#include "kis_time_range.h"
struct TimelineFramesModel::Private
{
Private()
: activeLayerIndex(0),
dummiesFacade(0),
needFinishInsertRows(false),
needFinishRemoveRows(false),
updateTimer(200, KisSignalCompressor::FIRST_INACTIVE),
parentOfRemovedNode(0)
{}
int activeLayerIndex;
KisDummiesFacadeBase *dummiesFacade;
KisImageWSP image;
bool needFinishInsertRows;
bool needFinishRemoveRows;
QList updateQueue;
KisSignalCompressor updateTimer;
KisNodeDummy* parentOfRemovedNode;
QScopedPointer converter;
QScopedPointer nodeInterface;
QPersistentModelIndex lastClickedIndex;
QVariant layerName(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return QVariant();
return dummy->node()->name();
}
bool layerEditable(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return true;
return dummy->node()->visible() && !dummy->node()->userLocked();
}
bool frameExists(int row, int column) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
return (primaryChannel && primaryChannel->keyframeAt(column));
}
bool specialKeyframeExists(int row, int column) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
QList channels = dummy->node()->keyframeChannels();
Q_FOREACH(KisKeyframeChannel *channel, channels) {
if (channel->id() != KisKeyframeChannel::Content.id() && channel->keyframeAt(column)) {
return true;
}
}
return false;
}
int frameColorLabel(int row, int column) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return -1;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!primaryChannel) return -1;
KisKeyframeSP frame = primaryChannel->keyframeAt(column);
if (!frame) return -1;
return frame->colorLabel();
}
void setFrameColorLabel(int row, int column, int color) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return;
KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (!primaryChannel) return;
KisKeyframeSP frame = primaryChannel->keyframeAt(column);
if (!frame) return;
frame->setColorLabel(color);
}
QVariant layerProperties(int row) const {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return QVariant();
PropertyList props = dummy->node()->sectionModelProperties();
return QVariant::fromValue(props);
}
bool setLayerProperties(int row, PropertyList props) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
KisNodePropertyListCommand::setNodePropertiesNoUndo(dummy->node(), image, props);
return true;
}
bool addKeyframe(int row, int column, bool copy) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
KisNodeSP node = dummy->node();
if (!KisAnimationUtils::supportsContentFrames(node)) return false;
return KisAnimationUtils::createKeyframeLazy(image, node, KisKeyframeChannel::Content.id(), column, copy);
}
bool addNewLayer(int row) {
Q_UNUSED(row);
if (nodeInterface) {
KisLayerSP layer = nodeInterface->addPaintLayer();
layer->setUseInTimeline(true);
}
return true;
}
bool removeLayer(int row) {
KisNodeDummy *dummy = converter->dummyFromRow(row);
if (!dummy) return false;
if (nodeInterface) {
nodeInterface->removeNode(dummy->node());
}
return true;
}
};
TimelineFramesModel::TimelineFramesModel(QObject *parent)
: ModelWithExternalNotifications(parent),
m_d(new Private)
{
connect(&m_d->updateTimer, SIGNAL(timeout()), SLOT(processUpdateQueue()));
}
TimelineFramesModel::~TimelineFramesModel()
{
}
bool TimelineFramesModel::hasConnectionToCanvas() const
{
return m_d->dummiesFacade;
}
void TimelineFramesModel::setNodeManipulationInterface(NodeManipulationInterface *iface)
{
m_d->nodeInterface.reset(iface);
}
KisNodeSP TimelineFramesModel::nodeAt(QModelIndex index) const
{
return m_d->converter->dummyFromRow(index.row())->node();
}
QList TimelineFramesModel::channelsAt(QModelIndex index) const
{
KisNodeDummy *srcDummy = m_d->converter->dummyFromRow(index.row());
return srcDummy->node()->keyframeChannels();
}
void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageSP image)
{
KisDummiesFacadeBase *oldDummiesFacade = m_d->dummiesFacade;
if (m_d->dummiesFacade) {
+ m_d->image->animationInterface()->disconnect(this);
m_d->image->disconnect(this);
m_d->dummiesFacade->disconnect(this);
}
m_d->image = image;
KisTimeBasedItemModel::setImage(image);
m_d->dummiesFacade = dummiesFacade;
m_d->converter.reset();
if (m_d->dummiesFacade) {
m_d->converter.reset(new TimelineNodeListKeeper(this, m_d->dummiesFacade));
connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)),
SLOT(slotDummyChanged(KisNodeDummy*)));
connect(m_d->image->animationInterface(),
SIGNAL(sigFullClipRangeChanged()), SIGNAL(sigInfiniteTimelineUpdateNeeded()));
+ connect(m_d->image->animationInterface(),
+ SIGNAL(sigAudioChannelChanged()), SIGNAL(sigAudioChannelChanged()));
+ connect(m_d->image->animationInterface(),
+ SIGNAL(sigAudioVolumeChanged()), SIGNAL(sigAudioChannelChanged()));
}
if (m_d->dummiesFacade != oldDummiesFacade) {
reset();
}
if (m_d->dummiesFacade) {
emit sigInfiniteTimelineUpdateNeeded();
+ emit sigAudioChannelChanged();
}
}
void TimelineFramesModel::slotDummyChanged(KisNodeDummy *dummy)
{
if (!m_d->updateQueue.contains(dummy)) {
m_d->updateQueue.append(dummy);
}
m_d->updateTimer.start();
}
void TimelineFramesModel::processUpdateQueue()
{
Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) {
int row = m_d->converter->rowForDummy(dummy);
if (row >= 0) {
emit headerDataChanged (Qt::Vertical, row, row);
emit dataChanged(this->index(row, 0), this->index(row, columnCount() - 1));
}
}
m_d->updateQueue.clear();
}
void TimelineFramesModel::slotCurrentNodeChanged(KisNodeSP node)
{
if (!node) {
m_d->activeLayerIndex = -1;
return;
}
KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node);
KIS_ASSERT_RECOVER_RETURN(dummy);
m_d->converter->updateActiveDummy(dummy);
const int row = m_d->converter->rowForDummy(dummy);
if (row < 0) {
qWarning() << "WARNING: TimelineFramesModel::slotCurrentNodeChanged: node not found!";
}
if (row >= 0 && m_d->activeLayerIndex != row) {
setData(index(row, 0), true, ActiveLayerRole);
}
}
int TimelineFramesModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
if(!m_d->dummiesFacade) return 0;
return m_d->converter->rowCount();
}
QVariant TimelineFramesModel::data(const QModelIndex &index, int role) const
{
if(!m_d->dummiesFacade) return QVariant();
switch (role) {
case ActiveLayerRole: {
return index.row() == m_d->activeLayerIndex;
}
case FrameEditableRole: {
return m_d->layerEditable(index.row());
}
case FrameExistsRole: {
return m_d->frameExists(index.row(), index.column());
}
case SpecialKeyframeExists: {
return m_d->specialKeyframeExists(index.row(), index.column());
}
case ColorLabel: {
int label = m_d->frameColorLabel(index.row(), index.column());
return label > 0 ? label : QVariant();
}
case Qt::DisplayRole: {
return QVariant();
}
case Qt::TextAlignmentRole: {
return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
}
}
return ModelWithExternalNotifications::data(index, role);
}
bool TimelineFramesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || !m_d->dummiesFacade) return false;
switch (role) {
case ActiveLayerRole: {
if (value.toBool() &&
index.row() != m_d->activeLayerIndex) {
int prevLayer = m_d->activeLayerIndex;
m_d->activeLayerIndex = index.row();
emit dataChanged(this->index(prevLayer, 0), this->index(prevLayer, columnCount() - 1));
emit dataChanged(this->index(m_d->activeLayerIndex, 0), this->index(m_d->activeLayerIndex, columnCount() - 1));
emit headerDataChanged(Qt::Vertical, prevLayer, prevLayer);
emit headerDataChanged(Qt::Vertical, m_d->activeLayerIndex, m_d->activeLayerIndex);
KisNodeDummy *dummy = m_d->converter->dummyFromRow(m_d->activeLayerIndex);
KIS_ASSERT_RECOVER(dummy) { return true; }
emit requestCurrentNodeChanged(dummy->node());
emit sigEnsureRowVisible(m_d->activeLayerIndex);
}
break;
}
case ColorLabel: {
m_d->setFrameColorLabel(index.row(), index.column(), value.toInt());
}
break;
}
return ModelWithExternalNotifications::setData(index, value, role);
}
QVariant TimelineFramesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(!m_d->dummiesFacade) return QVariant();
if (orientation == Qt::Vertical) {
switch (role) {
case ActiveLayerRole:
return section == m_d->activeLayerIndex;
case Qt::DisplayRole: {
QVariant value = headerData(section, orientation, Qt::ToolTipRole);
if (!value.isValid()) return value;
QString name = value.toString();
const int maxNameSize = 13;
if (name.size() > maxNameSize) {
name = QString("%1...").arg(name.left(maxNameSize));
}
return name;
}
case Qt::TextColorRole: {
// WARNING: this role doesn't work for header views! Use
// bold font to show isolated mode instead!
return QVariant();
}
case Qt::FontRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return QVariant();
KisNodeSP node = dummy->node();
QFont baseFont;
if (node->projectionLeaf()->isDroppedMask()) {
baseFont.setStrikeOut(true);
} else if (m_d->image && m_d->image->isolatedModeRoot() &&
KisNodeModel::belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade)) {
baseFont.setBold(true);
}
return baseFont;
}
case Qt::ToolTipRole: {
return m_d->layerName(section);
}
case TimelinePropertiesRole: {
return QVariant::fromValue(m_d->layerProperties(section));
}
case OtherLayersRole: {
TimelineNodeListKeeper::OtherLayersList list =
m_d->converter->otherLayersList();
return QVariant::fromValue(list);
}
case LayerUsedInTimelineRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return QVariant();
return dummy->node()->useInTimeline();
}
}
}
return ModelWithExternalNotifications::headerData(section, orientation, role);
}
bool TimelineFramesModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
if (!m_d->dummiesFacade) return false;
if (orientation == Qt::Vertical) {
switch (role) {
case ActiveLayerRole: {
setData(index(section, 0), value, role);
break;
}
case TimelinePropertiesRole: {
TimelineFramesModel::PropertyList props = value.value();
int result = m_d->setLayerProperties(section, props);
emit headerDataChanged (Qt::Vertical, section, section);
return result;
}
case LayerUsedInTimelineRole: {
KisNodeDummy *dummy = m_d->converter->dummyFromRow(section);
if (!dummy) return false;
dummy->node()->setUseInTimeline(value.toBool());
return true;
}
}
}
return ModelWithExternalNotifications::setHeaderData(section, orientation, value, role);
}
Qt::DropActions TimelineFramesModel::supportedDragActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
Qt::DropActions TimelineFramesModel::supportedDropActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
QStringList TimelineFramesModel::mimeTypes() const
{
QStringList types;
types << QLatin1String("application/x-krita-frame");
return types;
}
void TimelineFramesModel::setLastClickedIndex(const QModelIndex &index)
{
m_d->lastClickedIndex = index;
}
QMimeData* TimelineFramesModel::mimeData(const QModelIndexList &indexes) const
{
QMimeData *data = new QMimeData();
QByteArray encoded;
QDataStream stream(&encoded, QIODevice::WriteOnly);
const int baseRow = m_d->lastClickedIndex.row();
const int baseColumn = m_d->lastClickedIndex.column();
stream << indexes.size();
stream << baseRow << baseColumn;
Q_FOREACH (const QModelIndex &index, indexes) {
stream << index.row() - baseRow << index.column() - baseColumn;
}
data->setData("application/x-krita-frame", encoded);
return data;
}
inline void decodeBaseIndex(QByteArray *encoded, int *row, int *col)
{
int size_UNUSED = 0;
QDataStream stream(encoded, QIODevice::ReadOnly);
stream >> size_UNUSED >> *row >> *col;
}
bool TimelineFramesModel::canDropFrameData(const QMimeData */*data*/, const QModelIndex &index)
{
if (!index.isValid()) return false;
/**
* Now we support D&D around any layer, so just return 'true' all
* the time.
*/
return true;
}
bool TimelineFramesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row);
Q_UNUSED(column);
bool result = false;
if ((action != Qt::MoveAction &&
action != Qt::CopyAction) || !parent.isValid()) return result;
const bool copyFrames = action == Qt::CopyAction;
QByteArray encoded = data->data("application/x-krita-frame");
QDataStream stream(&encoded, QIODevice::ReadOnly);
int size, baseRow, baseColumn;
stream >> size >> baseRow >> baseColumn;
QModelIndexList srcIndexes;
for (int i = 0; i < size; i++) {
int relRow, relColumn;
stream >> relRow >> relColumn;
int srcRow = baseRow + relRow;
int srcColumn = baseColumn + relColumn;
srcIndexes << index(srcRow, srcColumn);
}
const QPoint offset(parent.column() - baseColumn, parent.row() - baseRow);
return offsetFrames(srcIndexes, offset, copyFrames);
}
Qt::ItemFlags TimelineFramesModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = ModelWithExternalNotifications::flags(index);
if (!index.isValid()) return flags;
if (m_d->frameExists(index.row(), index.column()) || m_d->specialKeyframeExists(index.row(), index.column())) {
if (data(index, FrameEditableRole).toBool()) {
flags |= Qt::ItemIsDragEnabled;
}
}
/**
* Basically we should forbid overrides only if we D&D a single frame
* and allow it when we D&D multiple frames. But we cannot distinguish
* it here... So allow all the time.
*/
flags |= Qt::ItemIsDropEnabled;
return flags;
}
bool TimelineFramesModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
KIS_ASSERT_RECOVER(count == 1) { return false; }
if (row < 0 || row > rowCount()) return false;
bool result = m_d->addNewLayer(row);
return result;
}
bool TimelineFramesModel::removeRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
KIS_ASSERT_RECOVER(count == 1) { return false; }
if (row < 0 || row >= rowCount()) return false;
bool result = m_d->removeLayer(row);
return result;
}
bool TimelineFramesModel::insertOtherLayer(int index, int dstRow)
{
Q_UNUSED(dstRow);
TimelineNodeListKeeper::OtherLayersList list =
m_d->converter->otherLayersList();
if (index < 0 || index >= list.size()) return false;
list[index].dummy->node()->setUseInTimeline(true);
dstRow = m_d->converter->rowForDummy(list[index].dummy);
setData(this->index(dstRow, 0), true, ActiveLayerRole);
return true;
}
int TimelineFramesModel::activeLayerRow() const
{
return m_d->activeLayerIndex;
}
bool TimelineFramesModel::createFrame(const QModelIndex &dstIndex)
{
if (!dstIndex.isValid()) return false;
bool result = m_d->addKeyframe(dstIndex.row(), dstIndex.column(), false);
if (result) {
emit dataChanged(dstIndex, dstIndex);
}
return result;
}
bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex)
{
if (!dstIndex.isValid()) return false;
bool result = m_d->addKeyframe(dstIndex.row(), dstIndex.column(), true);
if (result) {
emit dataChanged(dstIndex, dstIndex);
}
return result;
}
+
+QString TimelineFramesModel::audioChannelFileName() const
+{
+ return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString();
+}
+
+void TimelineFramesModel::setAudioChannelFileName(const QString &fileName)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
+ m_d->image->animationInterface()->setAudioChannelFileName(fileName);
+}
+
+bool TimelineFramesModel::isAudioMuted() const
+{
+ return m_d->image ? m_d->image->animationInterface()->isAudioMuted() : false;
+}
+
+void TimelineFramesModel::setAudioMuted(bool value)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
+ m_d->image->animationInterface()->setAudioMuted(value);
+}
+
+qreal TimelineFramesModel::audioVolume() const
+{
+ return m_d->image ? m_d->image->animationInterface()->audioVolume() : 0.5;
+}
+
+void TimelineFramesModel::setAudioVolume(qreal value)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
+ m_d->image->animationInterface()->setAudioVolume(value);
+}
diff --git a/plugins/dockers/animation/timeline_frames_model.h b/plugins/dockers/animation/timeline_frames_model.h
index 101326bf3b..59c5c05d49 100644
--- a/plugins/dockers/animation/timeline_frames_model.h
+++ b/plugins/dockers/animation/timeline_frames_model.h
@@ -1,122 +1,132 @@
/*
* Copyright (c) 2015 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 __TIMELINE_FRAMES_MODEL_H
#define __TIMELINE_FRAMES_MODEL_H
#include
#include
#include "kritaanimationdocker_export.h"
#include "kis_node_model.h"
#include "kis_types.h"
#include "kis_node.h"
#include "timeline_node_list_keeper.h"
class KisNodeDummy;
class KisDummiesFacadeBase;
class KisAnimationPlayer;
class KRITAANIMATIONDOCKER_EXPORT TimelineFramesModel : public TimelineNodeListKeeper::ModelWithExternalNotifications
{
Q_OBJECT
public:
TimelineFramesModel(QObject *parent);
~TimelineFramesModel();
bool hasConnectionToCanvas() const;
void setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageSP image);
bool canDropFrameData(const QMimeData *data, const QModelIndex &index);
bool insertOtherLayer(int index, int dstRow);
int activeLayerRow() const;
bool createFrame(const QModelIndex &dstIndex);
bool copyFrame(const QModelIndex &dstIndex);
+ QString audioChannelFileName() const;
+ void setAudioChannelFileName(const QString &fileName);
+
+ bool isAudioMuted() const;
+ void setAudioMuted(bool value);
+
+ qreal audioVolume() const;
+ void setAudioVolume(qreal value);
+
void setLastClickedIndex(const QModelIndex &index);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role);
Qt::DropActions supportedDragActions() const;
Qt::DropActions supportedDropActions() const;
QStringList mimeTypes() const;
QMimeData * mimeData(const QModelIndexList &indexes) const;
bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent);
Qt::ItemFlags flags(const QModelIndex &index) const;
bool insertRows(int row, int count, const QModelIndex &parent);
bool removeRows(int row, int count, const QModelIndex &parent);
enum ItemDataRole
{
ActiveLayerRole = KisTimeBasedItemModel::UserRole,
TimelinePropertiesRole,
OtherLayersRole,
LayerUsedInTimelineRole,
ColorLabel
};
// metatype is added by the original implementation
typedef KisBaseNode::Property Property;
typedef KisBaseNode::PropertyList PropertyList;
typedef TimelineNodeListKeeper::OtherLayer OtherLayer;
typedef TimelineNodeListKeeper::OtherLayersList OtherLayersList;
struct NodeManipulationInterface {
virtual ~NodeManipulationInterface() {}
virtual KisLayerSP addPaintLayer() const = 0;
virtual void removeNode(KisNodeSP node) const = 0;
};
/**
* NOTE: the model has an ownership over the interface, that is it'll
* be deleted automatically later
*/
void setNodeManipulationInterface(NodeManipulationInterface *iface);
protected:
KisNodeSP nodeAt(QModelIndex index) const;
QList channelsAt(QModelIndex index) const;
private Q_SLOTS:
void slotDummyChanged(KisNodeDummy *dummy);
void processUpdateQueue();
public Q_SLOTS:
void slotCurrentNodeChanged(KisNodeSP node);
Q_SIGNALS:
void requestCurrentNodeChanged(KisNodeSP node);
void sigInfiniteTimelineUpdateNeeded();
+ void sigAudioChannelChanged();
void sigEnsureRowVisible(int row);
-
+
private:
struct Private;
const QScopedPointer m_d;
};
#endif /* __TIMELINE_FRAMES_MODEL_H */
diff --git a/plugins/dockers/animation/timeline_frames_view.cpp b/plugins/dockers/animation/timeline_frames_view.cpp
index 51933cb114..826d805fbe 100644
--- a/plugins/dockers/animation/timeline_frames_view.cpp
+++ b/plugins/dockers/animation/timeline_frames_view.cpp
@@ -1,916 +1,1062 @@
/*
* Copyright (c) 2015 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 "timeline_frames_view.h"
#include "timeline_frames_model.h"
#include "timeline_ruler_header.h"
#include "timeline_layers_header.h"
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_debug.h"
#include "timeline_frames_item_delegate.h"
#include "kis_zoom_button.h"
#include "kis_icon_utils.h"
#include "kis_animation_utils.h"
#include "kis_custom_modifiers_catcher.h"
#include "kis_action.h"
#include "kis_signal_compressor.h"
#include "kis_time_range.h"
#include "kis_color_label_selector_widget.h"
+#include "kis_slider_spin_box.h"
+#include
+
+#include
+#include
+#include
+
+#include "config-qtmultimedia.h"
typedef QPair QItemViewPaintPair;
typedef QList QItemViewPaintPairs;
struct TimelineFramesView::Private
{
Private(TimelineFramesView *_q)
: q(_q),
fps(1),
zoomStillPointIndex(-1),
zoomStillPointOriginalOffset(0),
dragInProgress(false),
dragWasSuccessful(false),
modifiersCatcher(0),
selectionChangedCompressor(300, KisSignalCompressor::FIRST_INACTIVE)
{}
TimelineFramesView *q;
TimelineFramesModel *model;
TimelineRulerHeader *horizontalRuler;
TimelineLayersHeader *layersHeader;
int fps;
int zoomStillPointIndex;
int zoomStillPointOriginalOffset;
QPoint initialDragPanValue;
QPoint initialDragPanPos;
QToolButton *addLayersButton;
KisAction *showHideLayerAction;
+ QToolButton *audioOptionsButton;
+
KisColorLabelSelectorWidget *colorSelector;
QWidgetAction *colorSelectorAction;
KisColorLabelSelectorWidget *multiframeColorSelector;
QWidgetAction *multiframeColorSelectorAction;
+ QMenu *audioOptionsMenu;
+ QAction *openAudioAction;
+ QAction *audioMuteAction;
+ KisSliderSpinBox *volumeSlider;
+
+
QMenu *layerEditingMenu;
QMenu *existingLayersMenu;
QMenu *frameCreationMenu;
QMenu *frameEditingMenu;
QMenu *multipleFrameEditingMenu;
QMap globalActions;
KisZoomButton *zoomDragButton;
bool dragInProgress;
bool dragWasSuccessful;
KisCustomModifiersCatcher *modifiersCatcher;
QPoint lastPressedPosition;
KisSignalCompressor selectionChangedCompressor;
QStyleOptionViewItem viewOptionsV4() const;
QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const;
};
TimelineFramesView::TimelineFramesView(QWidget *parent)
: QTableView(parent),
m_d(new Private(this))
{
m_d->modifiersCatcher = new KisCustomModifiersCatcher(this);
m_d->modifiersCatcher->addModifier("pan-zoom", Qt::Key_Space);
m_d->modifiersCatcher->addModifier("offset-frame", Qt::Key_Alt);
setCornerButtonEnabled(false);
setSelectionBehavior(QAbstractItemView::SelectItems);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setItemDelegate(new TimelineFramesItemDelegate(this));
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragDrop);
setAcceptDrops(true);
setDropIndicatorShown(true);
setDefaultDropAction(Qt::MoveAction);
m_d->horizontalRuler = new TimelineRulerHeader(this);
this->setHorizontalHeader(m_d->horizontalRuler);
m_d->layersHeader = new TimelineLayersHeader(this);
m_d->layersHeader->setSectionResizeMode(QHeaderView::Fixed);
m_d->layersHeader->setDefaultSectionSize(24);
m_d->layersHeader->setMinimumWidth(60);
m_d->layersHeader->setHighlightSections(true);
this->setVerticalHeader(m_d->layersHeader);
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slotUpdateInfiniteFramesCount()));
connect(horizontalScrollBar(), SIGNAL(sliderReleased()), SLOT(slotUpdateInfiniteFramesCount()));
+
+ /********** New Layer Menu ***********************************************************/
+
m_d->addLayersButton = new QToolButton(this);
m_d->addLayersButton->setAutoRaise(true);
m_d->addLayersButton->setIcon(KisIconUtils::loadIcon("addlayer"));
m_d->addLayersButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_d->addLayersButton->setPopupMode(QToolButton::InstantPopup);
m_d->layerEditingMenu = new QMenu(this);
m_d->layerEditingMenu->addAction(KisAnimationUtils::newLayerActionName, this, SLOT(slotAddNewLayer()));
m_d->existingLayersMenu = m_d->layerEditingMenu->addMenu(KisAnimationUtils::addExistingLayerActionName);
m_d->layerEditingMenu->addSeparator();
m_d->showHideLayerAction = new KisAction(KisAnimationUtils::showLayerActionName, this);
m_d->showHideLayerAction->setActivationFlags(KisAction::ACTIVE_LAYER);
connect(m_d->showHideLayerAction, SIGNAL(triggered()), SLOT(slotHideLayerFromTimeline()));
m_d->showHideLayerAction->setCheckable(true);
m_d->globalActions.insert("show_in_timeline", m_d->showHideLayerAction);
m_d->layerEditingMenu->addAction(m_d->showHideLayerAction);
m_d->layerEditingMenu->addAction(KisAnimationUtils::removeLayerActionName, this, SLOT(slotRemoveLayer()));
connect(m_d->existingLayersMenu, SIGNAL(aboutToShow()), SLOT(slotUpdateLayersMenu()));
connect(m_d->existingLayersMenu, SIGNAL(triggered(QAction*)), SLOT(slotAddExistingLayer(QAction*)));
connect(m_d->layersHeader, SIGNAL(sigRequestContextMenu(const QPoint&)), SLOT(slotLayerContextMenuRequested(const QPoint&)));
m_d->addLayersButton->setMenu(m_d->layerEditingMenu);
+ /********** Audio Channel Menu *******************************************************/
+
+ m_d->audioOptionsButton = new QToolButton(this);
+ m_d->audioOptionsButton->setAutoRaise(true);
+ m_d->audioOptionsButton->setIcon(KisIconUtils::loadIcon("audio-none"));
+ m_d->audioOptionsButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_d->audioOptionsButton->setPopupMode(QToolButton::InstantPopup);
+
+ m_d->audioOptionsMenu = new QMenu(this);
+
+#ifndef HAVE_QT_MULTIMEDIA
+ m_d->audioOptionsMenu->addSection(i18nc("@item:inmenu", "Audio playback is not supported in this build!"));
+#endif
+
+ m_d->openAudioAction= new QAction("XXX", this);
+ connect(m_d->openAudioAction, SIGNAL(triggered()), this, SLOT(slotSelectAudioChannelFile()));
+ m_d->audioOptionsMenu->addAction(m_d->openAudioAction);
+
+ m_d->audioMuteAction = new QAction(i18nc("@item:inmenu", "Mute"), this);
+ m_d->audioMuteAction->setCheckable(true);
+ connect(m_d->audioMuteAction, SIGNAL(triggered(bool)), SLOT(slotAudioChannelMute(bool)));
+
+ m_d->audioOptionsMenu->addAction(m_d->audioMuteAction);
+ m_d->audioOptionsMenu->addAction(i18nc("@item:inmenu", "Remove audio"), this, SLOT(slotAudioChannelRemove()));
+
+ m_d->audioOptionsMenu->addSeparator();
+
+ m_d->volumeSlider = new KisSliderSpinBox(this);
+ m_d->volumeSlider->setRange(0, 100);
+ m_d->volumeSlider->setSuffix("%");
+ m_d->volumeSlider->setPrefix(i18nc("@item:inmenu, slider", "Volume:"));
+ m_d->volumeSlider->setSingleStep(1);
+ m_d->volumeSlider->setPageStep(10);
+ m_d->volumeSlider->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+ connect(m_d->volumeSlider, SIGNAL(valueChanged(int)), SLOT(slotAudioVolumeChanged(int)));
+
+ QWidgetAction *volumeAction = new QWidgetAction(m_d->audioOptionsMenu);
+ volumeAction->setDefaultWidget(m_d->volumeSlider);
+ m_d->audioOptionsMenu->addAction(volumeAction);
+
+ m_d->audioOptionsButton->setMenu(m_d->audioOptionsMenu);
+
+ /********** Frame Editing Context Menu ***********************************************/
+
m_d->frameCreationMenu = new QMenu(this);
m_d->frameCreationMenu->addAction(KisAnimationUtils::addFrameActionName, this, SLOT(slotNewFrame()));
m_d->frameCreationMenu->addAction(KisAnimationUtils::duplicateFrameActionName, this, SLOT(slotCopyFrame()));
m_d->colorSelector = new KisColorLabelSelectorWidget(this);
m_d->colorSelectorAction = new QWidgetAction(this);
m_d->colorSelectorAction->setDefaultWidget(m_d->colorSelector);
connect(m_d->colorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged);
m_d->frameEditingMenu = new QMenu(this);
m_d->frameEditingMenu->addAction(KisAnimationUtils::removeFrameActionName, this, SLOT(slotRemoveFrame()));
m_d->frameEditingMenu->addAction(m_d->colorSelectorAction);
m_d->multiframeColorSelector = new KisColorLabelSelectorWidget(this);
m_d->multiframeColorSelectorAction = new QWidgetAction(this);
m_d->multiframeColorSelectorAction->setDefaultWidget(m_d->multiframeColorSelector);
connect(m_d->multiframeColorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged);
m_d->multipleFrameEditingMenu = new QMenu(this);
m_d->multipleFrameEditingMenu->addAction(KisAnimationUtils::removeFramesActionName, this, SLOT(slotRemoveFrame()));
m_d->multipleFrameEditingMenu->addAction(m_d->multiframeColorSelectorAction);
+ /********** Zoom Button **************************************************************/
+
m_d->zoomDragButton = new KisZoomButton(this);
m_d->zoomDragButton->setAutoRaise(true);
m_d->zoomDragButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal"));
m_d->zoomDragButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_d->zoomDragButton->setToolTip(i18nc("@info:tooltip", "Zoom Timeline. Hold down and drag left or right."));
m_d->zoomDragButton->setPopupMode(QToolButton::InstantPopup);
connect(m_d->zoomDragButton, SIGNAL(zoomLevelChanged(qreal)), SLOT(slotZoomButtonChanged(qreal)));
connect(m_d->zoomDragButton, SIGNAL(zoomStarted(qreal)), SLOT(slotZoomButtonPressed(qreal)));
setFramesPerSecond(12);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
connect(&m_d->selectionChangedCompressor, SIGNAL(timeout()),
SLOT(slotSelectionChanged()));
}
TimelineFramesView::~TimelineFramesView()
{
}
QMap TimelineFramesView::globalActions() const
{
return m_d->globalActions;
}
void resizeToMinimalSize(QAbstractButton *w, int minimalSize) {
QSize buttonSize = w->sizeHint();
if (buttonSize.height() > minimalSize) {
buttonSize = QSize(minimalSize, minimalSize);
}
w->resize(buttonSize);
}
void TimelineFramesView::updateGeometries()
{
QTableView::updateGeometries();
const int availableHeight = m_d->horizontalRuler->height();
const int margin = 2;
const int minimalSize = availableHeight - 2 * margin;
resizeToMinimalSize(m_d->addLayersButton, minimalSize);
+ resizeToMinimalSize(m_d->audioOptionsButton, minimalSize);
resizeToMinimalSize(m_d->zoomDragButton, minimalSize);
int x = 2 * margin;
int y = (availableHeight - minimalSize) / 2;
m_d->addLayersButton->move(x, 2 * y);
+ m_d->audioOptionsButton->move(x + minimalSize + 2 * margin, 2 * y);
const int availableWidth = m_d->layersHeader->width();
x = availableWidth - margin - minimalSize;
m_d->zoomDragButton->move(x, 2 * y);
}
void TimelineFramesView::setModel(QAbstractItemModel *model)
{
TimelineFramesModel *framesModel = qobject_cast(model);
m_d->model = framesModel;
QTableView::setModel(model);
connect(m_d->model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)),
this, SLOT(slotHeaderDataChanged(Qt::Orientation, int, int)));
connect(m_d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
connect(m_d->model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
this, SLOT(slotReselectCurrentIndex()));
connect(m_d->model, SIGNAL(sigInfiniteTimelineUpdateNeeded()),
this, SLOT(slotUpdateInfiniteFramesCount()));
+ connect(m_d->model, SIGNAL(sigAudioChannelChanged()),
+ this, SLOT(slotUpdateAudioActions()));
+
connect(selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
&m_d->selectionChangedCompressor, SLOT(start()));
connect(m_d->model, SIGNAL(sigEnsureRowVisible(int)), SLOT(slotEnsureRowVisible(int)));
+ slotUpdateAudioActions();
}
void TimelineFramesView::setFramesPerSecond(int fps)
{
m_d->fps = fps;
m_d->horizontalRuler->setFramePerSecond(fps);
// For some reason simple update sometimes doesn't work here, so
// reset the whole header
//
// m_d->horizontalRuler->reset();
}
void TimelineFramesView::slotZoomButtonPressed(qreal staticPoint)
{
m_d->zoomStillPointIndex =
qIsNaN(staticPoint) ? currentIndex().column() : staticPoint;
const int w = m_d->horizontalRuler->defaultSectionSize();
m_d->zoomStillPointOriginalOffset =
w * m_d->zoomStillPointIndex -
horizontalScrollBar()->value();
}
void TimelineFramesView::slotZoomButtonChanged(qreal zoomLevel)
{
if (m_d->horizontalRuler->setZoom(zoomLevel)) {
slotUpdateInfiniteFramesCount();
const int w = m_d->horizontalRuler->defaultSectionSize();
horizontalScrollBar()->setValue(w * m_d->zoomStillPointIndex - m_d->zoomStillPointOriginalOffset);
viewport()->update();
}
}
void TimelineFramesView::slotColorLabelChanged(int label)
{
Q_FOREACH(QModelIndex index, selectedIndexes()) {
m_d->model->setData(index, label, TimelineFramesModel::ColorLabel);
}
KisImageConfig config;
config.setDefaultFrameColorLabel(label);
}
+void TimelineFramesView::slotSelectAudioChannelFile()
+{
+ if (!m_d->model) return;
+
+ QString defaultDir = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
+
+ const QString currentFile = m_d->model->audioChannelFileName();
+ QDir baseDir = QFileInfo(currentFile).absoluteDir();
+ if (baseDir.exists()) {
+ defaultDir = baseDir.absolutePath();
+ }
+
+ const QString result = KisImportExportManager::askForAudioFileName(defaultDir, this);
+ const QFileInfo info(result);
+
+ if (info.exists()) {
+ m_d->model->setAudioChannelFileName(info.absoluteFilePath());
+ }
+}
+
+void TimelineFramesView::slotAudioChannelMute(bool value)
+{
+ if (!m_d->model) return;
+
+ if (value != m_d->model->isAudioMuted()) {
+ m_d->model->setAudioMuted(value);
+ }
+}
+
+void TimelineFramesView::slotAudioChannelRemove()
+{
+ if (!m_d->model) return;
+ m_d->model->setAudioChannelFileName(QString());
+}
+
+void TimelineFramesView::slotUpdateAudioActions()
+{
+ if (!m_d->model) return;
+
+ const QString currentFile = m_d->model->audioChannelFileName();
+
+ if (currentFile.isEmpty()) {
+ m_d->openAudioAction->setText(i18nc("@item:inmenu", "Open audio..."));
+ } else {
+ QFileInfo info(currentFile);
+ m_d->openAudioAction->setText(i18nc("@item:inmenu", "Change audio (%1)...", info.fileName()));
+ }
+
+ m_d->audioMuteAction->setChecked(m_d->model->isAudioMuted());
+
+ QIcon audioIcon;
+ if (currentFile.isEmpty()) {
+ audioIcon = KisIconUtils::loadIcon("audio-none");
+ } else {
+ if (m_d->model->isAudioMuted()) {
+ audioIcon = KisIconUtils::loadIcon("audio-volume-mute");
+ } else {
+ audioIcon = KisIconUtils::loadIcon("audio-volume-high");
+ }
+ }
+
+ m_d->audioOptionsButton->setIcon(audioIcon);
+
+ m_d->volumeSlider->setEnabled(!m_d->model->isAudioMuted());
+
+ KisSignalsBlocker b(m_d->volumeSlider);
+ m_d->volumeSlider->setValue(qRound(m_d->model->audioVolume() * 100.0));
+}
+
+void TimelineFramesView::slotAudioVolumeChanged(int value)
+{
+ m_d->model->setAudioVolume(qreal(value) / 100.0);
+}
+
void TimelineFramesView::slotUpdateInfiniteFramesCount()
{
if (horizontalScrollBar()->isSliderDown()) return;
const int sectionWidth = m_d->horizontalRuler->defaultSectionSize();
const int calculatedIndex =
(horizontalScrollBar()->value() +
m_d->horizontalRuler->width() - 1) / sectionWidth;
m_d->model->setLastVisibleFrame(calculatedIndex);
}
void TimelineFramesView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
QTableView::currentChanged(current, previous);
if (previous.column() != current.column()) {
m_d->model->setData(previous, false, TimelineFramesModel::ActiveFrameRole);
m_d->model->setData(current, true, TimelineFramesModel::ActiveFrameRole);
}
}
QItemSelectionModel::SelectionFlags TimelineFramesView::selectionCommand(const QModelIndex &index,
const QEvent *event) const
{
// WARNING: Copy-pasted from KisNodeView! Please keep in sync!
/**
* Qt has a bug: when we Ctrl+click on an item, the item's
* selections gets toggled on mouse *press*, whereas usually it is
* done on mouse *release*. Therefore the user cannot do a
* Ctrl+D&D with the default configuration. This code fixes the
* problem by manually returning QItemSelectionModel::NoUpdate
* flag when the user clicks on an item and returning
* QItemSelectionModel::Toggle on release.
*/
if (event &&
(event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) &&
index.isValid()) {
const QMouseEvent *mevent = static_cast(event);
if (mevent->button() == Qt::RightButton &&
selectionModel()->selectedIndexes().contains(index)) {
// Allow calling context menu for multiple layers
return QItemSelectionModel::NoUpdate;
}
if (event->type() == QEvent::MouseButtonPress &&
(mevent->modifiers() & Qt::ControlModifier)) {
return QItemSelectionModel::NoUpdate;
}
if (event->type() == QEvent::MouseButtonRelease &&
(mevent->modifiers() & Qt::ControlModifier)) {
return QItemSelectionModel::Toggle;
}
}
return QAbstractItemView::selectionCommand(index, event);
}
void TimelineFramesView::slotSelectionChanged()
{
int minColumn = std::numeric_limits::max();
int maxColumn = std::numeric_limits::min();
foreach (const QModelIndex &idx, selectedIndexes()) {
if (idx.column() > maxColumn) {
maxColumn = idx.column();
}
if (idx.column() < minColumn) {
minColumn = idx.column();
}
}
KisTimeRange range;
if (maxColumn > minColumn) {
range = KisTimeRange(minColumn, maxColumn - minColumn + 1);
}
m_d->model->setPlaybackRange(range);
}
void TimelineFramesView::slotReselectCurrentIndex()
{
QModelIndex index = currentIndex();
currentChanged(index, index);
}
void TimelineFramesView::slotEnsureRowVisible(int row)
{
QModelIndex index = currentIndex();
if (!index.isValid() || row < 0) return;
index = m_d->model->index(row, index.column());
scrollTo(index);
}
void TimelineFramesView::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
if (m_d->model->isPlaybackActive()) return;
int selectedColumn = -1;
for (int j = topLeft.column(); j <= bottomRight.column(); j++) {
QVariant value = m_d->model->data(
m_d->model->index(topLeft.row(), j),
TimelineFramesModel::ActiveFrameRole);
if (value.isValid() && value.toBool()) {
selectedColumn = j;
break;
}
}
QModelIndex index = currentIndex();
if (!index.isValid() && selectedColumn < 0) {
return;
}
if (selectedColumn == -1) {
selectedColumn = index.column();
}
if (selectedColumn != index.column() && !m_d->dragInProgress) {
int row= index.isValid() ? index.row() : 0;
setCurrentIndex(m_d->model->index(row, selectedColumn));
}
}
void TimelineFramesView::slotHeaderDataChanged(Qt::Orientation orientation, int first, int last)
{
Q_UNUSED(first);
Q_UNUSED(last);
if (orientation == Qt::Horizontal) {
const int newFps = m_d->model->headerData(0, Qt::Horizontal, TimelineFramesModel::FramesPerSecondRole).toInt();
if (newFps != m_d->fps) {
setFramesPerSecond(newFps);
}
} else /* if (orientation == Qt::Vertical) */ {
updateShowInTimeline();
}
}
void TimelineFramesView::rowsInserted(const QModelIndex& parent, int start, int end)
{
QTableView::rowsInserted(parent, start, end);
updateShowInTimeline();
}
inline bool isIndexDragEnabled(QAbstractItemModel *model, const QModelIndex &index) {
return (model->flags(index) & Qt::ItemIsDragEnabled);
}
QStyleOptionViewItem TimelineFramesView::Private::viewOptionsV4() const
{
QStyleOptionViewItem option = q->viewOptions();
option.locale = q->locale();
option.locale.setNumberOptions(QLocale::OmitGroupSeparator);
option.widget = q;
return option;
}
QItemViewPaintPairs TimelineFramesView::Private::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
{
Q_ASSERT(r);
QRect &rect = *r;
const QRect viewportRect = q->viewport()->rect();
QItemViewPaintPairs ret;
for (int i = 0; i < indexes.count(); ++i) {
const QModelIndex &index = indexes.at(i);
const QRect current = q->visualRect(index);
if (current.intersects(viewportRect)) {
ret += qMakePair(current, index);
rect |= current;
}
}
rect &= viewportRect;
return ret;
}
QPixmap TimelineFramesView::Private::renderToPixmap(const QModelIndexList &indexes, QRect *r) const
{
Q_ASSERT(r);
QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
if (paintPairs.isEmpty())
return QPixmap();
QPixmap pixmap(r->size());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
QStyleOptionViewItem option = viewOptionsV4();
option.state |= QStyle::State_Selected;
for (int j = 0; j < paintPairs.count(); ++j) {
option.rect = paintPairs.at(j).first.translated(-r->topLeft());
const QModelIndex ¤t = paintPairs.at(j).second;
//adjustViewOptionsForIndex(&option, current);
q->itemDelegate(current)->paint(&painter, option, current);
}
return pixmap;
}
void TimelineFramesView::startDrag(Qt::DropActions supportedActions)
{
QModelIndexList indexes = selectionModel()->selectedIndexes();
if (!indexes.isEmpty() && m_d->modifiersCatcher->modifierPressed("offset-frame")) {
QVector rows;
int leftmostColumn = std::numeric_limits::max();
Q_FOREACH (const QModelIndex &index, indexes) {
leftmostColumn = qMin(leftmostColumn, index.column());
if (!rows.contains(index.row())) {
rows.append(index.row());
}
}
const int lastColumn = m_d->model->columnCount() - 1;
selectionModel()->clear();
Q_FOREACH (const int row, rows) {
QItemSelection sel(m_d->model->index(row, leftmostColumn), m_d->model->index(row, lastColumn));
selectionModel()->select(sel, QItemSelectionModel::Select);
}
supportedActions = Qt::MoveAction;
{
QModelIndexList indexes = selectedIndexes();
for(int i = indexes.count() - 1 ; i >= 0; --i) {
if (!isIndexDragEnabled(m_d->model, indexes.at(i)))
indexes.removeAt(i);
}
selectionModel()->clear();
if (indexes.count() > 0) {
QMimeData *data = m_d->model->mimeData(indexes);
if (!data)
return;
QRect rect;
QPixmap pixmap = m_d->renderToPixmap(indexes, &rect);
rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
QDrag *drag = new QDrag(this);
drag->setPixmap(pixmap);
drag->setMimeData(data);
drag->setHotSpot(m_d->lastPressedPosition - rect.topLeft());
drag->exec(supportedActions, Qt::MoveAction);
setCurrentIndex(currentIndex());
}
}
} else {
/**
* Workaround for Qt5's bugs:
*
* 1) Qt doesn't treat selection the selection on D&D
* correctly, so we save it in advance and restore
* afterwards.
*
* 2) There is a private variable in QAbstractItemView:
* QAbstractItemView::Private::currentSelectionStartIndex.
* It is initialized *only* when the setCurrentIndex() is called
* explicitly on the view object, not on the selection model.
* Therefore we should explicitly call setCurrentIndex() after
* D&D, even if it already has *correct* value!
*
* 2) We should also call selectionModel()->select()
* explicitly. There are two reasons for it: 1) Qt doesn't
* maintain selection over D&D; 2) when reselecting single
* element after D&D, Qt goes crazy, because it tries to
* read *global* keyboard modifiers. Therefore if we are
* dragging with Shift or Ctrl pressed it'll get crazy. So
* just reset it explicitly.
*/
QModelIndexList selectionBefore = selectionModel()->selectedIndexes();
QModelIndex currentBefore = selectionModel()->currentIndex();
// initialize a global status variable
m_d->dragWasSuccessful = false;
QAbstractItemView::startDrag(supportedActions);
QModelIndex newCurrent;
QPoint selectionOffset;
if (m_d->dragWasSuccessful) {
newCurrent = currentIndex();
selectionOffset = QPoint(newCurrent.column() - currentBefore.column(),
newCurrent.row() - currentBefore.row());
} else {
newCurrent = currentBefore;
selectionOffset = QPoint();
}
setCurrentIndex(newCurrent);
selectionModel()->clearSelection();
Q_FOREACH (const QModelIndex &idx, selectionBefore) {
QModelIndex newIndex =
model()->index(idx.row() + selectionOffset.y(),
idx.column() + selectionOffset.x());
selectionModel()->select(newIndex, QItemSelectionModel::Select);
}
}
}
void TimelineFramesView::dragEnterEvent(QDragEnterEvent *event)
{
m_d->dragInProgress = true;
m_d->model->setScrubState(true);
QTableView::dragEnterEvent(event);
}
void TimelineFramesView::dragMoveEvent(QDragMoveEvent *event)
{
m_d->dragInProgress = true;
m_d->model->setScrubState(true);
QTableView::dragMoveEvent(event);
if (event->isAccepted()) {
QModelIndex index = indexAt(event->pos());
if (!m_d->model->canDropFrameData(event->mimeData(), index)) {
event->ignore();
} else {
selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
}
}
}
void TimelineFramesView::dropEvent(QDropEvent *event)
{
m_d->dragInProgress = false;
m_d->model->setScrubState(false);
QAbstractItemView::dropEvent(event);
m_d->dragWasSuccessful = event->isAccepted();
}
void TimelineFramesView::dragLeaveEvent(QDragLeaveEvent *event)
{
m_d->dragInProgress = false;
m_d->model->setScrubState(false);
QAbstractItemView::dragLeaveEvent(event);
}
void TimelineFramesView::mousePressEvent(QMouseEvent *event)
{
QPersistentModelIndex index = indexAt(event->pos());
if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
if (event->button() == Qt::RightButton) {
// TODO: try calculate index under mouse cursor even when
// it is outside any visible row
qreal staticPoint = index.isValid() ? index.column() : currentIndex().column();
m_d->zoomDragButton->beginZoom(event->pos(), staticPoint);
} else if (event->button() == Qt::LeftButton) {
m_d->initialDragPanPos = event->pos();
m_d->initialDragPanValue =
QPoint(horizontalScrollBar()->value(),
verticalScrollBar()->value());
}
event->accept();
} else if (event->button() == Qt::RightButton) {
int numSelectedItems = selectionModel()->selectedIndexes().size();
if (index.isValid() &&
numSelectedItems <= 1 &&
m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) {
model()->setData(index, true, TimelineFramesModel::ActiveLayerRole);
model()->setData(index, true, TimelineFramesModel::ActiveFrameRole);
setCurrentIndex(index);
if (model()->data(index, TimelineFramesModel::FrameExistsRole).toBool() ||
model()->data(index, TimelineFramesModel::SpecialKeyframeExists).toBool()) {
{
KisSignalsBlocker b(m_d->colorSelector);
QVariant colorLabel = index.data(TimelineFramesModel::ColorLabel);
int labelIndex = colorLabel.isValid() ? colorLabel.toInt() : 0;
m_d->colorSelector->setCurrentIndex(labelIndex);
}
m_d->frameEditingMenu->exec(event->globalPos());
} else {
m_d->frameCreationMenu->exec(event->globalPos());
}
} else if (numSelectedItems > 1) {
int labelIndex = 0;
bool haveFrames = false;
Q_FOREACH(QModelIndex index, selectedIndexes()) {
haveFrames |= index.data(TimelineFramesModel::FrameExistsRole).toBool();
QVariant colorLabel = index.data(TimelineFramesModel::ColorLabel);
if (colorLabel.isValid()) {
if (labelIndex == 0) {
labelIndex = colorLabel.toInt();
} else {
labelIndex = 0;
break;
}
}
}
if (!haveFrames) {
m_d->multiframeColorSelectorAction->setVisible(false);
} else {
KisSignalsBlocker b(m_d->multiframeColorSelector);
m_d->multiframeColorSelector->setCurrentIndex(labelIndex);
m_d->multiframeColorSelectorAction->setVisible(true);
}
m_d->multipleFrameEditingMenu->exec(event->globalPos());
}
} else {
if (index.isValid()) {
m_d->model->setLastClickedIndex(index);
}
m_d->lastPressedPosition =
QPoint(horizontalOffset(), verticalOffset()) + event->pos();
QAbstractItemView::mousePressEvent(event);
}
}
void TimelineFramesView::mouseMoveEvent(QMouseEvent *e)
{
if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
if (e->buttons() & Qt::RightButton) {
m_d->zoomDragButton->continueZoom(e->pos());
} else if (e->buttons() & Qt::LeftButton) {
QPoint diff = e->pos() - m_d->initialDragPanPos;
QPoint offset = QPoint(m_d->initialDragPanValue.x() - diff.x(),
m_d->initialDragPanValue.y() - diff.y());
const int height = m_d->layersHeader->defaultSectionSize();
horizontalScrollBar()->setValue(offset.x());
verticalScrollBar()->setValue(offset.y() / height);
}
e->accept();
} else {
m_d->model->setScrubState(true);
QTableView::mouseMoveEvent(e);
}
}
void TimelineFramesView::mouseReleaseEvent(QMouseEvent *e)
{
if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
e->accept();
} else {
m_d->model->setScrubState(false);
QTableView::mouseReleaseEvent(e);
}
}
void TimelineFramesView::wheelEvent(QWheelEvent *e)
{
QModelIndex index = currentIndex();
int column= -1;
if (index.isValid()) {
column= index.column() + ((e->delta() > 0) ? 1 : -1);
}
if (column >= 0 && !m_d->dragInProgress) {
setCurrentIndex(m_d->model->index(index.row(), column));
}
}
void TimelineFramesView::slotUpdateLayersMenu()
{
QAction *action = 0;
m_d->existingLayersMenu->clear();
QVariant value = model()->headerData(0, Qt::Vertical, TimelineFramesModel::OtherLayersRole);
if (value.isValid()) {
TimelineFramesModel::OtherLayersList list = value.value();
int i = 0;
Q_FOREACH (const TimelineFramesModel::OtherLayer &l, list) {
action = m_d->existingLayersMenu->addAction(l.name);
action->setData(i++);
}
}
}
void TimelineFramesView::slotLayerContextMenuRequested(const QPoint &globalPos)
{
m_d->layerEditingMenu->exec(globalPos);
}
void TimelineFramesView::updateShowInTimeline()
{
const int row = m_d->model->activeLayerRow();
const bool status = m_d->model->headerData(row, Qt::Vertical, TimelineFramesModel::LayerUsedInTimelineRole).toBool();
m_d->showHideLayerAction->setChecked(status);
}
void TimelineFramesView::slotAddNewLayer()
{
QModelIndex index = currentIndex();
const int newRow = index.isValid() ? index.row() : 0;
model()->insertRow(newRow);
}
void TimelineFramesView::slotAddExistingLayer(QAction *action)
{
QVariant value = action->data();
if (value.isValid()) {
QModelIndex index = currentIndex();
const int newRow = index.isValid() ? index.row() + 1 : 0;
m_d->model->insertOtherLayer(value.toInt(), newRow);
}
}
void TimelineFramesView::slotRemoveLayer()
{
QModelIndex index = currentIndex();
if (!index.isValid()) return;
model()->removeRow(index.row());
}
void TimelineFramesView::slotHideLayerFromTimeline()
{
const int row = m_d->model->activeLayerRow();
const bool status = m_d->model->headerData(row, Qt::Vertical, TimelineFramesModel::LayerUsedInTimelineRole).toBool();
m_d->model->setHeaderData(row, Qt::Vertical, !status, TimelineFramesModel::LayerUsedInTimelineRole);
}
void TimelineFramesView::slotNewFrame()
{
QModelIndex index = currentIndex();
if (!index.isValid() ||
!m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) {
return;
}
m_d->model->createFrame(index);
}
void TimelineFramesView::slotCopyFrame()
{
QModelIndex index = currentIndex();
if (!index.isValid() ||
!m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) {
return;
}
m_d->model->copyFrame(index);
}
void TimelineFramesView::slotRemoveFrame()
{
QModelIndexList indexes = selectionModel()->selectedIndexes();
for (auto it = indexes.begin(); it != indexes.end(); /*noop*/) {
if (!m_d->model->data(*it, TimelineFramesModel::FrameEditableRole).toBool()) {
it = indexes.erase(it);
} else {
++it;
}
}
if (!indexes.isEmpty()) {
m_d->model->removeFrames(indexes);
}
}
diff --git a/plugins/dockers/animation/timeline_frames_view.h b/plugins/dockers/animation/timeline_frames_view.h
index 4a77116edc..0d05dd6172 100644
--- a/plugins/dockers/animation/timeline_frames_view.h
+++ b/plugins/dockers/animation/timeline_frames_view.h
@@ -1,102 +1,108 @@
/*
* Copyright (c) 2015 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 __TIMELINE_FRAMES_VIEW_H
#define __TIMELINE_FRAMES_VIEW_H
#include
#include
#include "kritaanimationdocker_export.h"
class KisAction;
class TimelineWidget;
class KRITAANIMATIONDOCKER_EXPORT TimelineFramesView : public QTableView
{
Q_OBJECT
public:
TimelineFramesView(QWidget *parent);
~TimelineFramesView();
void setModel(QAbstractItemModel *model);
void updateGeometries();
QMap globalActions() const;
public Q_SLOTS:
void slotSelectionChanged();
private Q_SLOTS:
void slotUpdateLayersMenu();
void slotAddNewLayer();
void slotAddExistingLayer(QAction *action);
void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void slotRemoveLayer();
void slotHideLayerFromTimeline();
void slotLayerContextMenuRequested(const QPoint &globalPos);
void slotNewFrame();
void slotCopyFrame();
void slotRemoveFrame();
void slotReselectCurrentIndex();
void slotUpdateInfiniteFramesCount();
void slotHeaderDataChanged(Qt::Orientation orientation, int first, int last);
void slotZoomButtonPressed(qreal staticPoint);
void slotZoomButtonChanged(qreal value);
void slotColorLabelChanged(int);
void slotEnsureRowVisible(int row);
+ void slotSelectAudioChannelFile();
+ void slotAudioChannelMute(bool value);
+ void slotAudioChannelRemove();
+ void slotUpdateAudioActions();
+ void slotAudioVolumeChanged(int value);
+
private:
void setFramesPerSecond(int fps);
void updateShowInTimeline();
protected:
QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index,
const QEvent *event) const;
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
void startDrag(Qt::DropActions supportedActions);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void wheelEvent(QWheelEvent *e);
void rowsInserted(const QModelIndex& parent, int start, int end);
private:
struct Private;
const QScopedPointer m_d;
};
#endif /* __TIMELINE_FRAMES_VIEW_H */
diff --git a/plugins/extensions/animationrenderer/AnimationRenderer.cpp b/plugins/extensions/animationrenderer/AnimationRenderer.cpp
index 4f49c05819..82137dc745 100644
--- a/plugins/extensions/animationrenderer/AnimationRenderer.cpp
+++ b/plugins/extensions/animationrenderer/AnimationRenderer.cpp
@@ -1,177 +1,177 @@
/*
* Copyright (c) 2016 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "AnimationRenderer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "DlgAnimationRenderer.h"
K_PLUGIN_FACTORY_WITH_JSON(AnimaterionRendererFactory, "kritaanimationrenderer.json", registerPlugin();)
AnimaterionRenderer::AnimaterionRenderer(QObject *parent, const QVariantList &)
: KisViewPlugin(parent)
{
// Shows the big dialog
KisAction *action = createAction("render_animation");
action->setActivationFlags(KisAction::IMAGE_HAS_ANIMATION);
connect(action, SIGNAL(triggered()), this, SLOT(slotRenderAnimation()));
// Re-renders the image sequence as defined in the last render
action = createAction("render_image_sequence_again");
action->setActivationFlags(KisAction::IMAGE_HAS_ANIMATION);
connect(action, SIGNAL(triggered()), this, SLOT(slotRenderSequenceAgain()));
}
AnimaterionRenderer::~AnimaterionRenderer()
{
}
void AnimaterionRenderer::slotRenderAnimation()
{
KisImageWSP image = m_view->image();
if (!image) return;
if (!image->animationInterface()->hasAnimation()) return;
KisDocument *doc = m_view->document();
doc->setFileProgressProxy();
doc->setFileProgressUpdater(i18n("Export frames"));
DlgAnimationRenderer dlgAnimationRenderer(doc, m_view->mainWindow());
dlgAnimationRenderer.setCaption(i18n("Render Animation"));
KisConfig kisConfig;
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
cfg->fromXML(kisConfig.exportConfiguration("IMAGESEQUENCE"));
- // Override the saved start/end with the ones from the image in case of using gui.
- cfg->setProperty("first_frame", image->animationInterface()->playbackRange().start());
- cfg->setProperty("last_frame", image->animationInterface()->playbackRange().end());
dlgAnimationRenderer.setSequenceConfiguration(cfg);
cfg->clearProperties();
cfg->fromXML(kisConfig.exportConfiguration("ANIMATION_RENDERER"));
dlgAnimationRenderer.setVideoConfiguration(cfg);
cfg->clearProperties();
cfg->fromXML(kisConfig.exportConfiguration("FFMPEG_CONFIG"));
dlgAnimationRenderer.setEncoderConfiguration(cfg);
if (dlgAnimationRenderer.exec() == QDialog::Accepted) {
KisPropertiesConfigurationSP sequenceConfig = dlgAnimationRenderer.getSequenceConfiguration();
kisConfig.setExportConfiguration("IMAGESEQUENCE", sequenceConfig);
QString mimetype = sequenceConfig->getString("mimetype");
QString extension = KisMimeDatabase::suffixesForMimeType(mimetype).first();
QString baseFileName = QString("%1/%2.%3").arg(sequenceConfig->getString("directory"))
.arg(sequenceConfig->getString("basename"))
.arg(extension);
KisAnimationExportSaver exporter(doc, baseFileName, sequenceConfig->getInt("first_frame"), sequenceConfig->getInt("last_frame"), sequenceConfig->getInt("sequence_start"));
- bool success = exporter.exportAnimation(dlgAnimationRenderer.getFrameExportConfiguration());
- Q_ASSERT(success);
- QString savedFilesMask = exporter.savedFilesMask();
-
- KisPropertiesConfigurationSP videoConfig = dlgAnimationRenderer.getVideoConfiguration();
- if (videoConfig) {
- kisConfig.setExportConfiguration("ANIMATION_RENDERER", videoConfig);
-
- KisPropertiesConfigurationSP encoderConfig = dlgAnimationRenderer.getEncoderConfiguration();
- if (encoderConfig) {
- kisConfig.setExportConfiguration("FFMPEG_CONFIG", encoderConfig);
- encoderConfig->setProperty("savedFilesMask", savedFilesMask);
- }
+ bool success = exporter.exportAnimation(dlgAnimationRenderer.getFrameExportConfiguration()) == KisImportExportFilter::OK;
- QSharedPointer encoder = dlgAnimationRenderer.encoderFilter();
- encoder->setMimeType(mimetype.toLatin1());
- QFile fi(videoConfig->getString("filename"));
- KisImportExportFilter::ConversionStatus res;
- if (!fi.open(QIODevice::WriteOnly)) {
- qWarning() << "Could not open" << fi.fileName() << "for writing!";
- res = KisImportExportFilter::CreationError;
- }
- else {
- encoder->setFilename(fi.fileName());
- res = encoder->convert(doc, &fi, encoderConfig);
- fi.close();
- }
- if (res != KisImportExportFilter::OK) {
- QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage()));
- }
- if (videoConfig->getBool("delete_sequence", false)) {
- QDir d(sequenceConfig->getString("directory"));
- QStringList sequenceFiles = d.entryList(QStringList() << sequenceConfig->getString("basename") + "*." + extension, QDir::Files);
- Q_FOREACH(const QString &f, sequenceFiles) {
- d.remove(f);
+ // the folder could have been read-only or something else could happen
+ if (success) {
+ QString savedFilesMask = exporter.savedFilesMask();
+
+ KisPropertiesConfigurationSP videoConfig = dlgAnimationRenderer.getVideoConfiguration();
+ if (videoConfig) {
+ kisConfig.setExportConfiguration("ANIMATION_RENDERER", videoConfig);
+
+ KisPropertiesConfigurationSP encoderConfig = dlgAnimationRenderer.getEncoderConfiguration();
+ if (encoderConfig) {
+ kisConfig.setExportConfiguration("FFMPEG_CONFIG", encoderConfig);
+ encoderConfig->setProperty("savedFilesMask", savedFilesMask);
+ }
+
+ QSharedPointer encoder = dlgAnimationRenderer.encoderFilter();
+ encoder->setMimeType(mimetype.toLatin1());
+ QFile fi(videoConfig->getString("filename"));
+ KisImportExportFilter::ConversionStatus res;
+ if (!fi.open(QIODevice::WriteOnly)) {
+ qWarning() << "Could not open" << fi.fileName() << "for writing!";
+ res = KisImportExportFilter::CreationError;
+ }
+ else {
+ encoder->setFilename(fi.fileName());
+ res = encoder->convert(doc, &fi, encoderConfig);
+ fi.close();
+ }
+ if (res != KisImportExportFilter::OK) {
+ QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage()));
+ }
+ if (videoConfig->getBool("delete_sequence", false)) {
+ QDir d(sequenceConfig->getString("directory"));
+ QStringList sequenceFiles = d.entryList(QStringList() << sequenceConfig->getString("basename") + "*." + extension, QDir::Files);
+ Q_FOREACH(const QString &f, sequenceFiles) {
+ d.remove(f);
+ }
}
}
}
}
doc->clearFileProgressUpdater();
doc->clearFileProgressProxy();
}
void AnimaterionRenderer::slotRenderSequenceAgain()
{
KisImageWSP image = m_view->image();
if (!image) return;
if (!image->animationInterface()->hasAnimation()) return;
KisDocument *doc = m_view->document();
doc->setFileProgressProxy(); doc->setFileProgressUpdater(i18n("Export frames"));
KisConfig kisConfig;
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
cfg->fromXML(kisConfig.exportConfiguration("IMAGESEQUENCE"));
QString mimetype = cfg->getString("mimetype");
QString extension = KisMimeDatabase::suffixesForMimeType(mimetype).first();
QString baseFileName = QString("%1/%2.%3").arg(cfg->getString("directory"))
.arg(cfg->getString("basename"))
.arg(extension);
KisAnimationExportSaver exporter(doc, baseFileName, cfg->getInt("first_frame"), cfg->getInt("last_frame"), cfg->getInt("sequence_start"));
bool success = exporter.exportAnimation();
Q_ASSERT(success);
doc->clearFileProgressUpdater();
doc->clearFileProgressProxy();
}
#include "AnimationRenderer.moc"
diff --git a/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp b/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp
index 4f0b4c1939..4b9cc22526 100644
--- a/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp
+++ b/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp
@@ -1,417 +1,443 @@
/*
* Copyright (c) 2016 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DlgAnimationRenderer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
: KoDialog(parent)
, m_image(doc->image())
+ , m_doc(doc)
, m_defaultFileName(QFileInfo(doc->url().toLocalFile()).completeBaseName())
{
KisConfig cfg;
setCaption(i18n("Render Animation"));
setButtons(Ok | Cancel);
setDefaultButton(Ok);
+ if (m_defaultFileName.isEmpty()) {
+ m_defaultFileName = i18n("Untitled");
+ }
+
m_page = new WdgAnimaterionRenderer(this);
m_page->layout()->setMargin(0);
m_page->dirRequester->setMode(KoFileDialog::OpenDirectory);
QString lastLocation = cfg.readEntry("AnimationRenderer/last_sequence_export_location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
m_page->dirRequester->setFileName(lastLocation);
m_page->intStart->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
m_page->intStart->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
m_page->intStart->setValue(doc->image()->animationInterface()->playbackRange().start());
m_page->intEnd->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end());
+ QFileInfo audioFileInfo(doc->image()->animationInterface()->audioChannelFileName());
+ const bool hasAudio = audioFileInfo.exists();
+ m_page->chkIncludeAudio->setEnabled(hasAudio);
+ m_page->chkIncludeAudio->setChecked(hasAudio && !doc->image()->animationInterface()->isAudioMuted());
+
QStringList mimes = KisImportExportManager::mimeFilter(KisImportExportManager::Export);
mimes.sort();
Q_FOREACH(const QString &mime, mimes) {
QString description = KisMimeDatabase::descriptionForMimeType(mime);
if (description.isEmpty()) {
description = mime;
}
m_page->cmbMimetype->addItem(description, mime);
if (mime == "image/png") {
m_page->cmbMimetype->setCurrentIndex(m_page->cmbMimetype->count() - 1);
}
}
setMainWidget(m_page);
resize(m_page->sizeHint());
KoJsonTrader trader;
QListlist = trader.query("Krita/AnimationExporter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
QStringList mimetypes = json.value("X-KDE-Export").toString().split(",");
Q_FOREACH(const QString &mime, mimetypes) {
KLibFactory *factory = qobject_cast(loader->instance());
if (!factory) {
warnUI << loader->errorString();
continue;
}
QObject* obj = factory->create(0);
if (!obj || !obj->inherits("KisImportExportFilter")) {
delete obj;
continue;
}
QSharedPointerfilter(static_cast(obj));
if (!filter) {
delete obj;
continue;
}
m_renderFilters.append(filter);
QString description = KisMimeDatabase::descriptionForMimeType(mime);
if (description.isEmpty()) {
description = mime;
}
m_page->cmbRenderType->addItem(description, mime);
}
}
m_page->videoFilename->setMode(KoFileDialog::SaveFile);
m_page->videoFilename->setStartDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
qDeleteAll(list);
connect(m_page->grpRender, SIGNAL(toggled(bool)), this, SLOT(toggleSequenceType(bool)));
connect(m_page->bnExportOptions, SIGNAL(clicked()), this, SLOT(sequenceMimeTypeSelected()));
connect(m_page->bnRenderOptions, SIGNAL(clicked()), this, SLOT(selectRenderOptions()));
m_page->ffmpegLocation->setFileName(findFFMpeg());
m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile);
connect(m_page->ffmpegLocation, SIGNAL(fileSelected(QString)), this, SLOT(ffmpegLocationChanged(QString)));
m_page->grpRender->setChecked(cfg.readEntry("AnimationRenderer/render_animation", false));
m_page->chkDeleteSequence->setChecked(cfg.readEntry("AnimationRenderer/delete_sequence", false));
m_page->cmbRenderType->setCurrentIndex(cfg.readEntry("AnimationRenderer/render_type", 0));
+
+ // connect and cold init
connect(m_page->cmbRenderType, SIGNAL(currentIndexChanged(int)), this, SLOT(selectRenderType(int)));
+ selectRenderType(m_page->cmbRenderType->currentIndex());
}
DlgAnimationRenderer::~DlgAnimationRenderer()
{
KisConfig cfg;
cfg.writeEntry("AnimationRenderer/render_animation", m_page->grpRender->isChecked());
cfg.writeEntry("AnimationRenderer/last_sequence_export_location", m_page->dirRequester->fileName());
cfg.writeEntry("AnimationRenderer/render_type", m_page->cmbRenderType->currentIndex());
cfg.writeEntry("AnimationRenderer/delete_sequence", m_page->chkDeleteSequence->isChecked());
cfg.setCustomFFMpegPath(m_page->ffmpegLocation->fileName());
if (m_encoderConfigWidget) {
m_encoderConfigWidget->setParent(0);
m_encoderConfigWidget->deleteLater();
}
if (m_frameExportConfigWidget) {
m_frameExportConfigWidget->setParent(0);
m_frameExportConfigWidget->deleteLater();
}
delete m_page;
}
KisPropertiesConfigurationSP DlgAnimationRenderer::getSequenceConfiguration() const
{
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
cfg->setProperty("basename", m_page->txtBasename->text());
+ cfg->setProperty("last_document_path", m_doc->localFilePath());
cfg->setProperty("directory", m_page->dirRequester->fileName());
cfg->setProperty("first_frame", m_page->intStart->value());
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
cfg->setProperty("mimetype", m_page->cmbMimetype->currentData().toString());
return cfg;
}
void DlgAnimationRenderer::setSequenceConfiguration(KisPropertiesConfigurationSP cfg)
{
m_page->txtBasename->setText(cfg->getString("basename", "frame"));
+
+ if (cfg->getString("last_document_path") != m_doc->localFilePath()) {
+ cfg->removeProperty("first_frame");
+ cfg->removeProperty("last_frame");
+ cfg->removeProperty("sequence_start");
+ }
+
m_page->dirRequester->setFileName(cfg->getString("directory", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)));
m_page->intStart->setValue(cfg->getInt("first_frame", m_image->animationInterface()->playbackRange().start()));
m_page->intEnd->setValue(cfg->getInt("last_frame", m_image->animationInterface()->playbackRange().end()));
m_page->sequenceStart->setValue(cfg->getInt("sequence_start", m_image->animationInterface()->playbackRange().start()));
QString mimetype = cfg->getString("mimetype");
for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
if (m_page->cmbMimetype->itemData(i).toString() == mimetype) {
m_page->cmbMimetype->setCurrentIndex(i);
break;
}
}
}
KisPropertiesConfigurationSP DlgAnimationRenderer::getFrameExportConfiguration() const
{
if (m_frameExportConfigWidget) {
KisPropertiesConfigurationSP cfg = m_frameExportConfigWidget->configuration();
cfg->setProperty("basename", m_page->txtBasename->text());
cfg->setProperty("directory", m_page->dirRequester->fileName());
cfg->setProperty("first_frame", m_page->intStart->value());
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
cfg->setProperty("ffmpeg_path", m_page->ffmpegLocation->fileName());
return m_frameExportConfigWidget->configuration();
}
return 0;
}
bool DlgAnimationRenderer::renderToVideo() const
{
return m_page->grpRender->isChecked();
}
KisPropertiesConfigurationSP DlgAnimationRenderer::getVideoConfiguration() const
{
if (!m_page->grpRender->isChecked()) {
return 0;
}
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
QString filename = m_page->videoFilename->fileName();
if (QFileInfo(filename).completeSuffix().isEmpty()) {
QString mimetype = m_page->cmbRenderType->itemData(m_page->cmbRenderType->currentIndex()).toString();
filename += "." + KisMimeDatabase::suffixesForMimeType(mimetype).first();
}
cfg->setProperty("filename", filename);
cfg->setProperty("delete_sequence", m_page->chkDeleteSequence->isChecked());
+ cfg->setProperty("first_frame", m_page->intStart->value());
+ cfg->setProperty("last_frame", m_page->intEnd->value());
+ cfg->setProperty("sequence_start", m_page->sequenceStart->value());
return cfg;
}
void DlgAnimationRenderer::setVideoConfiguration(KisPropertiesConfigurationSP /*cfg*/)
{
}
KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() const
{
if (!m_page->grpRender->isChecked()) {
return 0;
}
KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
if (m_encoderConfigWidget) {
cfg = m_encoderConfigWidget->configuration();
}
cfg->setProperty("mimetype", m_page->cmbRenderType->currentData().toString());
cfg->setProperty("directory", m_page->dirRequester->fileName());
cfg->setProperty("first_frame", m_page->intStart->value());
cfg->setProperty("last_frame", m_page->intEnd->value());
cfg->setProperty("sequence_start", m_page->sequenceStart->value());
+ cfg->setProperty("include_audio", m_page->chkIncludeAudio->isChecked());
return cfg;
}
void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP /*cfg*/)
{
}
QSharedPointer DlgAnimationRenderer::encoderFilter() const
{
if (m_page->cmbRenderType->currentIndex() < m_renderFilters.size()) {
return m_renderFilters[m_page->cmbRenderType->currentIndex()];
}
return QSharedPointer(0);
}
void DlgAnimationRenderer::selectRenderType(int index)
{
if (index >= m_renderFilters.size()) return;
QString mimetype = m_page->cmbRenderType->itemData(index).toString();
if (!m_page->videoFilename->fileName().isEmpty() && QFileInfo(m_page->videoFilename->fileName()).completeBaseName() != m_defaultFileName) {
m_defaultFileName = QFileInfo(m_page->videoFilename->fileName()).completeBaseName();
}
m_page->videoFilename->setMimeTypeFilters(QStringList() << mimetype, mimetype);
+
m_page->videoFilename->setFileName(m_defaultFileName + "." + KisMimeDatabase::suffixesForMimeType(mimetype).first());
}
void DlgAnimationRenderer::selectRenderOptions()
{
int index = m_page->cmbRenderType->currentIndex();
if (m_encoderConfigWidget) {
m_encoderConfigWidget->deleteLater();
m_encoderConfigWidget = 0;
}
if (index >= m_renderFilters.size()) return;
QSharedPointer filter = m_renderFilters[index];
QString mimetype = m_page->cmbRenderType->itemData(index).toString();
if (filter) {
m_encoderConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
if (m_encoderConfigWidget) {
m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1()));
KoDialog dlg(this);
dlg.setMainWidget(m_encoderConfigWidget);
dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
if (!dlg.exec()) {
m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration());
}
dlg.setMainWidget(0);
m_encoderConfigWidget->hide();
m_encoderConfigWidget->setParent(0);
}
}
else {
m_encoderConfigWidget = 0;
}
}
void DlgAnimationRenderer::toggleSequenceType(bool toggle)
{
m_page->cmbMimetype->setEnabled(!toggle);
for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
if (m_page->cmbMimetype->itemData(i).toString() == "image/png") {
m_page->cmbMimetype->setCurrentIndex(i);
break;
}
}
}
void DlgAnimationRenderer::sequenceMimeTypeSelected()
{
int index = m_page->cmbMimetype->currentIndex();
if (m_frameExportConfigWidget) {
m_frameExportConfigWidget->deleteLater();
m_frameExportConfigWidget = 0;
}
QString mimetype = m_page->cmbMimetype->itemData(index).toString();
QSharedPointer filter(KisImportExportManager::filterForMimeType(mimetype, KisImportExportManager::Export));
if (filter) {
m_frameExportConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
if (m_frameExportConfigWidget) {
m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1()));
KoDialog dlg(this);
dlg.setMainWidget(m_frameExportConfigWidget);
dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
if (!dlg.exec()) {
m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration());
}
m_frameExportConfigWidget->hide();
m_frameExportConfigWidget->setParent(0);
dlg.setMainWidget(0);
}
}
}
void DlgAnimationRenderer::ffmpegLocationChanged(const QString &s)
{
KisConfig cfg;
cfg.setCustomFFMpegPath(s);
}
void DlgAnimationRenderer::slotButtonClicked(int button)
{
if (button == KoDialog::Ok && m_page->grpRender->isChecked()) {
QString ffmpeg = m_page->ffmpegLocation->fileName();
if (m_page->videoFilename->fileName().isEmpty()) {
QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Please enter a file name to render to."));
return;
}
else if (ffmpeg.isEmpty()) {
QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is unknown. Please install FFmpeg first: Krita cannot render animations without FFmpeg. (www.ffmpeg.org )"));
return;
}
else {
QFileInfo fi(ffmpeg);
if (!fi.exists()) {
QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is invalid. Please select the correct location of the FFmpeg executable on your system."));
return;
}
}
}
KoDialog::slotButtonClicked(button);
}
QString DlgAnimationRenderer::findFFMpeg()
{
QString result;
QStringList proposedPaths;
QString customPath = KisConfig().customFFMpegPath();
proposedPaths << customPath;
proposedPaths << customPath + QDir::separator() + "ffmpeg";
proposedPaths << QDir::homePath() + "/bin/ffmpeg";
proposedPaths << "/usr/bin/ffmpeg";
proposedPaths << "/usr/local/bin/ffmpeg";
proposedPaths << KoResourcePaths::getApplicationRoot() +
QDir::separator() + "bin" + QDir::separator() + "ffmpeg";
Q_FOREACH (const QString &path, proposedPaths) {
if (path.isEmpty()) continue;
QProcess testProcess;
testProcess.start(path, QStringList() << "-version");
testProcess.waitForFinished(1000);
const bool successfulStart =
testProcess.state() == QProcess::NotRunning &&
testProcess.error() == QProcess::UnknownError;
if (successfulStart) {
result = path;
break;
}
}
return result;
}
diff --git a/plugins/extensions/animationrenderer/DlgAnimationRenderer.h b/plugins/extensions/animationrenderer/DlgAnimationRenderer.h
index 9d86a7a710..6861fb41f3 100644
--- a/plugins/extensions/animationrenderer/DlgAnimationRenderer.h
+++ b/plugins/extensions/animationrenderer/DlgAnimationRenderer.h
@@ -1,95 +1,96 @@
/*
* Copyright (c) 2016 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DLG_ANIMATIONRENDERERIMAGE
#define DLG_ANIMATIONRENDERERIMAGE
#include
#include
#include "ui_wdg_animationrenderer.h"
#include
#include
class KisDocument;
class KisImportExportFilter;
class KisConfigWidget;
class QHBoxLayout;
class WdgAnimaterionRenderer : public QWidget, public Ui::WdgAnimaterionRenderer
{
Q_OBJECT
public:
WdgAnimaterionRenderer(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
}
};
class DlgAnimationRenderer: public KoDialog
{
Q_OBJECT
public:
DlgAnimationRenderer(KisDocument *doc, QWidget *parent = 0);
~DlgAnimationRenderer();
KisPropertiesConfigurationSP getSequenceConfiguration() const;
void setSequenceConfiguration(KisPropertiesConfigurationSP cfg);
KisPropertiesConfigurationSP getFrameExportConfiguration() const;
bool renderToVideo() const;
KisPropertiesConfigurationSP getVideoConfiguration() const;
void setVideoConfiguration(KisPropertiesConfigurationSP cfg);
KisPropertiesConfigurationSP getEncoderConfiguration() const;
void setEncoderConfiguration(KisPropertiesConfigurationSP cfg);
QSharedPointer encoderFilter() const;
private Q_SLOTS:
void selectRenderType(int i);
void selectRenderOptions();
void toggleSequenceType(bool toggle);
void sequenceMimeTypeSelected();
void ffmpegLocationChanged(const QString&);
protected Q_SLOTS:
void slotButtonClicked(int button);
private:
static QString findFFMpeg();
- KisImageWSP m_image;
+ KisImageSP m_image;
+ KisDocument *m_doc;
WdgAnimaterionRenderer *m_page {0};
QList> m_renderFilters;
KisConfigWidget *m_encoderConfigWidget {0};
KisConfigWidget *m_frameExportConfigWidget {0};
QString m_defaultFileName;
};
#endif // DLG_ANIMATIONRENDERERIMAGE
diff --git a/plugins/extensions/animationrenderer/wdg_animationrenderer.ui b/plugins/extensions/animationrenderer/wdg_animationrenderer.ui
index f60044edc7..4364bdf2dc 100644
--- a/plugins/extensions/animationrenderer/wdg_animationrenderer.ui
+++ b/plugins/extensions/animationrenderer/wdg_animationrenderer.ui
@@ -1,282 +1,289 @@
WdgAnimaterionRenderer
0
0
444
443
AnimationRenderer Image
-
Image Sequence
-
Base name:
-
frame
-
Fi&le format:
label_8
-
-
2
0
Select the file format for the image sequence. If you want to render to video or animated gif, you can only select PNG
-
Select the frame export options
...
-
Render location:
-
1
0
-
First frame:
-
1
0
-
Last frame:
-
1
0
-
-
Naming sequence starts with:
-
1
0
-
Qt::Vertical
20
40
-
0
1
Render
true
false
-
Render as:
-
-
-
Select the ffmpeg render options.
...
-
File:
-
1
0
-
FF&Mpeg:
ffmpegLocation
-
- -
+
-
Delete Sequence After Rendering
true
- -
+
-
Qt::Vertical
20
40
+ -
+
+
+ Include Audio
+
+
+
KisFileNameRequester
QWidget
kis_file_name_requester.h
1
txtBasename
cmbMimetype
intStart
intEnd
sequenceStart
grpRender
cmbRenderType
chkDeleteSequence
diff --git a/plugins/impex/libkra/kis_kra_loader.cpp b/plugins/impex/libkra/kis_kra_loader.cpp
index b076d719bb..3c5e89a147 100644
--- a/plugins/impex/libkra/kis_kra_loader.cpp
+++ b/plugins/impex/libkra/kis_kra_loader.cpp
@@ -1,1105 +1,1156 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2007
*
* 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 "kis_kra_loader.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "lazybrush/kis_colorize_mask.h"
#include
#include