diff --git a/CMakeLists.txt b/CMakeLists.txt index cdf8f95877..b1f52c7b34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,740 +1,742 @@ 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) set(MIN_FRAMEWORKS_VERSION 5.18.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.11 -Wno-macro-redefined -Wno-deprecated-register) endif() if (CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9 AND NOT WIN32) add_definitions(-Werror=delete-incomplete) endif() ###################### ####################### ## Constants defines ## ####################### ###################### # define common versions of Krita applications, used to generate kritaversion.h # update these version for every release: set(KRITA_VERSION_STRING "4.2.0-pre-alpha") # Major version: 3 for 3.x, 4 for 4.x, etc. set(KRITA_STABLE_VERSION_MAJOR 4) # Minor version: 0 for 4.0, 1 for 4.1, etc. set(KRITA_STABLE_VERSION_MINOR 2) # Bugfix release version, or 0 for before the first stable release set(KRITA_VERSION_RELEASE 0) # the 4th digit, really only used for the Windows installer: # - [Pre-]Alpha: Starts from 0, increment 1 per release # - Beta: Starts from 50, increment 1 per release # - Stable: Set to 100, bump to 101 if emergency update is needed set(KRITA_VERSION_REVISION 0) 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 2018) # 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, 16 in 4.x series if(KRITA_STABLE_VERSION_MAJOR EQUAL 4) math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 16") else() # let's make sure we won't forget to update the "16" message(FATAL_ERROR "Reminder: please update offset == 16 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_hash(GIT_SHA1) get_git_branch(GIT_BRANCH) if(GIT_SHA1) string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1) set(KRITA_GIT_SHA1_STRING ${GIT_SHA1}) if(GIT_BRANCH) set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH}) else() set(KRITA_GIT_BRANCH_STRING "(detached HEAD)") endif() endif() # 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) 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(USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking." OFF) +configure_file(config-hash-table-implementaion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hash-table-implementaion.h) +add_feature_info("Lock free hash table" USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking.") + 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).") option(ENABLE_PYTHON_2 "Enables the compiler to look for Python 2.7 instead of Python 3. Some packaged scripts are not compatible with Python 2 and this should only be used if you really have to use 2.7." OFF) include(MacroJPEG) ######################################################### ## Look for Python3 It is also searched by KF5, ## ## so we should request the correct version in advance ## ######################################################### function(TestCompileLinkPythonLibs OUTPUT_VARNAME) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${PYTHON_INCLUDE_PATH}) set(CMAKE_REQUIRED_LIBRARIES ${PYTHON_LIBRARIES}) if (MINGW) set(CMAKE_REQUIRED_DEFINITIONS -D_hypot=hypot) endif (MINGW) unset(${OUTPUT_VARNAME} CACHE) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { Py_InitializeEx(0); }" ${OUTPUT_VARNAME}) endfunction() if(MINGW) if(ENABLE_PYTHON_2) message(FATAL_ERROR "Python 2.7 is not supported on Windows at the moment.") else(ENABLE_PYTHON_2) find_package(PythonInterp 3.6 EXACT) find_package(PythonLibs 3.6 EXACT) endif(ENABLE_PYTHON_2) if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) if(ENABLE_PYTHON_2) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonLibrary 3.6) endif(ENABLE_PYTHON_2) TestCompileLinkPythonLibs(CAN_USE_PYTHON_LIBS) if (NOT CAN_USE_PYTHON_LIBS) message(FATAL_ERROR "Compiling with Python library failed, please check whether the architecture is correct. Python will be disabled.") endif (NOT CAN_USE_PYTHON_LIBS) endif (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) else(MINGW) if(ENABLE_PYTHON_2) find_package(PythonInterp 2.7) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonInterp 3.0) find_package(PythonLibrary 3.0) endif(ENABLE_PYTHON_2) endif(MINGW) ######################## ######################### ## Look for KDE and Qt ## ######################### ######################## find_package(ECM 5.22 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 APPLE) find_package(Qt5Quick ${MIN_QT_VERSION}) set_package_properties(Qt5Quick PROPERTIES DESCRIPTION "QtQuick" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") macro_bool_to_01(Qt5Quick_FOUND HAVE_QT_QUICK) find_package(Qt5QuickWidgets ${MIN_QT_VERSION}) set_package_properties(Qt5QuickWidgets PROPERTIES DESCRIPTION "QtQuickWidgets" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") endif() if (NOT WIN32 AND NOT APPLE) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras) 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}) 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}) 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 ) if (${Qt5_VERSION} VERSION_GREATER "5.8.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50900) elseif(${Qt5_VERSION} VERSION_GREATER "5.7.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50800) elseif(${Qt5_VERSION} VERSION_GREATER "5.6.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50700) else() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50600) endif() 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() # KDECompilerSettings adds the `--export-all-symbols` linker flag. # We don't really need it. if(MINGW) string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif(MINGW) # enable exceptions globally kde_enable_exceptions() 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 1.55 REQUIRED COMPONENTS system) include_directories(SYSTEM ${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 ## ############################ ########################### 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") find_package(GIF) set_package_properties(GIF PROPERTIES DESCRIPTION "Library for loading and saving gif files." URL "http://giflib.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required by the Krita GIF filter") find_package(HEIF "1.3.0") set_package_properties(HEIF PROPERTIES DESCRIPTION "Library for loading and saving heif files." URL "https://github.com/strukturag/libheif" TYPE OPTIONAL PURPOSE "Required by the Krita HEIF 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) set_package_properties(PythonLibrary PROPERTIES DESCRIPTION "Python Library" URL "http://www.python.org" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYTHONLIBS_FOUND HAVE_PYTHONLIBS) find_package(SIP "4.18.0") set_package_properties(SIP PROPERTIES DESCRIPTION "Support for generating SIP Python bindings" URL "https://www.riverbankcomputing.com/software/sip/download" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(SIP_FOUND HAVE_SIP) find_package(PyQt5 "5.6.0") set_package_properties(PyQt5 PROPERTIES DESCRIPTION "Python bindings for Qt5." URL "https://www.riverbankcomputing.com/software/pyqt/download5" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYQT5_FOUND HAVE_PYQT5) ## ## 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 3.0 REQUIRED) set_package_properties(Eigen3 PROPERTIES DESCRIPTION "C++ template library for linear algebra" URL "http://eigen.tuxfamily.org" TYPE REQUIRED) ## ## Test for exiv2 ## find_package(Exiv2 0.16 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 2.4 REQUIRED) 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 ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") 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) endif() 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") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() elseif (NOT MSVC) set(ADDITIONAL_VC_FLAGS "-Wabi -fabi-version=0 -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() 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) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() macro(ko_compile_for_all_implementations _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() endif() set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} ) add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS}) ## ## Test endianness ## include (TestBigEndian) test_big_endian(CMAKE_WORDS_BIGENDIAN) ## ## Test for qt-poppler ## find_package(Poppler COMPONENTS Qt5) set_package_properties(Poppler PROPERTIES DESCRIPTION "A PDF rendering library" URL "http://poppler.freedesktop.org" TYPE OPTIONAL PURPOSE "Required by the Krita PDF filter.") ############################ ############################# ## 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) if(WIN32) include(${CMAKE_CURRENT_LIST_DIR}/packaging/windows/installer/ConfigureInstallerNsis.cmake) endif() message("\nBroken tests:") foreach(tst ${KRITA_BROKEN_TESTS}) message(" * ${tst}") endforeach() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po OR EXISTS ${CMAKE_CURRENT_BINARY_DIR}/po ) find_package(KF5I18n CONFIG REQUIRED) ki18n_install(po) endif() diff --git a/build-tools/docker/Dockerfile b/build-tools/docker/Dockerfile index ff5f8b99df..8682392bed 100644 --- a/build-tools/docker/Dockerfile +++ b/build-tools/docker/Dockerfile @@ -1,35 +1,44 @@ FROM kdeorg/appimage-base MAINTAINER Dmitry Kazakov -RUN apt-get update && apt-get -y install curl +RUN apt-get update && \ + apt-get -y install curl && \ + apt-get -y install emacs24-nox && \ + apt-get -y install gitk git-gui && \ + apt-get -y install cmake3-curses-gui gdb valgrind sysvinit-utils && \ + apt-get -y install mirage && \ + apt-get -y install mesa-utils ENV USRHOME=/home/appimage RUN chsh -s /bin/bash appimage RUN locale-gen en_US.UTF-8 -USER appimage - RUN echo 'export LC_ALL=en_US.UTF-8' >> ${USRHOME}/.bashrc && \ echo 'export LANG=en_US.UTF-8' >> ${USRHOME}/.bashrc && \ echo "export PS1='\u@\h:\w>'" >> ${USRHOME}/.bashrc && \ echo 'source ~/devenv.inc' >> ${USRHOME}/.bashrc && \ echo 'prepend PATH ~/bin/' >> ${USRHOME}/.bashrc RUN mkdir -p ${USRHOME}/appimage-workspace/krita-inst && \ mkdir -p ${USRHOME}/appimage-workspace/krita-build && \ mkdir -p ${USRHOME}/bin COPY ./default-home/devenv.inc \ ./default-home/.bash_aliases \ ${USRHOME}/ COPY ./default-home/run_cmake.sh \ ${USRHOME}/bin ADD persistent/krita-appimage-deps.tar ${USRHOME}/appimage-workspace/ +RUN chown appimage:appimage -R ${USRHOME}/ +RUN chmod a+rwx /tmp + +USER appimage + CMD tail -f /dev/null diff --git a/build-tools/docker/README.md b/build-tools/docker/README.md index 8e362cd127..55054b94fe 100644 --- a/build-tools/docker/README.md +++ b/build-tools/docker/README.md @@ -1,114 +1,125 @@ # Krita developer environment Docker image This *Dockerfile* is based on the official KDE build environmet [0] that in used on KDE CI for building official AppImage packages. Therefore running this image in a docker container is the best way to reproduce AppImage-only bugs in Krita. [0] - https://binary-factory.kde.org/job/Krita_Nightly_Appimage_Dependency_Build/ ## Prerequisites -Firstly we need to download deps and Krita source tree. These steps are not +Firstly make sure you have Docker installed + +```bash +sudo apt install docker docker.io +``` + +Then you need to download deps and Krita source tree. These steps are not included into the *Dockerfile* to save internal bandwidth (most Krita developers already have al least one clone of Krita source tree). ```bash +# create directory structure for container control directory +mkdir -p krita-master/persistent +cd krita-master + +# copy/chechout Krita sources to 'persistent/krita' +cp -r /path/to/sources/krita ./persistent/krita + +# initialize control scripts and the Dockerfile +./persistent/krita/build-tools/docker/bin/bootstrap-root.sh + # download the deps archive ./bin/bootstrap-deps.sh - -# mount/copy/chechout Krita sources to 'persistent/krita' -mkdir -p persistent/krita -sudo mount --bind ../../ ./persistent/krita ``` ## Build the docker image and run the container ```bash ./bin/build_image krita-deps -./bin/run_container krita-deps krita-build +./bin/run_container krita-deps krita-master ``` ## Enter the container and build Krita ```bash -# enter the docker container -./bin/enter_container krita-build +# enter the docker container (the name will be +# fetched automatically from '.container_name' file) + +./bin/enter # ... now your are inside the container with all the deps prepared ... # build Krita as usual cd appimage-workspace/krita-build/ run_cmake.sh ~/persistent/krita make -j8 install # start Krita krita ``` ## Extra developer tools -If you want to develop Krita, you might want to install at least some -developer tools into the container, e.g. GDB, Valgring, ccmake and QtCreator. -To do that, execute the following from yout **host** console: +To install QtCreator, enter container and start the installer, downloaded while +fetching dependencies. Make sure you install it into '~/qtcreator' directory +without any version suffixes, then you will be able to use the script below: ```bash -sudo docker exec -ti -u root krita-build apt install gdb -sudo docker exec -ti -u root krita-build apt install valgrind -sudo docker exec -ti -u root krita-build apt install cmake-curses-gui - # inside the container -cd ~/persistent -wget http://master.qt.io/archive/online_installers/3.0/qt-unified-linux-x64-3.0.4-online.run -./qt-unified-linux-x64-3.0.4-online.run - -# when going through the setup wizard select not to install any -# extra Qt libraries, install QtCreator only! +./persistent/qt-creator-opensource-linux-x86_64-4.6.2.run +``` -# to start QtCreator without the conflicts to with Krita's Qt paths, type -# in your **host** console: -sudo docker exec -ti krita-build /home/appimage//Qt/Tools/QtCreator/bin/qtcreator +To start QtCreator: +```bash +# from the host +./bin/qtcreator ``` ## Stopping the container and cleaning up When not in use you can stop the container. All your filesystem state is saved, but all the currently running processes are killed (just ensure you logout from all the terminals before stopping). ```bash -sudo docker stop krita-build +# stop the container +./bin/stop + +# start the container +./bin/start ``` If you don't need your container/image anymore, you can delete them from the docker ```bash # remove the container -sudo docker rm krita-build +sudo docker rm krita-master # remove the image sudo docker rmi krita-deps ``` TODO: do we need some extra cleaups for docker's caches? ## Troubleshooting ### Krita binary is not found after the first build Either relogin to the container or just execute `source ~/.devenv.inc` ### Not enough space on root partition All the docker images and containers are stored in a special docker-daemon controlled folder under */var* directory. You might not have enough space there for building Krita (it needs about 10 GiB). In such a case it is recommended to move the docker images folder into another location, where there is enough space. ```bash echo 'DOCKER_OPTS="-g /home/devel5/docker"' >> /etc/default/docker ``` diff --git a/build-tools/docker/bin/bootstrap-deps.sh b/build-tools/docker/bin/bootstrap-deps.sh index b293b80226..b4bb707821 100755 --- a/build-tools/docker/bin/bootstrap-deps.sh +++ b/build-tools/docker/bin/bootstrap-deps.sh @@ -1,13 +1,23 @@ #!/bin/bash if [ ! -d ./persistent ]; then mkdir ./persistent fi if [ ! -f ./persistent/krita-appimage-deps.tar ]; then ( cd ./persistent/ wget https://binary-factory.kde.org/job/Krita_Nightly_Appimage_Dependency_Build/lastSuccessfulBuild/artifact/krita-appimage-deps.tar || exit 1 ) fi +creator_major=4.6 +creator_minor=2 +creator_file=qt-creator-opensource-linux-x86_64-${creator_major}.${creator_minor}.run +if [ ! -f ./persistent/${creator_file} ]; then + ( + cd ./persistent/ + wget http://download.qt.io/official_releases/qtcreator/${creator_major}/${creator_major}.${creator_minor}/${creator_file} || exit 1 + chmod a+x ${creator_file} + ) +fi diff --git a/build-tools/docker/bin/bootstrap-root.sh b/build-tools/docker/bin/bootstrap-root.sh new file mode 100755 index 0000000000..ef810f3fe5 --- /dev/null +++ b/build-tools/docker/bin/bootstrap-root.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [ -d ./persistent/krita ]; then + for i in 'bin default-home'; do + if [ ! -d "$i" ]; then + mkdir $i + fi + done + + cp persistent/krita/build-tools/docker/bin/* ./bin/ + cp persistent/krita/build-tools/docker/default-home/{,.}* ./default-home/ + cp persistent/krita/build-tools/docker/Dockerfile ./ + cp persistent/krita/build-tools/docker/README.md ./ +fi diff --git a/build-tools/docker/bin/enter b/build-tools/docker/bin/enter new file mode 100755 index 0000000000..4ae54c6f62 --- /dev/null +++ b/build-tools/docker/bin/enter @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +sudo docker exec -ti ${container_name} sh -c "cd /home/appimage && /bin/bash -l" diff --git a/build-tools/docker/bin/enter_container b/build-tools/docker/bin/enter_container deleted file mode 100755 index 083e3dd25a..0000000000 --- a/build-tools/docker/bin/enter_container +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if [ "$#" -ne 1 ]; then - echo "Usage: $0 CONTAINER_NAME" >&2 - exit 1 -fi - -sudo docker exec -ti $1 sh -c "cd /home/appimage && /bin/bash -l" diff --git a/build-tools/docker/bin/find_default_container_file.inc b/build-tools/docker/bin/find_default_container_file.inc new file mode 100644 index 0000000000..39b520a9bf --- /dev/null +++ b/build-tools/docker/bin/find_default_container_file.inc @@ -0,0 +1,30 @@ +#!/bin/bash + +function findContainerName { + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + container_file=`${DIR}/find_up ./ -name .container_name` + + if [ ! -z ${container_file} ]; then + cat ${container_file} + fi +} + +function parseContainerArgs { + container_name= + + if [ "$#" -ne 1 ]; then + if [ "$#" -eq 0 ]; then + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + container_name=$(findContainerName) + fi + + if [ -z ${container_name} ]; then + echo "Usage: $0 CONTAINER_NAME" >&2 + exit 1 + fi + else + container_name=$1 + fi + echo ${container_name} +} + diff --git a/build-tools/docker/bin/find_up b/build-tools/docker/bin/find_up new file mode 100755 index 0000000000..11d120290a --- /dev/null +++ b/build-tools/docker/bin/find_up @@ -0,0 +1,10 @@ +#!/bin/bash +set -e +path="$1" +shift 1 +while [[ $path != / ]]; +do + find "$path" -maxdepth 1 -mindepth 1 "$@" + # Note: if you want to ignore symlinks, use "$(realpath -s "$path"/..)" + path="$(readlink -f "$path"/..)" +done diff --git a/build-tools/docker/bin/install_nvidia_drivers.sh b/build-tools/docker/bin/install_nvidia_drivers.sh new file mode 100755 index 0000000000..8e7e869e17 --- /dev/null +++ b/build-tools/docker/bin/install_nvidia_drivers.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +if [ ! -e /proc/driver/nvidia/version ]; then + echo "Cannot find NVIDIA bestion file: /proc/driver/nvidia/version" + exit 1 +fi + +nvidia_version=$(cat /proc/driver/nvidia/version | head -n 1 | awk '{ print $8 }') +driver_file=NVIDIA-Linux-x86_64-${nvidia_version}.run +driver_url=http://download.nvidia.com/XFree86/Linux-x86_64/${nvidia_version}/${driver_file} + +if [ ! -f persistent/${driver_file} ]; then + ( + cd persistent + wget http://download.nvidia.com/XFree86/Linux-x86_64/${nvidia_version}/${driver_file} || exit 1 + chmod a+x ${driver_file} + ) +fi + +if [ -f persistent/${driver_file} ]; then + sudo docker exec -ti -u root ${container_name} /home/appimage/persistent/${driver_file} -a -N --ui=none --no-kernel-module -s +else + echo "Cannot find the driver file: ${driver_file}" + exit 1 +fi diff --git a/build-tools/docker/bin/qtcreator b/build-tools/docker/bin/qtcreator new file mode 100755 index 0000000000..453169e057 --- /dev/null +++ b/build-tools/docker/bin/qtcreator @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +sudo docker exec -ti ${container_name} /bin/bash -c 'source /home/appimage/devenv.inc; /home/appimage/qtcreator/bin/qtcreator.sh' diff --git a/build-tools/docker/bin/run_container b/build-tools/docker/bin/run_container index 54d67de8bc..d0eee8faba 100755 --- a/build-tools/docker/bin/run_container +++ b/build-tools/docker/bin/run_container @@ -1,21 +1,31 @@ #!/bin/bash if [ "$#" -ne 2 ]; then echo "Usage: $0 IMAGE_NAME CONTAINER_NAME" >&2 exit 1 fi +NVIDIA_OPTS= +if [ -e /dev/nvidiactl ]; then + NVIDIA_OPTS+="--device /dev/nvidia0 --device /dev/nvidiactl --device /dev/nvidia-uvm" +fi + sudo docker run -P -t -d \ -v $(pwd)/persistent/:/home/appimage/persistent/:rw \ -v /tmp/.X11-unix/:/tmp/.X11-unix \ -v /home/$USER/.Xauthority:/home/appimage/.Xauthority \ -v /etc/localtime:/etc/localtime:ro \ -e DISPLAY=$DISPLAY \ -h $HOSTNAME \ --cap-add=SYS_PTRACE \ --security-opt seccomp=unconfined \ --device /dev/dri \ --device /dev/snd \ - -p127.0.0.1:2022:22 \ + $NVIDIA_OPTS \ --name $2 \ - $1 + $1 || exit 1 + +if [ ! -f .container_name ]; then + echo $2 > .container_name +fi + diff --git a/build-tools/docker/bin/start b/build-tools/docker/bin/start new file mode 100755 index 0000000000..781b1a395b --- /dev/null +++ b/build-tools/docker/bin/start @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +sudo docker start ${container_name} diff --git a/build-tools/docker/bin/stop b/build-tools/docker/bin/stop new file mode 100755 index 0000000000..eed1ec8474 --- /dev/null +++ b/build-tools/docker/bin/stop @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +sudo docker stop ${container_name} diff --git a/build-tools/docker/bin/sudoenter b/build-tools/docker/bin/sudoenter new file mode 100755 index 0000000000..0c1bbc4ca2 --- /dev/null +++ b/build-tools/docker/bin/sudoenter @@ -0,0 +1,11 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source ${DIR}/find_default_container_file.inc + +container_name=$(parseContainerArgs $*) +if [ -z ${container_name} ]; then + exit 1 +fi + +sudo docker exec -user root -ti ${container_name} sh -c "cd /home/appimage && /bin/bash -l" diff --git a/build-tools/docker/default-home/devenv.inc b/build-tools/docker/default-home/devenv.inc index 4030c1f28f..d6acdca85f 100644 --- a/build-tools/docker/default-home/devenv.inc +++ b/build-tools/docker/default-home/devenv.inc @@ -1,26 +1,26 @@ prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; } export KRITADIR=/home/appimage/appimage-workspace/krita-inst export DEPSDIR=/home/appimage/appimage-workspace/deps/usr prepend PATH $KRITADIR/bin prepend LD_LIBRARY_PATH $KRITADIR/lib64 prepend LD_LIBRARY_PATH $KRITADIR/lib #prepend XDG_DATA_DIRS $KRITADIR/share prepend PKG_CONFIG_PATH $KRITADIR/lib64/pkgconfig prepend PKG_CONFIG_PATH $KRITADIR/lib/pkgconfig prepend PATH $DEPSDIR/bin prepend LD_LIBRARY_PATH $DEPSDIR/lib64 prepend LD_LIBRARY_PATH $DEPSDIR/lib #prepend XDG_DATA_DIRS $DEPSDIR/share prepend PKG_CONFIG_PATH $DEPSDIR/lib64/pkgconfig prepend PKG_CONFIG_PATH $DEPSDIR/lib/pkgconfig prepend CMAKE_PREFIX_PATH $DEPSDIR #prepend PYTHONPATH $DEPSDIR/lib/python3.5/ -#prepend PYTHONPATH $DEPSDIR/sip +prepend PYTHONPATH $DEPSDIR/sip #prepend PYQT_SIP_DIR_OVERRIDE $DEPSDIR/share/sip diff --git a/build-tools/docker/default-home/run_cmake.sh b/build-tools/docker/default-home/run_cmake.sh index dc5ff85582..8b8a7f6666 100755 --- a/build-tools/docker/default-home/run_cmake.sh +++ b/build-tools/docker/default-home/run_cmake.sh @@ -1,8 +1,8 @@ #!/bin/bash cmake -DCMAKE_INSTALL_PREFIX=${KRITADIR} \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBUILD_TESTING=TRUE \ -DHIDE_SAFE_ASSERTS=FALSE \ - -DPYQT_SIP_DIR_OVERRIDE=~/appimage-workspace/deps/usr/share/sip + -DPYQT_SIP_DIR_OVERRIDE=~/appimage-workspace/deps/usr/share/sip \ $@ diff --git a/config-hash-table-implementaion.h.cmake b/config-hash-table-implementaion.h.cmake new file mode 100644 index 0000000000..30dc23732a --- /dev/null +++ b/config-hash-table-implementaion.h.cmake @@ -0,0 +1,3 @@ +/* config-hash-table-implementation.h. Generated by cmake from config-hash-table-implementation.h.cmake */ + +#cmakedefine USE_LOCK_FREE_HASH_TABLE 1 diff --git a/interfaces/KoGenericRegistry.h b/interfaces/KoGenericRegistry.h index b6ea309fee..25f55dd29f 100644 --- a/interfaces/KoGenericRegistry.h +++ b/interfaces/KoGenericRegistry.h @@ -1,170 +1,201 @@ /* This file is part of the KDE project * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2006 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _KO_GENERIC_REGISTRY_H_ #define _KO_GENERIC_REGISTRY_H_ #include #include #include +#include "kis_assert.h" + /** * Base class for registry objects. * * Registered objects are owned by the registry. * * Items are mapped by QString as a unique Id. * * Example of use: * @code * class KoMyClassRegistry : public KoGenericRegistry { * public: * static KoMyClassRegistry * instance(); * private: * static KoMyClassRegistry* s_instance; * }; * * KoMyClassRegistry *KoMyClassRegistry::s_instance = 0; * KoMyClassRegistry * KoMyClassRegistry::instance() * { * if(s_instance == 0) * { * s_instance = new KoMyClassRegistry; * } * return s_instance; * } * * @endcode */ template class KoGenericRegistry { public: KoGenericRegistry() { } virtual ~KoGenericRegistry() { m_hash.clear(); } public: /** * Add an object to the registry. If it is a QObject, make sure it isn't in the * QObject ownership hierarchy, since the registry itself is responsbile for * deleting it. * * @param item the item to add (NOTE: T must have an QString id() const function) */ void add(T item) { - Q_ASSERT(item); - QString id = item->id(); + KIS_SAFE_ASSERT_RECOVER_RETURN(item); + + const QString id = item->id(); + KIS_SAFE_ASSERT_RECOVER_NOOP(!m_aliases.contains(id)); + if (m_hash.contains(id)) { m_doubleEntries << value(id); remove(id); } m_hash.insert(id, item); } /** * add an object to the registry * @param id the id of the object * @param item the item to add */ void add(const QString &id, T item) { - Q_ASSERT(item); + KIS_SAFE_ASSERT_RECOVER_RETURN(item); + KIS_SAFE_ASSERT_RECOVER_NOOP(!m_aliases.contains(id)); + if (m_hash.contains(id)) { m_doubleEntries << value(id); remove(id); } m_hash.insert(id, item); } /** * This function removes an item from the registry */ void remove(const QString &id) { m_hash.remove(id); } + void addAlias(const QString &alias, const QString &id) + { + KIS_SAFE_ASSERT_RECOVER_NOOP(!m_hash.contains(alias)); + m_aliases[alias] = id; + } + + void removeAlias(const QString &alias) + { + m_aliases.remove(alias); + } + /** * Retrieve the object from the registry based on the unique * identifier string. * * @param id the id */ T get(const QString &id) const { return value(id); } /** * @return if there is an object stored in the registry identified * by the id. * @param id the unique identifier string */ bool contains(const QString &id) const { - return m_hash.contains(id); + bool result = m_hash.contains(id); + + if (!result && m_aliases.contains(id)) { + result = m_hash.contains(m_aliases.value(id)); + } + + return result; } /** * Retrieve the object from the registry based on the unique identifier string * @param id the id */ const T value(const QString &id) const { - return m_hash.value(id); + T result = m_hash.value(id); + + if (!result && m_aliases.contains(id)) { + result = m_hash.value(m_aliases.value(id)); + } + + return result; } /** * @return a list of all keys */ QList keys() const { return m_hash.keys(); } int count() const { return m_hash.count(); } QList values() const { return m_hash.values(); } QList doubleEntries() const { return m_doubleEntries; } private: QList m_doubleEntries; private: QHash m_hash; + QHash m_aliases; }; #endif diff --git a/krita/data/templates/animation/.directory b/krita/data/templates/animation/.directory index 0e5995b3e8..b47b7e40c3 100644 --- a/krita/data/templates/animation/.directory +++ b/krita/data/templates/animation/.directory @@ -1,24 +1,25 @@ [Desktop Entry] Name=Animation Templates Name[ar]=قوالب الحركات Name[ca]=Plantilles d'animació Name[ca@valencia]=Plantilles d'animació Name[cs]=Šablony animací: Name[de]=Animations-Vorlagen Name[el]=Πρότυπα εφέ κίνησης Name[en_GB]=Animation Templates Name[es]=Plantillas de animación +Name[fr]=Modèles pour animation Name[gl]=Modelos de animación Name[is]=Sniðmát fyrir hreyfimyndir Name[it]=Modelli di animazioni Name[nl]=Animatiesjablonen Name[pl]=Szablony animacji Name[pt]=Modelos de Animações Name[pt_BR]=Modelos de animação Name[sv]=Animeringsmallar Name[tr]=Canlandırma Şablonları Name[uk]=Шаблони анімацій Name[x-test]=xxAnimation Templatesxx Name[zh_CN]=动画模板 Name[zh_TW]=動畫範本 X-KDE-DefaultTab=true diff --git a/krita/data/templates/animation/Anim-Jp-EN.desktop b/krita/data/templates/animation/Anim-Jp-EN.desktop index 99bf400a65..9a09ada8ee 100644 --- a/krita/data/templates/animation/Anim-Jp-EN.desktop +++ b/krita/data/templates/animation/Anim-Jp-EN.desktop @@ -1,29 +1,30 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-EN.kra Icon=template_animation Name=Animation-Japanese-En Name[ar]=حركة يابانيّة (إنجليزيّ) Name[ca]=Animació-Japonès-EN Name[ca@valencia]=Animació-Japonés-EN Name[de]=Animation-Japanisch-En Name[el]=Εφέ-κίνησης-Ιαπωνικό-En Name[en_GB]=Animation-Japanese-En Name[es]=Animación-Japonés-En Name[et]=Animation-Japanese-En +Name[fr]=Animation japonaise (en) Name[gl]=Animación-xaponesa-en-inglés Name[is]=Hreyfimynd-Japanska-En Name[it]=Animazione-Giapponese-EN Name[ja]=日本式アニメ(英語版) Name[nl]=Animatie-Japans-En Name[pl]=Animacja-Japońska-En Name[pt]=Animação-Japonês-EN Name[pt_BR]=Animation-Japanese-En Name[ru]=Анимация-японская-англ Name[sk]=Animation-Japanese-En Name[sv]=Animering-japanska-en Name[tr]=Canlandırma-Japonca-İngilizce Name[uk]=Японська анімація (англійською) Name[x-test]=xxAnimation-Japanese-Enxx Name[zh_CN]=日式动画 (英文图层名) Name[zh_TW]=動畫-Japanese-En diff --git a/krita/data/templates/animation/Anim-Jp-JP.desktop b/krita/data/templates/animation/Anim-Jp-JP.desktop index 404250f4e1..0d64b20fb0 100644 --- a/krita/data/templates/animation/Anim-Jp-JP.desktop +++ b/krita/data/templates/animation/Anim-Jp-JP.desktop @@ -1,29 +1,30 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-JP.kra Icon=template_animation Name=Animation-Japanese-JP Name[ar]=حركة يابانيّة (يابانيّ) Name[ca]=Animació-Japonès-JP Name[ca@valencia]=Animació-Japonés-JP Name[de]=Animation-Japanisch-JP Name[el]=Εφέ-κίνησης-Ιαπωνικό-JP Name[en_GB]=Animation-Japanese-JP Name[es]=Animación-Japonés-JP Name[et]=Animation-Japanese-JP +Name[fr]=Animation japonaise (jp) Name[gl]=Animación-xaponesa-en-xaponés Name[is]=Hreyfimynd-Japanska-JP Name[it]=Animazione-Giapponese-JP Name[ja]=日本式アニメ(日本語版) Name[nl]=Animatie-Japans-JP Name[pl]=Animacja-Japońska-JP Name[pt]=Animação-Japonês-JP Name[pt_BR]=Animation-Japanese-JP Name[ru]=Анимация-японская-японск Name[sk]=Animation-Japanese-JP Name[sv]=Animering-japanska-jp Name[tr]=Canlandırma-Japonca-JP Name[uk]=Японська анімація (японською) Name[x-test]=xxAnimation-Japanese-JPxx Name[zh_CN]=日本动画 (日式) Name[zh_TW]=動畫-Japanese-JP diff --git a/krita/data/templates/comics/a4_waffle_grid.desktop b/krita/data/templates/comics/a4_waffle_grid.desktop index 97aaee3762..873ada9ffd 100644 --- a/krita/data/templates/comics/a4_waffle_grid.desktop +++ b/krita/data/templates/comics/a4_waffle_grid.desktop @@ -1,69 +1,69 @@ [Desktop Entry] Type=Link URL=.source/a4_waffle_grid.kra Icon=template_comics_empty Name=waffle-iron grid Name[bs]=mreža sječenog željeza Name[ca]=graella de ferro Name[ca@valencia]=graella de ferro Name[da]=vaffeljernsgitter Name[de]=Waffeleisengitter Name[el]=waffle-iron κάνναβος Name[en_GB]=waffle-iron grid Name[es]=rejilla de hierro para gofres Name[et]=Vahvlimasina ruudustik Name[eu]=gofreetarako burdinazko sareta -Name[fr]=Grille en métal-gaufré +Name[fr]=Grille en métal gaufré Name[gl]=Grade de 3×5 viñetas Name[is]=vöfflujárnshnit Name[it]=Griglia a wafer Name[ja]=格子状コマ Name[kk]=торлы көзді Name[nb]=vaffeljern-rutenett Name[nds]=Wafeliesengadder Name[nl]=wafelijzer-raster Name[pl]=siatka gofrownicy Name[pt]=grelha de ferro para 'waffles' Name[pt_BR]=Grade de ferro vazia Name[ru]=Страница с ячейками Name[sk]=vaflovo-železná mriežka Name[sv]=våffelmönster Name[tr]=waffle-çelik ızgara Name[uk]=сітка з комірками Name[wa]=grile di fier a wåfes Name[x-test]=xxwaffle-iron gridxx Name[zh_CN]=十五宫格 Name[zh_TW]=鬆餅機格線 Comment=300 dpi, A4 waffle-iron grid comic page with ink and color layers Comment[bs]=300 dpi, A4 mreža sječenog željeza stranica stripa s slojevima za tintu i bojemreža sječenog željeza Comment[ca]=300 ppp, pàgina de còmic amb graella de ferro amb capes de tinta i color Comment[ca@valencia]=300 ppp, pàgina de còmic amb graella de ferro amb capes de tinta i color Comment[da]=300 dpi, A4 tegneserieside i vaffeljernsgitter med blæk og farvelag Comment[de]=Comicseite mit Waffeleisengitter-Muster, Tinten- und Farbebenen. Format A4, Auflösung 300 dpi. Comment[el]=300 dpi, σελίδα κόμικ A4 με waffle-iron κάνναβο και στρώματα μελάνης και χρώματος Comment[en_GB]=300 dpi, A4 waffle-iron grid comic page with ink and colour layers Comment[es]=página de cómic con rejilla de hierro para gofres de tamaño A4, a 300 ppp, con tinta y capas de colores Comment[et]=300 DPI A4 vahvlimasina ruudustikuga koomiksilehekülg tindi- ja värvikihiga Comment[eu]=Gofreetarako burdinazko sareta duen 300 dpi-ko A4 komiki-orria, tinta- eta kolore-geruzaduna -Comment[fr]=Page de bande dessinée avec Grille en métal-gaufré de 300 dpi, A4 avec encre et calques colorés +Comment[fr]=Page de bande dessinée avec grille en métal gaufré en A4 300 dpi avec encre et calques de couleurs Comment[gl]=Páxina de banda deseñada de grade en A4 a 300 dpi con 3×5 viñetas regulares e capas de tinta e cor. Comment[is]=300 pát, A4 vöfflujárnshnit teiknimyndasíða með lögum fyrir blek og liti Comment[it]=Pagina di fumetti con griglia a wafer a 300 dpi, A4, con livelli per inchiostro e colore Comment[ja]=300 dpi A4 サイズの、ペン入れレイヤーと彩色レイヤーを備えた格子状コマテンプレート Comment[kk]=300 н/д A4 торлы көзді парақтағы комикс Comment[nb]=300 dpi, A4 tegneserieside med vaffeljern-rutenett, med tusj- og fargelag Comment[nds]=300 dpi, A4 Wafeliesengadder-Comicsiet mit Dint un Klöörlagen. Comment[nl]=300 dpi, A4 wafelijzer-raster strippagina met inkt en kleurlagen Comment[pl]=300 dpi, strona A4 siatki gofrownicy z warstwami tuszu i koloru Comment[pt]=banda desenhada A4, em grelha de 'waffle' a 300 ppp, com camadas de cores e de pinturas Comment[pt_BR]=Página de quadrinhos A4, em grade de ferro a 300 ppp, com camadas de cores e de pinturas Comment[ru]=300 dpi, страница комикса в формате A4 с ячейками и слоями контуров и цветов Comment[sk]=300 dpi, A4 vaflovo železná mriežka komiksovej strany s atramentom a farebnými vrstvami Comment[sv]=300 punkter/tum, A4 våffelmönstrad seriesida med bläck- och färglager Comment[tr]=300 dpi, A4 waffle-çelik ızgara mürekkep ve renk katmanlı çizgi roman sayfası Comment[uk]=300 т/д, сторінка коміксу у форматі A4 з комірками та шарами контурів та кольорів Comment[wa]=Pådje A4 di binde d' imådjes avou on discôpaedje come ene grile di fier a wåfes avou des coûtches d' intche eyet d' coleurs. Comment[x-test]=xx300 dpi, A4 waffle-iron grid comic page with ink and color layersxx Comment[zh_CN]=300 DPI,A4 尺寸的十五宫格网格漫画页,内置线稿和着色图层 Comment[zh_TW]=300 dpi,A4 大小的烘餅鐵模狀的格線,有墨水與顏色圖層 X-Krita-Version=28 diff --git a/krita/krita4.xmlgui b/krita/krita4.xmlgui index 7c29c0e666..5cee8c5e52 100644 --- a/krita/krita4.xmlgui +++ b/krita/krita4.xmlgui @@ -1,379 +1,379 @@ &File &Edit Fill Special &View &Canvas &Snap To &Image &Rotate &Layer New &Import/Export Import &Convert &Select &Group &Transform &Rotate S&plit S&plit Alpha &Select - + Filte&r &Tools Scripts Setti&ngs &Help File Brushes and Stuff diff --git a/krita/org.kde.krita.appdata.xml b/krita/org.kde.krita.appdata.xml index 60ace37b65..d0259a3782 100644 --- a/krita/org.kde.krita.appdata.xml +++ b/krita/org.kde.krita.appdata.xml @@ -1,248 +1,249 @@ org.kde.krita org.kde.krita.desktop CC0-1.0 GPL-3.0-only Krita Foundation Fundació Krita Fundació Krita Krita Foundation + Krita Foundation Fundación Krita Fondazione Krita Krita Foundation Fundacja Krity Fundação do Krita Krita Foundation Krita-stiftelsen Фундація Krita xxKrita Foundationxx Krita 基金会 foundation@krita.org Krita كريتا Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita Krita xxKritaxx Krita Krita Digital Painting, Creative Freedom رسم رقميّ، حريّة إبداعيّة Pintura dixital, llibertá creativa Digitalno crtanje, kreativna sloboda Dibuix digital, Llibertat creativa Dibuix digital, Llibertat creativa Digitální malování, svoboda tvorby Digital tegning, kunstnerisk frihed Digitales Malen, kreative Freiheit Ψηφιακή ζωγραφική, δημιουργική ελευθερία Digital Painting, Creative Freedom Pintura digital, libertad creativa Digitaalne joonistamine, loominguline vabadus Digitaalimaalaus, luova vapaus Peinture numérique, liberté créatrice Debuxo dixital, liberdade creativa Pictura digital, Libertate creative Pelukisan Digital, Kebebasan Berkreatif Pittura digitale, libertà creativa Digital Painting, Creative Freedom Cyfrowe malowanie, Wolność Twórcza Pintura Digital, Liberdade Criativa Pintura digital, liberdade criativa Цифровое рисование. Творческая свобода Digitálne maľovanie, kreatívna sloboda Digital målning, kreativ frihet Sayısal Boyama, Yaratıcı Özgürlük Цифрове малювання, творча свобода xxDigital Painting, Creative Freedomxx 自由挥洒数字绘画的无限创意 數位繪畫,創作自由

Krita is the full-featured digital art studio.

Krita ye l'estudiu completu d'arte dixital.

Krita je potpuni digitalni umjetnički studio.

Krita és l'estudi d'art digital ple de funcionalitats.

Krita és l'estudi d'art digital ple de funcionalitats.

Krita ist ein digitales Designstudio mit umfangreichen Funktionen.

Το Krita είναι ένα πλήρες χαρακτηριστικών ψηφιακό ατελιέ.

Krita is the full-featured digital art studio.

Krita es un estudio de arte digital completo

Krita on rohkete võimalustega digitaalkunstistuudio.

Krita on täyspiirteinen digitaiteen ateljee.

Krita est le studio d'art numérique complet.

Krita é un estudio completo de arte dixital.

Krita es le studio de arte digital complete.

Krita adalah studio seni digital yang penuh dengan fitur.

Krita è uno studio d'arte digitale completo.

Krita は、フル機能を備えたデジタルなアートスタジオです。

Krita is de digitale kunststudio vol mogelijkheden.

Krita jest pełnowymiarowym, cyfrowym studiem artystycznym

O Krita é o estúdio de arte digital completo.

O Krita é o estúdio de arte digital completo.

Krita полнофункциональный инструмент для создания цифровой графики.

Krita je plne vybavené digitálne umelecké štúdio.

Krita är den fullfjädrade digitala konststudion.

Krita, tam özellikli dijital sanat stüdyosudur.

Krita — повноцінний комплекс для створення цифрових художніх творів.

xxKrita is the full-featured digital art studio.xx

Krita 是一款功能齐全的数字绘画工作室软件。

Krita 是全功能的數位藝術工作室。

It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.

On je savršen za skiciranje i slikanje i predstavlja finalno rješenje za kreiranje digitalnih slika od nule s majstorima

És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.

És perfecte per fer esbossos i pintar, i presenta una solució final per crear fitxers de dibuix digital des de zero per a mestres.

Είναι ιδανικό για σκιτσογραφία και ζωγραφική, και παρουσιάζει μια από άκρη σε άκρη λύση για τη δημιουργία από το μηδέν αρχείων ψηφιακης ζωγραφικής από τους δασκάλους της τέχνης.

It is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.

Es perfecto para diseñar y pintar, y ofrece una solución completa para crear desde cero archivos de pintura digital apta para profesionales.

See on suurepärane töövahend visandite ja joonistuste valmistamiseks ning annab andekatele kunstnikele võimaluse luua digitaalpilt algusest lõpuni just oma käe järgi.

Se on täydellinen luonnosteluun ja maalaukseen ja tarjoaa kokonaisratkaisun digitaalisten kuvatiedostojen luomiseen alusta alkaen.

Il est parfait pour crayonner et peindre, et constitue une solution de bout en bout pour créer des fichier de peinture numérique depuis la feuille blanche jusqu'au épreuves finales.

Resulta perfecto para debuxar e pintar, e presenta unha solución completa que permite aos mestres crear ficheiros de debuxo dixital desde cero.

Illo es perfecte pro schizzar e pinger, e presenta un solution ab fin al fin pro crear files de pictura digital ab grattamentos per maestros.

Ini adalah sempurna untuk mensketsa dan melukis, dan menghadirkan sebuah solusi untuk menciptakan file-file pelukisan digital dari goresan si pelukis ulung.

Perfetto per fare schizzi e dipingere, prevede una soluzione completa che consente agli artisti di creare file di dipinti digitali partendo da zero.

Het is perfect voor schetsen en schilderen en zet een end–to–end oplossing voor het maken van digitale bestanden voor schilderingen vanuit het niets door meesters.

Nadaje się perfekcyjnie do szkicowania i malowania i dostarcza zupełnego rozwiązania dla tworzenia plików malowideł cyfrowych od zalążka.

É perfeito para desenhos e pinturas, oferecendo uma solução final para criar ficheiros de pintura digital do zero por mestres.

É perfeito para desenhos e pinturas, oferecendo uma solução final para criar arquivos de desenho digital feitos a partir do zero por mestres.

Она превосходно подходит для набросков и рисования, предоставляя мастерам самодостаточный инструмент для создания цифровой живописи с нуля.

Je ideálna na skicovanie a maľovanie a poskytuje end-to-end riešenie na vytváranie súborov digitálneho maľovania od základu od profesionálov.

Den är perfekt för att skissa och måla, samt erbjuder en helomfattande lösning för att skapa digitala målningsfiler från grunden av mästare.

Eskiz ve boyama için mükemmeldir ve ustaların sıfırdan dijital boyama dosyaları oluşturmak için uçtan-uca bir çözüm sunar.

Цей комплекс чудово пасує для створення ескізів та художніх зображень і є самодостатнім набором для створення файлів цифрових полотен «з нуля» для справжніх художників.

xxIt is perfect for sketching and painting, and presents an end–to–end solution for creating digital painting files from scratch by masters.xx

它专门为数字绘画设计,为美术工作者提供了一个从起草、上色到完成作品等整个创作流程的完整解决方案。

它是素描和繪畫的完美選擇,並提供了一個從零開始建立數位繪畫檔的端到端解決方案。

Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.

Krita je odličan izbor za kreiranje konceptualne umjetnosti, stripove, teksture za obradu i mat slike. Krita podržava mnoge prostore boja kao RGB i CMIK na 8 i 16 bitnim cjelobrojnim kanalimaa, kao i 16 i 32 bita floating point kanalima.

El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.

El Krita és una gran elecció per crear art conceptual, còmics, textures per renderitzar i pintures «matte». El Krita permet molts espais de color com el RGB i el CMYK a 8 i 16 bits de canals sencers, així com 16 i 32 bits de canals de coma flotant.

Το Krita είναι μια εξαιρετική επιλογή για τη δημιουργία αφηρημένης τέχνης, ιστοριών με εικόνες, υφής για ζωγραφική αποτύπωσης και διάχυσης φωτός. Το Krita υποστηρίζει πολλούς χρωματικούς χώρους όπως τα RGB και CMYK σε 8 και 16 bit κανάλια ακεραίων καθώς επίσης και σε 16 και 32 bit κανάλια κινητής υποδιαστολής,

Krita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colourspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.

Krita es una gran elección para crear arte conceptual, cómics, texturas para renderizar y «matte paintings». Krita permite el uso de muchos espacios de color, como, por ejemplo, RGB y CMYK, tanto en canales de enteros de 8 y 16 bits, así como en canales de coma flotante de 16 y 32 bits.

Krita on üks paremaid valikuid kontseptuaalkunsti, koomiksite, tekstuuride ja digitaalmaalide loomiseks. Krita toetab paljusid värviruume, näiteks RGB ja CMYK 8 ja 16 täisarvulise bitiga kanali kohta, samuti 16 ja 32 ujukomabitiga kanali kohta.

Krita on hyvä valinta konseptikuvituksen, sarjakuvien, pintakuvioiden ja maalausten luomiseen. Krita tukee useita väriavaruuksia kuten RGB:tä ja CMYK:ta 8 ja 16 bitin kokonaisluku- samoin kuin 16 ja 32 bitin liukulukukanavin.

Krita est un très bon choix pour créer des concepts arts, des bandes-dessinées, des textures de rendu et des peintures. Krita prend en charge plusieurs espaces de couleurs comme RVB et CMJN avec les canaux de 8 et 16 bits entiers ainsi que les canaux de 16 et 32 bits flottants.

Krita é unha gran opción para crear arte conceptual, texturas para renderización e pinturas mate. Krita permite usar moitos espazos de cores como RGB e CMYK con canles de 8 e 16 bits, así como canles de coma flotante de 16 e 32 bits.

Krita es un grande selection pro crear arte de concepto, comics, texturas pro rendering e picturas opac. Krita supporta multe spatios de colores como RGB e CMYK con canales de integer a 8 e 16 bits, como anque canales floating point a 16 e 32 bits.

Krita adalah pilihan yang cocok untuk menciptakan konsep seni, komik, tekstur untuk rendering dan lukisan matte. Krita mendukung banyak ruang warna seperti RGB dan CMYK pada channel integer 8 dan 16 bit, serta 16 dan 32 bit channel titik mengambang.

Krita rappresenta una scelta ottimale per la creazione di arte concettuale, fumetti e texture per il rendering e il matte painting. Krita supporta molti spazi colori come RGB e CMYK a 8 e 16 bit per canali interi e 16 e 32 bit per canali a virgola mobile.

コンセプトアート、コミック、3DCG 用テクスチャ、マットペイントを制作する方にとって、Krita は最適な選択です。Krita は、8/16 ビット整数/チャンネル、および 16/32 ビット浮動小数点/チャンネルの RGB や CMYK をはじめ、さまざまな色空間をサポートしています。

Krita is een goede keuze voor het maken van kunstconcepten, strips, textuur voor weergeven en matte schilderijen. Krita ondersteunt vele kleurruimten zoals RGB en CMYK in 8 en 16 bits kanalen met gehele getallen, evenals 16 en 32 bits kanalen met drijvende komma.

Krita jest świetnym wyborem przy tworzeniu koncepcyjnej sztuki, komiksów, tekstur do wyświetlania i kaszet. Krita obsługuje wiele przestrzeni barw takich jak RGB oraz CMYK dla kanałów 8 oraz 16 bitowych wyrażonych w l. całkowitych, a także 16 oraz 32 bitowych wyrażonych w l. zmiennoprzecinkowych.

O Krita é uma óptima escolha para criar arte conceptual, banda desenhada, texturas para desenho e pinturas. O Krita suporta diversos espaços de cores como o RGB e o CMYK com canais de cores inteiros a 8 e 16 bits, assim como canais de vírgula flutuante a 16 e a 32 bits.

O Krita é uma ótima escolha para criação de arte conceitual, histórias em quadrinhos, texturas para desenhos e pinturas. O Krita tem suporte a diversos espaços de cores como RGB e CMYK com canais de cores inteiros de 8 e 16 bits, assim como canais de ponto flutuante de 16 e 32 bits.

Krita - отличный выбор для создания концепт-артов, комиксов, текстур для рендеринга и рисования. Она поддерживает множество цветовых пространств включая RGB и CMYK с 8 и 16 целыми битами на канал, а также 16 и 32 битами с плавающей запятой на канал.

Krita je výborná voľba pre vytváranie konceptového umenia, textúr na renderovanie a matné kresby. Krita podporuje mnoho farebných priestorov ako RGB a CMYK na 8 a 16 bitových celočíselných kanáloch ako aj 16 a 32 bitových reálnych kanáloch.

Krita är ett utmärkt val för att skapa concept art, serier, strukturer för återgivning och bakgrundsmålningar. Krita stöder många färgrymder som RGB och CMYK med 8- och 16-bitars heltal, samt 16- och 32-bitars flyttal.

Krita, konsept sanat, çizgi roman, kaplama ve mat resimler için dokular oluşturmak için mükemmel bir seçimdir. Krita, 8 ve 16 bit tamsayı kanallarında RGB ve CMYK gibi birçok renk alanını ve 16 ve 32 bit kayan nokta kanallarını desteklemektedir.

Krita — чудовий інструмент для створення концептуального живопису, коміксів, текстур для моделей та декорацій. У Krita передбачено підтримку багатьох просторів кольорів, зокрема RGB та CMYK з 8-бітовими та 16-бітовими цілими значеннями, а також 16-бітовими та 32-бітовими значеннями з рухомою крапкою для каналів кольорів.

xxKrita is a great choice for creating concept art, comics, textures for rendering and matte paintings. Krita supports many colorspaces like RGB and CMYK at 8 and 16 bits integer channels, as well as 16 and 32 bits floating point channels.xx

Krita 是绘制概念美术、漫画、纹理和电影布景的理想选择。Krita 支持多种色彩空间,如 8 位和 16 位整数及 16 位和 32 位浮点的 RGB 和 CMYK 颜色模型。

Krita 是創造概念藝術、漫畫、彩現紋理和場景繪畫的絕佳選擇。Krita 在 8 位元和 16 位元整數色版,以及 16 位元和 32 位元浮點色版中支援 RGB 和 CMYK 等多種色彩空間。

Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.

Zabavite se kreirajući napredne pogone četki, filtere i mnoge praktične osobine koje čine Krita vrlo produktivnim.

Gaudiu pintant amb els motors de pinzells avançats, els filtres impressionants i moltes funcionalitats útils que fan el Krita molt productiu.

Gaudiu pintant amb els motors de pinzells avançats, els filtres impressionants i moltes funcionalitats útils que fan el Krita molt productiu.

Διασκεδάστε ζωγραφίζοντας με τις προηγμένες μηχανές πινέλων, με εκπληκτικά φίλτρα και πολλά εύκολης χρήσης χαρακτηριστικά που παρέχουν στο Krita εξαιρετικά αυξημένη παραγωγικότητα.

Have fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.

Diviértase pintando con los avanzados motores de pinceles, los espectaculares filtros y muchas funcionalidades prácticas que hacen que Krita sea enormemente productivo.

Joonistamise muudavad tunduvalt lõbusamaks võimsad pintslimootorid, imetabased filtrid ja veel paljud käepärased võimalused, mis muudavad Krita kasutaja tohutult tootlikuks.

Pidä hauskaa maalatessasi edistyneillä sivellinmoottoreilla, hämmästyttävillä suotimilla ja monilla muilla kätevillä ominaisuuksilla, jotka tekevät Kritasta tavattoman tehokkaan.

Amusez-vous à peindre avec les outils de brosse avancés, les filtres incroyables et les nombreuses fonctionnalités pratiques qui rendent Krita extrêmement productif.

Goza debuxando con motores de pincel avanzados, filtros fantásticos e moitas outras funcionalidades útiles que fan de Krita un programa extremadamente produtivo.

Amusa te a pinger con le motores de pincel avantiate, filtros stupende e multe characteristicas amical que face Krita enormemente productive.

Bersenang-senanglah melukis dengan mesin kuas canggih, filter luar biasa dan banyak fitur berguna yang membuat Krita sangat produktif.

Divertiti a dipingere con gli avanzati sistemi di pennelli, i sorprendenti filtri e molte altre utili caratteristiche che fanno di Krita un software enormemente produttivo.

Krita のソフトウェアとしての生産性を高めている先進的なブラシエンジンや素晴らしいフィルタのほか、便利な機能の数々をお楽しみください。

Veel plezier met schilderen met the geavanceerde penseel-engines, filters vol verbazing en vele handige mogelijkheden die maken dat Krita enorm productief is.

Baw się przy malowaniu przy użyciu zaawansowanych silników pędzli, zadziwiających filtrów i wielu innych przydatnych cech, które czynią z Krity bardzo produktywną.

Divirta-se a pintar com os motores de pincéis avançados, os filtros espantosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.

Divirta-se pintando com os mecanismos de pincéis avançados, filtros maravilhosos e muitas outras funcionalidades úteis que tornam o Krita altamente produtivo.

Получайте удовольствие от использования особых кистевых движков, впечатляющих фильтров и множества других функций, делающих Krita сверхпродуктивной.

Užívajte si maľovanie s pokročilými kresliacimi enginmi, úžasnými filtrami a mnohými užitočnými funkciami, ktoré robia Kritu veľmi produktívnu.

Ha det så kul vid målning med de avancerade penselfunktionerna, fantastiska filtren och många praktiska funktioner som gör Krita så enormt produktiv.

Gelişmiş fırça motorları, şaşırtıcı filtreler ve Krita'yı son derece üretken yapan bir çok kullanışlı özellikli boya ile iyi eğlenceler.

Отримуйте задоволення від малювання за допомогою пензлів з найширшими можливостями, чудових фільтрів та багатьох зручних можливостей, які роблять Krita надзвичайно продуктивним засобом малювання.

xxHave fun painting with the advanced brush engines, amazing filters and many handy features that make Krita enormously productive.xx

Krita 具有功能强大的笔刷引擎、种类繁多的滤镜以及便于操作的交互设计,可让你尽情、高效地挥洒无限创意。

使用先進的筆刷引擎、驚人的濾鏡和許多方便的功能來開心地繪畫,讓 Krita 擁有巨大的生產力。

https://www.krita.org/ https://krita.org/about/faq/ https://krita.org/support-us/donations/ https://docs.krita.org/Category:Tutorials https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_001.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_002.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_003.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_004.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_005.png https://cdn.kde.org/screenshots/krita/2018-03-17_screenshot_006.png none none none none none none none none none none none none none none none none none none none none Graphics KDE krita
diff --git a/libs/global/CMakeLists.txt b/libs/global/CMakeLists.txt index e8823c59c2..1145842c59 100644 --- a/libs/global/CMakeLists.txt +++ b/libs/global/CMakeLists.txt @@ -1,52 +1,53 @@ add_subdirectory( tests ) include(CheckFunctionExists) check_function_exists(backtrace HAVE_BACKTRACE) configure_file(config-debug.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-debug.h) option(HAVE_MEMORY_LEAK_TRACKER "Enable memory leak tracker (always disabled in release build)" OFF) option(HAVE_BACKTRACE_SUPPORT "Enable recording of backtrace in memory leak tracker" OFF) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-memory-leak-tracker.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-memory-leak-tracker.h) ### WRONG PLACE??? set(kritaglobal_LIB_SRCS kis_assert.cpp kis_debug.cpp kis_algebra_2d.cpp kis_memory_leak_tracker.cpp kis_shared.cpp kis_dom_utils.cpp kis_painting_tweaks.cpp KisHandlePainterHelper.cpp KisHandleStyle.cpp kis_relaxed_timer.cpp kis_signal_compressor.cpp kis_signal_compressor_with_param.cpp kis_thread_safe_signal_compressor.cpp kis_acyclic_signal_connector.cpp kis_latency_tracker.cpp KisQPainterStateSaver.cpp KisSharedThreadPoolAdapter.cpp KisSharedRunnable.cpp KisRollingMeanAccumulatorWrapper.cpp KisLoggingManager.cpp + kis_config_notifier.cpp ) add_library(kritaglobal SHARED ${kritaglobal_LIB_SRCS} ) generate_export_header(kritaglobal BASE_NAME kritaglobal) target_link_libraries(kritaglobal PUBLIC Qt5::Concurrent Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml KF5::I18n ) set_target_properties(kritaglobal PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaglobal ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/ui/kis_config_notifier.cpp b/libs/global/kis_config_notifier.cpp similarity index 100% rename from libs/ui/kis_config_notifier.cpp rename to libs/global/kis_config_notifier.cpp diff --git a/libs/ui/kis_config_notifier.h b/libs/global/kis_config_notifier.h similarity index 95% rename from libs/ui/kis_config_notifier.h rename to libs/global/kis_config_notifier.h index da3f0cd549..2838b17984 100644 --- a/libs/ui/kis_config_notifier.h +++ b/libs/global/kis_config_notifier.h @@ -1,67 +1,67 @@ /* * Copyright (c) 2007 Adrian Page * * 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_NOTIFIER_H_ #define KIS_CONFIG_NOTIFIER_H_ #include #include -#include "kritaui_export.h" +#include "kritaglobal_export.h" /** * An object that emits a signal to inform interested parties that the * configuration settings have changed. */ -class KRITAUI_EXPORT KisConfigNotifier : public QObject +class KRITAGLOBAL_EXPORT KisConfigNotifier : public QObject { Q_OBJECT public: KisConfigNotifier(); ~KisConfigNotifier() override; /** * @return the KisConfigNotifier singleton */ static KisConfigNotifier *instance(); /** * Notify that the configuration has changed. This will cause the * configChanged() signal to be emitted. */ void notifyConfigChanged(void); void notifyDropFramesModeChanged(); void notifyPixelGridModeChanged(); Q_SIGNALS: /** * This signal is emitted whenever notifyConfigChanged() is called. */ void configChanged(void); void dropFramesModeChanged(); void pixelGridModeChanged(); private: KisConfigNotifier(const KisConfigNotifier&); KisConfigNotifier operator=(const KisConfigNotifier&); private: struct Private; const QScopedPointer m_d; }; #endif // KIS_CONFIG_NOTIFIER_H_ diff --git a/libs/global/kis_shared_ptr.h b/libs/global/kis_shared_ptr.h index 5453bfabb3..c75e1cc671 100644 --- a/libs/global/kis_shared_ptr.h +++ b/libs/global/kis_shared_ptr.h @@ -1,521 +1,526 @@ /* * Copyright (c) 2005 Frerich Raabe * Copyright (c) 2006,2010 Cyrille Berger * * 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_SHAREDPTR_H #define KIS_SHAREDPTR_H #include #include #include "kis_memory_leak_tracker.h" template class KisWeakSharedPtr; /** * KisSharedPtr is a shared pointer similar to KSharedPtr and * boost::shared_ptr. The difference with KSharedPtr is that our * constructor is not explicit. * * A shared pointer is a wrapper around a real pointer. The shared * pointer keeps a reference count, and when the reference count drops * to 0 the contained pointer is deleted. You can use the shared * pointer just as you would use a real pointer. * * See also also item 28 and 29 of More Effective C++ and * http://bugs.kde.org/show_bug.cgi?id=52261 as well as * http://www.boost.org/libs/smart_ptr/shared_ptr.htm. * * Advantage of KisSharedPtr over boost pointer or QSharedPointer? * * The difference with boost share pointer is that in * boost::shared_ptr, the counter is kept inside the smart pointer, * meaning that you should never never remove the pointer from its * smart pointer object, because if you do that, and somewhere in the * code, the pointer is put back in a smart pointer, then you have two * counters, and when one reach zero, then the object gets deleted * while some other code thinks the pointer is still valid. * * Disadvantage of KisSharedPtr compared to boost pointer? * * KisSharedPtr requires the class to inherits KisShared. * * Difference with QSharedDataPointer * * QSharedDataPointer and KisSharedPtr are very similar, but * QSharedDataPointer has an explicit constructor which makes it more * painful to use in some constructions. And QSharedDataPointer * doesn't offer a weak pointer. */ template class KisSharedPtr { friend class KisWeakSharedPtr; public: /** * Creates a null pointer. */ inline KisSharedPtr() : d(0) { } /** * Creates a new pointer. * @param p the pointer */ inline KisSharedPtr(T* p) : d(p) { ref(); } inline KisSharedPtr(const KisWeakSharedPtr& o); // Free the pointer and set it to new value void attach(T* p); // Free the pointer void clear(); /** * Copies a pointer. * @param o the pointer to copy */ inline KisSharedPtr(const KisSharedPtr& o) : d(o.d) { ref(); } /** * Dereferences the object that this pointer points to. If it was * the last reference, the object will be deleted. */ inline ~KisSharedPtr() { deref(); } inline KisSharedPtr& operator= (const KisSharedPtr& o) { attach(o.d); return *this; } inline bool operator== (const T* p) const { return (d == p); } inline bool operator!= (const T* p) const { return (d != p); } inline bool operator== (const KisSharedPtr& o) const { return (d == o.d); } inline bool operator!= (const KisSharedPtr& o) const { return (d != o.d); } inline KisSharedPtr& operator= (T* p) { attach(p); return *this; } inline operator const T*() const { return d; } template< class T2> inline operator KisSharedPtr() const { return KisSharedPtr(d); } /** * @return the contained pointer. If you delete the contained * pointer, you will make KisSharedPtr very unhappy. It is * perfectly save to put the contained pointer in another * KisSharedPtr, though. */ inline T* data() { return d; } /** * @return the pointer */ inline const T* data() const { return d; } /** * @return a const pointer to the shared object. */ inline const T* constData() const { return d; } inline const T& operator*() const { Q_ASSERT(d); return *d; } inline T& operator*() { Q_ASSERT(d); return *d; } inline const T* operator->() const { Q_ASSERT(d); return d; } inline T* operator->() { Q_ASSERT(d); return d; } /** * @return true if the pointer is null */ inline bool isNull() const { return (d == 0); } -private: + inline static void ref(const KisSharedPtr* sp, T* t) { #ifndef HAVE_MEMORY_LEAK_TRACKER Q_UNUSED(sp); #else KisMemoryLeakTracker::instance()->reference(t, sp); #endif if (t) { t->ref(); } } - inline void ref() const - { - ref(this, d); - } + inline static bool deref(const KisSharedPtr* sp, T* t) { #ifndef HAVE_MEMORY_LEAK_TRACKER Q_UNUSED(sp); #else KisMemoryLeakTracker::instance()->dereference(t, sp); #endif if (t && !t->deref()) { delete t; return false; } return true; } + +private: + inline void ref() const + { + ref(this, d); + } + inline void deref() const { bool v = deref(this, d); #ifndef NDEBUG if (!v) { d = 0; } #else Q_UNUSED(v); #endif } + private: mutable T* d; }; /** * A weak shared ptr is an ordinary shared ptr, with two differences: * it doesn't delete the contained pointer if the refcount drops to * zero and it doesn't prevent the contained pointer from being * deleted if the last strong shared pointer goes out of scope. */ template class KisWeakSharedPtr { friend class KisSharedPtr; public: /** * Creates a null pointer. */ inline KisWeakSharedPtr() : d(0), weakReference(0) { } /** * Creates a new pointer. * @param p the pointer */ inline KisWeakSharedPtr(T* p) { load(p); } inline KisWeakSharedPtr(const KisSharedPtr& o) { load(o.d); } /** * Copies a pointer. * @param o the pointer to copy */ inline KisWeakSharedPtr(const KisWeakSharedPtr& o) { if (o.isConsistent()) { load(o.d); } else { d = 0; weakReference = 0; } } inline ~KisWeakSharedPtr() { detach(); } inline KisWeakSharedPtr& operator= (const KisWeakSharedPtr& o) { attach(o); return *this; } inline bool operator== (const T* p) const { return (d == p); } inline bool operator!= (const T* p) const { return (d != p); } inline bool operator== (const KisWeakSharedPtr& o) const { return (d == o.d); } inline bool operator!= (const KisWeakSharedPtr& o) const { return (d != o.d); } inline KisWeakSharedPtr& operator= (T* p) { attach(p); return *this; } template< class T2> inline operator KisWeakSharedPtr() const { return KisWeakSharedPtr(d); } /** * Note that if you use this function, the pointer might be destroyed * if KisSharedPtr pointing to this pointer are deleted, resulting in * a segmentation fault. Use with care. * @return a const pointer to the shared object. */ inline T* data() { if (!isConsistent()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return d; } /** * @see data() */ inline const T* data() const { if (!isConsistent()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return d; } /** * @see data() */ inline const T* constData() const { if (!isConsistent()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return d; } /** * @see data() */ inline operator const T*() const { /** * This operator is used in boolean expressions where we check * for pointer consistency, so return 0 instead of asserting. */ return isConsistent() ? d : 0; } inline const T& operator*() const { if (!isValid()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return *d; } inline T& operator*() { if (!isValid()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return *d; } inline const T* operator->() const { if (!isValid()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return d; } inline T* operator->() { if (!isValid()) { warnKrita << kisBacktrace(); Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); } return d; } /** * @return true if the pointer is null */ inline bool isNull() const { return (d == 0); } /** * @return true if the weak pointer points to a valid pointer * and false if the data has been deleted or is null */ inline bool isValid() const { Q_ASSERT(!d || weakReference); return d && weakReference && isOdd((int)*weakReference); } /** * @brief toStrongRef returns a KisSharedPtr which may be dereferenced. * * Weak pointers should only be used to track ownership but never be used as pointers. * This has historically not been the case, but in new API this function should be used * instead of directly using a weak pointer as pointer. * @return a KisSharedPtr, which may be null */ inline KisSharedPtr toStrongRef() const { return KisSharedPtr(*this); } private: static const qint32 WEAK_REF = 2; static inline bool isOdd(const qint32 &x) { return x & 0x01; } inline bool isConsistent() const { Q_ASSERT(!d || weakReference); return !d || (weakReference && isOdd((int)*weakReference)); } void load(T* newValue) { d = newValue; if (d) { weakReference = d->sharedWeakReference(); weakReference->fetchAndAddOrdered(WEAK_REF); } else { weakReference = 0; } } // see note in kis_shared.cc inline void attach(T* newValue) { detach(); load(newValue); } inline void attach(const KisWeakSharedPtr& o) { detach(); if (o.isConsistent()) { load(o.d); } else { d = 0; weakReference = 0; } } // see note in kis_shared.cc void detach() { d = 0; if (weakReference && weakReference->fetchAndAddOrdered(-WEAK_REF) <= WEAK_REF) { // sanity check: Q_ASSERT((int)*weakReference == 0); delete weakReference; weakReference = 0; } } mutable T* d; QAtomicInt *weakReference; }; template Q_INLINE_TEMPLATE KisSharedPtr::KisSharedPtr(const KisWeakSharedPtr& o) : d(o.d) { if (o.isValid()) { ref(); /** * Thread safety: * Is the object we have just referenced still valid? */ Q_ASSERT(o.isConsistent()); } else { d = 0; } } template Q_INLINE_TEMPLATE void KisSharedPtr::attach(T* p) { if (d != p) { ref(this, p); T* old = d; d = p; deref(this, old); } } template Q_INLINE_TEMPLATE void KisSharedPtr::clear() { attach((T*)0); } #endif diff --git a/libs/image/3rdparty/lock_free_map/atomic.h b/libs/image/3rdparty/lock_free_map/atomic.h new file mode 100644 index 0000000000..50d948f56a --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/atomic.h @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#include + +inline void signalFenceConsume() +{ + std::atomic_signal_fence(std::memory_order_acquire); +} + +inline void signalFenceAcquire() +{ + std::atomic_signal_fence(std::memory_order_acquire); +} + +inline void signalFenceRelease() +{ + std::atomic_signal_fence(std::memory_order_release); +} + +inline void signalFenceSeqCst() +{ + std::atomic_signal_fence(std::memory_order_seq_cst); +} + +inline void threadFenceConsume() +{ + std::atomic_thread_fence(std::memory_order_acquire); +} + +inline void threadFenceAcquire() +{ + std::atomic_thread_fence(std::memory_order_acquire); +} + +inline void threadFenceRelease() +{ + std::atomic_thread_fence(std::memory_order_release); +} + +inline void threadFenceSeqCst() +{ + std::atomic_thread_fence(std::memory_order_seq_cst); +} + +enum MemoryOrder { + Relaxed = std::memory_order_relaxed, + Consume = std::memory_order_consume, + Acquire = std::memory_order_acquire, + Release = std::memory_order_release, + ConsumeRelease = std::memory_order_acq_rel, + AcquireRelease = std::memory_order_acq_rel, +}; + +template +class Atomic : protected std::atomic +{ +private: + T operator=(T value); + +public: + Atomic() + { + } + + Atomic(T value) : std::atomic(value) + { + } + + Atomic(const Atomic& other) : std::atomic(other.loadNonatomic()) + { + } + + T loadNonatomic() const + { + return std::atomic::load(std::memory_order_relaxed); + } + + T load(MemoryOrder memoryOrder) const + { + return std::atomic::load((std::memory_order) memoryOrder); + } + + void storeNonatomic(T value) + { + return std::atomic::store(value, std::memory_order_relaxed); + } + + void store(T value, MemoryOrder memoryOrder) + { + return std::atomic::store(value, (std::memory_order) memoryOrder); + } + + T compareExchange(T expected, T desired, MemoryOrder memoryOrder) + { + std::atomic::compare_exchange_strong(expected, desired, (std::memory_order) memoryOrder); + return expected; // modified by reference by compare_exchange_strong + } + + bool compareExchangeStrong(T& expected, T desired, MemoryOrder memoryOrder) + { + return std::atomic::compare_exchange_strong(expected, desired, (std::memory_order) memoryOrder); + } + + bool compareExchangeWeak(T& expected, T desired, MemoryOrder success, MemoryOrder failure) + { + return std::atomic::compare_exchange_weak(expected, desired, (std::memory_order) success, (std::memory_order) failure); + } + + T exchange(T desired, MemoryOrder memoryOrder) + { + return std::atomic::exchange(desired, (std::memory_order) memoryOrder); + } + + T fetchAdd(T operand, MemoryOrder memoryOrder) + { + return std::atomic::fetch_add(operand, (std::memory_order) memoryOrder); + } + + T fetchSub(T operand, MemoryOrder memoryOrder) + { + return std::atomic::fetch_sub(operand, (std::memory_order) memoryOrder); + } + + T fetchAnd(T operand, MemoryOrder memoryOrder) + { + return std::atomic::fetch_and(operand, (std::memory_order) memoryOrder); + } + + T fetchOr(T operand, MemoryOrder memoryOrder) + { + return std::atomic::fetch_or(operand, (std::memory_order) memoryOrder); + } +}; + +#endif // ATOMIC_H diff --git a/libs/image/3rdparty/lock_free_map/concurrent_map.h b/libs/image/3rdparty/lock_free_map/concurrent_map.h new file mode 100644 index 0000000000..bb9bddc79c --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/concurrent_map.h @@ -0,0 +1,362 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef CONCURRENTMAP_H +#define CONCURRENTMAP_H + +#include "leapfrog.h" +#include "qsbr.h" + +template , class VT = DefaultValueTraits > +class ConcurrentMap +{ +public: + typedef K Key; + typedef V Value; + typedef KT KeyTraits; + typedef VT ValueTraits; + typedef quint32 Hash; + typedef Leapfrog Details; + +private: + Atomic m_root; + QSBR m_gc; + +public: + ConcurrentMap(quint64 capacity = Details::InitialSize) : m_root(Details::Table::create(capacity)) + { + } + + ~ConcurrentMap() + { + typename Details::Table* table = m_root.loadNonatomic(); + table->destroy(); + } + + QSBR &getGC() + { + return m_gc; + } + + bool migrationInProcess() + { + return (quint64) m_root.loadNonatomic()->jobCoordinator.loadConsume() != 1; + } + + // publishTableMigration() is called by exactly one thread from Details::TableMigration::run() + // after all the threads participating in the migration have completed their work. + void publishTableMigration(typename Details::TableMigration* migration) + { + m_root.store(migration->m_destination, Release); + // Caller will GC the TableMigration and the source table. + } + + // A Mutator represents a known cell in the hash table. + // It's meant for manipulations within a temporary function scope. + // Obviously you must not call QSBR::Update while holding a Mutator. + // Any operation that modifies the table (exchangeValue, eraseValue) + // may be forced to follow a redirected cell, which changes the Mutator itself. + // Note that even if the Mutator was constructed from an existing cell, + // exchangeValue() can still trigger a resize if the existing cell was previously marked deleted, + // or if another thread deletes the key between the two steps. + class Mutator + { + private: + friend class ConcurrentMap; + + ConcurrentMap& m_map; + typename Details::Table* m_table; + typename Details::Cell* m_cell; + Value m_value; + + // Constructor: Find existing cell + Mutator(ConcurrentMap& map, Key key, bool) : m_map(map), m_value(Value(ValueTraits::NullValue)) + { + Hash hash = KeyTraits::hash(key); + for (;;) { + m_table = m_map.m_root.load(Consume); + m_cell = Details::find(hash, m_table); + if (!m_cell) { + return; + } + + Value value = m_cell->value.load(Consume); + if (value != Value(ValueTraits::Redirect)) { + // Found an existing value + m_value = value; + return; + } + // We've encountered a Redirect value. Help finish the migration. + m_table->jobCoordinator.participate(); + // Try again using the latest root. + } + } + + // Constructor: Insert or find cell + Mutator(ConcurrentMap& map, Key key) : m_map(map), m_value(Value(ValueTraits::NullValue)) + { + Hash hash = KeyTraits::hash(key); + for (;;) { + m_table = m_map.m_root.load(Consume); + quint64 overflowIdx; + switch (Details::insertOrFind(hash, m_table, m_cell, overflowIdx)) { // Modifies m_cell + case Details::InsertResult_InsertedNew: { + // We've inserted a new cell. Don't load m_cell->value. + return; + } + case Details::InsertResult_AlreadyFound: { + // The hash was already found in the table. + Value value = m_cell->value.load(Consume); + if (value == Value(ValueTraits::Redirect)) { + // We've encountered a Redirect value. + break; // Help finish the migration. + } + // Found an existing value + m_value = value; + return; + } + case Details::InsertResult_Overflow: { + // Unlike ConcurrentMap_Linear, we don't need to keep track of & pass a "mustDouble" flag. + // Passing overflowIdx is sufficient to prevent an infinite loop here. + // It defines the start of the range of cells to check while estimating total cells in use. + // After the first migration, deleted keys are purged, so if we hit this line during the + // second loop iteration, every cell in the range will be in use, thus the estimate will be 100%. + // (Concurrent deletes could result in further iterations, but it will eventually settle.) + Details::beginTableMigration(m_map, m_table, overflowIdx); + break; + } + } + // A migration has been started (either by us, or another thread). Participate until it's complete. + m_table->jobCoordinator.participate(); + // Try again using the latest root. + } + } + + public: + Value getValue() const + { + // Return previously loaded value. Don't load it again. + return Value(m_value); + } + + Value exchangeValue(Value desired) + { + for (;;) { + Value oldValue = m_value; + if (m_cell->value.compareExchangeStrong(m_value, desired, ConsumeRelease)) { + // Exchange was successful. Return previous value. + Value result = m_value; + m_value = desired; // Leave the mutator in a valid state + return result; + } + // The CAS failed and m_value has been updated with the latest value. + if (m_value != Value(ValueTraits::Redirect)) { + if (oldValue == Value(ValueTraits::NullValue) && m_value != Value(ValueTraits::NullValue)) { + // racing write inserted new value + } + // There was a racing write (or erase) to this cell. + // Pretend we exchanged with ourselves, and just let the racing write win. + return desired; + } + + // We've encountered a Redirect value. Help finish the migration. + Hash hash = m_cell->hash.load(Relaxed); + for (;;) { + // Help complete the migration. + m_table->jobCoordinator.participate(); + // Try again in the new table. + m_table = m_map.m_root.load(Consume); + m_value = Value(ValueTraits::NullValue); + quint64 overflowIdx; + + switch (Details::insertOrFind(hash, m_table, m_cell, overflowIdx)) { // Modifies m_cell + case Details::InsertResult_AlreadyFound: + m_value = m_cell->value.load(Consume); + if (m_value == Value(ValueTraits::Redirect)) { + break; + } + goto breakOuter; + case Details::InsertResult_InsertedNew: + goto breakOuter; + case Details::InsertResult_Overflow: + Details::beginTableMigration(m_map, m_table, overflowIdx); + break; + } + // We were redirected... again + } + breakOuter:; + // Try again in the new table. + } + } + + void assignValue(Value desired) + { + exchangeValue(desired); + } + + Value eraseValue() + { + for (;;) { + if (m_value == Value(ValueTraits::NullValue)) { + return Value(m_value); + } + + if (m_cell->value.compareExchangeStrong(m_value, Value(ValueTraits::NullValue), Consume)) { + // Exchange was successful and a non-NULL value was erased and returned by reference in m_value. + Value result = m_value; + m_value = Value(ValueTraits::NullValue); // Leave the mutator in a valid state + return result; + } + + // The CAS failed and m_value has been updated with the latest value. + if (m_value != Value(ValueTraits::Redirect)) { + // There was a racing write (or erase) to this cell. + // Pretend we erased nothing, and just let the racing write win. + return Value(ValueTraits::NullValue); + } + + // We've been redirected to a new table. + Hash hash = m_cell->hash.load(Relaxed); // Re-fetch hash + for (;;) { + // Help complete the migration. + m_table->jobCoordinator.participate(); + // Try again in the new table. + m_table = m_map.m_root.load(Consume); + m_cell = Details::find(hash, m_table); + if (!m_cell) { + m_value = Value(ValueTraits::NullValue); + return m_value; + } + + m_value = m_cell->value.load(Relaxed); + if (m_value != Value(ValueTraits::Redirect)) { + break; + } + } + } + } + }; + + Mutator insertOrFind(Key key) + { + return Mutator(*this, key); + } + + Mutator find(Key key) + { + return Mutator(*this, key, false); + } + + // Lookup without creating a temporary Mutator. + Value get(Key key) + { + Hash hash = KeyTraits::hash(key); + for (;;) { + typename Details::Table* table = m_root.load(Consume); + typename Details::Cell* cell = Details::find(hash, table); + if (!cell) { + return Value(ValueTraits::NullValue); + } + + Value value = cell->value.load(Consume); + if (value != Value(ValueTraits::Redirect)) { + return value; // Found an existing value + } + // We've been redirected to a new table. Help with the migration. + table->jobCoordinator.participate(); + // Try again in the new table. + } + } + + Value assign(Key key, Value desired) + { + Mutator iter(*this, key); + return iter.exchangeValue(desired); + } + + Value exchange(Key key, Value desired) + { + Mutator iter(*this, key); + return iter.exchangeValue(desired); + } + + Value erase(Key key) + { + Mutator iter(*this, key, false); + return iter.eraseValue(); + } + + // The easiest way to implement an Iterator is to prevent all Redirects. + // The currrent Iterator does that by forbidding concurrent inserts. + // To make it work with concurrent inserts, we'd need a way to block TableMigrations. + class Iterator + { + private: + typename Details::Table* m_table; + quint64 m_idx; + Key m_hash; + Value m_value; + + public: + Iterator() = default; + Iterator(ConcurrentMap& map) + { + // Since we've forbidden concurrent inserts (for now), nonatomic would suffice here, but let's plan ahead: + m_table = map.m_root.load(Consume); + m_idx = -1; + next(); + } + + void setMap(ConcurrentMap& map) + { + m_table = map.m_root.load(Consume); + m_idx = -1; + next(); + } + + void next() + { + while (++m_idx <= m_table->sizeMask) { + // Index still inside range of table. + typename Details::CellGroup* group = m_table->getCellGroups() + (m_idx >> 2); + typename Details::Cell* cell = group->cells + (m_idx & 3); + m_hash = cell->hash.load(Relaxed); + + if (m_hash != KeyTraits::NullHash) { + // Cell has been reserved. + m_value = cell->value.load(Relaxed); + if (m_value != Value(ValueTraits::NullValue)) + return; // Yield this cell. + } + } + // That's the end of the map. + m_hash = KeyTraits::NullHash; + m_value = Value(ValueTraits::NullValue); + } + + bool isValid() const + { + return m_value != Value(ValueTraits::NullValue); + } + + Key getKey() const + { + // Since we've forbidden concurrent inserts (for now), nonatomic would suffice here, but let's plan ahead: + return KeyTraits::dehash(m_hash); + } + + Value getValue() const + { + return m_value; + } + }; +}; + +#endif // CONCURRENTMAP_LEAPFROG_H diff --git a/libs/image/3rdparty/lock_free_map/leapfrog.h b/libs/image/3rdparty/lock_free_map/leapfrog.h new file mode 100644 index 0000000000..7bc95a8253 --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/leapfrog.h @@ -0,0 +1,573 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef LEAPFROG_H +#define LEAPFROG_H + +#include "map_traits.h" +#include "simple_job_coordinator.h" +#include "kis_assert.h" + +#define SANITY_CHECK + +template +struct Leapfrog { + typedef typename Map::Hash Hash; + typedef typename Map::Value Value; + typedef typename Map::KeyTraits KeyTraits; + typedef typename Map::ValueTraits ValueTraits; + + static const quint64 InitialSize = 8; + static const quint64 TableMigrationUnitSize = 32; + static const quint64 LinearSearchLimit = 128; + static const quint64 CellsInUseSample = LinearSearchLimit; + + Q_STATIC_ASSERT(LinearSearchLimit > 0 && LinearSearchLimit < 256); // Must fit in CellGroup::links + Q_STATIC_ASSERT(CellsInUseSample > 0 && CellsInUseSample <= LinearSearchLimit); // Limit sample to failed search chain + + struct Cell { + Atomic hash; + Atomic value; + }; + + struct CellGroup { + // Every cell in the table actually represents a bucket of cells, all linked together in a probe chain. + // Each cell in the probe chain is located within the table itself. + // "deltas" determines the index of the next cell in the probe chain. + // The first cell in the chain is the one that was hashed. It may or may not actually belong in the bucket. + // The "second" cell in the chain is given by deltas 0 - 3. It's guaranteed to belong in the bucket. + // All subsequent cells in the chain is given by deltas 4 - 7. Also guaranteed to belong in the bucket. + Atomic deltas[8]; + Cell cells[4]; + }; + + struct Table { + const quint64 sizeMask; // a power of two minus one + QMutex mutex; // to DCLI the TableMigration (stored in the jobCoordinator) + SimpleJobCoordinator jobCoordinator; // makes all blocked threads participate in the migration + + Table(quint64 sizeMask) : sizeMask(sizeMask) + { + } + + static Table* create(quint64 tableSize) + { +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(isPowerOf2(tableSize)); + KIS_ASSERT_RECOVER_NOOP(tableSize >= 4); +#endif // SANITY_CHECK + quint64 numGroups = tableSize >> 2; + Table* table = (Table*) std::malloc(sizeof(Table) + sizeof(CellGroup) * numGroups); + new (table) Table(tableSize - 1); + + for (quint64 i = 0; i < numGroups; i++) { + CellGroup* group = table->getCellGroups() + i; + + for (quint64 j = 0; j < 4; j++) { + group->deltas[j].storeNonatomic(0); + group->deltas[j + 4].storeNonatomic(0); + group->cells[j].hash.storeNonatomic(KeyTraits::NullHash); + group->cells[j].value.storeNonatomic(Value(ValueTraits::NullValue)); + } + } + return table; + } + + void destroy() + { + this->Table::~Table(); + std::free(this); + } + + CellGroup* getCellGroups() const + { + return (CellGroup*)(this + 1); + } + + quint64 getNumMigrationUnits() const + { + return sizeMask / TableMigrationUnitSize + 1; + } + }; + + class TableMigration : public SimpleJobCoordinator::Job + { + public: + struct Source { + Table* table; + Atomic sourceIndex; + }; + + Map& m_map; + Table* m_destination; + Atomic m_workerStatus; // number of workers + end flag + Atomic m_overflowed; + Atomic m_unitsRemaining; + quint64 m_numSources; + + TableMigration(Map& map) : m_map(map) + { + } + + static TableMigration* create(Map& map, quint64 numSources) + { + TableMigration* migration = + (TableMigration*) std::malloc(sizeof(TableMigration) + sizeof(TableMigration::Source) * numSources); + new (migration) TableMigration(map); + + migration->m_workerStatus.storeNonatomic(0); + migration->m_overflowed.storeNonatomic(false); + migration->m_unitsRemaining.storeNonatomic(0); + migration->m_numSources = numSources; + // Caller is responsible for filling in sources & destination + return migration; + } + + virtual ~TableMigration() override + { + } + + void destroy() + { + // Destroy all source tables. + for (quint64 i = 0; i < m_numSources; i++) + if (getSources()[i].table) + getSources()[i].table->destroy(); + // Delete the migration object itself. + this->TableMigration::~TableMigration(); + std::free(this); + } + + Source* getSources() const + { + return (Source*)(this + 1); + } + + bool migrateRange(Table* srcTable, quint64 startIdx); + virtual void run() override; + }; + + static Cell* find(Hash hash, Table* table) + { +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(table); + KIS_ASSERT_RECOVER_NOOP(hash != KeyTraits::NullHash); +#endif // SANITY_CHECK + quint64 sizeMask = table->sizeMask; + // Optimistically check hashed cell even though it might belong to another bucket + quint64 idx = hash & sizeMask; + CellGroup* group = table->getCellGroups() + (idx >> 2); + Cell* cell = group->cells + (idx & 3); + Hash probeHash = cell->hash.load(Relaxed); + + if (probeHash == hash) { + return cell; + } else if (probeHash == KeyTraits::NullHash) { + return cell = NULL; + } + // Follow probe chain for our bucket + quint8 delta = group->deltas[idx & 3].load(Relaxed); + while (delta) { + idx = (idx + delta) & sizeMask; + group = table->getCellGroups() + (idx >> 2); + cell = group->cells + (idx & 3); + Hash probeHash = cell->hash.load(Relaxed); + // Note: probeHash might actually be NULL due to memory reordering of a concurrent insert, + // but we don't check for it. We just follow the probe chain. + if (probeHash == hash) { + return cell; + } + delta = group->deltas[(idx & 3) + 4].load(Relaxed); + } + // End of probe chain, not found + return NULL; + } + + // FIXME: Possible optimization: Dedicated insert for migration? It wouldn't check for InsertResult_AlreadyFound. + enum InsertResult { InsertResult_AlreadyFound, InsertResult_InsertedNew, InsertResult_Overflow }; + static InsertResult insertOrFind(Hash hash, Table* table, Cell*& cell, quint64& overflowIdx) + { +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(table); + KIS_ASSERT_RECOVER_NOOP(hash != KeyTraits::NullHash); +#endif // SANITY_CHECK + quint64 sizeMask = table->sizeMask; + quint64 idx = quint64(hash); + + // Check hashed cell first, though it may not even belong to the bucket. + CellGroup* group = table->getCellGroups() + ((idx & sizeMask) >> 2); + cell = group->cells + (idx & 3); + Hash probeHash = cell->hash.load(Relaxed); + + if (probeHash == KeyTraits::NullHash) { + if (cell->hash.compareExchangeStrong(probeHash, hash, Relaxed)) { + // There are no links to set. We're done. + return InsertResult_InsertedNew; + } else { + // Fall through to check if it was the same hash... + } + } + + if (probeHash == hash) { + return InsertResult_AlreadyFound; + } + + // Follow the link chain for this bucket. + quint64 maxIdx = idx + sizeMask; + quint64 linkLevel = 0; + Atomic* prevLink; + for (;;) { + followLink: + prevLink = group->deltas + ((idx & 3) + linkLevel); + linkLevel = 4; + quint8 probeDelta = prevLink->load(Relaxed); + + if (probeDelta) { + idx += probeDelta; + // Check the hash for this cell. + group = table->getCellGroups() + ((idx & sizeMask) >> 2); + cell = group->cells + (idx & 3); + probeHash = cell->hash.load(Relaxed); + + if (probeHash == KeyTraits::NullHash) { + // Cell was linked, but hash is not visible yet. + // We could avoid this case (and guarantee it's visible) using acquire & release, but instead, + // just poll until it becomes visible. + do { + probeHash = cell->hash.load(Acquire); + } while (probeHash == KeyTraits::NullHash); + } + +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(((probeHash ^ hash) & sizeMask) == 0); // Only hashes in same bucket can be linked +#endif // SANITY_CHECK + if (probeHash == hash) { + return InsertResult_AlreadyFound; + } + } else { + // Reached the end of the link chain for this bucket. + // Switch to linear probing until we reserve a new cell or find a late-arriving cell in the same bucket. + quint64 prevLinkIdx = idx; +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(qint64(maxIdx - idx) >= 0); // Nobody would have linked an idx that's out of range. +#endif // SANITY_CHECK + quint64 linearProbesRemaining = qMin(maxIdx - idx, quint64(LinearSearchLimit)); + + while (linearProbesRemaining-- > 0) { + idx++; + group = table->getCellGroups() + ((idx & sizeMask) >> 2); + cell = group->cells + (idx & 3); + probeHash = cell->hash.load(Relaxed); + + if (probeHash == KeyTraits::NullHash) { + // It's an empty cell. Try to reserve it. + if (cell->hash.compareExchangeStrong(probeHash, hash, Relaxed)) { + // Success. We've reserved the cell. Link it to previous cell in same bucket. +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(probeDelta == 0); +#endif // SANITY_CHECK + quint8 desiredDelta = idx - prevLinkIdx; + prevLink->store(desiredDelta, Relaxed); + return InsertResult_InsertedNew; + } else { + // Fall through to check if it's the same hash... + } + } + Hash x = (probeHash ^ hash); + // Check for same hash. + if (!x) { + return InsertResult_AlreadyFound; + } + // Check for same bucket. + if ((x & sizeMask) == 0) { + // Attempt to set the link on behalf of the late-arriving cell. + // This is usually redundant, but if we don't attempt to set the late-arriving cell's link here, + // there's no guarantee that our own link chain will be well-formed by the time this function returns. + // (Indeed, subsequent lookups sometimes failed during testing, for this exact reason.) + quint8 desiredDelta = idx - prevLinkIdx; + prevLink->store(desiredDelta, Relaxed); + goto followLink; // Try to follow link chain for the bucket again. + } + // Continue linear search... + } + // Table is too full to insert. + overflowIdx = idx + 1; + return InsertResult_Overflow; + } + } + } + + static void beginTableMigrationToSize(Map& map, Table* table, quint64 nextTableSize) + { + // Create new migration by DCLI. + SimpleJobCoordinator::Job* job = table->jobCoordinator.loadConsume(); + if (job) { + // new migration already exists + } else { + QMutexLocker guard(&table->mutex); + job = table->jobCoordinator.loadConsume(); // Non-atomic would be sufficient, but that's OK. + + if (job) { + // new migration already exists (double-checked) + } else { + // Create new migration. + TableMigration* migration = TableMigration::create(map, 1); + migration->m_unitsRemaining.storeNonatomic(table->getNumMigrationUnits()); + migration->getSources()[0].table = table; + migration->getSources()[0].sourceIndex.storeNonatomic(0); + migration->m_destination = Table::create(nextTableSize); + // Publish the new migration. + table->jobCoordinator.storeRelease(migration); + } + } + } + + static void beginTableMigration(Map& map, Table* table, quint64 overflowIdx) + { + // Estimate number of cells in use based on a small sample. + quint64 sizeMask = table->sizeMask; + quint64 idx = overflowIdx - CellsInUseSample; + quint64 inUseCells = 0; + for (quint64 linearProbesRemaining = CellsInUseSample; linearProbesRemaining > 0; linearProbesRemaining--) { + CellGroup* group = table->getCellGroups() + ((idx & sizeMask) >> 2); + Cell* cell = group->cells + (idx & 3); + Value value = cell->value.load(Relaxed); + if (value == Value(ValueTraits::Redirect)) { + // Another thread kicked off the jobCoordinator. The caller will participate upon return. + return; + } + if (value != Value(ValueTraits::NullValue)) + inUseCells++; + idx++; + } + float inUseRatio = float(inUseCells) / CellsInUseSample; + float estimatedInUse = (sizeMask + 1) * inUseRatio; + quint64 nextTableSize = qMax(quint64(InitialSize), roundUpPowerOf2(quint64(estimatedInUse * 2))); + beginTableMigrationToSize(map, table, nextTableSize); + } +}; // Leapfrog + +template +bool Leapfrog::TableMigration::migrateRange(Table* srcTable, quint64 startIdx) +{ + quint64 srcSizeMask = srcTable->sizeMask; + quint64 endIdx = qMin(startIdx + TableMigrationUnitSize, srcSizeMask + 1); + // Iterate over source range. + for (quint64 srcIdx = startIdx; srcIdx < endIdx; srcIdx++) { + CellGroup* srcGroup = srcTable->getCellGroups() + ((srcIdx & srcSizeMask) >> 2); + Cell* srcCell = srcGroup->cells + (srcIdx & 3); + Hash srcHash; + Value srcValue; + // Fetch the srcHash and srcValue. + for (;;) { + srcHash = srcCell->hash.load(Relaxed); + if (srcHash == KeyTraits::NullHash) { + // An unused cell. Try to put a Redirect marker in its value. + srcValue = + srcCell->value.compareExchange(Value(ValueTraits::NullValue), Value(ValueTraits::Redirect), Relaxed); + if (srcValue == Value(ValueTraits::Redirect)) { + // srcValue is already marked Redirect due to previous incomplete migration. + break; + } + if (srcValue == Value(ValueTraits::NullValue)) { + break; // Redirect has been placed. Break inner loop, continue outer loop. + } + // Otherwise, somebody just claimed the cell. Read srcHash again... + } else { + // Check for deleted/uninitialized value. + srcValue = srcCell->value.load(Relaxed); + if (srcValue == Value(ValueTraits::NullValue)) { + // Try to put a Redirect marker. + if (srcCell->value.compareExchangeStrong(srcValue, Value(ValueTraits::Redirect), Relaxed)) { + break; // Redirect has been placed. Break inner loop, continue outer loop. + } + + if (srcValue == Value(ValueTraits::Redirect)) { + // FIXME: I don't think this will happen. Investigate & change to assert + break; + } + } else if (srcValue == Value(ValueTraits::Redirect)) { + // srcValue is already marked Redirect due to previous incomplete migration. + break; + } + + // We've got a key/value pair to migrate. + // Reserve a destination cell in the destination. +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(srcHash != KeyTraits::NullHash); + KIS_ASSERT_RECOVER_NOOP(srcValue != Value(ValueTraits::NullValue)); + KIS_ASSERT_RECOVER_NOOP(srcValue != Value(ValueTraits::Redirect)); +#endif // SANITY_CHECK + Cell* dstCell; + quint64 overflowIdx; + InsertResult result = insertOrFind(srcHash, m_destination, dstCell, overflowIdx); + // During migration, a hash can only exist in one place among all the source tables, + // and it is only migrated by one thread. Therefore, the hash will never already exist + // in the destination table: +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(result != InsertResult_AlreadyFound); +#endif // SANITY_CHECK + if (result == InsertResult_Overflow) { + // Destination overflow. + // This can happen for several reasons. For example, the source table could have + // existed of all deleted cells when it overflowed, resulting in a small destination + // table size, but then another thread could re-insert all the same hashes + // before the migration completed. + // Caller will cancel the current migration and begin a new one. + return false; + } + // Migrate the old value to the new cell. + for (;;) { + // Copy srcValue to the destination. + dstCell->value.store(srcValue, Relaxed); + // Try to place a Redirect marker in srcValue. + Value doubleCheckedSrcValue = srcCell->value.compareExchange(srcValue, Value(ValueTraits::Redirect), Relaxed); +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(doubleCheckedSrcValue != Value(ValueTraits::Redirect)); // Only one thread can redirect a cell at a time. +#endif // SANITY_CHECK + if (doubleCheckedSrcValue == srcValue) { + // No racing writes to the src. We've successfully placed the Redirect marker. + // srcValue was non-NULL when we decided to migrate it, but it may have changed to NULL + // by a late-arriving erase. + if (srcValue == Value(ValueTraits::NullValue)) { + // racing update was erase", uptr(srcTable), srcIdx) + } + + break; + } + // There was a late-arriving write (or erase) to the src. Migrate the new value and try again. + srcValue = doubleCheckedSrcValue; + } + // Cell successfully migrated. Proceed to next source cell. + break; + } + } + } + // Range has been migrated successfully. + return true; +} + +template +void Leapfrog::TableMigration::run() +{ + // Conditionally increment the shared # of workers. + quint64 probeStatus = m_workerStatus.load(Relaxed); + do { + if (probeStatus & 1) { + // End flag is already set, so do nothing. + return; + } + } while (!m_workerStatus.compareExchangeWeak(probeStatus, probeStatus + 2, Relaxed, Relaxed)); + // # of workers has been incremented, and the end flag is clear. +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP((probeStatus & 1) == 0); +#endif // SANITY_CHECK + + // Iterate over all source tables. + for (quint64 s = 0; s < m_numSources; s++) { + Source& source = getSources()[s]; + // Loop over all migration units in this source table. + for (;;) { + if (m_workerStatus.load(Relaxed) & 1) { + goto endMigration; + } + quint64 startIdx = source.sourceIndex.fetchAdd(TableMigrationUnitSize, Relaxed); + if (startIdx >= source.table->sizeMask + 1) + break; // No more migration units in this table. Try next source table. + bool overflowed = !migrateRange(source.table, startIdx); + if (overflowed) { + // *** FAILED MIGRATION *** + // TableMigration failed due to destination table overflow. + // No other thread can declare the migration successful at this point, because *this* unit will never complete, + // hence m_unitsRemaining won't reach zero. + // However, multiple threads can independently detect a failed migration at the same time. + // The reason we store overflowed in a shared variable is because we can must flush all the worker threads before + // we can safely deal with the overflow. Therefore, the thread that detects the failure is often different from + // the thread + // that deals with it. + bool oldOverflowed = m_overflowed.exchange(overflowed, Relaxed); + if (oldOverflowed) { + // race to set m_overflowed + } + + m_workerStatus.fetchOr(1, Relaxed); + goto endMigration; + } + + qint64 prevRemaining = m_unitsRemaining.fetchSub(1, Relaxed); +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(prevRemaining > 0); +#endif // SANITY_CHECK + if (prevRemaining == 1) { + // *** SUCCESSFUL MIGRATION *** + // That was the last chunk to migrate. + m_workerStatus.fetchOr(1, Relaxed); + goto endMigration; + } + } + } + +endMigration: + // Decrement the shared # of workers. + probeStatus = m_workerStatus.fetchSub(2, AcquireRelease); // AcquireRelease makes all previous writes visible to the last worker thread. + if (probeStatus >= 4) { + // There are other workers remaining. Return here so that only the very last worker will proceed. + return; + } + + // We're the very last worker thread. + // Perform the appropriate post-migration step depending on whether the migration succeeded or failed. +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(probeStatus == 3); +#endif // SANITY_CHECK + bool overflowed = m_overflowed.loadNonatomic(); // No racing writes at this point + if (!overflowed) { + // The migration succeeded. This is the most likely outcome. Publish the new subtree. + m_map.publishTableMigration(this); + // End the jobCoodinator. + getSources()[0].table->jobCoordinator.end(); + } else { + // The migration failed due to the overflow of the destination table. + Table* origTable = getSources()[0].table; + QMutexLocker guard(&origTable->mutex); + SimpleJobCoordinator::Job* checkedJob = origTable->jobCoordinator.loadConsume(); + + if (checkedJob != this) { + // a new TableMigration was already started + } else { + TableMigration* migration = TableMigration::create(m_map, m_numSources + 1); + // Double the destination table size. + migration->m_destination = Table::create((m_destination->sizeMask + 1) * 2); + // Transfer source tables to the new migration. + for (quint64 i = 0; i < m_numSources; i++) { + migration->getSources()[i].table = getSources()[i].table; + getSources()[i].table = NULL; + migration->getSources()[i].sourceIndex.storeNonatomic(0); + } + + migration->getSources()[m_numSources].table = m_destination; + migration->getSources()[m_numSources].sourceIndex.storeNonatomic(0); + // Calculate total number of migration units to move. + quint64 unitsRemaining = 0; + for (quint64 s = 0; s < migration->m_numSources; s++) { + unitsRemaining += migration->getSources()[s].table->getNumMigrationUnits(); + } + + migration->m_unitsRemaining.storeNonatomic(unitsRemaining); + // Publish the new migration. + origTable->jobCoordinator.storeRelease(migration); + } + } + + // We're done with this TableMigration. Queue it for GC. + m_map.getGC().enqueue(&TableMigration::destroy, this, true); +} + +#endif // LEAPFROG_H diff --git a/libs/image/3rdparty/lock_free_map/map_traits.h b/libs/image/3rdparty/lock_free_map/map_traits.h new file mode 100644 index 0000000000..92d97e6f4f --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/map_traits.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef MAPTRAITS_H +#define MAPTRAITS_H + +#include + +inline quint64 roundUpPowerOf2(quint64 v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + v++; + return v; +} + +inline bool isPowerOf2(quint64 v) +{ + return (v & (v - 1)) == 0; +} + +inline quint32 avalanche(quint32 h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +inline quint32 deavalanche(quint32 h) +{ + h ^= h >> 16; + h *= 0x7ed1b41d; + h ^= (h ^ (h >> 13)) >> 13; + h *= 0xa5cb9243; + h ^= h >> 16; + return h; +} + +template +struct DefaultKeyTraits { + typedef T Key; + typedef quint32 Hash; + static const Key NullKey = Key(0); + static const Hash NullHash = Hash(0); + + static Hash hash(T key) + { + return avalanche(Hash(key)); + } + + static Key dehash(Hash hash) + { + return (T) deavalanche(hash); + } +}; + +template +struct DefaultValueTraits { + typedef T Value; + typedef quint32 IntType; + static const IntType NullValue = 0; + static const IntType Redirect = 1; +}; + +#endif // MAPTRAITS_H diff --git a/libs/image/3rdparty/lock_free_map/qsbr.h b/libs/image/3rdparty/lock_free_map/qsbr.h new file mode 100644 index 0000000000..81508780f0 --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/qsbr.h @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef QSBR_H +#define QSBR_H + +#include +#include +#include + +#define CALL_MEMBER(obj, pmf) ((obj).*(pmf)) + +class QSBR +{ +private: + struct Action { + void (*func)(void*); + quint64 param[4]; // Size limit found experimentally. Verified by assert below. + + Action() = default; + + Action(void (*f)(void*), void* p, quint64 paramSize) : func(f) + { + Q_ASSERT(paramSize <= sizeof(param)); // Verify size limit. + memcpy(¶m, p, paramSize); + } + + void operator()() + { + func(¶m); + } + }; + + QMutex m_mutex; + QVector m_pendingActions; + QVector m_deferedActions; + std::atomic_flag m_isProcessing = ATOMIC_FLAG_INIT; + +public: + + template + void enqueue(void (T::*pmf)(), T* target, bool migration = false) + { + struct Closure { + void (T::*pmf)(); + T* target; + + static void thunk(void* param) + { + Closure* self = (Closure*) param; + CALL_MEMBER(*self->target, self->pmf)(); + } + }; + + Closure closure = {pmf, target}; + while (m_isProcessing.test_and_set(std::memory_order_acquire)) { + } + + if (migration) { + m_deferedActions.append(Action(Closure::thunk, &closure, sizeof(closure))); + } else { + m_pendingActions.append(Action(Closure::thunk, &closure, sizeof(closure))); + } + + m_isProcessing.clear(std::memory_order_release); + } + + void update(bool migration) + { + if (!m_isProcessing.test_and_set(std::memory_order_acquire)) { + QVector actions; + actions.swap(m_pendingActions); + + if (!migration) { + m_pendingActions.swap(m_deferedActions); + } + + m_isProcessing.clear(std::memory_order_release); + + for (auto &action : actions) { + action(); + } + } + } + + void flush() + { + if (!m_isProcessing.test_and_set(std::memory_order_acquire)) { + for (auto &action : m_pendingActions) { + action(); + } + + for (auto &action : m_deferedActions) { + action(); + } + + m_isProcessing.clear(std::memory_order_release); + } + } +}; + +#endif // QSBR_H diff --git a/libs/image/3rdparty/lock_free_map/simple_job_coordinator.h b/libs/image/3rdparty/lock_free_map/simple_job_coordinator.h new file mode 100644 index 0000000000..0df56f995f --- /dev/null +++ b/libs/image/3rdparty/lock_free_map/simple_job_coordinator.h @@ -0,0 +1,107 @@ +/*------------------------------------------------------------------------ + Junction: Concurrent data structures in C++ + Copyright (c) 2016 Jeff Preshing + Distributed under the Simplified BSD License. + Original location: https://github.com/preshing/junction + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the LICENSE file for more information. +------------------------------------------------------------------------*/ + +#ifndef SIMPLEJOBCOORDINATOR_H +#define SIMPLEJOBCOORDINATOR_H + +#include +#include +#include + +#include "kis_assert.h" +#include "atomic.h" + +#define SANITY_CHECK + +class SimpleJobCoordinator +{ +public: + struct Job { + virtual ~Job() + { + } + + virtual void run() = 0; + }; + +private: + Atomic m_job; + QMutex mutex; + QWaitCondition condVar; + +public: + SimpleJobCoordinator() : m_job(quint64(NULL)) + { + } + + Job* loadConsume() const + { + return (Job*) m_job.load(Consume); + } + + void storeRelease(Job* job) + { + { + QMutexLocker guard(&mutex); + m_job.store(quint64(job), Release); + } + + condVar.wakeAll(); + } + + void participate() + { + quint64 prevJob = quint64(NULL); + + for (;;) { + quint64 job = m_job.load(Consume); + if (job == prevJob) { + QMutexLocker guard(&mutex); + + for (;;) { + job = m_job.loadNonatomic(); // No concurrent writes inside lock + if (job != prevJob) { + break; + } + + condVar.wait(&mutex); + } + } + + if (job == 1) { + return; + } + + reinterpret_cast(job)->run(); + prevJob = job; + } + } + + void runOne(Job* job) + { +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(job != (Job*) m_job.load(Relaxed)); +#endif // SANITY_CHECK + storeRelease(job); + job->run(); + } + + void end() + { + { + QMutexLocker guard(&mutex); + m_job.store(1, Release); + } + + condVar.wakeAll(); + } +}; + +#endif // SIMPLEJOBCOORDINATOR_H diff --git a/libs/image/kis_filter_strategy.cc b/libs/image/kis_filter_strategy.cc index 802ec01736..73fc75609e 100644 --- a/libs/image/kis_filter_strategy.cc +++ b/libs/image/kis_filter_strategy.cc @@ -1,238 +1,239 @@ /* * Copyright (c) 2004 Michael Thaler * Copyright (c) 2005 C. Boemann * Copyright (c) 2013 Juan Palacios * * 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_filter_strategy.h" #include #include #include #include "kis_debug.h" Q_GLOBAL_STATIC(KisFilterStrategyRegistry, s_instance) qreal KisHermiteFilterStrategy::valueAt(qreal t) const { /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ if (t < 0.0) t = -t; if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); return(0.0); } qint32 KisHermiteFilterStrategy::intValueAt(qint32 t) const { /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { t = (2 * t - 3 * 256) * t * t + (256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } return(0); } qint32 KisBicubicFilterStrategy::intValueAt(qint32 t) const { /* f(t) = 1.5|t|^3 - 2.5|t|^2 + 1, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { t = (3 * t - 5 * 256) * t * t / 2 + (256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } if (t < 512) { /* f(t) = -0.5|t|^3 + 2.5|t|^2 + 4|t| - 2, -2 <= t <= 2 */ t = ((-t + 5 * 256) * t / 2 - 4 * 256 * 256) * t + (2 * 256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } return(0); } qreal KisBoxFilterStrategy::valueAt(qreal t) const { if ((t > -0.5) && (t <= 0.5)) return(1.0); return(0.0); } qint32 KisBoxFilterStrategy::intValueAt(qint32 t) const { /* f(t) = 1, -0.5 < t <= 0.5 */ if ((t > -128) && (t <= 128)) return 255; return 0; } qreal KisBilinearFilterStrategy::valueAt(qreal t) const { if (t < 0.0) t = -t; if (t < 1.0) return(1.0 - t); return(0.0); } qint32 KisBilinearFilterStrategy::intValueAt(qint32 t) const { /* f(t) = |t|, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { // calc 256-1 but also go from .8 fixed point to 8bitscale. ie t = (t*255)/256; ie: if(t>=128) return t-1; if (t >= 128) return 256 - t; return 255 - t; } return(0); } qreal KisBellFilterStrategy::valueAt(qreal t) const { if (t < 0) t = -t; if (t < .5) return(.75 - (t * t)); if (t < 1.5) { t = (t - 1.5); return(.5 *(t * t)); } return(0.0); } qreal KisBSplineFilterStrategy::valueAt(qreal t) const { qreal tt; if (t < 0) t = -t; if (t < 1) { tt = t * t; return((.5 * tt * t) - tt + (2.0 / 3.0)); } else if (t < 2) { t = 2 - t; return((1.0 / 6.0) *(t * t * t)); } return(0.0); } qreal KisLanczos3FilterStrategy::valueAt(qreal t) const { if (t < 0) t = -t; if (t < 3.0) return(sinc(t) * sinc(t / 3.0)); return(0.0); } qreal KisLanczos3FilterStrategy::sinc(qreal x) const { const qreal pi = 3.1415926535897932385; x *= pi; if (x != 0) return(sin(x) / x); return(1.0); } qreal KisMitchellFilterStrategy::valueAt(qreal t) const { const qreal B = 1.0 / 3.0; const qreal C = 1.0 / 3.0; qreal tt; tt = t * t; if (t < 0) t = -t; if (t < 1.0) { t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B)); return(t / 6.0); } else if (t < 2.0) { t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C)); return(t / 6.0); } return(0.0); } KisFilterStrategyRegistry::KisFilterStrategyRegistry() { } KisFilterStrategyRegistry::~KisFilterStrategyRegistry() { Q_FOREACH (const QString &id, keys()) { delete get(id); } dbgRegistry << "deleting KisFilterStrategyRegistry"; } KisFilterStrategyRegistry* KisFilterStrategyRegistry::instance() { if (!s_instance.exists()) { + s_instance->add(new KisBoxFilterStrategy); + s_instance->addAlias("Box", "NearestNeighbor"); + s_instance->add(new KisHermiteFilterStrategy); s_instance->add(new KisBicubicFilterStrategy); - s_instance->add(new KisBoxFilterStrategy); s_instance->add(new KisBilinearFilterStrategy); s_instance->add(new KisBellFilterStrategy); s_instance->add(new KisBSplineFilterStrategy); s_instance->add(new KisLanczos3FilterStrategy); s_instance->add(new KisMitchellFilterStrategy); - } return s_instance; } QList KisFilterStrategyRegistry::listKeys() const { QList answer; Q_FOREACH (const QString key, keys()) { answer.append(KoID(key, get(key)->name())); } return answer; } QString KisFilterStrategyRegistry::formattedDescriptions() const { QString formatedDescription(""); Q_FOREACH (const QString key, keys()) { KisFilterStrategy *strategy = get(key); QString description = strategy->description(); if (!description.isEmpty()) { formatedDescription.append("

"); formatedDescription.append(strategy->name()); formatedDescription.append(": "); formatedDescription.append(description); formatedDescription.append("

"); } } formatedDescription.append(""); return formatedDescription; } diff --git a/libs/image/kis_warptransform_worker.h b/libs/image/kis_warptransform_worker.h index 294e3ae1f6..6b44c7c5ff 100644 --- a/libs/image/kis_warptransform_worker.h +++ b/libs/image/kis_warptransform_worker.h @@ -1,85 +1,87 @@ /* * kis_warptransform_worker.h - part of Krita * * Copyright (c) 2010 Marc Pegon * * 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_WARPTRANSFORM_WORKER_H #define KIS_WARPTRANSFORM_WORKER_H #include "kis_types.h" #include "kritaimage_export.h" #include #include #include #include #include #include /** * Class to apply a transformation (affine, similitude, MLS) to a paintDevice * or a QImage according an original set of points p, a new set of points q, * and the constant alpha. * The algorithms are based a paper entitled "Image Deformation Using * Moving Least Squares", by Scott Schaefer (Texas A&M University), Travis * McPhail (Rice University) and Joe Warren (Rice University) */ class KRITAIMAGE_EXPORT KisWarpTransformWorker : public QObject { Q_OBJECT public: typedef enum WarpType_ {AFFINE_TRANSFORM = 0, SIMILITUDE_TRANSFORM, RIGID_TRANSFORM, N_MODES} WarpType; + typedef enum WarpCalculation_ {GRID = 0, DRAW} WarpCalculation; static QPointF affineTransformMath(QPointF v, QVector p, QVector q, qreal alpha); static QPointF similitudeTransformMath(QPointF v, QVector p, QVector q, qreal alpha); static QPointF rigidTransformMath(QPointF v, QVector p, QVector q, qreal alpha); static QImage transformQImage(WarpType warpType, const QVector &origPoint, const QVector &transfPoint, qreal alpha, const QImage& srcImage, const QPointF &srcQImageOffset, QPointF *newOffset); // Prepare the transformation on dev KisWarpTransformWorker(WarpType warpType, KisPaintDeviceSP dev, QVector origPoint, QVector transfPoint, qreal alpha, KoUpdater *progress); ~KisWarpTransformWorker() override; // Perform the prepared transformation void run(); QRect approxChangeRect(const QRect &rc); QRect approxNeedRect(const QRect &rc, const QRect &fullBounds); private: struct FunctionTransformOp; typedef QPointF (*WarpMathFunction)(QPointF, QVector, QVector, qreal); private: WarpMathFunction m_warpMathFunction; + WarpCalculation m_warpCalc; QVector m_origPoint; QVector m_transfPoint; qreal m_alpha; KisPaintDeviceSP m_dev; KoUpdater *m_progress; }; #endif diff --git a/libs/image/tiles3/kis_memento_manager.h b/libs/image/tiles3/kis_memento_manager.h index 5b9543983c..0b20aaa852 100644 --- a/libs/image/tiles3/kis_memento_manager.h +++ b/libs/image/tiles3/kis_memento_manager.h @@ -1,164 +1,174 @@ /* * Copyright (c) 2009 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_MEMENTO_MANAGER_ #define KIS_MEMENTO_MANAGER_ #include #include "kis_memento_item.h" -#include "kis_tile_hash_table.h" +#include "config-hash-table-implementaion.h" typedef QList KisMementoItemList; typedef QListIterator KisMementoItemListIterator; class KisMemento; struct KisHistoryItem { KisMemento* memento; KisMementoItemList itemList; }; typedef QList KisHistoryList; class KisMemento; typedef KisSharedPtr KisMementoSP; +#ifdef USE_LOCK_FREE_HASH_TABLE +#include "kis_tile_hash_table2.h" + +typedef KisTileHashTableTraits2 KisMementoItemHashTable; +typedef KisTileHashTableIteratorTraits2 KisMementoItemHashTableIterator; +typedef KisTileHashTableIteratorTraits2 KisMementoItemHashTableIteratorConst; +#else +#include "kis_tile_hash_table.h" + typedef KisTileHashTableTraits KisMementoItemHashTable; typedef KisTileHashTableIteratorTraits KisMementoItemHashTableIterator; typedef KisTileHashTableIteratorTraits KisMementoItemHashTableIteratorConst; +#endif // USE_LOCK_FREE_HASH_TABLE class KRITAIMAGE_EXPORT KisMementoManager { public: KisMementoManager(); KisMementoManager(const KisMementoManager& rhs); ~KisMementoManager(); /** * Most tricky part. This function is called by a tile, when it gets new * tile-data through COW. The Memento Manager wraps this tile-data into * KisMementoItem class and waits until commit() order given. By this * time KisMementoItem doesn't take part in COW mechanism. It only holds * tileData->m_refCount counter to ensure tile isn't deleted from memory. * When commit() comes, KisMementoItem grabs tileData->m_usersCount and * since that moment it is a rightful co-owner of the tileData and COW * participant. It means that tileData won't be ever changed since then. * Every write request to the original tile will lead to duplicating * tileData and registering it here again... */ void registerTileChange(KisTile *tile); /** * Called when a tile deleted. Creates empty KisMementoItem showing that * there was a tile one day */ void registerTileDeleted(KisTile *tile); /** * Commits changes, made in INDEX: appends m_index into m_revisions list * and owes all modified tileDatas. */ void commit(); /** * Undo and Redo stuff respectively. * * When calling them, INDEX list should be empty, so to say, "working * copy should be clean". */ void rollback(KisTileHashTable *ht); void rollforward(KisTileHashTable *ht); /** * Get old tile, whose memento is in the HEAD revision. * \p existingTile returns if the tile is actually an existing * non-default tile or it was created on the fly * from the default tile data */ KisTileSP getCommitedTile(qint32 col, qint32 row, bool &existingTile); KisMementoSP getMemento(); bool hasCurrentMemento() { return m_currentMemento; } KisMementoSP currentMemento(); void setDefaultTileData(KisTileData *defaultTileData); void debugPrintInfo(); /** * Removes all the history that preceds the revision * pointed by oldestMemento. That is after calling to * purgeHistory(someMemento) you won't be able to do * rollback(someMemento) anymore. */ void purgeHistory(KisMementoSP oldestMemento); protected: qint32 findRevisionByMemento(KisMementoSP memento) const; void resetRevisionHistory(KisMementoItemList list); protected: /** * INDEX of tiles to be committed with next commit() * We use a hash table to be able to check that * we have the only memento item for a tile * per commit efficiently */ KisMementoItemHashTable m_index; /** * Main list that stores every commit ever done */ KisHistoryList m_revisions; /** * List of revisions temporarily undone while rollback() */ KisHistoryList m_cancelledRevisions; /** * A hash table, that stores the most recently updated * versions of tiles. Say, HEAD revision :) */ KisMementoItemHashTable m_headsHashTable; /** * Stores extent of current INDEX. * It is the "name" of current named transaction */ KisMementoSP m_currentMemento; /** * The flag that blocks registration of changes on tiles. * This is a temporary state of the memento manager, that * is used for traveling in history * * \see rollback() * \see rollforward() */ bool m_registrationBlocked; }; #endif /* KIS_MEMENTO_MANAGER_ */ diff --git a/libs/image/tiles3/kis_tile_hash_table2.h b/libs/image/tiles3/kis_tile_hash_table2.h new file mode 100644 index 0000000000..f468f46000 --- /dev/null +++ b/libs/image/tiles3/kis_tile_hash_table2.h @@ -0,0 +1,371 @@ +#ifndef KIS_TILEHASHTABLE_2_H +#define KIS_TILEHASHTABLE_2_H + +#include "kis_shared.h" +#include "kis_shared_ptr.h" +#include "3rdparty/lock_free_map/concurrent_map.h" +#include "kis_tile.h" + +#define SANITY_CHECK + +/** + * This is a template for a hash table that stores tiles (or some other + * objects resembling tiles). Actually, this object should only have + * col()/row() methods and be able to answer setNext()/next() requests to + * be stored here. It is used in KisTiledDataManager and + * KisMementoManager. + * + * How to use: + * 1) each hash must be unique, otherwise tiles would rewrite each-other + * 2) 0 key is reserved, so can't be used + * 3) col and row must be less than 0x7FFF to guarantee uniqueness of hash for each pair + */ + +template +class KisTileHashTableIteratorTraits2; + +template +class KisTileHashTableTraits2 +{ + static constexpr bool isInherited = std::is_convertible::value; + Q_STATIC_ASSERT_X(isInherited, "Template must inherit KisShared"); + +public: + typedef T TileType; + typedef KisSharedPtr TileTypeSP; + typedef KisWeakSharedPtr TileTypeWSP; + + KisTileHashTableTraits2(KisMementoManager *mm); + KisTileHashTableTraits2(const KisTileHashTableTraits2 &ht, KisMementoManager *mm); + ~KisTileHashTableTraits2(); + + bool isEmpty() + { + return !m_numTiles.load(); + } + + bool tileExists(qint32 col, qint32 row); + + /** + * Returns a tile in position (col,row). If no tile exists, + * returns null. + * \param col column of the tile + * \param row row of the tile + */ + TileTypeSP getExistingTile(qint32 col, qint32 row); + + /** + * Returns a tile in position (col,row). If no tile exists, + * creates a new one, attaches it to the list and returns. + * \param col column of the tile + * \param row row of the tile + * \param newTile out-parameter, returns true if a new tile + * was created + */ + TileTypeSP getTileLazy(qint32 col, qint32 row, bool& newTile); + + /** + * Returns a tile in position (col,row). If no tile exists, + * creates nothing, but returns shared default tile object + * of the table. Be careful, this object has column and row + * parameters set to (qint32_MIN, qint32_MIN). + * \param col column of the tile + * \param row row of the tile + * \param existingTile returns true if the tile actually exists in the table + * and it is not a lazily created default wrapper tile + */ + TileTypeSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile); + void addTile(TileTypeSP tile); + bool deleteTile(TileTypeSP tile); + bool deleteTile(qint32 col, qint32 row); + + void clear(); + + void setDefaultTileData(KisTileData *defaultTileData); + KisTileData* defaultTileData(); + + qint32 numTiles() + { + return m_numTiles.load(); + } + + void debugPrintInfo(); + void debugMaxListLength(qint32 &min, qint32 &max); + + friend class KisTileHashTableIteratorTraits2; + +private: + struct MemoryReclaimer { + MemoryReclaimer(TileType *data) : d(data) {} + + void destroy() + { + TileTypeSP::deref(reinterpret_cast(this), d); + this->MemoryReclaimer::~MemoryReclaimer(); + delete this; + } + + private: + TileType *d; + }; + + inline quint32 calculateHash(qint32 col, qint32 row) + { +#ifdef SANITY_CHECK + KIS_ASSERT_RECOVER_NOOP(row < 0x7FFF && col < 0x7FFF) +#endif // SANITY_CHECK + + if (col == 0 && row == 0) { + col = 0x7FFF; + row = 0x7FFF; + } + + return ((static_cast(row) << 16) | (static_cast(col) & 0xFFFF)); + } + + inline void insert(quint32 key, TileTypeSP value) + { + TileTypeSP::ref(&value, value.data()); + TileType *result = m_map.assign(key, value.data()); + + if (result) { + m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result)); + } else { + m_numTiles.fetchAndAddRelaxed(1); + } + + m_map.getGC().update(m_map.migrationInProcess()); + } + + inline bool erase(quint32 key) + { + bool wasDeleted = false; + TileType *result = m_map.erase(key); + + if (result) { + wasDeleted = true; + m_numTiles.fetchAndSubRelaxed(1); + m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result)); + } + + m_map.getGC().update(m_map.migrationInProcess()); + return wasDeleted; + } + +private: + ConcurrentMap m_map; + + /** + * We still need something to guard changes in m_defaultTileData, + * otherwise there will be concurrent read/writes, resulting in broken memory. + */ + QReadWriteLock m_defaultPixelDataLock; + + QAtomicInt m_numTiles; + KisTileData *m_defaultTileData; + KisMementoManager *m_mementoManager; +}; + +template +class KisTileHashTableIteratorTraits2 +{ +public: + typedef T TileType; + typedef KisSharedPtr TileTypeSP; + typedef typename ConcurrentMap::Iterator Iterator; + + KisTileHashTableIteratorTraits2(KisTileHashTableTraits2 *ht) : m_ht(ht) + { + m_iter.setMap(m_ht->m_map); + } + + void next() + { + m_iter.next(); + } + + TileTypeSP tile() const + { + return TileTypeSP(m_iter.getValue()); + } + + bool isDone() const + { + return !m_iter.isValid(); + } + + void deleteCurrent() + { + m_ht->erase(m_iter.getKey()); + next(); + } + + void moveCurrentToHashTable(KisTileHashTableTraits2 *newHashTable) + { + TileTypeSP tile = m_iter.getValue(); + next(); + m_ht->deleteTile(tile); + newHashTable->addTile(tile); + } + +private: + KisTileHashTableTraits2 *m_ht; + Iterator m_iter; +}; + +template +KisTileHashTableTraits2::KisTileHashTableTraits2(KisMementoManager *mm) + : m_numTiles(0), m_defaultTileData(0), m_mementoManager(mm) +{ +} + +template +KisTileHashTableTraits2::KisTileHashTableTraits2(const KisTileHashTableTraits2 &ht, KisMementoManager *mm) + : KisTileHashTableTraits2(mm) +{ + setDefaultTileData(ht.m_defaultTileData); + typename ConcurrentMap::Iterator iter(const_cast &>(ht.m_map)); + while (iter.isValid()) { + insert(iter.getKey(), iter.getValue()); + iter.next(); + } +} + +template +KisTileHashTableTraits2::~KisTileHashTableTraits2() +{ + clear(); + m_map.getGC().flush(); + setDefaultTileData(0); +} + +template +bool KisTileHashTableTraits2::tileExists(qint32 col, qint32 row) +{ + return getExistingTile(col, row); +} + +template +typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getExistingTile(qint32 col, qint32 row) +{ + quint32 idx = calculateHash(col, row); + TileTypeSP result = m_map.get(idx); + m_map.getGC().update(m_map.migrationInProcess()); + return result; +} + +template +typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getTileLazy(qint32 col, qint32 row, bool &newTile) +{ + newTile = false; + TileTypeSP tile; + quint32 idx = calculateHash(col, row); + typename ConcurrentMap::Mutator mutator = m_map.insertOrFind(idx); + + if (!mutator.getValue()) { + { + QReadLocker guard(&m_defaultPixelDataLock); + tile = new TileType(col, row, m_defaultTileData, m_mementoManager); + } + TileTypeSP::ref(&tile, tile.data()); + TileType *result = mutator.exchangeValue(tile.data()); + + if (result) { + m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result)); + } else { + newTile = true; + m_numTiles.fetchAndAddRelaxed(1); + } + + tile = m_map.get(idx); + } else { + tile = mutator.getValue(); + } + + m_map.getGC().update(m_map.migrationInProcess()); + return tile; +} + +template +typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile) +{ + quint32 idx = calculateHash(col, row); + TileTypeSP tile = m_map.get(idx); + existingTile = tile; + + if (!existingTile) { + QReadLocker guard(&m_defaultPixelDataLock); + tile = new TileType(col, row, m_defaultTileData, 0); + } + + m_map.getGC().update(m_map.migrationInProcess()); + return tile; +} + +template +void KisTileHashTableTraits2::addTile(TileTypeSP tile) +{ + quint32 idx = calculateHash(tile->col(), tile->row()); + insert(idx, tile); +} + +template +bool KisTileHashTableTraits2::deleteTile(TileTypeSP tile) +{ + return deleteTile(tile->col(), tile->row()); +} + +template +bool KisTileHashTableTraits2::deleteTile(qint32 col, qint32 row) +{ + quint32 idx = calculateHash(col, row); + return erase(idx); +} + +template +void KisTileHashTableTraits2::clear() +{ + typename ConcurrentMap::Iterator iter(m_map); + while (iter.isValid()) { + erase(iter.getKey()); + iter.next(); + } +} + +template +inline void KisTileHashTableTraits2::setDefaultTileData(KisTileData *defaultTileData) +{ + QWriteLocker guard(&m_defaultPixelDataLock); + if (m_defaultTileData) { + m_defaultTileData->release(); + m_defaultTileData = 0; + } + + if (defaultTileData) { + defaultTileData->acquire(); + m_defaultTileData = defaultTileData; + } +} + +template +inline KisTileData* KisTileHashTableTraits2::defaultTileData() +{ + QReadLocker guard(&m_defaultPixelDataLock); + return m_defaultTileData; +} + +template +void KisTileHashTableTraits2::debugPrintInfo() +{ +} + +template +void KisTileHashTableTraits2::debugMaxListLength(qint32 &min, qint32 &max) +{ +} + +typedef KisTileHashTableTraits2 KisTileHashTable; +typedef KisTileHashTableIteratorTraits2 KisTileHashTableIterator; +typedef KisTileHashTableIteratorTraits2 KisTileHashTableConstIterator; + +#endif // KIS_TILEHASHTABLE_2_H diff --git a/libs/image/tiles3/kis_tiled_data_manager.h b/libs/image/tiles3/kis_tiled_data_manager.h index 8308965a0c..b6f8384d17 100644 --- a/libs/image/tiles3/kis_tiled_data_manager.h +++ b/libs/image/tiles3/kis_tiled_data_manager.h @@ -1,414 +1,420 @@ /* * Copyright (c) 2004 Boudewijn Rempt * (c) 2009 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_TILEDDATAMANAGER_H_ #define KIS_TILEDDATAMANAGER_H_ #include #include #include #include #include +#include "config-hash-table-implementaion.h" //#include "kis_debug.h" #include "kritaimage_export.h" +#ifdef USE_LOCK_FREE_HASH_TABLE +#include "kis_tile_hash_table2.h" +#else #include "kis_tile_hash_table.h" +#endif // USE_LOCK_FREE_HASH_TABLE + #include "kis_memento_manager.h" #include "kis_memento.h" #include "KisTiledExtentManager.h" class KisTiledDataManager; typedef KisSharedPtr KisTiledDataManagerSP; class KisTiledIterator; class KisTiledRandomAccessor; class KisPaintDeviceWriter; class QIODevice; /** * KisTiledDataManager implements the interface that KisDataManager defines * * The interface definition is enforced by KisDataManager calling all the methods * which must also be defined in KisTiledDataManager. It is not allowed to change the interface * as other datamangers may also rely on the same interface. * * * Storing undo/redo data * * Offering ordered and unordered iterators over rects of pixels * * (eventually) efficiently loading and saving data in a format * that may allow deferred loading. * * A datamanager knows nothing about the type of pixel data except * how many quint8's a single pixel takes. */ class KRITAIMAGE_EXPORT KisTiledDataManager : public KisShared { private: static const qint32 LEGACY_VERSION = 1; static const qint32 CURRENT_VERSION = 2; protected: /*FIXME:*/ public: KisTiledDataManager(quint32 pixelSize, const quint8 *defPixel); virtual ~KisTiledDataManager(); KisTiledDataManager(const KisTiledDataManager &dm); KisTiledDataManager & operator=(const KisTiledDataManager &dm); protected: // Allow the baseclass of iterators access to the interior // derived iterator classes must go through KisTiledIterator friend class KisTiledIterator; friend class KisBaseIterator; friend class KisTiledRandomAccessor; friend class KisRandomAccessor2; friend class KisStressJob; public: void setDefaultPixel(const quint8 *defPixel); const quint8 *defaultPixel() const { return m_defaultPixel; } /** * Every iterator fetches both types of tiles all the time: old and new. * For projection devices these tiles are **always** the same, but doing * two distinct calls makes double pressure on the read-write lock in the * hash table. * * Merging two calls into one allows us to avoid additional tile fetch from * the hash table and therefore reduce waiting time. */ inline void getTilesPair(qint32 col, qint32 row, bool writable, KisTileSP *tile, KisTileSP *oldTile) { *tile = getTile(col, row, writable); bool unused; *oldTile = m_mementoManager->getCommitedTile(col, row, unused); if (!*oldTile) { *oldTile = *tile; } } inline KisTileSP getTile(qint32 col, qint32 row, bool writable) { if (writable) { bool newTile; KisTileSP tile = m_hashTable->getTileLazy(col, row, newTile); if (newTile) { m_extentManager.notifyTileAdded(col, row); } return tile; } else { bool unused; return m_hashTable->getReadOnlyTileLazy(col, row, unused); } } inline KisTileSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile) { return m_hashTable->getReadOnlyTileLazy(col, row, existingTile); } inline KisTileSP getOldTile(qint32 col, qint32 row, bool &existingTile) { KisTileSP tile = m_mementoManager->getCommitedTile(col, row, existingTile); return tile ? tile : getReadOnlyTileLazy(col, row, existingTile); } inline KisTileSP getOldTile(qint32 col, qint32 row) { bool unused; return getOldTile(col, row, unused); } KisMementoSP getMemento() { QWriteLocker locker(&m_lock); KisMementoSP memento = m_mementoManager->getMemento(); memento->saveOldDefaultPixel(m_defaultPixel, m_pixelSize); return memento; } /** * Finishes having already started transaction */ void commit() { QWriteLocker locker(&m_lock); KisMementoSP memento = m_mementoManager->currentMemento(); if(memento) { memento->saveNewDefaultPixel(m_defaultPixel, m_pixelSize); } m_mementoManager->commit(); } void rollback(KisMementoSP memento) { commit(); QWriteLocker locker(&m_lock); m_mementoManager->rollback(m_hashTable); const quint8 *defaultPixel = memento->oldDefaultPixel(); if(memcmp(m_defaultPixel, defaultPixel, m_pixelSize)) { setDefaultPixelImpl(defaultPixel); } recalculateExtent(); } void rollforward(KisMementoSP memento) { commit(); QWriteLocker locker(&m_lock); m_mementoManager->rollforward(m_hashTable); const quint8 *defaultPixel = memento->newDefaultPixel(); if(memcmp(m_defaultPixel, defaultPixel, m_pixelSize)) { setDefaultPixelImpl(defaultPixel); } recalculateExtent(); } bool hasCurrentMemento() const { return m_mementoManager->hasCurrentMemento(); //return true; } /** * Removes all the history that preceds the revision * pointed by oldestMemento. That is after calling to * purgeHistory(someMemento) you won't be able to do * rollback(someMemento) anymore. */ void purgeHistory(KisMementoSP oldestMemento) { QWriteLocker locker(&m_lock); m_mementoManager->purgeHistory(oldestMemento); } static void releaseInternalPools(); protected: /** * Reads and writes the tiles */ bool write(KisPaintDeviceWriter &store); bool read(QIODevice *stream); void purge(const QRect& area); inline quint32 pixelSize() const { return m_pixelSize; } /* FIXME:*/ public: void extent(qint32 &x, qint32 &y, qint32 &w, qint32 &h) const; void setExtent(qint32 x, qint32 y, qint32 w, qint32 h); QRect extent() const; void setExtent(QRect newRect); QRegion region() const; void clear(QRect clearRect, quint8 clearValue); void clear(QRect clearRect, const quint8 *clearPixel); void clear(qint32 x, qint32 y, qint32 w, qint32 h, quint8 clearValue); void clear(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *clearPixel); void clear(); /** * Clones rect from another datamanager. The cloned area will be * shared between both datamanagers as much as possible using * copy-on-write. Parts of the rect that cannot be shared * (cross tiles) are deep-copied, */ void bitBlt(KisTiledDataManager *srcDM, const QRect &rect); /** * The same as \ref bitBlt(), but reads old data */ void bitBltOldData(KisTiledDataManager *srcDM, const QRect &rect); /** * Clones rect from another datamanager in a rough and fast way. * All the tiles touched by rect will be shared, between both * managers, that means it will copy a bigger area than was * requested. This method is supposed to be used for bitBlt'ing * into temporary paint devices. */ void bitBltRough(KisTiledDataManager *srcDM, const QRect &rect); /** * The same as \ref bitBltRough(), but reads old data */ void bitBltRoughOldData(KisTiledDataManager *srcDM, const QRect &rect); /** * write the specified data to x, y. There is no checking on pixelSize! */ void setPixel(qint32 x, qint32 y, const quint8 * data); /** * Copy the bytes in the specified rect to a vector. The caller is responsible * for managing the vector. * * \param dataRowStride is the step (in bytes) which should be * added to \p bytes pointer to get to the * next row */ void readBytes(quint8 * bytes, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1) const; /** * Copy the bytes in the vector to the specified rect. If there are bytes left * in the vector after filling the rect, they will be ignored. If there are * not enough bytes, the rest of the rect will be filled with the default value * given (by default, 0); * * \param dataRowStride is the step (in bytes) which should be * added to \p bytes pointer to get to the * next row */ void writeBytes(const quint8 * bytes, qint32 x, qint32 y, qint32 w, qint32 h, qint32 dataRowStride = -1); /** * Copy the bytes in the paint device into a vector of arrays of bytes, * where the number of arrays is the number of channels in the * paint device. If the specified area is larger than the paint * device's extent, the default pixel will be read. */ QVector readPlanarBytes(QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) const; /** * Write the data in the separate arrays to the channels. If there * are less vectors than channels, the remaining channels will not * be copied. If any of the arrays points to 0, the channel in * that location will not be touched. If the specified area is * larger than the paint device, the paint device will be * extended. There are no guards: if the area covers more pixels * than there are bytes in the arrays, krita will happily fill * your paint device with areas of memory you never wanted to be * read. Krita may also crash. */ void writePlanarBytes(QVector planes, QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h); /** * Get the number of contiguous columns starting at x, valid for all values * of y between minY and maxY. */ qint32 numContiguousColumns(qint32 x, qint32 minY, qint32 maxY) const; /** * Get the number of contiguous rows starting at y, valid for all values * of x between minX and maxX. */ qint32 numContiguousRows(qint32 y, qint32 minX, qint32 maxX) const; /** * Get the row stride at pixel (x, y). This is the number of bytes to add to a * pointer to pixel (x, y) to access (x, y + 1). */ qint32 rowStride(qint32 x, qint32 y) const; private: KisTileHashTable *m_hashTable; KisMementoManager *m_mementoManager; quint8* m_defaultPixel; qint32 m_pixelSize; KisTiledExtentManager m_extentManager; mutable QReadWriteLock m_lock; private: // Allow compression routines to calculate (col,row) coordinates // and pixel size friend class KisAbstractTileCompressor; friend class KisTileDataWrapper; qint32 xToCol(qint32 x) const; qint32 yToRow(qint32 y) const; private: void setDefaultPixelImpl(const quint8 *defPixel); bool writeTilesHeader(KisPaintDeviceWriter &store, quint32 numTiles); bool processTilesHeader(QIODevice *stream, quint32 &numTiles); qint32 divideRoundDown(qint32 x, const qint32 y) const; void recalculateExtent(); quint8* duplicatePixel(qint32 num, const quint8 *pixel); template void bitBltImpl(KisTiledDataManager *srcDM, const QRect &rect); template void bitBltRoughImpl(KisTiledDataManager *srcDM, const QRect &rect); void writeBytesBody(const quint8 *data, qint32 x, qint32 y, qint32 width, qint32 height, qint32 dataRowStride = -1); void readBytesBody(quint8 *data, qint32 x, qint32 y, qint32 width, qint32 height, qint32 dataRowStride = -1) const; template void writePlanarBytesBody(QVector planes, QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h); QVector readPlanarBytesBody(QVector channelsizes, qint32 x, qint32 y, qint32 w, qint32 h) const; public: void debugPrintInfo() { m_mementoManager->debugPrintInfo(); } }; inline qint32 KisTiledDataManager::divideRoundDown(qint32 x, const qint32 y) const { /** * Equivalent to the following: * -(( -x + (y-1) ) / y) */ return x >= 0 ? x / y : -(((-x - 1) / y) + 1); } inline qint32 KisTiledDataManager::xToCol(qint32 x) const { return divideRoundDown(x, KisTileData::WIDTH); } inline qint32 KisTiledDataManager::yToRow(qint32 y) const { return divideRoundDown(y, KisTileData::HEIGHT); } // during development the following line helps to check the interface is correct // it should be safe to keep it here even during normal compilation //#include "kis_datamanager.h" #endif // KIS_TILEDDATAMANAGER_H_ diff --git a/libs/pigment/resources/KoColorSetEntry.cpp b/libs/pigment/resources/KoColorSetEntry.cpp index 76d5628572..8ac5d764b9 100644 --- a/libs/pigment/resources/KoColorSetEntry.cpp +++ b/libs/pigment/resources/KoColorSetEntry.cpp @@ -1,31 +1,33 @@ /* - * Copyright (c) 2018 Michael Zhou + * This file is part of the KDE project + * Copyright (c) 2005 Boudewijn Rempt + * Copyright (c) 2016 L. E. Segovia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; 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 "KoColorSetEntry.h" KoColorSetEntry::KoColorSetEntry() : m_spotColor(false) { } KoColorSetEntry::KoColorSetEntry(const KoColor &color, const QString &name) : m_color(color) , m_name(name) , m_spotColor(false) { } diff --git a/libs/pigment/resources/KoColorSetEntry.h b/libs/pigment/resources/KoColorSetEntry.h index 1801831680..7ff11429a1 100644 --- a/libs/pigment/resources/KoColorSetEntry.h +++ b/libs/pigment/resources/KoColorSetEntry.h @@ -1,55 +1,60 @@ /* - * Copyright (c) 2018 Michael Zhou + * This file is part of the KDE project + * Copyright (c) 2005 Boudewijn Rempt + * Copyright (c) 2016 L. E. Segovia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; 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 KOCOLORSETENTRY_H #define KOCOLORSETENTRY_H #include "kritapigment_export.h" #include #include "KoColor.h" class KRITAPIGMENT_EXPORT KoColorSetEntry { public: KoColorSetEntry(); KoColorSetEntry(const KoColor &color, const QString &name); public: QString name() const { return m_name; } void setName(const QString &name) { m_name = name; } + QString id() const { return m_id; } void setId(const QString &id) { m_id = id; } + KoColor color() const { return m_color; } void setColor(const KoColor &color) { m_color = color; } + bool spotColor() const { return m_spotColor; } void setSpotColor(bool spotColor) { m_spotColor = spotColor; } public: bool operator==(const KoColorSetEntry& rhs) const { return m_color == rhs.m_color && m_name == rhs.m_name; } private: KoColor m_color; QString m_name; QString m_id; bool m_spotColor; }; #endif // KOCOLORSETENTRY_H diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index fe7af22802..31fce2d593 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,588 +1,571 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ${EXIV2_INCLUDE_DIR} ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) find_library(APPKIT_LIBRARY AppKit) 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 canvas/KisSnapPointStrategy.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 dialogs/KisSessionManagerDialog.cpp dialogs/KisNewWindowLayoutDialog.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 KisPaintopPropertiesBase.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_change_file_layer_command.h kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc KisImageBarrierLockerWithFeedback.cpp 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 KisDecorationsManager.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 KisResourceServerProvider.cpp KisResourceBundleServerProvider.cpp KisSelectedShapesProxy.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 KisActionPlugin.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 opengl/kis_texture_tile_info_pool.cpp opengl/KisOpenGLUpdateInfoBuilder.cpp kis_fps_decoration.cpp 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_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/KisStrokeSpeedMonitor.cpp tool/strokes/freehand_stroke.cpp tool/strokes/KisStrokeEfficiencyMeasurer.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp tool/strokes/KisFreehandStrokeInfo.cpp tool/strokes/KisMaskedFreehandStrokePainter.cpp tool/strokes/KisMaskingBrushRenderer.cpp tool/strokes/KisMaskingBrushCompositeOpFactory.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_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_paintop_presets_save.cpp widgets/kis_paintop_preset_icon_library.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/KisSelectionPropertySlider.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.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/kis_preset_live_preview_view.cpp + widgets/KisScreenColorPicker.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 widgets/KoStrokeConfigWidget.cpp widgets/KoFillConfigWidget.cpp utils/kis_document_aware_spin_box_unit_manager.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_native_gesture_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp input/KisQtWidgetsTweaker.cpp input/KisInputActionGroup.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 actions/KisPasteActionFactory.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 KisCloneDocumentStroke.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 KisImportExportUtils.cpp kis_async_action_feedback.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoActionsUpdateManager.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 KisWindowLayoutResource.cpp KisWindowLayoutManager.cpp KisSessionResource.cpp KisReferenceImagesDecoration.cpp KisReferenceImage.cpp flake/KisReferenceImagesLayer.cpp flake/KisReferenceImagesLayer.h ) if(WIN32) 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 input/wintab/kis_tablet_support_win8.cpp opengl/kis_opengl_win.cpp ) endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp KisAsyncAnimationRendererBase.cpp KisAsyncAnimationCacheRenderer.cpp KisAsyncAnimationFramesSavingRenderer.cpp dialogs/KisAsyncAnimationRenderDialogBase.cpp dialogs/KisAsyncAnimationCacheRenderDialog.cpp dialogs/KisAsyncAnimationFramesSaveDialog.cpp canvas/kis_animation_player.cpp kis_animation_importer.cpp KisSyncedAudioPlayback.cpp KisFrameDataSerializer.cpp KisFrameCacheStore.cpp KisFrameCacheSwapper.cpp KisAbstractFrameCacheSwapper.cpp KisInMemoryFrameCacheSwapper.cpp input/wintab/drawpile_tablettester/tablettester.cpp input/wintab/drawpile_tablettester/tablettest.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/qxcbconnection_xi2.cpp input/wintab/qxcbconnection.cpp input/wintab/kis_xi2_event_filter.cpp ) endif() endif() if(APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} osx.mm ) endif() ki18n_wrap_ui(kritaui_LIB_SRCS widgets/KoFillConfigWidget.ui widgets/KoStrokeConfigWidget.ui 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/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgsavebrushpreset.ui forms/wdgpreseticonlibrary.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui forms/wdgstopgradienteditor.ui forms/wdgsessionmanager.ui forms/wdgnewwindowlayout.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 input/wintab/drawpile_tablettester/tablettest.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}) target_link_libraries(kritaui ${APPKIT_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/KisApplication.cpp b/libs/ui/KisApplication.cpp index aaea1acf51..2dfc9e1366 100644 --- a/libs/ui/KisApplication.cpp +++ b/libs/ui/KisApplication.cpp @@ -1,839 +1,845 @@ /* * Copyright (C) 1998, 1999 Torben Weis * Copyright (C) 2012 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 "KisApplication.h" #include #ifdef Q_OS_WIN #include #include #endif #ifdef Q_OS_OSX #include "osx.h" #endif #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 "KoConfig.h" #include #include #include #include "thememanager.h" #include "KisPrintJob.h" #include "KisDocument.h" #include "KisMainWindow.h" #include "KisAutoSaveRecoveryDialog.h" #include "KisPart.h" #include #include "kis_md5_generator.h" #include "kis_splash_screen.h" #include "kis_config.h" #include "flake/kis_shape_selection.h" #include #include #include #include #include #include #include #include "kisexiv2/kis_exiv2.h" #include "KisApplicationArguments.h" #include #include "kis_action_registry.h" #include #include #include #include "kis_image_barrier_locker.h" #include "opengl/kis_opengl.h" #include "kis_spin_box_unit_manager.h" #include "kis_document_aware_spin_box_unit_manager.h" #include "KisViewManager.h" #include "kis_workspace_resource.h" #include #include #include +#include "widgets/KisScreenColorPicker.h" +#include "KisDlgInternalColorSelector.h" + namespace { const QTime appStartTime(QTime::currentTime()); } class KisApplication::Private { public: Private() {} QPointer splashScreen; KisAutoSaveRecoveryDialog *autosaveDialog {0}; QPointer mainWindow; // The first mainwindow we create on startup bool batchRun {false}; }; class KisApplication::ResetStarting { public: ResetStarting(KisSplashScreen *splash, int fileCount) : m_splash(splash) , m_fileCount(fileCount) { } ~ResetStarting() { if (m_splash) { KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); if (m_fileCount > 0 || hideSplash) { m_splash->hide(); } else { m_splash->setWindowFlags(Qt::Dialog); QRect r(QPoint(), m_splash->size()); m_splash->move(QApplication::desktop()->availableGeometry().center() - r.center()); m_splash->setWindowTitle(qAppName()); m_splash->setParent(0); Q_FOREACH (QObject *o, m_splash->children()) { QWidget *w = qobject_cast(o); if (w && w->isHidden()) { w->setVisible(true); } } m_splash->show(); m_splash->activateWindow(); } } } QPointer m_splash; int m_fileCount; }; KisApplication::KisApplication(const QString &key, int &argc, char **argv) : QtSingleApplication(key, argc, argv) , d(new Private) { #ifdef Q_OS_OSX setMouseCoalescingEnabled(false); #endif + KisDlgInternalColorSelector::s_screenColorPickerFactory = KisScreenColorPicker::createScreenColorPicker; + + QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); setApplicationDisplayName("Krita"); setApplicationName("krita"); // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird. // setOrganizationName("krita"); setOrganizationDomain("krita.org"); QString version = KritaVersionWrapper::versionString(true); setApplicationVersion(version); setWindowIcon(KisIconUtils::loadIcon("calligrakrita")); if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) { QStringList styles = QStringList() << "breeze" << "fusion" << "plastique"; if (!styles.contains(style()->objectName().toLower())) { Q_FOREACH (const QString & style, styles) { if (!setStyle(style)) { qDebug() << "No" << style << "available."; } else { qDebug() << "Set style" << style; break; } } } } else { qDebug() << "Style override disabled, using" << style()->objectName(); } KisOpenGL::initialize(); } #if defined(Q_OS_WIN) && defined(ENV32BIT) typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; BOOL isWow64() { BOOL bIsWow64 = FALSE; //IsWow64Process is not available on all supported versions of Windows. //Use GetModuleHandle to get a handle to the DLL that contains the function //and GetProcAddress to get a pointer to the function if available. fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); if(0 != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { //handle error } } return bIsWow64; } #endif void KisApplication::initializeGlobals(const KisApplicationArguments &args) { int dpiX = args.dpiX(); int dpiY = args.dpiY(); if (dpiX > 0 && dpiY > 0) { KoDpi::setDPI(dpiX, dpiY); } } void KisApplication::addResourceTypes() { // qDebug() << "addResourceTypes();"; // All Krita's resource types KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("kis_brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("kis_paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("kis_workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("kis_windowlayouts", "data", "/windowlayouts/"); KoResourcePaths::addResourceType("kis_sessions", "data", "/sessions/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("ko_patterns", "data", "/patterns/", true); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("ko_gradients", "data", "/gradients/", true); KoResourcePaths::addResourceType("ko_palettes", "data", "/palettes/", true); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); KoResourcePaths::addResourceType("templates", "data", "/templates"); KoResourcePaths::addResourceType("pythonscripts", "data", "/pykrita"); KoResourcePaths::addResourceType("symbols", "data", "/symbols"); KoResourcePaths::addResourceType("preset_icons", "data", "/preset_icons"); // // Extra directories to look for create resources. (Does anyone actually use that anymore?) // KoResourcePaths::addResourceDir("ko_gradients", "/usr/share/create/gradients/gimp"); // KoResourcePaths::addResourceDir("ko_gradients", QDir::homePath() + QString("/.create/gradients/gimp")); // KoResourcePaths::addResourceDir("ko_patterns", "/usr/share/create/patterns/gimp"); // KoResourcePaths::addResourceDir("ko_patterns", QDir::homePath() + QString("/.create/patterns/gimp")); // KoResourcePaths::addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); // KoResourcePaths::addResourceDir("kis_brushes", QDir::homePath() + QString("/.create/brushes/gimp")); // KoResourcePaths::addResourceDir("ko_palettes", "/usr/share/create/swatches"); // KoResourcePaths::addResourceDir("ko_palettes", QDir::homePath() + QString("/.create/swatches")); // Make directories for all resources we can save, and tags QDir d; d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tags/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/asl/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/brushes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gradients/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/paintoppresets/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/palettes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patterns/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/workspaces/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/input/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/pykrita/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/symbols/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/color-schemes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/tool_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/emblem_icons/"); // Indicate that it is now safe for users of KoResourcePaths to load resources KoResourcePaths::setReady(); } void KisApplication::loadResources() { // qDebug() << "loadResources();"; setSplashScreenLoadingText(i18n("Loading Resources...")); processEvents(); KoResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brush Presets...")); processEvents(); KisResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brushes...")); processEvents(); KisBrushServer::instance()->brushServer(); setSplashScreenLoadingText(i18n("Loading Bundles...")); processEvents(); KisResourceBundleServerProvider::instance(); } void KisApplication::loadResourceTags() { // qDebug() << "loadResourceTags()"; KoResourceServerProvider::instance()->patternServer()->loadTags(); KoResourceServerProvider::instance()->gradientServer()->loadTags(); KoResourceServerProvider::instance()->paletteServer()->loadTags(); KoResourceServerProvider::instance()->svgSymbolCollectionServer()->loadTags(); KisBrushServer::instance()->brushServer()->loadTags(); KisResourceServerProvider::instance()->workspaceServer()->loadTags(); KisResourceServerProvider::instance()->layerStyleCollectionServer()->loadTags(); KisResourceBundleServerProvider::instance()->resourceBundleServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->clearOldSystemTags(); } void KisApplication::loadPlugins() { // qDebug() << "loadPlugins();"; KoShapeRegistry* r = KoShapeRegistry::instance(); r->add(new KisShapeSelectionFactory()); KisActionRegistry::instance(); KisFilterRegistry::instance(); KisGeneratorRegistry::instance(); KisPaintOpRegistry::instance(); KoColorSpaceRegistry::instance(); } void KisApplication::loadGuiPlugins() { // qDebug() << "loadGuiPlugins();"; // Load the krita-specific tools setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Tool...")); processEvents(); // qDebug() << "loading tools"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Tool"), QString::fromLatin1("[X-Krita-Version] == 28")); // Load dockers setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Dock...")); processEvents(); // qDebug() << "loading dockers"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Dock"), QString::fromLatin1("[X-Krita-Version] == 28")); // XXX_EXIV: make the exiv io backends real plugins setSplashScreenLoadingText(i18n("Loading Plugins Exiv/IO...")); processEvents(); // qDebug() << "loading exiv2"; KisExiv2::initialize(); } bool KisApplication::start(const KisApplicationArguments &args) { KisConfig cfg; #if defined(Q_OS_WIN) #ifdef ENV32BIT if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You are running a 32 bits build on a 64 bits Windows.\n" "This is not recommended.\n" "Please download and install the x64 build instead.")); cfg.writeEntry("WarnedAbout32Bits", true); } #endif #endif QString opengl = cfg.canvasState(); if (opengl == "OPENGL_NOT_TRIED" ) { cfg.setCanvasState("TRY_OPENGL"); } else if (opengl != "OPENGL_SUCCESS") { cfg.setCanvasState("OPENGL_FAILED"); } setSplashScreenLoadingText(i18n("Initializing Globals")); processEvents(); initializeGlobals(args); const bool doNewImage = args.doNewImage(); const bool doTemplate = args.doTemplate(); const bool exportAs = args.exportAs(); const QString exportFileName = args.exportFileName(); d->batchRun = (exportAs || !exportFileName.isEmpty()); const bool needsMainWindow = !exportAs; // only show the mainWindow when no command-line mode option is passed bool showmainWindow = !exportAs; // would be !batchRun; const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH"); if (showSplashScreen && d->splashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } KoHashGeneratorProvider::instance()->setGenerator("MD5", new KisMD5Generator()); KConfigGroup group(KSharedConfig::openConfig(), "theme"); Digikam::ThemeManager themeManager; themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done Q_UNUSED(resetStarting); // Make sure we can save resources and tags setSplashScreenLoadingText(i18n("Adding resource types")); processEvents(); addResourceTypes(); // Load the plugins loadPlugins(); // Load all resources loadResources(); // Load all the tags loadResourceTags(); // Load the gui plugins loadGuiPlugins(); KisPart *kisPart = KisPart::instance(); if (needsMainWindow) { // show a mainWindow asap, if we want that setSplashScreenLoadingText(i18n("Loading Main Window...")); processEvents(); bool sessionNeeded = true; auto sessionMode = cfg.sessionOnStartup(); if (!args.session().isEmpty()) { sessionNeeded = !kisPart->restoreSession(args.session()); } else if (sessionMode == KisConfig::SOS_ShowSessionManager) { showmainWindow = false; sessionNeeded = false; kisPart->showSessionManager(); } else if (sessionMode == KisConfig::SOS_PreviousSession) { KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session"); const QString &sessionName = sessionCfg.readEntry("previousSession"); sessionNeeded = !kisPart->restoreSession(sessionName); } if (sessionNeeded) { kisPart->startBlankSession(); } if (!args.windowLayout().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); KisWindowLayoutResource* windowLayout = rserver->resourceByName(args.windowLayout()); if (windowLayout) { windowLayout->applyLayout(); } } if (showmainWindow) { d->mainWindow = kisPart->currentMainwindow(); if (!args.workspace().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); KisWorkspaceResource* workspace = rserver->resourceByName(args.workspace()); if (workspace) { d->mainWindow->restoreWorkspace(workspace); } } if (args.canvasOnly()) { d->mainWindow->viewManager()->switchCanvasOnly(true); } if (args.fullScreen()) { d->mainWindow->showFullScreen(); } } else { d->mainWindow = kisPart->createMainWindow(); } } short int numberOfOpenDocuments = 0; // number of documents open // Check for autosave files that can be restored, if we're not running a batchrun (test) if (!d->batchRun) { checkAutosaveFiles(); } setSplashScreenLoadingText(QString()); // done loading, so clear out label processEvents(); //configure the unit manager KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder()); connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave. //the new syntax slot syntax allow to connect to a non q_object static method. // Create a new image, if needed if (doNewImage) { KisDocument *doc = args.image(); if (doc) { kisPart->addDocument(doc); d->mainWindow->addViewAndNotifyLoadingCompleted(doc); } } // Get the command line arguments which we have to parse int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; argNumber++) { QString fileName = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { // called in mix with batch options? ignore and silently skip if (d->batchRun) { continue; } if (createNewDocFromTemplate(fileName, d->mainWindow)) { ++numberOfOpenDocuments; } // now try to load } else { if (exportAs) { QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false); if (outputMimetype == "application/octetstream") { dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl; return 1; } KisDocument *doc = kisPart->createDocument(); doc->setFileBatchMode(d->batchRun); doc->openUrl(QUrl::fromLocalFile(fileName)); qApp->processEvents(); // For vector layers to be updated doc->setFileBatchMode(true); if (!doc->exportDocumentSync(QUrl::fromLocalFile(exportFileName), outputMimetype.toLatin1())) { dbgKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage(); } QTimer::singleShot(0, this, SLOT(quit())); } else if (d->mainWindow) { if (fileName.endsWith(".bundle")) { d->mainWindow->installBundle(fileName); } else { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (d->mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) { // Normal case, success numberOfOpenDocuments++; } } } } } } // fixes BUG:369308 - Krita crashing on splash screen when loading. // trying to open a file before Krita has loaded can cause it to hang and crash if (d->splashScreen) { d->splashScreen->displayLinks(true); d->splashScreen->displayRecentFiles(true); } // not calling this before since the program will quit there. return true; } KisApplication::~KisApplication() { } void KisApplication::setSplashScreen(QWidget *splashScreen) { d->splashScreen = qobject_cast(splashScreen); } void KisApplication::setSplashScreenLoadingText(QString textToLoad) { if (d->splashScreen) { //d->splashScreen->loadingLabel->setText(textToLoad); d->splashScreen->setLoadingText(textToLoad); d->splashScreen->repaint(); } } void KisApplication::hideSplashScreen() { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } } bool KisApplication::notify(QObject *receiver, QEvent *event) { try { return QApplication::notify(receiver, event); } catch (std::exception &e) { qWarning("Error %s sending event %i to object %s", e.what(), event->type(), qPrintable(receiver->objectName())); } catch (...) { qWarning("Error sending event %i to object %s", event->type(), qPrintable(receiver->objectName())); } return false; } void KisApplication::remoteArguments(QByteArray message, QObject *socket) { Q_UNUSED(socket); // check if we have any mainwindow KisMainWindow *mw = qobject_cast(qApp->activeWindow()); if (!mw) { mw = KisPart::instance()->mainWindows().first(); } if (!mw) { return; } KisApplicationArguments args = KisApplicationArguments::deserialize(message); const bool doTemplate = args.doTemplate(); const int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; ++argNumber) { QString filename = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { createNewDocFromTemplate(filename, mw); } else if (QFile(filename).exists()) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mw->openDocument(QUrl::fromLocalFile(filename), flags); } } } } void KisApplication::fileOpenRequested(const QString &url) { KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first(); if (mainWindow) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mainWindow->openDocument(QUrl::fromLocalFile(url), flags); } } void KisApplication::checkAutosaveFiles() { if (d->batchRun) return; // Check for autosave files from a previous run. There can be several, and // we want to offer a restore for every one. Including a nice thumbnail! QStringList filters; filters << QString(".krita-*-*-autosave.kra"); #ifdef Q_OS_WIN QDir dir = QDir::temp(); #else QDir dir = QDir::home(); #endif // all autosave files for our application QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden); // Allow the user to make their selection if (autosaveFiles.size() > 0) { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow()); QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec(); if (result == QDialog::Accepted) { QStringList filesToRecover = d->autosaveDialog->recoverableFiles(); Q_FOREACH (const QString &autosaveFile, autosaveFiles) { if (!filesToRecover.contains(autosaveFile)) { QFile::remove(dir.absolutePath() + "/" + autosaveFile); } } autosaveFiles = filesToRecover; } else { autosaveFiles.clear(); } if (autosaveFiles.size() > 0) { QList autosaveUrls; Q_FOREACH (const QString &autoSaveFile, autosaveFiles) { const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile); autosaveUrls << url; } if (d->mainWindow) { Q_FOREACH (const QUrl &url, autosaveUrls) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; d->mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile); } } } // cleanup delete d->autosaveDialog; d->autosaveDialog = nullptr; } } bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow) { QString templatePath; const QUrl templateUrl = QUrl::fromLocalFile(fileName); if (QFile::exists(fileName)) { templatePath = templateUrl.toLocalFile(); dbgUI << "using full path..."; } else { QString desktopName(fileName); const QString templatesResourcePath = QStringLiteral("templates/"); QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName); if (paths.isEmpty()) { paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName); } if (paths.isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("No template found for: %1", desktopName)); } else if (paths.count() > 1) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Too many templates found for: %1", desktopName)); } else { templatePath = paths.at(0); } } if (!templatePath.isEmpty()) { QUrl templateBase; templateBase.setPath(templatePath); KDesktopFile templateInfo(templatePath); QString templateName = templateInfo.readUrl(); QUrl templateURL; templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName); KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (mainWindow->openDocument(templateURL, KisMainWindow::Import | batchFlags)) { dbgUI << "Template loaded..."; return true; } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Template %1 failed to load.", templateURL.toDisplayString())); } } return false; } void KisApplication::clearConfig() { KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread()); KSharedConfigPtr config = KSharedConfig::openConfig(); // find user settings file bool createDir = false; QString kritarcPath = KoResourcePaths::locateLocal("config", "kritarc", createDir); QFile configFile(kritarcPath); if (configFile.exists()) { // clear file if (configFile.open(QFile::WriteOnly)) { configFile.close(); } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Failed to clear %1\n\n" "Please make sure no other program is using the file and try again.", kritarcPath), QMessageBox::Ok, QMessageBox::Ok); } } // reload from disk; with the user file settings cleared, // this should load any default configuration files shipping with the program config->reparseConfiguration(); config->sync(); } void KisApplication::askClearConfig() { Qt::KeyboardModifiers mods = QApplication::queryKeyboardModifiers(); bool askClearConfig = (mods & Qt::ControlModifier) && (mods & Qt::ShiftModifier) && (mods & Qt::AltModifier); if (askClearConfig) { bool ok = QMessageBox::question(0, i18nc("@title:window", "Krita"), i18n("Do you want to clear the settings file?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; if (ok) { clearConfig(); } } } diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc index da97d9f897..07e820850e 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -1,1403 +1,1404 @@ /* * preferencesdlg.cc - part of KImageShop * * Copyright (c) 1999 Michael Koch * Copyright (c) 2003-2011 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_dlg_preferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoID.h" #include #include #include +#include #include #include #include "kis_action_registry.h" #include #include #include "kis_clipboard.h" #include "widgets/kis_cmb_idlist.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "KoColorConversionTransformation.h" #include "kis_cursor.h" #include "kis_config.h" #include "kis_canvas_resource_provider.h" #include "kis_preference_set_registry.h" #include "kis_color_manager.h" #include "KisProofingConfiguration.h" #include "kis_image_config.h" #include "slider_and_spin_box_sync.h" // for the performance update #include #include #include "input/config/kis_input_configuration_page.h" #include "input/wintab/drawpile_tablettester/tablettester.h" #ifdef Q_OS_WIN # include #endif GeneralTab::GeneralTab(QWidget *_parent, const char *_name) : WdgGeneralSettings(_parent, _name) { KisConfig cfg; // // Cursor Tab // m_cmbCursorShape->addItem(i18n("No Cursor")); m_cmbCursorShape->addItem(i18n("Tool Icon")); m_cmbCursorShape->addItem(i18n("Arrow")); m_cmbCursorShape->addItem(i18n("Small Circle")); m_cmbCursorShape->addItem(i18n("Crosshair")); m_cmbCursorShape->addItem(i18n("Triangle Righthanded")); m_cmbCursorShape->addItem(i18n("Triangle Lefthanded")); m_cmbCursorShape->addItem(i18n("Black Pixel")); m_cmbCursorShape->addItem(i18n("White Pixel")); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle()); m_cmbOutlineShape->addItem(i18n("No Outline")); m_cmbOutlineShape->addItem(i18n("Circle Outline")); m_cmbOutlineShape->addItem(i18n("Preview Outline")); m_cmbOutlineShape->addItem(i18n("Tilt Outline")); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle()); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting()); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline()); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor()); cursorColorBtutton->setColor(cursorColor); // // Window Tab // m_cmbMDIType->setCurrentIndex(cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView)); m_backgroundimage->setText(cfg.getMDIBackgroundImage()); connect(m_bnFileName, SIGNAL(clicked()), SLOT(getBackgroundImage())); connect(clearBgImageButton, SIGNAL(clicked()), SLOT(clearBackgroundImage())); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor()); m_mdiColor->setColor(mdiColor); m_chkRubberBand->setChecked(cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); m_chkHiDPI->setChecked(kritarc.value("EnableHiDPI", false).toBool()); m_chkSingleApplication->setChecked(kritarc.value("EnableSingleApplication", true).toBool()); // // Tools tab // m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker()); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt()); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas()); m_cmbKineticScrollingGesture->addItem(i18n("Disabled")); m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag")); m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag")); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture()); m_kineticScrollingSensitivity->setValue(cfg.kineticScrollingSensitivity()); m_chkKineticScrollingScrollbar->setChecked(cfg.kineticScrollingScrollbar()); // // Miscellaneous // cmbStartupSession->addItem(i18n("Open default window")); cmbStartupSession->addItem(i18n("Load previous session")); cmbStartupSession->addItem(i18n("Show session manager")); cmbStartupSession->setCurrentIndex(cfg.sessionOnStartup()); chkSaveSessionOnQuit->setChecked(cfg.saveSessionOnQuit(false)); int autosaveInterval = cfg.autoSaveInterval(); //convert to minutes m_autosaveSpinBox->setValue(autosaveInterval / 60); m_autosaveCheckBox->setChecked(autosaveInterval > 0); m_chkCompressKra->setChecked(cfg.compressKra()); m_backupFileCheckBox->setChecked(cfg.backupFile()); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport()); m_undoStackSize->setValue(cfg.undoStackLimit()); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets()); chkShowRootLayer->setChecked(cfg.showRootLayer()); m_hideSplashScreen->setChecked(cfg.hideSplashScreen()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); bool dontUseNative = true; #ifdef Q_OS_UNIX if (qgetenv("XDG_CURRENT_DESKTOP") == "KDE") { dontUseNative = false; } #endif #ifdef Q_OS_WIN dontUseNative = false; #endif m_chkNativeFileDialog->setChecked(!group.readEntry("DontUseNativeFileDialog", dontUseNative)); intMaxBrushSize->setValue(cfg.readEntry("maximumBrushSize", 1000)); } void GeneralTab::setDefault() { KisConfig cfg; m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle(true)); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle(true)); chkShowRootLayer->setChecked(cfg.showRootLayer(true)); m_autosaveCheckBox->setChecked(cfg.autoSaveInterval(true) > 0); //convert to minutes m_autosaveSpinBox->setValue(cfg.autoSaveInterval(true) / 60); m_undoStackSize->setValue(cfg.undoStackLimit(true)); m_backupFileCheckBox->setChecked(cfg.backupFile(true)); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting(true)); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline(true)); m_hideSplashScreen->setChecked(cfg.hideSplashScreen(true)); m_chkNativeFileDialog->setChecked(false); intMaxBrushSize->setValue(1000); m_cmbMDIType->setCurrentIndex((int)QMdiArea::TabbedView); m_chkRubberBand->setChecked(cfg.useOpenGL(true)); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets(true)); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor(true)); m_mdiColor->setColor(mdiColor); m_backgroundimage->setText(cfg.getMDIBackgroundImage(true)); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true)); m_chkCompressKra->setChecked(cfg.compressKra(true)); m_chkHiDPI->setChecked(false); m_chkSingleApplication->setChecked(true); m_chkHiDPI->setChecked(true); m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true)); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture(true)); m_kineticScrollingSensitivity->setValue(cfg.kineticScrollingSensitivity(true)); m_chkKineticScrollingScrollbar->setChecked(cfg.kineticScrollingScrollbar(true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true)); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas(true)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport(true)); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor(true)); cursorColorBtutton->setColor(cursorColor); } CursorStyle GeneralTab::cursorStyle() { return (CursorStyle)m_cmbCursorShape->currentIndex(); } OutlineStyle GeneralTab::outlineStyle() { return (OutlineStyle)m_cmbOutlineShape->currentIndex(); } KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const { return (KisConfig::SessionOnStartup)cmbStartupSession->currentIndex(); } bool GeneralTab::saveSessionOnQuit() const { return chkSaveSessionOnQuit->isChecked(); } bool GeneralTab::showRootLayer() { return chkShowRootLayer->isChecked(); } int GeneralTab::autoSaveInterval() { //convert to seconds return m_autosaveCheckBox->isChecked() ? m_autosaveSpinBox->value() * 60 : 0; } int GeneralTab::undoStackSize() { return m_undoStackSize->value(); } bool GeneralTab::showOutlineWhilePainting() { return m_showOutlinePainting->isChecked(); } bool GeneralTab::hideSplashScreen() { return m_hideSplashScreen->isChecked(); } int GeneralTab::mdiMode() { return m_cmbMDIType->currentIndex(); } int GeneralTab::favoritePresets() { return m_favoritePresetsSpinBox->value(); } bool GeneralTab::showCanvasMessages() { return m_chkCanvasMessages->isChecked(); } bool GeneralTab::compressKra() { return m_chkCompressKra->isChecked(); } bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); } int GeneralTab::kineticScrollingGesture() { return m_cmbKineticScrollingGesture->currentIndex(); } int GeneralTab::kineticScrollingSensitivity() { return m_kineticScrollingSensitivity->value(); } bool GeneralTab::kineticScrollingScrollbar() { return m_chkKineticScrollingScrollbar->isChecked(); } bool GeneralTab::switchSelectionCtrlAlt() { return m_chkSwitchSelectionCtrlAlt->isChecked(); } bool GeneralTab::convertToImageColorspaceOnImport() { return m_chkConvertOnImport->isChecked(); } void GeneralTab::getBackgroundImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BackgroundImages"); dialog.setCaption(i18n("Select a Background Image")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setImageFilters(); QString fn = dialog.filename(); // dialog box was canceled or somehow no file was selected if (fn.isEmpty()) { return; } QImage image(fn); if (image.isNull()) { QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("%1 is not a valid image file!", fn)); } else { m_backgroundimage->setText(fn); } } void GeneralTab::clearBackgroundImage() { // clearing the background image text will implicitly make the background color be used m_backgroundimage->setText(""); } #include "kactioncollection.h" #include "KisActionsSnapshot.h" ShortcutSettingsTab::ShortcutSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgShortcutSettings(this); l->addWidget(m_page, 0, 0); m_snapshot.reset(new KisActionsSnapshot); KActionCollection *collection = KisPart::instance()->currentMainwindow()->actionCollection(); Q_FOREACH (QAction *action, collection->actions()) { m_snapshot->addAction(action->objectName(), action); } QMap sortedCollections = m_snapshot->actionCollections(); for (auto it = sortedCollections.constBegin(); it != sortedCollections.constEnd(); ++it) { m_page->addCollection(it.value(), it.key()); } } ShortcutSettingsTab::~ShortcutSettingsTab() { } void ShortcutSettingsTab::setDefault() { m_page->allDefault(); } void ShortcutSettingsTab::saveChanges() { m_page->save(); KisActionRegistry::instance()->settingsPageSaved(); } void ShortcutSettingsTab::cancelChanges() { m_page->undo(); } ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); // XXX: Make sure only profiles that fit the specified color model // are shown in the profile combos QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgColorSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg; m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile()); connect(m_page->chkUseSystemMonitorProfile, SIGNAL(toggled(bool)), this, SLOT(toggleAllowMonitorProfileSelection(bool))); m_page->cmbWorkingColorSpace->setIDList(KoColorSpaceRegistry::instance()->listKeys()); m_page->cmbWorkingColorSpace->setCurrent(cfg.workingColorSpace()); m_page->bnAddColorProfile->setIcon(KisIconUtils::loadIcon("document-open")); m_page->bnAddColorProfile->setToolTip( i18n("Open Color Profile") ); connect(m_page->bnAddColorProfile, SIGNAL(clicked()), SLOT(installProfile())); QFormLayout *monitorProfileGrid = new QFormLayout(m_page->monitorprofileholder); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QLabel *lbl = new QLabel(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileLabels << lbl; SqueezedComboBox *cmb = new SqueezedComboBox(); cmb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); monitorProfileGrid->addRow(lbl, cmb); m_monitorProfileWidgets << cmb; } refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation()); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization()); KisImageConfig cfgImage; KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); m_page->sldAdaptationState->setMaximum(20); m_page->sldAdaptationState->setMinimum(0); m_page->sldAdaptationState->setValue((int)proofingConfig->adaptationState*20); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_pasteBehaviourGroup.addButton(m_page->radioPasteWeb, PASTE_ASSUME_WEB); m_pasteBehaviourGroup.addButton(m_page->radioPasteMonitor, PASTE_ASSUME_MONITOR); m_pasteBehaviourGroup.addButton(m_page->radioPasteAsk, PASTE_ASK); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour()); Q_ASSERT(button); if (button) { button->setChecked(true); } m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent()); toggleAllowMonitorProfileSelection(cfg.useSystemMonitorProfile()); } void ColorSettingsTab::installProfile() { KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocumentICC"); dialog.setCaption(i18n("Install Color Profiles")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setMimeTypeFilters(QStringList() << "application/vnd.iccprofile", "application/vnd.iccprofile"); QStringList profileNames = dialog.filenames(); KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); Q_ASSERT(iccEngine); QString saveLocation = KoResourcePaths::saveLocation("icc_profiles"); Q_FOREACH (const QString &profileName, profileNames) { if (!QFile::copy(profileName, saveLocation + QFileInfo(profileName).fileName())) { qWarning() << "Could not install profile!" << saveLocation + QFileInfo(profileName).fileName(); continue; } iccEngine->addProfile(saveLocation + QFileInfo(profileName).fileName()); } KisConfig cfg; refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } void ColorSettingsTab::toggleAllowMonitorProfileSelection(bool useSystemProfile) { if (useSystemProfile) { KisConfig cfg; QStringList devices = KisColorManager::instance()->devices(); if (devices.size() == QApplication::desktop()->screenCount()) { for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); QString monitorForScreen = cfg.monitorForScreen(i, devices[i]); Q_FOREACH (const QString &device, devices) { m_monitorProfileLabels[i]->setText(i18nc("The display/screen we got from Qt", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->addSqueezedItem(KisColorManager::instance()->deviceName(device), device); if (devices[i] == monitorForScreen) { m_monitorProfileWidgets[i]->setCurrentIndex(i); } } } } } else { KisConfig cfg; refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } } void ColorSettingsTab::setDefault() { m_page->cmbWorkingColorSpace->setCurrent("RGBA"); refillMonitorProfiles(KoID("RGBA", "")); KisConfig cfg; KisImageConfig cfgImage; KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,proofingConfig->proofingDepth,proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_page->sldAdaptationState->setValue(0); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation(true)); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization(true)); m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent(true)); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile(true)); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour(true)); Q_ASSERT(button); if (button) { button->setChecked(true); } } void ColorSettingsTab::refillMonitorProfiles(const KoID & colorSpaceId) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); } QMap profileList; Q_FOREACH(const KoColorProfile *profile, KoColorSpaceRegistry::instance()->profilesFor(colorSpaceId.id())) { profileList[profile->name()] = profile; } Q_FOREACH (const KoColorProfile *profile, profileList.values()) { //qDebug() << "Profile" << profile->name() << profile->isSuitableForDisplay() << csf->defaultProfile(); if (profile->isSuitableForDisplay()) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->addSqueezedItem(profile->name()); } } } for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileLabels[i]->setText(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->setCurrent(KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId.id())); } } //--------------------------------------------------------------------------------------------------- void TabletSettingsTab::setDefault() { KisCubicCurve curve; curve.fromString(DEFAULT_CURVE_STRING); m_page->pressureCurve->setCurve(curve); #ifdef Q_OS_WIN if (KisTabletSupportWin8::isAvailable()) { KisConfig cfg; m_page->radioWintab->setChecked(!cfg.useWin8PointerInput(true)); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput(true)); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); } #endif } TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgTabletSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg; KisCubicCurve curve; curve.fromString( cfg.pressureTabletCurve() ); m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); m_page->pressureCurve->setCurve(curve); #ifdef Q_OS_WIN if (KisTabletSupportWin8::isAvailable()) { m_page->radioWintab->setChecked(!cfg.useWin8PointerInput()); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput()); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); m_page->grpTabletApi->setVisible(false); } #else m_page->grpTabletApi->setVisible(false); #endif connect(m_page->btnTabletTest, SIGNAL(clicked()), SLOT(slotTabletTest())); } void TabletSettingsTab::slotTabletTest() { TabletTestDialog tabletTestDialog(this); tabletTestDialog.exec(); } //--------------------------------------------------------------------------------------------------- #include "kis_acyclic_signal_connector.h" int getTotalRAM() { KisImageConfig cfg; return cfg.totalRAM(); } int PerformanceTab::realTilesRAM() { return intMemoryLimit->value() - intPoolLimit->value(); } PerformanceTab::PerformanceTab(QWidget *parent, const char *name) : WdgPerformanceSettings(parent, name) { KisImageConfig cfg; - const int totalRAM = cfg.totalRAM(); - lblTotalMemory->setText(i18n("%1 MiB", totalRAM)); + const double totalRAM = cfg.totalRAM(); + lblTotalMemory->setText(KFormat().formatByteSize(totalRAM * 1024 * 1024, 0, KFormat::IECBinaryDialect, KFormat::UnitMegaByte)); sliderMemoryLimit->setSuffix(i18n(" %")); sliderMemoryLimit->setRange(1, 100, 2); sliderMemoryLimit->setSingleStep(0.01); sliderPoolLimit->setSuffix(i18n(" %")); sliderPoolLimit->setRange(0, 20, 2); sliderMemoryLimit->setSingleStep(0.01); sliderUndoLimit->setSuffix(i18n(" %")); sliderUndoLimit->setRange(0, 50, 2); sliderMemoryLimit->setSingleStep(0.01); intMemoryLimit->setMinimumWidth(80); intPoolLimit->setMinimumWidth(80); intUndoLimit->setMinimumWidth(80); SliderAndSpinBoxSync *sync1 = new SliderAndSpinBoxSync(sliderMemoryLimit, intMemoryLimit, getTotalRAM); sync1->slotParentValueChanged(); m_syncs << sync1; SliderAndSpinBoxSync *sync2 = new SliderAndSpinBoxSync(sliderPoolLimit, intPoolLimit, std::bind(&KisIntParseSpinBox::value, intMemoryLimit)); connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync2, SLOT(slotParentValueChanged())); sync2->slotParentValueChanged(); m_syncs << sync2; SliderAndSpinBoxSync *sync3 = new SliderAndSpinBoxSync(sliderUndoLimit, intUndoLimit, std::bind(&PerformanceTab::realTilesRAM, this)); connect(intPoolLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged())); sync3->slotParentValueChanged(); m_syncs << sync3; sliderSwapSize->setSuffix(i18n(" GiB")); sliderSwapSize->setRange(1, 64); intSwapSize->setRange(1, 64); KisAcyclicSignalConnector *swapSizeConnector = new KisAcyclicSignalConnector(this); swapSizeConnector->connectForwardInt(sliderSwapSize, SIGNAL(valueChanged(int)), intSwapSize, SLOT(setValue(int))); swapSizeConnector->connectBackwardInt(intSwapSize, SIGNAL(valueChanged(int)), sliderSwapSize, SLOT(setValue(int))); lblSwapFileLocation->setText(cfg.swapDir()); connect(bnSwapFile, SIGNAL(clicked()), SLOT(selectSwapDir())); sliderThreadsLimit->setRange(1, QThread::idealThreadCount()); sliderFrameClonesLimit->setRange(1, QThread::idealThreadCount()); sliderFpsLimit->setRange(20, 100); sliderFpsLimit->setSuffix(i18n(" fps")); connect(sliderThreadsLimit, SIGNAL(valueChanged(int)), SLOT(slotThreadsLimitChanged(int))); connect(sliderFrameClonesLimit, SIGNAL(valueChanged(int)), SLOT(slotFrameClonesLimitChanged(int))); intCachedFramesSizeLimit->setRange(1, 10000); intCachedFramesSizeLimit->setSuffix(i18n(" px")); intCachedFramesSizeLimit->setSingleStep(1); intCachedFramesSizeLimit->setPageStep(1000); intRegionOfInterestMargin->setRange(1, 100); intRegionOfInterestMargin->setSuffix(i18n(" %")); intRegionOfInterestMargin->setSingleStep(1); intRegionOfInterestMargin->setPageStep(10); connect(chkCachedFramesSizeLimit, SIGNAL(toggled(bool)), intCachedFramesSizeLimit, SLOT(setEnabled(bool))); connect(chkUseRegionOfInterest, SIGNAL(toggled(bool)), intRegionOfInterestMargin, SLOT(setEnabled(bool))); load(false); } PerformanceTab::~PerformanceTab() { qDeleteAll(m_syncs); } void PerformanceTab::load(bool requestDefault) { KisImageConfig cfg; sliderMemoryLimit->setValue(cfg.memoryHardLimitPercent(requestDefault)); sliderPoolLimit->setValue(cfg.memoryPoolLimitPercent(requestDefault)); sliderUndoLimit->setValue(cfg.memorySoftLimitPercent(requestDefault)); chkPerformanceLogging->setChecked(cfg.enablePerfLog(requestDefault)); chkProgressReporting->setChecked(cfg.enableProgressReporting(requestDefault)); sliderSwapSize->setValue(cfg.maxSwapSize(requestDefault) / 1024); lblSwapFileLocation->setText(cfg.swapDir(requestDefault)); m_lastUsedThreadsLimit = cfg.maxNumberOfThreads(requestDefault); m_lastUsedClonesLimit = cfg.frameRenderingClones(requestDefault); sliderThreadsLimit->setValue(m_lastUsedThreadsLimit); sliderFrameClonesLimit->setValue(m_lastUsedClonesLimit); sliderFpsLimit->setValue(cfg.fpsLimit(requestDefault)); { KisConfig cfg2; chkOpenGLFramerateLogging->setChecked(cfg2.enableOpenGLFramerateLogging(requestDefault)); chkBrushSpeedLogging->setChecked(cfg2.enableBrushSpeedLogging(requestDefault)); chkDisableVectorOptimizations->setChecked(cfg2.enableAmdVectorizationWorkaround(requestDefault)); chkBackgroundCacheGeneration->setChecked(cfg2.calculateAnimationCacheInBackground(requestDefault)); } if (cfg.useOnDiskAnimationCacheSwapping(requestDefault)) { optOnDisk->setChecked(true); } else { optInMemory->setChecked(true); } chkCachedFramesSizeLimit->setChecked(cfg.useAnimationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setValue(cfg.animationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setEnabled(chkCachedFramesSizeLimit->isChecked()); chkUseRegionOfInterest->setChecked(cfg.useAnimationCacheRegionOfInterest(requestDefault)); intRegionOfInterestMargin->setValue(cfg.animationCacheRegionOfInterestMargin(requestDefault) * 100.0); intRegionOfInterestMargin->setEnabled(chkUseRegionOfInterest->isChecked()); } void PerformanceTab::save() { KisImageConfig cfg; cfg.setMemoryHardLimitPercent(sliderMemoryLimit->value()); cfg.setMemorySoftLimitPercent(sliderUndoLimit->value()); cfg.setMemoryPoolLimitPercent(sliderPoolLimit->value()); cfg.setEnablePerfLog(chkPerformanceLogging->isChecked()); cfg.setEnableProgressReporting(chkProgressReporting->isChecked()); cfg.setMaxSwapSize(sliderSwapSize->value() * 1024); cfg.setSwapDir(lblSwapFileLocation->text()); cfg.setMaxNumberOfThreads(sliderThreadsLimit->value()); cfg.setFrameRenderingClones(sliderFrameClonesLimit->value()); cfg.setFpsLimit(sliderFpsLimit->value()); { KisConfig cfg2; cfg2.setEnableOpenGLFramerateLogging(chkOpenGLFramerateLogging->isChecked()); cfg2.setEnableBrushSpeedLogging(chkBrushSpeedLogging->isChecked()); cfg2.setEnableAmdVectorizationWorkaround(chkDisableVectorOptimizations->isChecked()); cfg2.setCalculateAnimationCacheInBackground(chkBackgroundCacheGeneration->isChecked()); } cfg.setUseOnDiskAnimationCacheSwapping(optOnDisk->isChecked()); cfg.setUseAnimationCacheFrameSizeLimit(chkCachedFramesSizeLimit->isChecked()); cfg.setAnimationCacheFrameSizeLimit(intCachedFramesSizeLimit->value()); cfg.setUseAnimationCacheRegionOfInterest(chkUseRegionOfInterest->isChecked()); cfg.setAnimationCacheRegionOfInterestMargin(intRegionOfInterestMargin->value() / 100.0); } void PerformanceTab::selectSwapDir() { KisImageConfig cfg; QString swapDir = cfg.swapDir(); swapDir = QFileDialog::getExistingDirectory(0, i18nc("@title:window", "Select a swap directory"), swapDir); if (swapDir.isEmpty()) { return; } lblSwapFileLocation->setText(swapDir); } void PerformanceTab::slotThreadsLimitChanged(int value) { KisSignalsBlocker b(sliderFrameClonesLimit); sliderFrameClonesLimit->setValue(qMin(m_lastUsedClonesLimit, value)); m_lastUsedThreadsLimit = value; } void PerformanceTab::slotFrameClonesLimitChanged(int value) { KisSignalsBlocker b(sliderThreadsLimit); sliderThreadsLimit->setValue(qMax(m_lastUsedThreadsLimit, value)); m_lastUsedClonesLimit = value; } //--------------------------------------------------------------------------------------------------- #include "KoColor.h" DisplaySettingsTab::DisplaySettingsTab(QWidget *parent, const char *name) : WdgDisplaySettings(parent, name) { KisConfig cfg; const QString rendererOpenGLText = i18nc("canvas renderer", "OpenGL"); const QString rendererAngleText = i18nc("canvas renderer", "Direct3D 11 via ANGLE"); #ifdef Q_OS_WIN cmbRenderer->clear(); QString qtPreferredRendererText; if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererAngle) { qtPreferredRendererText = rendererAngleText; } else { qtPreferredRendererText = rendererOpenGLText; } cmbRenderer->addItem(i18nc("canvas renderer", "Auto (%1)", qtPreferredRendererText), KisOpenGL::RendererAuto); cmbRenderer->setCurrentIndex(0); if (KisOpenGL::getSupportedOpenGLRenderers() & KisOpenGL::RendererDesktopGL) { cmbRenderer->addItem(rendererOpenGLText, KisOpenGL::RendererDesktopGL); if (KisOpenGL::getNextUserOpenGLRendererConfig() == KisOpenGL::RendererDesktopGL) { cmbRenderer->setCurrentIndex(cmbRenderer->count() - 1); } } if (KisOpenGL::getSupportedOpenGLRenderers() & KisOpenGL::RendererAngle) { cmbRenderer->addItem(rendererAngleText, KisOpenGL::RendererAngle); if (KisOpenGL::getNextUserOpenGLRendererConfig() == KisOpenGL::RendererAngle) { cmbRenderer->setCurrentIndex(cmbRenderer->count() - 1); } } #else lblRenderer->setEnabled(false); cmbRenderer->setEnabled(false); cmbRenderer->clear(); cmbRenderer->addItem(rendererOpenGLText); cmbRenderer->setCurrentIndex(0); #endif #ifdef Q_OS_WIN if (!(KisOpenGL::getSupportedOpenGLRenderers() & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererAngle))) { #else if (!KisOpenGL::hasOpenGL()) { #endif grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL()); chkUseTextureBuffer->setEnabled(cfg.useOpenGL()); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer()); chkDisableVsync->setVisible(cfg.showAdvancedOpenGLSettings()); chkDisableVsync->setEnabled(cfg.useOpenGL()); chkDisableVsync->setChecked(cfg.disableVSync()); cmbFilterMode->setEnabled(cfg.useOpenGL()); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode()); // Don't show the high quality filtering mode if it's not available if (!KisOpenGL::supportsLoD()) { cmbFilterMode->removeItem(3); } } const QStringList openglWarnings = KisOpenGL::getOpenGLWarnings(); if (openglWarnings.isEmpty()) { lblOpenGLWarnings->setVisible(false); } else { QString text(" "); text.append(i18n("Warning(s):")); text.append("
    "); Q_FOREACH (const QString &warning, openglWarnings) { text.append("
  • "); text.append(warning.toHtmlEscaped()); text.append("
  • "); } text.append("
"); lblOpenGLWarnings->setText(text); lblOpenGLWarnings->setVisible(true); } if (qApp->applicationName() == "kritasketch" || qApp->applicationName() == "kritagemini") { grpOpenGL->setVisible(false); grpOpenGL->setMaximumHeight(0); } KoColor c; c.fromQColor(cfg.selectionOverlayMaskColor()); c.setOpacity(1.0); btnSelectionOverlayColor->setColor(c); sldSelectionOverlayOpacity->setRange(0.0, 1.0, 2); sldSelectionOverlayOpacity->setSingleStep(0.05); sldSelectionOverlayOpacity->setValue(cfg.selectionOverlayMaskColor().alphaF()); intCheckSize->setValue(cfg.checkSize()); chkMoving->setChecked(cfg.scrollCheckers()); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1()); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2()); colorChecks2->setColor(ck2); KoColor cb(KoColorSpaceRegistry::instance()->rgb8()); cb.fromQColor(cfg.canvasBorderColor()); canvasBorder->setColor(cb); hideScrollbars->setChecked(cfg.hideScrollbars()); chkCurveAntialiasing->setChecked(cfg.antialiasCurves()); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline()); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor()); chkHidePopups->setChecked(cfg.hidePopups()); connect(grpOpenGL, SIGNAL(toggled(bool)), SLOT(slotUseOpenGLToggled(bool))); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor()); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold() * 100); } void DisplaySettingsTab::setDefault() { KisConfig cfg; cmbRenderer->setCurrentIndex(0); #ifdef Q_OS_WIN if (!(KisOpenGL::getSupportedOpenGLRenderers() & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererAngle))) { #else if (!KisOpenGL::hasOpenGL()) { #endif grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL(true)); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer(true)); chkUseTextureBuffer->setEnabled(true); chkDisableVsync->setEnabled(true); chkDisableVsync->setChecked(cfg.disableVSync(true)); cmbFilterMode->setEnabled(true); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode(true)); } chkMoving->setChecked(cfg.scrollCheckers(true)); intCheckSize->setValue(cfg.checkSize(true)); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1(true)); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2(true)); colorChecks2->setColor(ck2); KoColor cvb(KoColorSpaceRegistry::instance()->rgb8()); cvb.fromQColor(cfg.canvasBorderColor(true)); canvasBorder->setColor(cvb); hideScrollbars->setChecked(cfg.hideScrollbars(true)); chkCurveAntialiasing->setChecked(cfg.antialiasCurves(true)); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline(true)); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor(true)); chkHidePopups->setChecked(cfg.hidePopups(true)); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor(true)); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold(true) * 100); } void DisplaySettingsTab::slotUseOpenGLToggled(bool isChecked) { chkUseTextureBuffer->setEnabled(isChecked); chkDisableVsync->setEnabled(isChecked); cmbFilterMode->setEnabled(isChecked); } //--------------------------------------------------------------------------------------------------- FullscreenSettingsTab::FullscreenSettingsTab(QWidget* parent) : WdgFullscreenSettingsBase(parent) { KisConfig cfg; chkDockers->setChecked(cfg.hideDockersFullscreen()); chkMenu->setChecked(cfg.hideMenuFullscreen()); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen()); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen()); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen()); chkToolbar->setChecked(cfg.hideToolbarFullscreen()); } void FullscreenSettingsTab::setDefault() { KisConfig cfg; chkDockers->setChecked(cfg.hideDockersFullscreen(true)); chkMenu->setChecked(cfg.hideMenuFullscreen(true)); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen(true)); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen(true)); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen(true)); chkToolbar->setChecked(cfg.hideToolbarFullscreen(true)); } //--------------------------------------------------------------------------------------------------- KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name) : KPageDialog(parent) { Q_UNUSED(name); setWindowTitle(i18n("Configure Krita")); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); button(QDialogButtonBox::Ok)->setDefault(true); setFaceType(KPageDialog::Tree); // General KoVBox *vbox = new KoVBox(); KPageWidgetItem *page = new KPageWidgetItem(vbox, i18n("General")); page->setObjectName("general"); page->setHeader(i18n("General")); page->setIcon(KisIconUtils::loadIcon("go-home")); addPage(page); m_general = new GeneralTab(vbox); // Shortcuts vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Keyboard Shortcuts")); page->setObjectName("shortcuts"); page->setHeader(i18n("Shortcuts")); page->setIcon(KisIconUtils::loadIcon("document-export")); addPage(page); m_shortcutSettings = new ShortcutSettingsTab(vbox); connect(this, SIGNAL(accepted()), m_shortcutSettings, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_shortcutSettings, SLOT(cancelChanges())); // Canvas input settings m_inputConfiguration = new KisInputConfigurationPage(); page = addPage(m_inputConfiguration, i18n("Canvas Input Settings")); page->setHeader(i18n("Canvas Input")); page->setObjectName("canvasinput"); page->setIcon(KisIconUtils::loadIcon("configure")); // Display vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Display")); page->setObjectName("display"); page->setHeader(i18n("Display")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-display")); addPage(page); m_displaySettings = new DisplaySettingsTab(vbox); // Color vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Color Management")); page->setObjectName("colormanagement"); page->setHeader(i18n("Color")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-color")); addPage(page); m_colorSettings = new ColorSettingsTab(vbox); // Performance vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Performance")); page->setObjectName("performance"); page->setHeader(i18n("Performance")); page->setIcon(KisIconUtils::loadIcon("applications-system")); addPage(page); m_performanceSettings = new PerformanceTab(vbox); // Tablet vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Tablet settings")); page->setObjectName("tablet"); page->setHeader(i18n("Tablet")); page->setIcon(KisIconUtils::loadIcon("document-edit")); addPage(page); m_tabletSettings = new TabletSettingsTab(vbox); // full-screen mode vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Canvas-only settings")); page->setObjectName("canvasonly"); page->setHeader(i18n("Canvas-only")); page->setIcon(KisIconUtils::loadIcon("folder-pictures")); addPage(page); m_fullscreenSettings = new FullscreenSettingsTab(vbox); // Author profiles m_authorPage = new KoConfigAuthorPage(); page = addPage(m_authorPage, i18nc("@title:tab Author page", "Author" )); page->setObjectName("author"); page->setHeader(i18n("Author")); page->setIcon(KisIconUtils::loadIcon("im-user")); QPushButton *restoreDefaultsButton = button(QDialogButtonBox::RestoreDefaults); restoreDefaultsButton->setText(i18nc("@action:button", "Restore Defaults")); connect(this, SIGNAL(accepted()), m_inputConfiguration, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_inputConfiguration, SLOT(revertChanges())); KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance(); Q_FOREACH (KisAbstractPreferenceSetFactory *preferenceSetFactory, preferenceSetRegistry->values()) { KisPreferenceSet* preferenceSet = preferenceSetFactory->createPreferenceSet(); vbox = new KoVBox(); page = new KPageWidgetItem(vbox, preferenceSet->name()); page->setHeader(preferenceSet->header()); page->setIcon(preferenceSet->icon()); addPage(page); preferenceSet->setParent(vbox); preferenceSet->loadPreferences(); connect(restoreDefaultsButton, SIGNAL(clicked(bool)), preferenceSet, SLOT(loadDefaultPreferences()), Qt::UniqueConnection); connect(this, SIGNAL(accepted()), preferenceSet, SLOT(savePreferences()), Qt::UniqueConnection); } connect(restoreDefaultsButton, SIGNAL(clicked(bool)), this, SLOT(slotDefault())); } KisDlgPreferences::~KisDlgPreferences() { } void KisDlgPreferences::slotDefault() { if (currentPage()->objectName() == "general") { m_general->setDefault(); } else if (currentPage()->objectName() == "shortcuts") { m_shortcutSettings->setDefault(); } else if (currentPage()->objectName() == "display") { m_displaySettings->setDefault(); } else if (currentPage()->objectName() == "colormanagement") { m_colorSettings->setDefault(); } else if (currentPage()->objectName() == "performance") { m_performanceSettings->load(true); } else if (currentPage()->objectName() == "tablet") { m_tabletSettings->setDefault(); } else if (currentPage()->objectName() == "canvasonly") { m_fullscreenSettings->setDefault(); } else if (currentPage()->objectName() == "canvasinput") { m_inputConfiguration->setDefaults(); } } bool KisDlgPreferences::editPreferences() { KisDlgPreferences* dialog; dialog = new KisDlgPreferences(); bool baccept = (dialog->exec() == Accepted); if (baccept) { // General settings KisConfig cfg; cfg.setNewCursorStyle(dialog->m_general->cursorStyle()); cfg.setNewOutlineStyle(dialog->m_general->outlineStyle()); cfg.setShowRootLayer(dialog->m_general->showRootLayer()); cfg.setShowOutlineWhilePainting(dialog->m_general->showOutlineWhilePainting()); cfg.setForceAlwaysFullSizedOutline(!dialog->m_general->m_changeBrushOutline->isChecked()); cfg.setHideSplashScreen(dialog->m_general->hideSplashScreen()); cfg.setSessionOnStartup(dialog->m_general->sessionOnStartup()); cfg.setSaveSessionOnQuit(dialog->m_general->saveSessionOnQuit()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); group.writeEntry("DontUseNativeFileDialog", !dialog->m_general->m_chkNativeFileDialog->isChecked()); cfg.writeEntry("maximumBrushSize", dialog->m_general->intMaxBrushSize->value()); cfg.writeEntry("mdi_viewmode", dialog->m_general->mdiMode()); cfg.setMDIBackgroundColor(dialog->m_general->m_mdiColor->color().toQColor()); cfg.setMDIBackgroundImage(dialog->m_general->m_backgroundimage->text()); cfg.setAutoSaveInterval(dialog->m_general->autoSaveInterval()); cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("EnableHiDPI", dialog->m_general->m_chkHiDPI->isChecked()); kritarc.setValue("EnableSingleApplication", dialog->m_general->m_chkSingleApplication->isChecked()); cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker()); cfg.setKineticScrollingGesture(dialog->m_general->kineticScrollingGesture()); cfg.setKineticScrollingSensitivity(dialog->m_general->kineticScrollingSensitivity()); cfg.setKineticScrollingScrollbar(dialog->m_general->kineticScrollingScrollbar()); cfg.setSwitchSelectionCtrlAlt(dialog->m_general->switchSelectionCtrlAlt()); cfg.setDisableTouchOnCanvas(!dialog->m_general->chkEnableTouch->isChecked()); cfg.setConvertToImageColorspaceOnImport(dialog->m_general->convertToImageColorspaceOnImport()); cfg.setUndoStackLimit(dialog->m_general->undoStackSize()); cfg.setFavoritePresets(dialog->m_general->favoritePresets()); // Color settings cfg.setUseSystemMonitorProfile(dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()) { int currentIndex = dialog->m_colorSettings->m_monitorProfileWidgets[i]->currentIndex(); QString monitorid = dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemData(currentIndex).toString(); cfg.setMonitorForScreen(i, monitorid); } else { cfg.setMonitorProfile(i, dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemHighlighted(), dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); } } cfg.setWorkingColorSpace(dialog->m_colorSettings->m_page->cmbWorkingColorSpace->currentItem().id()); KisImageConfig cfgImage; cfgImage.setDefaultProofingConfig(dialog->m_colorSettings->m_page->proofingSpaceSelector->currentColorSpace(), dialog->m_colorSettings->m_page->cmbProofingIntent->currentIndex(), dialog->m_colorSettings->m_page->ckbProofBlackPoint->isChecked(), dialog->m_colorSettings->m_page->gamutAlarm->color(), (double)dialog->m_colorSettings->m_page->sldAdaptationState->value()/20); cfg.setUseBlackPointCompensation(dialog->m_colorSettings->m_page->chkBlackpoint->isChecked()); cfg.setAllowLCMSOptimization(dialog->m_colorSettings->m_page->chkAllowLCMSOptimization->isChecked()); cfg.setPasteBehaviour(dialog->m_colorSettings->m_pasteBehaviourGroup.checkedId()); cfg.setRenderIntent(dialog->m_colorSettings->m_page->cmbMonitorIntent->currentIndex()); // Tablet settings cfg.setPressureTabletCurve( dialog->m_tabletSettings->m_page->pressureCurve->curve().toString() ); #ifdef Q_OS_WIN if (KisTabletSupportWin8::isAvailable()) { cfg.setUseWin8PointerInput(dialog->m_tabletSettings->m_page->radioWin8PointerInput->isChecked()); } #endif dialog->m_performanceSettings->save(); #ifdef Q_OS_WIN { KisOpenGL::OpenGLRenderer renderer = static_cast( dialog->m_displaySettings->cmbRenderer->itemData( dialog->m_displaySettings->cmbRenderer->currentIndex()).toInt()); KisOpenGL::setNextUserOpenGLRendererConfig(renderer); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("OpenGLRenderer", KisOpenGL::convertOpenGLRendererToConfig(renderer)); } #endif if (!cfg.useOpenGL() && dialog->m_displaySettings->grpOpenGL->isChecked()) cfg.setCanvasState("TRY_OPENGL"); cfg.setUseOpenGL(dialog->m_displaySettings->grpOpenGL->isChecked()); cfg.setUseOpenGLTextureBuffer(dialog->m_displaySettings->chkUseTextureBuffer->isChecked()); cfg.setOpenGLFilteringMode(dialog->m_displaySettings->cmbFilterMode->currentIndex()); cfg.setDisableVSync(dialog->m_displaySettings->chkDisableVsync->isChecked()); cfg.setCheckSize(dialog->m_displaySettings->intCheckSize->value()); cfg.setScrollingCheckers(dialog->m_displaySettings->chkMoving->isChecked()); cfg.setCheckersColor1(dialog->m_displaySettings->colorChecks1->color().toQColor()); cfg.setCheckersColor2(dialog->m_displaySettings->colorChecks2->color().toQColor()); cfg.setCanvasBorderColor(dialog->m_displaySettings->canvasBorder->color().toQColor()); cfg.setHideScrollbars(dialog->m_displaySettings->hideScrollbars->isChecked()); KoColor c = dialog->m_displaySettings->btnSelectionOverlayColor->color(); c.setOpacity(dialog->m_displaySettings->sldSelectionOverlayOpacity->value()); cfg.setSelectionOverlayMaskColor(c.toQColor()); cfg.setAntialiasCurves(dialog->m_displaySettings->chkCurveAntialiasing->isChecked()); cfg.setAntialiasSelectionOutline(dialog->m_displaySettings->chkSelectionOutlineAntialiasing->isChecked()); cfg.setShowSingleChannelAsColor(dialog->m_displaySettings->chkChannelsAsColor->isChecked()); cfg.setHidePopups(dialog->m_displaySettings->chkHidePopups->isChecked()); cfg.setHideDockersFullscreen(dialog->m_fullscreenSettings->chkDockers->checkState()); cfg.setHideMenuFullscreen(dialog->m_fullscreenSettings->chkMenu->checkState()); cfg.setHideScrollbarsFullscreen(dialog->m_fullscreenSettings->chkScrollbars->checkState()); cfg.setHideStatusbarFullscreen(dialog->m_fullscreenSettings->chkStatusbar->checkState()); cfg.setHideTitlebarFullscreen(dialog->m_fullscreenSettings->chkTitlebar->checkState()); cfg.setHideToolbarFullscreen(dialog->m_fullscreenSettings->chkToolbar->checkState()); cfg.setCursorMainColor(dialog->m_general->cursorColorBtutton->color().toQColor()); cfg.setPixelGridColor(dialog->m_displaySettings->pixelGridColorButton->color().toQColor()); cfg.setPixelGridDrawingThreshold(dialog->m_displaySettings->pixelGridDrawingThresholdBox->value() / 100); dialog->m_authorPage->apply(); } delete dialog; return baccept; } diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc index 50ad23521c..505908e629 100644 --- a/libs/ui/kis_config.cc +++ b/libs/ui/kis_config.cc @@ -1,2013 +1,2003 @@ /* * Copyright (c) 2002 Patrick Julien * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_canvas_resource_provider.h" #include "kis_config_notifier.h" #include "kis_snap_config.h" #include #include 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); } int KisConfig::preferredVectorImportResolutionPPI(bool defaultValue) const { return defaultValue ? 100.0 : m_cfg.readEntry("preferredVectorImportResolution", 100.0); } void KisConfig::setPreferredVectorImportResolutionPPI(int value) const { m_cfg.writeEntry("preferredVectorImportResolution", value); } void cleanOldCursorStyleKeys(KConfigGroup &cfg) { if (cfg.hasKey("newCursorStyle") && cfg.hasKey("newOutlineStyle")) { cfg.deleteEntry("cursorStyleDef"); } } CursorStyle KisConfig::newCursorStyle(bool defaultValue) const { if (defaultValue) { return CURSOR_STYLE_NO_CURSOR; } int style = m_cfg.readEntry("newCursorStyle", int(-1)); if (style < 0) { // old style format style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE)); switch (style) { case OLD_CURSOR_STYLE_TOOLICON: style = CURSOR_STYLE_TOOLICON; break; case OLD_CURSOR_STYLE_CROSSHAIR: case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS: style = CURSOR_STYLE_CROSSHAIR; break; case OLD_CURSOR_STYLE_POINTER: style = CURSOR_STYLE_POINTER; break; case OLD_CURSOR_STYLE_OUTLINE: case OLD_CURSOR_STYLE_NO_CURSOR: style = CURSOR_STYLE_NO_CURSOR; break; case OLD_CURSOR_STYLE_SMALL_ROUND: case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT: style = CURSOR_STYLE_SMALL_ROUND; break; case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED: case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED: style = CURSOR_STYLE_TRIANGLE_RIGHTHANDED; break; case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED: case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED: style = CURSOR_STYLE_TRIANGLE_LEFTHANDED; break; default: style = -1; } } cleanOldCursorStyleKeys(m_cfg); // compatibility with future versions if (style < 0 || style >= N_CURSOR_STYLE_SIZE) { style = CURSOR_STYLE_NO_CURSOR; } return (CursorStyle) style; } void KisConfig::setNewCursorStyle(CursorStyle style) { m_cfg.writeEntry("newCursorStyle", (int)style); } QColor KisConfig::getCursorMainColor(bool defaultValue) const { QColor col; col.setRgbF(0.501961, 1.0, 0.501961); return (defaultValue ? col : m_cfg.readEntry("cursorMaincColor", col)); } void KisConfig::setCursorMainColor(const QColor &v) const { m_cfg.writeEntry("cursorMaincColor", v); } OutlineStyle KisConfig::newOutlineStyle(bool defaultValue) const { if (defaultValue) { return OUTLINE_FULL; } int style = m_cfg.readEntry("newOutlineStyle", int(-1)); if (style < 0) { // old style format style = m_cfg.readEntry("cursorStyleDef", int(OLD_CURSOR_STYLE_OUTLINE)); switch (style) { case OLD_CURSOR_STYLE_TOOLICON: case OLD_CURSOR_STYLE_CROSSHAIR: case OLD_CURSOR_STYLE_POINTER: case OLD_CURSOR_STYLE_NO_CURSOR: case OLD_CURSOR_STYLE_SMALL_ROUND: case OLD_CURSOR_STYLE_TRIANGLE_RIGHTHANDED: case OLD_CURSOR_STYLE_TRIANGLE_LEFTHANDED: style = OUTLINE_NONE; break; case OLD_CURSOR_STYLE_OUTLINE: case OLD_CURSOR_STYLE_OUTLINE_CENTER_DOT: case OLD_CURSOR_STYLE_OUTLINE_CENTER_CROSS: case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_RIGHTHANDED: case OLD_CURSOR_STYLE_OUTLINE_TRIANGLE_LEFTHANDED: style = OUTLINE_FULL; break; default: style = -1; } } cleanOldCursorStyleKeys(m_cfg); // compatibility with future versions if (style < 0 || style >= N_OUTLINE_STYLE_SIZE) { style = OUTLINE_FULL; } return (OutlineStyle) style; } void KisConfig::setNewOutlineStyle(OutlineStyle style) { m_cfg.writeEntry("newOutlineStyle", (int)style); } QRect KisConfig::colorPreviewRect() const { return m_cfg.readEntry("colorPreviewRect", QVariant(QRect(32, 32, 48, 48))).toRect(); } void KisConfig::setColorPreviewRect(const QRect &rect) { m_cfg.writeEntry("colorPreviewRect", QVariant(rect)); } bool KisConfig::useDirtyPresets(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("useDirtyPresets",false)); } void KisConfig::setUseDirtyPresets(bool value) { m_cfg.writeEntry("useDirtyPresets",value); KisConfigNotifier::instance()->notifyConfigChanged(); } bool KisConfig::useEraserBrushSize(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("useEraserBrushSize",false)); } void KisConfig::setUseEraserBrushSize(bool value) { m_cfg.writeEntry("useEraserBrushSize",value); KisConfigNotifier::instance()->notifyConfigChanged(); } bool KisConfig::useEraserBrushOpacity(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("useEraserBrushOpacity",false)); } void KisConfig::setUseEraserBrushOpacity(bool value) { m_cfg.writeEntry("useEraserBrushOpacity",value); KisConfigNotifier::instance()->notifyConfigChanged(); } QColor KisConfig::getMDIBackgroundColor(bool defaultValue) const { QColor col(77, 77, 77); return (defaultValue ? col : m_cfg.readEntry("mdiBackgroundColor", col)); } void KisConfig::setMDIBackgroundColor(const QColor &v) const { m_cfg.writeEntry("mdiBackgroundColor", v); } QString KisConfig::getMDIBackgroundImage(bool defaultValue) const { return (defaultValue ? "" : m_cfg.readEntry("mdiBackgroundImage", "")); } void KisConfig::setMDIBackgroundImage(const QString &filename) const { m_cfg.writeEntry("mdiBackgroundImage", filename); } QString KisConfig::monitorProfile(int screen) const { // Note: keep this in sync with the default profile for the RGB colorspaces! QString profile = m_cfg.readEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), "sRGB-elle-V2-srgbtrc.icc"); //dbgKrita << "KisConfig::monitorProfile()" << profile; return profile; } QString KisConfig::monitorForScreen(int screen, const QString &defaultMonitor, bool defaultValue) const { return (defaultValue ? defaultMonitor : m_cfg.readEntry(QString("monitor_for_screen_%1").arg(screen), defaultMonitor)); } void KisConfig::setMonitorForScreen(int screen, const QString& monitor) { m_cfg.writeEntry(QString("monitor_for_screen_%1").arg(screen), monitor); } void KisConfig::setMonitorProfile(int screen, const QString & monitorProfile, bool override) const { m_cfg.writeEntry("monitorProfile/OverrideX11", override); m_cfg.writeEntry("monitorProfile" + QString(screen == 0 ? "": QString("_%1").arg(screen)), monitorProfile); } const KoColorProfile *KisConfig::getScreenProfile(int screen) { if (screen < 0) return 0; KisConfig cfg; 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::forceShowSaveMessages(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("forceShowSaveMessages", false)); } void KisConfig::setForceShowSaveMessages(bool value) const { m_cfg.writeEntry("forceShowSaveMessages", value); } bool KisConfig::forceShowAutosaveMessages(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("forceShowAutosaveMessages", false)); } void KisConfig::setForceShowAutosaveMessages(bool value) const { m_cfg.writeEntry("forceShowAutosaveMessages", value); } bool KisConfig::rulersTrackMouse(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("rulersTrackMouse", true)); } void KisConfig::setRulersTrackMouse(bool value) const { m_cfg.writeEntry("rulersTrackMouse", value); } qint32 KisConfig::pasteBehaviour(bool defaultValue) const { return (defaultValue ? 2 : m_cfg.readEntry("pasteBehaviour", 2)); } void KisConfig::setPasteBehaviour(qint32 renderIntent) const { m_cfg.writeEntry("pasteBehaviour", renderIntent); } qint32 KisConfig::monitorRenderIntent(bool defaultValue) const { qint32 intent = m_cfg.readEntry("renderIntent", INTENT_PERCEPTUAL); if (intent > 3) intent = 3; if (intent < 0) intent = 0; return (defaultValue ? INTENT_PERCEPTUAL : intent); } void KisConfig::setRenderIntent(qint32 renderIntent) const { if (renderIntent > 3) renderIntent = 3; if (renderIntent < 0) renderIntent = 0; m_cfg.writeEntry("renderIntent", renderIntent); } bool KisConfig::useOpenGL(bool defaultValue) const { if (defaultValue) { return true; } //dbgKrita << "use opengl" << m_cfg.readEntry("useOpenGL", true) << "success" << m_cfg.readEntry("canvasState", "OPENGL_SUCCESS"); QString cs = canvasState(); #ifdef Q_OS_WIN return (m_cfg.readEntry("useOpenGLWindows", true) && (cs == "OPENGL_SUCCESS" || cs == "TRY_OPENGL")); #else return (m_cfg.readEntry("useOpenGL", true) && (cs == "OPENGL_SUCCESS" || cs == "TRY_OPENGL")); #endif } void KisConfig::setUseOpenGL(bool useOpenGL) const { #ifdef Q_OS_WIN m_cfg.writeEntry("useOpenGLWindows", useOpenGL); #else m_cfg.writeEntry("useOpenGL", useOpenGL); #endif } int KisConfig::openGLFilteringMode(bool defaultValue) const { return (defaultValue ? 3 : m_cfg.readEntry("OpenGLFilterMode", 3)); } void KisConfig::setOpenGLFilteringMode(int filteringMode) { m_cfg.writeEntry("OpenGLFilterMode", filteringMode); } bool KisConfig::useOpenGLTextureBuffer(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("useOpenGLTextureBuffer", true)); } void KisConfig::setUseOpenGLTextureBuffer(bool useBuffer) { m_cfg.writeEntry("useOpenGLTextureBuffer", useBuffer); } int KisConfig::openGLTextureSize(bool defaultValue) const { return (defaultValue ? 256 : m_cfg.readEntry("textureSize", 256)); } bool KisConfig::disableVSync(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("disableVSync", true)); } void KisConfig::setDisableVSync(bool disableVSync) { m_cfg.writeEntry("disableVSync", disableVSync); } bool KisConfig::showAdvancedOpenGLSettings(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("showAdvancedOpenGLSettings", false)); } bool KisConfig::forceOpenGLFenceWorkaround(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("forceOpenGLFenceWorkaround", false)); } int KisConfig::numMipmapLevels(bool defaultValue) const { return (defaultValue ? 4 : m_cfg.readEntry("numMipmapLevels", 4)); } int KisConfig::textureOverlapBorder() const { return 1 << qMax(0, numMipmapLevels()); } quint32 KisConfig::getGridMainStyle(bool defaultValue) const { int v = m_cfg.readEntry("gridmainstyle", 0); v = qBound(0, v, 2); return (defaultValue ? 0 : v); } void KisConfig::setGridMainStyle(quint32 v) const { m_cfg.writeEntry("gridmainstyle", v); } quint32 KisConfig::getGridSubdivisionStyle(bool defaultValue) const { quint32 v = m_cfg.readEntry("gridsubdivisionstyle", 1); if (v > 2) v = 2; return (defaultValue ? 1 : v); } void KisConfig::setGridSubdivisionStyle(quint32 v) const { m_cfg.writeEntry("gridsubdivisionstyle", v); } QColor KisConfig::getGridMainColor(bool defaultValue) const { QColor col(99, 99, 99); return (defaultValue ? col : m_cfg.readEntry("gridmaincolor", col)); } void KisConfig::setGridMainColor(const QColor & v) const { m_cfg.writeEntry("gridmaincolor", v); } QColor KisConfig::getGridSubdivisionColor(bool defaultValue) const { QColor col(150, 150, 150); return (defaultValue ? col : m_cfg.readEntry("gridsubdivisioncolor", col)); } void KisConfig::setGridSubdivisionColor(const QColor & v) const { m_cfg.writeEntry("gridsubdivisioncolor", v); } QColor KisConfig::getPixelGridColor(bool defaultValue) const { QColor col(255, 255, 255); return (defaultValue ? col : m_cfg.readEntry("pixelGridColor", col)); } void KisConfig::setPixelGridColor(const QColor & v) const { m_cfg.writeEntry("pixelGridColor", v); } qreal KisConfig::getPixelGridDrawingThreshold(bool defaultValue) const { qreal border = 24.0f; return (defaultValue ? border : m_cfg.readEntry("pixelGridDrawingThreshold", border)); } void KisConfig::setPixelGridDrawingThreshold(qreal v) const { m_cfg.writeEntry("pixelGridDrawingThreshold", v); } bool KisConfig::pixelGridEnabled(bool defaultValue) const { bool enabled = true; return (defaultValue ? enabled : m_cfg.readEntry("pixelGridEnabled", enabled)); } void KisConfig::enablePixelGrid(bool v) const { m_cfg.writeEntry("pixelGridEnabled", v); } quint32 KisConfig::guidesLineStyle(bool defaultValue) const { int v = m_cfg.readEntry("guidesLineStyle", 0); v = qBound(0, v, 2); return (defaultValue ? 0 : v); } void KisConfig::setGuidesLineStyle(quint32 v) const { m_cfg.writeEntry("guidesLineStyle", v); } QColor KisConfig::guidesColor(bool defaultValue) const { QColor col(99, 99, 99); return (defaultValue ? col : m_cfg.readEntry("guidesColor", col)); } void KisConfig::setGuidesColor(const QColor & v) const { m_cfg.writeEntry("guidesColor", v); } void KisConfig::loadSnapConfig(KisSnapConfig *config, bool defaultValue) const { KisSnapConfig defaultConfig(false); if (defaultValue) { *config = defaultConfig; return; } config->setOrthogonal(m_cfg.readEntry("globalSnapOrthogonal", defaultConfig.orthogonal())); config->setNode(m_cfg.readEntry("globalSnapNode", defaultConfig.node())); config->setExtension(m_cfg.readEntry("globalSnapExtension", defaultConfig.extension())); config->setIntersection(m_cfg.readEntry("globalSnapIntersection", defaultConfig.intersection())); config->setBoundingBox(m_cfg.readEntry("globalSnapBoundingBox", defaultConfig.boundingBox())); config->setImageBounds(m_cfg.readEntry("globalSnapImageBounds", defaultConfig.imageBounds())); config->setImageCenter(m_cfg.readEntry("globalSnapImageCenter", defaultConfig.imageCenter())); } 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::forceAlwaysFullSizedOutline(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("forceAlwaysFullSizedOutline", false)); } void KisConfig::setForceAlwaysFullSizedOutline(bool value) const { m_cfg.writeEntry("forceAlwaysFullSizedOutline", value); } 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); } KisConfig::SessionOnStartup KisConfig::sessionOnStartup(bool defaultValue) const { int value = defaultValue ? SOS_BlankSession : m_cfg.readEntry("sessionOnStartup", (int)SOS_BlankSession); return (KisConfig::SessionOnStartup)value; } void KisConfig::setSessionOnStartup(SessionOnStartup value) { m_cfg.writeEntry("sessionOnStartup", (int)value); } bool KisConfig::saveSessionOnQuit(bool defaultValue) const { return defaultValue ? false : m_cfg.readEntry("saveSessionOnQuit", false); } void KisConfig::setSaveSessionOnQuit(bool value) { m_cfg.writeEntry("saveSessionOnQuit", value); } qreal KisConfig::outlineSizeMinimum(bool defaultValue) const { return (defaultValue ? 1.0 : m_cfg.readEntry("OutlineSizeMinimum", 1.0)); } void KisConfig::setOutlineSizeMinimum(qreal outlineSizeMinimum) const { m_cfg.writeEntry("OutlineSizeMinimum", outlineSizeMinimum); } qreal KisConfig::selectionViewSizeMinimum(bool defaultValue) const { return (defaultValue ? 5.0 : m_cfg.readEntry("SelectionViewSizeMinimum", 5.0)); } void KisConfig::setSelectionViewSizeMinimum(qreal outlineSizeMinimum) const { m_cfg.writeEntry("SelectionViewSizeMinimum", outlineSizeMinimum); } int KisConfig::autoSaveInterval(bool defaultValue) const { return (defaultValue ? 15 * 60 : m_cfg.readEntry("AutoSaveInterval", 15 * 60)); } void KisConfig::setAutoSaveInterval(int seconds) const { return m_cfg.writeEntry("AutoSaveInterval", seconds); } bool KisConfig::backupFile(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("CreateBackupFile", true)); } void KisConfig::setBackupFile(bool backupFile) const { m_cfg.writeEntry("CreateBackupFile", backupFile); } bool KisConfig::showFilterGallery(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("showFilterGallery", false)); } void KisConfig::setShowFilterGallery(bool showFilterGallery) const { m_cfg.writeEntry("showFilterGallery", showFilterGallery); } bool KisConfig::showFilterGalleryLayerMaskDialog(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("showFilterGalleryLayerMaskDialog", true)); } void KisConfig::setShowFilterGalleryLayerMaskDialog(bool showFilterGallery) const { m_cfg.writeEntry("setShowFilterGalleryLayerMaskDialog", showFilterGallery); } QString KisConfig::canvasState(bool defaultValue) const { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); return (defaultValue ? "OPENGL_NOT_TRIED" : kritarc.value("canvasState", "OPENGL_NOT_TRIED").toString()); } void KisConfig::setCanvasState(const QString& state) const { static QStringList acceptableStates; if (acceptableStates.isEmpty()) { acceptableStates << "OPENGL_SUCCESS" << "TRY_OPENGL" << "OPENGL_NOT_TRIED" << "OPENGL_FAILED"; } if (acceptableStates.contains(state)) { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("canvasState", state); } } bool KisConfig::toolOptionsPopupDetached(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("ToolOptionsPopupDetached", false)); } void KisConfig::setToolOptionsPopupDetached(bool detached) const { m_cfg.writeEntry("ToolOptionsPopupDetached", detached); } bool KisConfig::paintopPopupDetached(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("PaintopPopupDetached", false)); } void KisConfig::setPaintopPopupDetached(bool detached) const { m_cfg.writeEntry("PaintopPopupDetached", detached); } QString KisConfig::pressureTabletCurve(bool defaultValue) const { return (defaultValue ? "0,0;1,1" : m_cfg.readEntry("tabletPressureCurve","0,0;1,1;")); } void KisConfig::setPressureTabletCurve(const QString& curveString) const { m_cfg.writeEntry("tabletPressureCurve", curveString); } bool KisConfig::useWin8PointerInput(bool defaultValue) const { #ifdef Q_OS_WIN return (defaultValue ? false : m_cfg.readEntry("useWin8PointerInput", false)); #else Q_UNUSED(defaultValue); return false; #endif } void KisConfig::setUseWin8PointerInput(bool value) const { #ifdef Q_OS_WIN // Special handling: Only set value if changed // I don't want it to be set if the user hasn't touched it if (useWin8PointerInput() != value) { m_cfg.writeEntry("useWin8PointerInput", value); } #else Q_UNUSED(value) #endif } qreal KisConfig::vastScrolling(bool defaultValue) const { return (defaultValue ? 0.9 : m_cfg.readEntry("vastScrolling", 0.9)); } void KisConfig::setVastScrolling(const qreal factor) const { m_cfg.writeEntry("vastScrolling", factor); } int KisConfig::presetChooserViewMode(bool defaultValue) const { return (defaultValue ? 0 : m_cfg.readEntry("presetChooserViewMode", 0)); } void KisConfig::setPresetChooserViewMode(const int mode) const { m_cfg.writeEntry("presetChooserViewMode", mode); } int KisConfig::presetIconSize(bool defaultValue) const { return (defaultValue ? 60 : m_cfg.readEntry("presetIconSize", 60)); } void KisConfig::setPresetIconSize(const int value) const { m_cfg.writeEntry("presetIconSize", value); } bool KisConfig::firstRun(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("firstRun", true)); } void KisConfig::setFirstRun(const bool first) const { m_cfg.writeEntry("firstRun", first); } int KisConfig::horizontalSplitLines(bool defaultValue) const { return (defaultValue ? 1 : m_cfg.readEntry("horizontalSplitLines", 1)); } void KisConfig::setHorizontalSplitLines(const int numberLines) const { m_cfg.writeEntry("horizontalSplitLines", numberLines); } int KisConfig::verticalSplitLines(bool defaultValue) const { return (defaultValue ? 1 : m_cfg.readEntry("verticalSplitLines", 1)); } void KisConfig::setVerticalSplitLines(const int numberLines) const { m_cfg.writeEntry("verticalSplitLines", numberLines); } bool KisConfig::clicklessSpacePan(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("clicklessSpacePan", true)); } void KisConfig::setClicklessSpacePan(const bool toggle) const { m_cfg.writeEntry("clicklessSpacePan", toggle); } bool KisConfig::hideDockersFullscreen(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("hideDockersFullScreen", true)); } void KisConfig::setHideDockersFullscreen(const bool value) const { m_cfg.writeEntry("hideDockersFullScreen", value); } bool KisConfig::showDockers(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("showDockers", true)); } void KisConfig::setShowDockers(const bool value) const { m_cfg.writeEntry("showDockers", value); } bool KisConfig::showStatusBar(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("showStatusBar", true)); } void KisConfig::setShowStatusBar(const bool value) const { m_cfg.writeEntry("showStatusBar", value); } bool KisConfig::hideMenuFullscreen(bool defaultValue) const { return (defaultValue ? true: m_cfg.readEntry("hideMenuFullScreen", true)); } void KisConfig::setHideMenuFullscreen(const bool value) const { m_cfg.writeEntry("hideMenuFullScreen", value); } bool KisConfig::hideScrollbarsFullscreen(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("hideScrollbarsFullScreen", true)); } void KisConfig::setHideScrollbarsFullscreen(const bool value) const { m_cfg.writeEntry("hideScrollbarsFullScreen", value); } bool KisConfig::hideStatusbarFullscreen(bool defaultValue) const { return (defaultValue ? true: m_cfg.readEntry("hideStatusbarFullScreen", true)); } void KisConfig::setHideStatusbarFullscreen(const bool value) const { m_cfg.writeEntry("hideStatusbarFullScreen", value); } bool KisConfig::hideTitlebarFullscreen(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("hideTitleBarFullscreen", true)); } void KisConfig::setHideTitlebarFullscreen(const bool value) const { m_cfg.writeEntry("hideTitleBarFullscreen", value); } bool KisConfig::hideToolbarFullscreen(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("hideToolbarFullscreen", true)); } void KisConfig::setHideToolbarFullscreen(const bool value) const { m_cfg.writeEntry("hideToolbarFullscreen", value); } bool KisConfig::fullscreenMode(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("fullscreenMode", true)); } void KisConfig::setFullscreenMode(const bool value) const { m_cfg.writeEntry("fullscreenMode", value); } QStringList KisConfig::favoriteCompositeOps(bool defaultValue) const { return (defaultValue ? QStringList() : m_cfg.readEntry("favoriteCompositeOps", QStringList())); } void KisConfig::setFavoriteCompositeOps(const QStringList& compositeOps) const { m_cfg.writeEntry("favoriteCompositeOps", compositeOps); } QString KisConfig::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); } QString KisConfig::importConfiguration(const QString &filterId, bool defaultValue) const { return (defaultValue ? QString() : m_cfg.readEntry("ImportConfiguration-" + filterId, QString())); } void KisConfig::setImportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const { QString importConfig = properties->toXML(); m_cfg.writeEntry("ImportConfiguration-" + filterId, importConfig); } bool KisConfig::useOcio(bool defaultValue) const { #ifdef HAVE_OCIO return (defaultValue ? false : m_cfg.readEntry("Krita/Ocio/UseOcio", false)); #else Q_UNUSED(defaultValue); return false; #endif } void KisConfig::setUseOcio(bool useOCIO) const { m_cfg.writeEntry("Krita/Ocio/UseOcio", useOCIO); } int KisConfig::favoritePresets(bool defaultValue) const { return (defaultValue ? 10 : m_cfg.readEntry("numFavoritePresets", 10)); } void KisConfig::setFavoritePresets(const int value) { m_cfg.writeEntry("numFavoritePresets", value); } bool KisConfig::levelOfDetailEnabled(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("levelOfDetailEnabled", false)); } void KisConfig::setLevelOfDetailEnabled(bool value) { m_cfg.writeEntry("levelOfDetailEnabled", value); } 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", "Default")); } void KisConfig::setDefaultPalette(const QString& name) const { m_cfg.writeEntry("defaultPalette", name); } QString KisConfig::toolbarSlider(int sliderNumber, bool defaultValue) const { QString def = "flow"; if (sliderNumber == 1) { def = "opacity"; } if (sliderNumber == 2) { def = "size"; } return (defaultValue ? def : m_cfg.readEntry(QString("toolbarslider_%1").arg(sliderNumber), def)); } void KisConfig::setToolbarSlider(int sliderNumber, const QString &slider) { m_cfg.writeEntry(QString("toolbarslider_%1").arg(sliderNumber), slider); } 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::trackTabletEventLatency(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("trackTabletEventLatency", false)); } void KisConfig::setTrackTabletEventLatency(bool value) { m_cfg.writeEntry("trackTabletEventLatency", value); } bool KisConfig::testingAcceptCompressedTabletEvents(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("testingAcceptCompressedTabletEvents", false)); } void KisConfig::setTestingAcceptCompressedTabletEvents(bool value) { m_cfg.writeEntry("testingAcceptCompressedTabletEvents", value); } bool KisConfig::shouldEatDriverShortcuts(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("shouldEatDriverShortcuts", false)); } bool KisConfig::testingCompressBrushEvents(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("testingCompressBrushEvents", false)); } void KisConfig::setTestingCompressBrushEvents(bool value) { m_cfg.writeEntry("testingCompressBrushEvents", value); } int KisConfig::workaroundX11SmoothPressureSteps(bool defaultValue) const { return (defaultValue ? 0 : m_cfg.readEntry("workaroundX11SmoothPressureSteps", 0)); } bool KisConfig::showCanvasMessages(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("showOnCanvasMessages", true)); } void KisConfig::setShowCanvasMessages(bool show) { m_cfg.writeEntry("showOnCanvasMessages", show); } bool KisConfig::compressKra(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("compressLayersInKra", false)); } void KisConfig::setCompressKra(bool compress) { m_cfg.writeEntry("compressLayersInKra", compress); } bool KisConfig::toolOptionsInDocker(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("ToolOptionsInDocker", true)); } void KisConfig::setToolOptionsInDocker(bool inDocker) { m_cfg.writeEntry("ToolOptionsInDocker", inDocker); } int KisConfig::kineticScrollingGesture(bool defaultValue) const { return (defaultValue ? 0 : m_cfg.readEntry("KineticScrollingGesture", 0)); } void KisConfig::setKineticScrollingGesture(int gesture) { m_cfg.writeEntry("KineticScrollingGesture", gesture); } int KisConfig::kineticScrollingSensitivity(bool defaultValue) const { return (defaultValue ? 75 : m_cfg.readEntry("KineticScrollingSensitivity", 75)); } void KisConfig::setKineticScrollingSensitivity(int sensitivity) { m_cfg.writeEntry("KineticScrollingSensitivity", sensitivity); } bool KisConfig::kineticScrollingScrollbar(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("KineticScrollingScrollbar", true)); } void KisConfig::setKineticScrollingScrollbar(bool scrollbar) { m_cfg.writeEntry("KineticScrollingScrollbar", scrollbar); } const KoColorSpace* KisConfig::customColorSelectorColorSpace(bool defaultValue) const { const KoColorSpace *cs = 0; KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); if (defaultValue || cfg.readEntry("useCustomColorSpace", true)) { KoColorSpaceRegistry* csr = KoColorSpaceRegistry::instance(); QString modelID = cfg.readEntry("customColorSpaceModel", "RGBA"); QString depthID = cfg.readEntry("customColorSpaceDepthID", "U8"); QString profile = cfg.readEntry("customColorSpaceProfile", "sRGB built-in - (lcms internal)"); if (profile == "default") { // qDebug() << "Falling back to default color profile."; profile = "sRGB built-in - (lcms internal)"; } cs = csr->colorSpace(modelID, depthID, profile); } return cs; } void KisConfig::setCustomColorSelectorColorSpace(const KoColorSpace *cs) { KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); cfg.writeEntry("useCustomColorSpace", bool(cs)); if(cs) { cfg.writeEntry("customColorSpaceModel", cs->colorModelId().id()); cfg.writeEntry("customColorSpaceDepthID", cs->colorDepthId().id()); cfg.writeEntry("customColorSpaceProfile", cs->profile()->name()); } KisConfigNotifier::instance()->notifyConfigChanged(); } bool KisConfig::enableOpenGLFramerateLogging(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("enableOpenGLFramerateLogging", false)); } void KisConfig::setEnableOpenGLFramerateLogging(bool value) const { m_cfg.writeEntry("enableOpenGLFramerateLogging", value); } bool KisConfig::enableBrushSpeedLogging(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("enableBrushSpeedLogging", false)); } void KisConfig::setEnableBrushSpeedLogging(bool value) const { m_cfg.writeEntry("enableBrushSpeedLogging", value); } void KisConfig::setEnableAmdVectorizationWorkaround(bool value) { m_cfg.writeEntry("amdDisableVectorWorkaround", value); } bool KisConfig::enableAmdVectorizationWorkaround(bool defaultValue) const { return (defaultValue ? false : m_cfg.readEntry("amdDisableVectorWorkaround", false)); } void KisConfig::setAnimationDropFrames(bool value) { bool oldValue = animationDropFrames(); if (value == oldValue) return; m_cfg.writeEntry("animationDropFrames", value); KisConfigNotifier::instance()->notifyDropFramesModeChanged(); } bool KisConfig::animationDropFrames(bool defaultValue) const { return (defaultValue ? true : m_cfg.readEntry("animationDropFrames", true)); } int KisConfig::scrubbingUpdatesDelay(bool defaultValue) const { return (defaultValue ? 30 : m_cfg.readEntry("scrubbingUpdatesDelay", 30)); } void KisConfig::setScrubbingUpdatesDelay(int value) { m_cfg.writeEntry("scrubbingUpdatesDelay", value); } int KisConfig::scrubbingAudioUpdatesDelay(bool defaultValue) const { return (defaultValue ? -1 : m_cfg.readEntry("scrubbingAudioUpdatesDelay", -1)); } void KisConfig::setScrubbingAudioUpdatesDelay(int value) { m_cfg.writeEntry("scrubbingAudioUpdatesDelay", value); } int KisConfig::audioOffsetTolerance(bool defaultValue) const { return (defaultValue ? -1 : m_cfg.readEntry("audioOffsetTolerance", -1)); } void KisConfig::setAudioOffsetTolerance(int value) { m_cfg.writeEntry("audioOffsetTolerance", value); } bool KisConfig::switchSelectionCtrlAlt(bool defaultValue) const { return defaultValue ? false : m_cfg.readEntry("switchSelectionCtrlAlt", false); } void KisConfig::setSwitchSelectionCtrlAlt(bool value) { m_cfg.writeEntry("switchSelectionCtrlAlt", value); KisConfigNotifier::instance()->notifyConfigChanged(); } bool KisConfig::convertToImageColorspaceOnImport(bool defaultValue) const { return defaultValue ? false : m_cfg.readEntry("ConvertToImageColorSpaceOnImport", false); } void KisConfig::setConvertToImageColorspaceOnImport(bool value) { m_cfg.writeEntry("ConvertToImageColorSpaceOnImport", value); } int KisConfig::stabilizerSampleSize(bool defaultValue) const { #ifdef Q_OS_WIN const int defaultSampleSize = 50; #else const int defaultSampleSize = 15; #endif return defaultValue ? defaultSampleSize : m_cfg.readEntry("stabilizerSampleSize", defaultSampleSize); } void KisConfig::setStabilizerSampleSize(int value) { m_cfg.writeEntry("stabilizerSampleSize", value); } bool KisConfig::stabilizerDelayedPaint(bool defaultValue) const { const bool defaultEnabled = true; return defaultValue ? defaultEnabled : m_cfg.readEntry("stabilizerDelayedPaint", defaultEnabled); } void KisConfig::setStabilizerDelayedPaint(bool value) { m_cfg.writeEntry("stabilizerDelayedPaint", value); } 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"; return defaultValue ? defaultDoc : m_cfg.readEntry("brushHudSettings", defaultDoc); } void KisConfig::setBrushHudSetting(const QString &value) const { m_cfg.writeEntry("brushHudSettings", value); } bool KisConfig::calculateAnimationCacheInBackground(bool defaultValue) const { return defaultValue ? true : m_cfg.readEntry("calculateAnimationCacheInBackground", true); } void KisConfig::setCalculateAnimationCacheInBackground(bool value) { m_cfg.writeEntry("calculateAnimationCacheInBackground", value); } QColor KisConfig::defaultAssistantsColor(bool defaultValue) const { static const QColor defaultColor = QColor(176, 176, 176, 255); return defaultValue ? defaultColor : m_cfg.readEntry("defaultAssistantsColor", defaultColor); } void KisConfig::setDefaultAssistantsColor(const QColor &color) const { m_cfg.writeEntry("defaultAssistantsColor", color); } #include #include void KisConfig::writeKoColor(const QString& name, const KoColor& color) const { QDomDocument doc = QDomDocument(name); QDomElement el = doc.createElement(name); doc.appendChild(el); color.toXML(doc, el); m_cfg.writeEntry(name, doc.toString()); } //ported from kispropertiesconfig. KoColor KisConfig::readKoColor(const QString& name, const KoColor& color) const { QDomDocument doc; if (!m_cfg.readEntry(name).isNull()) { doc.setContent(m_cfg.readEntry(name)); QDomElement e = doc.documentElement().firstChild().toElement(); return KoColor::fromXML(e, Integer16BitsColorDepthID.id()); } else { QString blackColor = "\n\n \n\n"; doc.setContent(blackColor); QDomElement e = doc.documentElement().firstChild().toElement(); return KoColor::fromXML(e, Integer16BitsColorDepthID.id()); } return color; } diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h index db655e5d76..7f3aeb1977 100644 --- a/libs/ui/kis_config.h +++ b/libs/ui/kis_config.h @@ -1,600 +1,597 @@ /* * 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; int preferredVectorImportResolutionPPI(bool defaultValue = false) const; void setPreferredVectorImportResolutionPPI(int value) 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); QColor getCursorMainColor(bool defaultValue = false) const; void setCursorMainColor(const QColor& v) const; 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 forceShowSaveMessages(bool defaultValue = true) const; void setForceShowSaveMessages(bool value) const; bool forceShowAutosaveMessages(bool defaultValue = true) const; void setForceShowAutosaveMessages(bool ShowAutosaveMessages) 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; 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; QColor getPixelGridColor(bool defaultValue = false) const; void setPixelGridColor(const QColor & v) const; qreal getPixelGridDrawingThreshold(bool defaultValue = false) const; void setPixelGridDrawingThreshold(qreal v) const; bool pixelGridEnabled(bool defaultValue = false) const; void enablePixelGrid(bool 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 forceAlwaysFullSizedOutline(bool defaultValue = false) const; void setForceAlwaysFullSizedOutline(bool value) const; bool hideSplashScreen(bool defaultValue = false) const; void setHideSplashScreen(bool hideSplashScreen) const; enum SessionOnStartup { SOS_BlankSession, SOS_PreviousSession, SOS_ShowSessionManager }; SessionOnStartup sessionOnStartup(bool defaultValue = false) const; void setSessionOnStartup(SessionOnStartup value); bool saveSessionOnQuit(bool defaultValue) const; void setSaveSessionOnQuit(bool value); 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; bool useWin8PointerInput(bool defaultValue = false) const; void setUseWin8PointerInput(bool value) 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 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; QString importConfiguration(const QString &filterId, bool defaultValue = false) const; void setImportConfiguration(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 trackTabletEventLatency(bool defaultValue = false) const; void setTrackTabletEventLatency(bool 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; 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); int kineticScrollingGesture(bool defaultValue = false) const; void setKineticScrollingGesture(int kineticScroll); int kineticScrollingSensitivity(bool defaultValue = false) const; void setKineticScrollingSensitivity(int sensitivity); bool kineticScrollingScrollbar(bool defaultValue = false) const; void setKineticScrollingScrollbar(bool scrollbar); void setEnableOpenGLFramerateLogging(bool value) const; bool enableOpenGLFramerateLogging(bool defaultValue = false) const; void setEnableBrushSpeedLogging(bool value) const; bool enableBrushSpeedLogging(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 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); bool stabilizerDelayedPaint(bool defaultValue = false) const; void setStabilizerDelayedPaint(bool 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; bool calculateAnimationCacheInBackground(bool defaultValue = false) const; void setCalculateAnimationCacheInBackground(bool value); QColor defaultAssistantsColor(bool defaultValue = false) const; void setDefaultAssistantsColor(const QColor &color) 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 management 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/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc index 7d5be239d2..b03ad44a18 100644 --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -1,1347 +1,1347 @@ /* * kis_paintop_box.cc - part of KImageShop/Krayon/Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2009-2011 Sven Langkamp (sven.langkamp@gmail.com) * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_paintop_box.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "KisResourceServerProvider.h" #include "kis_favorite_resource_manager.h" #include "kis_config.h" -#include "widgets/kis_popup_button.h" +#include "kis_popup_button.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_popup.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_chooser_popup.h" #include "widgets/kis_workspace_chooser.h" #include "widgets/kis_paintop_list_widget.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_widget_chooser.h" #include "tool/kis_tool.h" #include "kis_signals_blocker.h" #include "kis_action_manager.h" #include "kis_highlighted_button.h" typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; KisPaintopBox::KisPaintopBox(KisViewManager *view, QWidget *parent, const char *name) : QWidget(parent) , m_resourceProvider(view->resourceProvider()) , m_optionWidget(0) , m_toolOptionsPopupButton(0) , m_brushEditorPopupButton(0) , m_presetSelectorPopupButton(0) , m_toolOptionsPopup(0) , m_viewManager(view) , m_previousNode(0) , m_currTabletToolID(KoInputDevice::invalid()) , m_presetsEnabled(true) , m_blockUpdate(false) , m_dirtyPresetsEnabled(false) , m_eraserBrushSizeEnabled(false) , m_eraserBrushOpacityEnabled(false) { Q_ASSERT(view != 0); setObjectName(name); KisConfig cfg; m_dirtyPresetsEnabled = cfg.useDirtyPresets(); m_eraserBrushSizeEnabled = cfg.useEraserBrushSize(); m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity(); KAcceleratorManager::setNoAccel(this); setWindowTitle(i18n("Painter's Toolchest")); m_favoriteResourceManager = new KisFavoriteResourceManager(this); KConfigGroup grp = KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff"); int iconsize = grp.readEntry("IconSize", 32); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopupButton = new KisPopupButton(this); m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings")); m_toolOptionsPopupButton->setFixedSize(iconsize, iconsize); } m_brushEditorPopupButton = new KisIconWidget(this); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings")); m_brushEditorPopupButton->setFixedSize(iconsize, iconsize); m_presetSelectorPopupButton = new KisPopupButton(this); m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset")); m_presetSelectorPopupButton->setFixedSize(iconsize, iconsize); m_eraseModeButton = new KisHighlightedToolButton(this); m_eraseModeButton->setFixedSize(iconsize, iconsize); m_eraseModeButton->setCheckable(true); m_eraseAction = m_viewManager->actionManager()->createAction("erase_action"); m_eraseModeButton->setDefaultAction(m_eraseAction); m_reloadButton = new QToolButton(this); m_reloadButton->setFixedSize(iconsize, iconsize); m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action"); m_reloadButton->setDefaultAction(m_reloadAction); m_alphaLockButton = new KisHighlightedToolButton(this); m_alphaLockButton->setFixedSize(iconsize, iconsize); m_alphaLockButton->setCheckable(true); KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha"); m_alphaLockButton->setDefaultAction(alphaLockAction); // horizontal and vertical mirror toolbar buttons // mirror tool options for the X Mirror QMenu *toolbarMenuXMirror = new QMenu(); hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations"); toolbarMenuXMirror->addAction(hideCanvasDecorationsX); lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock"); toolbarMenuXMirror->addAction(lockActionX); moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter"); toolbarMenuXMirror->addAction(moveToCenterActionX); // mirror tool options for the Y Mirror QMenu *toolbarMenuYMirror = new QMenu(); hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations"); toolbarMenuYMirror->addAction(hideCanvasDecorationsY); lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock"); toolbarMenuYMirror->addAction(lockActionY); moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter"); toolbarMenuYMirror->addAction(moveToCenterActionY); // create horizontal and vertical mirror buttons m_hMirrorButton = new KisHighlightedToolButton(this); int menuPadding = 10; m_hMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_hMirrorButton->setCheckable(true); m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action"); m_hMirrorButton->setDefaultAction(m_hMirrorAction); m_hMirrorButton->setMenu(toolbarMenuXMirror); m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); m_vMirrorButton = new KisHighlightedToolButton(this); m_vMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_vMirrorButton->setCheckable(true); m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action"); m_vMirrorButton->setDefaultAction(m_vMirrorAction); m_vMirrorButton->setMenu(toolbarMenuYMirror); m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); // add connections for horizontal and mirrror buttons connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool))); connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool))); connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX())); connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY())); connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool))); connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool))); const bool sliderLabels = cfg.sliderLabels(); int sliderWidth; if (sliderLabels) { sliderWidth = 150 * logicalDpiX() / 96; } else { sliderWidth = 120 * logicalDpiX() / 96; } for (int i = 0; i < 3; ++i) { m_sliderChooser[i] = new KisWidgetChooser(i + 1); KisDoubleSliderSpinBox* slOpacity; KisDoubleSliderSpinBox* slFlow; KisDoubleSliderSpinBox* slSize; if (sliderLabels) { slOpacity = m_sliderChooser[i]->addWidget("opacity"); slFlow = m_sliderChooser[i]->addWidget("flow"); slSize = m_sliderChooser[i]->addWidget("size"); slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:"))); slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:"))); slSize->setPrefix(QString("%1 ").arg(i18n("Size:"))); } else { slOpacity = m_sliderChooser[i]->addWidget("opacity", i18n("Opacity:")); slFlow = m_sliderChooser[i]->addWidget("flow", i18n("Flow:")); slSize = m_sliderChooser[i]->addWidget("size", i18n("Size:")); } slOpacity->setRange(0, 100, 0); slOpacity->setValue(100); slOpacity->setSingleStep(5); slOpacity->setSuffix("%"); slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width())); slOpacity->setFixedHeight(iconsize); slOpacity->setBlockUpdateSignalOnDrag(true); slFlow->setRange(0, 100, 0); slFlow->setValue(100); slFlow->setSingleStep(5); slFlow->setSuffix("%"); slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width())); slFlow->setFixedHeight(iconsize); slFlow->setBlockUpdateSignalOnDrag(true); slSize->setRange(0, cfg.readEntry("maximumBrushSize", 1000), 2); slSize->setValue(100); slSize->setSingleStep(1); slSize->setExponentRatio(3.0); slSize->setSuffix(i18n(" px")); slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width())); slSize->setFixedHeight(iconsize); slSize->setBlockUpdateSignalOnDrag(true); m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1)); } m_cmbCompositeOp = new KisCompositeOpComboBox(); m_cmbCompositeOp->setFixedHeight(iconsize); Q_FOREACH (KisAction * a, m_cmbCompositeOp->blendmodeActions()) { m_viewManager->actionManager()->addAction(a->text(), a); } m_workspaceWidget = new KisPopupButton(this); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_workspaceWidget->setToolTip(i18n("Choose workspace")); m_workspaceWidget->setFixedSize(iconsize, iconsize); m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(view)); QHBoxLayout* baseLayout = new QHBoxLayout(this); m_paintopWidget = new QWidget(this); baseLayout->addWidget(m_paintopWidget); baseLayout->setSpacing(4); baseLayout->setContentsMargins(0, 0, 0, 0); m_layout = new QHBoxLayout(m_paintopWidget); if (!cfg.toolOptionsInDocker()) { m_layout->addWidget(m_toolOptionsPopupButton); } m_layout->addWidget(m_brushEditorPopupButton); m_layout->addWidget(m_presetSelectorPopupButton); m_layout->setSpacing(4); m_layout->setContentsMargins(0, 0, 0, 0); QWidget* compositeActions = new QWidget(this); QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions); compositeLayout->addWidget(m_cmbCompositeOp); compositeLayout->addWidget(m_eraseModeButton); compositeLayout->addWidget(m_alphaLockButton); compositeLayout->setSpacing(4); compositeLayout->setContentsMargins(0, 0, 0, 0); compositeLayout->addWidget(m_reloadButton); QWidgetAction * action; action = new QWidgetAction(this); view->actionCollection()->addAction("composite_actions", action); action->setText(i18n("Brush composite")); action->setDefaultWidget(compositeActions); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider1", action); view->actionCollection()->addAction("brushslider1", action); action->setDefaultWidget(m_sliderChooser[0]); connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider2", action); view->actionCollection()->addAction("brushslider2", action); action->setDefaultWidget(m_sliderChooser[1]); connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider3", action); view->actionCollection()->addAction("brushslider3", action); action->setDefaultWidget(m_sliderChooser[2]); connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action); view->actionCollection()->addAction("next_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action); view->actionCollection()->addAction("previous_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_preset", action); view->actionCollection()->addAction("previous_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset())); if (!cfg.toolOptionsInDocker()) { action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_tool_options", action); view->actionCollection()->addAction("show_tool_options", action); connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget())); } action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_editor", action); view->actionCollection()->addAction("show_brush_editor", action); connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_presets", action); view->actionCollection()->addAction("show_brush_presets", action); connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget())); QWidget* mirrorActions = new QWidget(this); QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions); mirrorLayout->addWidget(m_hMirrorButton); mirrorLayout->addWidget(m_vMirrorButton); mirrorLayout->setSpacing(4); mirrorLayout->setContentsMargins(0, 0, 0, 0); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("mirror_actions", action); action->setDefaultWidget(mirrorActions); view->actionCollection()->addAction("mirror_actions", action); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("workspaces", action); view->actionCollection()->addAction("workspaces", action); action->setDefaultWidget(m_workspaceWidget); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopup = new KisToolOptionsPopup(); m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup); m_toolOptionsPopup->switchDetached(false); } m_savePresetWidget = new KisPresetSaveWidget(this); m_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget); m_brushEditorPopupButton->setPopupWidget(m_presetsPopup); m_presetsPopup->parentWidget()->setWindowTitle(i18n("Brush Editor")); connect(m_presetsPopup, SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons())); m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup(); m_presetsChooserPopup->setMinimumHeight(550); m_presetsChooserPopup->setMinimumWidth(450); m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup); m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); slotNodeChanged(view->activeNode()); // Get all the paintops QList keys = KisPaintOpRegistry::instance()->keys(); QList factoryList; Q_FOREACH (const QString & paintopId, keys) { factoryList.append(KisPaintOpRegistry::instance()->get(paintopId)); } m_presetsPopup->setPaintOpList(factoryList); connect(m_presetsPopup , SIGNAL(paintopActivated(QString)) , SLOT(slotSetPaintop(QString))); connect(m_presetsPopup , SIGNAL(defaultPresetClicked()) , SLOT(slotSetupDefaultPreset())); connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResource*)), SLOT(resourceSelected(KoResource*))); connect(m_presetsPopup , SIGNAL(reloadPresetClicked()) , SLOT(slotReloadPreset())); connect(m_presetsPopup , SIGNAL(dirtyPresetToggled(bool)) , SLOT(slotDirtyPresetToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushSizeToggled(bool)) , SLOT(slotEraserBrushSizeToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushOpacityToggled(bool)) , SLOT(slotEraserBrushOpacityToggled(bool))); connect(m_presetsPopup, SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString))); connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResource*)) , SLOT(resourceSelected(KoResource*))); connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResource*)) , SLOT(resourceSelected(KoResource*))); connect(m_resourceProvider , SIGNAL(sigNodeChanged(const KisNodeSP)) , SLOT(slotNodeChanged(const KisNodeSP))); connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int))); connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool))); connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool))); m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure"); connect(m_disablePressureAction , SIGNAL(toggled(bool)) , SLOT(slotDisablePressureMode(bool))); m_disablePressureAction->setChecked(true); connect(m_hMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotHorizontalMirrorChanged(bool))); connect(m_vMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotVerticalMirrorChanged(bool))); connect(m_reloadAction , SIGNAL(triggered()) , SLOT(slotReloadPreset())); connect(m_sliderChooser[0]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[1]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[2]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); //Needed to connect canvas to favorite resource manager connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), SLOT(slotUnsetEraseMode())); connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor))); connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor))); // cold initialization m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor()); m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor()); connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigEnableChangeColor(bool)), m_resourceProvider, SLOT(slotResetEnableFGChange(bool))); connect(view->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon())); slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice()); KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); m_eraserName = "eraser_circle"; m_defaultPresetName = "basic_tip_default"; bool foundEraser = false; bool foundTip = false; for (int i=0; iresourceCount(); i++) { KisPaintOpPresetSP resource = rserver->resources().at(i); if (resource->name().toLower().contains("eraser_circle")) { m_eraserName = resource->name(); foundEraser = true; } else if (foundEraser == false && (resource->name().toLower().contains("eraser") || resource->filename().toLower().contains("eraser"))) { m_eraserName = resource->name(); foundEraser = true; } if (resource->name().toLower().contains("basic_tip_default")) { m_defaultPresetName = resource->name(); foundTip = true; } else if (foundTip == false && (resource->name().toLower().contains("default") || resource->filename().toLower().contains("default"))) { m_defaultPresetName = resource->name(); foundTip = true; } } } KisPaintopBox::~KisPaintopBox() { KisConfig cfg; QMapIterator iter(m_tabletToolMap); while (iter.hasNext()) { iter.next(); //qDebug() << "Writing last used preset for" << iter.key().pointer << iter.key().uniqueID << iter.value().preset->name(); if ((iter.key().pointer) == QTabletEvent::Eraser) { cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } else { cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } } // Do not delete the widget, since it is global to the application, not owned by the view m_presetsPopup->setPaintOpSettingsWidget(0); qDeleteAll(m_paintopOptionWidgets); delete m_favoriteResourceManager; for (int i = 0; i < 3; ++i) { delete m_sliderChooser[i]; } } void KisPaintopBox::restoreResource(KoResource* resource) { KisPaintOpPreset* preset = dynamic_cast(resource); //qDebug() << "restoreResource" << resource << preset; if (preset) { setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::newOptionWidgets(const QList > &optionWidgetList) { if (m_toolOptionsPopup) { m_toolOptionsPopup->newOptionWidgets(optionWidgetList); } } void KisPaintopBox::resourceSelected(KoResource* resource) { m_presetsPopup->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating KisPaintOpPreset* preset = dynamic_cast(resource); if (preset && preset != m_resourceProvider->currentPreset()) { if (!preset->settings()->isLoadable()) return; if (!m_dirtyPresetsEnabled) { KisSignalsBlocker blocker(m_optionWidget); if (!preset->load()) { warnKrita << "failed to load the preset."; } } //qDebug() << "resourceSelected" << resource->name(); setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::setCurrentPaintop(const KoID& paintop) { KisPaintOpPresetSP preset = activePreset(paintop); Q_ASSERT(preset && preset->settings()); //qDebug() << "setCurrentPaintop();" << paintop << preset; setCurrentPaintop(preset); } void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset) { //qDebug() << "setCurrentPaintop(); " << preset->name(); if (preset == m_resourceProvider->currentPreset()) { if (preset == m_tabletToolMap[m_currTabletToolID].preset) { return; } } Q_ASSERT(preset); const KoID& paintop = preset->paintOp(); m_presetConnections.clear(); if (m_resourceProvider->currentPreset()) { m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset()); if (m_optionWidget) { m_optionWidget->hide(); } } if (!m_paintopOptionWidgets.contains(paintop)) m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this); m_optionWidget = m_paintopOptionWidgets[paintop]; KisSignalsBlocker b(m_optionWidget); preset->setOptionsWidget(m_optionWidget); m_optionWidget->setImage(m_viewManager->image()); m_optionWidget->setNode(m_viewManager->activeNode()); m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset())); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP))); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP))); // load the current brush engine icon for the brush editor toolbar button m_brushEditorPopupButton->slotSetItem(preset.data()); m_presetsPopup->setCurrentPaintOpId(paintop.id()); ////qDebug() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name(); m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset; m_tabletToolMap[m_currTabletToolID].preset = preset; m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp(); if (m_presetsPopup->currentPaintOpId() != paintop.id()) { // Must change the paintop as the current one is not supported // by the new colorspace. dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace"; } } void KisPaintopBox::slotUpdateOptionsWidgetPopup() { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); KIS_SAFE_ASSERT_RECOVER_RETURN(preset); KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget); m_optionWidget->setConfigurationSafe(preset->settings()); m_presetsPopup->resourceSelected(preset.data()); m_presetsPopup->updateViewSettings(); // the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed // need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation m_optionWidget->setImage(m_viewManager->image()); } KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp) { QString defaultName = paintOp.id() + ".kpp"; QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName); KisPaintOpPresetSP preset = new KisPaintOpPreset(path); if (!preset->load()) { preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp); } Q_ASSERT(preset); Q_ASSERT(preset->valid()); return preset; } KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp) { if (m_paintOpPresetMap[paintOp] == 0) { m_paintOpPresetMap[paintOp] = defaultPreset(paintOp); } return m_paintOpPresetMap[paintOp]; } void KisPaintopBox::updateCompositeOp(QString compositeOpID) { if (!m_optionWidget) return; KisSignalsBlocker blocker(m_optionWidget); KisNodeSP node = m_resourceProvider->currentNode(); if (node && node->paintDevice()) { if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID)) compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); { KisSignalsBlocker b1(m_cmbCompositeOp); m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID)); } if (compositeOpID != m_currCompositeOpID) { m_currCompositeOpID = compositeOpID; } if (compositeOpID == COMPOSITE_ERASE || m_resourceProvider->eraserMode()) { m_eraseModeButton->setChecked(true); } else { m_eraseModeButton->setChecked(false); } } } void KisPaintopBox::setWidgetState(int flags) { if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) { m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP); m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP); } if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) { m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS); m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS); } for (int i = 0; i < 3; ++i) { if (flags & (ENABLE_OPACITY | DISABLE_OPACITY)) m_sliderChooser[i]->getWidget("opacity")->setEnabled(flags & ENABLE_OPACITY); if (flags & (ENABLE_FLOW | DISABLE_FLOW)) m_sliderChooser[i]->getWidget("flow")->setEnabled(flags & ENABLE_FLOW); if (flags & (ENABLE_SIZE | DISABLE_SIZE)) m_sliderChooser[i]->getWidget("size")->setEnabled(flags & ENABLE_SIZE); } } void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value) { for (int i = 0; i < 3; ++i) { KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget(sliderID); KisSignalsBlocker b(slider); if (sliderID == "opacity" || sliderID == "flow") { // opacity and flows UI stored at 0-100% slider->setValue(value*100); } else { slider->setValue(value); // brush size } } } void KisPaintopBox::slotSetPaintop(const QString& paintOpId) { if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) { KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name()); //qDebug() << "slotsetpaintop" << id; setCurrentPaintop(id); } } void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice) { TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice); //qDebug() << "slotInputDeviceChanged()" << inputDevice.device() << inputDevice.uniqueTabletId(); m_currTabletToolID = TabletToolID(inputDevice); if (toolData == m_tabletToolMap.end()) { KisConfig cfg; KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset; if (inputDevice.pointer() == QTabletEvent::Eraser) { preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), m_eraserName)); } else { preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), m_defaultPresetName)); //if (preset) //qDebug() << "found stored preset " << preset->name() << "for" << inputDevice.uniqueTabletId(); //else //qDebug() << "no preset found for" << inputDevice.uniqueTabletId(); } if (!preset) { preset = rserver->resourceByName(m_defaultPresetName); } if (preset) { //qDebug() << "inputdevicechanged 1" << preset; setCurrentPaintop(preset); } } else { if (toolData->preset) { //qDebug() << "inputdevicechanged 2" << toolData->preset; setCurrentPaintop(toolData->preset); } else { //qDebug() << "inputdevicechanged 3" << toolData->paintOpID; setCurrentPaintop(toolData->paintOpID); } } } void KisPaintopBox::slotCreatePresetFromScratch(QString paintop) { //First try to select an available default preset for that engine. If it doesn't exist, then //manually set the engine to use a new preset. KoID id(paintop, KisPaintOpRegistry::instance()->get(paintop)->name()); KisPaintOpPresetSP preset = defaultPreset(id); slotSetPaintop(paintop); // change the paintop settings area and update the UI if (!preset) { m_presetsPopup->setCreatingBrushFromScratch(true); // disable UI elements while creating from scratch preset = m_resourceProvider->currentPreset(); } else { m_resourceProvider->setPaintOpPreset(preset); preset->setOptionsWidget(m_optionWidget); } m_presetsPopup->resourceSelected(preset.data()); // this helps update the UI on the brush editor } void KisPaintopBox::slotCanvasResourceChanged(int key, const QVariant &value) { if (m_viewManager) { sender()->blockSignals(true); KisPaintOpPresetSP preset = m_viewManager->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) { QString compositeOp = preset->settings()->getString("CompositeOp"); updateCompositeOp(compositeOp); resourceSelected(preset.data()); } /** * Update currently selected preset in both the popup widgets */ m_presetsChooserPopup->canvasResourceChanged(preset); m_presetsPopup->currentPresetChanged(preset); if (key == KisCanvasResourceProvider::CurrentCompositeOp) { if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) { updateCompositeOp(m_resourceProvider->currentCompositeOp()); } } if (key == KisCanvasResourceProvider::Size) { setSliderValue("size", m_resourceProvider->size()); } if (key == KisCanvasResourceProvider::Opacity) { setSliderValue("opacity", m_resourceProvider->opacity()); } if (key == KisCanvasResourceProvider::Flow) { setSliderValue("flow", m_resourceProvider->flow()); } if (key == KisCanvasResourceProvider::EraserMode) { m_eraseAction->setChecked(value.toBool()); } if (key == KisCanvasResourceProvider::DisablePressure) { m_disablePressureAction->setChecked(value.toBool()); } sender()->blockSignals(false); } } void KisPaintopBox::slotUpdatePreset() { if (!m_resourceProvider->currentPreset()) return; // block updates of avoid some over updating of the option widget m_blockUpdate = true; setSliderValue("size", m_resourceProvider->size()); { qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity(); m_resourceProvider->setOpacity(opacity); setSliderValue("opacity", opacity); setWidgetState(ENABLE_OPACITY); } { setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow()); setWidgetState(ENABLE_FLOW); } { updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp()); setWidgetState(ENABLE_COMPOSITEOP); } m_blockUpdate = false; } void KisPaintopBox::slotSetupDefaultPreset() { KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp()); preset->setOptionsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); // tell the brush editor that the resource has changed // so it can update everything m_presetsPopup->resourceSelected(preset.data()); } void KisPaintopBox::slotNodeChanged(const KisNodeSP node) { if (m_previousNode.isValid() && m_previousNode->paintDevice()) disconnect(m_previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); // Reconnect colorspace change of node if (node && node->paintDevice()) { connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID); m_previousNode = node; slotColorSpaceChanged(node->colorSpace()); } if (m_optionWidget) { m_optionWidget->setNode(node); } } void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace) { m_cmbCompositeOp->validate(colorSpace); } void KisPaintopBox::slotToggleEraseMode(bool checked) { const bool oldEraserMode = m_resourceProvider->eraserMode(); m_resourceProvider->setEraserMode(checked); if (oldEraserMode != checked && m_eraserBrushSizeEnabled) { const qreal currentSize = m_resourceProvider->size(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush size. set the eraser size to the normal brush size if not set if (checked) { settings->setSavedBrushSize(currentSize); if (qFuzzyIsNull(settings->savedEraserSize())) { settings->setSavedEraserSize(currentSize); } } else { settings->setSavedEraserSize(currentSize); if (qFuzzyIsNull(settings->savedBrushSize())) { settings->setSavedBrushSize(currentSize); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newSize = checked ? settings->savedEraserSize() : settings->savedBrushSize(); m_resourceProvider->setSize(newSize); } if (oldEraserMode != checked && m_eraserBrushOpacityEnabled) { const qreal currentOpacity = m_resourceProvider->opacity(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush opacity. set the eraser opacity to the normal brush opacity if not set if (checked) { settings->setSavedBrushOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedEraserOpacity())) { settings->setSavedEraserOpacity(currentOpacity); } } else { settings->setSavedEraserOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedBrushOpacity())) { settings->setSavedBrushOpacity(currentOpacity); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newOpacity = checked ? settings->savedEraserOpacity() : settings->savedBrushOpacity(); m_resourceProvider->setOpacity(newOpacity); } } void KisPaintopBox::slotSetCompositeMode(int index) { Q_UNUSED(index); QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id(); m_resourceProvider->setCurrentCompositeOp(compositeOp); } void KisPaintopBox::slotHorizontalMirrorChanged(bool value) { m_resourceProvider->setMirrorHorizontal(value); } void KisPaintopBox::slotVerticalMirrorChanged(bool value) { m_resourceProvider->setMirrorVertical(value); } void KisPaintopBox::sliderChanged(int n) { if (!m_optionWidget) // widget will not exist if the are no documents open return; KisSignalsBlocker blocker(m_optionWidget); // flow and opacity are shown as 0-100% on the UI, but their data is actually 0-1. Convert those two values // back for further work qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value()/100; qreal flow = m_sliderChooser[n]->getWidget("flow")->value()/100; qreal size = m_sliderChooser[n]->getWidget("size")->value(); setSliderValue("opacity", opacity); setSliderValue("flow" , flow); setSliderValue("size" , size); if (m_presetsEnabled) { // IMPORTANT: set the PaintOp size before setting the other properties // it wont work the other way // TODO: why?! m_resourceProvider->setSize(size); m_resourceProvider->setOpacity(opacity); m_resourceProvider->setFlow(flow); KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings()); propertiesProxy->setProperty("OpacityValue", opacity); propertiesProxy->setProperty("FlowValue", flow); m_optionWidget->setConfigurationSafe(m_resourceProvider->currentPreset()->settings().data()); } else { m_resourceProvider->setOpacity(opacity); } m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); } void KisPaintopBox::slotSlider1Changed() { sliderChanged(0); } void KisPaintopBox::slotSlider2Changed() { sliderChanged(1); } void KisPaintopBox::slotSlider3Changed() { sliderChanged(2); } void KisPaintopBox::slotToolChanged(KoCanvasController* canvas, int toolId) { Q_UNUSED(canvas); Q_UNUSED(toolId); if (!m_viewManager->canvasBase()) return; QString id = KoToolManager::instance()->activeToolId(); KisTool* tool = dynamic_cast(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id)); if (tool) { int flags = tool->flags(); if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) { setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY); } else { setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY); } if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) { setWidgetState(ENABLE_PRESETS); slotUpdatePreset(); m_presetsEnabled = true; } else { setWidgetState(DISABLE_PRESETS); m_presetsEnabled = false; } if (flags & KisTool::FLAG_USES_CUSTOM_SIZE) { setWidgetState(ENABLE_SIZE | ENABLE_FLOW); } else { setWidgetState(DISABLE_SIZE | DISABLE_FLOW); } } else setWidgetState(DISABLE_ALL); } void KisPaintopBox::slotPreviousFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for (int i=0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset() && m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i > 0) { m_favoriteResourceManager->slotChangeActivePaintop(i - 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1); } //floating message should have least 2 lines, otherwise //preset thumbnail will be too small to distinguish //(because size of image on floating message depends on amount of lines in msg) m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotNextFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for(int i = 0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i < m_favoriteResourceManager->numFavoritePresets() - 1) { m_favoriteResourceManager->slotChangeActivePaintop(i + 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(0); } m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotSwitchToPreviousPreset() { if (m_resourceProvider->previousPreset()) { //qDebug() << "slotSwitchToPreviousPreset();" << m_resourceProvider->previousPreset(); setCurrentPaintop(m_resourceProvider->previousPreset()); m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); } } void KisPaintopBox::slotUnsetEraseMode() { m_eraseAction->setChecked(false); } void KisPaintopBox::slotToggleAlphaLockMode(bool checked) { if (checked) { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-locked")); } else { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-unlocked")); } m_resourceProvider->setGlobalAlphaLock(checked); } void KisPaintopBox::slotDisablePressureMode(bool checked) { if (checked) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } m_resourceProvider->setDisablePressure(checked); } void KisPaintopBox::slotReloadPreset() { KisSignalsBlocker blocker(m_optionWidget); //Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading. KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name()); if (preset) { preset->load(); } } void KisPaintopBox::slotGuiChangedCurrentPreset() // Called only when UI is changed and not when preset is changed { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { /** * Here we postpone all the settings updates events until the entire writing * operation will be finished. As soon as it is finished, the updates will be * emitted happily (if there were any). */ KisPaintOpPreset::UpdatedPostponer postponer(preset.data()); QStringList preserveProperties; preserveProperties << "lodUserAllowed"; preserveProperties << "lodSizeThreshold"; // clear all the properties before dumping the stuff into the preset, // some of the options add the values incrementally // (e.g. KisPaintOpUtils::RequiredBrushFilesListTag), therefore they // may add up if we pass the same preset multiple times preset->settings()->resetSettings(preserveProperties); m_optionWidget->writeConfigurationSafe(const_cast(preset->settings().data())); } // we should also update the preset strip to update the status of the "dirty" mark m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); // TODO!!!!!!!! //m_presetsPopup->updateViewSettings(); } void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p) { QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value())); if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) { m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous"); } } slotGuiChangedCurrentPreset(); } void KisPaintopBox::slotDropLockedOption(KisPropertiesConfigurationSP p) { KisSignalsBlocker blocker(m_optionWidget); KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { KisPaintOpPreset::DirtyStateSaver dirtySaver(preset.data()); QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); if (preset->settings()->hasProperty(i.key() + "_previous")) { preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous")); preset->settings()->removeProperty(i.key() + "_previous"); } } } //slotUpdatePreset(); } void KisPaintopBox::slotDirtyPresetToggled(bool value) { if (!value) { slotReloadPreset(); m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); m_presetsPopup->updateViewSettings(); } m_dirtyPresetsEnabled = value; KisConfig cfg; cfg.setUseDirtyPresets(m_dirtyPresetsEnabled); } void KisPaintopBox::slotEraserBrushSizeToggled(bool value) { m_eraserBrushSizeEnabled = value; KisConfig cfg; cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled); } void KisPaintopBox::slotEraserBrushOpacityToggled(bool value) { m_eraserBrushOpacityEnabled = value; KisConfig cfg; cfg.setUseEraserBrushOpacity(m_eraserBrushOpacityEnabled); } void KisPaintopBox::slotUpdateSelectionIcon() { m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal")); m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical")); KisConfig cfg; if (!cfg.toolOptionsInDocker() && m_toolOptionsPopupButton) { m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); } m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser")); m_reloadAction->setIcon(KisIconUtils::loadIcon("view-refresh")); if (m_disablePressureAction->isChecked()) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } } void KisPaintopBox::slotLockXMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorHorizontalLock(toggleLock); } void KisPaintopBox::slotLockYMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorVerticalLock(toggleLock); } void KisPaintopBox::slotHideDecorationMirrorX(bool toggled) { m_resourceProvider->setMirrorHorizontalHideDecorations(toggled); } void KisPaintopBox::slotHideDecorationMirrorY(bool toggled) { m_resourceProvider->setMirrorVerticalHideDecorations(toggled); } void KisPaintopBox::slotMoveToCenterMirrorX() { m_resourceProvider->mirrorHorizontalMoveCanvasToCenter(); } void KisPaintopBox::slotMoveToCenterMirrorY() { m_resourceProvider->mirrorVerticalMoveCanvasToCenter(); } diff --git a/libs/ui/widgets/kis_screen_color_picker.cpp b/libs/ui/widgets/KisScreenColorPicker.cpp similarity index 96% rename from libs/ui/widgets/kis_screen_color_picker.cpp rename to libs/ui/widgets/KisScreenColorPicker.cpp index 58744c9c0c..90b6dbe817 100644 --- a/libs/ui/widgets/kis_screen_color_picker.cpp +++ b/libs/ui/widgets/KisScreenColorPicker.cpp @@ -1,274 +1,274 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include -#include "kis_icon.h" -#include "kis_screen_color_picker.h" -#include "KisMainWindow.h" #include + +#include "kis_shared_ptr.h" +#include "kis_icon.h" +#include "kis_image.h" #include "kis_wrapped_rect.h" #include "KisPart.h" +#include "KisScreenColorPicker.h" +#include "KisDlgInternalColorSelector.h" struct KisScreenColorPicker::Private { QPushButton *screenColorPickerButton = 0; QLabel *lblScreenColorInfo = 0; KoColor currentColor = KoColor(); KoColor beforeScreenColorPicking = KoColor(); KisScreenColorPickingEventFilter *colorPickingEventFilter = 0; #ifdef Q_OS_WIN32 QTimer *updateTimer = 0; QWindow dummyTransparentWindow; #endif }; -KisScreenColorPicker::KisScreenColorPicker(QWidget *parent) : QWidget(parent), m_d(new Private) +KisScreenColorPicker::KisScreenColorPicker(QWidget *parent) : KisScreenColorPickerBase(parent), m_d(new Private) { QVBoxLayout *layout = new QVBoxLayout(); this->setLayout(layout); m_d->screenColorPickerButton = new QPushButton(); m_d->screenColorPickerButton->setMinimumHeight(25); this->layout()->addWidget(m_d->screenColorPickerButton); m_d->lblScreenColorInfo = new QLabel(QLatin1String("\n")); this->layout()->addWidget(m_d->lblScreenColorInfo); connect(m_d->screenColorPickerButton, SIGNAL(clicked()), SLOT(pickScreenColor())); updateIcons(); #ifdef Q_OS_WIN32 m_d->updateTimer = new QTimer(this); m_d->dummyTransparentWindow.resize(1, 1); m_d->dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint); connect(m_d->updateTimer, SIGNAL(timeout()), SLOT(updateColorPicking())); #endif } KisScreenColorPicker::~KisScreenColorPicker() { } void KisScreenColorPicker::updateIcons() { - m_d->screenColorPickerButton->setIcon(kisIcon("krita_tool_color_picker")); + m_d->screenColorPickerButton->setIcon(kisIcon("krita_tool_color_picker")); } KoColor KisScreenColorPicker::currentColor() { return m_d->currentColor; } void KisScreenColorPicker::pickScreenColor() { if (!m_d->colorPickingEventFilter) m_d->colorPickingEventFilter = new KisScreenColorPickingEventFilter(this); this->installEventFilter(m_d->colorPickingEventFilter); // If user pushes Escape, the last color before picking will be restored. m_d->beforeScreenColorPicking = currentColor(); grabMouse(Qt::CrossCursor); #ifdef Q_OS_WIN32 // excludes WinCE and WinRT // On Windows mouse tracking doesn't work over other processes's windows m_d->updateTimer->start(30); // HACK: Because mouse grabbing doesn't work across processes, we have to have a dummy, // invisible window to catch the mouse click, otherwise we will click whatever we clicked // and loose focus. m_d->dummyTransparentWindow.show(); #endif grabKeyboard(); /* With setMouseTracking(true) the desired color can be more precisely picked up, * and continuously pushing the mouse button is not necessary. */ setMouseTracking(true); //emit to the rest of the dialog to disable. Q_EMIT sigPleaseDisableEverything(true); m_d->screenColorPickerButton->setDisabled(true); const QPoint globalPos = QCursor::pos(); setCurrentColor(grabScreenColor(globalPos)); updateColorLabelText(globalPos); } void KisScreenColorPicker::setCurrentColor(KoColor c) { m_d->currentColor = c; } KoColor KisScreenColorPicker::grabScreenColor(const QPoint &p) { // First check whether we're clicking on a Krita window for some real color picking Q_FOREACH(KisView *view, KisPart::instance()->views()) { QWidget *canvasWidget = view->canvasBase()->canvasWidget(); QPoint widgetPoint = canvasWidget->mapFromGlobal(p); if (canvasWidget->rect().contains(widgetPoint)) { QPointF imagePoint = view->canvasBase()->coordinatesConverter()->widgetToImage(widgetPoint); KisImageWSP image = view->image(); if (image) { if (image->wrapAroundModePermitted()) { imagePoint = KisWrappedRect::ptToWrappedPt(imagePoint.toPoint(), image->bounds()); } KoColor pickedColor = KoColor(); image->projection()->pixel(imagePoint.x(), imagePoint.y(), &pickedColor); return pickedColor; } } } // And otherwise, we'll check the desktop const QDesktopWidget *desktop = QApplication::desktop(); const QPixmap pixmap = QGuiApplication::screens().at(desktop->screenNumber())->grabWindow(desktop->winId(), p.x(), p.y(), 1, 1); QImage i = pixmap.toImage(); KoColor col = KoColor(); col.fromQColor(QColor::fromRgb(i.pixel(0, 0))); return col; } void KisScreenColorPicker::updateColorLabelText(const QPoint &globalPos) { KoColor col = grabScreenColor(globalPos); QString colname = KoColor::toQString(col); QString location = QString::number(globalPos.x())+QString(", ")+QString::number(globalPos.y()); m_d->lblScreenColorInfo->setWordWrap(true); m_d->lblScreenColorInfo->setText(location+QString(": ")+colname); } bool KisScreenColorPicker::handleColorPickingMouseMove(QMouseEvent *e) { // If the cross is visible the grabbed color will be black most of the times //cp->setCrossVisible(!cp->geometry().contains(e->pos())); continueUpdateColorPicking(e->globalPos()); return true; } bool KisScreenColorPicker::handleColorPickingMouseButtonRelease(QMouseEvent *e) { setCurrentColor(grabScreenColor(e->globalPos())); Q_EMIT sigNewColorPicked(currentColor()); releaseColorPicking(); return true; } bool KisScreenColorPicker::handleColorPickingKeyPress(QKeyEvent *e) { #if QT_VERSION >= 0x050600 if (e->matches(QKeySequence::Cancel)) { #else if (e->key() == Qt::Key_Escape) { #endif releaseColorPicking(); setCurrentColor(m_d->beforeScreenColorPicking); } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { setCurrentColor(grabScreenColor(QCursor::pos())); releaseColorPicking(); } e->accept(); return true; } void KisScreenColorPicker::releaseColorPicking() { removeEventFilter(m_d->colorPickingEventFilter); releaseMouse(); #ifdef Q_OS_WIN32 m_d->updateTimer->stop(); m_d->dummyTransparentWindow.setVisible(false); #endif releaseKeyboard(); setMouseTracking(false); m_d->lblScreenColorInfo->setText(QLatin1String("\n")); //emit enable signal Q_EMIT sigPleaseDisableEverything(false); m_d->screenColorPickerButton->setDisabled(false); } void KisScreenColorPicker::changeEvent(QEvent *e) { QWidget::changeEvent(e); } void KisScreenColorPicker::updateColorPicking() { static QPoint lastGlobalPos; QPoint newGlobalPos = QCursor::pos(); if (lastGlobalPos == newGlobalPos) return; lastGlobalPos = newGlobalPos; if (!rect().contains(mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called continueUpdateColorPicking(newGlobalPos); #ifdef Q_OS_WIN32 m_d->dummyTransparentWindow.setPosition(newGlobalPos); #endif } } void KisScreenColorPicker::continueUpdateColorPicking(const QPoint &globalPos) { const KoColor color = grabScreenColor(globalPos); // QTBUG-39792, do not change standard, custom color selectors while moving as // otherwise it is not possible to pre-select a custom cell for assignment. setCurrentColor(color); updateColorLabelText(globalPos); } // Event filter to be installed on the dialog while in color-picking mode. KisScreenColorPickingEventFilter::KisScreenColorPickingEventFilter(KisScreenColorPicker *w, QObject *parent) : QObject(parent) , m_w(w) {} bool KisScreenColorPickingEventFilter::eventFilter(QObject *, QEvent *event) { switch (event->type()) { case QEvent::MouseMove: return m_w->handleColorPickingMouseMove(static_cast(event)); case QEvent::MouseButtonRelease: return m_w->handleColorPickingMouseButtonRelease(static_cast(event)); case QEvent::KeyPress: return m_w->handleColorPickingKeyPress(static_cast(event)); default: break; } return false; } - - -#include "kis_screen_color_picker.moc" diff --git a/libs/ui/widgets/kis_screen_color_picker.h b/libs/ui/widgets/KisScreenColorPicker.h similarity index 90% rename from libs/ui/widgets/kis_screen_color_picker.h rename to libs/ui/widgets/KisScreenColorPicker.h index 5008928c04..79c327e6db 100644 --- a/libs/ui/widgets/kis_screen_color_picker.h +++ b/libs/ui/widgets/KisScreenColorPicker.h @@ -1,81 +1,84 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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 KISSCREENCOLORPICKER_H #define KISSCREENCOLORPICKER_H #include #include #include #include "KoColor.h" +#include #include "kritaui_export.h" /** * @brief The KisScreenColorPicker class * Based on the original QColorDialog's screen color picker, this class provides a button * that can be used to activate a colorpicker that can pick from anywhere on the screen. */ -class KRITAUI_EXPORT KisScreenColorPicker : public QWidget +class KRITAUI_EXPORT KisScreenColorPicker : public KisScreenColorPickerBase { Q_OBJECT public: explicit KisScreenColorPicker(QWidget *parent = 0); ~KisScreenColorPicker() override; KoColor currentColor(); bool handleColorPickingMouseMove(QMouseEvent *e); bool handleColorPickingMouseButtonRelease(QMouseEvent *e); bool handleColorPickingKeyPress(QKeyEvent *e); /// reloads icon(s) when theme is updated - void updateIcons(); + void updateIcons() override; + + static KisScreenColorPicker *createScreenColorPicker(QWidget *parent = 0) {return new KisScreenColorPicker(parent);} Q_SIGNALS: void sigNewColorPicked(KoColor c); void sigPleaseDisableEverything(bool disable); public Q_SLOTS: void pickScreenColor(); private Q_SLOTS: void updateColorPicking(); protected: void changeEvent(QEvent *event) override; private: struct Private; //The private struct const QScopedPointer m_d; //the private pointer void setCurrentColor(KoColor c); KoColor grabScreenColor(const QPoint &p); void updateColorLabelText(const QPoint &globalPos); void releaseColorPicking(); void continueUpdateColorPicking(const QPoint &globalPos); }; class KisScreenColorPickingEventFilter : public QObject { public: explicit KisScreenColorPickingEventFilter(KisScreenColorPicker *w, QObject *parent = 0); bool eventFilter(QObject *, QEvent *event) override; private: KisScreenColorPicker *m_w; }; #endif // KISSCREENCOLORPICKER_H diff --git a/libs/ui/widgets/KoDualColorButton.cpp b/libs/ui/widgets/KoDualColorButton.cpp index a01bff6ec6..dde55e9377 100644 --- a/libs/ui/widgets/KoDualColorButton.cpp +++ b/libs/ui/widgets/KoDualColorButton.cpp @@ -1,406 +1,406 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Daniel M. Duley This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoDualColorButton.h" #include "KoColor.h" #include "KoColorDisplayRendererInterface.h" #include #include "dcolorarrow.xbm" #include "dcolorreset.xpm" #include -#include "dialogs/kis_dlg_internal_color_selector.h" +#include "KisDlgInternalColorSelector.h" #include "kis_signals_blocker.h" #include #include #include #include #include #include class Q_DECL_HIDDEN KoDualColorButton::Private { public: Private(const KoColor &fgColor, const KoColor &bgColor, QWidget *_dialogParent, const KoColorDisplayRendererInterface *_displayRenderer) : dialogParent(_dialogParent) , dragFlag( false ) , miniCtlFlag( false ) , foregroundColor(fgColor) , backgroundColor(bgColor) , displayRenderer(_displayRenderer) { updateArrows(); resetPixmap = QPixmap( (const char **)dcolorreset_xpm ); popDialog = true; } void updateArrows() { arrowBitmap = QPixmap(12,12); arrowBitmap.fill(Qt::transparent); QPainter p(&arrowBitmap); p.setPen(dialogParent->palette().foreground().color()); // arrow pointing left p.drawLine(0, 3, 7, 3); p.drawLine(1, 2, 1, 4); p.drawLine(2, 1, 2, 5); p.drawLine(3, 0, 3, 6); // arrow pointing down p.drawLine(8, 4, 8, 11); p.drawLine(5, 8, 11, 8); p.drawLine(6, 9, 10, 9); p.drawLine(7, 10, 9, 10); } QWidget* dialogParent; QPixmap arrowBitmap; QPixmap resetPixmap; bool dragFlag, miniCtlFlag; KoColor foregroundColor; KoColor backgroundColor; KisDlgInternalColorSelector *colorSelectorDialog; QPoint dragPosition; Selection tmpSelection; bool popDialog; const KoColorDisplayRendererInterface *displayRenderer; void init(KoDualColorButton *q); }; void KoDualColorButton::Private::init(KoDualColorButton *q) { if ( q->sizeHint().isValid() ) q->setMinimumSize( q->sizeHint() ); q->setAcceptDrops( true ); QString caption = i18n("Select a color"); KisDlgInternalColorSelector::Config config = KisDlgInternalColorSelector::Config(); config.modal = false; colorSelectorDialog = new KisDlgInternalColorSelector(q, foregroundColor, config, caption, displayRenderer); connect(colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), q, SLOT(slotSetForeGroundColorFromDialog(KoColor))); connect(q, SIGNAL(foregroundColorChanged(KoColor)), colorSelectorDialog, SLOT(slotColorUpdated(KoColor))); } KoDualColorButton::KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, QWidget *parent, QWidget* dialogParent ) : QWidget( parent ), d( new Private(foregroundColor, backgroundColor, dialogParent, KoDumbColorDisplayRenderer::instance()) ) { d->init(this); } KoDualColorButton::KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, const KoColorDisplayRendererInterface *displayRenderer, QWidget *parent, QWidget* dialogParent) : QWidget( parent ), d( new Private(foregroundColor, backgroundColor, dialogParent, displayRenderer) ) { d->init(this); } KoDualColorButton::~KoDualColorButton() { delete d; } KoColor KoDualColorButton::foregroundColor() const { return d->foregroundColor; } KoColor KoDualColorButton::backgroundColor() const { return d->backgroundColor; } bool KoDualColorButton::popDialog() const { return d->popDialog; } QSize KoDualColorButton::sizeHint() const { return QSize( 34, 34 ); } void KoDualColorButton::setForegroundColor( const KoColor &color ) { d->foregroundColor = color; { /** * The internal color selector might emit the color of a different profile, so * we should break this cycling dependency somehow. */ KisSignalsBlocker b(d->colorSelectorDialog); d->colorSelectorDialog->slotColorUpdated(color); } repaint(); } void KoDualColorButton::setBackgroundColor( const KoColor &color ) { d->backgroundColor = color; repaint(); } void KoDualColorButton::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { d->displayRenderer = displayRenderer; d->colorSelectorDialog->setDisplayRenderer(displayRenderer); connect(d->displayRenderer, SIGNAL(destroyed()), this, SLOT(setDisplayRenderer()), Qt::UniqueConnection); } else { d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } } void KoDualColorButton::setColorSpace(const KoColorSpace *cs) { d->colorSelectorDialog->lockUsedColorSpace(cs); } QColor KoDualColorButton::getColorFromDisplayRenderer(KoColor c) { QColor col; if (d->displayRenderer) { c.convertTo(d->displayRenderer->getPaintingColorSpace()); col = d->displayRenderer->toQColor(c); } else { col = c.toQColor(); } return col; } void KoDualColorButton::setPopDialog( bool popDialog ) { d->popDialog = popDialog; } void KoDualColorButton::metrics( QRect &foregroundRect, QRect &backgroundRect ) { foregroundRect = QRect( 0, 0, width() - 14, height() - 14 ); backgroundRect = QRect( 14, 14, width() - 14, height() - 14 ); } void KoDualColorButton::paintEvent(QPaintEvent *) { QRect foregroundRect; QRect backgroundRect; QPainter painter( this ); metrics( foregroundRect, backgroundRect ); QBrush defBrush = palette().brush( QPalette::Button ); QBrush foregroundBrush( getColorFromDisplayRenderer(d->foregroundColor), Qt::SolidPattern ); QBrush backgroundBrush( getColorFromDisplayRenderer(d->backgroundColor), Qt::SolidPattern ); qDrawShadeRect( &painter, backgroundRect, palette(), false, 1, 0, isEnabled() ? &backgroundBrush : &defBrush ); qDrawShadeRect( &painter, foregroundRect, palette(), false, 1, 0, isEnabled() ? &foregroundBrush : &defBrush ); painter.setPen( palette().color( QPalette::Shadow ) ); painter.drawPixmap( foregroundRect.right() + 2, 1, d->arrowBitmap ); painter.drawPixmap( 1, foregroundRect.bottom() + 2, d->resetPixmap ); } void KoDualColorButton::dragEnterEvent( QDragEnterEvent *event ) { event->setAccepted( isEnabled() && KColorMimeData::canDecode( event->mimeData() ) ); } void KoDualColorButton::dropEvent( QDropEvent *event ) { Q_UNUSED(event); /* QColor color = KColorMimeData::fromMimeData( event->mimeData() ); if ( color.isValid() ) { if ( d->selection == Foreground ) { d->foregroundColor = color; emit foregroundColorChanged( color ); } else { d->backgroundColor = color; emit backgroundColorChanged( color ); } repaint(); } */ } void KoDualColorButton::slotSetForeGroundColorFromDialog(const KoColor color) { d->foregroundColor = color; repaint(); emit foregroundColorChanged(d->foregroundColor); } void KoDualColorButton::mousePressEvent( QMouseEvent *event ) { QRect foregroundRect; QRect backgroundRect; metrics( foregroundRect, backgroundRect ); d->dragPosition = event->pos(); d->dragFlag = false; if ( foregroundRect.contains( d->dragPosition ) ) { d->tmpSelection = Foreground; d->miniCtlFlag = false; } else if( backgroundRect.contains( d->dragPosition ) ) { d->tmpSelection = Background; d->miniCtlFlag = false; } else if ( event->pos().x() > foregroundRect.width() ) { // We handle the swap and reset controls as soon as the mouse is // is pressed and ignore further events on this click (mosfet). KoColor tmp = d->foregroundColor; d->foregroundColor = d->backgroundColor; d->backgroundColor = tmp; emit backgroundColorChanged( d->backgroundColor ); emit foregroundColorChanged( d->foregroundColor ); d->miniCtlFlag = true; } else if ( event->pos().x() < backgroundRect.x() ) { d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::black); d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::white); emit backgroundColorChanged( d->backgroundColor ); emit foregroundColorChanged( d->foregroundColor ); d->miniCtlFlag = true; } repaint(); } void KoDualColorButton::mouseMoveEvent( QMouseEvent *event ) { if ( !d->miniCtlFlag ) { int delay = QApplication::startDragDistance(); if ( event->x() >= d->dragPosition.x() + delay || event->x() <= d->dragPosition.x() - delay || event->y() >= d->dragPosition.y() + delay || event->y() <= d->dragPosition.y() - delay ) { KColorMimeData::createDrag( d->tmpSelection == Foreground ? getColorFromDisplayRenderer(d->foregroundColor) : getColorFromDisplayRenderer(d->backgroundColor), this )->start(); d->dragFlag = true; } } } void KoDualColorButton::mouseReleaseEvent( QMouseEvent *event ) { d->dragFlag = false; if ( d->miniCtlFlag ) return; d->miniCtlFlag = false; QRect foregroundRect; QRect backgroundRect; metrics( foregroundRect, backgroundRect ); if (foregroundRect.contains( event->pos())) { if (d->tmpSelection == Foreground) { if (d->popDialog) { #ifndef Q_OS_OSX d->colorSelectorDialog->setPreviousColor(d->foregroundColor); //this should toggle, but I don't know how to implement that... d->colorSelectorDialog->show(); #else QColor c = d->displayRenderer->toQColor(d->foregroundColor); c = QColorDialog::getColor(c, this); if (c.isValid()) { d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(c); emit foregroundColorChanged(d->foregroundColor); } #endif } else { emit pleasePopDialog(d->foregroundColor); } } else { d->foregroundColor = d->backgroundColor; emit foregroundColorChanged( d->foregroundColor ); } } else if ( backgroundRect.contains( event->pos() )) { if(d->tmpSelection == Background ) { if( d->popDialog) { #ifndef Q_OS_OSX KoColor c = d->backgroundColor; c = KisDlgInternalColorSelector::getModalColorDialog(c, this); d->backgroundColor = c; emit backgroundColorChanged(d->backgroundColor); #else QColor c = d->displayRenderer->toQColor(d->backgroundColor); c = QColorDialog::getColor(c, this); if (c.isValid()) { d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(c); emit backgroundColorChanged(d->backgroundColor); } #endif } else emit pleasePopDialog( d->backgroundColor); } else { d->backgroundColor = d->foregroundColor; emit backgroundColorChanged( d->backgroundColor ); } } repaint(); } void KoDualColorButton::changeEvent(QEvent *event) { QWidget::changeEvent(event); switch (event->type()) { case QEvent::StyleChange: case QEvent::PaletteChange: d->updateArrows(); default: break; } } diff --git a/libs/ui/widgets/kis_iconwidget.h b/libs/ui/widgets/kis_iconwidget.h index 2e1f2732c1..b1b4f54246 100644 --- a/libs/ui/widgets/kis_iconwidget.h +++ b/libs/ui/widgets/kis_iconwidget.h @@ -1,58 +1,58 @@ /* * Copyright (c) 2000 Matthias Elter * Copyright (c) 2003 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_ICONWIDGET_H_ #define KIS_ICONWIDGET_H_ -#include +#include class KoResource; class KoAbstractResourceServerAdapter; /** * The icon widget is used in the control box where the current color and brush * are shown. */ class KisIconWidget : public KisPopupButton { Q_OBJECT public: KisIconWidget(QWidget *parent = 0, const char *name = 0); /** * Set an resource server adapter that the widget will observe. */ void setResourceAdapter(QSharedPointer adapter); public Q_SLOTS: void slotSetItem(KoResource * resource); void slotAdapterResourceChanged(KoResource * resource); void slotAdapterResourceRemoved(KoResource * resource); protected: void paintEvent(QPaintEvent *) override; private: KoResource *m_resource; QSharedPointer m_adapter; }; #endif // KIS_ICONWIDGET_H_ diff --git a/libs/ui/widgets/kis_paintop_presets_popup.cpp b/libs/ui/widgets/kis_paintop_presets_popup.cpp index 39593323eb..e17ba32d22 100644 --- a/libs/ui/widgets/kis_paintop_presets_popup.cpp +++ b/libs/ui/widgets/kis_paintop_presets_popup.cpp @@ -1,848 +1,852 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * Copyright (C) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "widgets/kis_paintop_presets_popup.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "KisResourceServerProvider.h" #include "kis_lod_availability_widget.h" #include "kis_signal_auto_connection.h" #include - // ones from brush engine selector #include #include - struct KisPaintOpPresetsPopup::Private { public: Ui_WdgPaintOpSettings uiWdgPaintOpPresetSettings; QGridLayout *layout; KisPaintOpConfigWidget *settingsWidget; QFont smallFont; KisCanvasResourceProvider *resourceProvider; KisFavoriteResourceManager *favoriteResManager; bool detached; bool ignoreHideEvents; bool isCreatingBrushFromScratch = false; QSize minimumSettingsWidgetSize; QRect detachedGeometry; KisSignalAutoConnectionsStore widgetConnections; }; KisPaintOpPresetsPopup::KisPaintOpPresetsPopup(KisCanvasResourceProvider * resourceProvider, KisFavoriteResourceManager* favoriteResourceManager, KisPresetSaveWidget* savePresetWidget, QWidget * parent) : QWidget(parent) , m_d(new Private()) { setObjectName("KisPaintOpPresetsPopup"); setFont(KoDockRegistry::dockFont()); current_paintOpId = ""; m_d->resourceProvider = resourceProvider; m_d->favoriteResManager = favoriteResourceManager; m_d->uiWdgPaintOpPresetSettings.setupUi(this); m_d->layout = new QGridLayout(m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer); m_d->layout->setSizeConstraint(QLayout::SetFixedSize); m_d->uiWdgPaintOpPresetSettings.scratchPad->setupScratchPad(resourceProvider, Qt::white); m_d->uiWdgPaintOpPresetSettings.scratchPad->setCutoutOverlayRect(QRect(25, 25, 200, 200)); m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setToolTip(i18n("The settings for this preset have changed from their default.")); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setToolTip(i18n("Toggle showing presets")); m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setToolTip(i18n("Toggle showing scratchpad")); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setToolTip(i18n("Reload the brush preset")); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setToolTip(i18n("Rename the brush preset")); // creating a new preset from scratch. Part of the brush presets area // the menu options will get filled up later when we are generating all available paintops // in the filter drop-down newPresetBrushEnginesMenu = new QMenu(); // overwrite existing preset and saving a new preset use the same dialog saveDialog = savePresetWidget; saveDialog->scratchPadSetup(resourceProvider); saveDialog->setFavoriteResourceManager(m_d->favoriteResManager); // this is needed when saving the preset saveDialog->hide(); // the area on the brush editor for renaming the brush. make sure edit fields are hidden by default toggleBrushRenameUIActive(false); // DETAIL and THUMBNAIL view changer QMenu* menu = new QMenu(this); menu->setStyleSheet("margin: 6px"); menu->addSection(i18n("Display")); QActionGroup *actionGroup = new QActionGroup(this); KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig().presetChooserViewMode(); QAction* action = menu->addAction(KisIconUtils::loadIcon("view-preview"), i18n("Thumbnails"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotThumbnailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::THUMBNAIL); action->setActionGroup(actionGroup); action = menu->addAction(KisIconUtils::loadIcon("view-list-details"), i18n("Details"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotDetailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::DETAIL); action->setActionGroup(actionGroup); // add horizontal slider for the icon size QSlider* iconSizeSlider = new QSlider(this); iconSizeSlider->setOrientation(Qt::Horizontal); iconSizeSlider->setRange(30, 80); iconSizeSlider->setValue(m_d->uiWdgPaintOpPresetSettings.presetWidget->iconSize()); iconSizeSlider->setMinimumHeight(20); iconSizeSlider->setMinimumWidth(40); iconSizeSlider->setTickInterval(10); QWidgetAction *sliderAction= new QWidgetAction(this); sliderAction->setDefaultWidget(iconSizeSlider); menu->addSection(i18n("Icon Size")); menu->addAction(sliderAction); // configure the button and assign menu m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setMenu(menu); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setPopupMode(QToolButton::InstantPopup); // loading preset from scratch option m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setPopupMode(QToolButton::InstantPopup); // show/hide buttons KisConfig cfg; m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setCheckable(true); m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setChecked(cfg.scratchpadVisible()); if (cfg.scratchpadVisible()) { slotSwitchScratchpad(true); // show scratchpad } else { slotSwitchScratchpad(false); } m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setCheckable(true); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setChecked(false); slotSwitchShowPresets(false); // hide presets by default // Connections connect(m_d->uiWdgPaintOpPresetSettings.paintPresetIcon, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(paintPresetImage())); connect(saveDialog, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); connect (m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton, SIGNAL(clicked(bool)), this, SLOT(slotRenameBrushActivated())); connect (m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton, SIGNAL(clicked(bool)), this, SLOT(slotRenameBrushDeactivated())); connect(m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveRenameCurrentBrush())); connect(m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField, SIGNAL(returnPressed()), SLOT(slotSaveRenameCurrentBrush())); connect(iconSizeSlider, SIGNAL(sliderMoved(int)), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSetIconSize(int))); connect(iconSizeSlider, SIGNAL(sliderReleased()), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSaveIconSize())); connect(m_d->uiWdgPaintOpPresetSettings.showScratchpadButton, SIGNAL(clicked(bool)), this, SLOT(slotSwitchScratchpad(bool))); connect(m_d->uiWdgPaintOpPresetSettings.showPresetsButton, SIGNAL(clicked(bool)), this, SLOT(slotSwitchShowPresets(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraseScratchPad, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillDefault())); connect(m_d->uiWdgPaintOpPresetSettings.fillLayer, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillLayer())); connect(m_d->uiWdgPaintOpPresetSettings.fillGradient, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillGradient())); connect(m_d->uiWdgPaintOpPresetSettings.fillSolid, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillBackground())); m_d->settingsWidget = 0; setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); connect(m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton, SIGNAL(clicked()), this, SLOT(slotSaveBrushPreset())); connect(m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton, SIGNAL(clicked()), this, SLOT(slotSaveNewBrushPreset())); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), this, SIGNAL(reloadPresetClicked())); connect(m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(dirtyPresetToggled(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(eraserBrushSizeToggled(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(eraserBrushOpacityToggled(bool))); // preset widget connections connect(m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SIGNAL(resourceSelected(KoResource*)), this, SIGNAL(signalResourceSelected(KoResource*))); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SLOT(updateViewSettings())); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), SLOT(slotUpdatePresetSettings())); m_d->detached = false; m_d->ignoreHideEvents = false; m_d->minimumSettingsWidgetSize = QSize(0, 0); m_d->detachedGeometry = QRect(100, 100, 0, 0); m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox->setChecked(cfg.useDirtyPresets()); m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox->setChecked(cfg.useEraserBrushSize()); m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox->setChecked(cfg.useEraserBrushOpacity()); m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setCanvasResourceManager(resourceProvider->resourceManager()); connect(resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), SLOT(slotResourceChanged(int, QVariant))); connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability, SIGNAL(sigUserChangedLodAvailability(bool)), SLOT(slotLodAvailabilityChanged(bool))); connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability, SIGNAL(sigUserChangedLodThreshold(qreal)), SLOT(slotLodThresholdChanged(qreal))); slotResourceChanged(KisCanvasResourceProvider::LodAvailability, resourceProvider->resourceManager()-> resource(KisCanvasResourceProvider::LodAvailability)); slotResourceChanged(KisCanvasResourceProvider::LodSizeThreshold, resourceProvider->resourceManager()-> resource(KisCanvasResourceProvider::LodSizeThreshold)); connect(m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatePaintOpFilter())); connect(m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset, SIGNAL(clicked()), this, SLOT(slotBlackListCurrentPreset())); updateThemedIcons(); // setup things like the scene construct images, layers, etc that is a one-time thing m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setup(); } void KisPaintOpPresetsPopup::slotBlackListCurrentPreset() { KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset(); if (rServer->resourceByName(curPreset->name())) { rServer->removeResourceAndBlacklist(curPreset); } } void KisPaintOpPresetsPopup::slotRenameBrushActivated() { toggleBrushRenameUIActive(true); } void KisPaintOpPresetsPopup::slotRenameBrushDeactivated() { toggleBrushRenameUIActive(false); } void KisPaintOpPresetsPopup::toggleBrushRenameUIActive(bool isRenaming) { // This function doesn't really do anything except get the UI in a state to rename a brush preset m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setVisible(isRenaming); m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton->setVisible(isRenaming); m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton->setVisible(isRenaming); // hide these below areas while renaming m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setEnabled(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setVisible(!isRenaming); // if the presets area is shown, only then can you show/hide the load default brush // need to think about weird state when you are in the middle of renaming a brush // what happens if you try to change presets. maybe we should auto-hide (or disable) // the presets area in this case if (m_d->uiWdgPaintOpPresetSettings.presetWidget->isVisible()) { m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(!isRenaming); } } void KisPaintOpPresetsPopup::slotSaveRenameCurrentBrush() { // if you are renaming a brush, that is different than updating the settings // make sure we are in a clean state before renaming. This logic might change, // but that is what we are going with for now emit reloadPresetClicked(); m_d->favoriteResManager->setBlockUpdates(true); // get a reference to the existing (and new) file name and path that we are working with KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset(); if (!curPreset) return; KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QString saveLocation = rServer->saveLocation(); QString originalPresetName = curPreset->name(); QString renamedPresetName = m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->text(); QString originalPresetPathAndFile = saveLocation + originalPresetName + curPreset->defaultFileExtension(); QString renamedPresetPathAndFile = saveLocation + renamedPresetName + curPreset->defaultFileExtension(); // create a new brush preset with the name specified and add to resource provider KisPaintOpPresetSP newPreset = curPreset->clone(); newPreset->setFilename(renamedPresetPathAndFile); // this also contains the path newPreset->setName(renamedPresetName); newPreset->setImage(curPreset->image()); // use existing thumbnail (might not need to do this) newPreset->setPresetDirty(false); newPreset->setValid(true); rServer->addResource(newPreset); resourceSelected(newPreset.data()); // refresh and select our freshly renamed resource // Now blacklist the original file if (rServer->resourceByName(originalPresetName)) { rServer->removeResourceAndBlacklist(curPreset); } m_d->favoriteResManager->setBlockUpdates(false); toggleBrushRenameUIActive(false); // this returns the UI to its original state after saving slotUpdatePresetSettings(); // update visibility of dirty preset and icon } void KisPaintOpPresetsPopup::slotResourceChanged(int key, const QVariant &value) { if (key == KisCanvasResourceProvider::LodAvailability) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodAvailability(value.toBool()); } else if (key == KisCanvasResourceProvider::LodSizeThreshold) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodThreshold(value.toDouble()); } else if (key == KisCanvasResourceProvider::Size) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedSize(value.toDouble()); } } void KisPaintOpPresetsPopup::slotLodAvailabilityChanged(bool value) { m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodAvailability, QVariant(value)); } void KisPaintOpPresetsPopup::slotLodThresholdChanged(qreal value) { m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodSizeThreshold, QVariant(value)); } KisPaintOpPresetsPopup::~KisPaintOpPresetsPopup() { if (m_d->settingsWidget) { m_d->layout->removeWidget(m_d->settingsWidget); m_d->settingsWidget->hide(); m_d->settingsWidget->setParent(0); m_d->settingsWidget = 0; } delete m_d; delete newPresetBrushEnginesMenu; } void KisPaintOpPresetsPopup::setPaintOpSettingsWidget(QWidget * widget) { if (m_d->settingsWidget) { m_d->layout->removeWidget(m_d->settingsWidget); m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer->updateGeometry(); } m_d->layout->update(); updateGeometry(); m_d->widgetConnections.clear(); m_d->settingsWidget = 0; if (widget) { m_d->settingsWidget = dynamic_cast(widget); KIS_ASSERT_RECOVER_RETURN(m_d->settingsWidget); KisConfig cfg; if (m_d->settingsWidget->supportScratchBox() && cfg.scratchpadVisible()) { slotSwitchScratchpad(true); } else { slotSwitchScratchpad(false); } m_d->widgetConnections.addConnection(m_d->settingsWidget, SIGNAL(sigConfigurationItemChanged()), this, SLOT(slotUpdateLodAvailability())); widget->setFont(m_d->smallFont); QSize hint = widget->sizeHint(); m_d->minimumSettingsWidgetSize = QSize(qMax(hint.width(), m_d->minimumSettingsWidgetSize.width()), qMax(hint.height(), m_d->minimumSettingsWidgetSize.height())); widget->setMinimumSize(m_d->minimumSettingsWidgetSize); m_d->layout->addWidget(widget); // hook up connections that will monitor if our preset is dirty or not. Show a notification if it is if (m_d->resourceProvider && m_d->resourceProvider->currentPreset() ) { KisPaintOpPresetSP preset = m_d->resourceProvider->currentPreset(); m_d->widgetConnections.addConnection(preset->updateProxy(), SIGNAL(sigSettingsChanged()), this, SLOT(slotUpdatePresetSettings())); } m_d->layout->update(); widget->show(); } slotUpdateLodAvailability(); } void KisPaintOpPresetsPopup::slotUpdateLodAvailability() { if (!m_d->settingsWidget) return; KisPaintopLodLimitations l = m_d->settingsWidget->lodLimitations(); m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setLimitations(l); } QImage KisPaintOpPresetsPopup::cutOutOverlay() { return m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay(); } void KisPaintOpPresetsPopup::contextMenuEvent(QContextMenuEvent *e) { Q_UNUSED(e); } void KisPaintOpPresetsPopup::switchDetached(bool show) { if (parentWidget()) { m_d->detached = !m_d->detached; if (m_d->detached) { m_d->ignoreHideEvents = true; if (show) { parentWidget()->show(); } m_d->ignoreHideEvents = false; } else { KisConfig cfg; parentWidget()->hide(); } KisConfig cfg; cfg.setPaintopPopupDetached(m_d->detached); } } void KisPaintOpPresetsPopup::setCreatingBrushFromScratch(bool enabled) { m_d->isCreatingBrushFromScratch = enabled; } void KisPaintOpPresetsPopup::resourceSelected(KoResource* resource) { // this gets called every time the brush editor window is opened // TODO: this gets called multiple times whenever the preset is changed in the presets area // the connections probably need to be thought about with this a bit more to keep things in sync m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(resource); // find the display name of the brush engine and append it to the selected preset display QString currentBrushEngineName; QPixmap currentBrushEngineIcon = QPixmap(26, 26); currentBrushEngineIcon.fill(Qt::transparent); for(int i=0; i < sortedBrushEnginesList.length(); i++) { if (sortedBrushEnginesList.at(i).id == currentPaintOpId() ) { currentBrushEngineName = sortedBrushEnginesList.at(i).name; currentBrushEngineIcon = sortedBrushEnginesList.at(i).icon.pixmap(26, 26); } } // brush names have underscores as part of the file name (to help with building). We don't really need underscores // when viewing the names, so replace them with spaces QString formattedBrushName = resource->name().replace("_", " "); m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setText(formattedBrushName); m_d->uiWdgPaintOpPresetSettings.currentBrushEngineLabel->setText(i18nc("%1 is the name of a brush engine", "%1 Engine", currentBrushEngineName)); m_d->uiWdgPaintOpPresetSettings.currentBrushEngineIcon->setPixmap(currentBrushEngineIcon); m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setText(resource->name()); // use file name // get the preset image and pop it into the thumbnail area on the top of the brush editor m_d->uiWdgPaintOpPresetSettings.presetThumbnailicon->setPixmap(QPixmap::fromImage(resource->image().scaled(55, 55, Qt::KeepAspectRatio, Qt::SmoothTransformation))); toggleBrushRenameUIActive(false); // reset the UI state of renaming a brush if we are changing brush presets slotUpdatePresetSettings(); // check to see if the dirty preset icon needs to be shown } bool variantLessThan(const KisPaintOpInfo v1, const KisPaintOpInfo v2) { return v1.priority < v2.priority; } void KisPaintOpPresetsPopup::setPaintOpList(const QList< KisPaintOpFactory* >& list) { m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->clear(); // reset combobox list just in case // create a new list so we can sort it and populate the brush engine combo box sortedBrushEnginesList.clear(); // just in case this function is called again, don't keep adding to the list for(int i=0; i < list.length(); i++) { KisPaintOpInfo paintOpInfo; paintOpInfo.id = list.at(i)->id(); paintOpInfo.name = list.at(i)->name(); paintOpInfo.icon = list.at(i)->icon(); paintOpInfo.priority = list.at(i)->priority(); sortedBrushEnginesList.append(paintOpInfo); } std::stable_sort(sortedBrushEnginesList.begin(), sortedBrushEnginesList.end(), variantLessThan ); // add an "All" option at the front to show all presets QPixmap emptyPixmap = QPixmap(22,22); emptyPixmap.fill(Qt::transparent); // if we create a new brush from scratch, we need a full list of paintops to choose from // we don't want "All", so populate the list before that is added newPresetBrushEnginesMenu->actions().clear(); // clean out list in case we run this again newBrushEngineOptions.clear(); for (int j = 0; j < sortedBrushEnginesList.length(); j++) { KisAction * newEngineAction = static_cast( newPresetBrushEnginesMenu->addAction(sortedBrushEnginesList[j].name)); newEngineAction->setObjectName(sortedBrushEnginesList[j].id); // we need the ID for changing the paintop when action triggered newEngineAction->setIcon(sortedBrushEnginesList[j].icon); newBrushEngineOptions.append(newEngineAction); connect(newEngineAction, SIGNAL(triggered()), this, SLOT(slotCreateNewBrushPresetEngine())); } m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setMenu(newPresetBrushEnginesMenu); // fill the list into the brush combo box sortedBrushEnginesList.push_front(KisPaintOpInfo(QString("all_options"), i18n("All"), QString(""), QIcon(emptyPixmap), 0 )); for (int m = 0; m < sortedBrushEnginesList.length(); m++) { m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->addItem(sortedBrushEnginesList[m].icon, sortedBrushEnginesList[m].name, QVariant(sortedBrushEnginesList[m].id)); } } void KisPaintOpPresetsPopup::setCurrentPaintOpId(const QString& paintOpId) { current_paintOpId = paintOpId; } QString KisPaintOpPresetsPopup::currentPaintOpId() { return current_paintOpId; } void KisPaintOpPresetsPopup::setPresetImage(const QImage& image) { m_d->uiWdgPaintOpPresetSettings.scratchPad->setPresetImage(image); saveDialog->brushPresetThumbnailWidget->setPresetImage(image); } void KisPaintOpPresetsPopup::hideEvent(QHideEvent *event) { if (m_d->ignoreHideEvents) { return; } if (m_d->detached) { m_d->detachedGeometry = window()->geometry(); } QWidget::hideEvent(event); } void KisPaintOpPresetsPopup::showEvent(QShowEvent *) { if (m_d->detached) { window()->setGeometry(m_d->detachedGeometry); } emit brushEditorShown(); } void KisPaintOpPresetsPopup::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); - emit sizeChanged(); + if (parentWidget()) { + // Make sure resizing doesn't push this widget out of the screen + QRect screenRect = QApplication::desktop()->availableGeometry(this); + QRect newPositionRect = kisEnsureInRect(parentWidget()->geometry(), screenRect); + parentWidget()->setGeometry(newPositionRect); + } } bool KisPaintOpPresetsPopup::detached() const { return m_d->detached; } void KisPaintOpPresetsPopup::slotSwitchScratchpad(bool visible) { // hide all the internal controls except the toggle button m_d->uiWdgPaintOpPresetSettings.scratchPad->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillGradient->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillLayer->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillSolid->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.scratchpadSidebarLabel->setVisible(visible); if (visible) { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } else { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } KisConfig cfg; cfg.setScratchpadVisible(visible); } void KisPaintOpPresetsPopup::slotSwitchShowEditor(bool visible) { m_d->uiWdgPaintOpPresetSettings.brushEditorSettingsControls->setVisible(visible); } void KisPaintOpPresetsPopup::slotSwitchShowPresets(bool visible) { m_d->uiWdgPaintOpPresetSettings.presetWidget->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.engineFilterLabel->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(visible); // we only want a spacer to work when the toggle icon is present. Otherwise the list of presets will shrink // which is something we don't want if (visible) { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } else { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } } void KisPaintOpPresetsPopup::slotUpdatePaintOpFilter() { QVariant userData = m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->currentData(); // grab paintOpID from data QString filterPaintOpId = userData.toString(); if (filterPaintOpId == "all_options") { filterPaintOpId = ""; } m_d->uiWdgPaintOpPresetSettings.presetWidget->setPresetFilter(filterPaintOpId); } void KisPaintOpPresetsPopup::slotSaveBrushPreset() { // here we are assuming that people want to keep their existing preset icon. We will just update the // settings and save a new copy with the same name. // there is a dialog with save options, but we don't need to show it in this situation saveDialog->useNewBrushDialog(false); // this mostly just makes sure we keep the existing brush preset name when saving saveDialog->loadExistingThumbnail(); // This makes sure we use the existing preset icon when updating the existing brush preset saveDialog->savePreset(); // refresh the view settings so the brush doesn't appear dirty slotUpdatePresetSettings(); } void KisPaintOpPresetsPopup::slotSaveNewBrushPreset() { saveDialog->useNewBrushDialog(true); saveDialog->saveScratchPadThumbnailArea(m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay()); saveDialog->showDialog(); } void KisPaintOpPresetsPopup::slotCreateNewBrushPresetEngine() { emit createPresetFromScratch(sender()->objectName()); } void KisPaintOpPresetsPopup::updateViewSettings() { m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->updateViewSettings(); } void KisPaintOpPresetsPopup::currentPresetChanged(KisPaintOpPresetSP preset) { if (preset) { m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(preset.data()); setCurrentPaintOpId(preset->paintOp().id()); } } void KisPaintOpPresetsPopup::updateThemedIcons() { m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setIcon(KisIconUtils::loadIcon("krita_tool_freehand")); m_d->uiWdgPaintOpPresetSettings.fillLayer->setIcon(KisIconUtils::loadIcon("document-new")); m_d->uiWdgPaintOpPresetSettings.fillLayer->hide(); m_d->uiWdgPaintOpPresetSettings.fillGradient->setIcon(KisIconUtils::loadIcon("krita_tool_gradient")); m_d->uiWdgPaintOpPresetSettings.fillSolid->setIcon(KisIconUtils::loadIcon("krita_tool_color_fill")); m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setIcon(KisIconUtils::loadIcon("edit-delete")); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer")); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer")); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setIcon(KisIconUtils::loadIcon("updateColorize")); // refresh icon m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setIcon(KisIconUtils::loadIcon("dirty-preset")); // edit icon m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setIcon(KisIconUtils::loadIcon("warning")); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer")); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer")); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setIcon(KisIconUtils::loadIcon("configure")); // if we cannot see the "Preset label", we know it is not visible // maybe this can also be stored in the config like the scratchpad? if (m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->isVisible()) { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } else { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } // we store whether the scratchpad if visible in the config. KisConfig cfg; if (cfg.scratchpadVisible()) { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } else { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } } void KisPaintOpPresetsPopup::slotUpdatePresetSettings() { if (!m_d->resourceProvider) { return; } if (!m_d->resourceProvider->currentPreset()) { return; } // hide options on UI if we are creating a brush preset from scratch to prevent confusion if (m_d->isCreatingBrushFromScratch) { m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(false); } else { bool isPresetDirty = m_d->resourceProvider->currentPreset()->isPresetDirty(); // don't need to reload or overwrite a clean preset m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(true); } // update live preview area in here... // don't update the live preview if the widget is not visible. if (m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->isVisible()) { m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setCurrentPreset(m_d->resourceProvider->currentPreset()); m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->updateStroke(); } } diff --git a/libs/ui/widgets/kis_paintop_presets_popup.h b/libs/ui/widgets/kis_paintop_presets_popup.h index e9f951f333..fea64cc57d 100644 --- a/libs/ui/widgets/kis_paintop_presets_popup.h +++ b/libs/ui/widgets/kis_paintop_presets_popup.h @@ -1,148 +1,147 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_PRESETS_POPUP_H #define KIS_PAINTOP_PRESETS_POPUP_H #include #include #include #include #include #include "../kis_paint_ops_model.h" #include #include #include "widgets/kis_paintop_presets_popup.h" #include "kis_favorite_resource_manager.h" class QString; class KisCanvasResourceProvider; class KoResource; /** * Popup widget for presets with built-in functionality * for adding and removing presets. */ class KisPaintOpPresetsPopup : public QWidget { Q_OBJECT public: KisPaintOpPresetsPopup(KisCanvasResourceProvider * resourceProvider, KisFavoriteResourceManager* favoriteResourceManager, KisPresetSaveWidget* savePresetWidget, QWidget * parent = 0); ~KisPaintOpPresetsPopup() override; void setPaintOpSettingsWidget(QWidget * widget); ///Image for preset preview ///@return image cut out from the scratchpad QImage cutOutOverlay(); void setPaintOpList(const QList& list); void setCurrentPaintOpId(const QString & paintOpId); /// returns the internal ID for the paint op (brush engine) QString currentPaintOpId(); ///fill the cutoutOverlay rect with the cotent of an image, used to get the image back when selecting a preset ///@param image image that will be used, should be image of an existing preset resource void setPresetImage(const QImage& image); void resizeEvent(QResizeEvent* ) override; bool detached() const; void updateViewSettings(); void currentPresetChanged(KisPaintOpPresetSP preset); KisPresetSaveWidget * saveDialog; // toggle the state when we are creating a brush from scratch void setCreatingBrushFromScratch(bool enable); protected: void contextMenuEvent(QContextMenuEvent *) override; void hideEvent(QHideEvent *) override; void showEvent(QShowEvent *) override; public Q_SLOTS: void switchDetached(bool show = true); void resourceSelected(KoResource* resource); void updateThemedIcons(); void slotUpdatePresetSettings(); void slotUpdateLodAvailability(); void slotRenameBrushActivated(); void slotRenameBrushDeactivated(); void slotSaveRenameCurrentBrush(); void slotCreateNewBrushPresetEngine(); Q_SIGNALS: void savePresetClicked(); void saveBrushPreset(); void defaultPresetClicked(); void paintopActivated(const QString& presetName); void signalResourceSelected(KoResource* resource); void reloadPresetClicked(); void dirtyPresetToggled(bool value); void eraserBrushSizeToggled(bool value); void eraserBrushOpacityToggled(bool value); - void sizeChanged(); void brushEditorShown(); void createPresetFromScratch(const QString& paintOpName); private Q_SLOTS: void slotSwitchScratchpad(bool visible); void slotResourceChanged(int key, const QVariant &value); void slotLodAvailabilityChanged(bool value); void slotLodThresholdChanged(qreal value); void slotSwitchShowEditor(bool visible); void slotUpdatePaintOpFilter(); void slotSwitchShowPresets(bool visible); void slotSaveBrushPreset(); void slotSaveNewBrushPreset(); /// we do not delete brushe presets, but blacklist them so they disappear from the interface void slotBlackListCurrentPreset(); private: struct Private; Private * const m_d; QString current_paintOpId; QList sortedBrushEnginesList; QMenu * newPresetBrushEnginesMenu; QList newBrushEngineOptions; void toggleBrushRenameUIActive(bool isRenaming); }; #endif diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt index ed5154ef13..c39c5ab054 100644 --- a/libs/widgets/CMakeLists.txt +++ b/libs/widgets/CMakeLists.txt @@ -1,109 +1,143 @@ add_subdirectory( tests ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(kritawidgets_LIB_SRCS KoGradientEditWidget.cpp KoVBox.cpp KoDialog.cpp KoZoomWidget.cpp KoTagToolButton.cpp KoTagChooserWidget.cpp KoTagFilterWidget.cpp KoResourceTaggingManager.cpp KoResourceItemChooserContextMenu.cpp KoAspectButton.cpp KoPagePreviewWidget.cpp KoSliderCombo.cpp KoColorPopupButton.cpp KoConfigAuthorPage.cpp KoUnitDoubleSpinBox.cpp KoZoomAction.cpp KoZoomController.cpp KoZoomInput.cpp KoZoomHandler.cpp KoZoomMode.cpp KoDpi.cpp KoColorPatch.cpp KoColorPopupAction.cpp KoColorSetWidget.cpp KoColorSlider.cpp KoEditColorSetDialog.cpp KoTriangleColorSelector.cpp KoResourcePopupAction.cpp KoIconToolTip.cpp KoResourceItemChooser.cpp KoResourceItemChooserSync.cpp KoResourceSelector.cpp KoResourceModel.cpp KoResourceItemDelegate.cpp KoResourceItemView.cpp KoResourceTagStore.cpp KoRuler.cpp KoItemToolTip.cpp KoCheckerBoardPainter.cpp KoResourceServerAdapter.cpp KoResourceServerProvider.cpp KoLineStyleSelector.cpp KoLineStyleItemDelegate.cpp KoLineStyleModel.cpp KoResourceFiltering.cpp KoTitledTabWidget.cpp KoToolBoxButton.cpp KoToolBox.cpp KoToolBoxDocker.cpp KoToolBoxFactory.cpp KoToolDocker.cpp - + + KisPaletteModel.cpp + kis_palette_delegate.cpp + kis_palette_view.cpp KoPageLayoutWidget.cpp KoPageLayoutDialog.cpp KoShadowConfigWidget.cpp KoMarkerSelector.cpp KoMarkerModel.cpp KoMarkerItemDelegate.cpp KoDocumentInfoDlg.cpp KoTableView.cpp WidgetsDebug.cpp kis_file_name_requester.cpp kis_double_parse_spin_box.cpp kis_double_parse_unit_spin_box.cpp kis_int_parse_spin_box.cpp KisColorSelectorInterface.cpp KoAnchorSelectionWidget.cpp squeezedcombobox.cpp KisGradientSlider.cpp KisGradientSliderWidget.cpp + + kis_color_input.cpp + + kis_spinbox_color_selector.cpp + + KisDlgInternalColorSelector.cpp + + KisVisualColorSelector.cpp + KisVisualColorSelectorShape.cpp + KisVisualEllipticalSelectorShape.cpp + KisVisualRectangleSelectorShape.cpp + KisVisualTriangleSelectorShape.cpp + kis_popup_button.cc + kis_color_button.cpp + KisScreenColorPickerBase.cpp + + KisColorsetChooser.cpp ) ki18n_wrap_ui( kritawidgets_LIB_SRCS KoConfigAuthorPage.ui koDocumentInfoAboutWidget.ui koDocumentInfoAuthorWidget.ui KoEditColorSet.ui wdg_file_name_requester.ui KoPageLayoutWidget.ui KoShadowConfigWidget.ui + WdgDlgInternalColorSelector.ui ) add_library(kritawidgets SHARED ${kritawidgets_LIB_SRCS}) generate_export_header(kritawidgets BASE_NAME kritawidgets) -target_link_libraries(kritawidgets kritaodf kritaflake kritapigment kritawidgetutils Qt5::PrintSupport KF5::CoreAddons KF5::ConfigGui KF5::GuiAddons KF5::WidgetsAddons KF5::ConfigCore KF5::Completion) +target_link_libraries(kritawidgets + kritaodf + kritaglobal + kritaflake + kritapigment + kritawidgetutils + Qt5::PrintSupport + KF5::CoreAddons + KF5::ConfigGui + KF5::GuiAddons + KF5::WidgetsAddons + KF5::ConfigCore + KF5::Completion +) if(X11_FOUND) target_link_libraries(kritawidgets Qt5::X11Extras ${X11_LIBRARIES}) endif() set_target_properties(kritawidgets PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritawidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/ui/widgets/KisColorSelectorConfiguration.h b/libs/widgets/KisColorSelectorConfiguration.h similarity index 96% rename from libs/ui/widgets/KisColorSelectorConfiguration.h rename to libs/widgets/KisColorSelectorConfiguration.h index 3076d381d5..a58312ccbe 100644 --- a/libs/ui/widgets/KisColorSelectorConfiguration.h +++ b/libs/widgets/KisColorSelectorConfiguration.h @@ -1,82 +1,82 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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_COLOR_SELECTOR_CONFIGURATION_H #define KIS_COLOR_SELECTOR_CONFIGURATION_H #include #include -#include "kritaui_export.h" +#include "kritawidgets_export.h" -class KRITAUI_EXPORT KisColorSelectorConfiguration { +class KRITAWIDGETS_EXPORT KisColorSelectorConfiguration { public: enum Type {Ring, Square, Wheel, Triangle, Slider}; enum Parameters {H, hsvS, V, hslS, L, SL, SV, SV2, hsvSH, hslSH, VH, LH, SI, SY, hsiSH, hsySH, I, Y, IH, YH, hsiS, hsyS}; Type mainType; Type subType; Parameters mainTypeParameter; Parameters subTypeParameter; KisColorSelectorConfiguration(Type mainT = Triangle, Type subT = Ring, Parameters mainTP = SL, Parameters subTP = H) : mainType(mainT) , subType(subT) , mainTypeParameter(mainTP) , subTypeParameter(subTP) { } KisColorSelectorConfiguration(QString string) { readString(string); } QString toString() const { return QString("%1|%2|%3|%4").arg(mainType).arg(subType).arg(mainTypeParameter).arg(subTypeParameter); } void readString(QString string) { QStringList strili = string.split('|'); if(strili.length()!=4) return; int imt=strili.at(0).toInt(); int ist=strili.at(1).toInt(); int imtp=strili.at(2).toInt(); int istp=strili.at(3).toInt(); if(imt>Slider || ist>Slider || imtp>hsyS || istp>hsyS)//this was LH before return; mainType = Type(imt); subType = Type(ist); mainTypeParameter = Parameters(imtp); subTypeParameter = Parameters(istp); } static KisColorSelectorConfiguration fromString(QString string) { KisColorSelectorConfiguration ret; ret.readString(string); return ret; } }; #endif diff --git a/libs/ui/KisColorsetChooser.cpp b/libs/widgets/KisColorsetChooser.cpp similarity index 94% rename from libs/ui/KisColorsetChooser.cpp rename to libs/widgets/KisColorsetChooser.cpp index 7cbee899b0..e805854e59 100644 --- a/libs/ui/KisColorsetChooser.cpp +++ b/libs/widgets/KisColorsetChooser.cpp @@ -1,166 +1,162 @@ /* This file is part of the KDE project * Copyright (C) 2013 Sven Langkamp * * 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 "KisColorsetChooser.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include "KisResourceServerProvider.h" -#include "KisViewManager.h" #include #include #include #include -#include - #include "kis_int_parse_spin_box.h" class ColorSetDelegate : public QAbstractItemDelegate { public: ColorSetDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~ColorSetDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void ColorSetDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { painter->save(); if (! index.isValid()) return; KoResource* resource = static_cast(index.internalPointer()); KoColorSet* colorSet = static_cast(resource); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); painter->setPen(option.palette.highlightedText().color()); } else { painter->setBrush(option.palette.text().color()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, colorSet->name()); int size = 7; for (quint32 i = 0; i < colorSet->nColors() && i*size < (quint32)option.rect.width(); i++) { QRect rect(option.rect.x() + i*size, option.rect.y() + option.rect.height() - size, size, size); painter->fillRect(rect, colorSet->getColorGlobal(i).color().toQColor()); } painter->restore(); } KisColorsetChooser::KisColorsetChooser(QWidget* parent): QWidget(parent) { KoResourceServer * rserver = KoResourceServerProvider::instance()->paletteServer(); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setItemDelegate(new ColorSetDelegate(this)); m_itemChooser->showTaggingBar(true); m_itemChooser->setFixedSize(250, 250); m_itemChooser->setRowHeight(30); m_itemChooser->setColumnCount(1); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); - KisConfig cfg; - m_itemChooser->configureKineticScrolling(cfg.kineticScrollingGesture(), - cfg.kineticScrollingSensitivity(), - cfg.kineticScrollingScrollbar()); + KConfigGroup cfg = KSharedConfig::openConfig()->group(""); + m_itemChooser->configureKineticScrolling(cfg.readEntry("KineticScrollingGesture", 0), + cfg.readEntry("KineticScrollingSensitivity", 75), + cfg.readEntry("KineticScrollingScrollbar", true)); QPushButton* saveButton = new QPushButton(i18n("Save")); connect(saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSave())); m_nameEdit = new QLineEdit(this); m_nameEdit->setPlaceholderText(i18n("Insert name")); m_nameEdit->setClearButtonEnabled(true); m_columnEdit = new KisIntParseSpinBox(this); m_columnEdit->setRange(1, 30); m_columnEdit->setValue(10); QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_itemChooser, 0, 0, 1, 3); layout->setColumnStretch(1, 1); layout->addWidget(saveButton, 2, 2, 1, 1); layout->addWidget(m_nameEdit, 1, 1, 1, 2); layout->addWidget(new QLabel(i18n("Name:"), this), 1, 0, 1, 1); layout->addWidget(m_columnEdit, 2, 1, 1, 1); layout->addWidget(new QLabel(i18n("Columns:"), this), 2, 0, 1, 1); } KisColorsetChooser::~KisColorsetChooser() { } void KisColorsetChooser::resourceSelected(KoResource* resource) { emit paletteSelected(static_cast(resource)); } void KisColorsetChooser::slotSave() { KoResourceServer * rserver = KoResourceServerProvider::instance()->paletteServer(); KoColorSet* colorset = new KoColorSet(); colorset->setValid(true); QString saveLocation = rserver->saveLocation(); QString name = m_nameEdit->text(); int columns = m_columnEdit->value(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Palette"); } QFileInfo fileInfo(saveLocation + name + colorset->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + colorset->defaultFileExtension()); i++; } colorset->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Palette %1", i); } colorset->setName(name); colorset->setColumnCount(columns); rserver->addResource(colorset); } diff --git a/libs/ui/KisColorsetChooser.h b/libs/widgets/KisColorsetChooser.h similarity index 93% rename from libs/ui/KisColorsetChooser.h rename to libs/widgets/KisColorsetChooser.h index 284f64a788..f51cdda0f6 100644 --- a/libs/ui/KisColorsetChooser.h +++ b/libs/widgets/KisColorsetChooser.h @@ -1,55 +1,55 @@ /* This file is part of the KDE project * Copyright (C) 2013 Sven Langkamp * * 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_COLORSET_CHOOSER_H #define KIS_COLORSET_CHOOSER_H #include class QSpinBox; class KoColorSet; class QLineEdit; class KoResourceItemChooser; class KoResource; -#include "kritaui_export.h" +#include "kritawidgets_export.h" -class KRITAUI_EXPORT KisColorsetChooser : public QWidget +class KRITAWIDGETS_EXPORT KisColorsetChooser : public QWidget { Q_OBJECT public: KisColorsetChooser(QWidget* parent = 0); ~KisColorsetChooser() override; Q_SIGNALS: void paletteSelected(KoColorSet* colorSet); private Q_SLOTS: void resourceSelected(KoResource* resource); void slotSave(); private: KoResourceItemChooser * m_itemChooser; QLineEdit* m_nameEdit; QSpinBox* m_columnEdit; }; #endif // COLORSET_CHOOSER_H diff --git a/libs/ui/dialogs/kis_dlg_internal_color_selector.cpp b/libs/widgets/KisDlgInternalColorSelector.cpp similarity index 90% rename from libs/ui/dialogs/kis_dlg_internal_color_selector.cpp rename to libs/widgets/KisDlgInternalColorSelector.cpp index f77bfceff2..01d5427506 100644 --- a/libs/ui/dialogs/kis_dlg_internal_color_selector.cpp +++ b/libs/widgets/KisDlgInternalColorSelector.cpp @@ -1,378 +1,392 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include +#include + +#include + #include "KoColorSpaceRegistry.h" #include #include #include #include #include #include #include "kis_signal_compressor.h" -#include "KisViewManager.h" #include "KoColorDisplayRendererInterface.h" #include "kis_spinbox_color_selector.h" -#include "kis_dlg_internal_color_selector.h" -#include "ui_wdgdlginternalcolorselector.h" -#include "kis_config.h" +#include "KisDlgInternalColorSelector.h" +#include "ui_WdgDlgInternalColorSelector.h" #include "kis_config_notifier.h" #include "kis_color_input.h" #include "kis_icon_utils.h" #include "squeezedcombobox.h" +std::function KisDlgInternalColorSelector::s_screenColorPickerFactory = 0; + struct KisDlgInternalColorSelector::Private { bool allowUpdates = true; KoColor currentColor; KoColor previousColor; KoColor sRGB = KoColor(KoColorSpaceRegistry::instance()->rgb8()); const KoColorSpace *currentColorSpace; bool lockUsedCS = false; bool chooseAlpha = false; KisSignalCompressor *compressColorChanges; const KoColorDisplayRendererInterface *displayRenderer; KisHexColorInput *hexColorInput = 0; KisPaletteModel *paletteModel = 0; KisColorsetChooser *colorSetChooser = 0; + KisScreenColorPickerBase *screenColorPicker = 0; }; KisDlgInternalColorSelector::KisDlgInternalColorSelector(QWidget *parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer) : QDialog(parent) , m_d(new Private) { setModal(config.modal); this->setFocusPolicy(Qt::ClickFocus); m_ui = new Ui_WdgDlgInternalColorSelector(); m_ui->setupUi(this); setWindowTitle(caption); m_d->currentColor = color; m_d->currentColorSpace = m_d->currentColor.colorSpace(); m_d->displayRenderer = displayRenderer; m_ui->spinboxselector->slotSetColor(color); connect(m_ui->spinboxselector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); m_ui->visualSelector->slotSetColor(color); m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->visualSelector->setConfig(false, config.modal); if (config.visualColorSelector) { connect(m_ui->visualSelector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_ui->visualSelector, SLOT(configurationChanged())); } else { m_ui->visualSelector->hide(); } - if (config.screenColorPicker) { - connect(m_ui->screenColorPicker, SIGNAL(sigNewColorPicked(KoColor)),this, SLOT(slotColorUpdated(KoColor))); - } else { - m_ui->screenColorPicker->hide(); - } if (!m_d->paletteModel) { m_d->paletteModel = new KisPaletteModel(this); m_ui->paletteBox->setPaletteModel(m_d->paletteModel); } - m_ui->paletteList->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); + m_ui->bnColorsetChooser->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); // For some bizare reason, the modal dialog doesn't like having the colorset set, so let's not. if (config.paletteBox) { //TODO: Add disable signal as well. Might be not necessary...? - KisConfig cfg; + KConfigGroup cfg(KSharedConfig::openConfig()->group("")); QString paletteName = cfg.readEntry("internal_selector_active_color_set", QString()); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); KoColorSet *savedPal = rServer->resourceByName(paletteName); if (savedPal) { this->slotChangePalette(savedPal); } else { Q_ASSERT(rServer->resources().count()); if (rServer->resources().count()) { savedPal = rServer->resources().first(); if (savedPal) { this->slotChangePalette(savedPal); } } } connect(m_ui->paletteBox, SIGNAL(entrySelected(KoColorSetEntry)), this, SLOT(slotSetColorFromColorSetEntry(KoColorSetEntry))); connect(m_ui->cmbNameList, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetColorFromColorList())); //m_ui->paletteBox->setDisplayRenderer(displayRenderer); m_d->colorSetChooser = new KisColorsetChooser(this); connect(m_d->colorSetChooser, SIGNAL(paletteSelected(KoColorSet*)), this, SLOT(slotChangePalette(KoColorSet*))); - m_ui->paletteList->setPopupWidget(m_d->colorSetChooser); + m_ui->bnColorsetChooser->setPopupWidget(m_d->colorSetChooser); } else { m_ui->paletteBox->setEnabled(false); m_ui->cmbNameList->setEnabled(false); - m_ui->paletteList->setEnabled(false); + m_ui->bnColorsetChooser->setEnabled(false); } if (config.prevNextButtons) { m_ui->currentColor->setColor(m_d->currentColor); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setColor(m_d->currentColor); m_ui->previousColor->setDisplayRenderer(displayRenderer); connect(m_ui->previousColor, SIGNAL(triggered(KoColorPatch*)), SLOT(slotSetColorFromPatch(KoColorPatch*))); } else { m_ui->currentColor->hide(); m_ui->previousColor->hide(); } if (config.hexInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput = new KisHexColorInput(this, &m_d->sRGB); m_d->hexColorInput->update(); connect(m_d->hexColorInput, SIGNAL(updated()), SLOT(slotSetColorFromHex())); m_ui->rightPane->addWidget(m_d->hexColorInput); m_d->hexColorInput->setToolTip(i18n("This is a hexcode input, for webcolors. It can only get colors in the sRGB space.")); } + // screen color picker is in kritaui, so a dependency inversion is used to get it + m_ui->screenColorPickerWidget->setLayout(new QHBoxLayout(m_ui->screenColorPickerWidget)); + if (s_screenColorPickerFactory) { + m_d->screenColorPicker = s_screenColorPickerFactory(m_ui->screenColorPickerWidget); + m_ui->screenColorPickerWidget->layout()->addWidget(m_d->screenColorPicker); + if (config.screenColorPicker) { + connect(m_d->screenColorPicker, SIGNAL(sigNewColorPicked(KoColor)),this, SLOT(slotColorUpdated(KoColor))); + } else { + m_d->screenColorPicker->hide(); + } + } + connect(this, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotLockSelector())); m_d->compressColorChanges = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); connect(m_d->compressColorChanges, SIGNAL(timeout()), this, SLOT(endUpdateWithNewColor())); connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(this, SIGNAL(finished(int)), SLOT(slotFinishUp())); } KisDlgInternalColorSelector::~KisDlgInternalColorSelector() { delete m_ui; } void KisDlgInternalColorSelector::slotColorUpdated(KoColor newColor) { //if the update did not come from this selector... if (m_d->allowUpdates || QObject::sender() == this->parent()) { if (m_d->lockUsedCS){ newColor.convertTo(m_d->currentColorSpace); m_d->currentColor = newColor; } else { m_d->currentColor = newColor; } updateAllElements(QObject::sender()); } } void KisDlgInternalColorSelector::slotSetColorFromPatch(KoColorPatch *patch) { slotColorUpdated(patch->color()); } void KisDlgInternalColorSelector::colorSpaceChanged(const KoColorSpace *cs) { if (cs == m_d->currentColorSpace) { return; } m_d->currentColorSpace = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile()); m_ui->spinboxselector->slotSetColorSpace(m_d->currentColorSpace); m_ui->visualSelector->slotsetColorSpace(m_d->currentColorSpace); } void KisDlgInternalColorSelector::lockUsedColorSpace(const KoColorSpace *cs) { colorSpaceChanged(cs); m_d->lockUsedCS = true; } void KisDlgInternalColorSelector::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { m_d->displayRenderer = displayRenderer; m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setDisplayRenderer(displayRenderer); //m_ui->paletteBox->setDisplayRenderer(displayRenderer); } else { m_d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } } KoColor KisDlgInternalColorSelector::getModalColorDialog(const KoColor color, QWidget* parent, QString caption) { Config config = Config(); KisDlgInternalColorSelector dialog(parent, color, config, caption); dialog.setPreviousColor(color); dialog.exec(); return dialog.getCurrentColor(); } KoColor KisDlgInternalColorSelector::getCurrentColor() { return m_d->currentColor; } void KisDlgInternalColorSelector::chooseAlpha(bool chooseAlpha) { m_d->chooseAlpha = chooseAlpha; } void KisDlgInternalColorSelector::slotConfigurationChanged() { //m_d->canvas->displayColorConverter()-> //slotColorSpaceChanged(m_d->canvas->image()->colorSpace()); } void KisDlgInternalColorSelector::slotLockSelector() { m_d->allowUpdates = false; } void KisDlgInternalColorSelector::setPreviousColor(KoColor c) { m_d->previousColor = c; } void KisDlgInternalColorSelector::reject() { slotColorUpdated(m_d->previousColor); QDialog::reject(); } void KisDlgInternalColorSelector::updateAllElements(QObject *source) { //update everything!!! if (source != m_ui->spinboxselector) { m_ui->spinboxselector->slotSetColor(m_d->currentColor); } if (source != m_ui->visualSelector) { m_ui->visualSelector->slotSetColor(m_d->currentColor); } if (source != m_d->hexColorInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput->update(); } m_ui->previousColor->setColor(m_d->previousColor); m_ui->currentColor->setColor(m_d->currentColor); if (source != this->parent()) { emit(signalForegroundColorChosen(m_d->currentColor)); m_d->compressColorChanges->start(); } - m_ui->screenColorPicker->updateIcons(); + if (m_d->screenColorPicker) { + m_d->screenColorPicker->updateIcons(); + } } void KisDlgInternalColorSelector::endUpdateWithNewColor() { m_d->allowUpdates = true; } void KisDlgInternalColorSelector::focusInEvent(QFocusEvent *) { //setPreviousColor(); } void KisDlgInternalColorSelector::slotFinishUp() { setPreviousColor(m_d->currentColor); - KisConfig cfg; + KConfigGroup cfg(KSharedConfig::openConfig()->group("")); if (m_d->paletteModel) { if (m_d->paletteModel->colorSet()) { cfg.writeEntry("internal_selector_active_color_set", m_d->paletteModel->colorSet()->name()); } } } void KisDlgInternalColorSelector::slotSetColorFromHex() { slotColorUpdated(m_d->sRGB); } void KisDlgInternalColorSelector::slotChangePalette(KoColorSet *set) { if (!set) { return; } m_d->paletteModel->setColorSet(set); m_ui->cmbNameList->clear(); for (quint32 i = 0; i< set->nColors(); i++) { KoColorSetEntry entry = set->getColorGlobal(i); QPixmap colorSquare = QPixmap(32, 32); if (entry.spotColor()) { QImage img = QImage(32, 32, QImage::Format_ARGB32); QPainter circlePainter; img.fill(Qt::transparent); circlePainter.begin(&img); QBrush brush = QBrush(Qt::SolidPattern); brush.setColor(entry.color().toQColor()); circlePainter.setBrush(brush); QPen pen = circlePainter.pen(); pen.setColor(Qt::transparent); pen.setWidth(0); circlePainter.setPen(pen); circlePainter.drawEllipse(0, 0, 32, 32); circlePainter.end(); colorSquare = QPixmap::fromImage(img); } else { colorSquare.fill(entry.color().toQColor()); } QString name = entry.name(); if (!entry.id().isEmpty()){ name = entry.id() + " - " + entry.name(); } m_ui->cmbNameList->addSqueezedItem(QIcon(colorSquare), name); } QCompleter *completer = new QCompleter(m_ui->cmbNameList->model()); completer->setCompletionMode(QCompleter::PopupCompletion); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchContains); m_ui->cmbNameList->setCompleter(completer); } void KisDlgInternalColorSelector::slotSetColorFromColorList() { int index = m_ui->cmbNameList->currentIndex(); if (m_d->paletteModel) { slotSetColorFromColorSetEntry(m_d->paletteModel->colorSet()->getColorGlobal(index)); m_ui->paletteBox->blockSignals(true); m_ui->paletteBox->selectionModel()->clearSelection(); m_ui->paletteBox->selectionModel()->setCurrentIndex(m_d->paletteModel->indexFromId(index), QItemSelectionModel::Select); m_ui->paletteBox->blockSignals(false); } } void KisDlgInternalColorSelector::slotSetColorFromColorSetEntry(KoColorSetEntry entry) { slotColorUpdated(entry.color()); } void KisDlgInternalColorSelector::showEvent(QShowEvent *event) { updateAllElements(0); QDialog::showEvent(event); } diff --git a/libs/ui/dialogs/kis_dlg_internal_color_selector.h b/libs/widgets/KisDlgInternalColorSelector.h similarity index 92% rename from libs/ui/dialogs/kis_dlg_internal_color_selector.h rename to libs/widgets/KisDlgInternalColorSelector.h index 97ad22b112..f6b1fe5c76 100644 --- a/libs/ui/dialogs/kis_dlg_internal_color_selector.h +++ b/libs/widgets/KisDlgInternalColorSelector.h @@ -1,193 +1,197 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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 KISINTERNALCOLORSELECTOR_H -#define KISINTERNALCOLORSELECTOR_H +#ifndef KISDLGINTERNALCOLORSELECTOR_H +#define KISDLGINTERNALCOLORSELECTOR_H -#include "kritaui_export.h" +#include "kritawidgets_export.h" #include "KoColor.h" #include "KoColorSpace.h" #include "KoColorDisplayRendererInterface.h" #include "KoColorSet.h" #include -#include "ui_wdgdlginternalcolorselector.h" +#include "KisScreenColorPickerBase.h" +#include "ui_WdgDlgInternalColorSelector.h" /** * @brief The KisInternalColorSelector class * * A non-modal color selector dialog that is not a plugin and can thus be used for filters. */ -class KRITAUI_EXPORT KisDlgInternalColorSelector : public QDialog +class KRITAWIDGETS_EXPORT KisDlgInternalColorSelector : public QDialog { Q_OBJECT + public: + + + static std::function s_screenColorPickerFactory; + + struct Config { Config() : modal(true), visualColorSelector(true), paletteBox(true), screenColorPicker(true), prevNextButtons(true), hexInput(true), useAlpha(false){} bool modal; bool visualColorSelector; bool paletteBox; bool screenColorPicker; bool prevNextButtons; bool hexInput; bool useAlpha; }; KisDlgInternalColorSelector(QWidget* parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisDlgInternalColorSelector() override; /** * @brief slotColorSpaceChanged * Color space has changed, use this dialog to change the colorspace. */ void colorSpaceChanged(const KoColorSpace *cs); /** * @brief lockUsedColorSpace * Lock the used colorspace of this selector. * @param cs */ void lockUsedColorSpace(const KoColorSpace *cs); /** * @brief setDisplayRenderer * Set the display renderer. This is necessary for HDR color manage support. * @param displayRenderer */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getModalColorDialog * Execute this dialog modally. The function returns * the KoColor you want. * @param color - The current color. Make sure this is in the color space you want your * end color to be in. * @param chooseAlpha - Whether or not the alpha-choosing functionality should be used. */ static KoColor getModalColorDialog(const KoColor color, QWidget* parent = Q_NULLPTR, QString caption = QString()); /** * @brief getCurrentColor * @return gives currently active color; */ KoColor getCurrentColor(); void chooseAlpha(bool chooseAlpha); Q_SIGNALS: /** * @brief signalForegroundColorChosen * The most important signal. This will sent out when a color has been picked from the selector. * There will be a small delay to make sure that the selector causes too many updates. * * Do not connect this to slotColorUpdated. * @param color The new color chosen */ void signalForegroundColorChosen(KoColor color); public Q_SLOTS: /** * @brief slotColorUpdated * Very important slot. Is connected to krita's resources to make sure it has * the currently active color. It's very important that this function is able to understand * when the signal came from itself. * @param newColor This is the new color. */ void slotColorUpdated(KoColor newColor); /** * @brief slotSetColorFromPatch * update current color from kocolorpatch. * @param patch */ void slotSetColorFromPatch(KoColorPatch* patch); /** * @brief setPreviousColor * set the previous color. */ void setPreviousColor(KoColor c); void reject() override; private Q_SLOTS: /** * @brief slotLockSelector * This slot will prevent the color from being updated. */ void slotLockSelector(); /** * @brief slotConfigurationChanged * Wrapper slot for changes to the colorspace. */ void slotConfigurationChanged(); void endUpdateWithNewColor(); /** * @brief slotFinishUp * This is called when the selector is closed, for saving the current palette. */ void slotFinishUp(); /** * @brief slotSetColorFromHex * Update from the hex color input. */ void slotSetColorFromHex(); void slotChangePalette(KoColorSet *set); void slotSetColorFromColorList(); void slotSetColorFromColorSetEntry(KoColorSetEntry entry); protected: - void showEvent(QShowEvent *event); private: - Ui_WdgDlgInternalColorSelector *m_ui; //the UI - struct Private; //The private struct - const QScopedPointer m_d; //the private pointer - - - + void focusInEvent(QFocusEvent *) override; /** * @brief updateAllElements * Updates each widget with the new element, and if it's responsible for the update sents * a signal out that there's a new color. */ void updateAllElements(QObject *source); - void focusInEvent(QFocusEvent *) override; +private: + Ui_WdgDlgInternalColorSelector *m_ui; + struct Private; //The private struct + const QScopedPointer m_d; //the private pointer }; -#endif // KISINTERNALCOLORSELECTOR_H +#endif // KISDLGINTERNALCOLORSELECTOR_H diff --git a/libs/ui/KisPaletteModel.cpp b/libs/widgets/KisPaletteModel.cpp similarity index 99% rename from libs/ui/KisPaletteModel.cpp rename to libs/widgets/KisPaletteModel.cpp index f801701940..c39a334d67 100644 --- a/libs/ui/KisPaletteModel.cpp +++ b/libs/widgets/KisPaletteModel.cpp @@ -1,644 +1,642 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisPaletteModel.h" #include #include #include #include #include #include +#include #include #include -#include -#include - KisPaletteModel::KisPaletteModel(QObject* parent) : QAbstractTableModel(parent), m_colorSet(0), m_displayRenderer(KoDumbColorDisplayRenderer::instance()) { } KisPaletteModel::~KisPaletteModel() { } void KisPaletteModel::setDisplayRenderer(KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { if (m_displayRenderer) { disconnect(m_displayRenderer, 0, this, 0); } m_displayRenderer = displayRenderer; connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(slotDisplayConfigurationChanged())); } else { m_displayRenderer = KoDumbColorDisplayRenderer::instance(); } } void KisPaletteModel::slotDisplayConfigurationChanged() { beginResetModel(); endResetModel(); } QModelIndex KisPaletteModel::getLastEntryIndex() { int endRow = rowCount(); int endColumn = columnCount(); if (m_colorSet->nColors()>0) { QModelIndex i = this->index(endRow, endColumn, QModelIndex()); while (qvariant_cast(i.data(RetrieveEntryRole)).isEmpty()) { i = this->index(endRow, endColumn); endColumn -=1; if (endColumn<0) { endColumn = columnCount(); endRow-=1; } } return i; } return QModelIndex(); } QVariant KisPaletteModel::data(const QModelIndex& index, int role) const { KoColorSetEntry entry; if (m_colorSet && m_displayRenderer) { //now to figure out whether we have a groupname row or not. bool groupNameRow = false; quint32 indexInGroup = 0; QString indexGroupName = QString(); int rowstotal = m_colorSet->nColorsGroup()/columnCount(); if (index.row()<=rowstotal && (quint32)(index.row()*columnCount()+index.column())nColorsGroup()) { indexInGroup = (quint32)(index.row()*columnCount()+index.column()); } if (m_colorSet->nColorsGroup()==0) { rowstotal+=1; //always add one for the default group when considering groups. } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ //we make an int for the rows added by the current group. int newrows = 1+m_colorSet->nColorsGroup(groupName)/columnCount(); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { newrows+=1; } if (newrows==0) { newrows+=1; //always add one for the group when considering groups. } quint32 tempIndex = (quint32)((index.row()-(rowstotal+2))*columnCount()+index.column()); if (index.row() == rowstotal+1) { //rowstotal+1 is taken up by the groupname. indexGroupName = groupName; groupNameRow = true; } else if (index.row() > (rowstotal+1) && index.row() <= rowstotal+newrows && tempIndexnColorsGroup(groupName)){ //otherwise it's an index to the colors in the group. indexGroupName = groupName; indexInGroup = tempIndex; } //add the new rows to the totalrows we've looked at. rowstotal += newrows; } if (groupNameRow) { switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return indexGroupName; } case IsHeaderRole: { return true; } case RetrieveEntryRole: { QStringList entryList; entryList.append(indexGroupName); entryList.append(QString::number(0)); return entryList; } } } else { if (indexInGroup < m_colorSet->nColorsGroup(indexGroupName)) { entry = m_colorSet->getColorGroup(indexInGroup, indexGroupName); switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return entry.name(); } case Qt::BackgroundRole: { QColor color = m_displayRenderer->toQColor(entry.color()); return QBrush(color); } case IsHeaderRole: { return false; } case RetrieveEntryRole: { QStringList entryList; entryList.append(indexGroupName); entryList.append(QString::number(indexInGroup)); return entryList; } } } } } return QVariant(); } int KisPaletteModel::rowCount(const QModelIndex& /*parent*/) const { if (!m_colorSet) { return 0; } if (m_colorSet->nColors()==0) { return 0; } if (columnCount() > 0) { int countedrows = m_colorSet->nColorsGroup("")/columnCount(); if (m_colorSet->nColorsGroup()%columnCount() > 0) { countedrows+=1; } if (m_colorSet->nColorsGroup()==0) { countedrows+=1; } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()) { countedrows += 1; //add one for the name; countedrows += 1+(m_colorSet->nColorsGroup(groupName)/ columnCount()); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { countedrows+=1; } if (m_colorSet->nColorsGroup(groupName)==0) { countedrows+=1; } } countedrows +=1; //Our code up till now doesn't take 0 into account. return countedrows; } return m_colorSet->nColors()/15 + 1; } int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const { if (m_colorSet && m_colorSet->columnCount() > 0) { return m_colorSet->columnCount(); } return 15; } Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const { if (index.isValid()) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::ItemIsDropEnabled; } QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const { if (m_colorSet) { //make an int to hold the amount of rows we've looked at. The initial is the total rows in the default group. int rowstotal = m_colorSet->nColorsGroup()/columnCount(); if (row<=rowstotal && (quint32)(row*columnCount()+column)nColorsGroup()) { //if the total rows are in the default group, we just return an index. return QAbstractTableModel::index(row, column, parent); } else if(row<0 && column<0) { return QAbstractTableModel::index(0, 0, parent); } if (m_colorSet->nColorsGroup()==0) { rowstotal+=1; //always add one for the default group when considering groups. } Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ //we make an int for the rows added by the current group. int newrows = 1+m_colorSet->nColorsGroup(groupName)/columnCount(); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { newrows+=1; } if (m_colorSet->nColorsGroup(groupName)==0) { newrows+=1; //always add one for the group when considering groups. } if (rowstotal + newrows>rowCount()) { newrows = rowCount() - rowstotal; } quint32 tempIndex = (quint32)((row-(rowstotal+2))*columnCount()+column); if (row == rowstotal+1) { //rowstotal+1 is taken up by the groupname. return QAbstractTableModel::index(row, 0, parent); } else if (row > (rowstotal+1) && row <= rowstotal+newrows && tempIndexnColorsGroup(groupName)){ //otherwise it's an index to the colors in the group. return QAbstractTableModel::index(row, column, parent); } //add the new rows to the totalrows we've looked at. rowstotal += newrows; } } return QModelIndex(); } void KisPaletteModel::setColorSet(KoColorSet* colorSet) { m_colorSet = colorSet; beginResetModel(); endResetModel(); } KoColorSet* KisPaletteModel::colorSet() const { return m_colorSet; } QModelIndex KisPaletteModel::indexFromId(int i) const { QModelIndex index = QModelIndex(); if (!colorSet() || colorSet()->nColors() == 0) { return index; } if (i > (int)colorSet()->nColors()) { qWarning()<<"index is too big"<nColors(); index = this->index(0,0); } if (i < (int)colorSet()->nColorsGroup(0)) { index = QAbstractTableModel::index(i/columnCount(), i % columnCount()); if (!index.isValid()) { index = QAbstractTableModel::index(0, 0, QModelIndex()); } return index; } else { int rowstotal = 1 + m_colorSet->nColorsGroup() / columnCount(); if (m_colorSet->nColorsGroup() == 0) { rowstotal += 1; } int totalIndexes = colorSet()->nColorsGroup(); Q_FOREACH (QString groupName, m_colorSet->getGroupNames()){ if (i + 1 <= (int)(totalIndexes + colorSet()->nColorsGroup(groupName)) && i + 1 > (int)totalIndexes) { int col = (i - totalIndexes) % columnCount(); int row = rowstotal + 1 + ((i - totalIndexes) / columnCount()); index = this->index(row, col); return index; } else { rowstotal += 1 + m_colorSet->nColorsGroup(groupName) / columnCount(); totalIndexes += colorSet()->nColorsGroup(groupName); if (m_colorSet->nColorsGroup(groupName)%columnCount() > 0) { rowstotal += 1; } if (m_colorSet->nColorsGroup(groupName)==0) { rowstotal += 1; //always add one for the group when considering groups. } } } } return index; } int KisPaletteModel::idFromIndex(const QModelIndex &index) const { if (index.isValid()==false) { return -1; qWarning()<<"invalid index"; } int i=0; QStringList entryList = qvariant_cast(data(index, RetrieveEntryRole)); if (entryList.isEmpty()) { return -1; qWarning()<<"invalid index, there's no data to retrieve here"; } if (entryList.at(0)==QString()) { return entryList.at(1).toUInt(); } i = colorSet()->nColorsGroup(""); //find at which position the group is. int groupIndex = colorSet()->getGroupNames().indexOf(entryList.at(0)); //add all the groupsizes onto it till we get to our group. for(int g=0; gnColorsGroup(colorSet()->getGroupNames().at(g)); } //then add the index. i += entryList.at(1).toUInt(); return i; } KoColorSetEntry KisPaletteModel::colorSetEntryFromIndex(const QModelIndex &index) const { KoColorSetEntry blank = KoColorSetEntry(); if (!index.isValid()) { return blank; } QStringList entryList = qvariant_cast(data(index, RetrieveEntryRole)); if (entryList.isEmpty()) { return blank; } QString groupName = entryList.at(0); quint32 indexInGroup = entryList.at(1).toUInt(); return m_colorSet->getColorGroup(indexInGroup, groupName); } bool KisPaletteModel::addColorSetEntry(KoColorSetEntry entry, QString groupName) { int col = m_colorSet->nColorsGroup(groupName)%columnCount(); QModelIndex i = getLastEntryIndex(); if (col+1 > columnCount()) { beginInsertRows(QModelIndex(), i.row(), i.row()+1); } if ((int)m_colorSet->nColors() < columnCount()) { beginInsertColumns(QModelIndex(), m_colorSet->nColors(), m_colorSet->nColors()+1); } m_colorSet->add(entry, groupName); if (col + 1 > columnCount()) { endInsertRows(); } if (m_colorSet->nColors() < (quint32)columnCount()) { endInsertColumns(); } return true; } bool KisPaletteModel::removeEntry(QModelIndex index, bool keepColors) { QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); if (entryList.empty()) { return false; } QString groupName = entryList.at(0); quint32 indexInGroup = entryList.at(1).toUInt(); if (qvariant_cast(index.data(IsHeaderRole))==false) { if (index.column()-1<0 && m_colorSet->nColorsGroup(groupName)%columnCount() <1 && index.row()-1>0 && m_colorSet->nColorsGroup(groupName)/columnCount()>0) { beginRemoveRows(QModelIndex(), index.row(), index.row()-1); } m_colorSet->removeAt(indexInGroup, groupName); if (index.column()-1<0 && m_colorSet->nColorsGroup(groupName)%columnCount() <1 && index.row()-1>0 && m_colorSet->nColorsGroup(groupName)/columnCount()>0) { endRemoveRows(); } } else { beginRemoveRows(QModelIndex(), index.row(), index.row()-1); m_colorSet->removeGroup(groupName, keepColors); endRemoveRows(); } return true; } bool KisPaletteModel::addGroup(QString groupName) { QModelIndex i = getLastEntryIndex(); beginInsertRows(QModelIndex(), i.row(), i.row()+1); m_colorSet->addGroup(groupName); endInsertRows(); return true; } bool KisPaletteModel::removeRows(int row, int count, const QModelIndex &parent) { Q_ASSERT(!parent.isValid()); int beginRow = qMax(0, row); int endRow = qMin(row + count - 1, (int)m_colorSet->nColors() - 1); beginRemoveRows(parent, beginRow, endRow); // Find the palette entry at row, count, remove from KoColorSet endRemoveRows(); return true; } bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) { return false; } if (action == Qt::IgnoreAction) { return false; } int endRow; int endColumn; if (!parent.isValid()) { if (row < 0) { endRow = indexFromId(m_colorSet->nColors()).row(); endColumn = indexFromId(m_colorSet->nColors()).column(); } else { endRow = qMin(row, indexFromId(m_colorSet->nColors()).row()); endColumn = qMin(column, m_colorSet->columnCount()); } } else { endRow = qMin(parent.row(), rowCount()); endColumn = qMin(parent.column(), columnCount()); } if (data->hasFormat("krita/x-colorsetgroup")) { QByteArray encodedData = data->data("krita/x-colorsetgroup"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { QString groupName; stream >> groupName; QModelIndex index = this->index(endRow, 0); if (index.isValid()) { QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupDroppedOn = QString(); if (!entryList.isEmpty()) { groupDroppedOn = entryList.at(0); } int groupIndex = colorSet()->getGroupNames().indexOf(groupName); beginMoveRows( QModelIndex(), groupIndex, groupIndex, QModelIndex(), endRow); m_colorSet->moveGroup(groupName, groupDroppedOn); m_colorSet->save(); endMoveRows(); ++endRow; } } } else { QByteArray encodedData = data->data("krita/x-colorsetentry"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { KoColorSetEntry entry; QString oldGroupName; int indexInGroup; QString colorXml; QString name, id; bool spotColor; stream >> name >> id >> spotColor >> indexInGroup >> oldGroupName >> colorXml; entry.setName(name); entry.setId(id); entry.setSpotColor(spotColor); QDomDocument doc; doc.setContent(colorXml); QDomElement e = doc.documentElement(); QDomElement c = e.firstChildElement(); if (!c.isNull()) { QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); entry.setColor(KoColor::fromXML(c, colorDepthId)); } QModelIndex index = this->index(endRow, endColumn); if (qvariant_cast(index.data(IsHeaderRole))){ endRow+=1; } if (index.isValid()) { /*this is to figure out the row of the old color. * That way we can in turn avoid moverows from complaining the * index is out of bounds when using index. * Makes me wonder if we shouldn't just insert the index of the * old color when requesting the mimetype... */ int i = indexInGroup; if (oldGroupName != QString()) { colorSet()->nColorsGroup(""); //find at which position the group is. int groupIndex = colorSet()->getGroupNames().indexOf(oldGroupName); //add all the groupsizes onto it till we get to our group. for(int g=0; gnColorsGroup(colorSet()->getGroupNames().at(g)); } } QModelIndex indexOld = indexFromId(i); if (action == Qt::MoveAction){ if (indexOld.row()!=qMax(endRow, 0) && indexOld.row()!=qMax(endRow+1,1)) { beginMoveRows(QModelIndex(), indexOld.row(), indexOld.row(), QModelIndex(), qMax(endRow+1,1)); } if (indexOld.column()!=qMax(endColumn, 0) && indexOld.column()!=qMax(endColumn+1,1)) { beginMoveColumns(QModelIndex(), indexOld.column(), indexOld.column(), QModelIndex(), qMax(endColumn+1,1)); } } else { beginInsertRows(QModelIndex(), endRow, endRow); } QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString entryInGroup = "0"; QString groupName = QString(); if (!entryList.isEmpty()) { groupName = entryList.at(0); entryInGroup = entryList.at(1); } int location = entryInGroup.toInt(); // Insert the entry if (groupName==oldGroupName && qvariant_cast(index.data(IsHeaderRole))==true) { groupName=QString(); location=m_colorSet->nColorsGroup(); } m_colorSet->insertBefore(entry, location, groupName); if (groupName==oldGroupName && locationremoveAt(indexInGroup, oldGroupName); } m_colorSet->save(); if (action == Qt::MoveAction){ if (indexOld.row()!=qMax(endRow, 0) && indexOld.row()!=qMax(endRow+1,1)) { endMoveRows(); } if (indexOld.column()!=qMax(endColumn, 0) && indexOld.column()!=qMax(endColumn+1,1)) { endMoveColumns(); } } else { endInsertRows(); } ++endRow; } } } return true; } QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QString mimeTypeName = "krita/x-colorsetentry"; //Q_FOREACH(const QModelIndex &index, indexes) { QModelIndex index = indexes.last(); if (index.isValid()) { if (qvariant_cast(index.data(IsHeaderRole))==false) { KoColorSetEntry entry = colorSetEntryFromIndex(index); QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupName = QString(); int indexInGroup = 0; if (!entryList.isEmpty()) { groupName = entryList.at(0); QString iig = entryList.at(1); indexInGroup = iig.toInt(); } QDomDocument doc; QDomElement root = doc.createElement("Color"); root.setAttribute("bitdepth", entry.color().colorSpace()->colorDepthId().id()); doc.appendChild(root); entry.color().toXML(doc, root); stream << entry.name() << entry.id() << entry.spotColor() << indexInGroup << groupName << doc.toString(); } else { mimeTypeName = "krita/x-colorsetgroup"; QStringList entryList = qvariant_cast(index.data(RetrieveEntryRole)); QString groupName = QString(); if (!entryList.isEmpty()) { groupName = entryList.at(0); } stream << groupName; } } mimeData->setData(mimeTypeName, encodedData); return mimeData; } QStringList KisPaletteModel::mimeTypes() const { return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup"; } Qt::DropActions KisPaletteModel::supportedDropActions() const { return Qt::MoveAction; } diff --git a/libs/ui/KisPaletteModel.h b/libs/widgets/KisPaletteModel.h similarity index 97% rename from libs/ui/KisPaletteModel.h rename to libs/widgets/KisPaletteModel.h index 086adbc256..64451c58cc 100644 --- a/libs/ui/KisPaletteModel.h +++ b/libs/widgets/KisPaletteModel.h @@ -1,150 +1,149 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PALETTEMODEL_H #define KIS_PALETTEMODEL_H #include #include #include -#include -#include "kritaui_export.h" +#include "kritawidgets_export.h" #include #include class KoColorSet; /** * @brief The KisPaletteModel class * This, together with kis_palette_view and kis_palette_delegate forms a mvc way to access kocolorsets. */ -class KRITAUI_EXPORT KisPaletteModel : public QAbstractTableModel +class KRITAWIDGETS_EXPORT KisPaletteModel : public QAbstractTableModel { Q_OBJECT public: KisPaletteModel(QObject* parent = 0); ~KisPaletteModel() override; enum AdditionalRoles { IsHeaderRole = Qt::UserRole + 1, ExpandCategoryRole = Qt::UserRole + 2, RetrieveEntryRole = Qt::UserRole + 3 }; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; void setColorSet(KoColorSet* colorSet); KoColorSet* colorSet() const; /** * Installs a display renderer object for a palette that will * convert the KoColor to the displayable QColor. Default is the * dumb renderer. */ void setDisplayRenderer(KoColorDisplayRendererInterface *displayRenderer); /** * @brief indexFromId * convenience function to get the tableindex from the global palette color. * used by lazybrush. * @param i * @return index in table. */ QModelIndex indexFromId(int i) const; /** * @brief idFromIndex * convenience function to get the global colorset entry id from the table index. * If you just want to use this to get the kocolorsetentry, use colorsetEntryFromIndex instead. * @param index * @return */ int idFromIndex(const QModelIndex &index) const; /** * @brief colorSetEntryFromIndex * This gives the colorset entry for the given table model index. * @param index the QModelIndex * @return the kocolorsetentry */ KoColorSetEntry colorSetEntryFromIndex(const QModelIndex &index) const; /** * @brief addColorSetEntry * proper function to handle adding entries. * @return whether successful. */ bool addColorSetEntry(KoColorSetEntry entry, QString groupName=QString()); /** * @brief removeEntry * proper function to remove the colorsetentry at the given index. * The consolidtes both removeentry and removegroup. * @param keepColors: This bool determines whether, when deleting a group, * the colors should be added to the default group. This is usually desirable, * so hence the default is true. * @return if successful */ bool removeEntry(QModelIndex index, bool keepColors=true); /** * @brief addGroup * Adds a group to the list. * @param groupName * @return if successful */ bool addGroup(QString groupName = QString()); bool removeRows(int row, int count, const QModelIndex &parent) override; /** * @brief dropMimeData * This is an overridden function that handles dropped mimedata. * right now only colorsetentries and colorsetgroups are handled. * @return */ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; /** * @brief mimeData * gives the mimedata for a kocolorsetentry or a kocolorsetgroup. * @param indexes * @return the mimedata for the given indices */ QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::DropActions supportedDropActions() const override; private Q_SLOTS: void slotDisplayConfigurationChanged(); private: KoColorSet* m_colorSet; QPointer m_displayRenderer; QModelIndex getLastEntryIndex(); }; #endif diff --git a/libs/ui/kis_palette_delegate.h b/libs/widgets/KisScreenColorPickerBase.cpp similarity index 52% copy from libs/ui/kis_palette_delegate.h copy to libs/widgets/KisScreenColorPickerBase.cpp index 010d3610f8..ed6477708d 100644 --- a/libs/ui/kis_palette_delegate.h +++ b/libs/widgets/KisScreenColorPickerBase.cpp @@ -1,42 +1,20 @@ /* - * Copyright (c) 2016 Dmitry Kazakov + * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 + * Copyright (C) Michael Zhou , (C) 2018 * * 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_PALETTE_DELEGATE_H -#define __KIS_PALETTE_DELEGATE_H - -#include - -#include "kritaui_export.h" - - -class KRITAUI_EXPORT KisPaletteDelegate : public QAbstractItemDelegate -{ -public: - KisPaletteDelegate(QObject * parent = 0); - ~KisPaletteDelegate() override; - - void setCrossedKeyword(const QString &value); - - void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; - QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override; - -private: - QString m_crossedKeyword; -}; - -#endif /* __KIS_PALETTE_DELEGATE_H */ +#include diff --git a/libs/ui/kis_palette_delegate.h b/libs/widgets/KisScreenColorPickerBase.h similarity index 53% copy from libs/ui/kis_palette_delegate.h copy to libs/widgets/KisScreenColorPickerBase.h index 010d3610f8..1997c49905 100644 --- a/libs/ui/kis_palette_delegate.h +++ b/libs/widgets/KisScreenColorPickerBase.h @@ -1,42 +1,39 @@ /* - * Copyright (c) 2016 Dmitry Kazakov + * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 + * Copyright (C) Michael Zhou , (C) 2018 * * 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_PALETTE_DELEGATE_H -#define __KIS_PALETTE_DELEGATE_H +#ifndef KISSCREENCOLORPICKERBASE_H +#define KISSCREENCOLORPICKERBASE_H +#include +#include "kritawidgets_export.h" -#include +class KoColor; -#include "kritaui_export.h" - - -class KRITAUI_EXPORT KisPaletteDelegate : public QAbstractItemDelegate +class KRITAWIDGETS_EXPORT KisScreenColorPickerBase : public QWidget { + Q_OBJECT public: - KisPaletteDelegate(QObject * parent = 0); - ~KisPaletteDelegate() override; - - void setCrossedKeyword(const QString &value); - - void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; - QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override; - -private: - QString m_crossedKeyword; + KisScreenColorPickerBase(QWidget *parent = 0) : QWidget(parent) { } + virtual ~KisScreenColorPickerBase() { } + /// reloads icon(s) when theme is updated + virtual void updateIcons() = 0; +Q_SIGNALS: + void sigNewColorPicked(KoColor); }; -#endif /* __KIS_PALETTE_DELEGATE_H */ +#endif // KISSCREENCOLORPICKERBASE_H diff --git a/libs/ui/widgets/KisVisualColorSelector.cpp b/libs/widgets/KisVisualColorSelector.cpp similarity index 100% rename from libs/ui/widgets/KisVisualColorSelector.cpp rename to libs/widgets/KisVisualColorSelector.cpp diff --git a/libs/ui/widgets/KisVisualColorSelector.h b/libs/widgets/KisVisualColorSelector.h similarity index 95% rename from libs/ui/widgets/KisVisualColorSelector.h rename to libs/widgets/KisVisualColorSelector.h index 7f19849360..04ad5eebd6 100644 --- a/libs/ui/widgets/KisVisualColorSelector.h +++ b/libs/widgets/KisVisualColorSelector.h @@ -1,86 +1,86 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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_VISUAL_COLOR_SELECTOR_H #define KIS_VISUAL_COLOR_SELECTOR_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisColorSelectorInterface.h" -#include "kritaui_export.h" +#include "kritawidgets_export.h" /** * @brief The KisVisualColorSelector class * * This gives a color selector box that draws gradients and everything. * * Unlike other color selectors, this one draws the full gamut of the given * colorspace. */ -class KRITAUI_EXPORT KisVisualColorSelector : public KisColorSelectorInterface +class KRITAWIDGETS_EXPORT KisVisualColorSelector : public KisColorSelectorInterface { Q_OBJECT public: explicit KisVisualColorSelector(QWidget *parent = 0); ~KisVisualColorSelector() override; /** * @brief setConfig * @param forceCircular * Force circular is for space where you only have room for a circular selector. * @param forceSelfUpdate * force self-update is for making it update itself when using a modal dialog. */ void setConfig(bool forceCircular, bool forceSelfUpdate) override; KoColor getCurrentColor() const override; public Q_SLOTS: void slotSetColor(const KoColor &c) override; void slotsetColorSpace(const KoColorSpace *cs); void slotRebuildSelectors(); void configurationChanged(); void setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer) override; private Q_SLOTS: void updateFromWidgets(KoColor c); void HSXwrangler(); protected: void leaveEvent(QEvent *) override; void resizeEvent(QResizeEvent *) override; private: struct Private; const QScopedPointer m_d; void updateSelectorElements(QObject *source); void drawGradients(); }; #endif diff --git a/libs/ui/widgets/KisVisualColorSelectorShape.cpp b/libs/widgets/KisVisualColorSelectorShape.cpp similarity index 100% rename from libs/ui/widgets/KisVisualColorSelectorShape.cpp rename to libs/widgets/KisVisualColorSelectorShape.cpp diff --git a/libs/ui/widgets/KisVisualColorSelectorShape.h b/libs/widgets/KisVisualColorSelectorShape.h similarity index 99% rename from libs/ui/widgets/KisVisualColorSelectorShape.h rename to libs/widgets/KisVisualColorSelectorShape.h index c27d4703ab..ba76d7280b 100644 --- a/libs/ui/widgets/KisVisualColorSelectorShape.h +++ b/libs/widgets/KisVisualColorSelectorShape.h @@ -1,236 +1,234 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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_VISUAL_COLOR_SELECTOR_SHAPE_H #define KIS_VISUAL_COLOR_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisVisualColorSelector.h" #include "KisColorSelectorConfiguration.h" -#include "kritaui_export.h" - /** * @brief The KisVisualColorSelectorShape class * A 2d widget can represent at maximum 2 coordinates. * So first decide howmany coordinates you need. (onedimensional, or twodimensional) * Then the model, (Channel, HSV, HSL, HSI, YUV). Channel is the raw color channels. * When it finds a non-implemented feature it'll return to Channel. * Then, select the channels you wish to be affected. This uses the model, so for cmyk * the channel is c=0, m=1, y=2, k=3, but for hsv, hue=0, sat=1, and val=2 * These can also be set with 'slotsetactive channels'. * Then finally, connect the displayrenderer, you can also do this with 'setdisplayrenderer' * * Either way, this class is made to be subclassed, with a few virtuals so that the geometry * can be calculated properly. */ class KisVisualColorSelectorShape : public QWidget { Q_OBJECT public: /** * @brief The Dimensions enum * Whether or not the shape is single or two dimensional. **/ enum Dimensions{onedimensional, twodimensional}; enum ColorModel{Channel, HSV, HSL, HSI, HSY, YUV}; explicit KisVisualColorSelectorShape(QWidget *parent, KisVisualColorSelectorShape::Dimensions dimension, KisVisualColorSelectorShape::ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisVisualColorSelectorShape() override; /** * @brief getCursorPosition * @return current cursor position in shape-coordinates. */ QPointF getCursorPosition(); /** * @brief getDimensions * @return whether this is a single or twodimensional widget. */ Dimensions getDimensions(); /** * @brief getColorModel * @return the model of this widget. */ ColorModel getColorModel(); /** * @brief getPixmap * @return the pixmap of the gradient, for drawing on with a subclass. * the pixmap will not change unless 'm_d->setPixmap=true' which is toggled by * refresh and update functions. */ bool imagesNeedUpdate() const; QImage getImageMap(); /** * @brief setFullImage * Set the full widget image to be painted. * @param full this should be the full image. */ void setFullImage(QImage full); /** * @brief getCurrentColor * @return the current kocolor */ KoColor getCurrentColor(); /** * @brief setDisplayRenderer * disconnect the old display renderer if needed and connect the new one. * @param displayRenderer */ void setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getColorFromConverter * @param c a koColor. * @return get the qcolor from the given kocolorusing this widget's display renderer. */ QColor getColorFromConverter(KoColor c); /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ virtual QRect getSpaceForSquare(QRect geom) = 0; virtual QRect getSpaceForCircle(QRect geom) = 0; virtual QRect getSpaceForTriangle(QRect geom) = 0; /** * @brief forceImageUpdate * force the image to recache. */ void forceImageUpdate(); /** * @brief setBorderWidth * set the border of the single dimensional selector. * @param width */ virtual void setBorderWidth(int width) = 0; /** * @brief getChannels * get used channels * @return */ QVector getChannels(); /** * @brief setHSX * This is for the cursor not to change when selecting * black, white, and desaturated values. Will not change the non-native values. * @param hsx the hsx value. */ void setHSX(QVector hsx, bool wrangler=false); /** * @brief getHSX sets the sat and hue so they won't * switch around much. * @param hsx the hsx values. * @return returns hsx, corrected. */ QVector getHSX(QVector hsx, bool wrangler= false); Q_SIGNALS: void sigNewColor(KoColor col); void sigHSXchange(); public Q_SLOTS: /** * @brief setColor * Set this widget's current color and change the cursor position. * @param c */ void setColor(KoColor c); /** * @brief setColorFromSibling * set this widget's current color, but don't change the cursor position, * instead sent out a signal of the new color. * @param c */ void setColorFromSibling(KoColor c); /** * @brief slotSetActiveChannels * Change the active channels if necessary. * @param channel1 used by single and twodimensional widgets. * @param channel2 only used by twodimensional widgets. */ void slotSetActiveChannels(int channel1, int channel2); /** * @brief updateFromChangedDisplayRenderer * for updating from the display renderer... not sure why this one is public. */ void updateFromChangedDisplayRenderer(); protected: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void paintEvent(QPaintEvent*) override; private: struct Private; const QScopedPointer m_d; /** * @brief convertShapeCoordinateToWidgetCoordinate * @return take the position in the shape and convert it to screen coordinates. */ virtual QPointF convertShapeCoordinateToWidgetCoordinate(QPointF) = 0; /** * @brief convertWidgetCoordinateToShapeCoordinate * Convert a coordinate in the widget's height/width to a shape coordinate. * @param coordinate the position your wish to have the shape coordinates of. */ virtual QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) = 0; /** * @brief updateCursor * Update the cursor position. */ void updateCursor(); QPointF convertKoColorToShapeCoordinate(KoColor c); KoColor convertShapeCoordinateToKoColor(QPointF coordinates, bool cursor = false); /** * @brief getPixmap * @return the pixmap of this shape. */ virtual QRegion getMaskMap() = 0; virtual void drawCursor() = 0; QVector convertvectorqrealTofloat(QVector real); QVector convertvectorfloatToqreal(QVector vloat); }; #endif diff --git a/libs/ui/widgets/KisVisualEllipticalSelectorShape.cpp b/libs/widgets/KisVisualEllipticalSelectorShape.cpp similarity index 100% rename from libs/ui/widgets/KisVisualEllipticalSelectorShape.cpp rename to libs/widgets/KisVisualEllipticalSelectorShape.cpp diff --git a/libs/ui/widgets/KisVisualEllipticalSelectorShape.h b/libs/widgets/KisVisualEllipticalSelectorShape.h similarity index 98% rename from libs/ui/widgets/KisVisualEllipticalSelectorShape.h rename to libs/widgets/KisVisualEllipticalSelectorShape.h index ab8075dbae..a09ecc156f 100644 --- a/libs/ui/widgets/KisVisualEllipticalSelectorShape.h +++ b/libs/widgets/KisVisualEllipticalSelectorShape.h @@ -1,75 +1,73 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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 KISVISUALCOLORSELECTOR_H #define KISVISUALCOLORSELECTOR_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" -#include "kritaui_export.h" - class KisVisualEllipticalSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{border, borderMirrored}; explicit KisVisualEllipticalSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int barWidth=20, KisVisualEllipticalSelectorShape::singelDTypes d = KisVisualEllipticalSelectorShape::border ); ~KisVisualEllipticalSelectorShape() override; void setBorderWidth(int width) override; /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; singelDTypes m_type; int m_barWidth; QRegion getMaskMap() override; void drawCursor() override; QSize sizeHint() const override; }; #endif // KISVISUALCOLORSELECTOR_H diff --git a/libs/ui/widgets/KisVisualRectangleSelectorShape.cpp b/libs/widgets/KisVisualRectangleSelectorShape.cpp similarity index 100% rename from libs/ui/widgets/KisVisualRectangleSelectorShape.cpp rename to libs/widgets/KisVisualRectangleSelectorShape.cpp diff --git a/libs/ui/widgets/KisVisualRectangleSelectorShape.h b/libs/widgets/KisVisualRectangleSelectorShape.h similarity index 98% rename from libs/ui/widgets/KisVisualRectangleSelectorShape.h rename to libs/widgets/KisVisualRectangleSelectorShape.h index 455a96ab11..4fe72d216c 100644 --- a/libs/ui/widgets/KisVisualRectangleSelectorShape.h +++ b/libs/widgets/KisVisualRectangleSelectorShape.h @@ -1,73 +1,71 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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_VISUAL_RECTANGLE_SELECTOR_SHAPE_H #define KIS_VISUAL_RECTANGLE_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" -#include "kritaui_export.h" - class KisVisualRectangleSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{vertical, horizontal, border, borderMirrored}; explicit KisVisualRectangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int width=20, KisVisualRectangleSelectorShape::singelDTypes d = KisVisualRectangleSelectorShape::vertical ); ~KisVisualRectangleSelectorShape() override; void setBorderWidth(int width) override; /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; singelDTypes m_type; int m_barWidth; QRegion getMaskMap() override; void drawCursor() override; }; #endif diff --git a/libs/ui/widgets/KisVisualTriangleSelectorShape.cpp b/libs/widgets/KisVisualTriangleSelectorShape.cpp similarity index 100% rename from libs/ui/widgets/KisVisualTriangleSelectorShape.cpp rename to libs/widgets/KisVisualTriangleSelectorShape.cpp diff --git a/libs/ui/widgets/KisVisualTriangleSelectorShape.h b/libs/widgets/KisVisualTriangleSelectorShape.h similarity index 98% rename from libs/ui/widgets/KisVisualTriangleSelectorShape.h rename to libs/widgets/KisVisualTriangleSelectorShape.h index d5c12320e7..fc4b68e82e 100644 --- a/libs/ui/widgets/KisVisualTriangleSelectorShape.h +++ b/libs/widgets/KisVisualTriangleSelectorShape.h @@ -1,79 +1,77 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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_VISUAL_TRIANGLE_SELECTOR_SHAPE_H #define KIS_VISUAL_TRIANGLE_SELECTOR_SHAPE_H #include #include #include #include #include #include #include #include "KoColorDisplayRendererInterface.h" #include "KisColorSelectorConfiguration.h" #include "KisVisualColorSelectorShape.h" -#include "kritaui_export.h" - class KisVisualTriangleSelectorShape : public KisVisualColorSelectorShape { Q_OBJECT public: enum singelDTypes{border, borderMirrored}; explicit KisVisualTriangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), int barwidth=20 ); ~KisVisualTriangleSelectorShape() override; void setBorderWidth(int width) override; void setTriangle(); /** * @brief getSpaceForSquare * @param geom the full widget rectangle * @return rectangle with enough space for second widget */ QRect getSpaceForSquare(QRect geom) override; QRect getSpaceForCircle(QRect geom) override; QRect getSpaceForTriangle(QRect geom) override; protected: void resizeEvent(QResizeEvent *) override; private: QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) override; QPointF convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) override; singelDTypes m_type; int m_barWidth; QPolygon m_triangle; QPointF m_center; qreal m_radius; QRegion getMaskMap() override; void drawCursor() override; }; #endif diff --git a/libs/ui/forms/wdgdlginternalcolorselector.ui b/libs/widgets/WdgDlgInternalColorSelector.ui similarity index 96% rename from libs/ui/forms/wdgdlginternalcolorselector.ui rename to libs/widgets/WdgDlgInternalColorSelector.ui index 3a35163995..b2c43046d5 100644 --- a/libs/ui/forms/wdgdlginternalcolorselector.ui +++ b/libs/widgets/WdgDlgInternalColorSelector.ui @@ -1,285 +1,279 @@ WdgDlgInternalColorSelector 0 0 505 483 Dialog 0 0 90 90 0 0 0 50 QFrame::StyledPanel QFrame::Sunken 2 2 0 0 0 0 0 0 0 50 70 0 0 25 25 0 0 90 0 0 - + 0 0 50 0 0 0 true - + 0 0 50 50 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok KisPopupButton QPushButton
kis_popup_button.h
KisPaletteView QTableView
kis_palette_view.h
SqueezedComboBox QComboBox
squeezedcombobox.h
KisSpinboxColorSelector QWidget
kis_spinbox_color_selector.h
1
- - KisScreenColorPicker - QWidget -
kis_screen_color_picker.h
- 1 -
KisVisualColorSelector QWidget
KisVisualColorSelector.h
1
KoColorPatch QWidget
KoColorPatch.h
1
buttonBox accepted() WdgDlgInternalColorSelector accept() 248 254 157 274 buttonBox rejected() WdgDlgInternalColorSelector reject() 316 260 286 274
diff --git a/libs/ui/widgets/kis_color_button.cpp b/libs/widgets/kis_color_button.cpp similarity index 99% rename from libs/ui/widgets/kis_color_button.cpp rename to libs/widgets/kis_color_button.cpp index 9d4d0056f4..ea6eeda34f 100644 --- a/libs/ui/widgets/kis_color_button.cpp +++ b/libs/widgets/kis_color_button.cpp @@ -1,382 +1,382 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) Copyright (C) 1999 Cristian Tibirna (ctibirna@kde.org) 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_color_button.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include class KisColorButton::KisColorButtonPrivate { public: KisColorButtonPrivate(KisColorButton *q); void _k_chooseColor(); void _k_colorChosen(); KisColorButton *q; KoColor m_defaultColor; bool m_bdefaultColor : 1; bool m_alphaChannel : 1; bool m_palette : 1; KoColor col; QPoint mPos; #ifndef Q_OS_OSX QPointer dialogPtr; #else QPointer dialogPtr; #endif void initStyleOption(QStyleOptionButton *opt) const; }; ///////////////////////////////////////////////////////////////////// // Functions duplicated from KColorMimeData // Should be kept in sync void _k_populateMimeData(QMimeData *mimeData, const KoColor &color) { mimeData->setColorData(color.toQColor()); mimeData->setText(color.toQColor().name()); } bool _k_canDecode(const QMimeData *mimeData) { if (mimeData->hasColor()) { return true; } if (mimeData->hasText()) { const QString colorName = mimeData->text(); if ((colorName.length() >= 4) && (colorName[0] == QLatin1Char('#'))) { return true; } } return false; } QColor _k_fromMimeData(const QMimeData *mimeData) { if (mimeData->hasColor()) { return mimeData->colorData().value(); } if (_k_canDecode(mimeData)) { return QColor(mimeData->text()); } return QColor(); } QDrag *_k_createDrag(const KoColor &color, QObject *dragsource) { QDrag *drag = new QDrag(dragsource); QMimeData *mime = new QMimeData; _k_populateMimeData(mime, color); drag->setMimeData(mime); QPixmap colorpix(25, 20); colorpix.fill(color.toQColor()); QPainter p(&colorpix); p.setPen(Qt::black); p.drawRect(0, 0, 24, 19); p.end(); drag->setPixmap(colorpix); drag->setHotSpot(QPoint(-5, -7)); return drag; } ///////////////////////////////////////////////////////////////////// KisColorButton::KisColorButtonPrivate::KisColorButtonPrivate(KisColorButton *q) : q(q) { m_bdefaultColor = false; m_alphaChannel = false; m_palette = true; q->setAcceptDrops(true); connect(q, SIGNAL(clicked()), q, SLOT(_k_chooseColor())); } KisColorButton::KisColorButton(QWidget *parent) : QPushButton(parent) , d(new KisColorButtonPrivate(this)) { } KisColorButton::KisColorButton(const KoColor &c, QWidget *parent) : QPushButton(parent) , d(new KisColorButtonPrivate(this)) { d->col = c; } KisColorButton::KisColorButton(const KoColor &c, const KoColor &defaultColor, QWidget *parent) : QPushButton(parent) , d(new KisColorButtonPrivate(this)) { d->col = c; setDefaultColor(defaultColor); } KisColorButton::~KisColorButton() { delete d; } KoColor KisColorButton::color() const { return d->col; } void KisColorButton::setColor(const KoColor &c) { d->col = c; update(); emit changed(d->col); } void KisColorButton::setAlphaChannelEnabled(bool alpha) { d->m_alphaChannel = alpha; } bool KisColorButton::isAlphaChannelEnabled() const { return d->m_alphaChannel; } void KisColorButton::setPaletteViewEnabled(bool enable) { d->m_palette = enable; } bool KisColorButton::paletteViewEnabled() const { return d->m_palette; } KoColor KisColorButton::defaultColor() const { return d->m_defaultColor; } void KisColorButton::setDefaultColor(const KoColor &c) { d->m_bdefaultColor = true; d->m_defaultColor = c; } void KisColorButton::KisColorButtonPrivate::initStyleOption(QStyleOptionButton *opt) const { opt->initFrom(q); opt->state |= q->isDown() ? QStyle::State_Sunken : QStyle::State_Raised; opt->features = QStyleOptionButton::None; if (q->isDefault()) { opt->features |= QStyleOptionButton::DefaultButton; } opt->text.clear(); opt->icon = QIcon(); } void KisColorButton::paintEvent(QPaintEvent *) { QPainter painter(this); QStyle *style = QWidget::style(); //First, we need to draw the bevel. QStyleOptionButton butOpt; d->initStyleOption(&butOpt); style->drawControl(QStyle::CE_PushButtonBevel, &butOpt, &painter, this); //OK, now we can muck around with drawing out pretty little color box //First, sort out where it goes QRect labelRect = style->subElementRect(QStyle::SE_PushButtonContents, &butOpt, this); int shift = style->pixelMetric(QStyle::PM_ButtonMargin, &butOpt, this) / 2; labelRect.adjust(shift, shift, -shift, -shift); int x, y, w, h; labelRect.getRect(&x, &y, &w, &h); if (isChecked() || isDown()) { x += style->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &butOpt, this); y += style->pixelMetric(QStyle::PM_ButtonShiftVertical, &butOpt, this); } QColor fillCol = isEnabled() ? d->col.toQColor() : palette().color(backgroundRole()); qDrawShadePanel(&painter, x, y, w, h, palette(), true, 1, NULL); if (fillCol.isValid()) { const QRect rect(x + 1, y + 1, w - 2, h - 2); if (fillCol.alpha() < 255) { QPixmap chessboardPattern(16, 16); QPainter patternPainter(&chessboardPattern); patternPainter.fillRect(0, 0, 8, 8, Qt::black); patternPainter.fillRect(8, 8, 8, 8, Qt::black); patternPainter.fillRect(0, 8, 8, 8, Qt::white); patternPainter.fillRect(8, 0, 8, 8, Qt::white); patternPainter.end(); painter.fillRect(rect, QBrush(chessboardPattern)); } painter.fillRect(rect, fillCol); } if (hasFocus()) { QRect focusRect = style->subElementRect(QStyle::SE_PushButtonFocusRect, &butOpt, this); QStyleOptionFocusRect focusOpt; focusOpt.init(this); focusOpt.rect = focusRect; focusOpt.backgroundColor = palette().background().color(); style->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOpt, &painter, this); } } QSize KisColorButton::sizeHint() const { QStyleOptionButton opt; d->initStyleOption(&opt); return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(40, 15), this). expandedTo(QApplication::globalStrut()); } QSize KisColorButton::minimumSizeHint() const { QStyleOptionButton opt; d->initStyleOption(&opt); return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(3, 3), this). expandedTo(QApplication::globalStrut()); } void KisColorButton::dragEnterEvent(QDragEnterEvent *event) { event->setAccepted(_k_canDecode(event->mimeData()) && isEnabled()); } void KisColorButton::dropEvent(QDropEvent *event) { QColor c = _k_fromMimeData(event->mimeData()); if (c.isValid()) { KoColor col; col.fromQColor(c); setColor(col); } } void KisColorButton::keyPressEvent(QKeyEvent *e) { int key = e->key() | e->modifiers(); if (QKeySequence::keyBindings(QKeySequence::Copy).contains(key)) { QMimeData *mime = new QMimeData; _k_populateMimeData(mime, color()); QApplication::clipboard()->setMimeData(mime, QClipboard::Clipboard); } else if (QKeySequence::keyBindings(QKeySequence::Paste).contains(key)) { QColor color = _k_fromMimeData(QApplication::clipboard()->mimeData(QClipboard::Clipboard)); KoColor col; col.fromQColor(color); setColor(col); } else { QPushButton::keyPressEvent(e); } } void KisColorButton::mousePressEvent(QMouseEvent *e) { d->mPos = e->pos(); QPushButton::mousePressEvent(e); } void KisColorButton::mouseMoveEvent(QMouseEvent *e) { if ((e->buttons() & Qt::LeftButton) && (e->pos() - d->mPos).manhattanLength() > QApplication::startDragDistance()) { _k_createDrag(color(), this)->start(); setDown(false); } } void KisColorButton::KisColorButtonPrivate::_k_chooseColor() { #ifndef Q_OS_OSX KisDlgInternalColorSelector *dialog = dialogPtr.data(); #else QColorDialog *dialog = dialogPtr.data(); #endif if (dialog) { #ifndef Q_OS_OSX dialog->setPreviousColor(q->color()); #else dialog->setCurrentColor(q->color().toQColor()); #endif dialog->show(); dialog->raise(); dialog->activateWindow(); return; } KisDlgInternalColorSelector::Config cfg; cfg.paletteBox = q->paletteViewEnabled(); #ifndef Q_OS_OSX dialog = new KisDlgInternalColorSelector(q, q->color(), cfg, i18n("Choose a color")); #else dialog = new QColorDialog(q); dialog->setOption(QColorDialog::ShowAlphaChannel, m_alphaChannel); #endif dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(accepted()), q, SLOT(_k_colorChosen())); dialogPtr = dialog; #ifndef Q_OS_OSX dialog->setPreviousColor(q->color()); #else dialog->setCurrentColor(q->color().toQColor()); #endif dialog->show(); } void KisColorButton::KisColorButtonPrivate::_k_colorChosen() { #ifndef Q_OS_OSX KisDlgInternalColorSelector *dialog = dialogPtr.data(); #else QColorDialog *dialog = dialogPtr.data(); #endif if (!dialog) { return; } #ifndef Q_OS_OSX q->setColor(dialog->getCurrentColor()); #else KoColor c; c.fromQColor(dialog->currentColor()); q->setColor(c); #endif } #include "moc_kis_color_button.cpp" diff --git a/libs/ui/widgets/kis_color_button.h b/libs/widgets/kis_color_button.h similarity index 97% rename from libs/ui/widgets/kis_color_button.h rename to libs/widgets/kis_color_button.h index 065b6ed267..703e9a7c7b 100644 --- a/libs/ui/widgets/kis_color_button.h +++ b/libs/widgets/kis_color_button.h @@ -1,137 +1,137 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * This file is forked from the KF5 KColorButton Copyright (C) 1997 Martin Jones (mjones@kde.org) 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 KisColorButton_H #define KisColorButton_H -#include +#include #include #include class KisColorButtonPrivate; /** * @short A pushbutton to display or allow user selection of a color. * * This widget can be used to display or allow user selection of a color. * * @see QColorDialog * * \image html KisColorButton.png "KDE Color Button" */ -class KRITAUI_EXPORT KisColorButton : public QPushButton +class KRITAWIDGETS_EXPORT KisColorButton : public QPushButton { Q_OBJECT /** * QtCreator treats KoColor as a QColor in incorrect way, so just disable using them in QtCreator * https://bugs.kde.org/show_bug.cgi?id=368483 */ Q_PROPERTY(KoColor color READ color WRITE setColor NOTIFY changed USER true DESIGNABLE false) Q_PROPERTY(KoColor defaultColor READ defaultColor WRITE setDefaultColor DESIGNABLE false) Q_PROPERTY(bool alphaChannelEnabled READ isAlphaChannelEnabled WRITE setAlphaChannelEnabled) public: /** * Creates a color button. */ explicit KisColorButton(QWidget *parent = 0); /** * Creates a color button with an initial color @p c. */ explicit KisColorButton(const KoColor &c, QWidget *parent = 0); /** * Creates a color button with an initial color @p c and default color @p defaultColor. */ KisColorButton(const KoColor &c, const KoColor &defaultColor, QWidget *parent = 0); ~KisColorButton() override; /** * Returns the currently chosen color. */ KoColor color() const; /** * Sets the current color to @p c. */ void setColor(const KoColor &c); /** * When set to true, allow the user to change the alpha component * of the color. The default value is false. */ void setAlphaChannelEnabled(bool alpha); /** * Returns true if the user is allowed to change the alpha component. */ bool isAlphaChannelEnabled() const; /** * Allow having a palette. */ void setPaletteViewEnabled( bool enable); /** * @brief paletteViewEnabled * @return whether the palette is enabled. */ bool paletteViewEnabled() const; /** * Returns the default color or an invalid color * if no default color is set. */ KoColor defaultColor() const; /** * Sets the default color to @p c. */ void setDefaultColor(const KoColor &c); QSize sizeHint() const override; QSize minimumSizeHint() const override; Q_SIGNALS: /** * Emitted when the color of the widget * is changed, either with setColor() or via user selection. */ void changed(const KoColor &newColor); protected: void paintEvent(QPaintEvent *pe) override; void dragEnterEvent(QDragEnterEvent *) override; void dropEvent(QDropEvent *) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void keyPressEvent(QKeyEvent *e) override; private: class KisColorButtonPrivate; KisColorButtonPrivate *const d; Q_PRIVATE_SLOT(d, void _k_chooseColor()) Q_PRIVATE_SLOT(d, void _k_colorChosen()) }; #endif diff --git a/libs/ui/widgets/kis_color_input.cpp b/libs/widgets/kis_color_input.cpp similarity index 100% rename from libs/ui/widgets/kis_color_input.cpp rename to libs/widgets/kis_color_input.cpp diff --git a/libs/ui/widgets/kis_color_input.h b/libs/widgets/kis_color_input.h similarity index 91% rename from libs/ui/widgets/kis_color_input.h rename to libs/widgets/kis_color_input.h index ade2fda5fa..a6a92196f8 100644 --- a/libs/ui/widgets/kis_color_input.h +++ b/libs/widgets/kis_color_input.h @@ -1,109 +1,109 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_COLOR_INPUT_H_ #define _KIS_COLOR_INPUT_H_ #include class KoChannelInfo; class KoColor; class QWidget; class QSpinBox; class QDoubleSpinBox; class KisIntParseSpinBox; class KisDoubleParseSpinBox; class KoColorSlider; class QLineEdit; #include -#include "kritaui_export.h" +#include "kritawidgets_export.h" -class KRITAUI_EXPORT KisColorInput : public QWidget +class KRITAWIDGETS_EXPORT KisColorInput : public QWidget { Q_OBJECT public: KisColorInput(QWidget* parent, const KoChannelInfo*, KoColor* color, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), bool usePercentage = false); inline bool usePercentage() const { return m_usePercentage; } inline void setPercentageWise(bool val) { m_usePercentage = val; } protected: void init(); virtual QWidget* createInput() = 0; Q_SIGNALS: void updated(); protected: const KoChannelInfo* m_channelInfo; KoColor* m_color; KoColorSlider* m_colorSlider; KoColorDisplayRendererInterface *m_displayRenderer; bool m_usePercentage; }; -class KRITAUI_EXPORT KisIntegerColorInput : public KisColorInput +class KRITAWIDGETS_EXPORT KisIntegerColorInput : public KisColorInput { Q_OBJECT public: KisIntegerColorInput(QWidget* parent, const KoChannelInfo*, KoColor* color, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), bool usePercentage = false); protected: QWidget* createInput() override; public Q_SLOTS: void setValue(int); void update(); private Q_SLOTS: void onColorSliderChanged(int); void onNumInputChanged(int); private: KisIntParseSpinBox* m_intNumInput; }; -class KRITAUI_EXPORT KisFloatColorInput : public KisColorInput +class KRITAWIDGETS_EXPORT KisFloatColorInput : public KisColorInput { Q_OBJECT public: KisFloatColorInput(QWidget* parent, const KoChannelInfo*, KoColor* color, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), bool usePercentage = false); protected: QWidget* createInput() override; public Q_SLOTS: void setValue(double); void sliderChanged(int); void update(); private: KisDoubleParseSpinBox* m_dblNumInput; qreal m_minValue; qreal m_maxValue; }; -class KRITAUI_EXPORT KisHexColorInput : public KisColorInput +class KRITAWIDGETS_EXPORT KisHexColorInput : public KisColorInput { Q_OBJECT public: KisHexColorInput(QWidget* parent, KoColor* color, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), bool usePercentage = false); protected: QWidget* createInput() override; public Q_SLOTS: void setValue(); void update(); private: QLineEdit* m_hexInput; }; #endif diff --git a/libs/ui/kis_palette_delegate.cpp b/libs/widgets/kis_palette_delegate.cpp similarity index 100% rename from libs/ui/kis_palette_delegate.cpp rename to libs/widgets/kis_palette_delegate.cpp diff --git a/libs/ui/kis_palette_delegate.h b/libs/widgets/kis_palette_delegate.h similarity index 92% rename from libs/ui/kis_palette_delegate.h rename to libs/widgets/kis_palette_delegate.h index 010d3610f8..3b85bbf9ea 100644 --- a/libs/ui/kis_palette_delegate.h +++ b/libs/widgets/kis_palette_delegate.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2016 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_PALETTE_DELEGATE_H #define __KIS_PALETTE_DELEGATE_H #include -#include "kritaui_export.h" +#include "kritawidgets_export.h" -class KRITAUI_EXPORT KisPaletteDelegate : public QAbstractItemDelegate +class KRITAWIDGETS_EXPORT KisPaletteDelegate : public QAbstractItemDelegate { public: KisPaletteDelegate(QObject * parent = 0); ~KisPaletteDelegate() override; void setCrossedKeyword(const QString &value); void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override; private: QString m_crossedKeyword; }; #endif /* __KIS_PALETTE_DELEGATE_H */ diff --git a/libs/ui/kis_palette_view.cpp b/libs/widgets/kis_palette_view.cpp similarity index 91% rename from libs/ui/kis_palette_view.cpp rename to libs/widgets/kis_palette_view.cpp index 04c70c32af..7434559820 100644 --- a/libs/ui/kis_palette_view.cpp +++ b/libs/widgets/kis_palette_view.cpp @@ -1,344 +1,342 @@ /* * Copyright (c) 2016 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_palette_view.h" #include #include - -#include "kis_palette_delegate.h" -#include "KisPaletteModel.h" -#include "kis_config.h" -#include -#include #include #include #include -#include #include #include #include +#include +#include +#include + +#include + +#include "kis_palette_delegate.h" +#include "KisPaletteModel.h" +#include "kis_color_button.h" struct KisPaletteView::Private { KisPaletteModel *model = nullptr; bool allowPaletteModification = true; }; - KisPaletteView::KisPaletteView(QWidget *parent) : KoTableView(parent) , m_d(new Private) { setShowGrid(false); horizontalHeader()->setVisible(false); verticalHeader()->setVisible(false); setItemDelegate(new KisPaletteDelegate()); // setDragEnabled(true); // setDragDropMode(QAbstractItemView::InternalMove); setDropIndicatorShown(true); - KisConfig cfg; + KConfigGroup cfg(KSharedConfig::openConfig()->group("")); //QPalette pal(palette()); //pal.setColor(QPalette::Base, cfg.getMDIBackgroundColor()); //setAutoFillBackground(true); //setPalette(pal); - int defaultSectionSize = cfg.paletteDockerPaletteViewSectionSize(); + int defaultSectionSize = cfg.readEntry("paletteDockerPaletteViewSectionSize", 12); horizontalHeader()->setDefaultSectionSize(defaultSectionSize); verticalHeader()->setDefaultSectionSize(defaultSectionSize); connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(modifyEntry(QModelIndex))); } KisPaletteView::~KisPaletteView() { } void KisPaletteView::setCrossedKeyword(const QString &value) { KisPaletteDelegate *delegate = dynamic_cast(itemDelegate()); KIS_ASSERT_RECOVER_RETURN(delegate); delegate->setCrossedKeyword(value); } bool KisPaletteView::addEntryWithDialog(KoColor color) { - KoDialog *window = new KoDialog(); + KoDialog *window = new KoDialog(this); window->setWindowTitle(i18nc("@title:window", "Add a new Colorset Entry")); - QFormLayout *editableItems = new QFormLayout(); + QFormLayout *editableItems = new QFormLayout(window); window->mainWidget()->setLayout(editableItems); - QComboBox *cmbGroups = new QComboBox(); + QComboBox *cmbGroups = new QComboBox(window); QString defaultGroupName = i18nc("Name for default group", "Default"); cmbGroups->addItem(defaultGroupName); cmbGroups->addItems(m_d->model->colorSet()->getGroupNames()); - QLineEdit *lnIDName = new QLineEdit(); - QLineEdit *lnName = new QLineEdit(); - KisColorButton *bnColor = new KisColorButton(); - bnColor->setPaletteViewEnabled(false); - QCheckBox *chkSpot = new QCheckBox(); + QLineEdit *lnIDName = new QLineEdit(window); + QLineEdit *lnName = new QLineEdit(window); + KisColorButton *bnColor = new KisColorButton(window); + QCheckBox *chkSpot = new QCheckBox(window); chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); editableItems->addRow(i18n("Group"), cmbGroups); editableItems->addRow(i18n("ID"), lnIDName); editableItems->addRow(i18n("Name"), lnName); editableItems->addRow(i18n("Color"), bnColor); editableItems->addRow(i18nc("Spot color", "Spot"), chkSpot); cmbGroups->setCurrentIndex(0); lnName->setText(i18nc("Part of a default name for a color","Color")+" "+QString::number(m_d->model->colorSet()->nColors()+1)); lnIDName->setText(QString::number(m_d->model->colorSet()->nColors()+1)); bnColor->setColor(color); chkSpot->setChecked(false); - // if (window->exec() == KoDialog::Accepted) { QString groupName = cmbGroups->currentText(); if (groupName == defaultGroupName) { groupName = QString(); } KoColorSetEntry newEntry; newEntry.setColor(bnColor->color()); newEntry.setName(lnName->text()); newEntry.setId(lnIDName->text()); newEntry.setSpotColor(chkSpot->isChecked()); m_d->model->addColorSetEntry(newEntry, groupName); m_d->model->colorSet()->save(); return true; } return false; } // should be move to colorSetChooser bool KisPaletteView::addGroupWithDialog() { KoDialog *window = new KoDialog(); window->setWindowTitle(i18nc("@title:window","Add a new group")); QFormLayout *editableItems = new QFormLayout(); window->mainWidget()->setLayout(editableItems); QLineEdit *lnName = new QLineEdit(); editableItems->addRow(i18nc("Name for a group", "Name"), lnName); lnName->setText(i18nc("Part of default name for a new group", "Color Group")+""+QString::number(m_d->model->colorSet()->getGroupNames().size()+1)); if (window->exec() == KoDialog::Accepted) { QString groupName = lnName->text(); m_d->model->addGroup(groupName); m_d->model->colorSet()->save(); return true; } return false; } bool KisPaletteView::removeEntryWithDialog(QModelIndex index) { bool keepColors = true; if (qvariant_cast(index.data(KisPaletteModel::IsHeaderRole))) { KoDialog *window = new KoDialog(); window->setWindowTitle(i18nc("@title:window","Removing Group")); QFormLayout *editableItems = new QFormLayout(); QCheckBox *chkKeep = new QCheckBox(); window->mainWidget()->setLayout(editableItems); editableItems->addRow(i18nc("Shows up when deleting a group","Keep the Colors"), chkKeep); chkKeep->setChecked(keepColors); if (window->exec() == KoDialog::Accepted) { keepColors = chkKeep->isChecked(); m_d->model->removeEntry(index, keepColors); m_d->model->colorSet()->save(); } } else { m_d->model->removeEntry(index, keepColors); m_d->model->colorSet()->save(); } return true; } void KisPaletteView::trySelectClosestColor(KoColor color) { KoColorSet* color_set = m_d->model->colorSet(); if (!color_set) return; //also don't select if the color is the same as the current selection if (selectedIndexes().size()>0) { QModelIndex currentI = currentIndex(); if (!currentI.isValid()) { currentI = selectedIndexes().last(); } if (!currentI.isValid()) { currentI = selectedIndexes().first(); } if (currentI.isValid()) { if (m_d->model->colorSetEntryFromIndex(currentI).color()==color) { return; } } } quint32 i = color_set->getIndexClosestColor(color); QModelIndex index = m_d->model->indexFromId(i); this->selectionModel()->clearSelection(); this->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select); } void KisPaletteView::mouseReleaseEvent(QMouseEvent *event) { bool foreground = false; if (event->button()== Qt::LeftButton) { foreground = true; } entrySelection(foreground); } void KisPaletteView::paletteModelChanged() { updateView(); updateRows(); } void KisPaletteView::setPaletteModel(KisPaletteModel *model) { if (m_d->model) { disconnect(m_d->model, 0, this, 0); } m_d->model = model; setModel(model); paletteModelChanged(); connect(m_d->model, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), this, SLOT(paletteModelChanged())); connect(m_d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(paletteModelChanged())); connect(m_d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(paletteModelChanged())); connect(m_d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(paletteModelChanged())); connect(m_d->model, SIGNAL(modelReset()), this, SLOT(paletteModelChanged())); } KisPaletteModel* KisPaletteView::paletteModel() const { return m_d->model; } void KisPaletteView::updateRows() { this->clearSpans(); if (m_d->model) { for (int r=0; r<=m_d->model->rowCount(); r++) { QModelIndex index = m_d->model->index(r, 0); if (qvariant_cast(index.data(KisPaletteModel::IsHeaderRole))) { setSpan(r, 0, 1, m_d->model->columnCount()); setRowHeight(r, this->fontMetrics().lineSpacing()+6); } else { this->setRowHeight(r, this->columnWidth(0)); } } } } void KisPaletteView::setAllowModification(bool allow) { m_d->allowPaletteModification = allow; } void KisPaletteView::wheelEvent(QWheelEvent *event) { if (event->modifiers() & Qt::ControlModifier) { int numDegrees = event->delta() / 8; int numSteps = numDegrees / 7; int curSize = horizontalHeader()->sectionSize(0); int setSize = numSteps + curSize; if ( (event->delta() <= 0) && (setSize <= 8) ) { // Ignore scroll-zooming down below a certain size } else { horizontalHeader()->setDefaultSectionSize(setSize); verticalHeader()->setDefaultSectionSize(setSize); - KisConfig cfg; - cfg.setPaletteDockerPaletteViewSectionSize(setSize); + KConfigGroup cfg(KSharedConfig::openConfig()->group("")); + cfg.writeEntry("paletteDockerPaletteViewSectionSize", setSize); } event->accept(); } else { KoTableView::wheelEvent(event); } } void KisPaletteView::entrySelection(bool foreground) { QModelIndex index; if (selectedIndexes().size()<=0) { return; } if (selectedIndexes().last().isValid()) { index = selectedIndexes().last(); } else if (selectedIndexes().first().isValid()) { index = selectedIndexes().first(); } else { return; } if (qvariant_cast(index.data(KisPaletteModel::IsHeaderRole))==false) { KoColorSetEntry entry = m_d->model->colorSetEntryFromIndex(index); if (foreground) { emit(entrySelected(entry)); emit(indexEntrySelected(index)); } else { emit(entrySelectedBackGround(entry)); emit(indexEntrySelected(index)); } } } void KisPaletteView::modifyEntry(QModelIndex index) { if (m_d->allowPaletteModification) { - KoDialog *group = new KoDialog(); - QFormLayout *editableItems = new QFormLayout(); + KoDialog *group = new KoDialog(this); + QFormLayout *editableItems = new QFormLayout(group); group->mainWidget()->setLayout(editableItems); - QLineEdit *lnIDName = new QLineEdit(); - QLineEdit *lnGroupName = new QLineEdit(); - KisColorButton *bnColor = new KisColorButton(); - bnColor->setPaletteViewEnabled(false); - QCheckBox *chkSpot = new QCheckBox(); + QLineEdit *lnIDName = new QLineEdit(group); + QLineEdit *lnGroupName = new QLineEdit(group); + KisColorButton *bnColor = new KisColorButton(group); + QCheckBox *chkSpot = new QCheckBox(group); if (qvariant_cast(index.data(KisPaletteModel::IsHeaderRole))) { QString groupName = qvariant_cast(index.data(Qt::DisplayRole)); editableItems->addRow(i18nc("Name for a colorgroup","Name"), lnGroupName); lnGroupName->setText(groupName); if (group->exec() == KoDialog::Accepted) { m_d->model->colorSet()->changeGroupName(groupName, lnGroupName->text()); m_d->model->colorSet()->save(); updateRows(); } //rename the group. } else { KoColorSetEntry entry = m_d->model->colorSetEntryFromIndex(index); QStringList entryList = qvariant_cast(index.data(KisPaletteModel::RetrieveEntryRole)); chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); editableItems->addRow(i18n("ID"), lnIDName); editableItems->addRow(i18n("Name"), lnGroupName); editableItems->addRow(i18n("Color"), bnColor); editableItems->addRow(i18n("Spot"), chkSpot); lnGroupName->setText(entry.name()); lnIDName->setText(entry.id()); bnColor->setColor(entry.color()); chkSpot->setChecked(entry.spotColor()); if (group->exec() == KoDialog::Accepted) { entry.setName(lnGroupName->text()); entry.setId(lnIDName->text()); entry.setColor(bnColor->color()); entry.setSpotColor(chkSpot->isChecked()); m_d->model->colorSet()->changeColorSetEntry(entry, entryList.at(0), entryList.at(1).toUInt()); m_d->model->colorSet()->save(); } } } } diff --git a/libs/ui/kis_palette_view.h b/libs/widgets/kis_palette_view.h similarity index 95% rename from libs/ui/kis_palette_view.h rename to libs/widgets/kis_palette_view.h index cd0da8d657..fa8795289e 100644 --- a/libs/ui/kis_palette_view.h +++ b/libs/widgets/kis_palette_view.h @@ -1,113 +1,119 @@ /* * Copyright (c) 2016 Dmitry Kazakov * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * 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_PALETTE_VIEW_H #define __KIS_PALETTE_VIEW_H #include + +#include +#include +#include +#include + #include #include -#include "kritaui_export.h" +#include "kritawidgets_export.h" class KisPaletteModel; class QWheelEvent; -class KRITAUI_EXPORT KisPaletteView : public KoTableView +class KRITAWIDGETS_EXPORT KisPaletteView : public KoTableView { Q_OBJECT public: KisPaletteView(QWidget *parent = 0); ~KisPaletteView() override; void setPaletteModel(KisPaletteModel *model); KisPaletteModel* paletteModel() const; /** * @brief updateRows * update the rows so they have the proper columnspanning. */ void updateRows(); /** * @brief setAllowModification * Set whether doubleclick calls up a modification window. This is to prevent users from editing * the palette when the palette is intended to be a list of items. */ void setAllowModification(bool allow); /** * @brief setCrossedKeyword * this apparently allows you to set keywords that can cross out colors. * This is implemented to mark the lazybrush "transparent" color. * @param value */ void setCrossedKeyword(const QString &value); public Q_SLOTS: void paletteModelChanged(); /** * add an entry with a dialog window. */ bool addEntryWithDialog(KoColor color); /** * @brief addGroupWithDialog * summons a little dialog to name the new group. */ bool addGroupWithDialog(); /** * remove entry with a dialog window.(Necessary for groups. */ bool removeEntryWithDialog(QModelIndex index); /** * This tries to select the closest color in the palette. * This doesn't update the foreground color, just the visual selection. */ void trySelectClosestColor(KoColor color); Q_SIGNALS: /** * @brief entrySelected * signals when an entry is selected. * @param entry the selected entry. */ void entrySelected(KoColorSetEntry entry); void entrySelectedBackGround(KoColorSetEntry entry); void indexEntrySelected(QModelIndex index); protected: void mouseReleaseEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; private: struct Private; const QScopedPointer m_d; private Q_SLOTS: /** * @brief entrySelection * the function that will emit entrySelected when the entry changes. */ void entrySelection(bool foreground = true); /** * @brief modifyEntry * function for changing the entry at the given index. * if modification isn't allow(@see setAllowModification), this does nothing. */ void modifyEntry(QModelIndex index); }; #endif /* __KIS_PALETTE_VIEW_H */ diff --git a/libs/ui/widgets/kis_popup_button.cc b/libs/widgets/kis_popup_button.cc similarity index 87% rename from libs/ui/widgets/kis_popup_button.cc rename to libs/widgets/kis_popup_button.cc index 357091f1a3..05e0a129b8 100644 --- a/libs/ui/widgets/kis_popup_button.cc +++ b/libs/widgets/kis_popup_button.cc @@ -1,158 +1,144 @@ /* * Copyright (c) 2007 Cyrille Berger * Copyright (c) 2008 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 "widgets/kis_popup_button.h" +#include "kis_popup_button.h" #include #include #include #include #include #include #include #include "kis_global.h" #include -#include - struct KisPopupButton::Private { Private() : frameLayout(0) {} QScopedPointer frame; QPointer popupWidget; QPointer frameLayout; }; KisPopupButton::KisPopupButton(QWidget* parent) : QPushButton(parent) , m_d(new Private) { setObjectName("KisPopupButton"); connect(this, SIGNAL(released()), SLOT(showPopupWidget())); } KisPopupButton::~KisPopupButton() { delete m_d; } void KisPopupButton::setAlwaysVisible(bool v) { if (v) { m_d->frame->setFrameStyle(Qt::SubWindow); showPopupWidget(); } else { m_d->frame->setFrameStyle(Qt::Popup); } } void KisPopupButton::setPopupWidget(QWidget* widget) { if (widget) { /** * Set parent explicitly to null to avoid propagation of the * ignored events (specifically, QEvent::ShortcutOverride) to * the view object. This avoids starting global actions while * the PopUp is active. See bug 329842. */ m_d->frame.reset(new QFrame(0)); m_d->frame->setObjectName("popup frame"); m_d->frame->setFrameStyle(QFrame::Box | QFrame::Plain); m_d->frame->setWindowFlags(Qt::Popup); m_d->frameLayout = new QHBoxLayout(m_d->frame.data()); m_d->frameLayout->setMargin(0); m_d->frameLayout->setSizeConstraint(QLayout::SetFixedSize); m_d->frame->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); m_d->popupWidget = widget; m_d->popupWidget->setParent(m_d->frame.data()); m_d->frameLayout->addWidget(m_d->popupWidget); - - // Workaround for bug 279740, preset popup widget resizes after it's shown for the first time - // so we catch that and correct the position - KisPaintOpPresetsPopup* presetPopup = dynamic_cast(widget); - if (presetPopup) { - connect(presetPopup, SIGNAL(sizeChanged()), this, SLOT(adjustPosition())); - } } } void KisPopupButton::setPopupWidgetWidth(int w) { m_d->frame->resize(w, m_d->frame->height()); } void KisPopupButton::showPopupWidget() { if (m_d->popupWidget && !m_d->frame->isVisible()) { m_d->frame->raise(); m_d->frame->show(); adjustPosition(); } else { hidePopupWidget(); } } void KisPopupButton::hidePopupWidget() { if (m_d->popupWidget) { m_d->frame->setVisible(false); } } void KisPopupButton::paintEvent ( QPaintEvent * event ) { QPushButton::paintEvent(event); paintPopupArrow(); } void KisPopupButton::paintPopupArrow() { QStylePainter p(this); QStyleOption option; option.rect = QRect(rect().right() - 15, rect().bottom() - 15, 14, 14); option.palette = palette(); option.palette.setBrush(QPalette::ButtonText, Qt::black); // Force color to black option.state = QStyle::State_Enabled; p.setBrush(Qt::black); // work around some theme that don't use QPalette::ButtonText like they should, but instead the QPainter brushes and pen p.setPen(Qt::black); p.drawPrimitive(QStyle::PE_IndicatorArrowDown, option); } void KisPopupButton::adjustPosition() { - KisPaintOpPresetsPopup* presetPopup = dynamic_cast(m_d->popupWidget.data()); - if (presetPopup && presetPopup->detached()) { - return; - } - QSize popSize = m_d->popupWidget->size(); QRect popupRect(this->mapToGlobal(QPoint(0, this->size().height())), popSize); // Get the available geometry of the screen which contains this KisPopupButton QDesktopWidget* desktopWidget = QApplication::desktop(); QRect screenRect = desktopWidget->availableGeometry(this); popupRect = kisEnsureInRect(popupRect, screenRect); m_d->frame->setGeometry(popupRect); } diff --git a/libs/ui/widgets/kis_popup_button.h b/libs/widgets/kis_popup_button.h similarity index 87% rename from libs/ui/widgets/kis_popup_button.h rename to libs/widgets/kis_popup_button.h index 22e44809a7..1e25a80cca 100644 --- a/libs/ui/widgets/kis_popup_button.h +++ b/libs/widgets/kis_popup_button.h @@ -1,76 +1,82 @@ /* * Copyright (c) 2007 Cyrille Berger * * 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_POPUP_BUTTON_H_ #define _KIS_POPUP_BUTTON_H_ #include -#include +#include /** * This class is a convenience class for a button that * when clicked displays a popup widget. */ -class KRITAUI_EXPORT KisPopupButton : public QPushButton +class KRITAWIDGETS_EXPORT KisPopupButton : public QPushButton { Q_OBJECT public: KisPopupButton(QWidget* parent); ~KisPopupButton() override; /** * Set the popup widget, the KisPopupButton becomes * the owner and parent of the widget. */ void setPopupWidget(QWidget* widget); /** * This function allow to force the popup to be visible. * @param v set to true to force the popup to be visible, set to false * to allow the popup to be hidden */ void setAlwaysVisible(bool v); /** * Set the width of the popup widget. * @return new width of the popup widget */ void setPopupWidgetWidth(int w); + /** + * @brief adjustPosition + * adjusts the position of the popup widget based on the position + * of this button and the size of the widget + */ + void adjustPosition(); + public Q_SLOTS: void showPopupWidget(); void hidePopupWidget(); - void adjustPosition(); protected: void paintEvent(QPaintEvent* event) override; void paintPopupArrow(); private: struct Private; Private* const m_d; }; #endif diff --git a/libs/ui/widgets/kis_spinbox_color_selector.cpp b/libs/widgets/kis_spinbox_color_selector.cpp similarity index 100% rename from libs/ui/widgets/kis_spinbox_color_selector.cpp rename to libs/widgets/kis_spinbox_color_selector.cpp diff --git a/libs/ui/widgets/kis_spinbox_color_selector.h b/libs/widgets/kis_spinbox_color_selector.h similarity index 94% rename from libs/ui/widgets/kis_spinbox_color_selector.h rename to libs/widgets/kis_spinbox_color_selector.h index 772f4fe882..9bf9f73605 100644 --- a/libs/ui/widgets/kis_spinbox_color_selector.h +++ b/libs/widgets/kis_spinbox_color_selector.h @@ -1,59 +1,59 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * 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 KISSPINBOXCOLORSELECTOR_H #define KISSPINBOXCOLORSELECTOR_H #include -#include "kritaui_export.h" +#include "kritawidgets_export.h" #include #include "KoColor.h" #include "KoColorSpace.h" /** * @brief The KisSpinboxColorSelector class * This will give a widget with spinboxes depending on the color space * Take responsibility for changing the color space. */ -class KRITAUI_EXPORT KisSpinboxColorSelector : public QWidget +class KRITAWIDGETS_EXPORT KisSpinboxColorSelector : public QWidget { Q_OBJECT public: explicit KisSpinboxColorSelector(QWidget *parent); ~KisSpinboxColorSelector() override; void chooseAlpha(bool chooseAlpha); Q_SIGNALS: void sigNewColor(KoColor color); public Q_SLOTS: void slotSetColorSpace(const KoColorSpace *cs); void slotSetColor(KoColor color); private Q_SLOTS: void slotUpdateFromSpinBoxes(); private: struct Private; const QScopedPointer m_d; void createColorFromSpinboxValues(); void updateSpinboxesWithNewValues(); }; #endif // KISSPINBOXCOLORSELECTOR_H diff --git a/plugins/dockers/palettedocker/palettedocker_dock.cpp b/plugins/dockers/palettedocker/palettedocker_dock.cpp index 599b919a25..e7108d9d2e 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.cpp +++ b/plugins/dockers/palettedocker/palettedocker_dock.cpp @@ -1,309 +1,309 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "palettedocker_dock.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 "KisPaletteModel.h" -#include "KisColorsetChooser.h" #include "ui_wdgpalettedock.h" #include "kis_palette_delegate.h" #include "kis_palette_view.h" +#include PaletteDockerDock::PaletteDockerDock( ) : QDockWidget(i18n("Palette")) , m_wdgPaletteDock(new Ui_WdgPaletteDock()) , m_currentColorSet(0) , m_resourceProvider(0) , m_canvas(0) { QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_wdgPaletteDock->setupUi(mainWidget); m_wdgPaletteDock->bnAdd->setIcon(KisIconUtils::loadIcon("list-add")); m_wdgPaletteDock->bnAdd->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnRemove->setIcon(KisIconUtils::loadIcon("edit-delete")); m_wdgPaletteDock->bnRemove->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); m_wdgPaletteDock->bnAddDialog->setVisible(false); m_wdgPaletteDock->bnAddGroup->setIcon(KisIconUtils::loadIcon("groupLayer")); m_wdgPaletteDock->bnAddGroup->setIconSize(QSize(16, 16)); m_model = new KisPaletteModel(this); m_wdgPaletteDock->paletteView->setPaletteModel(m_model); connect(m_wdgPaletteDock->bnAdd, SIGNAL(clicked(bool)), this, SLOT(addColorForeground())); connect(m_wdgPaletteDock->bnRemove, SIGNAL(clicked(bool)), this, SLOT(removeColor())); connect(m_wdgPaletteDock->bnAddGroup, SIGNAL(clicked(bool)), m_wdgPaletteDock->paletteView, SLOT(addGroupWithDialog())); connect(m_wdgPaletteDock->paletteView, SIGNAL(entrySelected(KoColorSetEntry)), this, SLOT(entrySelected(KoColorSetEntry))); connect(m_wdgPaletteDock->paletteView, SIGNAL(entrySelectedBackGround(KoColorSetEntry)), this, SLOT(entrySelectedBack(KoColorSetEntry))); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); m_serverAdapter = QSharedPointer(new KoResourceServerAdapter(rServer)); m_serverAdapter->connectToResourceServer(); rServer->addObserver(this); - m_colorSetChooser = new KisColorsetChooser(this); - connect(m_colorSetChooser, SIGNAL(paletteSelected(KoColorSet*)), this, SLOT(setColorSet(KoColorSet*))); + m_paletteChooser = new KisColorsetChooser(this); + connect(m_paletteChooser, SIGNAL(paletteSelected(KoColorSet*)), this, SLOT(setColorSet(KoColorSet*))); m_wdgPaletteDock->bnColorSets->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_wdgPaletteDock->bnColorSets->setToolTip(i18n("Choose palette")); - m_wdgPaletteDock->bnColorSets->setPopupWidget(m_colorSetChooser); + m_wdgPaletteDock->bnColorSets->setPopupWidget(m_paletteChooser); connect(m_wdgPaletteDock->cmbNameList, SIGNAL(currentIndexChanged(int)), this, SLOT(setColorFromNameList(int))); KisConfig cfg; QString defaultPalette = cfg.defaultPalette(); KoColorSet* defaultColorSet = rServer->resourceByName(defaultPalette); if (defaultColorSet) { setColorSet(defaultColorSet); } } PaletteDockerDock::~PaletteDockerDock() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); if (m_currentColorSet) { KisConfig cfg; cfg.setDefaultPalette(m_currentColorSet->name()); } delete m_wdgPaletteDock->paletteView->itemDelegate(); delete m_wdgPaletteDock; } void PaletteDockerDock::setMainWindow(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); connect(m_resourceProvider, SIGNAL(sigSavingWorkspace(KisWorkspaceResource*)), SLOT(saveToWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigLoadingWorkspace(KisWorkspaceResource*)), SLOT(loadFromWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)),m_wdgPaletteDock->paletteView, SLOT(trySelectClosestColor(KoColor))); kisview->nodeManager()->disconnect(m_model); } void PaletteDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (canvas) { KisCanvas2 *cv = qobject_cast(canvas); m_model->setDisplayRenderer(cv->displayColorConverter()->displayRendererInterface()); } m_canvas = static_cast(canvas); } void PaletteDockerDock::unsetCanvas() { setEnabled(false); m_model->setDisplayRenderer(0); m_canvas = 0; } void PaletteDockerDock::unsetResourceServer() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); } void PaletteDockerDock::removingResource(KoColorSet *resource) { if (resource == m_currentColorSet) { setColorSet(0); } } void PaletteDockerDock::resourceChanged(KoColorSet *resource) { setColorSet(resource); } void PaletteDockerDock::setColorSet(KoColorSet* colorSet) { m_model->setColorSet(colorSet); m_wdgPaletteDock->paletteView->updateView(); m_wdgPaletteDock->paletteView->updateRows(); m_wdgPaletteDock->cmbNameList->clear(); if (colorSet && colorSet->nColors()>0) { for (quint32 i = 0; i< colorSet->nColors(); i++) { KoColorSetEntry entry = colorSet->getColorGlobal(i); QPixmap colorSquare = QPixmap(32, 32); if (entry.spotColor()) { QImage img = QImage(32, 32, QImage::Format_ARGB32); QPainter circlePainter; img.fill(Qt::transparent); circlePainter.begin(&img); QBrush brush = QBrush(Qt::SolidPattern); brush.setColor(entry.color().toQColor()); circlePainter.setBrush(brush); QPen pen = circlePainter.pen(); pen.setColor(Qt::transparent); pen.setWidth(0); circlePainter.setPen(pen); circlePainter.drawEllipse(0, 0, 32, 32); circlePainter.end(); colorSquare = QPixmap::fromImage(img); } else { colorSquare.fill(entry.color().toQColor()); } QString name = entry.name(); if (!entry.id().isEmpty()){ name = entry.id() + " - " + entry.name(); } m_wdgPaletteDock->cmbNameList->addSqueezedItem(QIcon(colorSquare), name); } } QCompleter *completer = new QCompleter(m_wdgPaletteDock->cmbNameList->model()); completer->setCompletionMode(QCompleter::PopupCompletion); completer->setCaseSensitivity(Qt::CaseInsensitive); completer->setFilterMode(Qt::MatchContains); m_wdgPaletteDock->cmbNameList->setCompleter(completer); if (colorSet && colorSet->removable()) { m_wdgPaletteDock->bnAdd->setEnabled(true); m_wdgPaletteDock->bnRemove->setEnabled(true); } else { m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); } m_currentColorSet = colorSet; } void PaletteDockerDock::setColorFromNameList(int index) { if (m_model && m_currentColorSet) { entrySelected(m_currentColorSet->getColorGlobal(index)); m_wdgPaletteDock->paletteView->blockSignals(true); m_wdgPaletteDock->cmbNameList->blockSignals(true); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); m_wdgPaletteDock->paletteView->selectionModel()->clearSelection(); m_wdgPaletteDock->paletteView->selectionModel()->setCurrentIndex(m_model->indexFromId(index), QItemSelectionModel::Select); m_wdgPaletteDock->paletteView->blockSignals(false); m_wdgPaletteDock->cmbNameList->blockSignals(false); } } void PaletteDockerDock::addColorForeground() { if (m_resourceProvider) { //setup dialog m_wdgPaletteDock->paletteView->addEntryWithDialog(m_resourceProvider->fgColor()); } } void PaletteDockerDock::removeColor() { QModelIndex index = m_wdgPaletteDock->paletteView->currentIndex(); if (!index.isValid()) { return; } m_wdgPaletteDock->paletteView->removeEntryWithDialog(index); } void PaletteDockerDock::entrySelected(KoColorSetEntry entry) { if (m_wdgPaletteDock->paletteView->currentIndex().isValid()) { quint32 index = m_model->idFromIndex(m_wdgPaletteDock->paletteView->currentIndex()); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); } if (m_resourceProvider) { m_resourceProvider->setFGColor(entry.color()); } if (m_currentColorSet->removable()) { m_wdgPaletteDock->bnRemove->setEnabled(true); } } void PaletteDockerDock::entrySelectedBack(KoColorSetEntry entry) { if (m_wdgPaletteDock->paletteView->currentIndex().isValid()) { quint32 index = m_model->idFromIndex(m_wdgPaletteDock->paletteView->currentIndex()); m_wdgPaletteDock->cmbNameList->setCurrentIndex(index); } if (m_resourceProvider) { m_resourceProvider->setBGColor(entry.color()); } if (m_currentColorSet->removable()) { m_wdgPaletteDock->bnRemove->setEnabled(true); } } void PaletteDockerDock::saveToWorkspace(KisWorkspaceResource* workspace) { if (m_currentColorSet) { workspace->setProperty("palette", m_currentColorSet->name()); } } void PaletteDockerDock::loadFromWorkspace(KisWorkspaceResource* workspace) { if (workspace->hasProperty("palette")) { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); KoColorSet* colorSet = rServer->resourceByName(workspace->getString("palette")); if (colorSet) { setColorSet(colorSet); } } } diff --git a/plugins/dockers/palettedocker/palettedocker_dock.h b/plugins/dockers/palettedocker/palettedocker_dock.h index 5b41e10b10..4cdc5b4198 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.h +++ b/plugins/dockers/palettedocker/palettedocker_dock.h @@ -1,86 +1,86 @@ /* * Copyright (c) 2013 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PALETTEDOCKER_DOCK_H #define PALETTEDOCKER_DOCK_H #include #include #include #include #include #include #include #include #include class KisViewManager; class KisCanvasResourceProvider; class KisWorkspaceResource; class KisColorsetChooser; class KisPaletteModel; class Ui_WdgPaletteDock; class PaletteDockerDock : public QDockWidget, public KisMainwindowObserver, public KoResourceServerObserver { Q_OBJECT public: PaletteDockerDock(); ~PaletteDockerDock() override; QString observerName() override { return "PaletteDockerDock"; } void setMainWindow(KisViewManager* kisview) override; void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; public: // KoResourceServerObserver void unsetResourceServer() override; void resourceAdded(KoColorSet *) override {} void removingResource(KoColorSet *resource) override; void resourceChanged(KoColorSet *resource) override; void syncTaggedResourceView() override {} void syncTagAddition(const QString&) override {} void syncTagRemoval(const QString&) override {} private Q_SLOTS: void addColorForeground(); void removeColor(); void entrySelected(KoColorSetEntry entry); void entrySelectedBack(KoColorSetEntry entry); void setColorSet(KoColorSet* colorSet); void setColorFromNameList(int index); void saveToWorkspace(KisWorkspaceResource* workspace); void loadFromWorkspace(KisWorkspaceResource* workspace); private: Ui_WdgPaletteDock* m_wdgPaletteDock; KisPaletteModel *m_model; QSharedPointer m_serverAdapter; KoColorSet *m_currentColorSet; - KisColorsetChooser *m_colorSetChooser; + KisColorsetChooser *m_paletteChooser; KisCanvasResourceProvider *m_resourceProvider; QPointer m_canvas; }; #endif diff --git a/plugins/paintops/particle/kis_particle_paintop_settings_widget.h b/plugins/paintops/particle/kis_particle_paintop_settings_widget.h index 3ee677c1dc..7d8a92fe8b 100644 --- a/plugins/paintops/particle/kis_particle_paintop_settings_widget.h +++ b/plugins/paintops/particle/kis_particle_paintop_settings_widget.h @@ -1,46 +1,46 @@ /* * Copyright (c) 2008 Lukas Tvrdy * * 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_PARTICLEPAINTOP_SETTINGS_WIDGET_H_ #define KIS_PARTICLEPAINTOP_SETTINGS_WIDGET_H_ #include #include "ui_wdgparticleoptions.h" -#include "widgets/kis_popup_button.h" +#include "kis_popup_button.h" class KisPaintActionTypeOption; class KisParticleOpOption; class KisParticlePaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisParticlePaintOpSettingsWidget(QWidget* parent = 0); ~KisParticlePaintOpSettingsWidget() override; KisPropertiesConfigurationSP configuration() const override; public: KisPaintActionTypeOption* m_paintActionTypeOption; KisParticleOpOption* m_particleOption; }; #endif diff --git a/plugins/python/colorspace/kritapykrita_colorspace.desktop b/plugins/python/colorspace/kritapykrita_colorspace.desktop index afa906b39f..0a86e92fc1 100644 --- a/plugins/python/colorspace/kritapykrita_colorspace.desktop +++ b/plugins/python/colorspace/kritapykrita_colorspace.desktop @@ -1,49 +1,51 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=colorspace X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Color Space Name[ar]=الفضاء اللونيّ Name[ca]=Espai de color Name[ca@valencia]=Espai de color Name[cs]=Barevný prostor Name[de]=Farbraum Name[el]=Χρωματικός χώρος Name[en_GB]=Colour Space Name[es]=Espacio de color +Name[fr]=Espace colorimétrique Name[gl]=Espazo de cores Name[is]=Litrýmd Name[it]=Spazio dei colori Name[nl]=Kleurruimte Name[pl]=Przestrzeń barw Name[pt]=Espaço de Cores Name[pt_BR]=Espaço de cores Name[sk]=Farebný priestor Name[sv]=Färgrymd Name[tr]=Renk Aralığı Name[uk]=Простір кольорів Name[x-test]=xxColor Spacexx Name[zh_CN]=色彩空间 Name[zh_TW]=色彩空間 Comment=Plugin to change color space to selected documents Comment[ar]=ملحقة لتغيير الفضاء اللونيّ في المستندات المحدّدة Comment[ca]=Un connector per canviar l'espai de color dels documents seleccionats Comment[ca@valencia]=Un connector per canviar l'espai de color dels documents seleccionats Comment[cs]=Modul pro změnu rozsahu barvy pro vybrané dokumenty Comment[el]=Πρόσθετο αλλαγής χρωματικού χώρου σε επιλεγμένα έγγραφα Comment[en_GB]=Plugin to change colour space to selected documents Comment[es]=Complemento para cambiar el espacio de color de los documentos seleccionados +Comment[fr]=Module externe pour l'espace de couleurs des documents sélectionnés Comment[gl]=Complemento para cambiar o espazo de cores dos documentos seleccionados. Comment[it]=Estensione per cambiare lo spazio dei colori ai documenti selezionati Comment[nl]=Plug-in om kleurruimte in geselecteerde documenten te wijzigen Comment[pl]=Wtyczka do zmiany przestrzeni barw wybranych dokumentów Comment[pt]='Plugin' para mudar o espaço de cores do documento seleccionado Comment[pt_BR]=Plug-in para alterar o espaço de cores em documentos selecionados Comment[sv]=Insticksprogram för att ändra färgrymd för valda dokument Comment[tr]=Seçili belgede renk aralığını değiştirmek için eklenti Comment[uk]=Додаток для зміни простору кольорів у позначених документах Comment[x-test]=xxPlugin to change color space to selected documentsxx Comment[zh_CN]=用于更改选定文档色彩空间的插件 Comment[zh_TW]=用於變更色彩空間為選定文件的外掛程式 diff --git a/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop b/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop index 1151ffa761..014b47501b 100644 --- a/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop +++ b/plugins/python/comics_project_management_tools/kritapykrita_comics_project_management_tools.desktop @@ -1,46 +1,47 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=comics_project_management_tools X-Krita-Manual=README.html X-Python-2-Compatible=false Name=Comics Project Management Tools Name[ar]=أدوات إدارة المشاريع الهزليّة Name[ca]=Eines per a la gestió dels projectes de còmics Name[ca@valencia]=Eines per a la gestió dels projectes de còmics Name[cs]=Nástroje pro správu projektů komixů Name[el]=Εργαλεία διαχείρισης έργων ιστοριών σε εικόνες Name[en_GB]=Comics Project Management Tools Name[es]=Herramientas de gestión de proyectos de cómics +Name[fr]=Outils de gestion d'un projet de bande dessinée Name[gl]=Ferramentas de xestión de proxectos de cómics Name[is]=Verkefnisstjórn teiknimyndasögu Name[it]=Strumenti per la gestione dei progetti di fumetti Name[nl]=Hulpmiddelen voor projectbeheer van strips Name[pl]=Narzędzia do zarządzania projektami komiksów Name[pt]=Ferramentas de Gestão de Projectos de Banda Desenhada Name[sv]=Projekthanteringsverktyg för tecknade serier Name[tr]=Çizgi Roman Projesi Yönetimi Araçları Name[uk]=Інструменти для керування проектами коміксів Name[x-test]=xxComics Project Management Toolsxx Name[zh_CN]=漫画项目管理工具 Name[zh_TW]=漫畫專案管理工具 Comment=Tools for managing comics. Comment[ar]=أدوات لإدارة الهزليّات. Comment[ca]=Eines per a gestionar els còmics. Comment[ca@valencia]=Eines per a gestionar els còmics. Comment[cs]=Nástroje pro správu komixů. Comment[el]=Εργαλεία για τη διαχείριση ιστοριών σε εικόνες. Comment[en_GB]=Tools for managing comics. Comment[es]=Herramientas para gestionar cómics. Comment[gl]=Ferramentas para xestionar cómics. Comment[is]=Verkfæri til að stýra gerð teiknimyndasögu. Comment[it]=Strumenti per la gestione dei fumetti. Comment[nl]=Hulpmiddelen voor beheer van strips. Comment[pl]=Narzędzie do zarządzania komiksami. Comment[pt]=Ferramentas para gerir bandas desenhadas. Comment[sv]=Verktyg för att hantera tecknade serier. Comment[tr]=Çizgi romanları yönetmek için araçlar. Comment[uk]=Інструменти для керування коміксами Comment[x-test]=xxTools for managing comics.xx Comment[zh_CN]=用于管理漫画的工具。 Comment[zh_TW]=管理漫畫的工具。 diff --git a/plugins/python/documenttools/kritapykrita_documenttools.desktop b/plugins/python/documenttools/kritapykrita_documenttools.desktop index 59007cae7c..43e86adc6a 100644 --- a/plugins/python/documenttools/kritapykrita_documenttools.desktop +++ b/plugins/python/documenttools/kritapykrita_documenttools.desktop @@ -1,46 +1,48 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=documenttools X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Document Tools Name[ar]=أدوات المستندات Name[ca]=Eines de document Name[ca@valencia]=Eines de document Name[cs]=Dokumentové nástroje Name[el]=Εργαλεία για έγγραφα Name[en_GB]=Document Tools Name[es]=Herramientas de documentos +Name[fr]=Outil Document Name[gl]=Ferramentas de documentos Name[it]=Strumenti per i documenti Name[nl]=Documenthulpmiddelen Name[pl]=Narzędzia dokumentu Name[pt]=Ferramentas de Documentos Name[pt_BR]=Ferramentas de documento Name[sv]=Dokumentverktyg Name[tr]=Belge Araçları Name[uk]=Засоби документа Name[x-test]=xxDocument Toolsxx Name[zh_CN]=文档工具 Name[zh_TW]=文件工具 Comment=Plugin to manipulate properties of selected documents Comment[ar]=ملحقة لتعديل خصائص المستندات المحدّدة Comment[ca]=Un connector per manipular propietats dels documents seleccionats Comment[ca@valencia]=Un connector per manipular propietats dels documents seleccionats Comment[cs]=Modul pro správu vlastností vybraných dokumentů Comment[el]=Πρόσθετο χειρισμού ιδιοτήτων σε επιλεγμένα έγγραφα Comment[en_GB]=Plugin to manipulate properties of selected documents Comment[es]=Complemento para manipular las propiedades de los documentos seleccionados +Comment[fr]=Module externe de gestion des propriétés des documents sélectionnés Comment[gl]=Complemento para manipular as propiedades dos documentos seleccionados. Comment[it]=Estensione per manipolare le proprietà dei documenti selezionati Comment[nl]=Plug-in om eigenschappen van geselecteerde documenten te manipuleren Comment[pl]=Wtyczka do zmiany właściwości wybranych dokumentów Comment[pt]='Plugin' para manipular as propriedades dos documentos seleccionados Comment[pt_BR]=Plug-in para manipular as propriedades de documentos selecionados Comment[sv]=Insticksprogram för att ändra egenskaper för valda dokument Comment[tr]=Seçili belgelerin özelliklerini değiştirmek için eklenti Comment[uk]=Додаток для керування властивостями позначених документів Comment[x-test]=xxPlugin to manipulate properties of selected documentsxx Comment[zh_CN]=用于编辑选定文档属性的插件 Comment[zh_TW]=用於修改所選文件屬性的外掛程式 diff --git a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop index 2587174e00..d1e42f28bf 100644 --- a/plugins/python/exportlayers/kritapykrita_exportlayers.desktop +++ b/plugins/python/exportlayers/kritapykrita_exportlayers.desktop @@ -1,48 +1,50 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=exportlayers X-Krita-Manual=Manual.html X-Python-2-Compatible=true Name=Export Layers Name[ar]=تصدير الطّبقات Name[ca]=Exportació de capes Name[ca@valencia]=Exportació de capes Name[cs]=Exportovat vrstvy Name[de]=Ebenen exportieren Name[el]=Εξαγωγή επιπέδων Name[en_GB]=Export Layers Name[es]=Exportar capas +Name[fr]=Exporter des calques Name[gl]=Exportar as capas Name[is]=Flytja út lög Name[it]=Esporta livelli Name[nl]=Lagen exporteren Name[pl]=Eksportuj warstwy Name[pt]=Exportar as Camadas Name[pt_BR]=Exportar camadas Name[sv]=Exportera lager Name[tr]=Katmanları Dışa Aktar Name[uk]=Експортувати шари Name[x-test]=xxExport Layersxx Name[zh_CN]=导出图层 Name[zh_TW]=匯出圖層 Comment=Plugin to export layers from a document Comment[ar]=ملحقة لتصدير الطّبقات من مستند Comment[ca]=Un connector per exportar capes d'un document Comment[ca@valencia]=Un connector per exportar capes d'un document Comment[cs]=Modul pro export vrstev z dokumentu Comment[el]=Πρόσθετο εξαγωγής επιπέδων από έγγραφο Comment[en_GB]=Plugin to export layers from a document Comment[es]=Complemento para exportar las capas de un documento +Comment[fr]=Module externe d'export de calques d'un document Comment[gl]=Complemento para exportar as capas dun documento. Comment[it]=Estensione per esportare i livelli da un documento Comment[nl]=Plug-in om lagen uit een document te exporteren Comment[pl]=Wtyczka do eksportowania warstw z dokumentu Comment[pt]='Plugin' para exportar as camadas de um documento Comment[pt_BR]=Plug-in para exportar as camadas de um documento Comment[sv]=Insticksprogram för att exportera lager från ett dokument Comment[tr]=Belgenin katmanlarını dışa aktarmak için eklenti Comment[uk]=Додаток для експортування шарів з документа Comment[x-test]=xxPlugin to export layers from a documentxx Comment[zh_CN]=用于从文档导出图层的插件 Comment[zh_TW]=用於從文件匯出圖層的外掛程式 diff --git a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop index ead386c720..43fadad7f9 100644 --- a/plugins/python/filtermanager/kritapykrita_filtermanager.desktop +++ b/plugins/python/filtermanager/kritapykrita_filtermanager.desktop @@ -1,48 +1,50 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=filtermanager X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Filter Manager Name[ar]=مدير المرشّحات Name[ca]=Gestor de filtres Name[ca@valencia]=Gestor de filtres Name[cs]=Správce filtrů Name[de]=Filterverwaltung Name[el]=Διαχειριστής φίλτρων Name[en_GB]=Filter Manager Name[es]=Gestor de filtros +Name[fr]=Gestionnaire de fichier Name[gl]=Xestor de filtros Name[it]=Gestore dei filtri Name[nl]=Beheerder van filters Name[pl]=Zarządzanie filtrami Name[pt]=Gestor de Filtros Name[pt_BR]=Gerenciador de filtros Name[sv]=Filterhantering Name[tr]=Süzgeç Yöneticisi Name[uk]=Керування фільтрами Name[x-test]=xxFilter Managerxx Name[zh_CN]=滤镜管理器 Name[zh_TW]=濾鏡管理器 Comment=Plugin to filters management Comment[ar]=ملحقة إدارة المرشّحات Comment[ca]=Un connector per gestionar filtres Comment[ca@valencia]=Un connector per gestionar filtres Comment[cs]=Modul pro správu filtrů Comment[de]=Modul zum Verwalten von Filtern Comment[el]=Πρόσθετο για τη διαχείριση φίλτρων Comment[en_GB]=Plugin to filters management Comment[es]=Complemento para la gestión de filtros +Comment[fr]=Module externe de gestion des filtres Comment[gl]=Complemento para a xestión de filtros. Comment[it]=Estensione per la gestione dei filtri Comment[nl]=Plug-in voor beheer van filters Comment[pl]=Wtyczka do zarządzania filtrami Comment[pt]='Plugin' para a gestão de filtros Comment[pt_BR]=Plug-in para gerenciamento de filtros Comment[sv]=Insticksprogram för filterhantering Comment[tr]=Süzgeç yönetimi için eklenti Comment[uk]=Додаток для керування фільтрами Comment[x-test]=xxPlugin to filters managementxx Comment[zh_CN]=滤镜管理插件 Comment[zh_TW]=用於濾鏡管理的外掛程式 diff --git a/plugins/python/highpass/kritapykrita_highpass.desktop b/plugins/python/highpass/kritapykrita_highpass.desktop index 5aadd0f5d3..4f5548a3f6 100644 --- a/plugins/python/highpass/kritapykrita_highpass.desktop +++ b/plugins/python/highpass/kritapykrita_highpass.desktop @@ -1,45 +1,46 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=highpass X-Python-2-Compatible=false Name=Highpass Filter Name[ca]=Filtre passaalt Name[ca@valencia]=Filtre passaalt Name[cs]=Filtr s horní propustí Name[de]=Hochpassfilter Name[el]=Υψιπερατό φίλτρο Name[en_GB]=Highpass Filter Name[es]=Filtro paso alto +Name[fr]=Filtre passe-haut Name[gl]=Filtro de paso alto Name[it]=Filtro di accentuazione passaggio Name[nl]=Hoogdoorlaatfilter Name[pl]=Filtr górnoprzepustowy Name[pt]=Filtro Passa-Alto Name[pt_BR]=Filtro passa alta Name[sv]=Högpassfilter Name[tr]=Yüksek Geçirgen Süzgeç Name[uk]=Високочастотний фільтр Name[x-test]=xxHighpass Filterxx Name[zh_CN]=高通滤镜 Name[zh_TW]=高通濾鏡 Comment=Highpass Filter, based on http://registry.gimp.org/node/7385 Comment[ca]=Filtre passaalt, basat en el http://registry.gimp.org/node/7385 Comment[ca@valencia]=Filtre passaalt, basat en el http://registry.gimp.org/node/7385 Comment[cs]=Filtr s horní propustí založený na http://registry.gimp.org/node/7385 Comment[de]=Hochpassfilter, Grundlage ist http://registry.gimp.org/node/7385 Comment[el]=Υψιπερατό φίλτρο, με βάση το http://registry.gimp.org/node/7385 Comment[en_GB]=Highpass Filter, based on http://registry.gimp.org/node/7385 Comment[es]=Filtro paso alto, basado en http://registry.gimp.org/node/7385 Comment[gl]=Filtro de paso alto, baseado en http://registry.gimp.org/node/7385. Comment[it]=Filtro di accentuazione passaggio, basato su http://registry.gimp.org/node/7385 Comment[nl]=Hoogdoorlaatfilter, gebaseerd op http://registry.gimp.org/node/7385 Comment[pl]=Filtr górnoprzepustowy, oparty na http://registry.gimp.org/node/7385 Comment[pt]=Filtro passa-alto, baseado em http://registry.gimp.org/node/7385 Comment[pt_BR]=Filtro passa alta, baseado em http://registry.gimp.org/node/7385 Comment[sv]=Högpassfilter, baserat på http://registry.gimp.org/node/7385 Comment[tr]=http://registry.gimp.org/node/7385 tabanlı Yüksek Geçirgen Süzgeç Comment[uk]=Високочастотний фільтр, засновано на on http://registry.gimp.org/node/7385 Comment[x-test]=xxHighpass Filter, based on http://registry.gimp.org/node/7385xx Comment[zh_CN]=高通滤镜,基于 http://registry.gimp.org/node/7385 Comment[zh_TW]=高通濾鏡,基於 http://registry.gimp.org/node/7385 diff --git a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop index 2b2f195e63..ab65097474 100644 --- a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop +++ b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop @@ -1,42 +1,43 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=lastdocumentsdocker X-Python-2-Compatible=false X-Krita-Manual=Manual.html Name=Last Documents Docker Name[ar]=رصيف بآخر المستندات Name[ca]=Acoblador dels darrers documents Name[ca@valencia]=Acoblador dels darrers documents Name[el]=Προσάρτηση τελευταίων εγγράφοων Name[en_GB]=Last Documents Docker Name[es]=Panel de últimos documentos +Name[fr]=Récemment ouverts Name[gl]=Doca dos últimos documentos Name[it]=Area di aggancio Ultimi documenti -Name[nl]=Vastzetter van laatste documenten +Name[nl]=Laatste documenten verankering Name[pl]=Dok ostatnich dokumentów Name[pt]=Área dos Últimos Documentos Name[sv]=Dockningsfönster för senaste dokument Name[tr]=Son Belgeler Doku Name[uk]=Бічна панель останніх документів Name[x-test]=xxLast Documents Dockerxx Name[zh_CN]=最近文档工具面板 Name[zh_TW]=「最後文件」面板 Comment=A Python-based docker for show thumbnails to last ten documents Comment[ar]=رصيف بِ‍«پيثون» لعرض مصغّرات آخر ١٠ مستندات مفتوحة Comment[ca]=Un acoblador basant en el Python per mostrar miniatures dels darrers deu documents Comment[ca@valencia]=Un acoblador basant en el Python per mostrar miniatures dels darrers deu documents Comment[el]=Ένα εργαλείο προσάρτησης σε Python για την εμφάνιση επισκοπήσεων των δέκα τελευταίων εγγράφων Comment[en_GB]=A Python-based docker for show thumbnails to last ten documents Comment[es]=Un panel basado en Python para mostrar miniaturas de los últimos diez documentos Comment[gl]=Unha doca baseada en Python para mostrar as miniaturas dos últimos dez documentos. Comment[it]=Un'area di aggancio basata su Python per mostrare miniature degli ultimi dieci documenti. Comment[nl]=Een op Python gebaseerde vastzetter om miniaturen te tonen naar de laatste tien documenten. Comment[pl]=Dok oparty na pythonie do wyświetlania miniatur ostatnich dziesięciu dokumentów Comment[pt]=Uma área acoplável, feita em Python, para mostrar as miniaturas dos últimos dez documentos Comment[sv]=Ett Python-baserat dockningsfönster för att visa miniatyrbilder för de tio senaste dokumenten Comment[tr]=Son on belgenin küçük resmini göstermek için Python-tabanlı bir dok Comment[uk]=Бічна панель на основі Python для показу мініатюр останніх десяти документів Comment[x-test]=xxA Python-based docker for show thumbnails to last ten documentsxx Comment[zh_CN]=基于 Python 的工具面板,显示最近十个文档的缩略图 Comment[zh_TW]=基於 Python 的面板,用於顯示最後 10 個文件縮圖 diff --git a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop index 227913909d..5dc417ce4f 100644 --- a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop +++ b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop @@ -1,45 +1,46 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=palette_docker X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Palette docker Name[ar]=رصيف اللوحات Name[ca]=Acoblador de paletes Name[ca@valencia]=Acoblador de paletes Name[cs]=Dok palet Name[de]=Paletten-Docker Name[el]=Προσάρτηση παλέτας Name[en_GB]=Palette docker Name[es]=Panel de paleta +Name[fr]=Panneau de palette Name[gl]=Doca de paleta Name[is]=Tengikví fyrir litaspjald Name[it]=Area di aggancio della tavolozza Name[nl]=Vastzetter van palet Name[pl]=Dok palety Name[pt]=Área acoplável da paleta Name[sv]=Dockningsfönster för palett Name[tr]=Palet doku Name[uk]=Панель палітри Name[x-test]=xxPalette dockerxx Name[zh_CN]=调色板工具面板 Name[zh_TW]=「調色盤」面板 Comment=A Python-based docker to edit color palettes. Comment[ar]=رصيف بِ‍«پيثون» لتحرير لوحات الألوان. Comment[ca]=Un acoblador basant en el Python per editar paletes de colors. Comment[ca@valencia]=Un acoblador basant en el Python per editar paletes de colors. Comment[el]=Ένα εργαλείο προσάρτησης σε Python για την επεξεργασία παλετών χρώματος. Comment[en_GB]=A Python-based docker to edit colour palettes. Comment[es]=Un panel basado en Python para editar paletas de colores. Comment[gl]=Unha doca baseada en Python para editar paletas de cores. Comment[it]=Un'area di aggancio per modificare le tavolozze di colori basata su Python. Comment[nl]=Een op Python gebaseerde vastzetter om kleurpaletten te bewerken. Comment[pl]=Dok oparty na pythonie do edytowania palet barw. Comment[pt]=Uma área acoplável, feita em Python, para editar paletas de cores. Comment[sv]=Ett Python-baserat dockningsfönster för att redigera färgpaletter. Comment[tr]=Renk paletlerini düzenlemek için Python-tabanlı bir dok. Comment[uk]=Бічна панель для редагування палітр кольорів на основі Python. Comment[x-test]=xxA Python-based docker to edit color palettes.xx Comment[zh_CN]=基于 Python 的调色板编辑器工具面板 Comment[zh_TW]=基於 Python 的面板,用於編輯調色盤。 diff --git a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop index e2e5102e39..55818d79b0 100644 --- a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop +++ b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop @@ -1,43 +1,44 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=quick_settings_docker X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Quick Settings Docker Name[ar]=رصيف بإعدادات سريعة Name[ca]=Acoblador d'arranjament ràpid Name[ca@valencia]=Acoblador d'arranjament ràpid Name[cs]=Dok pro rychlé nastavení Name[el]=Προσάρτηση γρήγορων ρυθμίσεων Name[en_GB]=Quick Settings Docker Name[es]=Panel de ajustes rápidos +Name[fr]=Réglages rapides Name[gl]=Doca de configuración rápida Name[it]=Area di aggancio delle impostazioni rapide -Name[nl]=Docker voor snelle instellingen +Name[nl]=Verankering voor snelle instellingen Name[pl]=Dok szybkich ustawień Name[pt]=Área de Configuração Rápida Name[sv]=Dockningspanel med snabbinställningar Name[tr]=Hızlı Ayarlar Doku Name[uk]=Панель швидких параметрів Name[x-test]=xxQuick Settings Dockerxx Name[zh_CN]=快速设置工具面板 Name[zh_TW]=「快速設定」面板 Comment=A Python-based docker for quickly changing brush size and opacity. Comment[ar]=رصيف بِ‍«پيثون» لتغيير حجم الفرشاة وشفافيّتها بسرعة. Comment[ca]=Un acoblador basant en el Python per canviar ràpidament la mida del pinzell i l'opacitat. Comment[ca@valencia]=Un acoblador basant en el Python per canviar ràpidament la mida del pinzell i l'opacitat. Comment[el]=Ένα εργαλείο προσάρτησης σε Python για γρήγορη αλλαγή του μεγέθους και της αδιαφάνειας του πινέλου. Comment[en_GB]=A Python-based docker for quickly changing brush size and opacity. Comment[es]=Un panel basado en Python para cambiar rápidamente el tamaño y la opacidad del pincel. Comment[gl]=Unha doca baseada en Python para cambiar rapidamente a opacidade e o tamaño dos pinceis. Comment[it]=Un'area di aggancio basata su Python per cambiare rapidamente la dimensione del pennello e l'opacità. Comment[nl]=Een op Python gebaseerde docker voor snel wijzigen van penseelgrootte en dekking. Comment[pl]=Dok oparty na pythonie do szybkiej zmiany rozmiaru i nieprzezroczystości pędzla. Comment[pt]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel. Comment[sv]=En Python-baserad dockningspanel för att snabbt ändra penselstorlek och ogenomskinlighet. Comment[tr]=Fırça boyutunu ve matlığını hızlıca değiştirmek için Python-tabanlı bir dok. Comment[uk]=Панель на основі мови програмування Python для швидкої зміни розміру та непрозорості пензля. Comment[x-test]=xxA Python-based docker for quickly changing brush size and opacity.xx Comment[zh_CN]=基于 Python 的用于快速更改笔刷尺寸和透明度的工具面板。 Comment[zh_TW]=基於 Python 的面板,用於快速變更筆刷尺寸和不透明度。 diff --git a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop index 7d86748428..4d7654b5c4 100644 --- a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop +++ b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop @@ -1,42 +1,43 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=scriptdocker X-Python-2-Compatible=false Name=Script Docker Name[ar]=رصيف سكربتات Name[ca]=Acoblador de scripts Name[ca@valencia]=Acoblador de scripts Name[cs]=Dok skriptu Name[el]=Προσάρτηση σεναρίων Name[en_GB]=Script Docker Name[es]=Panel de guiones +Name[fr]=Panneau de script Name[gl]=Doca de scripts Name[it]=Area di aggancio degli script -Name[nl]=Vastzetten van scripts +Name[nl]=Verankering van scripts Name[pl]=Dok skryptów Name[pt]=Área de Programas Name[sv]=Dockningsfönster för skript Name[tr]=Betik Doku Name[uk]=Бічна панель скриптів Name[x-test]=xxScript Dockerxx Name[zh_CN]=脚本工具面板 Name[zh_TW]=「腳本」面板 Comment=A Python-based docker for create actions and point to Python scripts Comment[ar]=رصيف بِ‍«پيثون» لإنشاء الإجراءات والإشارة إلى سكربتات «پيثون» Comment[ca]=Un acoblador basant en el Python per crear accions i apuntar a scripts del Python Comment[ca@valencia]=Un acoblador basant en el Python per crear accions i apuntar a scripts del Python Comment[el]=Ένα εργαλείο προσάρτησης σε Python για τη δημιουργία ενεργειών και τη δεικτοδότηση σεναρίων σε Python Comment[en_GB]=A Python-based docker for create actions and point to Python scripts Comment[es]=Un panel basado en Python para crear y apuntar a guiones de Python Comment[gl]=Unha doca escrita en Python para crear accións e apuntar a scripts escritos en Python. Comment[it]=Un'area di aggancio basata su Python per creare azioni e scegliere script Python Comment[nl]=Een op Python gebaseerde vastzetter voor aanmaakacties en wijzen naar Python-scripts Comment[pl]=Dok oparty na pythonie do tworzenia działań i punktów dla skryptów pythona Comment[pt]=Uma área acoplável, feita em Python, para criar acções e apontar para programas em Python Comment[sv]=Ett Python-baserat dockningsfönster för att skapa åtgärder och peka ut Python-skript Comment[tr]=Eylemler oluşturmak ve Python betiklerine yönlendirmek için Python-tabanlı bir dok Comment[uk]=Бічна панель для створення дій і керування скриптами на основі Python. Comment[x-test]=xxA Python-based docker for create actions and point to Python scriptsxx Comment[zh_CN]=基于 Python 的用于创建动作并指向 Python 脚本的工具面板 Comment[zh_TW]=基於 Python 的面板,用於建立動作並指向 Python 腳本 diff --git a/plugins/python/scripter/kritapykrita_scripter.desktop b/plugins/python/scripter/kritapykrita_scripter.desktop index 4ace62d5fd..dec85cc9cc 100644 --- a/plugins/python/scripter/kritapykrita_scripter.desktop +++ b/plugins/python/scripter/kritapykrita_scripter.desktop @@ -1,41 +1,42 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=scripter X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Scripter Name[ca]=Scripter Name[ca@valencia]=Scripter Name[de]=Scripter Name[el]=Σενάρια Name[en_GB]=Scripter Name[es]=Guionador +Name[fr]=Scripter Name[gl]=Executor de scripts Name[it]=Scripter -Name[nl]=Scriptschrijver +Name[nl]=Scriptmaker Name[pl]=Skrypter Name[pt]=Programador Name[sv]=Skriptgenerator Name[tr]=Betik yazarı Name[uk]=Скриптер Name[x-test]=xxScripterxx Name[zh_CN]=脚本编写器 Name[zh_TW]=腳本編寫者 Comment=Plugin to execute ad-hoc Python code Comment[ca]=Connector per executar codi Python ad hoc Comment[ca@valencia]=Connector per executar codi Python ad hoc Comment[el]=Πρόσθετο για την εκτέλεση συγκεκριμένου κώδικα Python Comment[en_GB]=Plugin to execute ad-hoc Python code Comment[es]=Complemento para ejecutar código Python a medida Comment[gl]=Complemento para executar código de Python escrito no momento. Comment[it]=Estensione per eseguire ad-hoc codice Python Comment[nl]=Plug-in om ad-hoc Python code uit te voeren Comment[pl]=Wtyczka do wykonywania kodu Pythona ad-hoc Comment[pt]='Plugin' para executar código em Python arbitrário Comment[sv]=Insticksprogram för att köra godtycklig Python-kod Comment[tr]=Geçici Python kodu çalıştırmak için eklenti Comment[uk]=Додаток для виконання апріорного коду Python Comment[x-test]=xxPlugin to execute ad-hoc Python codexx Comment[zh_CN]=执行现场编写的 Python 代码的插件 Comment[zh_TW]=外掛程式,用於執行特定 Python 程式碼 diff --git a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop index b19c9a320d..00fcbba00e 100644 --- a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop +++ b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop @@ -1,42 +1,43 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=selectionsbagdocker X-Python-2-Compatible=false Name=Selections Bag Docker Name[ar]=رصيف سلّة التّحديدات Name[ca]=Acoblador de bossa de seleccions Name[ca@valencia]=Acoblador de bossa de seleccions Name[el]=Προσάρτηση σάκου επιλογών Name[en_GB]=Selections Bag Docker Name[es]=Panel de selecciones +Name[fr]=Outils de sélection Name[gl]=Doca de bolsa das seleccións Name[it]=Area di raccolta selezioni Name[nl]=Docker van zak met selecties Name[pl]=Dok worka zaznaczeń Name[pt]=Área de Selecções Name[sv]=Dockningspanel med markeringspåse Name[tr]=Seçim Çantası Doku Name[uk]=Бічна панель позначеного Name[x-test]=xxSelections Bag Dockerxx Name[zh_CN]=选区列表工具面板 Name[zh_TW]=「選取範圍收藏」面板 Comment=A docker that allow to store a list of selections Comment[ar]=رصيف يتيح تخزين قائمة تحديدات Comment[ca]=Un acoblador que permet emmagatzemar una llista de seleccions Comment[ca@valencia]=Un acoblador que permet emmagatzemar una llista de seleccions Comment[cs]=Dok umožňující uložit seznam výběrů Comment[el]=Ένα εργαλείο προσάρτησης που επιτρέπει την αποθήκευση μιας λίστας επιλογών Comment[en_GB]=A docker that allow to store a list of selections Comment[es]=Un panel que permite guardar una lista de selecciones Comment[gl]=Unha doca que permite almacenar unha lista de seleccións. Comment[it]=Un'area di aggancio che consente di memorizzare un elenco di selezioni Comment[nl]=Een docker die een lijst met selecties kan opslaan Comment[pl]=Dok, który umożliwia przechowywanie listy zaznaczeń Comment[pt]=Uma área acoplável que permite guardar uma lista de selecções Comment[sv]=En dockningspanel som gör det möjligt att lagra en lista över markeringar Comment[tr]=Seçimlerin bir listesini saklamayı sağlayan bir dok Comment[uk]=Бічна панель, на якій можна зберігати список позначеного Comment[x-test]=xxA docker that allow to store a list of selectionsxx Comment[zh_CN]=用于保存一系列选区的工具面板 Comment[zh_TW]=允許儲存選取範圍列表的面板 diff --git a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop index 827b65acf6..57d113a250 100644 --- a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop +++ b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop @@ -1,43 +1,44 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=tenbrushes X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Ten Brushes Name[ar]=عشرُ فُرش Name[ca]=Deu pinzells Name[ca@valencia]=Deu pinzells Name[cs]=Deset štětců Name[el]=Δέκα πινέλα Name[en_GB]=Ten Brushes Name[es]=Diez pinceles +Name[fr]=Raccourcis des préréglages de brosses Name[gl]=Dez pinceis Name[is]=Tíu penslar Name[it]=Dieci pennelli Name[nl]=Tien penselen Name[pl]=Dziesięć pędzli Name[pt]=Dez Pincéis Name[sv]=Tio penslar Name[tr]=On Fırça Name[uk]=Десять пензлів Name[x-test]=xxTen Brushesxx Name[zh_CN]=十大笔刷 Name[zh_TW]=10 個筆刷 Comment=Assign a preset to ctrl-1 to ctrl-0 Comment[ca]=Assigna una predefinició des de Ctrl-1 a Ctrl-0 Comment[ca@valencia]=Assigna una predefinició des de Ctrl-1 a Ctrl-0 Comment[el]=Αντιστοίχιση προκαθορισμένου από ctrl-1 στο ctrl-0 Comment[en_GB]=Assign a preset to ctrl-1 to ctrl-0 Comment[es]=Asignar una preselección a Ctrl-1 hasta Ctrl-0 Comment[gl]=Asigne unha predefinición do Ctrl+1 ao Ctrl+0. Comment[it]=Assegna una preimpostazione per ctrl-1 a ctrl-0 Comment[nl]=Een voorinstelling toekennen aan Ctrl-1 tot Ctrl-0 Comment[pl]=Przypisz nastawę do ctrl-1 lub ctrl-0 Comment[pt]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0 Comment[sv]=Tilldela en förinställning för Ctrl+1 till Ctrl+0 Comment[tr]= ctrl-1 ve ctrl-0 için ayar atama Comment[uk]=Прив’язування наборів налаштувань до скорочень від ctrl-1 до ctrl-0 Comment[x-test]=xxAssign a preset to ctrl-1 to ctrl-0xx Comment[zh_CN]=将预设分配给 Ctrl+1 到 Ctrl+0 快捷键 Comment[zh_TW]=將預設指定給 ctrl-1 至 ctrl-0 diff --git a/plugins/python/tenbrushes/tenbrushes.py b/plugins/python/tenbrushes/tenbrushes.py index d640a998f6..d84c9b58e5 100644 --- a/plugins/python/tenbrushes/tenbrushes.py +++ b/plugins/python/tenbrushes/tenbrushes.py @@ -1,75 +1,83 @@ ''' This script is licensed CC 0 1.0, so that you can learn from it. ------ CC 0 1.0 --------------- The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. https://creativecommons.org/publicdomain/zero/1.0/legalcode ''' import krita from . import uitenbrushes class TenBrushesExtension(krita.Extension): def __init__(self, parent): super(TenBrushesExtension, self).__init__(parent) self.actions = [] self.buttons = [] self.selectedPresets = [] + # Indicates whether we want to activate the previous-selected brush + # on the second press of the shortcut + self.activatePrev = True self.oldPreset = None def setup(self): self.readSettings() def createActions(self, window): action = window.createAction("ten_brushes", i18n("Ten Brushes")) action.setToolTip(i18n("Assign ten brush presets to ten shortcuts.")) action.triggered.connect(self.initialize) self.loadActions(window) def initialize(self): self.uitenbrushes = uitenbrushes.UITenBrushes() self.uitenbrushes.initialize(self) def readSettings(self): self.selectedPresets = Application.readSetting("", "tenbrushes", "").split(',') + setting = Application.readSetting("", "tenbrushesActivatePrev2ndPress", "True") + # we should not get anything other than 'True' and 'False' + self.activatePrev = setting == 'True' def writeSettings(self): presets = [] for index, button in enumerate(self.buttons): self.actions[index].preset = button.preset presets.append(button.preset) Application.writeSetting("", "tenbrushes", ','.join(map(str, presets))) + Application.writeSetting("", "tenbrushesActivatePrev2ndPress", + str(self.activatePrev)) def loadActions(self, window): allPresets = Application.resources("preset") for index, item in enumerate(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']): action = window.createAction("activate_preset_" + item, str(i18n("Activate Brush Preset {num}")).format(num=item), "") action.triggered.connect(self.activatePreset) if index < len(self.selectedPresets) and self.selectedPresets[index] in allPresets: action.preset = self.selectedPresets[index] else: action.preset = None self.actions.append(action) def activatePreset(self): allPresets = Application.resources("preset") if Application.activeWindow() and len(Application.activeWindow().views()) > 0 and self.sender().preset in allPresets: currentPreset = Application.activeWindow().views()[0].currentBrushPreset() - if self.sender().preset == currentPreset.name(): + if self.activatePrev and self.sender().preset == currentPreset.name(): Application.activeWindow().views()[0].activateResource(self.oldPreset) else: self.oldPreset = Application.activeWindow().views()[0].currentBrushPreset() Application.activeWindow().views()[0].activateResource(allPresets[self.sender().preset]) Scripter.addExtension(TenBrushesExtension(Application)) diff --git a/plugins/python/tenbrushes/uitenbrushes.py b/plugins/python/tenbrushes/uitenbrushes.py index fbbe040d40..768f801139 100644 --- a/plugins/python/tenbrushes/uitenbrushes.py +++ b/plugins/python/tenbrushes/uitenbrushes.py @@ -1,75 +1,84 @@ ''' This script is licensed CC 0 1.0, so that you can learn from it. ------ CC 0 1.0 --------------- The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. https://creativecommons.org/publicdomain/zero/1.0/legalcode ''' from PyQt5.QtCore import Qt, QSize from PyQt5.QtGui import QPixmap, QIcon -from PyQt5.QtWidgets import (QDialogButtonBox, QLabel, QVBoxLayout, QHBoxLayout) +from PyQt5.QtWidgets import (QDialogButtonBox, QLabel, QVBoxLayout, QHBoxLayout, QCheckBox) from . import tenbrushesdialog, dropbutton import krita class UITenBrushes(object): def __init__(self): self.kritaInstance = krita.Krita.instance() self.mainDialog = tenbrushesdialog.TenBrushesDialog(self, self.kritaInstance.activeWindow().qwindow()) self.buttonBox = QDialogButtonBox(self.mainDialog) self.vbox = QVBoxLayout(self.mainDialog) self.hbox = QHBoxLayout(self.mainDialog) + self.checkBox = QCheckBox(i18n("&Activate previous brush when pressing the shortcut for the second time"), self.mainDialog) self.buttonBox.accepted.connect(self.mainDialog.accept) self.buttonBox.rejected.connect(self.mainDialog.reject) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.presetChooser = krita.PresetChooser(self.mainDialog) def initialize(self, tenbrushes): self.tenbrushes = tenbrushes self.loadButtons() self.vbox.addLayout(self.hbox) self.vbox.addWidget(QLabel(i18n("Select the brush preset, then click on the button you want to use to select the preset"))) self.vbox.addWidget(self.presetChooser) + + self.checkBox.setChecked(self.tenbrushes.activatePrev) + self.checkBox.toggled.connect(self.setActivatePrev) + self.vbox.addWidget(self.checkBox) + self.vbox.addWidget(self.buttonBox) self.mainDialog.show() self.mainDialog.activateWindow() self.mainDialog.exec_() + def setActivatePrev(self, checked): + self.tenbrushes.activatePrev = checked + def loadButtons(self): self.tenbrushes.buttons = [] allPresets = Application.resources("preset") for index, item in enumerate(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']): buttonLayout = QVBoxLayout() button = dropbutton.DropButton(self.mainDialog) button.setObjectName(item) button.clicked.connect(button.selectPreset) button.presetChooser = self.presetChooser if self.tenbrushes.actions[index] and self.tenbrushes.actions[index].preset and self.tenbrushes.actions[index].preset in allPresets: p = allPresets[self.tenbrushes.actions[index].preset] button.preset = p.name() button.setIcon(QIcon(QPixmap.fromImage(p.image()))) buttonLayout.addWidget(button) label = QLabel(self.tenbrushes.actions[index].shortcut().toString()) label.setAlignment(Qt.AlignHCenter) buttonLayout.addWidget(label) self.hbox.addLayout(buttonLayout) self.tenbrushes.buttons.append(button) diff --git a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop index 25cdadfd6e..328b36cd47 100644 --- a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop +++ b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop @@ -1,39 +1,40 @@ [Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=tenscripts X-Python-2-Compatible=true X-Krita-Manual=Manual.html Name=Ten Scripts Name[ar]=عشرُ سكربتات Name[ca]=Deu scripts Name[ca@valencia]=Deu scripts Name[en_GB]=Ten Scripts Name[es]=Diez guiones +Name[fr]=Raccourcis des scripts Name[gl]=Dez scripts Name[is]=Tíu skriftur Name[it]=Dieci script Name[nl]=Tien scripts Name[pl]=Skrypty Ten Name[pt]=Dez Programas Name[sv]=Tio skript Name[uk]=Десять скриптів Name[x-test]=xxTen Scriptsxx Name[zh_CN]=十大脚本 Name[zh_TW]=10 個腳本 Comment=A Python-based plugin for creating ten actions and assign them to Python scripts Comment[ar]=ملحقة بِ‍«پيثون» لإنشاء ١٠ إجراءات وإسنادها إلى سكربتات «پيثون» Comment[ca]=Un connector basant en el Python per crear deu accions i assignar-les a scripts del Python Comment[ca@valencia]=Un connector basant en el Python per crear deu accions i assignar-les a scripts del Python Comment[en_GB]=A Python-based plugin for creating ten actions and assign them to Python scripts Comment[es]=Un complemento basado en Python para crear diez acciones y asignarlas a guiones de Python Comment[gl]=Un complemento escrito en Python para crear dez accións e asignalas a scripts escritos en Python. Comment[it]=Un'estensione basata su Python per creare dieci azioni e assegnarle a script Python Comment[nl]=Een op Python gebaseerde plug-in voor aanmaken van tien acties en ze dan toewijzen aan Python-scripts Comment[pl]=Wtyczka oparta na Pythonie do tworzenia działań i przypisywanie ich skryptom Pythona Comment[pt]=Um 'plugin' feito em Python para criar dez acções e atribuí-las a programas em Python Comment[sv]=Ett Python-baserat insticksprogram för att skapa tio åtgärder och tilldela dem till Python-skript Comment[uk]=Скрипт на основі Python для створення десяти дій і прив'язування до них скриптів Python Comment[x-test]=xxA Python-based plugin for creating ten actions and assign them to Python scriptsxx Comment[zh_CN]=基于 Python 的可创建十个操作并将它们指定到其它 Python 脚本的插件 Comment[zh_TW]=基於 Python 的外掛程式,用於建立 10 個動作並且將它們指定給 Python 腳本 diff --git a/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp b/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp index ba0ff8d8da..12ede4bd95 100644 --- a/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp +++ b/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp @@ -1,1289 +1,1297 @@ /* * Copyright (c) 2013 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_tool_transform_config_widget.h" #include #include "rotation_icons.h" #include "kis_canvas2.h" #include #include "kis_liquify_properties.h" #include "KisMainWindow.h" #include "KisViewManager.h" #include "kis_transform_utils.h" template inline T sign(T x) { return x > 0 ? 1 : x == (T)0 ? 0 : -1; } const int KisToolTransformConfigWidget::DEFAULT_POINTS_PER_LINE = 3; KisToolTransformConfigWidget::KisToolTransformConfigWidget(TransformTransactionProperties *transaction, KisCanvas2 *canvas, bool workRecursively, QWidget *parent) : QWidget(parent), m_transaction(transaction), m_notificationsBlocked(0), m_uiSlotsBlocked(0), m_configChanged(false) { setupUi(this); showDecorationsBox->setIcon(KisIconUtils::loadIcon("krita_tool_transform")); chkWorkRecursively->setIcon(KisIconUtils::loadIcon("krita_tool_transform_recursive")); flipXButton->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); flipYButton->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_y")); rotateCWButton->setIcon(KisIconUtils::loadIcon("transform_icons_rotate_cw")); rotateCCWButton->setIcon(KisIconUtils::loadIcon("transform_icons_rotate_ccw")); chkWorkRecursively->setChecked(workRecursively); connect(chkWorkRecursively, SIGNAL(toggled(bool)), this, SIGNAL(sigRestartTransform())); // Init Filter combo cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); cmbFilter->setCurrent("Bicubic"); cmbFilter->setToolTip(i18nc("@info:tooltip", "

Select filtering mode:\n" "

    " "
  • Bilinear for areas with uniform color to avoid artifacts
  • " "
  • Bicubic for smoother results
  • " "
  • Lanczos3 for sharp results. May produce aerials.
  • " "

")); connect(cmbFilter, SIGNAL(activated(const KoID &)), this, SLOT(slotFilterChanged(const KoID &))); // Init Warp Type combo cmbWarpType->insertItem(KisWarpTransformWorker::AFFINE_TRANSFORM,i18n("Default (Affine)")); cmbWarpType->insertItem(KisWarpTransformWorker::RIGID_TRANSFORM,i18n("Strong (Rigid)")); cmbWarpType->insertItem(KisWarpTransformWorker::SIMILITUDE_TRANSFORM,i18n("Strongest (Similitude)")); cmbWarpType->setCurrentIndex(KisWarpTransformWorker::AFFINE_TRANSFORM); connect(cmbWarpType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotWarpTypeChanged(int))); // Init Rotation Center buttons m_handleDir[0] = QPointF(1, 0); m_handleDir[1] = QPointF(1, -1); m_handleDir[2] = QPointF(0, -1); m_handleDir[3] = QPointF(-1, -1); m_handleDir[4] = QPointF(-1, 0); m_handleDir[5] = QPointF(-1, 1); m_handleDir[6] = QPointF(0, 1); m_handleDir[7] = QPointF(1, 1); m_handleDir[8] = QPointF(0, 0); // also add the center m_rotationCenterButtons = new QButtonGroup(0); // we set the ids to match m_handleDir m_rotationCenterButtons->addButton(middleRightButton, 0); m_rotationCenterButtons->addButton(topRightButton, 1); m_rotationCenterButtons->addButton(middleTopButton, 2); m_rotationCenterButtons->addButton(topLeftButton, 3); m_rotationCenterButtons->addButton(middleLeftButton, 4); m_rotationCenterButtons->addButton(bottomLeftButton, 5); m_rotationCenterButtons->addButton(middleBottomButton, 6); m_rotationCenterButtons->addButton(bottomRightButton, 7); m_rotationCenterButtons->addButton(centerButton, 8); QToolButton *nothingSelected = new QToolButton(0); nothingSelected->setCheckable(true); nothingSelected->setAutoExclusive(true); nothingSelected->hide(); // a convenient button for when no button is checked in the group m_rotationCenterButtons->addButton(nothingSelected, 9); // initialize values for free transform sliders shearXBox->setSuffix(i18n(" px")); shearYBox->setSuffix(i18n(" px")); shearXBox->setRange(-5.0, 5.0, 2); shearYBox->setRange(-5.0, 5.0, 2); shearXBox->setSingleStep(0.01); shearYBox->setSingleStep(0.01); shearXBox->setValue(0.0); shearYBox->setValue(0.0); translateXBox->setSuffix(i18n(" px")); translateYBox->setSuffix(i18n(" px")); translateXBox->setRange(-10000, 10000); translateYBox->setRange(-10000, 10000); scaleXBox->setSuffix("%"); scaleYBox->setSuffix("%"); scaleXBox->setRange(-10000, 10000); scaleYBox->setRange(-10000, 10000); scaleXBox->setValue(100.0); scaleYBox->setValue(100.0); m_scaleRatio = 1.0; aXBox->setSuffix(QChar(Qt::Key_degree)); aYBox->setSuffix(QChar(Qt::Key_degree)); aZBox->setSuffix(QChar(Qt::Key_degree)); aXBox->setRange(0.0, 360.0, 2); aYBox->setRange(0.0, 360.0, 2); aZBox->setRange(0.0, 360.0, 2); aXBox->setValue(0.0); aYBox->setValue(0.0); aZBox->setValue(0.0); aXBox->setSingleStep(1.0); aYBox->setSingleStep(1.0); aZBox->setSingleStep(1.0); connect(m_rotationCenterButtons, SIGNAL(buttonPressed(int)), this, SLOT(slotRotationCenterChanged(int))); connect(btnTransformAroundPivotPoint, SIGNAL(clicked(bool)), this, SLOT(slotTransformAroundRotationCenter(bool))); // Init Free Transform Values connect(scaleXBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetScaleX(int))); connect(scaleYBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetScaleY(int))); connect(shearXBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetShearX(qreal))); connect(shearYBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetShearY(qreal))); connect(translateXBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetTranslateX(int))); connect(translateYBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetTranslateY(int))); connect(aXBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetAX(qreal))); connect(aYBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetAY(qreal))); connect(aZBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetAZ(qreal))); connect(aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(slotSetKeepAspectRatio(bool))); connect(flipXButton, SIGNAL(clicked(bool)), this, SLOT(slotFlipX())); connect(flipYButton, SIGNAL(clicked(bool)), this, SLOT(slotFlipY())); connect(rotateCWButton, SIGNAL(clicked(bool)), this, SLOT(slotRotateCW())); connect(rotateCCWButton, SIGNAL(clicked(bool)), this, SLOT(slotRotateCCW())); // toggle visibility of different free buttons connect(freeMoveRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); connect(freeRotationRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); connect(freeScaleRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); connect(freeShearRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); // only first group for free transform rotationGroup->hide(); moveGroup->show(); scaleGroup->hide(); shearGroup->hide(); // Init Warp Transform Values alphaBox->setSingleStep(0.1); alphaBox->setRange(0, 10, 1); connect(alphaBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetWarpAlpha(qreal))); connect(densityBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetWarpDensity(int))); connect(defaultRadioButton, SIGNAL(clicked(bool)), this, SLOT(slotWarpDefaultPointsButtonClicked(bool))); connect(customRadioButton, SIGNAL(clicked(bool)), this, SLOT(slotWarpCustomPointsButtonClicked(bool))); connect(lockUnlockPointsButton, SIGNAL(clicked()), this, SLOT(slotWarpLockPointsButtonClicked())); connect(resetPointsButton, SIGNAL(clicked()), this, SLOT(slotWarpResetPointsButtonClicked())); // Init Cage Transform Values cageTransformButtonGroup->setId(cageAddEditRadio, 0); // we need to set manually since Qt Designer generates negative by default cageTransformButtonGroup->setId(cageDeformRadio, 1); connect(cageTransformButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotCageOptionsChanged(int))); // Init Liquify Transform Values liquifySizeSlider->setRange(KisLiquifyProperties::minSize(), KisLiquifyProperties::maxSize(), 2); liquifySizeSlider->setExponentRatio(4); liquifySizeSlider->setValue(60.0); connect(liquifySizeSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifySizeChanged(qreal))); liquifySizeSlider->setToolTip(i18nc("@info:tooltip", "Size of the deformation brush")); liquifyAmountSlider->setRange(0.0, 1.0, 2); liquifyAmountSlider->setValue(0.05); connect(liquifyAmountSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifyAmountChanged(qreal))); liquifyAmountSlider->setToolTip(i18nc("@info:tooltip", "Amount of the deformation you get")); liquifyFlowSlider->setRange(0.0, 1.0, 2); liquifyFlowSlider->setValue(1.0); connect(liquifyFlowSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifyFlowChanged(qreal))); liquifyFlowSlider->setToolTip(i18nc("@info:tooltip", "When in non-buildup mode, shows how fast the deformation limit is reached.")); buidupModeComboBox->setCurrentIndex(0); // set to build-up mode by default connect(buidupModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(liquifyBuildUpChanged(int))); buidupModeComboBox->setToolTip(i18nc("@info:tooltip", "Switch between Build Up and Wash mode of painting. Build Up mode adds deformations one on top of the other without any limits. Wash mode gradually deforms the piece to the selected deformation level.")); liquifySpacingSlider->setRange(0.0, 3.0, 2); liquifySizeSlider->setExponentRatio(3); liquifySpacingSlider->setSingleStep(0.01); liquifySpacingSlider->setValue(0.2); connect(liquifySpacingSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifySpacingChanged(qreal))); liquifySpacingSlider->setToolTip(i18nc("@info:tooltip", "Space between two sequential applications of the deformation")); liquifySizePressureBox->setChecked(true); connect(liquifySizePressureBox, SIGNAL(toggled(bool)), this, SLOT(liquifySizePressureChanged(bool))); liquifySizePressureBox->setToolTip(i18nc("@info:tooltip", "Scale Size value according to current stylus pressure")); liquifyAmountPressureBox->setChecked(true); connect(liquifyAmountPressureBox, SIGNAL(toggled(bool)), this, SLOT(liquifyAmountPressureChanged(bool))); liquifyAmountPressureBox->setToolTip(i18nc("@info:tooltip", "Scale Amount value according to current stylus pressure")); liquifyReverseDirectionChk->setChecked(false); connect(liquifyReverseDirectionChk, SIGNAL(toggled(bool)), this, SLOT(liquifyReverseDirectionChanged(bool))); liquifyReverseDirectionChk->setToolTip(i18nc("@info:tooltip", "Reverse direction of the current deformation tool")); QSignalMapper *liquifyModeMapper = new QSignalMapper(this); connect(liquifyMove, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); connect(liquifyScale, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); connect(liquifyRotate, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); connect(liquifyOffset, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); connect(liquifyUndo, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); liquifyModeMapper->setMapping(liquifyMove, (int)KisLiquifyProperties::MOVE); liquifyModeMapper->setMapping(liquifyScale, (int)KisLiquifyProperties::SCALE); liquifyModeMapper->setMapping(liquifyRotate, (int)KisLiquifyProperties::ROTATE); liquifyModeMapper->setMapping(liquifyOffset, (int)KisLiquifyProperties::OFFSET); liquifyModeMapper->setMapping(liquifyUndo, (int)KisLiquifyProperties::UNDO); connect(liquifyModeMapper, SIGNAL(mapped(int)), SLOT(slotLiquifyModeChanged(int))); liquifyMove->setToolTip(i18nc("@info:tooltip", "Move: drag the image along the brush stroke")); liquifyScale->setToolTip(i18nc("@info:tooltip", "Scale: grow/shrink image under cursor")); liquifyRotate->setToolTip(i18nc("@info:tooltip", "Rotate: twirl image under cursor")); liquifyOffset->setToolTip(i18nc("@info:tooltip", "Offset: shift the image to the right of the stroke direction")); liquifyUndo->setToolTip(i18nc("@info:tooltip", "Undo: erase actions of other tools")); // Connect all edit boxes to the Editing Finished signal connect(densityBox, SIGNAL(editingFinished()), this, SLOT(notifyEditingFinished())); // Connect other widget (not having editingFinished signal) to // the same slot. From Qt 4.6 onwards the sequence of the signal // delivery is definite. connect(cmbFilter, SIGNAL(activated(const KoID &)), this, SLOT(notifyEditingFinished())); connect(cmbWarpType, SIGNAL(currentIndexChanged(int)), this, SLOT(notifyEditingFinished())); connect(m_rotationCenterButtons, SIGNAL(buttonPressed(int)), this, SLOT(notifyEditingFinished())); connect(aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(notifyEditingFinished())); - connect(defaultRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); - connect(customRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); + connect(lockUnlockPointsButton, SIGNAL(clicked()), this, SLOT(notifyEditingFinished())); connect(resetPointsButton, SIGNAL(clicked()), this, SLOT(notifyEditingFinished())); + connect(defaultRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); + connect(customRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); + // Liquify // // liquify brush options do not affect the image directly and are not // saved to undo, so we don't emit notifyEditingFinished() for them // Connect Apply/Reset buttons connect(buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(slotButtonBoxClicked(QAbstractButton *))); // Mode switch buttons connect(freeTransformButton, SIGNAL(clicked(bool)), this, SLOT(slotSetFreeTransformModeButtonClicked(bool))); connect(warpButton, SIGNAL(clicked(bool)), this, SLOT(slotSetWarpModeButtonClicked(bool))); connect(cageButton, SIGNAL(clicked(bool)), this, SLOT(slotSetCageModeButtonClicked(bool))); connect(perspectiveTransformButton, SIGNAL(clicked(bool)), this, SLOT(slotSetPerspectiveModeButtonClicked(bool))); connect(liquifyButton, SIGNAL(clicked(bool)), this, SLOT(slotSetLiquifyModeButtonClicked(bool))); // Connect Decorations switcher connect(showDecorationsBox, SIGNAL(toggled(bool)), canvas, SLOT(updateCanvas())); tooBigLabelWidget->hide(); connect(canvas->viewManager()->mainWindow(), SIGNAL(themeChanged()), SLOT(slotUpdateIcons()), Qt::UniqueConnection); slotUpdateIcons(); } void KisToolTransformConfigWidget::slotUpdateIcons() { freeTransformButton->setIcon(KisIconUtils::loadIcon("transform_icons_main")); warpButton->setIcon(KisIconUtils::loadIcon("transform_icons_warp")); cageButton->setIcon(KisIconUtils::loadIcon("transform_icons_cage")); perspectiveTransformButton->setIcon(KisIconUtils::loadIcon("transform_icons_perspective")); liquifyButton->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_main")); liquifyMove->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_move")); liquifyScale->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_resize")); liquifyRotate->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_rotate")); liquifyOffset->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_offset")); liquifyUndo->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_erase")); middleRightButton->setIcon(KisIconUtils::loadIcon("arrow-right")); topRightButton->setIcon(KisIconUtils::loadIcon("arrow-topright")); middleTopButton->setIcon(KisIconUtils::loadIcon("arrow-up")); topLeftButton->setIcon(KisIconUtils::loadIcon("arrow-topleft")); middleLeftButton->setIcon(KisIconUtils::loadIcon("arrow-left")); bottomLeftButton->setIcon(KisIconUtils::loadIcon("arrow-downleft")); middleBottomButton->setIcon(KisIconUtils::loadIcon("arrow-down")); bottomRightButton->setIcon(KisIconUtils::loadIcon("arrow-downright")); btnTransformAroundPivotPoint->setIcon(KisIconUtils::loadIcon("pivot-point")); // pressure icons liquifySizePressureBox->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); liquifyAmountPressureBox->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } double KisToolTransformConfigWidget::radianToDegree(double rad) { double piX2 = 2 * M_PI; if (rad < 0 || rad >= piX2) { rad = fmod(rad, piX2); if (rad < 0) { rad += piX2; } } return (rad * 360. / piX2); } double KisToolTransformConfigWidget::degreeToRadian(double degree) { if (degree < 0. || degree >= 360.) { degree = fmod(degree, 360.); if (degree < 0) degree += 360.; } return (degree * M_PI / 180.); } void KisToolTransformConfigWidget::updateLiquifyControls() { blockUiSlots(); ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); const bool useWashMode = props->useWashMode(); liquifySizeSlider->setValue(props->size()); liquifyAmountSlider->setValue(props->amount()); liquifyFlowSlider->setValue(props->flow()); buidupModeComboBox->setCurrentIndex(useWashMode); liquifySpacingSlider->setValue(props->spacing()); liquifySizePressureBox->setChecked(props->sizeHasPressure()); liquifyAmountPressureBox->setChecked(props->amountHasPressure()); liquifyReverseDirectionChk->setChecked(props->reverseDirection()); KisLiquifyProperties::LiquifyMode mode = static_cast(props->mode()); bool canInverseDirection = mode != KisLiquifyProperties::UNDO; bool canUseWashMode = mode != KisLiquifyProperties::UNDO; liquifyReverseDirectionChk->setEnabled(canInverseDirection); liquifyFlowSlider->setEnabled(canUseWashMode && useWashMode); buidupModeComboBox->setEnabled(canUseWashMode); const qreal maxAmount = canUseWashMode ? 5.0 : 1.0; liquifyAmountSlider->setRange(0.0, maxAmount, 2); unblockUiSlots(); } void KisToolTransformConfigWidget::slotLiquifyModeChanged(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); KisLiquifyProperties::LiquifyMode mode = static_cast(value); if (mode == props->mode()) return; props->setMode(mode); props->loadMode(); updateLiquifyControls(); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifySizeChanged(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setSize(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifyAmountChanged(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setAmount(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifyFlowChanged(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setFlow(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifyBuildUpChanged(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setUseWashMode(value); // 0 == build up mode / 1 == wash mode notifyConfigChanged(); // we need to enable/disable flow slider updateLiquifyControls(); } void KisToolTransformConfigWidget::liquifySpacingChanged(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setSpacing(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifySizePressureChanged(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setSizeHasPressure(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifyAmountPressureChanged(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setAmountHasPressure(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::liquifyReverseDirectionChanged(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); KisLiquifyProperties *props = config->liquifyProperties(); props->setReverseDirection(value); notifyConfigChanged(); } void KisToolTransformConfigWidget::updateConfig(const ToolTransformArgs &config) { blockUiSlots(); if (config.mode() == ToolTransformArgs::FREE_TRANSFORM || config.mode() == ToolTransformArgs::PERSPECTIVE_4POINT) { quickTransformGroup->setEnabled(config.mode() == ToolTransformArgs::FREE_TRANSFORM); stackedWidget->setCurrentIndex(0); bool freeTransformIsActive = config.mode() == ToolTransformArgs::FREE_TRANSFORM; if (freeTransformIsActive) { freeTransformButton->setChecked(true); } else { perspectiveTransformButton->setChecked(true); } aXBox->setEnabled(freeTransformIsActive); aYBox->setEnabled(freeTransformIsActive); aZBox->setEnabled(freeTransformIsActive); freeRotationRadioButton->setEnabled(freeTransformIsActive); scaleXBox->setValue(config.scaleX() * 100.); scaleYBox->setValue(config.scaleY() * 100.); shearXBox->setValue(config.shearX()); shearYBox->setValue(config.shearY()); const QPointF anchorPoint = config.originalCenter() + config.rotationCenterOffset(); const KisTransformUtils::MatricesPack m(config); const QPointF anchorPointView = m.finalTransform().map(anchorPoint); translateXBox->setValue(anchorPointView.x()); translateYBox->setValue(anchorPointView.y()); aXBox->setValue(radianToDegree(config.aX())); aYBox->setValue(radianToDegree(config.aY())); aZBox->setValue(radianToDegree(config.aZ())); aspectButton->setKeepAspectRatio(config.keepAspectRatio()); cmbFilter->setCurrent(config.filterId()); QPointF pt = m_transaction->currentConfig()->rotationCenterOffset(); pt.rx() /= m_transaction->originalHalfWidth(); pt.ry() /= m_transaction->originalHalfHeight(); for (int i = 0; i < 9; i++) { if (qFuzzyCompare(m_handleDir[i].x(), pt.x()) && qFuzzyCompare(m_handleDir[i].y(), pt.y())) { m_rotationCenterButtons->button(i)->setChecked(true); break; } } btnTransformAroundPivotPoint->setChecked(config.transformAroundRotationCenter()); } else if (config.mode() == ToolTransformArgs::WARP) { stackedWidget->setCurrentIndex(1); warpButton->setChecked(true); if (config.defaultPoints()) { densityBox->setValue(std::sqrt(config.numPoints())); } cmbWarpType->setCurrentIndex((int)config.warpType()); defaultRadioButton->setChecked(config.defaultPoints()); customRadioButton->setChecked(!config.defaultPoints()); densityBox->setEnabled(config.defaultPoints()); customWarpWidget->setEnabled(!config.defaultPoints()); updateLockPointsButtonCaption(); } else if (config.mode() == ToolTransformArgs::CAGE) { // default UI options resetUIOptions(); // we need at least 3 point before we can start actively deforming if (config.origPoints().size() >= 3) { cageTransformDirections->setText(i18n("Switch between editing and deforming cage")); cageAddEditRadio->setVisible(true); cageDeformRadio->setVisible(true); // update to correct radio button if (config.isEditingTransformPoints()) cageAddEditRadio->setChecked(true); else cageDeformRadio->setChecked(true); } } else if (config.mode() == ToolTransformArgs::LIQUIFY) { stackedWidget->setCurrentIndex(3); liquifyButton->setChecked(true); const KisLiquifyProperties *props = config.liquifyProperties(); switch (props->mode()) { case KisLiquifyProperties::MOVE: liquifyMove->setChecked(true); break; case KisLiquifyProperties::SCALE: liquifyScale->setChecked(true); break; case KisLiquifyProperties::ROTATE: liquifyRotate->setChecked(true); break; case KisLiquifyProperties::OFFSET: liquifyOffset->setChecked(true); break; case KisLiquifyProperties::UNDO: liquifyUndo->setChecked(true); break; case KisLiquifyProperties::N_MODES: qFatal("Unsupported mode"); } updateLiquifyControls(); } unblockUiSlots(); } void KisToolTransformConfigWidget::updateLockPointsButtonCaption() { ToolTransformArgs *config = m_transaction->currentConfig(); if (config->isEditingTransformPoints()) { lockUnlockPointsButton->setText(i18n("Lock Points")); } else { lockUnlockPointsButton->setText(i18n("Unlock Points")); } } void KisToolTransformConfigWidget::setApplyResetDisabled(bool disabled) { QAbstractButton *applyButton = buttonBox->button(QDialogButtonBox::Apply); QAbstractButton *resetButton = buttonBox->button(QDialogButtonBox::Reset); Q_ASSERT(applyButton); Q_ASSERT(resetButton); applyButton->setDisabled(disabled); resetButton->setDisabled(disabled); } void KisToolTransformConfigWidget::resetRotationCenterButtons() { int checkedId = m_rotationCenterButtons->checkedId(); if (checkedId >= 0 && checkedId <= 8) { // uncheck the current checked button m_rotationCenterButtons->button(9)->setChecked(true); } } bool KisToolTransformConfigWidget::workRecursively() const { return chkWorkRecursively->isChecked(); } void KisToolTransformConfigWidget::setTooBigLabelVisible(bool value) { tooBigLabelWidget->setVisible(value); } bool KisToolTransformConfigWidget::showDecorations() const { return showDecorationsBox->isChecked(); } void KisToolTransformConfigWidget::blockNotifications() { m_notificationsBlocked++; } void KisToolTransformConfigWidget::unblockNotifications() { m_notificationsBlocked--; } void KisToolTransformConfigWidget::notifyConfigChanged() { if (!m_notificationsBlocked) { emit sigConfigChanged(); } m_configChanged = true; } void KisToolTransformConfigWidget::blockUiSlots() { m_uiSlotsBlocked++; } void KisToolTransformConfigWidget::unblockUiSlots() { m_uiSlotsBlocked--; } void KisToolTransformConfigWidget::notifyEditingFinished() { if (m_uiSlotsBlocked || m_notificationsBlocked || !m_configChanged) return; emit sigEditingFinished(); m_configChanged = false; } void KisToolTransformConfigWidget::resetUIOptions() { // reset tool states since we are done (probably can encapsulate this later) ToolTransformArgs *config = m_transaction->currentConfig(); if (config->mode() == ToolTransformArgs::CAGE) { cageAddEditRadio->setVisible(false); cageAddEditRadio->setChecked(true); cageDeformRadio->setVisible(false); cageTransformDirections->setText(i18n("Create 3 points on the canvas to begin")); // ensure we are on the right options view stackedWidget->setCurrentIndex(2); } } void KisToolTransformConfigWidget::slotButtonBoxClicked(QAbstractButton *button) { QAbstractButton *applyButton = buttonBox->button(QDialogButtonBox::Apply); QAbstractButton *resetButton = buttonBox->button(QDialogButtonBox::Reset); resetUIOptions(); if (button == applyButton) { emit sigApplyTransform(); } else if (button == resetButton) { emit sigResetTransform(); } } void KisToolTransformConfigWidget::slotSetFreeTransformModeButtonClicked(bool value) { if (!value) return; lblTransformType->setText(freeTransformButton->toolTip()); ToolTransformArgs *config = m_transaction->currentConfig(); config->setMode(ToolTransformArgs::FREE_TRANSFORM); emit sigResetTransform(); } void KisToolTransformConfigWidget::slotSetWarpModeButtonClicked(bool value) { if (!value) return; lblTransformType->setText(warpButton->toolTip()); ToolTransformArgs *config = m_transaction->currentConfig(); config->setMode(ToolTransformArgs::WARP); + config->setWarpCalculation(KisWarpTransformWorker::WarpCalculation::GRID); emit sigResetTransform(); } void KisToolTransformConfigWidget::slotSetCageModeButtonClicked(bool value) { if (!value) return; lblTransformType->setText(cageButton->toolTip()); ToolTransformArgs *config = m_transaction->currentConfig(); config->setMode(ToolTransformArgs::CAGE); emit sigResetTransform(); } void KisToolTransformConfigWidget::slotSetLiquifyModeButtonClicked(bool value) { if (!value) return; lblTransformType->setText(liquifyButton->toolTip()); ToolTransformArgs *config = m_transaction->currentConfig(); config->setMode(ToolTransformArgs::LIQUIFY); emit sigResetTransform(); } void KisToolTransformConfigWidget::slotSetPerspectiveModeButtonClicked(bool value) { if (!value) return; lblTransformType->setText(perspectiveTransformButton->toolTip()); ToolTransformArgs *config = m_transaction->currentConfig(); config->setMode(ToolTransformArgs::PERSPECTIVE_4POINT); emit sigResetTransform(); } void KisToolTransformConfigWidget::slotFilterChanged(const KoID &filterId) { ToolTransformArgs *config = m_transaction->currentConfig(); config->setFilterId(filterId.id()); notifyConfigChanged(); } void KisToolTransformConfigWidget::slotRotationCenterChanged(int index) { if (m_uiSlotsBlocked) return; if (index >= 0 && index <= 8) { ToolTransformArgs *config = m_transaction->currentConfig(); double i = m_handleDir[index].x(); double j = m_handleDir[index].y(); config->setRotationCenterOffset(QPointF(i * m_transaction->originalHalfWidth(), j * m_transaction->originalHalfHeight())); notifyConfigChanged(); updateConfig(*config); } } void KisToolTransformConfigWidget::slotTransformAroundRotationCenter(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); config->setTransformAroundRotationCenter(value); notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetScaleX(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleX(value / 100.); } if (config->keepAspectRatio()) { blockNotifications(); int calculatedValue = int( value/ m_scaleRatio ); scaleYBox->blockSignals(true); scaleYBox->setValue(calculatedValue); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleY(calculatedValue / 100.); } scaleYBox->blockSignals(false); unblockNotifications(); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetScaleY(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleY(value / 100.); } if (config->keepAspectRatio()) { blockNotifications(); int calculatedValue = int(m_scaleRatio * value); scaleXBox->blockSignals(true); scaleXBox->setValue(calculatedValue); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleX(calculatedValue / 100.); } scaleXBox->blockSignals(false); unblockNotifications(); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetShearX(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setShearX((double)value); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetShearY(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setShearY((double)value); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetTranslateX(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); const QPointF anchorPoint = config->originalCenter() + config->rotationCenterOffset(); const KisTransformUtils::MatricesPack m(*config); const QPointF anchorPointView = m.finalTransform().map(anchorPoint); const QPointF newAnchorPointView(value, anchorPointView.y()); config->setTransformedCenter(config->transformedCenter() + newAnchorPointView - anchorPointView); notifyConfigChanged(); } void KisToolTransformConfigWidget::slotSetTranslateY(int value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); const QPointF anchorPoint = config->originalCenter() + config->rotationCenterOffset(); const KisTransformUtils::MatricesPack m(*config); const QPointF anchorPointView = m.finalTransform().map(anchorPoint); const QPointF newAnchorPointView(anchorPointView.x(), value); config->setTransformedCenter(config->transformedCenter() + newAnchorPointView - anchorPointView); notifyConfigChanged(); } void KisToolTransformConfigWidget::slotSetAX(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setAX(degreeToRadian((double)value)); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetAY(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setAY(degreeToRadian((double)value)); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetAZ(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setAZ(degreeToRadian((double)value)); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotFlipX() { ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleX(config->scaleX() * -1); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotFlipY() { ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setScaleY(config->scaleY() * -1); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotRotateCW() { ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setAZ(normalizeAngle(config->aZ() + M_PI_2)); } notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotRotateCCW() { ToolTransformArgs *config = m_transaction->currentConfig(); { KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); config->setAZ(normalizeAngle(config->aZ() - M_PI_2)); } notifyConfigChanged(); notifyEditingFinished(); } // change free transform setting we want to alter (all radio buttons call this) void KisToolTransformConfigWidget::slotTransformAreaVisible(bool value) { Q_UNUSED(value); //QCheckBox sender = (QCheckBox)(*)(QObject::sender()); QString senderName = QObject::sender()->objectName(); // only show setting with what we have selected rotationGroup->hide(); shearGroup->hide(); scaleGroup->hide(); moveGroup->hide(); if ("freeMoveRadioButton" == senderName) { moveGroup->show(); } else if ("freeShearRadioButton" == senderName) { shearGroup->show(); } else if ("freeScaleRadioButton" == senderName) { scaleGroup->show(); } else { rotationGroup->show(); } } void KisToolTransformConfigWidget::slotSetKeepAspectRatio(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); config->setKeepAspectRatio(value); if (value) { blockNotifications(); int tmpXScaleBox = scaleXBox->value(); int tmpYScaleBox = scaleYBox->value(); m_scaleRatio = (tmpXScaleBox / (double) tmpYScaleBox); unblockNotifications(); } notifyConfigChanged(); } void KisToolTransformConfigWidget::slotSetWarpAlpha(qreal value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); config->setAlpha((double)value); notifyConfigChanged(); notifyEditingFinished(); } void KisToolTransformConfigWidget::slotSetWarpDensity(int value) { if (m_uiSlotsBlocked) return; setDefaultWarpPoints(value); } void KisToolTransformConfigWidget::setDefaultWarpPoints(int pointsPerLine) { if (pointsPerLine < 0) { pointsPerLine = DEFAULT_POINTS_PER_LINE; } int nbPoints = pointsPerLine * pointsPerLine; QVector origPoints(nbPoints); QVector transfPoints(nbPoints); qreal gridSpaceX, gridSpaceY; if (nbPoints == 1) { //there is actually no grid origPoints[0] = m_transaction->originalCenterGeometric(); transfPoints[0] = m_transaction->originalCenterGeometric(); } else if (nbPoints > 1) { gridSpaceX = m_transaction->originalRect().width() / (pointsPerLine - 1); gridSpaceY = m_transaction->originalRect().height() / (pointsPerLine - 1); double y = m_transaction->originalRect().top(); for (int i = 0; i < pointsPerLine; ++i) { double x = m_transaction->originalRect().left(); for (int j = 0 ; j < pointsPerLine; ++j) { origPoints[i * pointsPerLine + j] = QPointF(x, y); transfPoints[i * pointsPerLine + j] = QPointF(x, y); x += gridSpaceX; } y += gridSpaceY; } } ToolTransformArgs *config = m_transaction->currentConfig(); config->setDefaultPoints(nbPoints > 0); config->setPoints(origPoints, transfPoints); notifyConfigChanged(); } void KisToolTransformConfigWidget::activateCustomWarpPoints(bool enabled) { ToolTransformArgs *config = m_transaction->currentConfig(); densityBox->setEnabled(!enabled); customWarpWidget->setEnabled(enabled); if (!enabled) { config->setEditingTransformPoints(false); setDefaultWarpPoints(densityBox->value()); + config->setWarpCalculation(KisWarpTransformWorker::WarpCalculation::GRID); } else { config->setEditingTransformPoints(true); + config->setWarpCalculation(KisWarpTransformWorker::WarpCalculation::DRAW); setDefaultWarpPoints(0); } + + + updateLockPointsButtonCaption(); } void KisToolTransformConfigWidget::slotWarpDefaultPointsButtonClicked(bool value) { if (m_uiSlotsBlocked) return; activateCustomWarpPoints(!value); } void KisToolTransformConfigWidget::slotWarpCustomPointsButtonClicked(bool value) { if (m_uiSlotsBlocked) return; activateCustomWarpPoints(value); } void KisToolTransformConfigWidget::slotWarpResetPointsButtonClicked() { if (m_uiSlotsBlocked) return; activateCustomWarpPoints(true); } void KisToolTransformConfigWidget::slotWarpLockPointsButtonClicked() { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); config->setEditingTransformPoints(!config->isEditingTransformPoints()); if (config->isEditingTransformPoints()) { // reinit the transf points to their original value ToolTransformArgs *config = m_transaction->currentConfig(); int nbPoints = config->origPoints().size(); for (int i = 0; i < nbPoints; ++i) { config->transfPoint(i) = config->origPoint(i); } } updateLockPointsButtonCaption(); notifyConfigChanged(); } void KisToolTransformConfigWidget::slotWarpTypeChanged(int index) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); switch (index) { case KisWarpTransformWorker::AFFINE_TRANSFORM: case KisWarpTransformWorker::SIMILITUDE_TRANSFORM: case KisWarpTransformWorker::RIGID_TRANSFORM: config->setWarpType((KisWarpTransformWorker::WarpType)index); break; default: config->setWarpType(KisWarpTransformWorker::RIGID_TRANSFORM); break; } notifyConfigChanged(); } void KisToolTransformConfigWidget::slotCageOptionsChanged(int value) { if ( value == 0) { slotEditCagePoints(true); } else { slotEditCagePoints(false); } notifyEditingFinished(); } void KisToolTransformConfigWidget::slotEditCagePoints(bool value) { if (m_uiSlotsBlocked) return; ToolTransformArgs *config = m_transaction->currentConfig(); config->refTransformedPoints() = config->origPoints(); config->setEditingTransformPoints(value); notifyConfigChanged(); } diff --git a/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp b/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp index c1fdd050ee..488a673a0d 100644 --- a/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp +++ b/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp @@ -1,592 +1,630 @@ /* * 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. */ #include "kis_warp_transform_strategy.h" #include #include #include #include "kis_coordinates_converter.h" #include "tool_transform_args.h" #include "transform_transaction_properties.h" #include "kis_painting_tweaks.h" #include "kis_cursor.h" #include "kis_transform_utils.h" #include "kis_algebra_2d.h" - +#include "KisHandlePainterHelper.h" struct KisWarpTransformStrategy::Private { Private(KisWarpTransformStrategy *_q, const KisCoordinatesConverter *_converter, ToolTransformArgs &_currentArgs, TransformTransactionProperties &_transaction) : q(_q), converter(_converter), currentArgs(_currentArgs), transaction(_transaction), lastNumPoints(0), - drawConnectionLines(true), - drawOrigPoints(true), + drawConnectionLines(false), // useful while developing + drawOrigPoints(false), drawTransfPoints(true), closeOnStartPointClick(false), clipOriginalPointsPosition(true), pointWasDragged(false) { } KisWarpTransformStrategy * const q; /// standard members /// const KisCoordinatesConverter *converter; ////// ToolTransformArgs ¤tArgs; ////// TransformTransactionProperties &transaction; QTransform paintingTransform; QPointF paintingOffset; QTransform handlesTransform; /// custom members /// QImage transformedImage; int pointIndexUnderCursor; enum Mode { OVER_POINT = 0, MULTIPLE_POINT_SELECTION, MOVE_MODE, ROTATE_MODE, SCALE_MODE, NOTHING }; Mode mode; QVector pointsInAction; int lastNumPoints; bool drawConnectionLines; bool drawOrigPoints; bool drawTransfPoints; bool closeOnStartPointClick; bool clipOriginalPointsPosition; QPointF pointPosOnClick; bool pointWasDragged; QPointF lastMousePos; void recalculateTransformations(); inline QPointF imageToThumb(const QPointF &pt, bool useFlakeOptimization); bool shouldCloseTheCage() const; QVector getSelectedPoints(QPointF *center, bool limitToSelectedOnly = false) const; }; KisWarpTransformStrategy::KisWarpTransformStrategy(const KisCoordinatesConverter *converter, ToolTransformArgs ¤tArgs, TransformTransactionProperties &transaction) : KisSimplifiedActionPolicyStrategy(converter), m_d(new Private(this, converter, currentArgs, transaction)) { } KisWarpTransformStrategy::~KisWarpTransformStrategy() { } void KisWarpTransformStrategy::setTransformFunction(const QPointF &mousePos, bool perspectiveModifierActive) { double handleRadius = KisTransformUtils::effectiveHandleGrabRadius(m_d->converter); bool cursorOverPoint = false; m_d->pointIndexUnderCursor = -1; KisTransformUtils::HandleChooser handleChooser(mousePos, Private::NOTHING); const QVector &points = m_d->currentArgs.transfPoints(); for (int i = 0; i < points.size(); ++i) { if (handleChooser.addFunction(points[i], handleRadius, Private::NOTHING)) { cursorOverPoint = true; m_d->pointIndexUnderCursor = i; } } if (cursorOverPoint) { m_d->mode = perspectiveModifierActive && !m_d->currentArgs.isEditingTransformPoints() ? Private::MULTIPLE_POINT_SELECTION : Private::OVER_POINT; } else if (!m_d->currentArgs.isEditingTransformPoints()) { QPolygonF polygon(m_d->currentArgs.transfPoints()); bool insidePolygon = polygon.boundingRect().contains(mousePos); m_d->mode = insidePolygon ? Private::MOVE_MODE : !perspectiveModifierActive ? Private::ROTATE_MODE : Private::SCALE_MODE; } else { m_d->mode = Private::NOTHING; } } QCursor KisWarpTransformStrategy::getCurrentCursor() const { QCursor cursor; switch (m_d->mode) { case Private::OVER_POINT: cursor = KisCursor::pointingHandCursor(); break; case Private::MULTIPLE_POINT_SELECTION: cursor = KisCursor::crossCursor(); break; case Private::MOVE_MODE: cursor = KisCursor::moveCursor(); break; case Private::ROTATE_MODE: cursor = KisCursor::rotateCursor(); break; case Private::SCALE_MODE: cursor = KisCursor::sizeVerCursor(); break; case Private::NOTHING: cursor = KisCursor::arrowCursor(); break; } return cursor; } void KisWarpTransformStrategy::overrideDrawingItems(bool drawConnectionLines, bool drawOrigPoints, bool drawTransfPoints) { m_d->drawConnectionLines = drawConnectionLines; m_d->drawOrigPoints = drawOrigPoints; m_d->drawTransfPoints = drawTransfPoints; } void KisWarpTransformStrategy::setCloseOnStartPointClick(bool value) { m_d->closeOnStartPointClick = value; } void KisWarpTransformStrategy::setClipOriginalPointsPosition(bool value) { m_d->clipOriginalPointsPosition = value; } void KisWarpTransformStrategy::drawConnectionLines(QPainter &gc, const QVector &origPoints, const QVector &transfPoints, bool isEditingPoints) { Q_UNUSED(isEditingPoints); QPen antsPen; QPen outlinePen; KisPaintingTweaks::initAntsPen(&antsPen, &outlinePen); const int numPoints = origPoints.size(); for (int i = 0; i < numPoints; ++i) { gc.setPen(outlinePen); gc.drawLine(transfPoints[i], origPoints[i]); gc.setPen(antsPen); gc.drawLine(transfPoints[i], origPoints[i]); } } void KisWarpTransformStrategy::paint(QPainter &gc) { // Draw preview image gc.save(); gc.setOpacity(m_d->transaction.basePreviewOpacity()); gc.setTransform(m_d->paintingTransform, true); gc.drawImage(m_d->paintingOffset, m_d->transformedImage); gc.restore(); gc.save(); gc.setTransform(m_d->handlesTransform, true); - // draw connecting lines if (m_d->drawConnectionLines) { gc.setOpacity(0.5); drawConnectionLines(gc, m_d->currentArgs.origPoints(), m_d->currentArgs.transfPoints(), m_d->currentArgs.isEditingTransformPoints()); } + + QPen mainPen(Qt::black); + QPen outlinePen(Qt::white); + // draw handles { const int numPoints = m_d->currentArgs.origPoints().size(); - QPen mainPen(Qt::black); - QPen outlinePen(Qt::white); + qreal handlesExtraScale = KisTransformUtils::scaleFromAffineMatrix(m_d->handlesTransform); qreal dstIn = 8 / handlesExtraScale; qreal dstOut = 10 / handlesExtraScale; qreal srcIn = 6 / handlesExtraScale; qreal srcOut = 6 / handlesExtraScale; QRectF handleRect1(-0.5 * dstIn, -0.5 * dstIn, dstIn, dstIn); QRectF handleRect2(-0.5 * dstOut, -0.5 * dstOut, dstOut, dstOut); if (m_d->drawTransfPoints) { gc.setOpacity(1.0); for (int i = 0; i < numPoints; ++i) { gc.setPen(outlinePen); gc.drawEllipse(handleRect2.translated(m_d->currentArgs.transfPoints()[i])); gc.setPen(mainPen); gc.drawEllipse(handleRect1.translated(m_d->currentArgs.transfPoints()[i])); } QPointF center; QVector selectedPoints = m_d->getSelectedPoints(¢er, true); QBrush selectionBrush = selectedPoints.size() > 1 ? Qt::red : Qt::black; QBrush oldBrush = gc.brush(); gc.setBrush(selectionBrush); Q_FOREACH (const QPointF *pt, selectedPoints) { gc.drawEllipse(handleRect1.translated(*pt)); } gc.setBrush(oldBrush); } if (m_d->drawOrigPoints) { QPainterPath inLine; inLine.moveTo(-0.5 * srcIn, 0); inLine.lineTo( 0.5 * srcIn, 0); inLine.moveTo( 0, -0.5 * srcIn); inLine.lineTo( 0, 0.5 * srcIn); QPainterPath outLine; outLine.moveTo(-0.5 * srcOut, -0.5 * srcOut); outLine.lineTo( 0.5 * srcOut, -0.5 * srcOut); outLine.lineTo( 0.5 * srcOut, 0.5 * srcOut); outLine.lineTo(-0.5 * srcOut, 0.5 * srcOut); outLine.lineTo(-0.5 * srcOut, -0.5 * srcOut); gc.setOpacity(0.5); for (int i = 0; i < numPoints; ++i) { gc.setPen(outlinePen); gc.drawPath(outLine.translated(m_d->currentArgs.origPoints()[i])); gc.setPen(mainPen); gc.drawPath(inLine.translated(m_d->currentArgs.origPoints()[i])); } } } + + // draw grid lines only if we are using the GRID mode. + if (m_d->currentArgs.warpCalculation() == KisWarpTransformWorker::WarpCalculation::GRID) { + + // see how many rows we have. we are only going to do lines up to 6 divisions/ + // it is almost impossible to use with 6 even. + const int numPoints = m_d->currentArgs.origPoints().size(); + + // grid is always square, so get the square root to find # of rows + int rowsInWarp = sqrt(m_d->currentArgs.origPoints().size()); + + + KisHandlePainterHelper handlePainter(&gc); + handlePainter.setHandleStyle(KisHandleStyle::primarySelection()); + + // draw horizontal lines + for (int i = 0; i < numPoints; i++) { + if (i != 0 && i % rowsInWarp == rowsInWarp -1) { + // skip line if it is the last in the row + } else { + handlePainter.drawConnectionLine(m_d->currentArgs.transfPoints()[i], m_d->currentArgs.transfPoints()[i+1] ); + } + } + + // draw vertical lines + for (int i = 0; i < numPoints; i++) { + + if ( (numPoints - i - 1) < rowsInWarp ) { + // last row doesn't need to draw vertical lines + } else { + handlePainter.drawConnectionLine(m_d->currentArgs.transfPoints()[i], m_d->currentArgs.transfPoints()[i+rowsInWarp] ); + } + } + + } // end if statement + gc.restore(); } void KisWarpTransformStrategy::externalConfigChanged() { if (m_d->lastNumPoints != m_d->currentArgs.transfPoints().size()) { m_d->pointsInAction.clear(); } m_d->recalculateTransformations(); } bool KisWarpTransformStrategy::beginPrimaryAction(const QPointF &pt) { const bool isEditingPoints = m_d->currentArgs.isEditingTransformPoints(); bool retval = false; if (m_d->mode == Private::OVER_POINT || m_d->mode == Private::MULTIPLE_POINT_SELECTION || m_d->mode == Private::MOVE_MODE || m_d->mode == Private::ROTATE_MODE || m_d->mode == Private::SCALE_MODE) { retval = true; } else if (isEditingPoints) { QPointF newPos = m_d->clipOriginalPointsPosition ? KisTransformUtils::clipInRect(pt, m_d->transaction.originalRect()) : pt; m_d->currentArgs.refOriginalPoints().append(newPos); m_d->currentArgs.refTransformedPoints().append(newPos); m_d->mode = Private::OVER_POINT; m_d->pointIndexUnderCursor = m_d->currentArgs.origPoints().size() - 1; m_d->recalculateTransformations(); emit requestCanvasUpdate(); retval = true; } if (m_d->mode == Private::OVER_POINT) { m_d->pointPosOnClick = m_d->currentArgs.transfPoints()[m_d->pointIndexUnderCursor]; m_d->pointWasDragged = false; m_d->pointsInAction.clear(); m_d->pointsInAction << m_d->pointIndexUnderCursor; m_d->lastNumPoints = m_d->currentArgs.transfPoints().size(); } else if (m_d->mode == Private::MULTIPLE_POINT_SELECTION) { QVector::iterator it = std::find(m_d->pointsInAction.begin(), m_d->pointsInAction.end(), m_d->pointIndexUnderCursor); if (it != m_d->pointsInAction.end()) { m_d->pointsInAction.erase(it); } else { m_d->pointsInAction << m_d->pointIndexUnderCursor; } m_d->lastNumPoints = m_d->currentArgs.transfPoints().size(); } m_d->lastMousePos = pt; return retval; } QVector KisWarpTransformStrategy::Private::getSelectedPoints(QPointF *center, bool limitToSelectedOnly) const { QVector &points = currentArgs.refTransformedPoints(); QRectF boundingRect; QVector selectedPoints; if (limitToSelectedOnly || pointsInAction.size() > 1) { Q_FOREACH (int index, pointsInAction) { selectedPoints << &points[index]; KisAlgebra2D::accumulateBounds(points[index], &boundingRect); } } else { QVector::iterator it = points.begin(); QVector::iterator end = points.end(); for (; it != end; ++it) { selectedPoints << &(*it); KisAlgebra2D::accumulateBounds(*it, &boundingRect); } } *center = boundingRect.center(); return selectedPoints; } void KisWarpTransformStrategy::continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive) { Q_UNUSED(shiftModifierActve); Q_UNUSED(altModifierActive); // toplevel code switches to HOVER mode if nothing is selected KIS_ASSERT_RECOVER_RETURN(m_d->mode == Private::MOVE_MODE || m_d->mode == Private::ROTATE_MODE || m_d->mode == Private::SCALE_MODE || (m_d->mode == Private::OVER_POINT && m_d->pointIndexUnderCursor >= 0 && m_d->pointsInAction.size() == 1) || (m_d->mode == Private::MULTIPLE_POINT_SELECTION && m_d->pointIndexUnderCursor >= 0)); if (m_d->mode == Private::OVER_POINT) { if (m_d->currentArgs.isEditingTransformPoints()) { QPointF newPos = m_d->clipOriginalPointsPosition ? KisTransformUtils::clipInRect(pt, m_d->transaction.originalRect()) : pt; m_d->currentArgs.origPoint(m_d->pointIndexUnderCursor) = newPos; m_d->currentArgs.transfPoint(m_d->pointIndexUnderCursor) = newPos; } else { m_d->currentArgs.transfPoint(m_d->pointIndexUnderCursor) = pt; } const qreal handleRadiusSq = pow2(KisTransformUtils::effectiveHandleGrabRadius(m_d->converter)); qreal dist = kisSquareDistance( m_d->currentArgs.transfPoint(m_d->pointIndexUnderCursor), m_d->pointPosOnClick); if (dist > handleRadiusSq) { m_d->pointWasDragged = true; } } else if (m_d->mode == Private::MOVE_MODE) { QPointF center; QVector selectedPoints = m_d->getSelectedPoints(¢er); QPointF diff = pt - m_d->lastMousePos; QVector::iterator it = selectedPoints.begin(); QVector::iterator end = selectedPoints.end(); for (; it != end; ++it) { **it += diff; } } else if (m_d->mode == Private::ROTATE_MODE) { QPointF center; QVector selectedPoints = m_d->getSelectedPoints(¢er); QPointF oldDirection = m_d->lastMousePos - center; QPointF newDirection = pt - center; qreal rotateAngle = KisAlgebra2D::angleBetweenVectors(oldDirection, newDirection); QTransform R; R.rotateRadians(rotateAngle); QTransform t = QTransform::fromTranslate(-center.x(), -center.y()) * R * QTransform::fromTranslate(center.x(), center.y()); QVector::iterator it = selectedPoints.begin(); QVector::iterator end = selectedPoints.end(); for (; it != end; ++it) { **it = t.map(**it); } } else if (m_d->mode == Private::SCALE_MODE) { QPointF center; QVector selectedPoints = m_d->getSelectedPoints(¢er); QPolygonF polygon(m_d->currentArgs.origPoints()); QSizeF maxSize = polygon.boundingRect().size(); qreal maxDimension = qMax(maxSize.width(), maxSize.height()); qreal scale = 1.0 - (pt - m_d->lastMousePos).y() / maxDimension; QTransform t = QTransform::fromTranslate(-center.x(), -center.y()) * QTransform::fromScale(scale, scale) * QTransform::fromTranslate(center.x(), center.y()); QVector::iterator it = selectedPoints.begin(); QVector::iterator end = selectedPoints.end(); for (; it != end; ++it) { **it = t.map(**it); } } m_d->lastMousePos = pt; m_d->recalculateTransformations(); emit requestCanvasUpdate(); } bool KisWarpTransformStrategy::Private::shouldCloseTheCage() const { return currentArgs.isEditingTransformPoints() && closeOnStartPointClick && pointIndexUnderCursor == 0 && currentArgs.origPoints().size() > 2 && !pointWasDragged; } bool KisWarpTransformStrategy::acceptsClicks() const { return m_d->shouldCloseTheCage() || m_d->currentArgs.isEditingTransformPoints(); } bool KisWarpTransformStrategy::endPrimaryAction() { if (m_d->shouldCloseTheCage()) { m_d->currentArgs.setEditingTransformPoints(false); } return true; } inline QPointF KisWarpTransformStrategy::Private::imageToThumb(const QPointF &pt, bool useFlakeOptimization) { return useFlakeOptimization ? converter->imageToDocument(converter->documentToFlake((pt))) : q->thumbToImageTransform().inverted().map(pt); } void KisWarpTransformStrategy::Private::recalculateTransformations() { QTransform scaleTransform = KisTransformUtils::imageToFlakeTransform(converter); QTransform resultThumbTransform = q->thumbToImageTransform() * scaleTransform; qreal scale = KisTransformUtils::scaleFromAffineMatrix(resultThumbTransform); bool useFlakeOptimization = scale < 1.0 && !KisTransformUtils::thumbnailTooSmall(resultThumbTransform, q->originalImage().rect()); QVector thumbOrigPoints(currentArgs.numPoints()); QVector thumbTransfPoints(currentArgs.numPoints()); for (int i = 0; i < currentArgs.numPoints(); ++i) { thumbOrigPoints[i] = imageToThumb(currentArgs.origPoints()[i], useFlakeOptimization); thumbTransfPoints[i] = imageToThumb(currentArgs.transfPoints()[i], useFlakeOptimization); } paintingOffset = transaction.originalTopLeft(); if (!q->originalImage().isNull() && !currentArgs.isEditingTransformPoints()) { QPointF origTLInFlake = imageToThumb(transaction.originalTopLeft(), useFlakeOptimization); if (useFlakeOptimization) { transformedImage = q->originalImage().transformed(resultThumbTransform); paintingTransform = QTransform(); } else { transformedImage = q->originalImage(); paintingTransform = resultThumbTransform; } transformedImage = q->calculateTransformedImage(currentArgs, transformedImage, thumbOrigPoints, thumbTransfPoints, origTLInFlake, &paintingOffset); } else { transformedImage = q->originalImage(); paintingOffset = imageToThumb(transaction.originalTopLeft(), false); paintingTransform = resultThumbTransform; } handlesTransform = scaleTransform; } QImage KisWarpTransformStrategy::calculateTransformedImage(ToolTransformArgs ¤tArgs, const QImage &srcImage, const QVector &origPoints, const QVector &transfPoints, const QPointF &srcOffset, QPointF *dstOffset) { return KisWarpTransformWorker::transformQImage( currentArgs.warpType(), origPoints, transfPoints, currentArgs.alpha(), srcImage, srcOffset, dstOffset); } diff --git a/plugins/tools/tool_transform2/tool_transform_args.h b/plugins/tools/tool_transform2/tool_transform_args.h index 47b985ed0f..b04e2ec363 100644 --- a/plugins/tools/tool_transform2/tool_transform_args.h +++ b/plugins/tools/tool_transform2/tool_transform_args.h @@ -1,325 +1,333 @@ /* * tool_transform_args.h - part of Krita * * Copyright (c) 2010 Marc Pegon * * 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 TOOL_TRANSFORM_ARGS_H_ #define TOOL_TRANSFORM_ARGS_H_ #include #include #include #include #include "kis_liquify_properties.h" #include "kritatooltransform_export.h" #include "kis_global.h" #include class KisLiquifyTransformWorker; class QDomElement; /** * Class used to store the parameters of a transformation. * Some parameters are specific to free transform mode, and * others to warp mode : maybe add a union to save a little more * memory. */ class KRITATOOLTRANSFORM_EXPORT ToolTransformArgs { public: enum TransformMode {FREE_TRANSFORM = 0, WARP, CAGE, LIQUIFY, PERSPECTIVE_4POINT, N_MODES}; /** * Initializes the parameters for an identity transformation, * with mode set to free transform. */ ToolTransformArgs(); /** * The object return will be a copy of args. */ ToolTransformArgs(const ToolTransformArgs& args); /** * If mode is warp, original and transformed vector points will be of size 0. * Use setPoints method to set those vectors. */ ToolTransformArgs(TransformMode mode, QPointF transformedCenter, QPointF originalCenter, QPointF rotationCenterOffset, bool transformAroundRotationCenter, double aX, double aY, double aZ, double scaleX, double scaleY, double shearX, double shearY, KisWarpTransformWorker::WarpType warpType, double alpha, bool defaultPoints, const QString &filterId); ~ToolTransformArgs(); ToolTransformArgs& operator=(const ToolTransformArgs& args); bool operator==(const ToolTransformArgs& other) const; bool isSameMode(const ToolTransformArgs& other) const; inline TransformMode mode() const { return m_mode; } inline void setMode(TransformMode mode) { m_mode = mode; } //warp-related inline int numPoints() const { KIS_ASSERT_RECOVER_NOOP(m_origPoints.size() == m_transfPoints.size()); return m_origPoints.size(); } inline QPointF &origPoint(int i) { return m_origPoints[i]; } inline QPointF &transfPoint(int i) { return m_transfPoints[i]; } inline const QVector &origPoints() const { return m_origPoints; } inline const QVector &transfPoints() const { return m_transfPoints; } inline QVector &refOriginalPoints() { return m_origPoints; } inline QVector &refTransformedPoints() { return m_transfPoints; } inline KisWarpTransformWorker::WarpType warpType() const { return m_warpType; } inline double alpha() const { return m_alpha; } inline bool defaultPoints() const { return m_defaultPoints; } inline void setPoints(QVector origPoints, QVector transfPoints) { m_origPoints = QVector(origPoints); m_transfPoints = QVector(transfPoints); } inline void setWarpType(KisWarpTransformWorker::WarpType warpType) { m_warpType = warpType; } + inline void setWarpCalculation(KisWarpTransformWorker::WarpCalculation warpCalc) { + m_warpCalculation = warpCalc; + } + inline KisWarpTransformWorker::WarpCalculation warpCalculation() { + return m_warpCalculation; + } + inline void setAlpha(double alpha) { m_alpha = alpha; } inline void setDefaultPoints(bool defaultPoints) { m_defaultPoints = defaultPoints; } //"free transform"-related inline QPointF transformedCenter() const { return m_transformedCenter; } inline QPointF originalCenter() const { return m_originalCenter; } inline QPointF rotationCenterOffset() const { return m_rotationCenterOffset; } inline bool transformAroundRotationCenter() const { return m_transformAroundRotationCenter; } inline double aX() const { return m_aX; } inline double aY() const { return m_aY; } inline double aZ() const { return m_aZ; } inline QVector3D cameraPos() const { return m_cameraPos; } inline double scaleX() const { return m_scaleX; } inline double scaleY() const { return m_scaleY; } inline bool keepAspectRatio() const { return m_keepAspectRatio; } inline double shearX() const { return m_shearX; } inline double shearY() const { return m_shearY; } inline void setTransformedCenter(QPointF transformedCenter) { m_transformedCenter = transformedCenter; } inline void setOriginalCenter(QPointF originalCenter) { m_originalCenter = originalCenter; } inline void setRotationCenterOffset(QPointF rotationCenterOffset) { m_rotationCenterOffset = rotationCenterOffset; } void setTransformAroundRotationCenter(bool value); inline void setAX(double aX) { KIS_ASSERT_RECOVER_NOOP(aX == normalizeAngle(aX)); m_aX = aX; } inline void setAY(double aY) { KIS_ASSERT_RECOVER_NOOP(aY == normalizeAngle(aY)); m_aY = aY; } inline void setAZ(double aZ) { KIS_ASSERT_RECOVER_NOOP(aZ == normalizeAngle(aZ)); m_aZ = aZ; } inline void setCameraPos(const QVector3D &pos) { m_cameraPos = pos; } inline void setScaleX(double scaleX) { m_scaleX = scaleX; } inline void setScaleY(double scaleY) { m_scaleY = scaleY; } inline void setKeepAspectRatio(bool value) { m_keepAspectRatio = value; } inline void setShearX(double shearX) { m_shearX = shearX; } inline void setShearY(double shearY) { m_shearY = shearY; } inline QString filterId() const { return m_filter->id(); } void setFilterId(const QString &id); inline KisFilterStrategy* filter() const { return m_filter; } bool isIdentity() const; inline QTransform flattenedPerspectiveTransform() const { return m_flattenedPerspectiveTransform; } inline void setFlattenedPerspectiveTransform(const QTransform &value) { m_flattenedPerspectiveTransform = value; } bool isEditingTransformPoints() const { return m_editTransformPoints; } void setEditingTransformPoints(bool value) { m_editTransformPoints = value; } const KisLiquifyProperties* liquifyProperties() const { return m_liquifyProperties.data(); } KisLiquifyProperties* liquifyProperties() { return m_liquifyProperties.data(); } void initLiquifyTransformMode(const QRect &srcRect); void saveLiquifyTransformMode() const; KisLiquifyTransformWorker* liquifyWorker() const { return m_liquifyWorker.data(); } void toXML(QDomElement *e) const; static ToolTransformArgs fromXML(const QDomElement &e); void translate(const QPointF &offset); void saveContinuedState(); void restoreContinuedState(); const ToolTransformArgs* continuedTransform() const; private: void clear(); void init(const ToolTransformArgs& args); TransformMode m_mode; // warp-related arguments // these are basically the arguments taken by the warp transform worker bool m_defaultPoints; // true : the original points are set to make a grid // which density is given by numPoints() QVector m_origPoints; QVector m_transfPoints; KisWarpTransformWorker::WarpType m_warpType; + KisWarpTransformWorker::WarpCalculation m_warpCalculation; // DRAW or GRID double m_alpha; //'free transform'-related // basically the arguments taken by the transform worker QPointF m_transformedCenter; QPointF m_originalCenter; QPointF m_rotationCenterOffset; // the position of the rotation center relative to // the original top left corner of the selection // before any transformation bool m_transformAroundRotationCenter; // In freehand mode makes the scaling and other transformations // be anchored to the rotation center point. double m_aX; double m_aY; double m_aZ; QVector3D m_cameraPos; double m_scaleX; double m_scaleY; double m_shearX; double m_shearY; bool m_keepAspectRatio; // perspective trasform related QTransform m_flattenedPerspectiveTransform; KisFilterStrategy *m_filter; bool m_editTransformPoints; QSharedPointer m_liquifyProperties; QScopedPointer m_liquifyWorker; /** * When we continue a transformation, m_continuedTransformation * stores the initial step of our transform. All cancel and revert * operations should revert to it. */ QScopedPointer m_continuedTransformation; }; #endif // TOOL_TRANSFORM_ARGS_H_ diff --git a/plugins/tools/tool_transform2/wdg_tool_transform.ui b/plugins/tools/tool_transform2/wdg_tool_transform.ui index 2ed7769bcc..467d799f89 100644 --- a/plugins/tools/tool_transform2/wdg_tool_transform.ui +++ b/plugins/tools/tool_transform2/wdg_tool_transform.ui @@ -1,2204 +1,2207 @@ WdgToolTransform 0 0 - 479 + 489 674 0 0 0 0 16777215 16777215 0 0 Qt::LeftToRight 0 0 0 0 0 4 QFrame::NoFrame QFrame::Plain 0 1 1 1 1 0 0 0 Free Free Transform true true true true 0 0 Perspective Perspective true true true 0 0 Warp Warp true false true true 0 0 Cage Cage true true true 0 0 Liquify Liquify true true true 0 0 Free Transform Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::StyledPanel QFrame::Raised - 3 + 0 0 0 0 0 0 0 12 QLayout::SetFixedSize 10 10 20 10 15 0 0 Qt::RightToLeft &Filter: Qt::AlignCenter cmbFilter QLayout::SetDefaultConstraint 0 true 0 0 true true 0 0 true true 0 0 true true 0 0 true true true 0 0 true true 0 0 true true 0 0 true true 0 0 true true 0 0 true true 0 0 0 0 Transform around pivot point (Alt) true true Posi&tion true freeTransformRadioGroup &Rotate freeTransformRadioGroup Scale freeTransformRadioGroup Shear freeTransformRadioGroup 0 0 0 0 75 true Qt::LeftToRight false off canvas Qt::RichText false true Qt::NoTextInteraction Qt::Horizontal 40 20 true 0 0 240 100 Rotation false false false 2 5 0 7 0 QFormLayout::AllNonFixedFieldsGrow 5 5 0 0 0 0 Rotate around X-Axis Qt::LeftToRight &x: aXBox Rotate around X-Axis 0 0 0 0 Rotate around Y-Axis Qt::LeftToRight &y: aYBox Rotate around Y-Axis 0 0 Rotate around Z-Axis 0 0 0 0 Rotate around Z-Axis Qt::LeftToRight &z: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter aZBox 0 0 240 70 Scale false false false 2 5 0 0 5 0 0 0 0 Horizontal Scale w&idth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter scaleXBox 0 0 Horizontal Scale % 0 0 Vertical Scale % 0 0 0 0 Vertical Scale &height: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter scaleYBox 0 0 20 25 0 0 240 70 Position false false false 2 5 0 0 QFormLayout::AllNonFixedFieldsGrow 0 0 Horizontal Translation Qt::LeftToRight x: translateXBox 0 0 Horizontal Translation Qt::LeftToRight 0 0 Vertical Translation 0 0 Vertical Translation y: translateYBox 0 0 240 80 false Shear Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false false false 2 5 0 0 QFormLayout::AllNonFixedFieldsGrow 8 20 0 0 Horizontal Shear x: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter shearXBox 0 0 Vertical Shear 0 0 0 0 Vertical Shear y: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter shearYBox 0 0 Horizontal Shear Qt::Vertical QSizePolicy::Preferred 20 10 6 0 0 32 16777215 Flip selection horizontally 0 0 32 16777215 Flip selection vertically Qt::Horizontal QSizePolicy::Preferred 20 20 0 0 32 16777215 Rotate selection counter-clockwise 90 degrees 0 0 32 16777215 Rotate the selection clockwise 90 degrees Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Preferred 20 10 10 0 0 0 0 0 2 0 &Flexibility: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter alphaBox 0 0 0 0 Anc&hor Strength: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter cmbWarpType false Anchor Points false false 0 0 0 0 0 0 0 Subd&ivide true true buttonGroup Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - 0 + 2 + + + 30 3 0 0 0 0 0 0 0 Draw true buttonGroup false 0 0 0 0 0 Clear Points Lock Points Qt::Vertical 20 10 Create 3 points on the canvas to begin Add/Ed&it Anchor Points true cageTransformButtonGroup true De&form Layer cageTransformButtonGroup Qt::Vertical 20 40 0 0 0 <html><head/><body><p><br/></p></body></html> QFrame::NoFrame QFrame::Plain 0 2 2 15 0 0 Move true true true true 0 0 Scale true true true 0 0 Rotate true true true 0 0 Offset true true true 0 0 Undo true true true 3 5 0 0 51 0 Reverse: 0 0 49 0 Spacing: 0 0 32 0 Flow: 0 0 27 0 Size: 0 0 51 0 Amount: 0 0 38 0 Mode: 0 0 0 Build Up Wash true 0 0 true Pressure true true true Pressure true true true Qt::Vertical 20 0 6 6 0 0 32 16777215 Show Decorations true false 0 0 32 16777215 Work Recursively true true Qt::Horizontal 13 13 Qt::LeftToRight Qt::Horizontal QDialogButtonBox::Apply|QDialogButtonBox::Reset true KisCmbIDList
widgets/kis_cmb_idlist.h
KoAspectButton QWidget
KoAspectButton.h
1
KisIntParseSpinBox QSpinBox
kis_int_parse_spin_box.h
KisDoubleSliderSpinBox QWidget
kis_slider_spin_box.h
1
- +