diff --git a/CMakeLists.txt b/CMakeLists.txt index e631cafe5d..9eab2731d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,674 +1,674 @@ project(krita) message(STATUS "Using CMake version: ${CMAKE_VERSION}") cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) if (WIN32) set(MIN_QT_VERSION 5.6.0) else() set(MIN_QT_VERSION 5.4.0) endif() set(MIN_FRAMEWORKS_VERSION 5.7.0) if (POLICY CMP0002) cmake_policy(SET CMP0002 OLD) endif() if (POLICY CMP0017) cmake_policy(SET CMP0017 NEW) endif () if (POLICY CMP0022) cmake_policy(SET CMP0022 OLD) endif () if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() if (POLICY CMP0046) cmake_policy(SET CMP0046 OLD) endif () if (POLICY CMP0059) cmake_policy(SET CMP0059 OLD) endif() if (POLICY CMP0063) cmake_policy(SET CMP0063 OLD) endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 OLD) endif() if (POLICY CMP0064) cmake_policy(SET CMP0064 OLD) endif() if (APPLE) set(APPLE_SUPPRESS_X11_WARNING TRUE) set(KDE_SKIP_RPATH_SETTINGS TRUE) set(CMAKE_MACOSX_RPATH 1) set(BUILD_WITH_INSTALL_RPATH 1) add_definitions(-mmacosx-version-min=10.9 -Wno-deprecated-register) endif() # QT5TODO: remove KDE4_BUILD_TESTS once all kde4_add_unit_test have been converted # transitional forward compatibility: # BUILD_TESTING is cmake standard, KDE4_BUILD_TESTS not used by ECM/KF5, but only # macros in cmake/transitional. Just, Macros from cmake/transitional, # incl. kde4_add_unit_test, are only picked up if no macros from kdelibs4 are installed, # because that transitional path is appended. Prepending instead might possibly unwantedly # mask ECM/KF5 macros. Not tested. # So have BUILD_TESTING define KDE4_BUILD_TESTS. if (BUILD_TESTING) set(KDE4_BUILD_TESTS TRUE) else() set(KDE4_BUILD_TESTS FALSE) endif() ###################### ####################### ## Constants defines ## ####################### ###################### # define common versions of Krita applications, used to generate kritaversion.h # update these version for every release: set(KRITA_VERSION_STRING "3.0.2 Alpha") set(KRITA_STABLE_VERSION_MAJOR 3) # 3 for 3.x, 4 for 4.x, etc. set(KRITA_STABLE_VERSION_MINOR 0) # 0 for 3.0, 1 for 3.1, etc. set(KRITA_VERSION_RELEASE 2) # 89 for Alpha, increase for next test releases, set 0 for first Stable, etc. set(KRITA_ALPHA 1) # uncomment only for Alpha #set(KRITA_BETA 1) # uncomment only for Beta #set(KRITA_RC 1) # uncomment only for RC set(KRITA_YEAR 2016) # update every year if(NOT DEFINED KRITA_ALPHA AND NOT DEFINED KRITA_BETA AND NOT DEFINED KRITA_RC) set(KRITA_STABLE 1) # do not edit endif() message(STATUS "Krita version: ${KRITA_VERSION_STRING}") # Define the generic version of the Krita libraries here # This makes it easy to advance it when the next Krita release comes. # 14 was the last GENERIC_KRITA_LIB_VERSION_MAJOR of the previous Krita series # (2.x) so we're starting with 15 in 3.x series. if(KRITA_STABLE_VERSION_MAJOR EQUAL 3) math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 15") else() # let's make sure we won't forget to update the "15" message(FATAL_ERROR "Reminder: please update offset == 15 used to compute GENERIC_KRITA_LIB_VERSION_MAJOR to something bigger") endif() set(GENERIC_KRITA_LIB_VERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}.0.0") set(GENERIC_KRITA_LIB_SOVERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/kde_macro") message("Module path:" ${CMAKE_MODULE_PATH}) # fetch git revision for the current build set(KRITA_GIT_SHA1_STRING "") set(KRITA_GIT_BRANCH_STRING "") include(GetGitRevisionDescription) get_git_head_revision(GIT_REFSPEC GIT_SHA1) get_git_branch(GIT_BRANCH) if(GIT_SHA1 AND GIT_BRANCH) string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1) set(KRITA_GIT_SHA1_STRING ${GIT_SHA1}) set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH}) endif() if(NOT DEFINED RELEASE_BUILD) # estimate mode by CMAKE_BUILD_TYPE content if not set on cmdline string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER) set(RELEASE_BUILD_TYPES "release" "relwithdebinfo" "minsizerel") list(FIND RELEASE_BUILD_TYPES "${CMAKE_BUILD_TYPE_TOLOWER}" INDEX) if (INDEX EQUAL -1) set(RELEASE_BUILD FALSE) else() set(RELEASE_BUILD TRUE) endif() endif() message(STATUS "Release build: ${RELEASE_BUILD}") ############ ############# ## Options ## ############# ############ option(PACKAGERS_BUILD "Build support of multiple CPU architectures in one binary. Should be used by packagers only or Krita developers. Only switch off when you're an artist optimizing a build for your very own machine." ON) if (WIN32) option(USE_BREAKPAD "Build the crash handler for Krita (only on windows)" OFF) 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) ####################### ######################## ## Productset setting ## ######################## ####################### # For predefined productsets see the definitions in KritaProducts.cmake and # in the files in the folder cmake/productsets. # Finding out the products & features to build is done in 5 steps: # 1. have the user define the products/features wanted, by giving a productset # 2. estimate all additional required products/features # 3. estimate which of the products/features can be build by external deps # 4. find which products/features have been temporarily disabled due to problems # 5. estimate which of the products/features can be build by internal deps # get the special macros include(CalligraProductSetMacros) include(MacroJPEG) include(GenerateTestExportHeader) # get the definitions of products, features and product sets include(KritaProducts.cmake) set(PRODUCTSET_DEFAULT "ALL") # temporary migration support if (CREATIVEONLY) set(WARN_ABOUT_CREATIVEONLY TRUE) set(PRODUCTSET_DEFAULT "CREATIVE") endif () if(NOT PRODUCTSET) set(PRODUCTSET ${PRODUCTSET_DEFAULT} CACHE STRING "Set of products/features to build" FORCE) endif() if (RELEASE_BUILD) set(CALLIGRA_SHOULD_BUILD_STAGING FALSE) else () set(CALLIGRA_SHOULD_BUILD_STAGING TRUE) endif () # finally choose products/features to build calligra_set_productset(${PRODUCTSET}) ######################## ######################### ## Look for KDE and Qt ## ######################### ######################## find_package(ECM 1.7.0 REQUIRED NOMODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(ECMOptionalAddSubdirectory) include(ECMAddAppIcon) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(ECMMarkAsTest) include(ECMInstallIcons) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) include(FeatureSummary) include(KDE4Macros) # 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 ) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Svg Test Concurrent ) set(QT_QTTEST_LIBRARY Qt5::Test) include (MacroLibrary) include (MacroAdditionalCleanFiles) include (MacroAddFileDependencies) 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) if (NOT WIN32 AND NOT APPLE) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras) find_package(Qt5DBus ${MIN_QT_VERSION} QUIET) set(HAVE_DBUS ${Qt5DBus_FOUND}) macro_log_feature(${Qt5DBus_FOUND} "dbus" "Qt DBUS integration" "http://www.qt.io/" FALSE "" "Optionally used to provide a dbus api on Linux") find_package(KF5KIO ${MIN_FRAMEWORKS_VERSION} QUIET) macro_bool_to_01(KF5KIO_FOUND HAVE_KIO) macro_log_feature(${KF5KIO_FOUND} "KIO" "KDE's KIO Framework" "http://api.kde.org/frameworks-api/frameworks5-apidocs/kio/html/index.html" FALSE "" "Optionally used for recent document handling") find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION} QUIET) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) macro_log_feature(${KF5Crash_FOUND} "kcrash" "KDE's Crash Handler" "http://api.kde.org/frameworks-api/frameworks5-apidocs/kcrash/html/index.html" FALSE "" "Optionally used to provide crash reporting on Linux") find_package(X11) if(X11_FOUND) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED NO_MODULE COMPONENTS X11Extras) set(HAVE_X11 TRUE) add_definitions(-DHAVE_X11) else() set(HAVE_X11 FALSE) endif() find_package(XCB COMPONENTS XCB ATOM) if(XCB_FOUND) set(HAVE_XCB TRUE) else() set(HAVE_XCB FALSE) endif() else() set(HAVE_DBUS FALSE) set(HAVE_X11 FALSE) set(HAVE_XCB FALSE) endif() add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_STRICT_ITERATORS -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_USE_FAST_OPERATOR_PLUS -DQT_USE_FAST_CONCATENATION -DQT_NO_URL_CAST_FROM_STRING -DQT_DISABLE_DEPRECATED_BEFORE=0 ) add_definitions(-DTRANSLATION_DOMAIN=\"krita\") # # The reason for this mode is that the Debug mode disable inlining # if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_KRITADEVS "-O3 -g" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") endif() if(UNIX) set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m") endif() if(WIN32) if(MSVC) # C4522: 'class' : multiple assignment operators specified set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4522") endif() endif() # enable exceptions globally kde_enable_exceptions() # only with this definition will all the FOO_TEST_EXPORT macro do something # TODO: check if this can be moved to only those places which make use of it, # to reduce global compiler definitions that would trigger a recompile of # everything on a change (like adding/removing tests to/from the build) if(BUILD_TESTING) add_definitions(-DCOMPILING_TESTS) endif() set(KRITA_DEFAULT_TEST_DATA_DIR ${CMAKE_SOURCE_DIR}/sdk/tests/data/) macro(macro_add_unittest_definitions) add_definitions(-DFILES_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data/") add_definitions(-DFILES_OUTPUT_DIR="${CMAKE_CURRENT_BINARY_DIR}") add_definitions(-DFILES_DEFAULT_DATA_DIR="${KRITA_DEFAULT_TEST_DATA_DIR}") endmacro() # overcome some platform incompatibilities if(WIN32) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/winquirks) add_definitions(-D_USE_MATH_DEFINES) add_definitions(-DNOMINMAX) set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib) endif() # set custom krita plugin installdir set(KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins) ########################### ############################ ## Required dependencies ## ############################ ########################### find_package(PNG REQUIRED) if (APPLE) # this is not added correctly on OSX -- see http://forum.kde.org/viewtopic.php?f=139&t=101867&p=221242#p221242 include_directories(SYSTEM ${PNG_INCLUDE_DIR}) endif() add_definitions(-DBOOST_ALL_NO_LIB) find_package(Boost REQUIRED COMPONENTS system) # for pigment and stage - +include_directories(${Boost_INCLUDE_DIRS}) ## ## Test for GNU Scientific Library ## macro_optional_find_package(GSL) macro_log_feature(GSL_FOUND "GSL" "GNU Scientific Library" "http://www.gnu.org/software/gsl" FALSE "1.7" "Required by Krita's Transform tool.") macro_bool_to_01(GSL_FOUND HAVE_GSL) configure_file(config-gsl.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gsl.h ) ########################### ############################ ## Optional dependencies ## ############################ ########################### ## ## Check for OpenEXR ## macro_optional_find_package(ZLIB) macro_log_feature(ZLIB_FOUND "zlib" "Compression library" "http://www.zlib.net/" FALSE "" "Optionally used by the G'Mic and the PSD plugins") macro_bool_to_01(ZLIB_FOUND HAVE_ZLIB) macro_optional_find_package(OpenEXR) macro_log_feature(OPENEXR_FOUND "OpenEXR" "High dynamic-range (HDR) image file format" "http://www.openexr.com" FALSE "" "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() macro_optional_find_package(TIFF) macro_log_feature(TIFF_FOUND "tiff" "TIFF Library and Utilities" "http://www.remotesensing.org/libtiff" FALSE "" "Required by the Krita TIFF filter") macro_optional_find_package(JPEG) macro_log_feature(JPEG_FOUND "jpeg" "Free library for JPEG image compression. Note: libjpeg8 is NOT supported." "http://www.libjpeg-turbo.org" FALSE "" "Required by the Krita JPEG filter") set(LIBRAW_MIN_VERSION "0.16") macro_optional_find_package(LibRaw ${LIBRAW_MIN_VERSION}) macro_log_feature(LIBRAW_FOUND "LibRaw" "Library to decode RAW images" "http://www.libraw.org" FALSE "" "Required to build the raw import plugin") macro_optional_find_package(FFTW3) macro_log_feature(FFTW3_FOUND "FFTW3" "A fast, free C FFT library" "http://www.fftw.org/" FALSE "" "Required by the Krita for fast convolution operators and some G'Mic features") macro_bool_to_01(FFTW3_FOUND HAVE_FFTW3) macro_optional_find_package(OCIO) macro_log_feature(OCIO_FOUND "OCIO" "The OpenColorIO Library" "http://www.opencolorio.org" FALSE "" "Required by the Krita LUT docker") macro_bool_to_01(OCIO_FOUND HAVE_OCIO) ## ## Look for OpenGL ## # TODO: see if there is a better check for QtGui being built with opengl support (and thus the QOpenGL* classes) if(Qt5Gui_OPENGL_IMPLEMENTATION) message(STATUS "Found QtGui OpenGL support") else() message(FATAL_ERROR "Did NOT find QtGui OpenGL support. Check your Qt configuration. You cannot build Krita without Qt OpenGL support.") endif() ## ## Test for eigen3 ## find_package(Eigen3 REQUIRED) macro_log_feature(EIGEN3_FOUND "Eigen" "C++ template library for linear algebra" "http://eigen.tuxfamily.org" FALSE "3.0" "Required by Krita") ## ## Test for exiv2 ## set(EXIV2_MIN_VERSION "0.16") find_package(Exiv2 REQUIRED) macro_log_feature(EXIV2_FOUND "Exiv2" "Image metadata library and tools" "http://www.exiv2.org" FALSE "0.16" "Required by Krita") ## ## Test for lcms ## find_package(LCMS2 REQUIRED) macro_log_feature(LCMS2_FOUND "LittleCMS" "Color management engine" "http://www.littlecms.com" FALSE "2.4" "Will be used for color management and is necessary for Krita") if(LCMS2_FOUND) if(NOT ${LCMS2_VERSION} VERSION_LESS 2040 ) set(HAVE_LCMS24 TRUE) endif() set(HAVE_REQUIRED_LCMS_VERSION TRUE) set(HAVE_LCMS2 TRUE) endif() ## ## Test for Vc ## set(OLD_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) set(HAVE_VC FALSE) if( NOT MSVC) macro_optional_find_package(Vc 1.1.0) macro_log_feature(Vc_FOUND "Vc" "Portable, zero-overhead SIMD library for C++" "https://github.com/VcDevel/Vc" FALSE "" "Required by the Krita for vectorization") macro_bool_to_01(Vc_FOUND HAVE_VC) macro_bool_to_01(PACKAGERS_BUILD DO_PACKAGERS_BUILD) endif() configure_file(config-vc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-vc.h ) if(HAVE_VC) message(STATUS "Vc found!") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/vc") include (VcMacros) if(Vc_COMPILER_IS_CLANG) set(ADDITIONAL_VC_FLAGS "-Wabi -ffp-contract=fast -fPIC") elseif (NOT MSVC) set(ADDITIONAL_VC_FLAGS "-Wabi -fabi-version=0 -ffp-contract=fast -fPIC") endif() #Handle Vc master if(Vc_COMPILER_IS_GCC OR Vc_COMPILER_IS_CLANG) AddCompilerFlag("-std=c++11" _ok) if(NOT _ok) AddCompilerFlag("-std=c++0x" _ok) endif() endif() macro(ko_compile_for_all_implementations_no_scalar _objs _src) if(PACKAGERS_BUILD) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) else() set(${_objs} ${_src}) endif() endmacro() macro(ko_compile_for_all_implementations _objs _src) if(PACKAGERS_BUILD) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) else() set(${_objs} ${_src}) endif() endmacro() if (NOT PACKAGERS_BUILD) # Optimize everything for the current architecture set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}") endif () endif() set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} ) ## ## Test for Xinput ## if(NOT WIN32 AND NOT APPLE) set(REQUIRED_Xinput_FOUND ${X11_Xinput_FOUND}) else() set(REQUIRED_Xinput_FOUND TRUE) endif() add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS}) if(WIN32) set(LIB_INSTALL_DIR ${LIB_INSTALL_DIR} RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY ${INSTALL_TARGETS_DEFAULT_ARGS} ARCHIVE ${INSTALL_TARGETS_DEFAULT_ARGS} ) endif() ## ## Test endianess ## include (TestBigEndian) test_big_endian(CMAKE_WORDS_BIGENDIAN) ## ## Test for qt-poppler ## macro_optional_find_package(Poppler) macro_log_feature( POPPLER_FOUND "Poppler-Qt5" "A PDF rendering library" "http://poppler.freedesktop.org" FALSE "" "Required by the Krita PDF filter.") ## ## Test for pthreads (for G'Mic) ## macro_optional_find_package(Threads) macro_log_feature(Threads_FOUND "PThreads" "A low-level threading library" "" FALSE "" "Optionally used by the G'Mic plugin") ## ## Test for OpenMP (for G'Mic) ## macro_optional_find_package(OpenMP) macro_log_feature(OPENMP_FOUND "OpenMP" "A low-level parallel execution library" "http://openmp.org/wp/" FALSE "" "Optionally used by the G'Mic plugin") ## ## Test for Curl (for G'Mic) ## macro_optional_find_package(CURL) macro_log_feature(CURL_FOUND "CURL" "A tool to fetch remote data" "http://curl.haxx.se/" FALSE "" "Optionally used by the G'Mic plugin") ############################ ############################# ## Add Krita helper macros ## ############################# ############################ include(MacroKritaAddBenchmark) #################### ##################### ## Define includes ## ##################### #################### # for config.h and includes (if any?) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/interfaces ) include_directories( ${CMAKE_SOURCE_DIR}/libs/version ${CMAKE_BINARY_DIR}/libs/version ) ################################################### #################################################### ## Detect which products/features can be compiled ## #################################################### ################################################### calligra_drop_product_on_bad_condition( APP_KRITA EIGEN3_FOUND "Eigen devel not found" EXIV2_FOUND "libexiv2 devel not found" HAVE_REQUIRED_LCMS_VERSION "lcms devel not found" Boost_SYSTEM_FOUND "boost-system devel not found" REQUIRED_Xinput_FOUND "Xinput devel not found " ) ############################################# #### Backward compatibility BUILD_x=off #### ############################################# # workaround: disable directly all products which might be activated by internal # dependencies, but belong to scope of old flag calligra_drop_products_on_old_flag(krita APP_KRITA) ############################################# #### Temporarily broken products #### ############################################# # If a product does not build due to some temporary brokeness disable it here, # by calling calligra_disable_product with the product id and the reason, # e.g.: # calligra_disable_product(APP_KEXI "isn't buildable at the moment") ############################################# #### Calculate buildable products #### ############################################# calligra_drop_unbuildable_products() ################### #################### ## Subdirectories ## #################### ################### if(SHOULD_BUILD_APP_KRITA) add_subdirectory(krita) endif() # non-app directories are moved here because they can depend on SHOULD_BUILD_{appname} variables set above add_subdirectory(libs) add_subdirectory(plugins) add_subdirectory( benchmarks ) macro_display_feature_log() calligra_product_deps_report("product_deps") calligra_log_should_build() 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) diff --git a/benchmarks/kis_bcontrast_benchmark.cpp b/benchmarks/kis_bcontrast_benchmark.cpp index dc25217552..109c398700 100644 --- a/benchmarks/kis_bcontrast_benchmark.cpp +++ b/benchmarks/kis_bcontrast_benchmark.cpp @@ -1,100 +1,100 @@ /* * Copyright (c) 2010 Lukáš Tvrdý lukast.dev@gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kis_bcontrast_benchmark.h" #include "kis_benchmark_values.h" #include #include #include #include #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter.h" #include "kis_processing_information.h" #include "kis_selection.h" #include #include "krita_utils.h" void KisBContrastBenchmark::initTestCase() { - m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); + m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); m_device = new KisPaintDevice(m_colorSpace); m_color = KoColor(m_colorSpace); - + srand(31524744); - + int r,g,b; KisSequentialIterator it(m_device, QRect(0, 0, GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT)); do { r = rand() % 255; g = rand() % 255; b = rand() % 255; - + m_color.fromQColor(QColor(r,g,b)); memcpy(it.rawData(), m_color.data(), m_colorSpace->pixelSize()); } while (it.nextPixel()); - + } void KisBContrastBenchmark::cleanupTestCase() { } void KisBContrastBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("brightnesscontrast"); - KisFilterConfiguration * kfc = filter->defaultConfiguration(m_device); + KisFilterConfigurationSP kfc = filter->defaultConfiguration(m_device); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } QSize size = KritaUtils::optimalPatchSize(); QVector rects = KritaUtils::splitRectIntoPatches(QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), size); QBENCHMARK{ Q_FOREACH (const QRect &rc, rects) { filter->process(m_device, rc, kfc); } } } QTEST_MAIN(KisBContrastBenchmark) diff --git a/benchmarks/kis_blur_benchmark.cpp b/benchmarks/kis_blur_benchmark.cpp index 2b9173f371..80d24578ac 100644 --- a/benchmarks/kis_blur_benchmark.cpp +++ b/benchmarks/kis_blur_benchmark.cpp @@ -1,92 +1,92 @@ /* * Copyright (c) 2010 Lukáš Tvrdý lukast.dev@gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kis_blur_benchmark.h" #include "kis_benchmark_values.h" #include #include #include #include #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter.h" #include "kis_processing_information.h" #include "kis_selection.h" #include void KisBlurBenchmark::initTestCase() { m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); m_device = new KisPaintDevice(m_colorSpace); m_color = KoColor(m_colorSpace); QColor qcolor(Qt::red); srand(31524744); int r,g,b; KisSequentialIterator it(m_device, QRect(0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT)); do { r = rand() % 255; g = rand() % 255; b = rand() % 255; m_color.fromQColor(QColor(r,g,b)); memcpy(it.rawData(), m_color.data(), m_colorSpace->pixelSize()); } while (it.nextPixel()); } void KisBlurBenchmark::cleanupTestCase() { } void KisBlurBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); - KisFilterConfiguration * kfc = filter->defaultConfiguration(m_device); + KisFilterConfigurationSP kfc = filter->defaultConfiguration(m_device); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } QBENCHMARK{ filter->process(m_device, QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), kfc); } } QTEST_MAIN(KisBlurBenchmark) diff --git a/benchmarks/kis_filter_selections_benchmark.h b/benchmarks/kis_filter_selections_benchmark.h index d7b7972c2b..80e6999de9 100644 --- a/benchmarks/kis_filter_selections_benchmark.h +++ b/benchmarks/kis_filter_selections_benchmark.h @@ -1,53 +1,53 @@ /* * 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_FILTER_SELECTIONS_BENCHMARK_H #define KIS_FILTER_SELECTIONS_BENCHMARK_H #include #include "kis_selection.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_processing_information.h" class KisFilterSelectionsBenchmark : public QObject { Q_OBJECT private Q_SLOTS: void testAll(); private: void initSelection(); void initFilter(const QString &name); void testFilter(const QString &name); void testUsualSelections(int num); void testNoSelections(int num); void testGoodSelections(int num); void testBitBltWOSelections(int num); void testBitBltSelections(int num); private: KisSelectionSP m_selection; KisPaintDeviceSP m_device; KisFilterSP m_filter; - KisFilterConfiguration *m_configuration; + KisFilterConfigurationSP m_configuration; }; #endif diff --git a/benchmarks/kis_level_filter_benchmark.cpp b/benchmarks/kis_level_filter_benchmark.cpp index 1100127305..6a9538b8ef 100644 --- a/benchmarks/kis_level_filter_benchmark.cpp +++ b/benchmarks/kis_level_filter_benchmark.cpp @@ -1,106 +1,106 @@ /* * Copyright (c) 2015 Thorsten Zachmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kis_level_filter_benchmark.h" #include "kis_benchmark_values.h" #include #include #include #include #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_color_transformation_configuration.h" #include "filter/kis_filter.h" #include "kis_processing_information.h" #include "kis_selection.h" #include #include "krita_utils.h" void KisLevelFilterBenchmark::initTestCase() { m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); m_device = new KisPaintDevice(m_colorSpace); m_color = KoColor(m_colorSpace); QColor qcolor(Qt::red); srand(31524744); int r,g,b; KisSequentialIterator it(m_device, QRect(0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT)); do { r = rand() % 255; g = rand() % 255; b = rand() % 255; m_color.fromQColor(QColor(r,g,b)); memcpy(it.rawData(), m_color.data(), m_colorSpace->pixelSize()); } while (it.nextPixel()); } void KisLevelFilterBenchmark::cleanupTestCase() { } void KisLevelFilterBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("levels"); - //KisFilterConfiguration * kfc = filter->defaultConfiguration(m_device); + //KisFilterConfigurationSP kfc = filter->defaultConfiguration(m_device); KisColorTransformationConfiguration * kfc= new KisColorTransformationConfiguration("levels", 1); kfc->setProperty("blackvalue", 75); kfc->setProperty("whitevalue", 231); kfc->setProperty("gammavalue", 1.0); kfc->setProperty("outblackvalue", 0); kfc->setProperty("outwhitevalue", 255); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } QSize size = KritaUtils::optimalPatchSize(); QVector rects = KritaUtils::splitRectIntoPatches(QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), size); QBENCHMARK{ Q_FOREACH (const QRect &rc, rects) { filter->process(m_device, rc, kfc); } } } QTEST_MAIN(KisLevelFilterBenchmark) diff --git a/interfaces/KoID.h b/interfaces/KoID.h index 26f2a3df9d..267fb0bd15 100644 --- a/interfaces/KoID.h +++ b/interfaces/KoID.h @@ -1,129 +1,136 @@ /* This file is part of the KDE project * Copyright (C) 2006 Thomas Zander * 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 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 _KO_ID_H_ #define _KO_ID_H_ #include #include #include #include /** * A KoID is a combination of a user-visible string and a string that uniquely * identifies a given resource across languages. */ class KoID { public: KoID() : m_id() , m_name() {} /** * Construct a KoID with the given id, and name, id is the untranslated * official name of the id, name should be translatable as it will be used * in the UI. * * @code * KoID("id", i18n("name")) * @endcode */ explicit KoID(const QString &id, const QString &name = QString()) : m_id(id) , m_name(name) {} /** * Use this constructore for static KoID. as KoID("id", ki18n("name")); * the name will be translated the first time it is needed. This is * important because static objects are constructed before translations * are initialized. */ explicit KoID(const QString &id, const KLocalizedString &name) : m_id(id) , m_localizedString(name) {} KoID(const KoID &rhs) { m_id = rhs.m_id; m_name = rhs.name(); } QString id() const { return m_id; } QString name() const { if (m_name.isEmpty() && !m_localizedString.isEmpty()) { m_name = m_localizedString.toString(); } return m_name; } friend inline bool operator==(const KoID &, const KoID &); friend inline bool operator!=(const KoID &, const KoID &); friend inline bool operator<(const KoID &, const KoID &); friend inline bool operator>(const KoID &, const KoID &); + static bool compareNames(const KoID &id1, const KoID &id2) + { + return id1.name() < id2.name(); + } + + + private: QString m_id; mutable QString m_name; KLocalizedString m_localizedString; }; Q_DECLARE_METATYPE(KoID) inline bool operator==(const KoID &v1, const KoID &v2) { return v1.m_id == v2.m_id; } inline bool operator!=(const KoID &v1, const KoID &v2) { return v1.m_id != v2.m_id; } inline bool operator<(const KoID &v1, const KoID &v2) { return v1.m_id < v2.m_id; } inline bool operator>(const KoID &v1, const KoID &v2) { return v1.m_id > v2.m_id; } inline QDebug operator<<(QDebug dbg, const KoID &id) { dbg.nospace() << id.name() << " (" << id.id() << " )"; return dbg.space(); } #endif diff --git a/krita/krita.action b/krita/krita.action index c7c18ae938..25530ef5a1 100644 --- a/krita/krita.action +++ b/krita/krita.action @@ -1,2961 +1,2973 @@ General Open Resources Folder Opens a file browser at the location Krita saves resources such as brushes to. Opens a file browser at the location Krita saves resources such as brushes to. Open Resources Folder 0 0 false Cleanup removed files... Cleanup removed files Cleanup removed files 0 0 false C&ascade Cascade Cascade 10 0 false &Tile Tile Tile 10 0 false Import Resources or Bundles... Import Resources or Bundles Import Resources or Bundles 0 0 false Create Resource Bundle... Create Resource Bundle Create Resource Bundle 0 0 false Show File Toolbar Show File Toolbar Show File Toolbar false Show color selector Show color selector Show color selector Shift+I false Show MyPaint shade selector Show MyPaint shade selector Show MyPaint shade selector Shift+M false Show minimal shade selector Show minimal shade selector Show minimal shade selector Shift+N false Show color history Show color history Show color history H false Show common colors Show common colors Show common colors U false Show Tool Options Show Tool Options Show Tool Options \ false Show Brush Editor Show Brush Editor Show Brush Editor F5 false Show Brush Presets Show Brush Presets Show Brush Presets F6 false Toggle Tablet Debugger Toggle Tablet Debugger Toggle Tablet Debugger 0 0 Ctrl+Shift+T false Rename Composition... Rename Composition Rename Composition 0 0 false Painting Make brush color lighter Make brush color lighter Make brush color lighter 0 0 L false Make brush color darker Make brush color darker Make brush color darker 0 0 K false Make brush color more saturated Make brush color more saturated Make brush color more saturated false Make brush color more desaturated Make brush color more desaturated Make brush color more desaturated false Shift brush color hue clockwise Shift brush color hue clockwise Shift brush color hue clockwise false Shift brush color hue counter-clockwise Shift brush color hue counter-clockwise Shift brush color hue counter-clockwise false Make brush color more red Make brush color more red Make brush color more red false Make brush color more green Make brush color more green Make brush color more green false Make brush color more blue Make brush color more blue Make brush color more blue false Make brush color more yellow Make brush color more yellow Make brush color more yellow false Increase opacity Increase opacity Increase opacity 0 0 O false Decrease opacity Decrease opacity Decrease opacity 0 0 I false draw-eraser Set eraser mode Set eraser mode Set eraser mode 10000 0 E true view-refresh Reload Original Preset Reload Original Preset Reload Original Preset 10000 false transparency-unlocked Preserve Alpha Preserve Alpha Preserve Alpha 10000 true transform_icons_penPressure Use Pen Pressure Use Pen Pressure Use Pen Pressure 10000 true symmetry-horizontal Horizontal Mirror Tool Horizontal Mirror Tool Horizontal Mirror Tool 10000 true symmetry-vertical Vertical Mirror Tool Vertical Mirror Tool Vertical Mirror Tool 10000 true Paste at cursor Paste at cursor Paste at cursor 0 0 false &Invert Selection Invert current selection Invert Selection 10000000000 100 Ctrl+Shift+I false Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) 10000 1 Ctrl+Shift+Backspace false Fill with Background Color (Opacity) Fill with Background Color (Opacity) Fill with Background Color (Opacity) 10000 1 Ctrl+Backspace false Fill with Pattern (Opacity) Fill with Pattern (Opacity) Fill with Pattern (Opacity) 10000 1 false &Toggle Selection Display Mode Toggle Selection Display Mode Toggle Selection Display Mode 0 0 false Next Favourite Preset Next Favourite Preset Next Favourite Preset , false Previous Favourite Preset Previous Favourite Preset Previous Favourite Preset . false Switch to Previous Preset Switch to Previous Preset Switch to Previous Preset / false Hide Brushes and Stuff Toolbar Hide Brushes and Stuff Toolbar Hide Brushes and Stuff Toolbar true zoom-in Zoom &In Zoom In Zoom In Ctrl++; Ctrl+= false zoom-out Zoom &Out Zoom Out Zoom Out Ctrl+- false Reset Foreground and Background Color Reset Foreground and Background Color Reset Foreground and Background Color D false Swap Foreground and Background Color Swap Foreground and Background Color Swap Foreground and Background Color X false Brush Smoothing: Weighted Brush Smoothing: Weighted Brush Smoothing: Weighted false Brush Smoothing: Disabled Brush Smoothing: Disabled Brush Smoothing: Disabled false Brush Smoothing: Stabilizer Brush Smoothing: Stabilizer Brush Smoothing: Stabilizer false Decrease Brush Size Decrease Brush Size Decrease Brush Size 0 0 [ false Brush Smoothing: Basic Brush Smoothing: Basic Brush Smoothing: Basic false Increase Brush Size Increase Brush Size Increase Brush Size 0 0 ] false Toggle Assistant Toggle Assistant ToggleAssistant Ctrl+Shift+L true Undo Polygon Selection Points Undo Polygon Selection Points Undo Polygon Selection Points Shift+Z false Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) 10000 1 Ctrl+Shift+Backspace false Fill with Background Color (Opacity) Fill with Background Color (Opacity) Fill with Background Color (Opacity) 10000 1 Ctrl+Backspace false Fill with Pattern (Opacity) Fill with Pattern (Opacity) Fill with Pattern (Opacity) 10000 1 false Convert &to Shape Convert to Shape Convert to Shape 10000000000 0 false &Select Opaque Select Opaque Select Opaque 100000 100 false &Show Global Selection Mask Shows global selection as a usual selection mask in <interface>Layers</interface> docker Show Global Selection Mask 0 0 true Filters &Color to Alpha... Color to Alpha Color to Alpha 10000 0 false &Top Edge Detection Top Edge Detection Top Edge Detection 10000 0 false &Index Colors... Index Colors Index Colors 10000 0 false Emboss Horizontal &Only Emboss Horizontal Only Emboss Horizontal Only 10000 0 false D&odge Dodge Dodge 10000 0 false &Sharpen Sharpen Sharpen 10000 0 false B&urn Burn Burn 10000 0 false &Mean Removal Mean Removal Mean Removal 10000 0 false &Gaussian Blur... Gaussian Blur Gaussian Blur 10000 0 false Emboss &in All Directions Emboss in All Directions Emboss in All Directions 10000 0 false &Small Tiles... Small Tiles Small Tiles 10000 0 false &Levels... Levels Levels 10000 0 Ctrl+L false &Sobel... Sobel Sobel 10000 0 false &Wave... Wave Wave 10000 0 false &Motion Blur... Motion Blur Motion Blur 10000 0 false &Color Adjustment curves... Color Adjustment curves Color Adjustment curves 10000 0 Ctrl+M false Pi&xelize... Pixelize Pixelize 10000 0 false Emboss (&Laplacian) Emboss (Laplacian) Emboss (Laplacian) 10000 0 false &Left Edge Detection Left Edge Detection Left Edge Detection 10000 0 false &Blur... Blur Blur 10000 0 false &Raindrops... Raindrops Raindrops 10000 0 false &Bottom Edge Detection Bottom Edge Detection Bottom Edge Detection 10000 0 false &Random Noise... Random Noise Random Noise 10000 0 false &Brightness/Contrast curve... Brightness/Contrast curve Brightness/Contrast curve 10000 0 false Colo&r Balance.. Color Balance.. Color Balance.. 10000 0 Ctrl+B false &PhongBumpmap... PhongBumpmap PhongBumpmap 10000 0 false &Desaturate Desaturate Desaturate 10000 0 Ctrl+Shift+U false Color &Transfer... Color Transfer Color Transfer 10000 0 false Emboss &Vertical Only Emboss Vertical Only Emboss Vertical Only 10000 0 false &Lens Blur... Lens Blur Lens Blur 10000 0 false M&inimize Channel Minimize Channel Minimize Channel 10000 0 false M&aximize Channel Maximize Channel Maximize Channel 10000 0 false &Oilpaint... Oilpaint Oilpaint 10000 0 false &Right Edge Detection Right Edge Detection Right Edge Detection 10000 0 false &Auto Contrast Auto Contrast Auto Contrast 10000 0 false &Round Corners... Round Corners Round Corners 10000 0 false &Unsharp Mask... Unsharp Mask Unsharp Mask 10000 0 false &Emboss with Variable Depth... Emboss with Variable Depth Emboss with Variable Depth 10000 0 false Emboss &Horizontal && Vertical Emboss Horizontal & Vertical Emboss Horizontal & Vertical 10000 0 false Random &Pick... Random Pick Random Pick 10000 0 false &Gaussian Noise Reduction... Gaussian Noise Reduction Gaussian Noise Reduction 10000 0 false &Posterize... Posterize Posterize 10000 0 false &Wavelet Noise Reducer... Wavelet Noise Reducer Wavelet Noise Reducer 10000 0 false &HSV Adjustment... HSV Adjustment HSV Adjustment 10000 0 Ctrl+U false Tool Shortcuts Dynamic Brush Tool Dynamic Brush Tool Dynamic Brush Tool false Crop Tool Crop the image to an area Crop the image to an area C false Polygon Tool Polygon Tool. Shift-mouseclick ends the polygon. Polygon Tool. Shift-mouseclick ends the polygon. false References References References false Rectangle Tool Rectangle Tool Rectangle Tool false Multibrush Tool Multibrush Tool Multibrush Tool Q false Shape Manipulation Tool Shape Manipulation Tool Shape Manipulation Tool false Color Picker Select a color from the image or current layer Select a color from the image or current layer P false Text Editing Tool Text editing Text editing false Outline Selection Tool Outline Selection Tool Outline Selection Tool false Artistic Text Tool Artistic text editing Artistic text editing false Bezier Curve Selection Tool Select a Bezier Curve Selection Tool false Similar Color Selection Tool Select a Similar Color Selection Tool false Fill Tool Fill a contiguous area of color with a color, or fill a selection. Fill a contiguous area of color with a color, or fill a selection. F false Line Tool Line Tool Line Tool false Freehand Path Tool Freehand Path Tool Freehand Path Tool false Bezier Curve Tool Bezier Curve Tool. Shift-mouseclick ends the curve. Bezier Curve Tool. Shift-mouseclick ends the curve. false Ellipse Tool Ellipse Tool Ellipse Tool false Freehand Brush Tool Freehand Brush Tool Freehand Brush Tool B false Create object Create object Create object false Elliptical Selection Tool Elliptical Selection Tool Elliptical Selection Tool J false Contiguous Selection Tool Contiguous Selection Tool Contiguous Selection Tool false Pattern editing Pattern editing Pattern editing false Review Review Review false Draw a gradient. Draw a gradient. Draw a gradient. G false Polygonal Selection Tool Polygonal Selection Tool Polygonal Selection Tool false Measurement Tool Measure the distance between two points Measure the distance between two points false Rectangular Selection Tool Rectangular Selection Tool Rectangular Selection Tool Ctrl+R false Move Tool Move a layer Move a layer T false Vector Image Tool Vector Image (EMF/WMF/SVM/SVG) tool Vector Image (EMF/WMF/SVM/SVG) tool false Calligraphy Calligraphy Calligraphy false Path editing Path editing Path editing false Polyline Tool Polyline Tool. Shift-mouseclick ends the polyline. Polyline Tool. Shift-mouseclick ends the polyline. false Transform Tool Transform a layer or a selection Transform a layer or a selection Ctrl+T false Ruler assistant editor tool Ruler assistant editor tool Ruler assistant editor tool false Text tool Text tool Text tool false Gradient Editing Tool Gradient editing Gradient editing false Brush Selection Tool Brush Selection Tool Brush Selection Tool false Blending Modes Next Blending Mode Next Blending Mode Next Blending Mode Alt+Shift++ false Previous Blending Mode Previous Blending Mode Previous Blending Mode Alt+Shift+- false Select Normal Blending Mode Select Normal Blending Mode Select Normal Blending Mode 0 0 Alt+Shift+N false Select Dissolve Blending Mode Select Dissolve Blending Mode Select Dissolve Blending Mode 0 0 Alt+Shift+I false Select Behind Blending Mode Select Behind Blending Mode Select Behind Blending Mode 0 0 Alt+Shift+Q false Select Clear Blending Mode Select Clear Blending Mode Select Clear Blending Mode 0 0 Alt+Shift+R false Select Darken Blending Mode Select Darken Blending Mode Select Darken Blending Mode 0 0 Alt+Shift+K false Select Multiply Blending Mode Select Multiply Blending Mode Select Multiply Blending Mode 0 0 Alt+Shift+M false Select Color Burn Blending Mode Select Color Burn Blending Mode Select Color Burn Blending Mode 0 0 Alt+Shift+B false Select Linear Burn Blending Mode Select Linear Burn Blending Mode Select Linear Burn Blending Mode 0 0 Alt+Shift+A false Select Lighten Blending Mode Select Lighten Blending Mode Select Lighten Blending Mode 0 0 Alt+Shift+G false Select Screen Blending Mode Select Screen Blending Mode Select Screen Blending Mode 0 0 Alt+Shift+S false Select Color Dodge Blending Mode Select Color Dodge Blending Mode Select Color Dodge Blending Mode 0 0 Alt+Shift+D false Select Linear Dodge Blending Mode Select Linear Dodge Blending Mode Select Linear Dodge Blending Mode 0 0 Alt+Shift+W false Select Overlay Blending Mode Select Overlay Blending Mode Select Overlay Blending Mode 0 0 Alt+Shift+O false Select Soft Light Blending Mode Select Soft Light Blending Mode Select Soft Light Blending Mode 0 0 Alt+Shift+F false Select Hard Light Blending Mode Select Hard Light Blending Mode Select Hard Light Blending Mode 0 0 Alt+Shift+H false Select Vivid Light Blending Mode Select Vivid Light Blending Mode Select Vivid Light Blending Mode 0 0 Alt+Shift+V false Select Linear Light Blending Mode Select Linear Light Blending Mode Select Linear Light Blending Mode 0 0 Alt+Shift+J false Select Pin Light Blending Mode Select Pin Light Blending Mode Select Pin Light Blending Mode 0 0 Alt+Shift+Z false Select Hard Mix Blending Mode Select Hard Mix Blending Mode Select Hard Mix Blending Mode 0 0 Alt+Shift+L false Select Difference Blending Mode Select Difference Blending Mode Select Difference Blending Mode 0 0 Alt+Shift+E false Select Exclusion Blending Mode Select Exclusion Blending Mode Select Exclusion Blending Mode 0 0 Alt+Shift+X false Select Hue Blending Mode Select Hue Blending Mode Select Hue Blending Mode 0 0 Alt+Shift+U false Select Saturation Blending Mode Select Saturation Blending Mode Select Saturation Blending Mode 0 0 Alt+Shift+T false Select Color Blending Mode Select Color Blending Mode Select Color Blending Mode 0 0 Alt+Shift+C false Select Luminosity Blending Mode Select Luminosity Blending Mode Select Luminosity Blending Mode 0 0 Alt+Shift+Y false Animation Previous frame Move to previous frame Move to previous frame 1 0 false Next frame Move to next frame Move to next frame 1 0 false Play / pause animation Play / pause animation Play / pause animation 1 0 false Add blank frame Add blank frame Add blank frame 100000 0 false Copy Frame Add duplicate frame Add duplicate frame 100000 0 false Toggle onion skin Toggle onion skin Toggle onion skin 100000 0 false Previous Keyframe false Next Keyframe false First Frame false Last Frame false Auto Frame Mode true true Add blank frame Add blank frame Add blank frame 100000 0 false Show in Timeline true Layers Activate next layer Activate next layer Activate next layer 100000 0 PgUp false Activate previous layer Activate previous layer Activate previous layer 100000 0 PgDown false groupLayer &Group Layer Group Layer Group Layer 1000 0 false cloneLayer &Clone Layer Clone Layer Clone Layer 1000 0 false vectorLayer &Vector Layer Vector Layer Vector Layer 1000 0 false filterLayer &Filter Layer... Filter Layer Filter Layer 1000 0 false fillLayer &Fill Layer... Fill Layer Fill Layer 1000 0 false fileLayer &File Layer... File Layer File Layer 1000 0 false transparencyMask &Transparency Mask Transparency Mask Transparency Mask 100000 0 false filterMask &Filter Mask... Filter Mask Filter Mask 100000 0 false filterMask &Colorize Mask Colorize Mask Colorize Mask 100000 0 false transformMask &Transform Mask... Transform Mask Transform Mask 100000 0 false selectionMask &Local Selection Local Selection Local Selection 100000 0 false view-filter &Isolate Layer Isolate Layer Isolate Layer 1000 0 true paintLayer &Paint Layer Paint Layer Paint Layer 1000 0 Insert false + + + &New Layer From Visible + + New layer from visible + New layer from visible + 1000 + 0 + + false + + duplicatelayer &Duplicate Layer or Mask Duplicate Layer or Mask Duplicate Layer or Mask 1000 0 Ctrl+J false &Cut Selection to New Layer Cut Selection to New Layer Cut Selection to New Layer 100000000 1 Ctrl+Shift+J false Copy &Selection to New Layer Copy Selection to New Layer Copy Selection to New Layer 100000000 0 Ctrl+Alt+J false Copy Layer Copy layer to clipboard Copy layer to clipboard 0 0 false Cut Layer Cut layer to clipboard Cut layer to clipboard 0 0 false Paste Layer Paste layer from clipboard Paste layer from clipboard 100000000000000 0 false Quick Group Create a group layer containing selected layers Quick Group 0 0 Ctrl+G false Quick Ungroup Remove grouping of the layers or remove one layer out of the group Quick Ungroup 0 0 Ctrl+Alt+G false Quick Clipping Group Group selected layers and add a layer with clipped alpha channel Quick Clipping Group 0 0 Ctrl+Shift+G false All Layers Select all layers Select all layers 0 0 false Visible Layers Select all visible layers Select all visible layers 0 0 false Locked Layers Select all locked layers Select all locked layers 0 0 false Invisible Layers Select all invisible layers Select all invisible layers 0 0 false Unlocked Layers Select all unlocked layers Select all unlocked layers 0 0 false document-save &Save Layer/Mask... Save Layer/Mask Save Layer/Mask 1000 0 false document-save Save &Group Layers... Save Group Layers Save Group Layers 100000 0 false Convert group to &animated layer Convert child layers into animation frames Convert child layers into animation frames 100000 0 false I&mport Layer... Import Layer Import Layer 100000 0 false paintLayer &as Paint Layer... as Paint Layer as Paint Layer 1000 0 false transparencyMask as &Transparency Mask... as Transparency Mask as Transparency Mask 1000 0 false filterMask as &Filter Mask... as Filter Mask as Filter Mask 1000 0 false selectionMask as &Selection Mask... as Selection Mask as Selection Mask 1000 0 false paintLayer to &Paint Layer to Paint Layer to Paint Layer 1000 0 false transparencyMask to &Transparency Mask to Transparency Mask to Transparency Mask 1000 0 false filterMask to &Filter Mask... to Filter Mask to Filter Mask 1000 0 false selectionMask to &Selection Mask to Selection Mask to Selection Mask 1000 0 false transparencyMask &Alpha into Mask Alpha into Mask Alpha into Mask 100000 10 false transparency-enabled &Write as Alpha Write as Alpha Write as Alpha 1000000 1 false document-save &Save Merged... Save Merged Save Merged 1000000 0 false Split Layer... Split Layer Split Layer 1000 0 false Wavelet Decompose ... Wavelet Decompose Wavelet Decompose 1000 1 false symmetry-horizontal Mirror Layer Hori&zontally Mirror Layer Horizontally Mirror Layer Horizontally 1000 1 false symmetry-vertical Mirror Layer &Vertically Mirror Layer Vertically Mirror Layer Vertically 1000 1 false &Rotate Layer... Rotate Layer Rotate Layer 100000 1 false object-rotate-right Rotate &Layer 90° to the Right Rotate Layer 90° to the Right Rotate Layer 90° to the Right 100000 1 false object-rotate-left Rotate Layer &90° to the Left Rotate Layer 90° to the Left Rotate Layer 90° to the Left 100000 1 false Rotate Layer &180° Rotate Layer 180° Rotate Layer 180° 100000 1 false Scale &Layer to new Size... Scale Layer to new Size Scale Layer to new Size 100000 1 false &Shear Layer... Shear Layer Shear Layer 100000 1 false &Offset Layer... Offset Layer Offset Layer 100000 1 false Clones &Array... Clones Array Clones Array 100000 0 false &Edit metadata... Edit metadata Edit metadata 100000 1 false &Histogram... Histogram Histogram 100000 0 false &Convert Layer Color Space... Convert Layer Color Space Convert Layer Color Space 100000 1 false &Merge with Layer Below Merge with Layer Below Merge with Layer Below 100000 0 Ctrl+E false &Flatten Layer Flatten Layer Flatten Layer 100000 0 false Ras&terize Layer Rasterize Layer Rasterize Layer 10000000 1 false Flatten ima&ge Flatten image Flatten image 100000 0 Ctrl+Shift+E false &Merge Selected Layers Merge Selected Layers Merge Selected Layers Ctrl+Alt+E false La&yer Style... Layer Style Layer Style 100000 1 false Move into previous group Move into previous group Move into previous group 0 0 false Move into next group Move into next group Move into next group 0 0 false Rename current layer Rename current layer Rename current layer 100000 0 F2 false deletelayer &Remove Layer Remove Layer Remove Layer 1000 1 Shift+Delete false arrowupblr Move Layer or Mask Up Move Layer or Mask Up Ctrl+PgUp false arrowdown Move Layer or Mask Down Move Layer or Mask Down Ctrl+PgDown false properties &Properties... Properties Properties 1000 1 F3 false diff --git a/krita/krita.xmlgui b/krita/krita.xmlgui index 32bea129e5..17fd61e013 100644 --- a/krita/krita.xmlgui +++ b/krita/krita.xmlgui @@ -1,369 +1,374 @@ - + &File + + - + + &Edit + &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 Recording Macros Setti&ngs &Help File Brushes and Stuff diff --git a/krita/kritamenu.action b/krita/kritamenu.action index 72722dea67..1e2b17b9d6 100644 --- a/krita/kritamenu.action +++ b/krita/kritamenu.action @@ -1,1694 +1,1718 @@ File document-new &New Create new document New 0 0 Ctrl+N false document-open &Open... Open an existing document Open 0 0 Ctrl+O false document-open-recent Open &Recent Open a document which was recently opened Open Recent 1 0 false document-save &Save Save Save 1 0 Ctrl+S false document-save-as Save &As... Save document under a new name Save As 1 0 Ctrl+Shift+S false Reload Reload Reload 1 0 false document-import Open ex&isting Document as Untitled Document... Open existing Document as Untitled Document Open existing Document as Untitled Document 0 0 false document-export E&xport... Export Export 1 0 false application-pdf &Export as PDF... Export as PDF Export as PDF 1 0 false Import animation frames... Import animation frames Import animation frames 1 0 false - + - Expor&t animation... + &Render Animation... - Export animation - Export animation - 1 + Render Animation to GIF, Image Sequence or Video + Render Animation + 1000 0 false + + + &Render Image Sequence Again + + Render Animation to Image Sequence Again + Render Animation + 1000 + 0 + + false + + Save Incremental &Version Save Incremental Version Save Incremental Version 1 0 Ctrl+Alt+S false Save Incremental &Backup Save Incremental Backup Save Incremental Backup 1 0 F4 false &Create Template From Image... Create Template From Image Create Template From Image 1 0 false Create Copy &From Current Image Create Copy From Current Image Create Copy From Current Image 1 0 false document-print &Print... Print document Print 1 0 Ctrl+P false document-print-preview Print Previe&w Show a print preview of document Print Preview 1 0 false configure &Document Information Document Information Document Information 1 0 false &Close All Close All Close All 1 0 Ctrl+Shift+W false C&lose Close Close 1 0 false &Quit Quit application Quit 0 0 Ctrl+Q false Edit edit-undo Undo Undo last action Undo 1 0 Ctrl+Z false _edit-redo Redo Redo last undone action Redo 1 0 Ctrl+Shift+Z false edit-cut Cu&t Cut selection to clipboard Cut 0 0 Ctrl+X false edit-copy &Copy Copy selection to clipboard Copy 0 0 Ctrl+C false C&opy (sharp) Copy (sharp) Copy (sharp) 100000000 0 false Cut (&sharp) Cut (sharp) Cut (sharp) 100000000 0 false Copy &merged Copy merged Copy merged 100000000 0 Ctrl+Shift+C false edit-paste &Paste Paste clipboard content Paste 0 0 Ctrl+V false Paste into &New Image Paste into New Image Paste into New Image 0 0 Ctrl+Shift+N false edit-clear C&lear Clear Clear 1 0 Del false &Fill with Foreground Color Fill with Foreground Color Fill with Foreground Color 10000 1 Shift+Backspace false Fill &with Background Color Fill with Background Color Fill with Background Color 10000 1 Backspace false F&ill with Pattern Fill with Pattern Fill with Pattern 10000 1 false Stro&ke selected shapes Stroke selected shapes Stroke selected shapes 1000000000 0 false + + + Stroke selec&tion + + Stroke selection + Stroke selection + 10000000000 + 0 + + false + + Delete keyframe Delete keyframe Delete keyframe 100000 0 false Window window-new &New Window New Window New Window 0 0 false N&ext Next Next 10 0 false Previous Previous Previous false View &Show Canvas Only Show just the canvas or the whole window Show Canvas Only 0 0 Tab true view-fullscreen F&ull Screen Mode Display the window in full screen Full Screen Mode 0 0 Ctrl+Shift+F false &Wrap Around Mode Wrap Around Mode Wrap Around Mode 1 0 W true &Instant Preview Mode Instant Preview Mode Instant Preview Mode 1 0 Shift+L true Soft Proofing Turns on Soft Proofing Turns on Soft Proofing Ctrl+Y true Out of Gamut Warnings Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on. Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on. Ctrl+Shift+Y true Mirror View Mirror View Mirror View M false &Reset zoom Reset zoom Reset zoom 1 0 Ctrl+0 false Zoom &In Zoom In Zoom In 0 0 Ctrl++ false Zoom &Out Zoom Out Zoom Out 0 0 Ctrl+- false Rotate &Canvas Right Rotate Canvas Right Rotate Canvas Right 1 0 Ctrl+] false Rotate Canvas &Left Rotate Canvas Left Rotate Canvas Left 1 0 Ctrl+[ false Reset Canvas Rotation Reset Canvas Rotation Reset Canvas Rotation 1 0 false Show &Rulers The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p> Show Rulers Show Rulers 1 0 true Rulers Track Pointer The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown Rulers Track Pointer Rulers Track Pointer 1 0 true Show Guides Show or hide guides Show Guides 1 0 true Lock Guides Lock or unlock guides Lock Guides 1 0 true Snap to Guides Snap cursor to guides position Snap to Guides 1 0 true Show Status &Bar Show or hide the status bar Show Status Bar 0 0 true view-grid Show &Grid Show Grid Show Grid 1000 0 Ctrl+Shift+' true Snap To Grid Snap To Grid Snap To Grid 1000 Ctrl+Shift+; true Show Snap Options Popup Show Snap Options Popup Show Snap Options Popup 1000 Shift+s false Snap Orthogonal Snap Orthogonal Snap Orthogonal 1000 true Snap Node Snap Node Snap Node 1000 true Snap Extension Snap Extension Snap Extension 1000 true Snap Intersection Snap Intersection Snap Intersection 1000 true Snap Bounding Box Snap Bounding Box Snap Bounding Box 1000 true Snap Image Bounds Snap Image Bounds Snap Image Bounds 1000 true Snap Image Center Snap Image Center Snap Image Center 1000 true S&how Painting Assistants Show Painting Assistants Show Painting Assistants 1000 0 true Show &Assistant Previews Show Assistant Previews Show Assistant Previews 1000 0 true Image document-properties &Properties... Properties Properties 1000 0 false format-stroke-color &Image Background Color and Transparency... Change the background color of the image Image Background Color and Transparency 1000 0 false &Convert Image Color Space... Convert Image Color Space Convert Image Color Space 1000 0 false trim-to-image &Trim to Image Size Trim to Image Size Trim to Image Size 1 0 false Trim to Current &Layer Trim to Current Layer Trim to Current Layer 100000 0 false Trim to S&election Trim to Selection Trim to Selection 100000000 0 false &Rotate Image... Rotate Image Rotate Image 1000 0 false object-rotate-right Rotate &Image 90° to the Right Rotate Image 90° to the Right Rotate Image 90° to the Right 1000 0 false object-rotate-left Rotate Image &90° to the Left Rotate Image 90° to the Left Rotate Image 90° to the Left 1000 0 false Rotate Image &180° Rotate Image 180° Rotate Image 180° 1000 0 false &Shear Image... Shear Image Shear Image 1000 0 false symmetry-horizontal &Mirror Image Horizontally Mirror Image Horizontally Mirror Image Horizontally 1000 0 false symmetry-vertical Mirror Image &Vertically Mirror Image Vertically Mirror Image Vertically 1000 0 false Scale Image To &New Size... Scale Image To New Size Scale Image To New Size 1000 0 Ctrl+Alt+I false &Offset Image... Offset Image Offset Image 1000 0 false R&esize Canvas... Resize Canvas Resize Canvas 1000 0 Ctrl+Alt+C false Im&age Split Image Split Image Split 1000 0 false Separate Ima&ge... Separate Image Separate Image 1000 0 false Select edit-select-all Select &All Select All Select All 0 0 Ctrl+A false edit-select-all &Deselect Deselect Deselect 1100000000 0 Ctrl+Shift+A false &Reselect Reselect Reselect 0 0 Ctrl+Shift+D false &Invert Invert Invert 10000 0 Ctrl+I false &Convert to Vector Selection Convert to Vector Selection Convert to Vector Selection 10000000000 0 false Convert Shapes to &Vector Selection Convert Shapes to Vector Selection Convert Shapes to Vector Selection 1000000000 0 false &Feather Selection... Feather Selection Feather Selection 10000000000 100 Shift+F6 false Dis&play Selection Display Selection Display Selection 1000 0 Ctrl+H true Sca&le... Scale Scale 100000000 100 false S&elect from Color Range... Select from Color Range Select from Color Range 10000 100 false Select &Opaque Select Opaque Select Opaque 10000 100 false &Grow Selection... Grow Selection Grow Selection 10000000000 100 false S&hrink Selection... Shrink Selection Shrink Selection 10000000000 100 false &Border Selection... Border Selection Border Selection 10000000000 100 false S&mooth Smooth Smooth 10000000000 100 false Filter &Apply Filter Again Apply Filter Again Apply Filter Again 0 0 Ctrl+F false Adjust Adjust Adjust false Artistic Artistic Artistic false Blur Blur Blur false Colors Colors Colors false Edge Detection Edge Detection Edge Detection false Enhance Enhance Enhance false Emboss Emboss Emboss false Map Map Map false Other Other Other false G'MIC Apply G'Mic Action Apply G'Mic Action false Tools media-record &Start recording macro Start recording macro Start recording macro 1000 0 false media-playback-stop Stop &recording actions Stop recording actions Stop recording actions 1000 0 false media-playback-start &Open and play... Open and play Open and play 0 0 false document-edit Open &and edit... Open and edit Open and edit 0 0 false Settings configure &Configure Krita... Configure Krita Configure Krita 0 0 false &Manage Resources... Manage Resources Manage Resources 0 0 false preferences-desktop-locale Switch Application &Language... Switch Application Language Switch Application Language false &Show Dockers Show Dockers Show Dockers 0 0 true Sho&w Docker Titlebars Show Docker Titlebars Show Docker Titlebars 0 0 true configure Configure Tool&bars... Configure Toolbars Configure Toolbars 0 0 false Dockers Dockers Dockers false &Themes Themes Themes false im-user Active Author Profile Active Author Profile Active Author Profile configure-shortcuts Configure S&hortcuts... Configure Shortcuts Configure Shortcuts 0 0 false &Window Window Window false Help help-contents Krita &Handbook Krita Handbook Krita Handbook F1 false tools-report-bug &Report Bug... Report Bug Report Bug false calligrakrita &About Krita About Krita About Krita false kde About &KDE About KDE About KDE false Brushes and Stuff &Gradients Gradients Gradients false &Patterns Patterns Patterns false &Color Color Color false &Painter's Tools Painter's Tools Painter's Tools false Brush composite Brush composite Brush composite false Brush option slider 1 Brush option slider 1 Brush option slider 1 false Brush option slider 2 Brush option slider 2 Brush option slider 2 false Brush option slider 3 Brush option slider 3 Brush option slider 3 false Mirror Mirror Mirror false Workspaces Workspaces Workspaces false diff --git a/libs/flake/KoPatternBackground.cpp b/libs/flake/KoPatternBackground.cpp index a2289b7a31..9f0a17023c 100644 --- a/libs/flake/KoPatternBackground.cpp +++ b/libs/flake/KoPatternBackground.cpp @@ -1,486 +1,495 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoPatternBackground.h" #include "KoShapeBackground_p.h" #include "KoShapeSavingContext.h" #include "KoImageData.h" #include "KoImageCollection.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#include class KoPatternBackgroundPrivate : public KoShapeBackgroundPrivate { public: KoPatternBackgroundPrivate() : repeat(KoPatternBackground::Tiled) , refPoint(KoPatternBackground::TopLeft) , imageCollection(0) , imageData(0) { } ~KoPatternBackgroundPrivate() { delete imageData; } QSizeF targetSize() const { QSizeF size = imageData->imageSize(); if (targetImageSizePercent.width() > 0.0) size.setWidth(0.01 * targetImageSizePercent.width() * size.width()); else if (targetImageSize.width() > 0.0) size.setWidth(targetImageSize.width()); if (targetImageSizePercent.height() > 0.0) size.setHeight(0.01 * targetImageSizePercent.height() * size.height()); else if (targetImageSize.height() > 0.0) size.setHeight(targetImageSize.height()); return size; } QPointF offsetFromRect(const QRectF &fillRect, const QSizeF &imageSize) const { QPointF offset; switch (refPoint) { case KoPatternBackground::TopLeft: offset = fillRect.topLeft(); break; case KoPatternBackground::Top: offset.setX(fillRect.center().x() - 0.5 * imageSize.width()); offset.setY(fillRect.top()); break; case KoPatternBackground::TopRight: offset.setX(fillRect.right() - imageSize.width()); offset.setY(fillRect.top()); break; case KoPatternBackground::Left: offset.setX(fillRect.left()); offset.setY(fillRect.center().y() - 0.5 * imageSize.height()); break; case KoPatternBackground::Center: offset.setX(fillRect.center().x() - 0.5 * imageSize.width()); offset.setY(fillRect.center().y() - 0.5 * imageSize.height()); break; case KoPatternBackground::Right: offset.setX(fillRect.right() - imageSize.width()); offset.setY(fillRect.center().y() - 0.5 * imageSize.height()); break; case KoPatternBackground::BottomLeft: offset.setX(fillRect.left()); offset.setY(fillRect.bottom() - imageSize.height()); break; case KoPatternBackground::Bottom: offset.setX(fillRect.center().x() - 0.5 * imageSize.width()); offset.setY(fillRect.bottom() - imageSize.height()); break; case KoPatternBackground::BottomRight: offset.setX(fillRect.right() - imageSize.width()); offset.setY(fillRect.bottom() - imageSize.height()); break; default: break; } if (refPointOffsetPercent.x() > 0.0) offset += QPointF(0.01 * refPointOffsetPercent.x() * imageSize.width(), 0); if (refPointOffsetPercent.y() > 0.0) offset += QPointF(0, 0.01 * refPointOffsetPercent.y() * imageSize.height()); return offset; } QTransform matrix; KoPatternBackground::PatternRepeat repeat; KoPatternBackground::ReferencePoint refPoint; QSizeF targetImageSize; QSizeF targetImageSizePercent; QPointF refPointOffsetPercent; QPointF tileRepeatOffsetPercent; - KoImageCollection * imageCollection; + QPointer imageCollection; KoImageData * imageData; }; // ---------------------------------------------------------------- -KoPatternBackground::KoPatternBackground(KoImageCollection * imageCollection) +KoPatternBackground::KoPatternBackground(KoImageCollection *imageCollection) : KoShapeBackground(*(new KoPatternBackgroundPrivate())) { Q_D(KoPatternBackground); d->imageCollection = imageCollection; Q_ASSERT(d->imageCollection); } KoPatternBackground::~KoPatternBackground() { Q_D(KoPatternBackground); } void KoPatternBackground::setTransform(const QTransform &matrix) { Q_D(KoPatternBackground); d->matrix = matrix; } QTransform KoPatternBackground::transform() const { Q_D(const KoPatternBackground); return d->matrix; } void KoPatternBackground::setPattern(const QImage &pattern) { Q_D(KoPatternBackground); delete d->imageData; - d->imageData = d->imageCollection->createImageData(pattern); + if (d->imageCollection) { + d->imageData = d->imageCollection->createImageData(pattern); + } } void KoPatternBackground::setPattern(KoImageData *imageData) { Q_D(KoPatternBackground); delete d->imageData; d->imageData = imageData; } QImage KoPatternBackground::pattern() const { Q_D(const KoPatternBackground); if (d->imageData) return d->imageData->image(); return QImage(); } void KoPatternBackground::setRepeat(PatternRepeat repeat) { Q_D(KoPatternBackground); d->repeat = repeat; } KoPatternBackground::PatternRepeat KoPatternBackground::repeat() const { Q_D(const KoPatternBackground); return d->repeat; } KoPatternBackground::ReferencePoint KoPatternBackground::referencePoint() const { Q_D(const KoPatternBackground); return d->refPoint; } void KoPatternBackground::setReferencePoint(ReferencePoint referencePoint) { Q_D(KoPatternBackground); d->refPoint = referencePoint; } QPointF KoPatternBackground::referencePointOffset() const { Q_D(const KoPatternBackground); return d->refPointOffsetPercent; } void KoPatternBackground::setReferencePointOffset(const QPointF &offset) { Q_D(KoPatternBackground); qreal ox = qMax(qreal(0.0), qMin(qreal(100.0), offset.x())); qreal oy = qMax(qreal(0.0), qMin(qreal(100.0), offset.y())); d->refPointOffsetPercent = QPointF(ox, oy); } QPointF KoPatternBackground::tileRepeatOffset() const { Q_D(const KoPatternBackground); return d->tileRepeatOffsetPercent; } void KoPatternBackground::setTileRepeatOffset(const QPointF &offset) { Q_D(KoPatternBackground); d->tileRepeatOffsetPercent = offset; } QSizeF KoPatternBackground::patternDisplaySize() const { Q_D(const KoPatternBackground); return d->targetSize(); } void KoPatternBackground::setPatternDisplaySize(const QSizeF &size) { Q_D(KoPatternBackground); d->targetImageSizePercent = QSizeF(); d->targetImageSize = size; } QSizeF KoPatternBackground::patternOriginalSize() const { Q_D(const KoPatternBackground); return d->imageData->imageSize(); } void KoPatternBackground::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const { Q_D(const KoPatternBackground); if (! d->imageData) return; painter.save(); if (d->repeat == Tiled) { // calculate scaling of pixmap QSizeF targetSize = d->targetSize(); QSizeF imageSize = d->imageData->imageSize(); qreal scaleX = targetSize.width() / imageSize.width(); qreal scaleY = targetSize.height() / imageSize.height(); QRectF targetRect = fillPath.boundingRect(); // undo scaling on target rectangle targetRect.setWidth(targetRect.width() / scaleX); targetRect.setHeight(targetRect.height() / scaleY); // determine pattern offset QPointF offset = d->offsetFromRect(targetRect, imageSize); // create matrix for pixmap scaling QTransform matrix; matrix.scale(scaleX, scaleY); painter.setClipPath(fillPath); painter.setWorldTransform(matrix, true); painter.drawTiledPixmap(targetRect, d->imageData->pixmap(imageSize.toSize()), -offset); } else if (d->repeat == Original) { QRectF sourceRect(QPointF(0, 0), d->imageData->imageSize()); QRectF targetRect(QPoint(0, 0), d->targetSize()); targetRect.moveCenter(fillPath.boundingRect().center()); painter.setClipPath(fillPath); painter.drawPixmap(targetRect, d->imageData->pixmap(sourceRect.size().toSize()), sourceRect); } else if (d->repeat == Stretched) { painter.setClipPath(fillPath); // undo conversion of the scaling so that we can use a nicely scaled image of the correct size qreal zoomX, zoomY; converter.zoom(&zoomX, &zoomY); zoomX = zoomX ? 1 / zoomX : zoomX; zoomY = zoomY ? 1 / zoomY : zoomY; painter.scale(zoomX, zoomY); QRectF targetRect = converter.documentToView(fillPath.boundingRect()); painter.drawPixmap(targetRect.topLeft(), d->imageData->pixmap(targetRect.size().toSize())); } painter.restore(); } void KoPatternBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context) { Q_D(KoPatternBackground); if (! d->imageData) return; switch (d->repeat) { case Original: style.addProperty("style:repeat", "no-repeat"); break; case Tiled: style.addProperty("style:repeat", "repeat"); break; case Stretched: style.addProperty("style:repeat", "stretch"); break; } if (d->repeat == Tiled) { QString refPointId = "top-left"; switch (d->refPoint) { case TopLeft: refPointId = "top-left"; break; case Top: refPointId = "top"; break; case TopRight: refPointId = "top-right"; break; case Left: refPointId = "left"; break; case Center: refPointId = "center"; break; case Right: refPointId = "right"; break; case BottomLeft: refPointId = "bottom-left"; break; case Bottom: refPointId = "bottom"; break; case BottomRight: refPointId = "bottom-right"; break; } style.addProperty("draw:fill-image-ref-point", refPointId); if (d->refPointOffsetPercent.x() > 0.0) style.addProperty("draw:fill-image-ref-point-x", QString("%1%").arg(d->refPointOffsetPercent.x())); if (d->refPointOffsetPercent.y() > 0.0) style.addProperty("draw:fill-image-ref-point-y", QString("%1%").arg(d->refPointOffsetPercent.y())); } if (d->repeat != Stretched) { QSizeF targetSize = d->targetSize(); QSizeF imageSize = d->imageData->imageSize(); if (targetSize.height() != imageSize.height()) style.addPropertyPt("draw:fill-image-height", targetSize.height()); if (targetSize.width() != imageSize.width()) style.addPropertyPt("draw:fill-image-width", targetSize.width()); } KoGenStyle patternStyle(KoGenStyle::FillImageStyle /*no family name*/); patternStyle.addAttribute("xlink:show", "embed"); patternStyle.addAttribute("xlink:actuate", "onLoad"); patternStyle.addAttribute("xlink:type", "simple"); patternStyle.addAttribute("xlink:href", context.imageHref(d->imageData)); QString patternStyleName = context.mainStyles().insert(patternStyle, "picture"); style.addProperty("draw:fill", "bitmap"); style.addProperty("draw:fill-image-name", patternStyleName); - context.addDataCenter(d->imageCollection); + if (d->imageCollection) { + context.addDataCenter(d->imageCollection); + } } bool KoPatternBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &) { Q_D(KoPatternBackground); KoStyleStack &styleStack = context.styleStack(); if (! styleStack.hasProperty(KoXmlNS::draw, "fill")) return false; QString fillStyle = styleStack.property(KoXmlNS::draw, "fill"); if (fillStyle != "bitmap") return false; QString styleName = styleStack.property(KoXmlNS::draw, "fill-image-name"); KoXmlElement* e = context.stylesReader().drawStyles("fill-image")[styleName]; if (! e) return false; const QString href = e->attributeNS(KoXmlNS::xlink, "href", QString()); if (href.isEmpty()) return false; delete d->imageData; - d->imageData = d->imageCollection->createImageData(href, context.store()); - if (! d->imageData) + d->imageData = 0; + if (d->imageCollection) { + d->imageData = d->imageCollection->createImageData(href, context.store()); + } + if (! d->imageData) { return false; + } // read the pattern repeat style QString style = styleStack.property(KoXmlNS::style, "repeat"); if (style == "stretch") d->repeat = Stretched; else if (style == "no-repeat") d->repeat = Original; else d->repeat = Tiled; if (style != "stretch") { // optional attributes which can override original image size if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-height")) { QString height = styleStack.property(KoXmlNS::draw, "fill-image-height"); if (height.endsWith('%')) d->targetImageSizePercent.setHeight(height.remove('%').toDouble()); else d->targetImageSize.setHeight(KoUnit::parseValue(height)); } if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-width")) { QString width = styleStack.property(KoXmlNS::draw, "fill-image-width"); if (width.endsWith('%')) d->targetImageSizePercent.setWidth(width.remove('%').toDouble()); else d->targetImageSize.setWidth(KoUnit::parseValue(width)); } } if (style == "repeat") { if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point")) { // align pattern to the given size QString align = styleStack.property(KoXmlNS::draw, "fill-image-ref-point"); if (align == "top-left") d->refPoint = TopLeft; else if (align == "top") d->refPoint = Top; else if (align == "top-right") d->refPoint = TopRight; else if (align == "left") d->refPoint = Left; else if (align == "center") d->refPoint = Center; else if (align == "right") d->refPoint = Right; else if (align == "bottom-left") d->refPoint = BottomLeft; else if (align == "bottom") d->refPoint = Bottom; else if (align == "bottom-right") d->refPoint = BottomRight; } if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point-x")) { QString pointX = styleStack.property(KoXmlNS::draw, "fill-image-ref-point-x"); d->refPointOffsetPercent.setX(pointX.remove('%').toDouble()); } if (styleStack.hasProperty(KoXmlNS::draw, "fill-image-ref-point-y")) { QString pointY = styleStack.property(KoXmlNS::draw, "fill-image-ref-point-y"); d->refPointOffsetPercent.setY(pointY.remove('%').toDouble()); } if (styleStack.hasProperty(KoXmlNS::draw, "tile-repeat-offset")) { QString repeatOffset = styleStack.property(KoXmlNS::draw, "tile-repeat-offset"); QStringList tokens = repeatOffset.split('%'); if (tokens.count() == 2) { QString direction = tokens[1].simplified(); if (direction == "horizontal") d->tileRepeatOffsetPercent.setX(tokens[0].toDouble()); else if (direction == "vertical") d->tileRepeatOffsetPercent.setY(tokens[0].toDouble()); } } } return true; } QRectF KoPatternBackground::patternRectFromFillSize(const QSizeF &size) { Q_D(KoPatternBackground); QRectF rect; switch (d->repeat) { case Tiled: rect.setTopLeft(d->offsetFromRect(QRectF(QPointF(), size), d->targetSize())); rect.setSize(d->targetSize()); break; case Original: rect.setLeft(0.5 * (size.width() - d->targetSize().width())); rect.setTop(0.5 * (size.height() - d->targetSize().height())); rect.setSize(d->targetSize()); break; case Stretched: rect.setTopLeft(QPointF(0.0, 0.0)); rect.setSize(size); break; } return rect; } diff --git a/libs/flake/KoShapeRegistry.h b/libs/flake/KoShapeRegistry.h index 4bcb47bd53..8f20c80b4f 100644 --- a/libs/flake/KoShapeRegistry.h +++ b/libs/flake/KoShapeRegistry.h @@ -1,86 +1,86 @@ /* This file is part of the KDE project * Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) * Copyright (C) 2006, 2010 Thomas Zander * * 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 KOSHAPEREGISTRY_H #define KOSHAPEREGISTRY_H #include #include #include #include "kritaflake_export.h" class KoShape; class KoShapeLoadingContext; /** * This singleton class keeps a register of all available flake shapes, * or rather, of the factories that applications can use to create flake * shape objects. */ class KRITAFLAKE_EXPORT KoShapeRegistry : public KoGenericRegistry { public: KoShapeRegistry(); - ~KoShapeRegistry(); + virtual ~KoShapeRegistry(); /** * Return an instance of the KoShapeRegistry * Creates an instance if that has never happened before and returns the singleton instance. */ static KoShapeRegistry *instance(); /** * Add shape factory for a shape that is not a plugin * This can be used also if you want to have a shape only in one application * * @param factory The factory of the shape */ void addFactory(KoShapeFactoryBase *factory); /** * Use the element to find out which flake plugin can load it, and * returns the loaded shape. The element expected is one of * 'draw:line', 'draw:frame' / etc. * * @returns the shape or 0 if no shape could be created. The shape may have as its parent * set a layer which was previously created and stored in the context. * @see KoShapeLoadingContext::layer() */ KoShape *createShapeFromOdf(const KoXmlElement &element, KoShapeLoadingContext &context) const; /** * Returns a list of shape factories supporting the specified xml element. * @param nameSpace the namespace of the xml element, see KoXmlNS for valid namespaces * @param elementName the tag name of the element * @return the list of shape factories supporting the specified xml element */ QList factoriesForElement(const QString &nameSpace, const QString &elementName); private: KoShapeRegistry(const KoShapeRegistry&); KoShapeRegistry operator=(const KoShapeRegistry&); class Private; Private * const d; }; #endif diff --git a/libs/image/brushengine/kis_locked_properties.cc b/libs/image/brushengine/kis_locked_properties.cc index 610e08db5c..80384c9de9 100644 --- a/libs/image/brushengine/kis_locked_properties.cc +++ b/libs/image/brushengine/kis_locked_properties.cc @@ -1,76 +1,78 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include KisLockedProperties::KisLockedProperties() { m_lockedProperties = new KisPropertiesConfiguration(); } -KisLockedProperties::KisLockedProperties(KisPropertiesConfiguration *p) +KisLockedProperties::KisLockedProperties(KisPropertiesConfigurationSP p) { m_lockedProperties = new KisPropertiesConfiguration(); QMap::Iterator i; for (i = p->getProperties().begin(); i != p->getProperties().end(); i++) { m_lockedProperties->setProperty(i.key(), i.value()); } } KisLockedProperties::~KisLockedProperties() { - delete m_lockedProperties; } -void KisLockedProperties::addToLockedProperties(KisPropertiesConfiguration *p) + +void KisLockedProperties::addToLockedProperties(KisPropertiesConfigurationSP p) { QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); m_lockedProperties->setProperty(i.key(), QVariant(i.value())); } } -void KisLockedProperties::removeFromLockedProperties(KisPropertiesConfiguration *p) + +void KisLockedProperties::removeFromLockedProperties(KisPropertiesConfigurationSP p) { - KisPropertiesConfiguration *temp = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP temp = new KisPropertiesConfiguration(); QMapIterator i(m_lockedProperties->getProperties()); while (i.hasNext()) { i.next(); temp->setProperty(i.key(), QVariant(i.value())); } m_lockedProperties->clearProperties(); QMapIterator j(temp->getProperties()); while (j.hasNext()) { j.next(); if (!p->hasProperty(j.key())) { m_lockedProperties->setProperty(j.key(), QVariant(j.value())); } } } + bool KisLockedProperties::hasProperty(const QString &p) { return m_lockedProperties->hasProperty(p); } -KisPropertiesConfiguration *KisLockedProperties::lockedProperties() +KisPropertiesConfigurationSP KisLockedProperties::lockedProperties() { return m_lockedProperties; } diff --git a/libs/image/brushengine/kis_locked_properties.h b/libs/image/brushengine/kis_locked_properties.h index 90b5c457e3..18c7256974 100644 --- a/libs/image/brushengine/kis_locked_properties.h +++ b/libs/image/brushengine/kis_locked_properties.h @@ -1,57 +1,53 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISLOCKEDPROPERTIES_H #define KISLOCKEDPROPERTIES_H #include "kis_properties_configuration.h" /** * This class maintains a list of all the PaintOp Options that are supposed to be * constant across all paintops and presets. * addToLockedProperties() adds all the settings mentioned in the parameter to the list * removeFromLockedProperties() removes a particular set of properties from the list * hasProperty() checks for a particular property in the list */ class KisLockedProperties { public: KisLockedProperties(); - KisLockedProperties(KisPropertiesConfiguration *p); + KisLockedProperties(KisPropertiesConfigurationSP p); ~KisLockedProperties(); /**Whenever any setting is made locked**/ - void addToLockedProperties(KisPropertiesConfiguration *p); + void addToLockedProperties(KisPropertiesConfigurationSP p); /**Whenever any property is unlocked**/ - void removeFromLockedProperties(KisPropertiesConfiguration *p); + void removeFromLockedProperties(KisPropertiesConfigurationSP p); bool hasProperty(const QString &p); - - - - KisPropertiesConfiguration *lockedProperties(); - + KisPropertiesConfigurationSP lockedProperties(); private: - KisPropertiesConfiguration* m_lockedProperties; + KisPropertiesConfigurationSP m_lockedProperties; }; #endif // KISLOCKEDPROPERTIES_H diff --git a/libs/image/brushengine/kis_locked_properties_proxy.cpp b/libs/image/brushengine/kis_locked_properties_proxy.cpp index cd2989665d..5a04000371 100644 --- a/libs/image/brushengine/kis_locked_properties_proxy.cpp +++ b/libs/image/brushengine/kis_locked_properties_proxy.cpp @@ -1,97 +1,98 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 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 KisLockedPropertiesProxy ::KisLockedPropertiesProxy() : m_lockedProperties(0) , m_parent(0) { } KisLockedPropertiesProxy::KisLockedPropertiesProxy(KisLockedProperties* p) { m_lockedProperties = p; } -KisLockedPropertiesProxy::KisLockedPropertiesProxy(const KisPropertiesConfiguration *p, KisLockedProperties *l) +KisLockedPropertiesProxy::KisLockedPropertiesProxy(KisPropertiesConfigurationSP p, KisLockedProperties *l) { - m_lockedProperties = l; m_parent = p; + m_lockedProperties = l; } QVariant KisLockedPropertiesProxy::getProperty(const QString &name) const { - KisPropertiesConfiguration* temp = const_cast(m_parent); - KisPaintOpSettings* t = dynamic_cast(temp); + KisPropertiesConfigurationSP temp = KisPropertiesConfigurationSP(m_parent); + KisPaintOpSettingsSP t = dynamic_cast(temp.data()); if (t->preset()) { // restores the dirty state on returns automagically KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset().data()); if (m_lockedProperties->lockedProperties()) { if (m_lockedProperties->lockedProperties()->hasProperty(name)) { KisLockedPropertiesServer::instance()->setPropertiesFromLocked(true); if (!m_parent->hasProperty(name + "_previous")) { temp->setProperty(name + "_previous", m_parent->getProperty(name)); } temp->setProperty(name, m_lockedProperties->lockedProperties()->getProperty(name)); return m_lockedProperties->lockedProperties()->getProperty(name); } else { if (m_parent->hasProperty(name + "_previous")) { - KisPropertiesConfiguration* temp = const_cast(m_parent); + KisPropertiesConfigurationSP temp = m_parent; temp->setProperty(name, m_parent->getProperty(name + "_previous")); temp->removeProperty(name + "_previous"); } } } } return m_parent->getProperty(name); } void KisLockedPropertiesProxy::setProperty(const QString & name, const QVariant & value) { - KisPropertiesConfiguration* temp = const_cast(m_parent); - KisPaintOpSettings* t = dynamic_cast(temp); + KisPropertiesConfigurationSP temp = m_parent; + KisPaintOpSettingsSP t = dynamic_cast(temp.data()); if (t->preset()) { // restores the dirty state on returns automagically KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset().data()); if (m_lockedProperties->lockedProperties()) { if (m_lockedProperties->lockedProperties()->hasProperty(name)) { m_lockedProperties->lockedProperties()->setProperty(name, value); t->setProperty(name, value); if (!m_parent->hasProperty(name + "_previous")) { t->setProperty(name + "_previous", m_parent->getProperty(name)); } return; } } + Q_UNUSED(dirtyStateSaver); } t->setProperty(name, value); } diff --git a/libs/image/brushengine/kis_locked_properties_proxy.h b/libs/image/brushengine/kis_locked_properties_proxy.h index 7e23ef710c..04a889993b 100644 --- a/libs/image/brushengine/kis_locked_properties_proxy.h +++ b/libs/image/brushengine/kis_locked_properties_proxy.h @@ -1,58 +1,59 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LOCKED_PROPERTIES_PROXY_H #define KIS_LOCKED_PROPERTIES_PROXY_H #include "kis_properties_configuration.h" - /** * This class acts as a proxy for all transfers between KisLockedPropertiesServer * and KisPaintOpSettings while using setConfiguration and writeConfiguration * methods. It is used to override the local settings of a * paintop with the * settings present in the KisLockedProperties List. * * Settings with the "_previous" suffix are used to save the local settings of * a preset in the preset itself. Whenever the user selects the option of going * back to the previous configuration of the preset or "unlocks" an option * -- these settings are restored and the settings with the "_previous" * suffix are destroyed. */ class KisLockedPropertiesServer; class KisLockedProperties; class KisLockedPropertiesProxy: public KisPropertiesConfiguration { public: KisLockedPropertiesProxy() ; - KisLockedPropertiesProxy(KisLockedProperties* p); - KisLockedPropertiesProxy(const KisPropertiesConfiguration *, KisLockedProperties *); + KisLockedPropertiesProxy(KisLockedProperties *p); + KisLockedPropertiesProxy(KisPropertiesConfigurationSP , KisLockedProperties *); + using KisPropertiesConfiguration::getProperty; QVariant getProperty(const QString &name) const; using KisPropertiesConfiguration::setProperty; void setProperty(const QString & name, const QVariant & value); private: + Q_DISABLE_COPY(KisLockedPropertiesProxy) KisLockedProperties *m_lockedProperties; - const KisPropertiesConfiguration *m_parent; + KisPropertiesConfigurationSP m_parent; }; -typedef QSharedPointer KisLockedPropertiesProxySP; -typedef QWeakPointer KisLockedPropertiesProxyWSP; +typedef KisSharedPtr KisLockedPropertiesProxySP; +typedef KisWeakSharedPtr KisLockedPropertiesProxyWSP; #endif // KIS_LOCKED_PROPERTIES_PROXY_H diff --git a/libs/image/brushengine/kis_locked_properties_server.cpp b/libs/image/brushengine/kis_locked_properties_server.cpp index 6374a029a3..fe5f186681 100644 --- a/libs/image/brushengine/kis_locked_properties_server.cpp +++ b/libs/image/brushengine/kis_locked_properties_server.cpp @@ -1,79 +1,83 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include Q_GLOBAL_STATIC(KisLockedPropertiesServer, s_instance); KisLockedPropertiesServer::KisLockedPropertiesServer() { m_lockedProperties = new KisLockedProperties(); m_propertiesFromLocked = false; } KisLockedPropertiesServer::~KisLockedPropertiesServer() { delete m_lockedProperties; } -KisLockedPropertiesProxy* KisLockedPropertiesServer::createLockedPropertiesProxy(const KisPropertiesConfiguration* config) +KisLockedPropertiesProxySP KisLockedPropertiesServer::createLockedPropertiesProxy(const KisPropertiesConfigurationSP config) { - KisLockedPropertiesProxy* m = new KisLockedPropertiesProxy(config, lockedProperties()); - return m; + return new KisLockedPropertiesProxy(config, lockedProperties()); } + KisLockedPropertiesServer* KisLockedPropertiesServer::instance() { if (s_instance) { return s_instance; } return NULL; } + KisLockedProperties* KisLockedPropertiesServer::lockedProperties() { return m_lockedProperties; } -void KisLockedPropertiesServer::addToLockedProperties(KisPropertiesConfiguration *p) + +void KisLockedPropertiesServer::addToLockedProperties(KisPropertiesConfigurationSP p) { lockedProperties()->addToLockedProperties(p); } -void KisLockedPropertiesServer::removeFromLockedProperties(KisPropertiesConfiguration *p) + +void KisLockedPropertiesServer::removeFromLockedProperties(KisPropertiesConfigurationSP p) { lockedProperties()->removeFromLockedProperties(p); } + void KisLockedPropertiesServer::setPropertiesFromLocked(bool value) { m_propertiesFromLocked = value; } bool KisLockedPropertiesServer::propertiesFromLocked() { return m_propertiesFromLocked; } bool KisLockedPropertiesServer::hasProperty(const QString &p) { return m_lockedProperties->hasProperty(p); } diff --git a/libs/image/brushengine/kis_locked_properties_server.h b/libs/image/brushengine/kis_locked_properties_server.h index 9ee1eb9a21..859bc48b5d 100644 --- a/libs/image/brushengine/kis_locked_properties_server.h +++ b/libs/image/brushengine/kis_locked_properties_server.h @@ -1,56 +1,56 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LOCKED_PROPERTIES_SERVER_H #define KIS_LOCKED_PROPERTIES_SERVER_H #include #include "kis_properties_configuration.h" class KisLockedPropertiesProxy; class KisLockedProperties; /** * The KisLockedPropertiesServer class * This static class stores an object of KisLockedProperties and generates a KisLockedPropertiesProxy used * by other classes/objects to access the LockedProperties object. */ class KRITAIMAGE_EXPORT KisLockedPropertiesServer: public QObject { public: KisLockedPropertiesServer(); ~KisLockedPropertiesServer(); static KisLockedPropertiesServer* instance(); KisLockedProperties* lockedProperties(); - void addToLockedProperties(KisPropertiesConfiguration *p); - void removeFromLockedProperties(KisPropertiesConfiguration *p); + void addToLockedProperties(KisPropertiesConfigurationSP p); + void removeFromLockedProperties(KisPropertiesConfigurationSP p); void setPropertiesFromLocked(bool value); bool propertiesFromLocked(); - KisLockedPropertiesProxy* createLockedPropertiesProxy(const KisPropertiesConfiguration*); + KisLockedPropertiesProxySP createLockedPropertiesProxy(const KisPropertiesConfigurationSP); bool hasProperty(const QString &p); private: KisLockedProperties *m_lockedProperties; bool m_propertiesFromLocked; }; #endif // KIS_LOCKED_PROPERTIES_SERVER_H diff --git a/libs/image/brushengine/kis_paintop_config_widget.cpp b/libs/image/brushengine/kis_paintop_config_widget.cpp index 2fbc63100b..ec5820830f 100644 --- a/libs/image/brushengine/kis_paintop_config_widget.cpp +++ b/libs/image/brushengine/kis_paintop_config_widget.cpp @@ -1,95 +1,97 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_paintop_config_widget.h" #include KisPaintOpConfigWidget::KisPaintOpConfigWidget(QWidget * parent, Qt::WFlags f) : KisConfigWidget(parent, f, 10), m_userAllowedLod(true), m_isInsideUpdateCall(0) { } KisPaintOpConfigWidget::~KisPaintOpConfigWidget() { } -void KisPaintOpConfigWidget::writeConfigurationSafe(KisPropertiesConfiguration *config) const + +void KisPaintOpConfigWidget::writeConfigurationSafe(KisPropertiesConfigurationSP config) const { if (m_isInsideUpdateCall) return; m_isInsideUpdateCall++; writeConfiguration(config); m_isInsideUpdateCall--; } -void KisPaintOpConfigWidget::setConfigurationSafe(const KisPropertiesConfiguration *config) +void KisPaintOpConfigWidget::setConfigurationSafe(const KisPropertiesConfigurationSP config) { if (m_isInsideUpdateCall) return; m_isInsideUpdateCall++; setConfiguration(config); m_isInsideUpdateCall--; } -void KisPaintOpConfigWidget::writeConfiguration(KisPropertiesConfiguration *config) const { +void KisPaintOpConfigWidget::writeConfiguration(KisPropertiesConfigurationSP config) const +{ KisPaintOpSettings::setLodUserAllowed(config, m_userAllowedLod); } -void KisPaintOpConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) { +void KisPaintOpConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_userAllowedLod = KisPaintOpSettings::isLodUserAllowed(config); emit sigUserChangedLodAvailability(m_userAllowedLod); } void KisPaintOpConfigWidget::setImage(KisImageWSP image) { m_image = image; } void KisPaintOpConfigWidget::setNode(KisNodeWSP node) { m_node = node; } void KisPaintOpConfigWidget::changePaintOpSize(qreal x, qreal y) { Q_UNUSED(x); Q_UNUSED(y); } QSizeF KisPaintOpConfigWidget::paintOpSize() const { return QSizeF(1.0, 1.0); } bool KisPaintOpConfigWidget::presetIsValid() { return true; } bool KisPaintOpConfigWidget::supportScratchBox() { return true; } void KisPaintOpConfigWidget::slotUserChangedLodAvailability(bool value) { m_userAllowedLod = value; emit sigConfigurationItemChanged(); } void KisPaintOpConfigWidget::coldInitExternalLodAvailabilityWidget() { emit sigUserChangedLodAvailability(m_userAllowedLod); emit sigConfigurationItemChanged(); } diff --git a/libs/image/brushengine/kis_paintop_config_widget.h b/libs/image/brushengine/kis_paintop_config_widget.h index f1d3a3f944..76746108a9 100644 --- a/libs/image/brushengine/kis_paintop_config_widget.h +++ b/libs/image/brushengine/kis_paintop_config_widget.h @@ -1,102 +1,105 @@ /* * 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. */ #ifndef KIS_PAINTOP_CONFIG_WIDGET_H_ #define KIS_PAINTOP_CONFIG_WIDGET_H_ #include "kritaimage_export.h" #include "kis_config_widget.h" #include "kis_image.h" #include +#include class KisPaintopLodLimitations; /** * Base class for widgets that are used to edit and display paintop settings. */ class KRITAIMAGE_EXPORT KisPaintOpConfigWidget : public KisConfigWidget { Q_OBJECT public: KisPaintOpConfigWidget(QWidget * parent = 0, Qt::WFlags f = 0); virtual ~KisPaintOpConfigWidget(); - void writeConfigurationSafe(KisPropertiesConfiguration *config) const; - void setConfigurationSafe(const KisPropertiesConfiguration *config); + void writeConfigurationSafe(KisPropertiesConfigurationSP config) const; + void setConfigurationSafe(const KisPropertiesConfigurationSP config); protected: /** * Write the settings in this widget to the given properties * configuration, which is cleared first. */ - virtual void writeConfiguration(KisPropertiesConfiguration *config) const; - virtual void setConfiguration(const KisPropertiesConfiguration * config); + virtual void writeConfiguration(KisPropertiesConfigurationSP config) const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); + public: + virtual KisPaintopLodLimitations lodLimitations() const = 0; virtual void setImage(KisImageWSP image); virtual void setNode(KisNodeWSP node); /** * @see KisPaintOpSettings::changePaintOpSize(qreal x, qreal y) */ virtual void changePaintOpSize(qreal x, qreal y); /** * @see KisPaintOpSettings::paintOpSize() */ virtual QSizeF paintOpSize() const; /** * This is true for all of the paintop widget except for the Custom brush tab in the Brush tip dialog */ virtual bool presetIsValid(); /** * Some paintops are more complicated and require full canvas with layers, projections and KisImage etc. * Example is duplicate paintop. In this case simple canvas like scratchbox does not work. * Every paintop supports the scratchbox by default, override and return false if paintop does not. */ virtual bool supportScratchBox(); /** * This call makes KisPaintOpConfigWidget emit * sigUserChangedLodAvailability() signal with the current * availability value */ void coldInitExternalLodAvailabilityWidget(); public Q_SLOTS: void slotUserChangedLodAvailability(bool value); Q_SIGNALS: void sigUserChangedLodAvailability(bool value); protected: KisImageWSP m_image; KisNodeWSP m_node; bool m_userAllowedLod; mutable int m_isInsideUpdateCall; }; #endif diff --git a/libs/image/brushengine/kis_paintop_settings.cpp b/libs/image/brushengine/kis_paintop_settings.cpp index d88411849a..329d721765 100644 --- a/libs/image/brushengine/kis_paintop_settings.cpp +++ b/libs/image/brushengine/kis_paintop_settings.cpp @@ -1,461 +1,470 @@ /* * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2008 Lukáš Tvrdý * 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 #include #include #include #include #include #include #include #include "kis_paint_layer.h" #include "kis_image.h" #include "kis_painter.h" #include "kis_paint_device.h" #include "kis_paintop_registry.h" #include #include "kis_paintop_config_widget.h" #include #include "kis_paintop_settings_update_proxy.h" #include #include #include #include #include struct Q_DECL_HIDDEN KisPaintOpSettings::Private { - Private() : disableDirtyNotifications(false) {} + Private() + : disableDirtyNotifications(false) + {} QPointer settingsWidget; QString modelName; KisPaintOpPresetWSP preset; QList uniformProperties; - bool disableDirtyNotifications; class DirtyNotificationsLocker { public: DirtyNotificationsLocker(KisPaintOpSettings::Private *d) : m_d(d), m_oldNotificationsState(d->disableDirtyNotifications) { m_d->disableDirtyNotifications = true; } ~DirtyNotificationsLocker() { m_d->disableDirtyNotifications = m_oldNotificationsState; } private: KisPaintOpSettings::Private *m_d; bool m_oldNotificationsState; Q_DISABLE_COPY(DirtyNotificationsLocker) }; KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const { return preset ? preset->updateProxyNoCreate() : 0; } KisPaintopSettingsUpdateProxy* updateProxyCreate() const { return preset ? preset->updateProxy() : 0; } }; KisPaintOpSettings::KisPaintOpSettings() : d(new Private) { d->preset = 0; } KisPaintOpSettings::~KisPaintOpSettings() { } +KisPaintOpSettings::KisPaintOpSettings(const KisPaintOpSettings &rhs) + : KisPropertiesConfiguration(rhs) + , d(new Private) +{ + d->settingsWidget = 0; + d->preset = rhs.preset(); + d->modelName = rhs.modelName(); +} + void KisPaintOpSettings::setOptionsWidget(KisPaintOpConfigWidget* widget) { d->settingsWidget = widget; } void KisPaintOpSettings::setPreset(KisPaintOpPresetWSP preset) { d->preset = preset; } KisPaintOpPresetWSP KisPaintOpSettings::preset() const { return d->preset; } bool KisPaintOpSettings::mousePressEvent(const KisPaintInformation &pos, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode) { Q_UNUSED(pos); Q_UNUSED(modifiers); Q_UNUSED(currentNode); setRandomOffset(); return true; // ignore the event by default } void KisPaintOpSettings::setRandomOffset() { srand(time(0)); bool isRandomOffsetX = KisPropertiesConfiguration::getBool("Texture/Pattern/isRandomOffsetX"); bool isRandomOffsetY = KisPropertiesConfiguration::getBool("Texture/Pattern/isRandomOffsetY"); int offsetX = KisPropertiesConfiguration::getInt("Texture/Pattern/OffsetX"); int offsetY = KisPropertiesConfiguration::getInt("Texture/Pattern/OffsetY"); if (KisPropertiesConfiguration::getBool("Texture/Pattern/Enabled")) { if (isRandomOffsetX) { offsetX = rand() % KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetX"); KisPropertiesConfiguration::setProperty("Texture/Pattern/OffsetX", offsetX); offsetX = KisPropertiesConfiguration::getInt("Texture/Pattern/OffsetX"); } if (isRandomOffsetY) { offsetY = rand() % KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetY"); KisPropertiesConfiguration::setProperty("Texture/Pattern/OffsetY", offsetY); offsetY = KisPropertiesConfiguration::getInt("Texture/Pattern/OffsetY"); } } } KisPaintOpSettingsSP KisPaintOpSettings::clone() const { QString paintopID = getString("paintop"); if (paintopID.isEmpty()) return 0; KisPaintOpSettingsSP settings = KisPaintOpRegistry::instance()->settings(KoID(paintopID, "")); QMapIterator i(getProperties()); while (i.hasNext()) { i.next(); settings->setProperty(i.key(), QVariant(i.value())); } settings->setPreset(this->preset()); return settings; } void KisPaintOpSettings::activate() { } void KisPaintOpSettings::setPaintOpOpacity(qreal value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("OpacityValue", value); } void KisPaintOpSettings::setPaintOpFlow(qreal value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("FlowValue", value); } void KisPaintOpSettings::setPaintOpCompositeOp(const QString &value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("CompositeOp", value); } -qreal KisPaintOpSettings::paintOpOpacity() const +qreal KisPaintOpSettings::paintOpOpacity() { - KisLockedPropertiesProxySP proxy( - KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); + KisLockedPropertiesProxySP proxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this); return proxy->getDouble("OpacityValue", 1.0); } -qreal KisPaintOpSettings::paintOpFlow() const +qreal KisPaintOpSettings::paintOpFlow() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getDouble("FlowValue", 1.0); } void KisPaintOpSettings::setPaintOpSize(qreal value) { /** * The widget already has the wrapping for the locked setings * functionality, so just request it. */ if (d->settingsWidget) { const qreal sizeDiff = value - paintOpSize(); { KisSignalsBlocker b(d->settingsWidget); d->settingsWidget.data()->setConfigurationSafe(this); d->settingsWidget.data()->changePaintOpSize(sizeDiff, 0); } d->settingsWidget.data()->writeConfigurationSafe(this); } } qreal KisPaintOpSettings::paintOpSize() const { // see a comment about locked settings in setPaintOpSize() qreal size = 1.0; if (d->settingsWidget) { size = d->settingsWidget.data()->paintOpSize().width(); } return size; } -QString KisPaintOpSettings::paintOpCompositeOp() const +QString KisPaintOpSettings::paintOpCompositeOp() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getString("CompositeOp", COMPOSITE_OVER); } void KisPaintOpSettings::setEraserMode(bool value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("EraserMode", value); } -bool KisPaintOpSettings::eraserMode() const +bool KisPaintOpSettings::eraserMode() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getBool("EraserMode", false); } -QString KisPaintOpSettings::effectivePaintOpCompositeOp() const +QString KisPaintOpSettings::effectivePaintOpCompositeOp() { return !eraserMode() ? paintOpCompositeOp() : COMPOSITE_ERASE; } qreal KisPaintOpSettings::savedEraserSize() const { return getDouble("SavedEraserSize", 0.0); } void KisPaintOpSettings::setSavedEraserSize(qreal value) { setProperty("SavedEraserSize", value); setPropertyNotSaved("SavedEraserSize"); } qreal KisPaintOpSettings::savedBrushSize() const { return getDouble("SavedBrushSize", 0.0); } void KisPaintOpSettings::setSavedBrushSize(qreal value) { setProperty("SavedBrushSize", value); setPropertyNotSaved("SavedBrushSize"); } qreal KisPaintOpSettings::savedEraserOpacity() const { return getDouble("SavedEraserOpacity", 0.0); } void KisPaintOpSettings::setSavedEraserOpacity(qreal value) { setProperty("SavedEraserOpacity", value); setPropertyNotSaved("SavedEraserOpacity"); } qreal KisPaintOpSettings::savedBrushOpacity() const { return getDouble("SavedBrushOpacity", 0.0); } void KisPaintOpSettings::setSavedBrushOpacity(qreal value) { setProperty("SavedBrushOpacity", value); setPropertyNotSaved("SavedBrushOpacity"); } QString KisPaintOpSettings::modelName() const { return d->modelName; } void KisPaintOpSettings::setModelName(const QString & modelName) { d->modelName = modelName; } KisPaintOpConfigWidget* KisPaintOpSettings::optionsWidget() const { if (d->settingsWidget.isNull()) return 0; return d->settingsWidget.data(); } bool KisPaintOpSettings::isValid() const { return true; } bool KisPaintOpSettings::isLoadable() { return isValid(); } QString KisPaintOpSettings::indirectPaintingCompositeOp() const { return COMPOSITE_ALPHA_DARKEN; } -QPainterPath KisPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { path = ellipseOutline(10, 10, 1.0, 0); - + if (mode == CursorTiltOutline) { path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 2.0)); } path.translate(info.pos()); } return path; } QPainterPath KisPaintOpSettings::ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation) { QPainterPath path; QRectF ellipse(0, 0, width * scale, height * scale); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); QTransform m; m.reset(); m.rotate(rotation); path = m.map(path); return path; } QPainterPath KisPaintOpSettings::makeTiltIndicator(KisPaintInformation const& info, QPointF const& start, qreal maxLength, qreal angle) { if (maxLength == 0.0) maxLength = 50.0; maxLength = qMax(maxLength, 50.0); qreal const length = maxLength * (1 - info.tiltElevation(info, 60.0, 60.0, true)); qreal const baseAngle = 360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0); QLineF guideLine = QLineF::fromPolar(length, baseAngle + angle); guideLine.translate(start); QPainterPath ret; ret.moveTo(guideLine.p1()); ret.lineTo(guideLine.p2()); guideLine.setAngle(baseAngle - angle); ret.lineTo(guideLine.p2()); ret.lineTo(guideLine.p1()); return ret; } void KisPaintOpSettings::setCanvasRotation(qreal angle) { Private::DirtyNotificationsLocker locker(d.data()); setProperty("runtimeCanvasRotation", angle); setPropertyNotSaved("runtimeCanvasRotation"); } void KisPaintOpSettings::setCanvasMirroring(bool xAxisMirrored, bool yAxisMirrored) { Private::DirtyNotificationsLocker locker(d.data()); setProperty("runtimeCanvasMirroredX", xAxisMirrored); setPropertyNotSaved("runtimeCanvasMirroredX"); setProperty("runtimeCanvasMirroredY", yAxisMirrored); setPropertyNotSaved("runtimeCanvasMirroredY"); } void KisPaintOpSettings::setProperty(const QString & name, const QVariant & value) { if (value != KisPropertiesConfiguration::getProperty(name) && !d->disableDirtyNotifications && this->preset()) { this->preset()->setPresetDirty(true); } KisPropertiesConfiguration::setProperty(name, value); onPropertyChanged(); } void KisPaintOpSettings::onPropertyChanged() { KisPaintopSettingsUpdateProxy *proxy = d->updateProxyNoCreate(); if (proxy) { proxy->notifySettingsChanged(); } } -bool KisPaintOpSettings::isLodUserAllowed(const KisPropertiesConfiguration *config) +bool KisPaintOpSettings::isLodUserAllowed(const KisPropertiesConfigurationSP config) { return config->getBool("lodUserAllowed", true); } -void KisPaintOpSettings::setLodUserAllowed(KisPropertiesConfiguration *config, bool value) +void KisPaintOpSettings::setLodUserAllowed(KisPropertiesConfigurationSP config, bool value) { config->setProperty("lodUserAllowed", value); } #include "kis_standard_uniform_properties_factory.h" QList KisPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(d->uniformProperties); if (props.isEmpty()) { using namespace KisStandardUniformPropertiesFactory; props.append(createProperty(opacity, this, d->updateProxyCreate())); props.append(createProperty(size, this, d->updateProxyCreate())); props.append(createProperty(flow, this, d->updateProxyCreate())); d->uniformProperties = listStrongToWeak(props); } return props; } diff --git a/libs/image/brushengine/kis_paintop_settings.h b/libs/image/brushengine/kis_paintop_settings.h index 1292a7d4cd..122cd26432 100644 --- a/libs/image/brushengine/kis_paintop_settings.h +++ b/libs/image/brushengine/kis_paintop_settings.h @@ -1,280 +1,281 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_SETTINGS_H_ #define KIS_PAINTOP_SETTINGS_H_ #include "kis_types.h" #include "kritaimage_export.h" #include #include -#include "kis_shared.h" #include "kis_properties_configuration.h" #include #include class KisPaintOpConfigWidget; class KisPaintopSettingsUpdateProxy; /** * This class is used to cache the settings for a paintop * between two creations. There is one KisPaintOpSettings per input device (mouse, tablet, * etc...). * * The settings may be stored in a preset or a recorded brush stroke. Note that if your * paintop's settings subclass has data that is not stored as a property, that data is not * saved and restored. * * The object also contains a pointer to its parent KisPaintOpPreset object.This is to control the DirtyPreset * property of KisPaintOpPreset. Whenever the settings are changed/modified from the original -- the preset is * set to dirty. */ -class KRITAIMAGE_EXPORT KisPaintOpSettings : public KisPropertiesConfiguration, public KisShared +class KRITAIMAGE_EXPORT KisPaintOpSettings : public KisPropertiesConfiguration { public: KisPaintOpSettings(); - virtual ~KisPaintOpSettings(); + KisPaintOpSettings(const KisPaintOpSettings &rhs); /** * */ virtual void setOptionsWidget(KisPaintOpConfigWidget* widget); /** * This function is called by a tool when the mouse is pressed. It's useful if * the paintop needs mouse interaction for instance in the case of the clone op. * If the tool is supposed to ignore the event, the paint op should return false * and if the tool is supposed to use the event, return true. */ virtual bool mousePressEvent(const KisPaintInformation &pos, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode); /** * This function is called to set random offsets to the brush whenever the mouse is clicked. It is * specific to when the pattern option is set. * */ virtual void setRandomOffset(); /** * Clone the current settings object. Override this if your settings instance doesn't * store everything as properties. */ virtual KisPaintOpSettingsSP clone() const; /** * @return the node the paintop is working on. */ KisNodeSP node() const; /** * Call this function when the paint op is selected or the tool is activated */ virtual void activate(); /** * XXX: Remove this after 2.0, when the paint operation (incremental/non incremental) will * be completely handled in the paintop, not in the tool. This is a filthy hack to move * the option to the right place, at least. * @return true if we paint incrementally, false if we paint like Photoshop. By default, paintops * do not support non-incremental. */ virtual bool paintIncremental() { return true; } /** * @return the composite op it to which the indirect painting device * should be initialized to. This is used by clone op to reset * the composite op to COMPOSITE_COPY */ virtual QString indirectPaintingCompositeOp() const; /** * Whether this paintop wants to deposit paint even when not moving, i.e. the * tool needs to activate its timer. */ virtual bool isAirbrushing() const { return false; } /** * If this paintop deposit the paint even when not moving, the tool needs to know the rate of it in miliseconds */ virtual int rate() const { return 100; } /** * This enum defines the current mode for painting an outline. */ enum OutlineMode { CursorIsOutline = 1, ///< When this mode is set, an outline is painted around the cursor CursorIsCircleOutline, CursorNoOutline, CursorTiltOutline, CursorColorOutline }; /** * Returns the brush outline in pixel coordinates. Tool is responsible for conversion into view coordinates. * Outline mode has to be passed to the paintop which builds the outline as some paintops have to paint outline * always like clone paintop indicating the duplicate position */ - virtual QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + virtual QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); /** * Helpers for drawing the brush outline */ static QPainterPath ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation); /** * Helper for drawing a triangle representing the tilt of the stylus. * * @param start is the offset from the brush's outline's bounding box * @param lengthScale is used for deciding the size of the triangle. * Brush diameter or width are common choices for this. * @param angle is the angle between the two sides of the triangle. */ static QPainterPath makeTiltIndicator(KisPaintInformation const& info, QPointF const& start, qreal lengthScale, qreal angle); /** * Set paintop opacity directly in the properties */ void setPaintOpOpacity(qreal value); /** * Set paintop flow directly in the properties */ void setPaintOpFlow(qreal value); /** * Set paintop composite mode directly in the properties */ void setPaintOpCompositeOp(const QString &value); /** * @return opacity saved in the properties */ - qreal paintOpOpacity() const; + qreal paintOpOpacity(); /** * @return flow saved in the properties */ - qreal paintOpFlow() const; + qreal paintOpFlow(); /** * @return composite mode saved in the properties */ - QString paintOpCompositeOp() const; + QString paintOpCompositeOp(); /** * Set paintop size directly in the properties */ void setPaintOpSize(qreal value); /** * @return size saved in the properties */ qreal paintOpSize() const; void setEraserMode(bool value); - bool eraserMode() const; + bool eraserMode(); qreal savedEraserSize() const; void setSavedEraserSize(qreal value); qreal savedBrushSize() const; void setSavedBrushSize(qreal value); qreal savedEraserOpacity() const; void setSavedEraserOpacity(qreal value); qreal savedBrushOpacity() const; void setSavedBrushOpacity(qreal value); - QString effectivePaintOpCompositeOp() const; + QString effectivePaintOpCompositeOp(); void setPreset(KisPaintOpPresetWSP preset); KisPaintOpPresetWSP preset() const; /** * @return filename of the 3D brush model, empty if no brush is set */ virtual QString modelName() const; /** * Set filename of 3D brush model. By default no brush is set */ void setModelName(const QString & modelName); /// Check if the settings are valid, setting might be invalid through missing brushes etc /// Overwrite if the settings of a paintop can be invalid /// @return state of the settings, default implementation is true virtual bool isValid() const; /// Check if the settings are loadable, that might the case if we can fallback to something /// Overwrite if the settings can do some kind of fallback /// @return loadable state of the settings, by default implementation return the same as isValid() virtual bool isLoadable(); /** * These methods are populating properties with runtime * information about canvas rotation/mirroring. This information * is set directly by KisToolFreehand. Later the data is accessed * by the pressure options to make a final decision. */ void setCanvasRotation(qreal angle); void setCanvasMirroring(bool xAxisMirrored, bool yAxisMirrored); /** * Overrides the method in KisPropertiesCofiguration to allow * onPropertyChanged() callback */ void setProperty(const QString & name, const QVariant & value); virtual QList uniformProperties(); - static bool isLodUserAllowed(const KisPropertiesConfiguration *config); - static void setLodUserAllowed(KisPropertiesConfiguration *config, bool value); + static bool isLodUserAllowed(const KisPropertiesConfigurationSP config); + static void setLodUserAllowed(KisPropertiesConfigurationSP config, bool value); /** * @return the option widget of the paintop (can be 0 is no option widgets is set) */ KisPaintOpConfigWidget* optionsWidget() const; protected: /** * The callback is called every time when a property changes */ virtual void onPropertyChanged(); private: struct Private; const QScopedPointer d; }; +typedef KisSharedPtr KisPaintOpSettingsSP; + #endif diff --git a/libs/image/commands/kis_change_filter_command.h b/libs/image/commands/kis_change_filter_command.h index c355bfd944..c095c531b5 100644 --- a/libs/image/commands/kis_change_filter_command.h +++ b/libs/image/commands/kis_change_filter_command.h @@ -1,96 +1,96 @@ /* * 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. */ #ifndef KIS_CHANGE_FILTER_COMMAND_H #define KIS_CHANGE_FILTER_COMMAND_H #include #include #include "kis_types.h" #include #include "filter/kis_filter_configuration.h" #include "kis_node.h" #include "kis_node_filter_interface.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter.h" #include "generator/kis_generator_registry.h" #include "generator/kis_generator.h" class KisChangeFilterCmd : public KUndo2Command { public: KisChangeFilterCmd(KisNodeSP node, const QString &filterNameBefore, const QString &xmlBefore, const QString &filterNameAfter, const QString &xmlAfter, bool useGeneratorRegistry) : KUndo2Command(kundo2_i18n("Change Filter")) { m_node = node; m_filterInterface = dynamic_cast(node.data()); Q_ASSERT(m_filterInterface); m_useGeneratorRegistry = useGeneratorRegistry; m_xmlBefore = xmlBefore; m_xmlAfter = xmlAfter; m_filterNameBefore = filterNameBefore; m_filterNameAfter = filterNameAfter; } public: virtual void redo() { m_filterInterface->setFilter(createConfiguration(m_filterNameAfter, m_xmlAfter)); m_node->setDirty(); } virtual void undo() { m_filterInterface->setFilter(createConfiguration(m_filterNameBefore, m_xmlBefore)); m_node->setDirty(); } private: - KisFilterConfiguration* createConfiguration(const QString &name, const QString &data) + KisFilterConfigurationSP createConfiguration(const QString &name, const QString &data) { - KisFilterConfiguration *config; + KisFilterConfigurationSP config; if (m_useGeneratorRegistry) { KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(name); config = generator->defaultConfiguration(0); } else { KisFilterSP filter = KisFilterRegistry::instance()->value(name); config = filter->defaultConfiguration(0); } config->fromXML(data); return config; } private: KisNodeSP m_node; KisNodeFilterInterface *m_filterInterface; bool m_useGeneratorRegistry; QString m_xmlBefore; QString m_xmlAfter; QString m_filterNameBefore; QString m_filterNameAfter; }; #endif diff --git a/libs/image/filter/kis_color_transformation_configuration.cc b/libs/image/filter/kis_color_transformation_configuration.cc index 26b80c57c5..4c99ab9e89 100644 --- a/libs/image/filter/kis_color_transformation_configuration.cc +++ b/libs/image/filter/kis_color_transformation_configuration.cc @@ -1,60 +1,68 @@ /* * Copyright (c) 2015 Thorsten Zachmann * * 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 "filter/kis_color_transformation_configuration.h" #include #include #include #include "filter/kis_color_transformation_filter.h" struct Q_DECL_HIDDEN KisColorTransformationConfiguration::Private { Private() {} ~Private() { qDeleteAll(colorTransformation); } + // XXX: Threadlocal storage!!! QMap colorTransformation; QMutex mutex; }; KisColorTransformationConfiguration::KisColorTransformationConfiguration(const QString & name, qint32 version) -: KisFilterConfiguration(name, version) -, d(new Private()) + : KisFilterConfiguration(name, version) + , d(new Private()) +{ +} + +KisColorTransformationConfiguration::KisColorTransformationConfiguration(const KisColorTransformationConfiguration &rhs) + : KisFilterConfiguration(rhs) + , d(new Private()) { } KisColorTransformationConfiguration::~KisColorTransformationConfiguration() { delete d; } -KoColorTransformation* KisColorTransformationConfiguration::colorTransformation(const KoColorSpace *cs, const KisColorTransformationFilter * filter) const +KoColorTransformation* KisColorTransformationConfiguration::colorTransformation(const KoColorSpace *cs, const KisColorTransformationFilter *filter) const { QMutexLocker locker(&d->mutex); KoColorTransformation *transformation = d->colorTransformation.value(QThread::currentThread(), 0); if (!transformation) { - transformation = filter->createTransformation(cs, this); + KisFilterConfigurationSP config(const_cast(this)); + transformation = filter->createTransformation(cs, config); d->colorTransformation.insert(QThread::currentThread(), transformation); } locker.unlock(); return transformation; } diff --git a/libs/image/filter/kis_color_transformation_configuration.h b/libs/image/filter/kis_color_transformation_configuration.h index 3208c056a5..1d53ac057e 100644 --- a/libs/image/filter/kis_color_transformation_configuration.h +++ b/libs/image/filter/kis_color_transformation_configuration.h @@ -1,40 +1,45 @@ /* * Copyright (c) 2015 Thorsten Zachmann * * 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_TRANSFORMATION_CONFIGURATION_H_ #define _KIS_COLOR_TRANSFORMATION_CONFIGURATION_H_ -#include "filter/kis_filter_configuration.h" +#include "kis_filter_configuration.h" #include "kritaimage_export.h" class KoColorSpace; class KisColorTransformationFilter; +class KisColorTransformationConfiguration; +typedef KisSharedPtr KisColorTransformationConfigurationSP; + + class KRITAIMAGE_EXPORT KisColorTransformationConfiguration : public KisFilterConfiguration { public: KisColorTransformationConfiguration(const QString & name, qint32 version); + KisColorTransformationConfiguration(const KisColorTransformationConfiguration &rhs); virtual ~KisColorTransformationConfiguration(); - KoColorTransformation *colorTransformation(const KoColorSpace *cs, const KisColorTransformationFilter * filter) const; + KoColorTransformation *colorTransformation(const KoColorSpace *cs, const KisColorTransformationFilter *filter) const; private: struct Private; Private* const d; }; #endif /* _KIS_COLOR_TRANSFORMATION_CONFIGURATION_H_ */ diff --git a/libs/image/filter/kis_color_transformation_filter.cc b/libs/image/filter/kis_color_transformation_filter.cc index 45e4d3514f..ab451b62dc 100644 --- a/libs/image/filter/kis_color_transformation_filter.cc +++ b/libs/image/filter/kis_color_transformation_filter.cc @@ -1,87 +1,88 @@ /* * Copyright (c) 2004, 2009 Cyrille Berger * * 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_transformation_filter.h" #include #include #include #include #include #ifndef NDEBUG #include #endif #include #include "kis_color_transformation_configuration.h" KisColorTransformationFilter::KisColorTransformationFilter(const KoID& id, const KoID & category, const QString & entry) : KisFilter(id, category, entry) { setSupportsLevelOfDetail(true); } KisColorTransformationFilter::~KisColorTransformationFilter() { } -void KisColorTransformationFilter::processImpl(KisPaintDeviceSP device, +void KisColorTransformationFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_ASSERT(!device.isNull()); if (progressUpdater) { progressUpdater->setRange(0, applyRect.height() * applyRect.width()); } const KoColorSpace * cs = device->colorSpace(); KoColorTransformation * colorTransformation = 0; - const KisColorTransformationConfiguration * colorTransformationConfiguration = dynamic_cast(config); + // Ew, casting + KisColorTransformationConfigurationSP colorTransformationConfiguration(dynamic_cast(const_cast(config.data()))); if (colorTransformationConfiguration) { colorTransformation = colorTransformationConfiguration->colorTransformation(cs, this); } else { colorTransformation = createTransformation(cs, config); } if (!colorTransformation) return; KisSequentialIterator it(device, applyRect); int p = 0; int conseq; do { conseq = it.nConseqPixels(); colorTransformation->transform(it.oldRawData(), it.rawData(), conseq); if (progressUpdater) progressUpdater->setValue(p += conseq); } while(it.nextPixels(conseq)); if (!colorTransformationConfiguration) { delete colorTransformation; } } -KisFilterConfiguration * KisColorTransformationFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisColorTransformationFilter::factoryConfiguration(const KisPaintDeviceSP) const { return new KisColorTransformationConfiguration(id(), 0); } diff --git a/libs/image/filter/kis_color_transformation_filter.h b/libs/image/filter/kis_color_transformation_filter.h index 9e9b5f595e..8666cb3a44 100644 --- a/libs/image/filter/kis_color_transformation_filter.h +++ b/libs/image/filter/kis_color_transformation_filter.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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_COLOR_TRANSFORMATION_FILTER_H_ #define _KIS_COLOR_TRANSFORMATION_FILTER_H_ #include "kis_filter.h" #include "kritaimage_export.h" /** * This is a base class for filters that implement a filter for * \ref KoColorTransformation based filters. */ class KRITAIMAGE_EXPORT KisColorTransformationFilter : public KisFilter { public: KisColorTransformationFilter(const KoID& id, const KoID & category, const QString & entry); virtual ~KisColorTransformationFilter(); - virtual void processImpl(KisPaintDeviceSP device, + virtual void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; /** * Create the color transformation that will be applied on the device. */ - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const = 0; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const = 0; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; #endif diff --git a/libs/image/filter/kis_filter.cc b/libs/image/filter/kis_filter.cc index c357c1e8b8..cf4f94353d 100644 --- a/libs/image/filter/kis_filter.cc +++ b/libs/image/filter/kis_filter.cc @@ -1,174 +1,174 @@ /* * Copyright (c) 2004,2006-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. */ #include "filter/kis_filter.h" #include #include #include "kis_bookmarked_configuration_manager.h" #include "filter/kis_filter_configuration.h" #include "kis_processing_information.h" #include "kis_transaction.h" #include "kis_paint_device.h" #include "kis_selection.h" #include "kis_types.h" #include KoID KisFilter::categoryAdjust() { return KoID("adjust_filters", i18n("Adjust")); } KoID KisFilter::categoryArtistic() { return KoID("artistic_filters", i18n("Artistic")); } KoID KisFilter::categoryBlur() { return KoID("blur_filters", i18n("Blur")); } KoID KisFilter::categoryColors() { return KoID("color_filters", i18n("Colors")); } KoID KisFilter::categoryEdgeDetection() { return KoID("edge_filters", i18n("Edge Detection")); } KoID KisFilter::categoryEmboss() { return KoID("emboss_filters", i18n("Emboss")); } KoID KisFilter::categoryEnhance() { return KoID("enhance_filters", i18n("Enhance")); } KoID KisFilter::categoryMap() { return KoID("map_filters", i18n("Map")); } KoID KisFilter::categoryNonPhotorealistic() { return KoID("nonphotorealistic_filters", i18n("Non-photorealistic")); } KoID KisFilter::categoryOther() { return KoID("other_filters", i18n("Other")); } KisFilter::KisFilter(const KoID& _id, const KoID & category, const QString & entry) : KisBaseProcessor(_id, category, entry), m_supportsLevelOfDetail(false) { init(id() + "_filter_bookmarks"); } KisFilter::~KisFilter() { } void KisFilter::process(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { process(device, device, 0, applyRect, config, progressUpdater); } void KisFilter::process(const KisPaintDeviceSP src, KisPaintDeviceSP dst, KisSelectionSP selection, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { if (applyRect.isEmpty()) return; QRect needRect = neededRect(applyRect, config, src->defaultBounds()->currentLevelOfDetail()); KisPaintDeviceSP temporary; KisTransaction *transaction = 0; bool weirdDstColorSpace = dst->colorSpace() != dst->compositionSourceColorSpace() && *dst->colorSpace() != *dst->compositionSourceColorSpace(); if(src == dst && !selection && !weirdDstColorSpace) { temporary = src; } else { temporary = dst->createCompositionSourceDevice(src, needRect); transaction = new KisTransaction(temporary); } try { processImpl(temporary, applyRect, config, progressUpdater); } catch (std::bad_alloc) { warnKrita << "Filter" << name() << "failed to allocate enough memory to run."; } if(transaction) { delete transaction; KisPainter::copyAreaOptimized(applyRect.topLeft(), temporary, dst, applyRect, selection); } } -QRect KisFilter::neededRect(const QRect & rect, const KisFilterConfiguration* c, int lod) const +QRect KisFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP c, int lod) const { Q_UNUSED(c); Q_UNUSED(lod); return rect; } -QRect KisFilter::changedRect(const QRect & rect, const KisFilterConfiguration* c, int lod) const +QRect KisFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP c, int lod) const { Q_UNUSED(c); Q_UNUSED(lod); return rect; } -bool KisFilter::supportsLevelOfDetail(const KisFilterConfiguration *config, int lod) const +bool KisFilter::supportsLevelOfDetail(const KisFilterConfigurationSP config, int lod) const { Q_UNUSED(config); Q_UNUSED(lod); return m_supportsLevelOfDetail; } void KisFilter::setSupportsLevelOfDetail(bool value) { m_supportsLevelOfDetail = value; } -bool KisFilter::needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const +bool KisFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); Q_UNUSED(cs); return false; } diff --git a/libs/image/filter/kis_filter.h b/libs/image/filter/kis_filter.h index 956d11d500..40b0ee31bb 100644 --- a/libs/image/filter/kis_filter.h +++ b/libs/image/filter/kis_filter.h @@ -1,141 +1,141 @@ /* * Copyright (c) 2004,2006-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_FILTER_H_ #define _KIS_FILTER_H_ #include #include #include #include "KoID.h" #include "KoColorSpace.h" #include "kis_types.h" #include "kis_base_processor.h" #include "kritaimage_export.h" /** * Basic interface of a Krita filter. */ class KRITAIMAGE_EXPORT KisFilter : public KisBaseProcessor { public: static KoID categoryAdjust(); static KoID categoryArtistic(); static KoID categoryBlur(); static KoID categoryColors(); static KoID categoryEdgeDetection(); static KoID categoryEmboss(); static KoID categoryEnhance(); static KoID categoryMap(); static KoID categoryNonPhotorealistic(); static KoID categoryOther(); public: /** * Construct a Krita filter */ KisFilter(const KoID& id, const KoID & category, const QString & entry); virtual ~KisFilter(); public: /** * Override this function with the implementation of your filter. * * This is a low level function that expects all the conditions * for the @param device be met. Use usual process() methods * instead. * * @param device the paint device to filter * @param applyRect the rectangle where the filter is applied * @param config the parameters of the filter * @param progressUpdater to pass on the progress the filter is making */ virtual void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const = 0; /** * Filter \p src device and write the result into \p dst device. * If \p dst is an alpha color space device, it will get special * treatment. * * @param src the source paint device * @param dst the destination paint device * @param selection the selection * @param applyRect the rectangle where the filter is applied * @param config the parameters of the filter * @param progressUpdater to pass on the progress the filter is making */ void process(const KisPaintDeviceSP src, KisPaintDeviceSP dst, KisSelectionSP selection, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const; /** * A convenience method for a two-device process() function */ void process(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater = 0 ) const; /** * Some filters need pixels outside the current processing rect to compute the new * value (for instance, convolution filters) */ - virtual QRect neededRect(const QRect & rect, const KisFilterConfiguration *config, int lod) const; + virtual QRect neededRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const; /** * Similar to \ref neededRect: some filters will alter a lot of pixels that are * near to each other at the same time. So when you changed a single rectangle * in a device, the actual rectangle that will feel the influence of this change * might be bigger. Use this function to determine that rect. */ - virtual QRect changedRect(const QRect & rect, const KisFilterConfiguration *config, int lod) const; + virtual QRect changedRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const; /** * Returns true if the filter is capable of handling LoD scaled planes * when generating preview. */ - virtual bool supportsLevelOfDetail(const KisFilterConfiguration *config, int lod) const; + virtual bool supportsLevelOfDetail(const KisFilterConfigurationSP config, int lod) const; - virtual bool needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const; + virtual bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const; protected: QString configEntryGroup() const; void setSupportsLevelOfDetail(bool value); private: bool m_supportsLevelOfDetail; }; #endif diff --git a/libs/image/filter/kis_filter_configuration.h b/libs/image/filter/kis_filter_configuration.h index b94b905c99..dbe9858c9a 100644 --- a/libs/image/filter/kis_filter_configuration.h +++ b/libs/image/filter/kis_filter_configuration.h @@ -1,138 +1,139 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_FILTER_CONFIGURATION_H_ #define _KIS_FILTER_CONFIGURATION_H_ #include #include "kis_properties_configuration.h" #include "kis_types.h" #include "kritaimage_export.h" /** * KisFilterConfiguration does inherit neither KisShared or QSharedData * so sometimes there might be problem with broken QSharedPointer counters. * This macro activates debugging routines for such stuff. * * In the future, please either port the entire KisNodeFilterInterface - * into KisSafeFilterConfigurationSP or derive filter configuration + * into KisFilterConfigurationSP or derive filter configuration * interface from QSharedData to handle these cases. */ #define SANITY_CHECK_FILTER_CONFIGURATION_OWNER /** * A KisFilterConfiguration is the serializable representation of * the filter parameters. Filters can subclass this class to implement * direct accessors to properties, but properties not in the map will * not be serialized. * * XXX: Use KoProperties here! */ class KRITAIMAGE_EXPORT KisFilterConfiguration : public KisPropertiesConfiguration { public: /** * Create a new filter config. */ KisFilterConfiguration(const QString & name, qint32 version); protected: /** * Deep copy the filter configFile */ KisFilterConfiguration(const KisFilterConfiguration & rhs); public: virtual ~KisFilterConfiguration(); public: /** * This function is use to convert from legacy XML as used in .kra file. */ virtual void fromLegacyXML(const QDomElement&); using KisPropertiesConfiguration::fromXML; using KisPropertiesConfiguration::toXML; virtual void fromXML(const QDomElement&); virtual void toXML(QDomDocument&, QDomElement&) const; /** * Get the unique, language independent name of the filter. */ const QString & name() const; /** * Get the version of the filter that has created this config */ qint32 version() const; /** * Check if that configuration is compatible with this paint device. * The default implementation always return true. */ virtual bool isCompatible(const KisPaintDeviceSP) const; /** * @return an array with each colorspace channel a true/false bit * that indicates whether the channel should be filtered or left * alone. It is up to the filter to decide whether channels that * are to be left alone are copied to the dest file or not. */ QBitArray channelFlags() const; /** * Set the channel flags. An empty array is allowed; that means * that all channels are to be filtered. Filters can optimize on * that. The array must be in the order of the pixel layout. */ void setChannelFlags(QBitArray channelFlags); /** * These functions exist solely to allow plugins to reimplement them as * needed, while allowing consumers to implement support for them without * linking directly to the plugin. In particular, the filter management * in Sketch requires this. */ virtual void setCurve(const KisCubicCurve &curve); virtual const KisCubicCurve& curve() const; virtual void setCurves(QList &curves); virtual const QList& curves() const; #ifdef SANITY_CHECK_FILTER_CONFIGURATION_OWNER private: friend class KisNodeFilterInterface; int sanityRefUsageCounter(); int sanityDerefUsageCounter(); #endif /* SANITY_CHECK_FILTER_CONFIGURATION_OWNER */ protected: void setVersion(qint32 version); private: struct Private; Private* const d; }; Q_DECLARE_METATYPE(KisFilterConfiguration*) + #endif // _KIS_FILTER_CONFIGURATION_H_ diff --git a/libs/image/filter/kis_filter_registry.cc b/libs/image/filter/kis_filter_registry.cc index 08d3fe66b8..6104ceaeff 100644 --- a/libs/image/filter/kis_filter_registry.cc +++ b/libs/image/filter/kis_filter_registry.cc @@ -1,81 +1,81 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2004-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 "filter/kis_filter_registry.h" #include #include #include #include #include #include "kis_debug.h" #include "kis_types.h" #include "kis_paint_device.h" #include "filter/kis_filter.h" #include "kis_filter_configuration.h" KisFilterRegistry::KisFilterRegistry(QObject *parent) : QObject(parent) { } KisFilterRegistry::~KisFilterRegistry() { dbgRegistry << "deleting KisFilterRegistry"; Q_FOREACH (KisFilterSP filter, values()) { remove(filter->id()); filter.clear(); } } KisFilterRegistry* KisFilterRegistry::instance() { KisFilterRegistry *reg = qApp->findChild(""); if (!reg) { reg = new KisFilterRegistry(qApp); KoPluginLoader::instance()->load("Krita/Filter", "Type == 'Service' and ([X-Krita-Version] == 28)"); } return reg; } void KisFilterRegistry::add(KisFilterSP item) { add(item->id(), item); } void KisFilterRegistry::add(const QString &id, KisFilterSP item) { KoGenericRegistry::add(id, item); emit(filterAdded(id)); } -KisFilterConfiguration* KisFilterRegistry::cloneConfiguration(KisFilterConfiguration* kfc) +KisFilterConfigurationSP KisFilterRegistry::cloneConfiguration(const KisFilterConfigurationSP kfc) { Q_ASSERT(kfc); KisFilterSP filter = value(kfc->name()); - KisFilterConfiguration* newkfc = filter->defaultConfiguration(0); + KisFilterConfigurationSP newkfc = filter->defaultConfiguration(0); newkfc->fromXML(kfc->toXML()); return newkfc; } diff --git a/libs/image/filter/kis_filter_registry.h b/libs/image/filter/kis_filter_registry.h index 845a47d44f..50cf6e2501 100644 --- a/libs/image/filter/kis_filter_registry.h +++ b/libs/image/filter/kis_filter_registry.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 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_FILTER_REGISTRY_H_ #define KIS_FILTER_REGISTRY_H_ #include #include "kis_filter.h" #include "kis_types.h" #include "KoGenericRegistry.h" #include class QString; class KisFilterConfiguration; class KRITAIMAGE_EXPORT KisFilterRegistry : public QObject, public KoGenericRegistry { Q_OBJECT public: virtual ~KisFilterRegistry(); static KisFilterRegistry* instance(); void add(KisFilterSP item); void add(const QString &id, KisFilterSP item); - KisFilterConfiguration* cloneConfiguration(KisFilterConfiguration*); + KisFilterConfigurationSP cloneConfiguration(const KisFilterConfigurationSP); Q_SIGNALS: void filterAdded(QString id); private: KisFilterRegistry(QObject *parent); KisFilterRegistry(const KisFilterRegistry&); KisFilterRegistry operator=(const KisFilterRegistry&); }; #endif // KIS_FILTERSPACE_REGISTRY_H_ diff --git a/libs/image/generator/kis_generator.cpp b/libs/image/generator/kis_generator.cpp index f8ee1f3cf7..d123e33145 100644 --- a/libs/image/generator/kis_generator.cpp +++ b/libs/image/generator/kis_generator.cpp @@ -1,57 +1,57 @@ /* * 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 "generator/kis_generator.h" #include #include "kis_bookmarked_configuration_manager.h" #include "filter/kis_filter_configuration.h" #include "kis_processing_information.h" #include "kis_paint_device.h" #include "kis_selection.h" #include "kis_types.h" KisGenerator::KisGenerator(const KoID& _id, const KoID & category, const QString & entry) : KisBaseProcessor(_id, category, entry) { init(id() + "_generator_bookmarks"); } KisGenerator::~KisGenerator() { } void KisGenerator::generate(KisProcessingInformation dst, const QSize& size, - const KisFilterConfiguration* config + const KisFilterConfigurationSP config ) const { generate(dst, size, config, 0); } const KoColorSpace * KisGenerator::colorSpace() { return 0; } -QRect KisGenerator::generatedRect(QRect _imageArea, const KisFilterConfiguration*) const +QRect KisGenerator::generatedRect(QRect _imageArea, const KisFilterConfigurationSP) const { return _imageArea; } diff --git a/libs/image/generator/kis_generator.h b/libs/image/generator/kis_generator.h index ec56bc7b1a..e7b113dffc 100644 --- a/libs/image/generator/kis_generator.h +++ b/libs/image/generator/kis_generator.h @@ -1,98 +1,98 @@ /* * 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. */ #ifndef _KIS_GENERATOR_H_ #define _KIS_GENERATOR_H_ #include #include #include "KoID.h" #include "KoColorSpace.h" #include "kis_types.h" #include "kis_base_processor.h" #include "kritaimage_export.h" class KisProcessingInformation; /** * Basic interface of a Krita generator: a generator is a program * that can fill a paint device with a color. A generator can have a * preferred colorspace. * * Generators can have initial parameter settings that determine the * way a particular generator works, but also state that allows the generator * to continue from one invocation of generate to another (handy for, e.g., * painting) */ class KRITAIMAGE_EXPORT KisGenerator : public KisBaseProcessor { friend class KisGeneratorConfigurationFactory; public: KisGenerator(const KoID& id, const KoID & category, const QString & entry); virtual ~KisGenerator(); public: /** * Override this function with the implementation of your generator. * * @param dst the destination paint device * @param size the size of the area that is to be filled * @param config the parameters of the filter */ virtual void generate(KisProcessingInformation dst, const QSize& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const = 0; /** * Provided for convenience when no progress reporting is needed. */ virtual void generate(KisProcessingInformation dst, const QSize& size, - const KisFilterConfiguration* config + const KisFilterConfigurationSP config ) const; /** * A generator may be specialized for working in a certain colorspace. * If so, this function returns in instance of that colorspace, else * it return 0. */ virtual const KoColorSpace * colorSpace(); /** * @param _imageArea the rectangle of the image * @return the rectangle that is affected by this generator, if the generator * is supposed to affect all pixels, then the function should return * @p _imageArea */ - virtual QRect generatedRect(QRect _imageArea, const KisFilterConfiguration* = 0) const; + virtual QRect generatedRect(QRect _imageArea, const KisFilterConfigurationSP = 0) const; protected: /// @return the name of config group in KConfig QString configEntryGroup() const; }; #endif diff --git a/libs/image/generator/kis_generator_layer.cpp b/libs/image/generator/kis_generator_layer.cpp index 24132118f4..cef1bd12ac 100644 --- a/libs/image/generator/kis_generator_layer.cpp +++ b/libs/image/generator/kis_generator_layer.cpp @@ -1,166 +1,166 @@ /* * 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 "kis_generator_layer.h" #include #include "kis_debug.h" #include #include #include "kis_selection.h" #include "filter/kis_filter_configuration.h" #include "kis_processing_information.h" #include "generator/kis_generator_registry.h" #include "generator/kis_generator.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" #include "kis_thread_safe_signal_compressor.h" #include "kis_recalculate_generator_layer_job.h" #define UPDATE_DELAY 100 /*ms */ struct Q_DECL_HIDDEN KisGeneratorLayer::Private { Private() : updateSignalCompressor(UPDATE_DELAY, KisSignalCompressor::FIRST_INACTIVE) { } KisThreadSafeSignalCompressor updateSignalCompressor; }; KisGeneratorLayer::KisGeneratorLayer(KisImageWSP image, const QString &name, - KisFilterConfiguration *kfc, + KisFilterConfigurationSP kfc, KisSelectionSP selection) : KisSelectionBasedLayer(image, name, selection, kfc, true), m_d(new Private) { connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDelayedStaticUpdate())); update(); } KisGeneratorLayer::KisGeneratorLayer(const KisGeneratorLayer& rhs) : KisSelectionBasedLayer(rhs), m_d(new Private) { connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDelayedStaticUpdate())); } KisGeneratorLayer::~KisGeneratorLayer() { } -void KisGeneratorLayer::setFilter(KisFilterConfiguration *filterConfig) +void KisGeneratorLayer::setFilter(KisFilterConfigurationSP filterConfig) { KisSelectionBasedLayer::setFilter(filterConfig); update(); } void KisGeneratorLayer::slotDelayedStaticUpdate() { /** * The mask might have been deleted from the layers stack in the * meanwhile. Just ignore the updates in the case. */ KisLayerSP parentLayer = dynamic_cast(parent().data()); if (!parentLayer) return; KisImageSP image = parentLayer->image(); if (image) { image->addSpontaneousJob(new KisRecalculateGeneratorLayerJob(this)); } } void KisGeneratorLayer::update() { - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); if (!filterConfig) { warnImage << "BUG: No Filter configuration in KisGeneratorLayer"; return; } KisGeneratorSP f = KisGeneratorRegistry::instance()->value(filterConfig->name()); if (!f) return; QRect processRect = exactBounds(); resetCache(f->colorSpace()); KisPaintDeviceSP originalDevice = original(); KisProcessingInformation dstCfg(originalDevice, processRect.topLeft(), 0); f->generate(dstCfg, processRect.size(), filterConfig.data()); // hack alert! // this avoids cyclic loop with KisRecalculateGeneratorLayerJob::run() KisSelectionBasedLayer::setDirty(extent()); } bool KisGeneratorLayer::accept(KisNodeVisitor & v) { return v.visit(this); } void KisGeneratorLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { return visitor.visit(this, undoAdapter); } QIcon KisGeneratorLayer::icon() const { return KisIconUtils::loadIcon("fillLayer"); } KisBaseNode::PropertyList KisGeneratorLayer::sectionModelProperties() const { - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); l << KisBaseNode::Property(KoID("generator", i18n("Generator")), KisGeneratorRegistry::instance()->value(filterConfig->name())->name()); return l; } void KisGeneratorLayer::setX(qint32 x) { KisSelectionBasedLayer::setX(x); m_d->updateSignalCompressor.start(); } void KisGeneratorLayer::setY(qint32 y) { KisSelectionBasedLayer::setY(y); m_d->updateSignalCompressor.start(); } void KisGeneratorLayer::setDirty(const QRect & rect) { KisSelectionBasedLayer::setDirty(rect); m_d->updateSignalCompressor.start(); } diff --git a/libs/image/generator/kis_generator_layer.h b/libs/image/generator/kis_generator_layer.h index 93b8cfe18d..dff2247f87 100644 --- a/libs/image/generator/kis_generator_layer.h +++ b/libs/image/generator/kis_generator_layer.h @@ -1,90 +1,90 @@ /* * 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. */ #ifndef KIS_GENERATOR_LAYER_H_ #define KIS_GENERATOR_LAYER_H_ #include "kis_selection_based_layer.h" #include #include class KisFilterConfiguration; /** * A generator layer is a special kind of layer that can be prefilled * with some pixel pattern generated by a KisGenerator plugin. * A KisGenerator is similar to a filter, but doesn't take * input pixel data and creates new pixel data. * * It is not possible to destructively paint on a generator layer. * * XXX: what about threadedness? */ class KRITAIMAGE_EXPORT KisGeneratorLayer : public KisSelectionBasedLayer { Q_OBJECT public: /** * Create a new Generator layer with the given configuration * and selection. Note that the selection will be _copied_ * (using COW, though). */ - KisGeneratorLayer(KisImageWSP image, const QString &name, KisFilterConfiguration * kfc, KisSelectionSP selection); + KisGeneratorLayer(KisImageWSP image, const QString &name, KisFilterConfigurationSP kfc, KisSelectionSP selection); KisGeneratorLayer(const KisGeneratorLayer& rhs); virtual ~KisGeneratorLayer(); KisNodeSP clone() const { return KisNodeSP(new KisGeneratorLayer(*this)); } - void setFilter(KisFilterConfiguration *filterConfig); + void setFilter(KisFilterConfigurationSP filterConfig); bool accept(KisNodeVisitor &); void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter); QIcon icon() const; KisBaseNode::PropertyList sectionModelProperties() const; /** * re-run the generator. This happens over the bounds * of the associated selection. */ void update(); using KisSelectionBasedLayer::setDirty; void setDirty(const QRect & rect); void setX(qint32 x); void setY(qint32 y); private Q_SLOTS: void slotDelayedStaticUpdate(); public: // KisIndirectPaintingSupport KisLayer* layer() { return this; } private: struct Private; const QScopedPointer m_d; }; #endif diff --git a/libs/image/generator/kis_generator_registry.cpp b/libs/image/generator/kis_generator_registry.cpp index 24bd2c20a5..5a969d9d80 100644 --- a/libs/image/generator/kis_generator_registry.cpp +++ b/libs/image/generator/kis_generator_registry.cpp @@ -1,80 +1,80 @@ /* * 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 "generator/kis_generator_registry.h" #include #include #include #include #include #include "filter/kis_filter_configuration.h" #include "kis_debug.h" #include "kis_types.h" #include "kis_paint_device.h" #include "generator/kis_generator.h" KisGeneratorRegistry::KisGeneratorRegistry(QObject *parent) : QObject(parent) { } KisGeneratorRegistry::~KisGeneratorRegistry() { Q_FOREACH (KisGeneratorSP generator, values()) { remove(generator->id()); generator.clear(); } dbgRegistry << "deleting KisGeneratorRegistry"; } KisGeneratorRegistry* KisGeneratorRegistry::instance() { KisGeneratorRegistry *reg = qApp->findChild(""); if (!reg) { reg = new KisGeneratorRegistry(qApp); KoPluginLoader::instance()->load("Krita/Generator", "Type == 'Service' and ([X-Krita-Version] == 28)"); } return reg; } void KisGeneratorRegistry::add(KisGeneratorSP item) { dbgPlugins << "adding " << item->name(); add(item->id(), item); } void KisGeneratorRegistry::add(const QString &id, KisGeneratorSP item) { dbgPlugins << "adding " << item->name() << " with id " << id; KoGenericRegistry::add(id, item); emit(generatorAdded(id)); } -KisFilterConfiguration* KisGeneratorRegistry::cloneConfiguration(KisFilterConfiguration* kfc) +KisFilterConfigurationSP KisGeneratorRegistry::cloneConfiguration(const KisFilterConfigurationSP kfc) { KisGeneratorSP filter = value(kfc->name()); - KisFilterConfiguration* newkfc = filter->defaultConfiguration(0); + KisFilterConfigurationSP newkfc = filter->defaultConfiguration(0); newkfc->fromXML(kfc->toXML()); return newkfc; } diff --git a/libs/image/generator/kis_generator_registry.h b/libs/image/generator/kis_generator_registry.h index 80e6c39820..800e214a96 100644 --- a/libs/image/generator/kis_generator_registry.h +++ b/libs/image/generator/kis_generator_registry.h @@ -1,60 +1,60 @@ /* * 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. */ #ifndef KIS_GENERATOR_REGISTRY_H_ #define KIS_GENERATOR_REGISTRY_H_ #include #include "kis_generator.h" #include "kis_types.h" #include "KoGenericRegistry.h" #include class QString; class KisFilterConfiguration; /** * XXX_DOCS */ class KRITAIMAGE_EXPORT KisGeneratorRegistry : public QObject, public KoGenericRegistry { Q_OBJECT public: virtual ~KisGeneratorRegistry(); static KisGeneratorRegistry* instance(); void add(KisGeneratorSP item); void add(const QString &id, KisGeneratorSP item); - KisFilterConfiguration* cloneConfiguration(KisFilterConfiguration* kfc); + KisFilterConfigurationSP cloneConfiguration(const KisFilterConfigurationSP kfc); Q_SIGNALS: void generatorAdded(QString id); private: KisGeneratorRegistry(QObject *parent); KisGeneratorRegistry(const KisGeneratorRegistry&); KisGeneratorRegistry operator=(const KisGeneratorRegistry&); }; #endif // KIS_GENERATOR_REGISTRY_H_ diff --git a/libs/image/kis_adjustment_layer.cc b/libs/image/kis_adjustment_layer.cc index 47654299a6..3ed3d4ff06 100644 --- a/libs/image/kis_adjustment_layer.cc +++ b/libs/image/kis_adjustment_layer.cc @@ -1,144 +1,144 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 C. Boemann * * 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_adjustment_layer.h" #include #include "kis_debug.h" #include #include #include #include "kis_image.h" #include "kis_selection.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" KisAdjustmentLayer::KisAdjustmentLayer(KisImageWSP image, const QString &name, - KisFilterConfiguration *kfc, + KisFilterConfigurationSP kfc, KisSelectionSP selection) : KisSelectionBasedLayer(image.data(), name, selection, kfc) { // by default Adjustment Layers have a copy composition, // which is more natural for users // https://bugs.kde.org/show_bug.cgi?id=324505 // https://bugs.kde.org/show_bug.cgi?id=294122 // demand the opposite from each other... setCompositeOpId(COMPOSITE_COPY); setUseSelectionInProjection(false); } KisAdjustmentLayer::KisAdjustmentLayer(const KisAdjustmentLayer& rhs) : KisSelectionBasedLayer(rhs) { } KisAdjustmentLayer::~KisAdjustmentLayer() { } -void KisAdjustmentLayer::setFilter(KisFilterConfiguration *filterConfig) +void KisAdjustmentLayer::setFilter(KisFilterConfigurationSP filterConfig) { filterConfig->setChannelFlags(channelFlags()); KisSelectionBasedLayer::setFilter(filterConfig); } QRect KisAdjustmentLayer::incomingChangeRect(const QRect &rect) const { - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); QRect filteredRect = rect; if (filterConfig) { KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); filteredRect = filter->changedRect(rect, filterConfig.data(), projection()->defaultBounds()->currentLevelOfDetail()); } /** * After the change in the blending using * setUseSelectionInProjection(false) we should *not* crop the * change rect of the layer, because we pass contents through. * * //filteredRect = cropChangeRectBySelection(filteredRect); */ return filteredRect; } QRect KisAdjustmentLayer::needRect(const QRect& rect, PositionToFilthy pos) const { Q_UNUSED(pos); - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); if (!filterConfig) return rect; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); /** * If we need some additional pixels even outside of a selection * for accurate layer filtering, we'll get them! * And no KisSelectionBasedLayer::needRect will prevent us * from doing this! ;) * That's why simply we do not call * KisSelectionBasedLayer::needRect here :) */ return filter->neededRect(rect, filterConfig.data(), projection()->defaultBounds()->currentLevelOfDetail()); } bool KisAdjustmentLayer::accept(KisNodeVisitor & v) { return v.visit(this); } void KisAdjustmentLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { return visitor.visit(this, undoAdapter); } QIcon KisAdjustmentLayer::icon() const { return KisIconUtils::loadIcon("filterLayer"); } KisBaseNode::PropertyList KisAdjustmentLayer::sectionModelProperties() const { - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); if (filterConfig) l << KisBaseNode::Property(KoID("filter", i18nc("property of a filter layer, noun", "Filter")), KisFilterRegistry::instance()->value(filterConfig->name())->name()); return l; } void KisAdjustmentLayer::setChannelFlags(const QBitArray & channelFlags) { - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); if (filterConfig) { filterConfig->setChannelFlags(channelFlags); } KisLayer::setChannelFlags(channelFlags); } diff --git a/libs/image/kis_adjustment_layer.h b/libs/image/kis_adjustment_layer.h index deb7a56c4c..fd003c3ff7 100644 --- a/libs/image/kis_adjustment_layer.h +++ b/libs/image/kis_adjustment_layer.h @@ -1,123 +1,123 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /** * @file * This file is part of the Krita calligra application. It handles * a contains a KisFilter OR a KisLayer, and this class is created * to influence the rendering of layers below this one. Can also * function as a fixating layer. * * @author Boudewijn Rempt * @author comments by hscott * @since 1.5 */ #ifndef KIS_ADJUSTMENT_LAYER_H_ #define KIS_ADJUSTMENT_LAYER_H_ #include #include #include "kis_selection_based_layer.h" class KisFilterConfiguration; /** * @class KisAdjustmentLayer Contains a KisFilter and a KisSelection. * If the selection is present, it is a mask used by the adjustment layer * to know where to apply the filter, thus the combination is used * to influence the rendering of the layers under this layer * in the layerstack. AdjustmentLayers also function as a kind * of "fixating layers". */ class KRITAIMAGE_EXPORT KisAdjustmentLayer : public KisSelectionBasedLayer { Q_OBJECT public: /** * creates a new adjustment layer with the given * configuration and selection. Note that the selection * will be _copied_ (with COW, though). * @param image the image to set this AdjustmentLayer to * @param name name of the adjustment layer * @param kfc the configuration for the adjustment layer filter * @param selection is a mask used by the adjustment layer to * know where to apply the filter. */ - KisAdjustmentLayer(KisImageWSP image, const QString &name, KisFilterConfiguration * kfc, KisSelectionSP selection); + KisAdjustmentLayer(KisImageWSP image, const QString &name, KisFilterConfigurationSP kfc, KisSelectionSP selection); KisAdjustmentLayer(const KisAdjustmentLayer& rhs); virtual ~KisAdjustmentLayer(); bool accept(KisNodeVisitor &); void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter); /** * clones this AdjustmentLayer into a KisNodeSP type. * @return the KisNodeSP returned */ KisNodeSP clone() const { return KisNodeSP(new KisAdjustmentLayer(*this)); } /** * gets the adjustmentLayer's tool filter * @return QIcon returns the QIcon tool filter */ QIcon icon() const; /** * gets the AdjustmentLayer properties describing whether * or not the node is locked, visible, and the filter * name is it is a filter. Overrides sectionModelProperties * in KisLayer, and KisLayer overrides * sectionModelProperties in KisBaseNode. * @return KisBaseNode::PropertyList returns a list * of the properties */ KisBaseNode::PropertyList sectionModelProperties() const; public: /** * \see KisNodeFilterInterface::setFilter() */ - void setFilter(KisFilterConfiguration *filterConfig); + void setFilter(KisFilterConfigurationSP filterConfig); void setChannelFlags(const QBitArray & channelFlags); protected: // override from KisLayer QRect incomingChangeRect(const QRect &rect) const; // override from KisNode QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const; public Q_SLOTS: /** * gets this AdjustmentLayer. Overrides function in * KisIndirectPaintingSupport * @return this AdjustmentLayer */ KisLayer* layer() { return this; } }; #endif // KIS_ADJUSTMENT_LAYER_H_ diff --git a/libs/image/kis_async_merger.cpp b/libs/image/kis_async_merger.cpp index 0d2a95841c..8e9b5aab64 100644 --- a/libs/image/kis_async_merger.cpp +++ b/libs/image/kis_async_merger.cpp @@ -1,365 +1,365 @@ /* Copyright (c) Dmitry Kazakov , 2009 * * 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_async_merger.h" #include #include #include #include #include "kis_node_visitor.h" #include "kis_painter.h" #include "kis_layer.h" #include "kis_group_layer.h" #include "kis_adjustment_layer.h" #include "generator/kis_generator_layer.h" #include "kis_external_layer_iface.h" #include "kis_paint_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_clone_layer.h" #include "kis_processing_information.h" #include "kis_busy_progress_indicator.h" #include "kis_merge_walker.h" #include "kis_refresh_subtree_walker.h" #include "kis_abstract_projection_plane.h" //#define DEBUG_MERGER #ifdef DEBUG_MERGER #define DEBUG_NODE_ACTION(message, type, leaf, rect) \ qDebug() << message << type << ":" << leaf->node()->name() << rect #else #define DEBUG_NODE_ACTION(message, type, leaf, rect) #endif class KisUpdateOriginalVisitor : public KisNodeVisitor { public: KisUpdateOriginalVisitor(const QRect &updateRect, KisPaintDeviceSP projection, const QRect &cropRect) : m_updateRect(updateRect), m_cropRect(cropRect), m_projection(projection) { } ~KisUpdateOriginalVisitor() { } public: using KisNodeVisitor::visit; bool visit(KisAdjustmentLayer* layer) { if (!layer->visible()) return true; if (!m_projection) { warnImage << "ObligeChild mechanism has been activated for " "an adjustment layer! Do nothing..."; layer->original()->clear(); return true; } KisPaintDeviceSP originalDevice = layer->original(); originalDevice->clear(m_updateRect); const QRect applyRect = m_updateRect & m_projection->extent(); // If the intersection of the updaterect and the projection extent is // null, we are finish here. if(applyRect.isNull()) return true; - KisSafeFilterConfigurationSP filterConfig = layer->filter(); + KisFilterConfigurationSP filterConfig = layer->filter(); if (!filterConfig) { /** * When an adjustment layer is just created, it may have no * filter inside. Then the layer has work as a pass-through * node. Just copy the merged data to the layer's original. */ KisPainter::copyAreaOptimized(applyRect.topLeft(), m_projection, originalDevice, applyRect); return true; } KisSelectionSP selection = layer->fetchComposedInternalSelection(applyRect); const QRect filterRect = selection ? applyRect & selection->selectedRect() : applyRect; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); if (!filter) return false; KisPaintDeviceSP dstDevice = originalDevice; if (selection) { dstDevice = new KisPaintDevice(originalDevice->colorSpace()); } if (!filterRect.isEmpty()) { KIS_ASSERT_RECOVER_NOOP(layer->busyProgressIndicator()); layer->busyProgressIndicator()->update(); // We do not create a transaction here, as srcDevice != dstDevice filter->process(m_projection, dstDevice, 0, filterRect, filterConfig.data(), 0); } if (selection) { KisPainter::copyAreaOptimized(applyRect.topLeft(), m_projection, originalDevice, applyRect); KisPainter::copyAreaOptimized(filterRect.topLeft(), dstDevice, originalDevice, filterRect, selection); } return true; } bool visit(KisExternalLayer*) { return true; } bool visit(KisGeneratorLayer*) { return true; } bool visit(KisPaintLayer*) { return true; } bool visit(KisGroupLayer*) { return true; } bool visit(KisCloneLayer *layer) { QRect emptyRect; KisRefreshSubtreeWalker walker(emptyRect); KisAsyncMerger merger; KisLayerSP srcLayer = layer->copyFrom(); QRect srcRect = m_updateRect.translated(-layer->x(), -layer->y()); QRegion prepareRegion(srcRect); prepareRegion -= m_cropRect; /** * If a clone has complicated masks, we should prepare additional * source area to ensure the rect is prepared. */ QRect needRectOnSource = layer->needRectOnSourceForMasks(srcRect); if (!needRectOnSource.isEmpty()) { prepareRegion += needRectOnSource; } Q_FOREACH (const QRect &rect, prepareRegion.rects()) { walker.collectRects(srcLayer, rect); merger.startMerge(walker, false); } return true; } bool visit(KisNode*) { return true; } bool visit(KisFilterMask*) { return true; } bool visit(KisTransformMask*) { return true; } bool visit(KisTransparencyMask*) { return true; } bool visit(KisSelectionMask*) { return true; } bool visit(KisColorizeMask*) { return true; } private: QRect m_updateRect; QRect m_cropRect; KisPaintDeviceSP m_projection; }; /*********************************************************************/ /* KisAsyncMerger */ /*********************************************************************/ void KisAsyncMerger::startMerge(KisBaseRectsWalker &walker, bool notifyClones) { KisMergeWalker::LeafStack &leafStack = walker.leafStack(); const bool useTempProjections = walker.needRectVaries(); while(!leafStack.isEmpty()) { KisMergeWalker::JobItem item = leafStack.pop(); KisProjectionLeafSP currentLeaf = item.m_leaf; if(currentLeaf->isRoot()) continue; // All the masks should be filtered by the walkers Q_ASSERT(currentLeaf->isLayer()); QRect applyRect = item.m_applyRect; if(item.m_position & KisMergeWalker::N_EXTRA) { // The type of layers that will not go to projection. DEBUG_NODE_ACTION("Updating", "N_EXTRA", currentLeaf, applyRect); KisUpdateOriginalVisitor originalVisitor(applyRect, m_currentProjection, walker.cropRect()); currentLeaf->accept(originalVisitor); currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node()); continue; } if(!m_currentProjection) setupProjection(currentLeaf, applyRect, useTempProjections); KisUpdateOriginalVisitor originalVisitor(applyRect, m_currentProjection, walker.cropRect()); if(item.m_position & KisMergeWalker::N_FILTHY) { DEBUG_NODE_ACTION("Updating", "N_FILTHY", currentLeaf, applyRect); currentLeaf->accept(originalVisitor); if (currentLeaf->visible()) { currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode()); } } else if(item.m_position & KisMergeWalker::N_ABOVE_FILTHY) { DEBUG_NODE_ACTION("Updating", "N_ABOVE_FILTHY", currentLeaf, applyRect); if(currentLeaf->dependsOnLowerNodes()) { currentLeaf->accept(originalVisitor); if (currentLeaf->visible()) { currentLeaf->projectionPlane()->recalculate(applyRect, currentLeaf->node()); } } } else if(item.m_position & KisMergeWalker::N_FILTHY_PROJECTION) { DEBUG_NODE_ACTION("Updating", "N_FILTHY_PROJECTION", currentLeaf, applyRect); if (currentLeaf->visible()) { currentLeaf->projectionPlane()->recalculate(applyRect, walker.startNode()); } } else /*if(item.m_position & KisMergeWalker::N_BELOW_FILTHY)*/ { DEBUG_NODE_ACTION("Updating", "N_BELOW_FILTHY", currentLeaf, applyRect); /* nothing to do */ } compositeWithProjection(currentLeaf, applyRect); if(item.m_position & KisMergeWalker::N_TOPMOST) { writeProjection(currentLeaf, useTempProjections, applyRect); resetProjection(); } // FIXME: remove it from the inner loop and/or change to a warning! Q_ASSERT(currentLeaf->projection()->defaultBounds()->currentLevelOfDetail() == walker.levelOfDetail()); } if(notifyClones) { doNotifyClones(walker); } if(m_currentProjection) { warnImage << "BUG: The walker hasn't reached the root layer!"; warnImage << " Start node:" << walker.startNode() << "Requested rect:" << walker.requestedRect(); warnImage << " There must be an inconsistency in the walkers happened!"; warnImage << " Please report a bug describing how you got this message."; // reset projection to avoid artefacts in next merges and allow people to work further resetProjection(); } } void KisAsyncMerger::resetProjection() { m_currentProjection = 0; m_finalProjection = 0; } void KisAsyncMerger::setupProjection(KisProjectionLeafSP currentLeaf, const QRect& rect, bool useTempProjection) { KisPaintDeviceSP parentOriginal = currentLeaf->parent()->original(); if (parentOriginal != currentLeaf->projection()) { if (useTempProjection) { if(!m_cachedPaintDevice) m_cachedPaintDevice = new KisPaintDevice(parentOriginal->colorSpace()); m_currentProjection = m_cachedPaintDevice; m_currentProjection->prepareClone(parentOriginal); m_finalProjection = parentOriginal; } else { parentOriginal->clear(rect); m_finalProjection = m_currentProjection = parentOriginal; } } else { /** * It happened so that our parent uses our own projection as * its original. It means obligeChild mechanism works. * We won't initialise m_currentProjection. This will cause * writeProjection() and compositeWithProjection() do nothing * when called. */ /* NOP */ } } void KisAsyncMerger::writeProjection(KisProjectionLeafSP topmostLeaf, bool useTempProjection, const QRect &rect) { Q_UNUSED(useTempProjection); Q_UNUSED(topmostLeaf); if (!m_currentProjection) return; if(m_currentProjection != m_finalProjection) { KisPainter::copyAreaOptimized(rect.topLeft(), m_currentProjection, m_finalProjection, rect); } DEBUG_NODE_ACTION("Writing projection", "", topmostLeaf->parent(), rect); } bool KisAsyncMerger::compositeWithProjection(KisProjectionLeafSP leaf, const QRect &rect) { if (!m_currentProjection) return true; if (!leaf->visible()) return true; KisPainter gc(m_currentProjection); leaf->projectionPlane()->apply(&gc, rect); DEBUG_NODE_ACTION("Compositing projection", "", leaf, rect); return true; } void KisAsyncMerger::doNotifyClones(KisBaseRectsWalker &walker) { KisBaseRectsWalker::CloneNotificationsVector &vector = walker.cloneNotifications(); KisBaseRectsWalker::CloneNotificationsVector::iterator it; for(it = vector.begin(); it != vector.end(); ++it) { (*it).notify(); } } diff --git a/libs/image/kis_base_processor.cpp b/libs/image/kis_base_processor.cpp index 6e132dc41a..84e59d94c6 100644 --- a/libs/image/kis_base_processor.cpp +++ b/libs/image/kis_base_processor.cpp @@ -1,198 +1,198 @@ /* * Copyright (c) 2004,2006-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. */ #include "kis_base_processor.h" #include #include "kis_bookmarked_configuration_manager.h" #include "filter/kis_filter_configuration.h" #include "kis_paint_device.h" #include "kis_selection.h" class KisBaseProcessorConfigurationFactory : public KisSerializableConfigurationFactory { public: KisBaseProcessorConfigurationFactory(KisBaseProcessor* _generator) : m_generator(_generator) {} virtual ~KisBaseProcessorConfigurationFactory() {} - virtual KisSerializableConfiguration* createDefault() { + virtual KisSerializableConfigurationSP createDefault() { return m_generator->factoryConfiguration(0); } - virtual KisSerializableConfiguration* create(const QDomElement& e) { - KisSerializableConfiguration* config = m_generator->factoryConfiguration(0); + virtual KisSerializableConfigurationSP create(const QDomElement& e) { + KisSerializableConfigurationSP config = m_generator->factoryConfiguration(0); config->fromXML(e); return config; } private: KisBaseProcessor* m_generator; }; struct Q_DECL_HIDDEN KisBaseProcessor::Private { Private() : bookmarkManager(0) , supportsPainting(false) , supportsAdjustmentLayers(true) , supportsThreading(true) , showConfigurationWidget(true) , colorSpaceIndependence(FULLY_INDEPENDENT) { } KisBookmarkedConfigurationManager* bookmarkManager; KoID id; KoID category; // The category in the filter menu this filter fits QString entry; // the i18n'ed accelerated menu text QKeySequence shortcut; bool supportsPainting; bool supportsAdjustmentLayers; bool supportsThreading; bool showConfigurationWidget; ColorSpaceIndependence colorSpaceIndependence; }; KisBaseProcessor::KisBaseProcessor(const KoID& id, const KoID & category, const QString & entry) : d(new Private) { d->id = id; d->category = category; d->entry = entry; } void KisBaseProcessor::init(const QString& configEntryGroup) { d->bookmarkManager = new KisBookmarkedConfigurationManager(configEntryGroup, new KisBaseProcessorConfigurationFactory(this)); } KisBaseProcessor::~KisBaseProcessor() { delete d->bookmarkManager; delete d; } -KisFilterConfiguration * KisBaseProcessor::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisBaseProcessor::factoryConfiguration(const KisPaintDeviceSP) const { return new KisFilterConfiguration(id(), 0); } -KisFilterConfiguration * KisBaseProcessor::defaultConfiguration(const KisPaintDeviceSP pd) const +KisFilterConfigurationSP KisBaseProcessor::defaultConfiguration(const KisPaintDeviceSP pd) const { - KisFilterConfiguration* fc = 0; + KisFilterConfigurationSP fc = 0; // if (bookmarkManager()) { // fc = dynamic_cast(bookmarkManager()->defaultConfiguration()); // } if (!fc || !fc->isCompatible(pd)) { fc = factoryConfiguration(pd); } return fc; } KisConfigWidget * KisBaseProcessor::createConfigurationWidget(QWidget *, const KisPaintDeviceSP) const { return 0; } KisBookmarkedConfigurationManager* KisBaseProcessor::bookmarkManager() { return d->bookmarkManager; } const KisBookmarkedConfigurationManager* KisBaseProcessor::bookmarkManager() const { return d->bookmarkManager; } QString KisBaseProcessor::id() const { return d->id.id(); } QString KisBaseProcessor::name() const { return d->id.name(); } KoID KisBaseProcessor::menuCategory() const { return d->category; } QString KisBaseProcessor::menuEntry() const { return d->entry; } QKeySequence KisBaseProcessor::shortcut() const { return d->shortcut; } void KisBaseProcessor::setShortcut(const QKeySequence & shortcut) { d->shortcut = shortcut; } bool KisBaseProcessor::supportsPainting() const { return d->supportsPainting; } bool KisBaseProcessor::supportsAdjustmentLayers() const { return d->supportsAdjustmentLayers; } bool KisBaseProcessor::supportsThreading() const { return d->supportsThreading; } ColorSpaceIndependence KisBaseProcessor::colorSpaceIndependence() const { return d->colorSpaceIndependence; } void KisBaseProcessor::setSupportsPainting(bool v) { d->supportsPainting = v; } void KisBaseProcessor::setSupportsAdjustmentLayers(bool v) { d->supportsAdjustmentLayers = v; } void KisBaseProcessor::setSupportsThreading(bool v) { d->supportsThreading = v; } void KisBaseProcessor::setColorSpaceIndependence(ColorSpaceIndependence v) { d->colorSpaceIndependence = v; } bool KisBaseProcessor::showConfigurationWidget() { return d->showConfigurationWidget; } void KisBaseProcessor::setShowConfigurationWidget(bool v) { d->showConfigurationWidget = v; } diff --git a/libs/image/kis_base_processor.h b/libs/image/kis_base_processor.h index 8354ff6063..65c857da8a 100644 --- a/libs/image/kis_base_processor.h +++ b/libs/image/kis_base_processor.h @@ -1,167 +1,167 @@ /* * 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. */ #ifndef _KIS_BASE_PROCESSOR_H_ #define _KIS_BASE_PROCESSOR_H_ #include #include #include #include #include "KoID.h" #include "KoColorSpace.h" #include "kis_types.h" #include "kis_shared.h" #include "kis_image.h" #include "kritaimage_export.h" class QWidget; class KisBookmarkedConfigurationManager; class KisFilterConfiguration; class KisConfigWidget; /** * Base class for classes that process areas of pixels. * Processors can either read in pixels and write out pixels * or just write out pixels, using a certain set of configuation * pixels. * * in-out processing is typically filtering: @see KisFilter. * out-only processing is typically generating: @see KisGenerator. * * Information about the area that needs to be processed is contained * @see KisProcessingInformation and @see KisConstProcessingInformation. */ class KRITAIMAGE_EXPORT KisBaseProcessor : public KisShared { friend class KisBaseProcessorConfigurationFactory; public: KisBaseProcessor(const KoID& id, const KoID & category, const QString & entry); virtual ~KisBaseProcessor(); /** * Return the configuration set as the default by the user or the default * configuration from the filter writer as returned by factoryConfiguration. * * This configuration is used by default for the configuration widget and * given to the process function if there is no configuration widget. * * @return the default configuration of this widget */ - KisFilterConfiguration * defaultConfiguration(const KisPaintDeviceSP) const; + KisFilterConfigurationSP defaultConfiguration(const KisPaintDeviceSP) const; /** * @return the bookmark manager for this processor */ KisBookmarkedConfigurationManager* bookmarkManager(); /** * @return the bookmark manager for this processor */ const KisBookmarkedConfigurationManager* bookmarkManager() const; /// @return Unique identification for this processor QString id() const; /// @return User-visible identification for this processor QString name() const; /// @return the submenu in the filters menu does processor want to go? KoID menuCategory() const; /// @return the i18n'ed string this filter wants to show itself in the menu QString menuEntry() const; /** * Return the default keyboard shortcut for activation of this filter * * @return the shortcut */ QKeySequence shortcut() const; /** * Create the configuration widget for this processor. * * @param parent the Qt owner widget of this widget * @param dev the paintdevice this filter will act on */ virtual KisConfigWidget * createConfigurationWidget(QWidget * parent, const KisPaintDeviceSP dev) const; // "Support" functions public: /** * If true, this filter can be used in painting tools as a paint operation */ bool supportsPainting() const; /// This filter can be used in adjustment layers bool supportsAdjustmentLayers() const; /** * This filter supports cutting up the work area and filtering * each chunk in a separate thread. Filters that need access to the * whole area for correct computations should return false. */ bool supportsThreading() const; /// If true, the filter wants to show a configuration widget bool showConfigurationWidget(); /** * Determine the colorspace independence of this filter. * @see ColorSpaceIndependence * * @return the degree of independence */ ColorSpaceIndependence colorSpaceIndependence() const; /// @return the default configuration as defined by whoever wrote the plugin - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; - + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; + protected: void setSupportsPainting(bool v); void setSupportsAdjustmentLayers(bool v); void setSupportsThreading(bool v); void setColorSpaceIndependence(ColorSpaceIndependence v); void setShowConfigurationWidget(bool v); /** * Set the default shortcut for activation of this filter. */ void setShortcut(const QKeySequence & shortcut); protected: void init(const QString& configEntryGroup); private: struct Private; Private* const d; }; #endif diff --git a/libs/image/kis_bookmarked_configuration_manager.cc b/libs/image/kis_bookmarked_configuration_manager.cc index 256f9cada1..6617c6ce4c 100644 --- a/libs/image/kis_bookmarked_configuration_manager.cc +++ b/libs/image/kis_bookmarked_configuration_manager.cc @@ -1,143 +1,143 @@ /* * 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. */ #include "kis_bookmarked_configuration_manager.h" #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "kis_serializable_configuration.h" const char KisBookmarkedConfigurationManager::ConfigDefault[] = "Default"; const char KisBookmarkedConfigurationManager::ConfigLastUsed[] = "Last Used"; struct Q_DECL_HIDDEN KisBookmarkedConfigurationManager::Private { QString configEntryGroup; KisSerializableConfigurationFactory* configFactory; }; KisBookmarkedConfigurationManager::KisBookmarkedConfigurationManager(const QString & configEntryGroup, KisSerializableConfigurationFactory* configFactory) : d(new Private) { d->configEntryGroup = configEntryGroup; d->configFactory = configFactory; } KisBookmarkedConfigurationManager::~KisBookmarkedConfigurationManager() { delete d->configFactory; delete d; } -KisSerializableConfiguration* KisBookmarkedConfigurationManager::load(const QString & configname) const +KisSerializableConfigurationSP KisBookmarkedConfigurationManager::load(const QString & configname) const { if (!exists(configname)) { if (configname == KisBookmarkedConfigurationManager::ConfigDefault) return d->configFactory->createDefault(); else return 0; } KConfigGroup cfg = KSharedConfig::openConfig()->group(configEntryGroup()); QDomDocument doc; doc.setContent(cfg.readEntry(configname, "")); QDomElement e = doc.documentElement(); - KisSerializableConfiguration* config = d->configFactory->create(e); + KisSerializableConfigurationSP config = d->configFactory->create(e); dbgImage << config << endl; return config; } -void KisBookmarkedConfigurationManager::save(const QString & configname, const KisSerializableConfiguration* config) +void KisBookmarkedConfigurationManager::save(const QString & configname, const KisSerializableConfigurationSP config) { dbgImage << "Saving configuration " << config << " to " << configname; if (!config) return; KConfigGroup cfg = KSharedConfig::openConfig()->group(configEntryGroup()); cfg.writeEntry(configname, config->toXML()); } bool KisBookmarkedConfigurationManager::exists(const QString & configname) const { KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); QMap< QString, QString > m = cfg->entryMap(configEntryGroup()); return (m.find(configname) != m.end()); } QList KisBookmarkedConfigurationManager::configurations() const { KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); QMap< QString, QString > m = cfg->entryMap(configEntryGroup()); QList keys = m.keys(); QList configsKey; Q_FOREACH (const QString & key, keys) { if (key != KisBookmarkedConfigurationManager::ConfigDefault && key != KisBookmarkedConfigurationManager::ConfigLastUsed) { configsKey << key; } } return configsKey; } -KisSerializableConfiguration* KisBookmarkedConfigurationManager::defaultConfiguration() const +KisSerializableConfigurationSP KisBookmarkedConfigurationManager::defaultConfiguration() const { if (exists(KisBookmarkedConfigurationManager::ConfigDefault)) { return load(KisBookmarkedConfigurationManager::ConfigDefault); } if (exists(KisBookmarkedConfigurationManager::ConfigLastUsed)) { return load(KisBookmarkedConfigurationManager::ConfigLastUsed); } return 0; } QString KisBookmarkedConfigurationManager::configEntryGroup() const { return d->configEntryGroup; } void KisBookmarkedConfigurationManager::remove(const QString & name) { KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); KConfigGroup group = cfg->group(configEntryGroup()); group.deleteEntry(name); } QString KisBookmarkedConfigurationManager::uniqueName(const KLocalizedString & base) { #ifndef QT_NO_DEBUG QString prev; #endif int nb = 1; while (true) { QString cur = base.subs(nb++).toString(); if (!exists(cur)) return cur; #ifndef QT_NO_DEBUG Q_ASSERT(prev != cur); prev = cur; #endif } } diff --git a/libs/image/kis_bookmarked_configuration_manager.h b/libs/image/kis_bookmarked_configuration_manager.h index 304a105d47..6acbb28ed7 100644 --- a/libs/image/kis_bookmarked_configuration_manager.h +++ b/libs/image/kis_bookmarked_configuration_manager.h @@ -1,86 +1,85 @@ /* * 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_BOOKMARKED_CONFIGURATION_MANAGER_H_ #define _KIS_BOOKMARKED_CONFIGURATION_MANAGER_H_ #include +#include "kis_serializable_configuration.h" -class KisSerializableConfiguration; -class KisSerializableConfigurationFactory; class QString; class KLocalizedString; #include "kritaimage_export.h" class KRITAIMAGE_EXPORT KisBookmarkedConfigurationManager { public: static const char ConfigDefault[]; static const char ConfigLastUsed[]; public: /** * @param configEntryGroup name of the configuration entry with the * bookmarked configurations. */ KisBookmarkedConfigurationManager(const QString & configEntryGroup, KisSerializableConfigurationFactory*); ~KisBookmarkedConfigurationManager(); /** * Load the configuration. */ - KisSerializableConfiguration* load(const QString & configname) const; + KisSerializableConfigurationSP load(const QString & configname) const; /** * Save the configuration. */ - void save(const QString & configname, const KisSerializableConfiguration*); + void save(const QString & configname, const KisSerializableConfigurationSP); /** * @return true if the configuration configname exists */ bool exists(const QString & configname) const; /** * @return the list of the names of configurations. */ QList configurations() const; /** * @return the default configuration */ - KisSerializableConfiguration* defaultConfiguration() const; + KisSerializableConfigurationSP defaultConfiguration() const; /** * Remove a bookmarked configuration */ void remove(const QString & name); /** * Generate an unique name, for instance when the user is creating a new * entry. * @param base the base of the new name, including a "%1" for incrementing * the number, for instance : "New Configuration %1", then this function * will return the string where %1 will be replaced by the lowest number * and be inexistant in the lists of configuration */ QString uniqueName(const KLocalizedString & base); private: QString configEntryGroup() const; private: struct Private; Private* const d; }; #endif diff --git a/libs/image/kis_config_widget.h b/libs/image/kis_config_widget.h index 4c4674079f..872920b9b1 100644 --- a/libs/image/kis_config_widget.h +++ b/libs/image/kis_config_widget.h @@ -1,92 +1,92 @@ /* * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2004-2006 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_CONFIG_WIDGET_H_ #define _KIS_CONFIG_WIDGET_H_ #include #include #include "kis_signal_compressor.h" +#include class KisViewManager; -class KisPropertiesConfiguration; /** * Empty base class. Configurable resources like filters, paintops etc. * can build their own configuration widgets that inherit this class. * The configuration widget should emit sigConfigurationItemChanged * when it wants a preview updated; there is a timer that * waits a little time to see if there are more changes coming * and then emits sigConfigurationUpdated. */ class KRITAIMAGE_EXPORT KisConfigWidget : public QWidget { Q_OBJECT protected: KisConfigWidget(QWidget * parent = 0, Qt::WFlags f = 0, int delay = 200); public: virtual ~KisConfigWidget(); /** * @param config the configuration for this configuration widget. */ - virtual void setConfiguration(const KisPropertiesConfiguration * config) = 0; + virtual void setConfiguration(const KisPropertiesConfigurationSP config) = 0; /** * @return the configuration */ - virtual KisPropertiesConfiguration* configuration() const = 0; + virtual KisPropertiesConfigurationSP configuration() const = 0; /** * Sets the view object that can be used by the configuration * widget for richer functionality */ virtual void setView(KisViewManager *view); Q_SIGNALS: /** * emitted whenever it makes sense to update the preview */ void sigConfigurationUpdated(); /** * Subclasses should emit this signal whenever the preview should be * be recalculated. This kicks of a timer, so it's perfectly fine * to connect this to the changed signals of the widgets in your configuration * widget. */ void sigConfigurationItemChanged(); - void sigSaveLockedConfig(KisPropertiesConfiguration* p); - void sigDropLockedConfig(KisPropertiesConfiguration* p); + void sigSaveLockedConfig(KisPropertiesConfigurationSP p); + void sigDropLockedConfig(KisPropertiesConfigurationSP p); private Q_SLOTS: void slotConfigChanged(); private: KisSignalCompressor m_compressor; }; #endif diff --git a/libs/image/kis_fill_painter.cc b/libs/image/kis_fill_painter.cc index 2a46de97f3..ab3bdc5f90 100644 --- a/libs/image/kis_fill_painter.cc +++ b/libs/image/kis_fill_painter.cc @@ -1,323 +1,323 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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_fill_painter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "generator/kis_generator.h" #include "filter/kis_filter_configuration.h" #include "generator/kis_generator_registry.h" #include "kis_processing_information.h" #include "kis_debug.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include #include "KoColorSpace.h" #include "kis_transaction.h" #include "kis_pixel_selection.h" #include #include #include "kis_random_accessor_ng.h" #include "kis_selection_filters.h" KisFillPainter::KisFillPainter() : KisPainter() { initFillPainter(); } KisFillPainter::KisFillPainter(KisPaintDeviceSP device) : KisPainter(device) { initFillPainter(); } KisFillPainter::KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection) : KisPainter(device, selection) { initFillPainter(); } void KisFillPainter::initFillPainter() { m_width = m_height = -1; m_careForSelection = false; m_sizemod = 0; m_feather = 0; m_useCompositioning = false; m_threshold = 0; } void KisFillPainter::fillSelection(const QRect &rc, const KoColor &color) { KisPaintDeviceSP fillDevice = new KisPaintDevice(device()->colorSpace()); fillDevice->setDefaultPixel(color); bitBlt(rc.topLeft(), fillDevice, rc); } // 'regular' filling // XXX: This also needs renaming, since filling ought to keep the opacity and the composite op in mind, // this is more eraseToColor. void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoColor& kc, quint8 opacity) { if (w > 0 && h > 0) { // Make sure we're in the right colorspace KoColor kc2(kc); // get rid of const kc2.convertTo(device()->colorSpace()); quint8 * data = kc2.data(); device()->colorSpace()->setOpacity(data, opacity, 1); device()->fill(x1, y1, w, h, data); addDirtyRect(QRect(x1, y1, w, h)); } } void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPattern * pattern) { if (!pattern) return; if (!pattern->valid()) return; if (!device()) return; if (w < 1) return; if (h < 1) return; KisPaintDeviceSP patternLayer = new KisPaintDevice(device()->compositionSourceColorSpace(), pattern->name()); patternLayer->convertFromQImage(pattern->pattern(), 0); fillRect(x1, y1, w, h, patternLayer, QRect(0, 0, pattern->width(), pattern->height())); } void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect) { Q_ASSERT(deviceRect.x() == 0); // the case x,y != 0,0 is not yet implemented Q_ASSERT(deviceRect.y() == 0); int sx, sy, sw, sh; int y = y1; if (y >= 0) { sy = y % deviceRect.height(); } else { sy = deviceRect.height() - (((-y - 1) % deviceRect.height()) + 1); } while (y < y1 + h) { sh = qMin((y1 + h) - y, deviceRect.height() - sy); int x = x1; if (x >= 0) { sx = x % deviceRect.width(); } else { sx = deviceRect.width() - (((-x - 1) % deviceRect.width()) + 1); } while (x < x1 + w) { sw = qMin((x1 + w) - x, deviceRect.width() - sx); bitBlt(x, y, device, sx, sy, sw, sh); x += sw; sx = 0; } y += sh; sy = 0; } addDirtyRect(QRect(x1, y1, w, h)); } -void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfiguration* generator) +void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator) { if (!generator) return; KisGeneratorSP g = KisGeneratorRegistry::instance()->value(generator->name()); if (!device()) return; if (w < 1) return; if (h < 1) return; QRect tmpRc(x1, y1, w, h); KisProcessingInformation dstCfg(device(), tmpRc.topLeft(), 0); g->generate(dstCfg, tmpRc.size(), generator); addDirtyRect(tmpRc); } // flood filling void KisFillPainter::fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice) { if (!m_useCompositioning) { if (m_sizemod || m_feather || compositeOp()->id() != COMPOSITE_OVER || opacity() != MAX_SELECTED || sourceDevice != device()) { warnKrita << "WARNING: Fast Flood Fill (no compositioning mode)" << "does not support compositeOps, opacity, " << "selection enhancements and separate source " << "devices"; } QRect fillBoundsRect(0, 0, m_width, m_height); QPoint startPoint(startX, startY); if (!fillBoundsRect.contains(startPoint)) return; KisScanlineFill gc(device(), startPoint, fillBoundsRect); gc.setThreshold(m_threshold); gc.fillColor(paintColor()); } else { genericFillStart(startX, startY, sourceDevice); // Now create a layer and fill it KisPaintDeviceSP filled = device()->createCompositionSourceDevice(); Q_CHECK_PTR(filled); KisFillPainter painter(filled); painter.fillRect(0, 0, m_width, m_height, paintColor()); painter.end(); genericFillEnd(filled); } } void KisFillPainter::fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice) { genericFillStart(startX, startY, sourceDevice); // Now create a layer and fill it KisPaintDeviceSP filled = device()->createCompositionSourceDevice(); Q_CHECK_PTR(filled); KisFillPainter painter(filled); painter.fillRect(0, 0, m_width, m_height, pattern()); painter.end(); genericFillEnd(filled); } void KisFillPainter::genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice) { Q_ASSERT(m_width > 0); Q_ASSERT(m_height > 0); // Create a selection from the surrounding area m_fillSelection = createFloodSelection(startX, startY, sourceDevice); } void KisFillPainter::genericFillEnd(KisPaintDeviceSP filled) { if (progressUpdater() && progressUpdater()->interrupted()) { m_width = m_height = -1; return; } // TODO: filling using the correct bound of the selection would be better, *but* // the selection is limited to the exact bound of a layer, while in reality, we don't // want that, since we want a transparent layer to be completely filled // QRect rc = m_fillSelection->selectedExactRect(); /** * Apply the real selection to a filled one */ KisSelectionSP realSelection = selection(); if (realSelection) { m_fillSelection->pixelSelection()->applySelection( realSelection->projection(), SELECTION_INTERSECT); } setSelection(m_fillSelection); bitBlt(0, 0, filled, 0, 0, m_width, m_height); setSelection(realSelection); if (progressUpdater()) progressUpdater()->setProgress(100); m_width = m_height = -1; } KisSelectionSP KisFillPainter::createFloodSelection(int startX, int startY, KisPaintDeviceSP sourceDevice) { if (m_width < 0 || m_height < 0) { if (selection() && m_careForSelection) { QRect rc = selection()->selectedExactRect(); m_width = rc.width() - (startX - rc.x()); m_height = rc.height() - (startY - rc.y()); } } dbgImage << "Width: " << m_width << " Height: " << m_height; // Otherwise the width and height should have been set Q_ASSERT(m_width > 0 && m_height > 0); QRect fillBoundsRect(0, 0, m_width, m_height); QPoint startPoint(startX, startY); KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(device())); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); if (!fillBoundsRect.contains(startPoint)) { return selection; } KisScanlineFill gc(sourceDevice, startPoint, fillBoundsRect); gc.setThreshold(m_threshold); gc.fillSelection(pixelSelection); if (m_sizemod > 0) { KisGrowSelectionFilter biggy(m_sizemod, m_sizemod); biggy.process(pixelSelection, selection->selectedRect().adjusted(-m_sizemod, -m_sizemod, m_sizemod, m_sizemod)); } else if (m_sizemod < 0) { KisShrinkSelectionFilter tiny(-m_sizemod, -m_sizemod, false); tiny.process(pixelSelection, selection->selectedRect()); } if (m_feather > 0) { KisFeatherSelectionFilter feathery(m_feather); feathery.process(pixelSelection, selection->selectedRect().adjusted(-m_feather, -m_feather, m_feather, m_feather)); } return selection; } diff --git a/libs/image/kis_fill_painter.h b/libs/image/kis_fill_painter.h index 57eb35263a..b6132d6a9c 100644 --- a/libs/image/kis_fill_painter.h +++ b/libs/image/kis_fill_painter.h @@ -1,285 +1,285 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Bart Coppens * * 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_FILL_PAINTER_H_ #define KIS_FILL_PAINTER_H_ #include #include "KoColor.h" #include "KoColorSpaceRegistry.h" #include "kis_painter.h" #include "kis_types.h" #include "kis_selection.h" #include class KoPattern; class KisFilterConfiguration; // XXX: Filling should set dirty rect. /** * This painter can be used to fill paint devices in different ways. This can also be used * for flood filling related operations. */ class KRITAIMAGE_EXPORT KisFillPainter : public KisPainter { public: /** * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach * to a paint device */ KisFillPainter(); /** * Start painting on the specified paint device */ KisFillPainter(KisPaintDeviceSP device); KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection); private: void initFillPainter(); public: /** * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA). */ void eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h); /** * Overloaded version of the above function. */ void eraseRect(const QRect& rc); /** * Fill current selection of KisPainter with a specified \p color. * * The filling rect is limited by \p rc to allow multithreaded * filling/processing. */ void fillSelection(const QRect &rc, const KoColor &color); /** * Fill a rectangle with a certain color. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c); /** * Fill a rectangle with a certain color and opacity. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c, quint8 opacity); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c, quint8 opacity); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPattern * pattern); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoPattern * pattern); /** * Fill the specified area with the output of the generator plugin that is configured * in the generator parameter */ - void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfiguration * generator); + void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator); /** * Fills the enclosed area around the point with the set color. If * there is a selection, the whole selection is filled. Note that * you must have set the width and height on the painter if you * don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Fills the enclosed area around the point with the set pattern. * If there is a selection, the whole selection is filled. Note * that you must have set the width and height on the painter if * you don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Returns a selection mask for the floodfill starting at the specified position. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ KisSelectionSP createFloodSelection(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only * fill parts that are the exact same color, 255 means anything will be filled */ void setFillThreshold(int threshold); /** Returns the fill threshold, see setFillThreshold for details */ int fillThreshold() const { return m_threshold; } bool useCompositioning() const { return m_useCompositioning; } void setUseCompositioning(bool useCompositioning) { m_useCompositioning = useCompositioning; } /** Sets the width of the paint device */ void setWidth(int w) { m_width = w; } /** Sets the height of the paint device */ void setHeight(int h) { m_height = h; } /** If true, floodfill doesn't fill outside the selected area of a layer */ bool careForSelection() const { return m_careForSelection; } /** Set caring for selection. See careForSelection for details */ void setCareForSelection(bool set) { m_careForSelection = set; } /** Sets the auto growth/shrinking radius */ void setSizemod(int sizemod) { m_sizemod = sizemod; } /** Sets how much to auto-grow or shrink (if @param sizemod is negative) the selection flood before painting, this affects every fill operation except fillRect */ int sizemod() { return m_sizemod; } /** Sets feathering radius */ void setFeather(int feather) { m_feather = feather; } /** defines the feathering radius for selection flood operations, this affects every fill operation except fillRect */ uint feather() { return m_feather; } private: // for floodfill void genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice); void genericFillEnd(KisPaintDeviceSP filled); KisSelectionSP m_fillSelection; int m_feather; int m_sizemod; int m_threshold; int m_width, m_height; QRect m_rect; bool m_careForSelection; bool m_useCompositioning; }; inline void KisFillPainter::fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c) { fillRect(x, y, w, h, c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::eraseRect(const QRect& rc) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c, quint8 opacity) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); } inline void KisFillPainter::fillRect(const QRect& rc, const KoPattern* pattern) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), pattern); } inline void KisFillPainter::setFillThreshold(int threshold) { m_threshold = threshold; } #endif //KIS_FILL_PAINTER_H_ diff --git a/libs/image/kis_filter_mask.cpp b/libs/image/kis_filter_mask.cpp index b370601be5..94d99d449d 100644 --- a/libs/image/kis_filter_mask.cpp +++ b/libs/image/kis_filter_mask.cpp @@ -1,179 +1,179 @@ /* * Copyright (c) 2007 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 #include #include #include "kis_layer.h" #include "kis_filter_mask.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_processing_information.h" #include "kis_node.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" #include "kis_busy_progress_indicator.h" #include "kis_transaction.h" #include "kis_painter.h" KisFilterMask::KisFilterMask() : KisEffectMask(), KisNodeFilterInterface(0, false) { setCompositeOpId(COMPOSITE_COPY); } KisFilterMask::~KisFilterMask() { } KisFilterMask::KisFilterMask(const KisFilterMask& rhs) : KisEffectMask(rhs) , KisNodeFilterInterface(rhs) { } QIcon KisFilterMask::icon() const { return KisIconUtils::loadIcon("filterMask"); } -void KisFilterMask::setFilter(KisFilterConfiguration * filterConfig) +void KisFilterMask::setFilter(KisFilterConfigurationSP filterConfig) { if (parent() && parent()->inherits("KisLayer")) { filterConfig->setChannelFlags(qobject_cast(parent().data())->channelFlags()); } KisNodeFilterInterface::setFilter(filterConfig); } QRect KisFilterMask::decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect & rc, PositionToFilthy maskPos) const { Q_UNUSED(maskPos); - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); Q_ASSERT(nodeProgressProxy()); Q_ASSERT_X(src != dst, "KisFilterMask::decorateRect", "src must be != dst, because we cant create transactions " "during merge, as it breaks reentrancy"); if (!filterConfig) { return QRect(); } KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); if (!filter) { warnKrita << "Could not retrieve filter \"" << filterConfig->name() << "\""; return QRect(); } KIS_ASSERT_RECOVER_NOOP(this->busyProgressIndicator()); this->busyProgressIndicator()->update(); filter->process(src, dst, 0, rc, filterConfig.data(), 0); QRect r = filter->changedRect(rc, filterConfig.data(), dst->defaultBounds()->currentLevelOfDetail()); return r; } bool KisFilterMask::accept(KisNodeVisitor &v) { return v.visit(this); } void KisFilterMask::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { return visitor.visit(this, undoAdapter); } /** * FIXME: try to cache filter pointer inside a Private block */ QRect KisFilterMask::changeRect(const QRect &rect, PositionToFilthy pos) const { /** * FIXME: This check of the emptiness should be done * on the higher/lower level */ if(rect.isEmpty()) return rect; QRect filteredRect = rect; - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); if (filterConfig) { KisNodeSP parent = this->parent(); const int lod = parent && parent->projection() ? parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); filteredRect = filter->changedRect(rect, filterConfig.data(), lod); } /** * We can't paint outside a selection, that is why we call * KisMask::changeRect to crop actual change area in the end */ filteredRect = KisMask::changeRect(filteredRect, pos); /** * FIXME: Think over this solution * Union of rects means that changeRect returns NOT the rect * changed by this very layer, but an accumulated rect changed * by all underlying layers. Just take into account and change * documentation accordingly */ return rect | filteredRect; } QRect KisFilterMask::needRect(const QRect& rect, PositionToFilthy pos) const { Q_UNUSED(pos); /** * FIXME: This check of the emptiness should be done * on the higher/lower level */ if(rect.isEmpty()) return rect; - KisSafeFilterConfigurationSP filterConfig = filter(); + KisFilterConfigurationSP filterConfig = filter(); if (!filterConfig) return rect; KisNodeSP parent = this->parent(); const int lod = parent && parent->projection() ? parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); /** * If we need some additional pixels even outside of a selection * for accurate layer filtering, we'll get them! * And no KisMask::needRect will prevent us from doing this! ;) * That's why simply we do not call KisMask::needRect here :) */ return filter->neededRect(rect, filterConfig.data(), lod); } diff --git a/libs/image/kis_filter_mask.h b/libs/image/kis_filter_mask.h index 60516d8c0b..ab23ddb3ed 100644 --- a/libs/image/kis_filter_mask.h +++ b/libs/image/kis_filter_mask.h @@ -1,70 +1,70 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_FILTER_MASK_ #define _KIS_FILTER_MASK_ #include "kis_types.h" #include "kis_effect_mask.h" #include "kis_node_filter_interface.h" class KisFilterConfiguration; /** An filter mask is a single channel mask that applies a particular filter to the layer the mask belongs to. It differs from an adjustment layer in that it only works on its parent layer, while adjustment layers work on all layers below it in its layer group. */ class KRITAIMAGE_EXPORT KisFilterMask : public KisEffectMask, public KisNodeFilterInterface { Q_OBJECT public: /** * Create an empty filter mask. */ KisFilterMask(); virtual ~KisFilterMask(); QIcon icon() const; KisNodeSP clone() const { return KisNodeSP(new KisFilterMask(*this)); } bool accept(KisNodeVisitor &v); void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter); KisFilterMask(const KisFilterMask& rhs); - void setFilter(KisFilterConfiguration *filterConfig); + void setFilter(KisFilterConfigurationSP filterConfig); QRect decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect & rc, PositionToFilthy maskPos) const; QRect changeRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const; QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const; }; #endif //_KIS_FILTER_MASK_ diff --git a/libs/image/kis_image.h b/libs/image/kis_image.h index f5c7ba56a3..27e749389a 100644 --- a/libs/image/kis_image.h +++ b/libs/image/kis_image.h @@ -1,926 +1,948 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_IMAGE_H_ #define KIS_IMAGE_H_ #include #include #include #include #include #include #include #include "kis_paint_device.h" // msvc cannot handle forward declarations, so include kis_paint_device here #include "kis_types.h" #include "kis_shared.h" #include "kis_node_graph_listener.h" #include "kis_node_facade.h" #include "kis_image_interfaces.h" #include class KisDocument; class KoColorSpace; class KoColor; class KisCompositeProgressProxy; class KisActionRecorder; class KisUndoStore; class KisUndoAdapter; class KisImageSignalRouter; class KisPostExecutionUndoAdapter; class KisFilterStrategy; class KoColorProfile; class KisLayerComposition; class KisSpontaneousJob; class KisImageAnimationInterface; class KUndo2MagicString; struct KisProofingConfiguration; namespace KisMetaData { class MergeStrategy; } /** * This is the image class, it contains a tree of KisLayer stack and * meta information about the image. And it also provides some * functions to manipulate the whole image. */ class KRITAIMAGE_EXPORT KisImage : public QObject, public KisStrokesFacade, public KisUpdatesFacade, public KisProjectionUpdateListener, public KisNodeFacade, public KisNodeGraphListener, public KisShared { Q_OBJECT public: /// @param colorSpace can be null. in that case it will be initialised to a default color space. KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace, const QString& name); virtual ~KisImage(); public: // KisNodeGraphListener implementation void aboutToAddANode(KisNode *parent, int index); void nodeHasBeenAdded(KisNode *parent, int index); void aboutToRemoveANode(KisNode *parent, int index); void nodeChanged(KisNode * node); void invalidateAllFrames(); void notifySelectionChanged(); void requestProjectionUpdate(KisNode *node, const QRect& rect); void invalidateFrames(const KisTimeRange &range, const QRect &rect); void requestTimeSwitch(int time); public: // KisProjectionUpdateListener implementation void notifyProjectionUpdated(const QRect &rc); public: /** * Render the projection onto a QImage. */ QImage convertToQImage(qint32 x1, qint32 y1, qint32 width, qint32 height, const KoColorProfile * profile); /** * Render the projection onto a QImage. * (this is an overloaded function) */ QImage convertToQImage(QRect imageRect, const KoColorProfile * profile); /** * XXX: docs! */ QImage convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile); /** - * Calls KisUpdateScheduler::lock + * Calls KisUpdateScheduler::lock (XXX: APIDOX -- what does that mean?) */ void lock(); /** - * Calls KisUpdateScheduler::unlock + * Calls KisUpdateScheduler::unlock (XXX: APIDOX -- what does that mean?) */ void unlock(); /** * Returns true if lock() has been called more often than unlock(). */ bool locked() const; /** * @return the global selection object or 0 if there is none. The * global selection is always read-write. */ KisSelectionSP globalSelection() const; /** * Retrieve the next automatic layername (XXX: fix to add option to return Mask X) */ QString nextLayerName(const QString &baseName = "") const; /** * Set the automatic layer name counter one back. */ void rollBackLayerName(); /** * Resize the image to the specified rect. The resize * method handles the creating on an undo step itself. * * @param newRect the rect describing the new width, height and offset * of the image */ void resizeImage(const QRect& newRect); /** * Crop the image to the specified rect. The crop * method handles the creating on an undo step itself. * * @param newRect the rect describing the new width, height and offset * of the image */ void cropImage(const QRect& newRect); /** * Crop a node to @newRect. The node will *not* be moved anywhere, * it just drops some content */ void cropNode(KisNodeSP node, const QRect& newRect); /// XXX: ApiDox void scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy); /// XXX: ApiDox void scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy); /** * Execute a rotate transform on all layers in this image. * Image is resized to fit rotated image. */ void rotateImage(double radians); /** * Execute a rotate transform on on a subtree of this image. * Image is not resized. */ void rotateNode(KisNodeSP node, double radians); /** * Execute a shear transform on all layers in this image. */ void shear(double angleX, double angleY); /** * Shear a node and all its children. * @param angleX, @param angleY are given in degrees. */ void shearNode(KisNodeSP node, double angleX, double angleY); /** * Convert the image and all its layers to the dstColorSpace */ void convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Set the color space of the projection (and the root layer) * to dstColorSpace. No conversion is done for other layers, * their colorspace can differ. * NOTE: Note conversion is done, only regeneration, so no rendering * intent needed */ void convertProjectionColorSpace(const KoColorSpace *dstColorSpace); // Get the profile associated with this image const KoColorProfile * profile() const; /** * Set the profile of the image to the new profile and do the same for * all layers that have the same colorspace and profile of the image. * It doesn't do any pixel conversion. * * This is essential if you have loaded an image that didn't * have an embedded profile to which you want to attach the right profile. * * This does not create an undo action; only call it when creating or * loading an image. * * @returns false if the profile could not be assigned */ bool assignImageProfile(const KoColorProfile *profile); /** * Returns the current undo adapter. You can add new commands to the * undo stack using the adapter. This adapter is used for a backward * compatibility for old commands created before strokes. It blocks * all the porcessing at the scheduler, waits until it's finished * adn executes commands exclusively. */ KisUndoAdapter* undoAdapter() const; /** * This adapter is used by the strokes system. The commands are added * to it *after* redo() is done (in the scheduler context). They are * wrapped into a special command and added to the undo stack. redo() * in not called. */ KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const; /** * Replace current undo store with the new one. The old store * will be deleted. * This method is used by KisDocument for dropping all the commands * during file loading. */ void setUndoStore(KisUndoStore *undoStore); /** * Return current undo store of the image */ KisUndoStore* undoStore(); /** * @return the action recorder associated with this image */ KisActionRecorder* actionRecorder() const; /** * Tell the image it's modified; this emits the sigImageModified * signal. This happens when the image needs to be saved */ void setModified(); /** * The default colorspace of this image: new layers will have this * colorspace and the projection will have this colorspace. */ const KoColorSpace * colorSpace() const; /** * X resolution in pixels per pt */ double xRes() const; /** * Y resolution in pixels per pt */ double yRes() const; /** * Set the resolution in pixels per pt. */ void setResolution(double xres, double yres); /** * Convert a document coordinate to a pixel coordinate. * * @param documentCoord PostScript Pt coordinate to convert. */ QPointF documentToPixel(const QPointF &documentCoord) const; /** * Convert a document coordinate to an integer pixel coordinate. * * @param documentCoord PostScript Pt coordinate to convert. */ QPoint documentToIntPixel(const QPointF &documentCoord) const; /** * Convert a document rectangle to a pixel rectangle. * * @param documentRect PostScript Pt rectangle to convert. */ QRectF documentToPixel(const QRectF &documentRect) const; /** * Convert a document rectangle to an integer pixel rectangle. * * @param documentRect PostScript Pt rectangle to convert. */ QRect documentToIntPixel(const QRectF &documentRect) const; /** * Convert a pixel coordinate to a document coordinate. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPointF &pixelCoord) const; /** * Convert an integer pixel coordinate to a document coordinate. * The document coordinate is at the centre of the pixel. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPoint &pixelCoord) const; /** * Convert a document rectangle to an integer pixel rectangle. * * @param pixelCoord pixel coordinate to convert. */ QRectF pixelToDocument(const QRectF &pixelCoord) const; /** * Return the width of the image */ qint32 width() const; /** * Return the height of the image */ qint32 height() const; /** * Return the size of the image */ QSize size() const { return QSize(width(), height()); } /** * @return the root node of the image node graph */ KisGroupLayerSP rootLayer() const; /** * Return the projection; that is, the complete, composited * representation of this image. */ KisPaintDeviceSP projection() const; /** * Return the number of layers (not other nodes) that are in this * image. */ qint32 nlayers() const; /** * Return the number of layers (not other node types) that are in * this image and that are hidden. */ qint32 nHiddenLayers() const; /** * Merge all visible layers and discard hidden ones. */ void flatten(); /** * Merge the specified layer with the layer * below this layer, remove the specified layer. */ void mergeDown(KisLayerSP l, const KisMetaData::MergeStrategy* strategy); /** * flatten the layer: that is, the projection becomes the layer * and all subnodes are removed. If this is not a paint layer, it will morph * into a paint layer. */ void flattenLayer(KisLayerSP layer); /** * Merges layers in \p mergedLayers and creates a new layer above * \p putAfter */ void mergeMultipleLayers(QList mergedLayers, KisNodeSP putAfter); /// @return the exact bounds of the image in pixel coordinates. QRect bounds() const; /** * Returns the actual bounds of the image, taking LevelOfDetail * into account. This value is used as a bounds() value of * KisDefaultBounds object. */ QRect effectiveLodBounds() const; /// use if the layers have changed _completely_ (eg. when flattening) void notifyLayersChanged(); /** * Sets the default color of the root layer projection. All the layers * will be merged on top of this very color */ void setDefaultProjectionColor(const KoColor &color); /** * \see setDefaultProjectionColor() */ KoColor defaultProjectionColor() const; void setRootLayer(KisGroupLayerSP rootLayer); /** * Add an annotation for this image. This can be anything: Gamma, EXIF, etc. * Note that the "icc" annotation is reserved for the color strategies. * If the annotation already exists, overwrite it with this one. */ void addAnnotation(KisAnnotationSP annotation); /** get the annotation with the given type, can return 0 */ KisAnnotationSP annotation(const QString& type); /** delete the annotation, if the image contains it */ void removeAnnotation(const QString& type); /** * Start of an iteration over the annotations of this image (including the ICC Profile) */ vKisAnnotationSP_it beginAnnotations(); /** end of an iteration over the annotations of this image */ vKisAnnotationSP_it endAnnotations(); /** * Called before the image is delted and sends the sigAboutToBeDeleted signal */ void notifyAboutToBeDeleted(); KisImageSignalRouter* signalRouter(); /** * Returns whether we can reselect current global selection * * \see reselectGlobalSelection() */ bool canReselectGlobalSelection(); /** * Returns the layer compositions for the image */ QList compositions(); /** * Adds a new layer composition, will be saved with the image */ void addComposition(KisLayerCompositionSP composition); /** * Remove the layer compostion */ void removeComposition(KisLayerCompositionSP composition); /** * Permit or deny the wrap-around mode for all the paint devices * of the image. Note that permitting the wraparound mode will not * necessarily activate it right now. To be activated the wrap * around mode should be 1) permitted; 2) supported by the * currently running stroke. */ void setWrapAroundModePermitted(bool value); /** * \return whether the wrap-around mode is permitted for this * image. If the wrap around mode is permitted and the * currently running stroke supports it, the mode will be * activated for all paint devices of the image. * * \see setWrapAroundMode */ bool wrapAroundModePermitted() const; /** * \return whether the wraparound mode is activated for all the * devices of the image. The mode is activated when both * factors are true: the user permitted it and the stroke * supports it */ bool wrapAroundModeActive() const; /** * \return curent level of detail which is used when processing the image. * Current working zoom = 2 ^ (- currentLevelOfDetail()). Default value is * null, which means we work on the original image. */ int currentLevelOfDetail() const; /** * Notify KisImage which level of detail should be used in the * lod-mode. Setting the mode does not guarantee the LOD to be * used. It will be activated only when the stokes supports it. */ void setDesiredLevelOfDetail(int lod); public Q_SLOTS: /** * Explicitly start regeneration of LoD planes of all the devices * in the image. This call should be performed when the user is idle, * just to make the quality of image updates better. */ void explicitRegenerateLevelOfDetail(); public: /** * Blocks usage of level of detail functionality. After this method * has been called, no new strokes will use LoD. */ void setLevelOfDetailBlocked(bool value); /** * \see setLevelOfDetailBlocked() */ bool levelOfDetailBlocked() const; /** * Notifies that the node collapsed state has changed */ void notifyNodeCollpasedChanged(); KisImageAnimationInterface *animationInterface() const; /** * @brief setProofingConfiguration, this sets the image's proofing configuration, and signals * the proofingConfiguration has changed. * @param proofingConfig - the kis proofing config that will be used instead. */ void setProofingConfiguration(KisProofingConfigurationSP proofingConfig); /** * @brief proofingConfiguration * @return the proofing configuration of the image. */ KisProofingConfigurationSP proofingConfiguration() const; public: bool startIsolatedMode(KisNodeSP node); void stopIsolatedMode(); KisNodeSP isolatedModeRoot() const; Q_SIGNALS: /** * Emitted whenever an action has caused the image to be * recomposited. * * @param rc The rect that has been recomposited. */ void sigImageUpdated(const QRect &); /** Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk. */ void sigImageModified(); /** * The signal is emitted when the size of the image is changed. * \p oldStillPoint and \p newStillPoint give the receiver the * hint about how the new and old rect of the image correspond to * each other. They specify the point of the image around which * the conversion was done. This point will stay still on the * user's screen. That is the \p newStillPoint of the new image * will be painted at the same screen position, where \p * oldStillPoint of the old image was painted. * * \param oldStillPoint is a still point represented in *old* * image coordinates * * \param newStillPoint is a still point represented in *new* * image coordinates */ void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint); void sigProfileChanged(const KoColorProfile * profile); void sigColorSpaceChanged(const KoColorSpace* cs); void sigResolutionChanged(double xRes, double yRes); void sigRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes); /** * Inform the model that a node was changed */ void sigNodeChanged(KisNodeSP node); /** * Inform that the image is going to be deleted */ void sigAboutToBeDeleted(); /** * The signal is emitted right after a node has been connected * to the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. If you need * information about the parent/siblings of the node connect * with Qt::DirectConnection, get needed information and then * emit another Qt::AutoConnection signal to pass this information * to your thread. See details of the implementation * in KisDummiesfacadeBase. */ void sigNodeAddedAsync(KisNodeSP node); /** * This signal is emitted right before a node is going to removed * from the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. * * \see comment in sigNodeAddedAsync() */ void sigRemoveNodeAsync(KisNodeSP node); /** * Emitted when the root node of the image has changed. * It happens, e.g. when we flatten the image. When * this happens the receiver should reload information * about the image */ void sigLayersChangedAsync(); /** * Emitted when the UI has requested the undo of the last stroke's * operation. The point is, we cannot deal with the internals of * the stroke without its creator knowing about it (which most * probably cause a crash), so we just forward this request from * the UI to the creator of the stroke. * * If your tool supports undoing part of its work, just listen to * this signal and undo when it comes */ void sigUndoDuringStrokeRequested(); /** * Emitted when the UI has requested the cancellation of * the stroke. The point is, we cannot cancel the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports cancelling of its work in the middle * of operation, just listen to this signal and cancel * the stroke when it comes */ void sigStrokeCancellationRequested(); /** * Emitted when the image decides that the stroke should better * be ended. The point is, we cannot just end the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports long strokes that may involve multiple * mouse actions in one stroke, just listen to this signal and * end the stroke when it comes. */ void sigStrokeEndRequested(); /** * Same as sigStrokeEndRequested() but is not emitted when the active node * is changed. */ void sigStrokeEndRequestedActiveNodeFiltered(); /** * Emitted when the isolated mode status has changed. * * Can be used by the receivers to catch a fact of forcefully * stopping the isolated mode by the image when some complex * action was requested */ void sigIsolatedModeChanged(); /** * Emitted when one or more nodes changed the collapsed state * */ void sigNodeCollapsedChanged(); /** * Emitted when the proofing configuration of the image is being changed. * */ void sigProofingConfigChanged(); public Q_SLOTS: KisCompositeProgressProxy* compositeProgressProxy(); bool isIdle(); + /** + * @brief barrierLock APIDOX + * @param readOnly + */ void barrierLock(bool readOnly = false); + + /** + * @brief barrierLock APIDOX + * @param readOnly + */ bool tryBarrierLock(bool readOnly = false); + + /** + * @brief barrierLock APIDOX + * @param readOnly + */ void waitForDone(); KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy); void addJob(KisStrokeId id, KisStrokeJobData *data); void endStroke(KisStrokeId id); bool cancelStroke(KisStrokeId id); + /** + * @brief blockUpdates block updating the image projection + */ void blockUpdates(); + + /** + * @brief unblockUpdates unblock updating the image project. This + * only restarts the scheduler and does not schedule a full refresh. + */ void unblockUpdates(); /** * Disables notification of the UI about the changes in the image. * This feature is used by KisProcessingApplicator. It is needed * when we change the size of the image. In this case, the whole * image will be reloaded into UI by sigSizeChanged(), so there is * no need to inform the UI about individual dirty rects. */ void disableUIUpdates(); /** * \see disableUIUpdates */ void enableUIUpdates(); /** * Disables the processing of all the setDirty() requests that * come to the image. The incoming requests are effectively * *dropped*. * * This feature is used by KisProcessingApplicator. For many cases * it provides its own updates interface, which recalculates the * whole subtree of nodes. But while we change any particular * node, it can ask for an update itself. This method is a way of * blocking such intermediate (and excessive) requests. * * NOTE: this is a convenience function for setProjectionUpdatesFilter() * that installs a predefined filter that eats everything. Please * note that these calls are *not* recursive */ void disableDirtyRequests(); /** * \see disableDirtyRequests() */ void enableDirtyRequests(); /** * Installs a filter object that will filter all the incoming projection update * requests. If the filter return true, the incoming update is dropped. * * NOTE: you cannot set filters recursively! */ void setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter); /** * \see setProjectionUpdatesFilter() */ KisProjectionUpdatesFilterSP projectionUpdatesFilter() const; void refreshGraphAsync(KisNodeSP root = 0); void refreshGraphAsync(KisNodeSP root, const QRect &rc); void refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect); /** * Triggers synchronous recomposition of the projection */ void refreshGraph(KisNodeSP root = 0); void refreshGraph(KisNodeSP root, const QRect& rc, const QRect &cropRect); void initialRefreshGraph(); /** * Initiate a stack regeneration skipping the recalculation of the * filthy node's projection. * * Works exactly as pseudoFilthy->setDirty() with the only * exception that pseudoFilthy::updateProjection() will not be * called. That is used by KisRecalculateTransformMaskJob to avoid * cyclic dependencies. */ void requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect); /** * Adds a spontaneous job to the updates queue. * * A spontaneous job may do some trivial tasks in the background, * like updating the outline of selection or purging unused tiles * from the existing paint devices. */ void addSpontaneousJob(KisSpontaneousJob *spontaneousJob); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks the current stroke should undo its last * action, for example, when the user presses Ctrl+Z while some * stroke is active. * * If the creator of the stroke supports undoing of intermediate * actions, it will be notified about this request and can undo * its last action. */ void requestUndoDuringStroke(); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks current stroke should be cancelled. If * there is a running stroke that has already been detached from * its creator (ended or cancelled), it will be forcefully * cancelled and reverted. If there is an open stroke present, and * if its creator supports cancelling, it will be notified about * the request and the stroke will be cancelled */ void requestStrokeCancellation(); /** * This method is called when image or some other part of Krita * (*not* the creator of the stroke) decides that the stroke * should be ended. If the creator of the stroke supports it, it * will be notified and the stroke will be cancelled */ void requestStrokeEnd(); /** * Same as requestStrokeEnd() but is called by view manager when * the current node is changed. Use to dintinguish * sigStrokeEndRequested() and * sigStrokeEndRequestedActiveNodeFiltered() which are used by * KisNodeJugglerCompressed */ void requestStrokeEndActiveNode(); private: KisImage(const KisImage& rhs); KisImage& operator=(const KisImage& rhs); void emitSizeChanged(); void resizeImageImpl(const QRect& newRect, bool cropLayers); void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double radians); void shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double angleX, double angleY, const QPointF &origin); void safeRemoveTwoNodes(KisNodeSP node1, KisNodeSP node2); void refreshHiddenArea(KisNodeSP rootNode, const QRect &preparedArea); void requestProjectionUpdateImpl(KisNode *node, const QRect& rect, const QRect &cropRect); friend class KisImageResizeCommand; void setSize(const QSize& size); friend class KisImageSetProjectionColorSpaceCommand; void setProjectionColorSpace(const KoColorSpace * colorSpace); friend class KisDeselectGlobalSelectionCommand; friend class KisReselectGlobalSelectionCommand; friend class KisSetGlobalSelectionCommand; friend class KisImageTest; /** * Replaces the current global selection with globalSelection. If * \p globalSelection is empty, removes the selection object, so that * \ref globalSelection() will return 0 after that. */ void setGlobalSelection(KisSelectionSP globalSelection); /** * Deselects current global selection. * \ref globalSelection() will return 0 after that. */ void deselectGlobalSelection(); /** * Reselects current deselected selection * * \see deselectGlobalSelection() */ void reselectGlobalSelection(); private: class KisImagePrivate; KisImagePrivate * m_d; }; #endif // KIS_IMAGE_H_ diff --git a/libs/image/kis_layer_utils.cpp b/libs/image/kis_layer_utils.cpp index 59c0c963ff..d9ba383bb0 100644 --- a/libs/image/kis_layer_utils.cpp +++ b/libs/image/kis_layer_utils.cpp @@ -1,1189 +1,1238 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_utils.h" #include #include #include "kis_painter.h" #include "kis_image.h" #include "kis_node.h" #include "kis_layer.h" #include "kis_paint_layer.h" #include "kis_clone_layer.h" #include "kis_group_layer.h" #include "kis_selection.h" #include "kis_selection_mask.h" #include "kis_meta_data_merge_strategy.h" #include #include "commands/kis_image_layer_add_command.h" #include "commands/kis_image_layer_remove_command.h" #include "commands/kis_image_layer_move_command.h" #include "commands/kis_image_change_layers_command.h" #include "commands_new/kis_activate_selection_mask_command.h" #include "kis_abstract_projection_plane.h" #include "kis_processing_applicator.h" #include "kis_image_animation_interface.h" #include "kis_keyframe_channel.h" #include "kis_command_utils.h" #include "kis_processing_applicator.h" #include "commands_new/kis_change_projection_color_command.h" #include "kis_layer_properties_icons.h" #include "lazybrush/kis_colorize_mask.h" #include "commands/kis_node_property_list_command.h" namespace KisLayerUtils { void fetchSelectionMasks(KisNodeList mergedNodes, QVector &selectionMasks) { foreach (KisNodeSP node, mergedNodes) { KisLayerSP layer = dynamic_cast(node.data()); KisSelectionMaskSP mask; if (layer && (mask = layer->selectionMask())) { selectionMasks.append(mask); } } } struct MergeDownInfoBase { MergeDownInfoBase(KisImageSP _image) : image(_image), storage(new SwitchFrameCommand::SharedStorage()) { } virtual ~MergeDownInfoBase() {} KisImageWSP image; QVector selectionMasks; KisNodeSP dstNode; SwitchFrameCommand::SharedStorageSP storage; QSet frames; virtual KisNodeList allSrcNodes() = 0; virtual KisLayerSP dstLayer() { return 0; } }; struct MergeDownInfo : public MergeDownInfoBase { MergeDownInfo(KisImageSP _image, KisLayerSP _prevLayer, KisLayerSP _currLayer) : MergeDownInfoBase(_image), prevLayer(_prevLayer), currLayer(_currLayer) { frames = fetchLayerFramesRecursive(prevLayer) | fetchLayerFramesRecursive(currLayer); } KisLayerSP prevLayer; KisLayerSP currLayer; KisNodeList allSrcNodes() { KisNodeList mergedNodes; mergedNodes << currLayer; mergedNodes << prevLayer; return mergedNodes; } KisLayerSP dstLayer() { return dynamic_cast(dstNode.data()); } }; struct MergeMultipleInfo : public MergeDownInfoBase { MergeMultipleInfo(KisImageSP _image, KisNodeList _mergedNodes) : MergeDownInfoBase(_image), mergedNodes(_mergedNodes) { foreach (KisNodeSP node, mergedNodes) { frames |= fetchLayerFramesRecursive(node); } } KisNodeList mergedNodes; KisNodeList allSrcNodes() { return mergedNodes; } }; typedef QSharedPointer MergeDownInfoBaseSP; typedef QSharedPointer MergeDownInfoSP; typedef QSharedPointer MergeMultipleInfoSP; struct FillSelectionMasks : public KUndo2Command { FillSelectionMasks(MergeDownInfoBaseSP info) : m_info(info) {} void redo() { fetchSelectionMasks(m_info->allSrcNodes(), m_info->selectionMasks); } private: MergeDownInfoBaseSP m_info; }; struct DisableColorizeKeyStrokes : public KisCommandUtils::AggregateCommand { DisableColorizeKeyStrokes(MergeDownInfoBaseSP info) : m_info(info) {} void populateChildCommands() { Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) { recursiveApplyNodes(node, [this] (KisNodeSP node) { if (dynamic_cast(node.data()) && KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool()) { KisBaseNode::PropertyList props = node->sectionModelProperties(); KisLayerPropertiesIcons::setNodeProperty(&props, KisLayerPropertiesIcons::colorizeEditKeyStrokes, false); addCommand(new KisNodePropertyListCommand(node, props)); } }); } } private: MergeDownInfoBaseSP m_info; }; struct RefreshHiddenAreas : public KUndo2Command { RefreshHiddenAreas(MergeDownInfoBaseSP info) : m_info(info) {} void redo() { KisImageAnimationInterface *interface = m_info->image->animationInterface(); const QRect preparedRect = !interface->externalFrameActive() ? m_info->image->bounds() : QRect(); foreach (KisNodeSP node, m_info->allSrcNodes()) { refreshHiddenAreaAsync(node, preparedRect); } } private: QRect realNodeExactBounds(KisNodeSP rootNode, QRect currentRect = QRect()) { KisNodeSP node = rootNode->firstChild(); while(node) { currentRect |= realNodeExactBounds(node, currentRect); node = node->nextSibling(); } // TODO: it would be better to count up changeRect inside // node's extent() method currentRect |= rootNode->projectionPlane()->changeRect(rootNode->exactBounds()); return currentRect; } void refreshHiddenAreaAsync(KisNodeSP rootNode, const QRect &preparedArea) { QRect realNodeRect = realNodeExactBounds(rootNode); if (!preparedArea.contains(realNodeRect)) { QRegion dirtyRegion = realNodeRect; dirtyRegion -= preparedArea; foreach(const QRect &rc, dirtyRegion.rects()) { m_info->image->refreshGraphAsync(rootNode, rc, realNodeRect); } } } private: MergeDownInfoBaseSP m_info; }; struct KeepMergedNodesSelected : public KisCommandUtils::AggregateCommand { KeepMergedNodesSelected(MergeDownInfoSP info, bool finalizing) : m_singleInfo(info), m_finalizing(finalizing) {} KeepMergedNodesSelected(MergeMultipleInfoSP info, KisNodeSP putAfter, bool finalizing) : m_multipleInfo(info), m_finalizing(finalizing), m_putAfter(putAfter) {} void populateChildCommands() { KisNodeSP prevNode; KisNodeSP nextNode; KisNodeList prevSelection; KisNodeList nextSelection; KisImageSP image; if (m_singleInfo) { prevNode = m_singleInfo->currLayer; nextNode = m_singleInfo->dstNode; image = m_singleInfo->image; } else if (m_multipleInfo) { prevNode = m_putAfter; nextNode = m_multipleInfo->dstNode; prevSelection = m_multipleInfo->allSrcNodes(); image = m_multipleInfo->image; } if (!m_finalizing) { addCommand(new KeepNodesSelectedCommand(prevSelection, KisNodeList(), prevNode, KisNodeSP(), image, false)); } else { addCommand(new KeepNodesSelectedCommand(KisNodeList(), nextSelection, KisNodeSP(), nextNode, image, true)); } } private: MergeDownInfoSP m_singleInfo; MergeMultipleInfoSP m_multipleInfo; bool m_finalizing; KisNodeSP m_putAfter; }; struct CreateMergedLayer : public KisCommandUtils::AggregateCommand { CreateMergedLayer(MergeDownInfoSP info) : m_info(info) {} void populateChildCommands() { // actual merging done by KisLayer::createMergedLayer (or specialized decendant) m_info->dstNode = m_info->currLayer->createMergedLayerTemplate(m_info->prevLayer); if (m_info->frames.size() > 0) { m_info->dstNode->enableAnimation(); } } private: MergeDownInfoSP m_info; }; struct CreateMergedLayerMultiple : public KisCommandUtils::AggregateCommand { - CreateMergedLayerMultiple(MergeMultipleInfoSP info) : m_info(info) {} + CreateMergedLayerMultiple(MergeMultipleInfoSP info, const QString name = QString() ) + : m_info(info), + m_name(name) {} void populateChildCommands() { - const QString mergedLayerSuffix = i18n("Merged"); - QString mergedLayerName = m_info->mergedNodes.first()->name(); - - if (!mergedLayerName.endsWith(mergedLayerSuffix)) { - mergedLayerName = QString("%1 %2") - .arg(mergedLayerName).arg(mergedLayerSuffix); + QString mergedLayerName; + + if (m_name.isEmpty()){ + const QString mergedLayerSuffix = i18n("Merged"); + mergedLayerName = m_info->mergedNodes.first()->name(); + + if (!mergedLayerName.endsWith(mergedLayerSuffix)) { + mergedLayerName = QString("%1 %2") + .arg(mergedLayerName).arg(mergedLayerSuffix); + } + } else { + mergedLayerName = m_name; } - + m_info->dstNode = new KisPaintLayer(m_info->image, mergedLayerName, OPACITY_OPAQUE_U8); if (m_info->frames.size() > 0) { m_info->dstNode->enableAnimation(); } QString compositeOpId; QBitArray channelFlags; bool compositionVaries = false; foreach (KisNodeSP node, m_info->allSrcNodes()) { if (compositeOpId.isEmpty()) { compositeOpId = node->compositeOpId(); } else if (compositeOpId != node->compositeOpId()) { compositionVaries = true; break; } KisLayerSP layer = dynamic_cast(node.data()); if (layer && layer->layerStyle()) { compositionVaries = true; break; } } if (!compositionVaries) { if (!compositeOpId.isEmpty()) { m_info->dstNode->setCompositeOpId(compositeOpId); } if (m_info->dstLayer() && !channelFlags.isEmpty()) { m_info->dstLayer()->setChannelFlags(channelFlags); } } } private: MergeMultipleInfoSP m_info; + QString m_name; }; struct MergeLayers : public KisCommandUtils::AggregateCommand { MergeLayers(MergeDownInfoSP info) : m_info(info) {} void populateChildCommands() { // actual merging done by KisLayer::createMergedLayer (or specialized decendant) m_info->currLayer->fillMergedLayerTemplate(m_info->dstLayer(), m_info->prevLayer); } private: MergeDownInfoSP m_info; }; struct MergeLayersMultiple : public KisCommandUtils::AggregateCommand { MergeLayersMultiple(MergeMultipleInfoSP info) : m_info(info) {} void populateChildCommands() { KisPainter gc(m_info->dstNode->paintDevice()); foreach (KisNodeSP node, m_info->allSrcNodes()) { QRect rc = node->exactBounds() | m_info->image->bounds(); node->projectionPlane()->apply(&gc, rc); } } private: MergeMultipleInfoSP m_info; }; struct MergeMetaData : public KUndo2Command { MergeMetaData(MergeDownInfoSP info, const KisMetaData::MergeStrategy* strategy) : m_info(info), m_strategy(strategy) {} void redo() { QRect layerProjectionExtent = m_info->currLayer->projection()->extent(); QRect prevLayerProjectionExtent = m_info->prevLayer->projection()->extent(); int prevLayerArea = prevLayerProjectionExtent.width() * prevLayerProjectionExtent.height(); int layerArea = layerProjectionExtent.width() * layerProjectionExtent.height(); QList scores; double norm = qMax(prevLayerArea, layerArea); scores.append(prevLayerArea / norm); scores.append(layerArea / norm); QList srcs; srcs.append(m_info->prevLayer->metaData()); srcs.append(m_info->currLayer->metaData()); m_strategy->merge(m_info->dstLayer()->metaData(), srcs, scores); } private: MergeDownInfoSP m_info; const KisMetaData::MergeStrategy *m_strategy; }; KeepNodesSelectedCommand::KeepNodesSelectedCommand(const KisNodeList &selectedBefore, const KisNodeList &selectedAfter, KisNodeSP activeBefore, KisNodeSP activeAfter, KisImageSP image, bool finalize, KUndo2Command *parent) : FlipFlopCommand(finalize, parent), m_selectedBefore(selectedBefore), m_selectedAfter(selectedAfter), m_activeBefore(activeBefore), m_activeAfter(activeAfter), m_image(image) { } void KeepNodesSelectedCommand::end() { KisImageSignalType type; if (isFinalizing()) { type = ComplexNodeReselectionSignal(m_activeAfter, m_selectedAfter); } else { type = ComplexNodeReselectionSignal(m_activeBefore, m_selectedBefore); } m_image->signalRouter()->emitNotification(type); } KisLayerSP constructDefaultLayer(KisImageSP image) { return new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace()); } RemoveNodeHelper::~RemoveNodeHelper() { } /** * The removal of two nodes in one go may be a bit tricky, because one * of them may be the clone of another. If we remove the source of a * clone layer, it will reincarnate into a paint layer. In this case * the pointer to the second layer will be lost. * * That's why we need to care about the order of the nodes removal: * the clone --- first, the source --- last. */ void RemoveNodeHelper::safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image) { const bool lastLayer = scanForLastLayer(image, nodes); while (!nodes.isEmpty()) { KisNodeList::iterator it = nodes.begin(); while (it != nodes.end()) { if (!checkIsSourceForClone(*it, nodes)) { KisNodeSP node = *it; addCommandImpl(new KisImageLayerRemoveCommand(image, node, false, true)); it = nodes.erase(it); } else { ++it; } } } if (lastLayer) { KisLayerSP newLayer = constructDefaultLayer(image); addCommandImpl(new KisImageLayerAddCommand(image, newLayer, image->root(), KisNodeSP(), false, false)); } } bool RemoveNodeHelper::checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes) { foreach (KisNodeSP node, nodes) { if (node == src) continue; KisCloneLayer *clone = dynamic_cast(node.data()); if (clone && KisNodeSP(clone->copyFrom()) == src) { return true; } } return false; } bool RemoveNodeHelper::scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove) { bool removeLayers = false; Q_FOREACH(KisNodeSP nodeToRemove, nodesToRemove) { if (dynamic_cast(nodeToRemove.data())) { removeLayers = true; break; } } if (!removeLayers) return false; bool lastLayer = true; KisNodeSP node = image->root()->firstChild(); while (node) { if (!nodesToRemove.contains(node) && dynamic_cast(node.data())) { lastLayer = false; break; } node = node->nextSibling(); } return lastLayer; } SimpleRemoveLayers::SimpleRemoveLayers(const KisNodeList &nodes, KisImageSP image) : m_nodes(nodes), m_image(image) { } void SimpleRemoveLayers::populateChildCommands() { if (m_nodes.isEmpty()) return; safeRemoveMultipleNodes(m_nodes, m_image); } void SimpleRemoveLayers::addCommandImpl(KUndo2Command *cmd) { addCommand(cmd); } + struct InsertNode : public KisCommandUtils::AggregateCommand { + InsertNode(MergeDownInfoBaseSP info, KisNodeSP putAfter) + : m_info(info), m_putAfter(putAfter) {} + + void populateChildCommands() { + addCommand(new KisImageLayerAddCommand(m_info->image, + m_info->dstNode, + m_putAfter->parent(), + m_putAfter, + true, false)); + + } + + private: + virtual void addCommandImpl(KUndo2Command *cmd) { + addCommand(cmd); + } + + private: + MergeDownInfoBaseSP m_info; + KisNodeSP m_putAfter; + }; + + struct CleanUpNodes : private RemoveNodeHelper, public KisCommandUtils::AggregateCommand { CleanUpNodes(MergeDownInfoBaseSP info, KisNodeSP putAfter) : m_info(info), m_putAfter(putAfter) {} static void findPerfectParent(KisNodeList nodesToDelete, KisNodeSP &putAfter, KisNodeSP &parent) { if (!putAfter) { putAfter = nodesToDelete.last(); } // Add the new merged node on top of the active node -- checking // whether the parent is going to be deleted parent = putAfter->parent(); while (parent && nodesToDelete.contains(parent)) { parent = parent->parent(); } } void populateChildCommands() { KisNodeList nodesToDelete = m_info->allSrcNodes(); KisNodeSP parent; findPerfectParent(nodesToDelete, m_putAfter, parent); if (!parent) { KisNodeSP oldRoot = m_info->image->root(); KisNodeSP newRoot = new KisGroupLayer(m_info->image, "root", OPACITY_OPAQUE_U8); addCommand(new KisImageLayerAddCommand(m_info->image, m_info->dstNode, newRoot, KisNodeSP(), true, false)); addCommand(new KisImageChangeLayersCommand(m_info->image, oldRoot, newRoot)); } else { if (parent == m_putAfter->parent()) { addCommand(new KisImageLayerAddCommand(m_info->image, m_info->dstNode, parent, m_putAfter, true, false)); } else { addCommand(new KisImageLayerAddCommand(m_info->image, m_info->dstNode, parent, parent->lastChild(), true, false)); } reparentSelectionMasks(m_info->image, m_info->dstLayer(), m_info->selectionMasks); safeRemoveMultipleNodes(m_info->allSrcNodes(), m_info->image); } } private: virtual void addCommandImpl(KUndo2Command *cmd) { addCommand(cmd); } void reparentSelectionMasks(KisImageSP image, KisLayerSP newLayer, const QVector &selectionMasks) { foreach (KisSelectionMaskSP mask, selectionMasks) { addCommand(new KisImageLayerMoveCommand(image, mask, newLayer, newLayer->lastChild())); addCommand(new KisActivateSelectionMaskCommand(mask, false)); } } private: MergeDownInfoBaseSP m_info; KisNodeSP m_putAfter; }; SwitchFrameCommand::SharedStorage::~SharedStorage() { } SwitchFrameCommand::SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage) : FlipFlopCommand(finalize), m_image(image), m_newTime(time), m_storage(storage) {} SwitchFrameCommand::~SwitchFrameCommand() {} void SwitchFrameCommand::init() { KisImageAnimationInterface *interface = m_image->animationInterface(); const int currentTime = interface->currentTime(); if (currentTime == m_newTime) { m_storage->value = m_newTime; return; } interface->image()->disableUIUpdates(); interface->saveAndResetCurrentTime(m_newTime, &m_storage->value); } void SwitchFrameCommand::end() { KisImageAnimationInterface *interface = m_image->animationInterface(); const int currentTime = interface->currentTime(); if (currentTime == m_storage->value) { return; } interface->restoreCurrentTime(&m_storage->value); interface->image()->enableUIUpdates(); } struct AddNewFrame : public KisCommandUtils::AggregateCommand { AddNewFrame(MergeDownInfoBaseSP info, int frame) : m_info(info), m_frame(frame) {} void populateChildCommands() { KUndo2Command *cmd = new KisCommandUtils::SkipFirstRedoWrapper(); KisKeyframeChannel *channel = m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Content.id()); channel->addKeyframe(m_frame, cmd); addCommand(cmd); } private: MergeDownInfoBaseSP m_info; int m_frame; }; QSet fetchLayerFrames(KisNodeSP node) { KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Content.id()); if (!channel) return QSet(); return channel->allKeyframeIds(); } QSet fetchLayerFramesRecursive(KisNodeSP rootNode) { QSet frames = fetchLayerFrames(rootNode); KisNodeSP node = rootNode->firstChild(); while(node) { frames |= fetchLayerFramesRecursive(node); node = node->nextSibling(); } return frames; } void updateFrameJobs(FrameJobs *jobs, KisNodeSP node) { QSet frames = fetchLayerFrames(node); if (frames.isEmpty()) { (*jobs)[0].insert(node); } else { foreach (int frame, frames) { (*jobs)[frame].insert(node); } } } void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode) { updateFrameJobs(jobs, rootNode); KisNodeSP node = rootNode->firstChild(); while(node) { updateFrameJobsRecursive(jobs, node); node = node->nextSibling(); } } void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy) { if (!layer->prevSibling()) return; // XXX: this breaks if we allow free mixing of masks and layers KisLayerSP prevLayer = dynamic_cast(layer->prevSibling().data()); if (!prevLayer) return; if (!layer->visible() && !prevLayer->visible()) { return; } KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Merge Down")); if (layer->visible() && prevLayer->visible()) { MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer)); // disable key strokes on all colorize masks and wait until // update is finished with a barrier applicator.applyCommand(new DisableColorizeKeyStrokes(info)); applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); applicator.applyCommand(new KeepMergedNodesSelected(info, false)); applicator.applyCommand(new FillSelectionMasks(info)); applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER); if (info->frames.size() > 0) { foreach (int frame, info->frames) { applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage)); applicator.applyCommand(new AddNewFrame(info, frame)); applicator.applyCommand(new RefreshHiddenAreas(info)); applicator.applyCommand(new MergeLayers(info), KisStrokeJobData::BARRIER); applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage)); } } else { applicator.applyCommand(new RefreshHiddenAreas(info)); applicator.applyCommand(new MergeLayers(info), KisStrokeJobData::BARRIER); } applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER); applicator.applyCommand(new CleanUpNodes(info, layer), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.applyCommand(new KeepMergedNodesSelected(info, true)); } else if (layer->visible()) { applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), layer, KisNodeSP(), image, false)); applicator.applyCommand( new SimpleRemoveLayers(KisNodeList() << prevLayer, image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), KisNodeSP(), layer, image, true)); } else if (prevLayer->visible()) { applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), layer, KisNodeSP(), image, false)); applicator.applyCommand( new SimpleRemoveLayers(KisNodeList() << layer, image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(), KisNodeSP(), prevLayer, image, true)); } applicator.end(); } bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents) { KisNodeList nodeParents; KisNodeSP parent = node->parent(); while (parent) { nodeParents << parent; parent = parent->parent(); } foreach(KisNodeSP perspectiveParent, parents) { if (nodeParents.contains(perspectiveParent)) { return true; } } return false; } bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes) { bool result = false; KisCloneLayer *clone = dynamic_cast(node.data()); if (clone) { KisNodeSP cloneSource = KisNodeSP(clone->copyFrom()); Q_FOREACH(KisNodeSP subtree, nodes) { result = recursiveFindNode(subtree, [cloneSource](KisNodeSP node) -> bool { return node == cloneSource; }); if (!result) { result = checkIsCloneOf(cloneSource, nodes); } if (result) { break; } } } return result; } void filterMergableNodes(KisNodeList &nodes, bool allowMasks) { KisNodeList::iterator it = nodes.begin(); while (it != nodes.end()) { if ((!allowMasks && !dynamic_cast(it->data())) || checkIsChildOf(*it, nodes)) { qDebug() << "Skipping node" << ppVar((*it)->name()); it = nodes.erase(it); } else { ++it; } } } void sortMergableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes) { KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root); if (it != inputNodes.end()) { outputNodes << *it; inputNodes.erase(it); } if (inputNodes.isEmpty()) { return; } KisNodeSP child = root->firstChild(); while (child) { sortMergableNodes(child, inputNodes, outputNodes); child = child->nextSibling(); } /** * By the end of recursion \p inputNodes must be empty */ KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty()); } KisNodeList sortMergableNodes(KisNodeSP root, KisNodeList nodes) { KisNodeList result; sortMergableNodes(root, nodes, result); return result; } KisNodeList sortAndFilterMergableInternalNodes(KisNodeList nodes, bool allowMasks) { KIS_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; } KisNodeSP root; Q_FOREACH(KisNodeSP node, nodes) { KisNodeSP localRoot = node; while (localRoot->parent()) { localRoot = localRoot->parent(); } if (!root) { root = localRoot; } KIS_ASSERT_RECOVER(root == localRoot) { return nodes; } } KisNodeList result; sortMergableNodes(root, nodes, result); filterMergableNodes(result, allowMasks); return result; } void addCopyOfNameTag(KisNodeSP node) { const QString prefix = i18n("Copy of"); QString newName = node->name(); if (!newName.startsWith(prefix)) { newName = QString("%1 %2").arg(prefix).arg(newName); node->setName(newName); } } KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot) { KisNodeList nodes; if ((!excludeRoot || root->parent()) && root->check(props)) { nodes << root; } KisNodeSP node = root->firstChild(); while (node) { nodes += findNodesWithProps(node, props, excludeRoot); node = node->nextSibling(); } return nodes; } KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter) { KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; } KIS_ASSERT_RECOVER(putAfter) { return nodes; } KisNodeList visibleNodes; int putAfterIndex = -1; Q_FOREACH(KisNodeSP node, nodes) { if (node->visible()) { visibleNodes << node; } else { *invisibleNodes << node; if (node == *putAfter) { putAfterIndex = visibleNodes.size() - 1; } } } if (!visibleNodes.isEmpty() && putAfterIndex >= 0) { putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1); *putAfter = visibleNodes[putAfterIndex]; } return visibleNodes; } void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color) { KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(image, image->root(), KisProcessingApplicator::RECURSIVE, emitSignals, kundo2_i18n("Change projection color"), 0, 142857 + 1); applicator.applyCommand(new KisChangeProjectionColorCommand(image, color), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE); applicator.end(); } - void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, bool flattenSingleLayer, const KUndo2MagicString &actionName) + void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, + bool flattenSingleLayer, const KUndo2MagicString &actionName, + bool cleanupNodes = true, const QString layerName = QString()) { filterMergableNodes(mergedNodes); { KisNodeList tempNodes; qSwap(mergedNodes, tempNodes); sortMergableNodes(image->root(), tempNodes, mergedNodes); } if (mergedNodes.size() <= 1 && (!flattenSingleLayer && mergedNodes.size() == 1)) return; KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes); KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, actionName); KisNodeList originalNodes = mergedNodes; KisNodeList invisibleNodes; mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter); if (!invisibleNodes.isEmpty()) { applicator.applyCommand( new SimpleRemoveLayers(invisibleNodes, image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) { MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes)); // disable key strokes on all colorize masks and wait until // update is finished with a barrier applicator.applyCommand(new DisableColorizeKeyStrokes(info)); applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER); applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false)); applicator.applyCommand(new FillSelectionMasks(info)); - applicator.applyCommand(new CreateMergedLayerMultiple(info), KisStrokeJobData::BARRIER); + applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER); if (info->frames.size() > 0) { foreach (int frame, info->frames) { applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage)); applicator.applyCommand(new AddNewFrame(info, frame)); applicator.applyCommand(new RefreshHiddenAreas(info)); applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER); applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage)); } } else { applicator.applyCommand(new RefreshHiddenAreas(info)); applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER); } //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER); - applicator.applyCommand(new CleanUpNodes(info, putAfter), - KisStrokeJobData::SEQUENTIAL, - KisStrokeJobData::EXCLUSIVE); + if (cleanupNodes){ + applicator.applyCommand(new CleanUpNodes(info, putAfter), + KisStrokeJobData::SEQUENTIAL, + KisStrokeJobData::EXCLUSIVE); + } else { + applicator.applyCommand(new InsertNode(info, putAfter), + KisStrokeJobData::SEQUENTIAL, + KisStrokeJobData::EXCLUSIVE); + } applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true)); } applicator.end(); } void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter) { - mergeMultipleLayersImpl(image, mergedNodes, putAfter, false, kundo2_i18n("Merge Selected Nodes")); + mergeMultipleLayersImpl(image, mergedNodes, putAfter, false, kundo2_i18n("Merge Selected Nodes"), false); + } + + void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter) + { + KisNodeList mergedNodes; + mergedNodes << image->root(); + + mergeMultipleLayersImpl(image, mergedNodes, putAfter, true, kundo2_i18n("New From Visible"), false, i18nc("New layer created from all the visible layers", "Visible")); } struct MergeSelectionMasks : public KisCommandUtils::AggregateCommand { MergeSelectionMasks(MergeDownInfoBaseSP info, KisNodeSP putAfter) : m_info(info), m_putAfter(putAfter){} void populateChildCommands() { KisNodeSP parent; CleanUpNodes::findPerfectParent(m_info->allSrcNodes(), m_putAfter, parent); KisLayerSP parentLayer; do { parentLayer = dynamic_cast(parent.data()); parent = parent->parent(); } while(!parentLayer && parent); KisSelectionSP selection = new KisSelection(); foreach (KisNodeSP node, m_info->allSrcNodes()) { KisMaskSP mask = dynamic_cast(node.data()); if (!mask) continue; selection->pixelSelection()->applySelection( mask->selection()->pixelSelection(), SELECTION_ADD); } KisSelectionMaskSP mergedMask = new KisSelectionMask(m_info->image); mergedMask->initSelection(parentLayer); mergedMask->setSelection(selection); m_info->dstNode = mergedMask; } private: MergeDownInfoBaseSP m_info; KisNodeSP m_putAfter; }; struct ActivateSelectionMask : public KisCommandUtils::AggregateCommand { ActivateSelectionMask(MergeDownInfoBaseSP info) : m_info(info) {} void populateChildCommands() { KisSelectionMaskSP mergedMask = dynamic_cast(m_info->dstNode.data()); addCommand(new KisActivateSelectionMaskCommand(mergedMask, true)); } private: MergeDownInfoBaseSP m_info; }; bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter) { QList selectionMasks; for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) { KisSelectionMaskSP mask = dynamic_cast(it->data()); if (!mask) { it = mergedNodes.erase(it); } else { selectionMasks.append(mask); ++it; } } if (mergedNodes.isEmpty()) return false; KisLayerSP parentLayer = dynamic_cast(selectionMasks.first()->parent().data()); KIS_ASSERT_RECOVER(parentLayer) { return 0; } KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Merge Selection Masks")); MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes)); applicator.applyCommand(new MergeSelectionMasks(info, putAfter)); applicator.applyCommand(new CleanUpNodes(info, putAfter), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.applyCommand(new ActivateSelectionMask(info)); applicator.end(); return true; } void flattenLayer(KisImageSP image, KisLayerSP layer) { if (!layer->childCount() && !layer->layerStyle()) return; KisNodeList mergedNodes; mergedNodes << layer; mergeMultipleLayersImpl(image, mergedNodes, layer, true, kundo2_i18n("Flatten Layer")); } void flattenImage(KisImageSP image) { KisNodeList mergedNodes; mergedNodes << image->root(); mergeMultipleLayersImpl(image, mergedNodes, 0, true, kundo2_i18n("Flatten Image")); } KisSimpleUpdateCommand::KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent) : FlipFlopCommand(finalize, parent), m_nodes(nodes) { } void KisSimpleUpdateCommand::end() { updateNodes(m_nodes); } void KisSimpleUpdateCommand::updateNodes(const KisNodeList &nodes) { Q_FOREACH(KisNodeSP node, nodes) { node->setDirty(node->extent()); } } void recursiveApplyNodes(KisNodeSP node, std::function func) { func(node); node = node->firstChild(); while (node) { recursiveApplyNodes(node, func); node = node->nextSibling(); } } KisNodeSP recursiveFindNode(KisNodeSP node, std::function func) { if (func(node)) { return node; } node = node->firstChild(); while (node) { KisNodeSP resultNode = recursiveFindNode(node, func); if (resultNode) { return resultNode; } node = node->nextSibling(); } return 0; } } diff --git a/libs/image/kis_layer_utils.h b/libs/image/kis_layer_utils.h index 46550d86c6..c815cb506f 100644 --- a/libs/image/kis_layer_utils.h +++ b/libs/image/kis_layer_utils.h @@ -1,196 +1,198 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LAYER_UTILS_H #define __KIS_LAYER_UTILS_H #include #include "kundo2command.h" #include "kis_types.h" #include "kritaimage_export.h" #include "kis_command_utils.h" class KoProperties; class KoColor; namespace KisMetaData { class MergeStrategy; } namespace KisLayerUtils { KRITAIMAGE_EXPORT void sortMergableNodes(KisNodeSP root, QList &inputNodes, QList &outputNodes); KRITAIMAGE_EXPORT KisNodeList sortMergableNodes(KisNodeSP root, KisNodeList nodes); KRITAIMAGE_EXPORT void filterMergableNodes(KisNodeList &nodes, bool allowMasks = false); KRITAIMAGE_EXPORT bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents); /** * Returns true if: * o \p node is a clone of some layer in \p nodes * o \p node is a clone any child layer of any layer in \p nodes * o \p node is a clone of a clone of a ..., that in the end points * to any layer in \p nodes of their children. */ KRITAIMAGE_EXPORT bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes); KRITAIMAGE_EXPORT KisNodeList sortAndFilterMergableInternalNodes(KisNodeList nodes, bool allowMasks = false); KRITAIMAGE_EXPORT void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy); KRITAIMAGE_EXPORT QSet fetchLayerFrames(KisNodeSP node); KRITAIMAGE_EXPORT QSet fetchLayerFramesRecursive(KisNodeSP rootNode); KRITAIMAGE_EXPORT void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter); + KRITAIMAGE_EXPORT void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter); + KRITAIMAGE_EXPORT bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter); KRITAIMAGE_EXPORT void flattenLayer(KisImageSP image, KisLayerSP layer); KRITAIMAGE_EXPORT void flattenImage(KisImageSP image); KRITAIMAGE_EXPORT void addCopyOfNameTag(KisNodeSP node); KRITAIMAGE_EXPORT KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot); KRITAIMAGE_EXPORT void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color); typedef QMap > FrameJobs; void updateFrameJobs(FrameJobs *jobs, KisNodeSP node); void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode); struct SwitchFrameCommand : public KisCommandUtils::FlipFlopCommand { struct SharedStorage { /** * For some reason the absence of a destructor in the SharedStorage * makes Krita crash on exit. Seems like some compiler weirdness... (DK) */ ~SharedStorage(); int value; }; typedef QSharedPointer SharedStorageSP; public: SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage); ~SwitchFrameCommand(); private: void init(); void end(); private: KisImageWSP m_image; int m_newTime; SharedStorageSP m_storage; }; /** * A command to keep correct set of selected/active nodes thoroughout * the action. */ class KRITAIMAGE_EXPORT KeepNodesSelectedCommand : public KisCommandUtils::FlipFlopCommand { public: KeepNodesSelectedCommand(const KisNodeList &selectedBefore, const KisNodeList &selectedAfter, KisNodeSP activeBefore, KisNodeSP activeAfter, KisImageSP image, bool finalize, KUndo2Command *parent = 0); void end(); private: KisNodeList m_selectedBefore; KisNodeList m_selectedAfter; KisNodeSP m_activeBefore; KisNodeSP m_activeAfter; KisImageWSP m_image; }; KRITAIMAGE_EXPORT KisLayerSP constructDefaultLayer(KisImageSP image); class KRITAIMAGE_EXPORT RemoveNodeHelper { public: virtual ~RemoveNodeHelper(); protected: virtual void addCommandImpl(KUndo2Command *cmd) = 0; void safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image); private: bool checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes); static bool scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove); }; struct SimpleRemoveLayers : private KisLayerUtils::RemoveNodeHelper, public KisCommandUtils::AggregateCommand { SimpleRemoveLayers(const KisNodeList &nodes, KisImageSP image); void populateChildCommands(); protected: virtual void addCommandImpl(KUndo2Command *cmd); private: KisNodeList m_nodes; KisImageSP m_image; KisNodeList m_selectedNodes; KisNodeSP m_activeNode; }; class KRITAIMAGE_EXPORT KisSimpleUpdateCommand : public KisCommandUtils::FlipFlopCommand { public: KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent = 0); void end(); static void updateNodes(const KisNodeList &nodes); private: KisNodeList m_nodes; }; template bool checkNodesDiffer(KisNodeList nodes, std::function checkerFunc) { bool valueDiffers = false; bool initialized = false; T currentValue; Q_FOREACH (KisNodeSP node, nodes) { if (!initialized) { currentValue = checkerFunc(node); initialized = true; } else if (currentValue != checkerFunc(node)) { valueDiffers = true; break; } } return valueDiffers; } /** * Applies \p func to \p node and all its children recursively */ void KRITAIMAGE_EXPORT recursiveApplyNodes(KisNodeSP node, std::function func); /** * Walks through \p node and all its children recursively until * \p func returns true. When \p func returns true, the node is * considered to be found, the search is stopped and the found * node is returned to the caller. */ KisNodeSP KRITAIMAGE_EXPORT recursiveFindNode(KisNodeSP node, std::function func); }; #endif /* __KIS_LAYER_UTILS_H */ diff --git a/libs/image/kis_node_filter_interface.cpp b/libs/image/kis_node_filter_interface.cpp index 23100e18f8..7f385c5cba 100644 --- a/libs/image/kis_node_filter_interface.cpp +++ b/libs/image/kis_node_filter_interface.cpp @@ -1,92 +1,92 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2012 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_node_filter_interface.h" #include "filter/kis_filter.h" #include "generator/kis_generator.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "generator/kis_generator_registry.h" #ifdef SANITY_CHECK_FILTER_CONFIGURATION_OWNER #define SANITY_ACQUIRE_FILTER(filter) \ do { \ if ((filter)) { \ (filter)->sanityRefUsageCounter(); \ } \ } while (0) #define SANITY_RELEASE_FILTER(filter) \ do { \ if (m_filter && m_filter->sanityDerefUsageCounter()) { \ warnKrita; \ warnKrita << "WARNING: filter configuration has more than one user! Krita will probably crash soon!"; \ warnKrita << "WARNING:" << ppVar(this); \ warnKrita << "WARNING:" << ppVar(filter.data()); \ warnKrita; \ } \ } while (0) #else /* SANITY_CHECK_FILTER_CONFIGURATION_OWNER */ #define SANITY_ACQUIRE_FILTER(filter) #define SANITY_RELEASE_FILTER(filter) #endif /* SANITY_CHECK_FILTER_CONFIGURATION_OWNER*/ -KisNodeFilterInterface::KisNodeFilterInterface(KisFilterConfiguration *filterConfig, bool useGeneratorRegistry) +KisNodeFilterInterface::KisNodeFilterInterface(KisFilterConfigurationSP filterConfig, bool useGeneratorRegistry) : m_filter(filterConfig), m_useGeneratorRegistry(useGeneratorRegistry) { SANITY_ACQUIRE_FILTER(m_filter); } KisNodeFilterInterface::KisNodeFilterInterface(const KisNodeFilterInterface &rhs) : m_useGeneratorRegistry(rhs.m_useGeneratorRegistry) { if (m_useGeneratorRegistry) { - m_filter = KisSafeFilterConfigurationSP(KisGeneratorRegistry::instance()->cloneConfiguration(rhs.m_filter.data())); + m_filter = KisGeneratorRegistry::instance()->cloneConfiguration(const_cast(rhs.m_filter.data())); } else { - m_filter = KisSafeFilterConfigurationSP(KisFilterRegistry::instance()->cloneConfiguration(rhs.m_filter.data())); + m_filter = KisFilterRegistry::instance()->cloneConfiguration(const_cast(rhs.m_filter.data())); } SANITY_ACQUIRE_FILTER(m_filter); } KisNodeFilterInterface::~KisNodeFilterInterface() { SANITY_RELEASE_FILTER(m_filter); } -KisSafeFilterConfigurationSP KisNodeFilterInterface::filter() const +KisFilterConfigurationSP KisNodeFilterInterface::filter() const { return m_filter; } -void KisNodeFilterInterface::setFilter(KisFilterConfiguration *filterConfig) +void KisNodeFilterInterface::setFilter(KisFilterConfigurationSP filterConfig) { SANITY_RELEASE_FILTER(m_filter); Q_ASSERT(filterConfig); - m_filter = KisSafeFilterConfigurationSP(filterConfig); + m_filter = filterConfig; SANITY_ACQUIRE_FILTER(m_filter); } diff --git a/libs/image/kis_node_filter_interface.h b/libs/image/kis_node_filter_interface.h index e8af0f814e..cee5e1c1f4 100644 --- a/libs/image/kis_node_filter_interface.h +++ b/libs/image/kis_node_filter_interface.h @@ -1,61 +1,59 @@ /* * Copyright (c) 2008 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_NODE_FILTER_INTERFACE_H_ #define _KIS_NODE_FILTER_INTERFACE_H_ #include #include -class KisFilterConfiguration; - /** * Define an interface for nodes that are associated with a filter. */ class KRITAIMAGE_EXPORT KisNodeFilterInterface { public: - KisNodeFilterInterface(KisFilterConfiguration *filterConfig, bool useGeneratorRegistry); + KisNodeFilterInterface(KisFilterConfigurationSP filterConfig, bool useGeneratorRegistry); KisNodeFilterInterface(const KisNodeFilterInterface &rhs); virtual ~KisNodeFilterInterface(); /** * @return safe shared pointer to the filter configuration * associated with this node */ - virtual KisSafeFilterConfigurationSP filter() const; + virtual KisFilterConfigurationSP filter() const; /** * Sets the filter configuration for this node. The filter might * differ from the filter that is currently set up on this node. * * WARNING: the filterConfig becomes *owned* by the node right * after you've set it. Don't try to access the configuration * after you've associated it with the node. */ - virtual void setFilter(KisFilterConfiguration *filterConfig); + virtual void setFilter(KisFilterConfigurationSP filterConfig); // the child classes should access the filter with the filter() method private: KisNodeFilterInterface& operator=(const KisNodeFilterInterface &other); - KisSafeFilterConfigurationSP m_filter; + KisFilterConfigurationSP m_filter; bool m_useGeneratorRegistry; }; #endif diff --git a/libs/image/kis_painter.cc b/libs/image/kis_painter.cc index c6304750c9..614c4828fb 100644 --- a/libs/image/kis_painter.cc +++ b/libs/image/kis_painter.cc @@ -1,2883 +1,2886 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2008-2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * Copyright (c) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_painter.h" #include #include #include #include #include #ifndef Q_OS_WIN #include #endif #include #include #include #include #include #include #include #include #include #include #include "kis_image.h" #include "filter/kis_filter.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_fixed_paint_device.h" #include "kis_transaction.h" #include "kis_vec.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_paintop.h" #include "kis_selection.h" #include "kis_fill_painter.h" #include "filter/kis_filter_configuration.h" #include "kis_pixel_selection.h" #include #include "kis_paintop_registry.h" #include "kis_perspective_math.h" #include "tiles3/kis_random_accessor.h" #include #include #include "kis_lod_transform.h" + + // Maximum distance from a Bezier control point to the line through the start // and end points for the curve to be considered flat. #define BEZIER_FLATNESS_THRESHOLD 0.5 #define trunc(x) ((int)(x)) #ifndef Q_OS_WIN #endif struct Q_DECL_HIDDEN KisPainter::Private { Private(KisPainter *_q) : q(_q) {} Private(KisPainter *_q, const KoColorSpace *cs) : q(_q), paintColor(cs), backgroundColor(cs) {} KisPainter *q; KisPaintDeviceSP device; KisSelectionSP selection; KisTransaction* transaction; KoUpdater* progressUpdater; QVector dirtyRects; KisPaintOp* paintOp; KoColor paintColor; KoColor backgroundColor; - const KisFilterConfiguration* generator; + KoColor customColor; + KisFilterConfigurationSP generator; KisPaintLayer* sourceLayer; FillStyle fillStyle; StrokeStyle strokeStyle; bool antiAliasPolygonFill; const KoPattern* pattern; QPointF duplicateOffset; quint32 pixelSize; const KoColorSpace* colorSpace; KoColorProfile* profile; const KoCompositeOp* compositeOp; const KoAbstractGradient* gradient; KisPaintOpPresetSP paintOpPreset; QImage polygonMaskImage; QPainter* maskPainter; KisFillPainter* fillPainter; KisPaintDeviceSP polygon; qint32 maskImageWidth; qint32 maskImageHeight; QPointF axesCenter; bool mirrorHorizontally; bool mirrorVertically; bool isOpacityUnit; // TODO: move into ParameterInfo KoCompositeOp::ParameterInfo paramInfo; KoColorConversionTransformation::Intent renderingIntent; KoColorConversionTransformation::ConversionFlags conversionFlags; bool tryReduceSourceRect(const KisPaintDevice *srcDev, QRect *srcRect, qint32 *srcX, qint32 *srcY, qint32 *srcWidth, qint32 *srcHeight, qint32 *dstX, qint32 *dstY); void fillPainterPathImpl(const QPainterPath& path, const QRect &requestedRect); }; KisPainter::KisPainter() : d(new Private(this)) { init(); } KisPainter::KisPainter(KisPaintDeviceSP device) : d(new Private(this, device->colorSpace())) { init(); Q_ASSERT(device); begin(device); } KisPainter::KisPainter(KisPaintDeviceSP device, KisSelectionSP selection) : d(new Private(this, device->colorSpace())) { init(); Q_ASSERT(device); begin(device); d->selection = selection; } void KisPainter::init() { d->selection = 0 ; d->transaction = 0; d->paintOp = 0; d->pattern = 0; d->sourceLayer = 0; d->fillStyle = FillStyleNone; d->strokeStyle = StrokeStyleBrush; d->antiAliasPolygonFill = true; d->progressUpdater = 0; d->gradient = 0; d->maskPainter = 0; d->fillPainter = 0; d->maskImageWidth = 255; d->maskImageHeight = 255; d->mirrorHorizontally = false; d->mirrorVertically = false; d->isOpacityUnit = true; d->paramInfo = KoCompositeOp::ParameterInfo(); d->renderingIntent = KoColorConversionTransformation::internalRenderingIntent(); d->conversionFlags = KoColorConversionTransformation::internalConversionFlags(); } KisPainter::~KisPainter() { // TODO: Maybe, don't be that strict? // deleteTransaction(); end(); delete d->paintOp; delete d->maskPainter; delete d->fillPainter; delete d; } template void copyAreaOptimizedImpl(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { const QRect dstRect(dstPt, srcRect.size()); const bool srcEmpty = (src->extent() & srcRect).isEmpty(); const bool dstEmpty = (dst->extent() & dstRect).isEmpty(); if (!srcEmpty || !dstEmpty) { if (srcEmpty) { dst->clear(dstRect); } else { KisPainter gc(dst); gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY)); if (useOldData) { gc.bitBltOldData(dstRect.topLeft(), src, srcRect); } else { gc.bitBlt(dstRect.topLeft(), src, srcRect); } } } } void KisPainter::copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { copyAreaOptimizedImpl(dstPt, src, dst, srcRect); } void KisPainter::copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { copyAreaOptimizedImpl(dstPt, src, dst, srcRect); } void KisPainter::copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect, KisSelectionSP selection) { if (!selection) { copyAreaOptimized(dstPt, src, dst, originalSrcRect); return; } const QRect selectionRect = selection->selectedRect(); const QRect srcRect = originalSrcRect & selectionRect; const QPoint dstOffset = srcRect.topLeft() - originalSrcRect.topLeft(); const QRect dstRect = QRect(dstPt + dstOffset, srcRect.size()); const bool srcEmpty = (src->extent() & srcRect).isEmpty(); const bool dstEmpty = (dst->extent() & dstRect).isEmpty(); if (!srcEmpty || !dstEmpty) { //if (srcEmpty) { // doesn't support dstRect // dst->clearSelection(selection); // } else */ { KisPainter gc(dst); gc.setSelection(selection); gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY)); gc.bitBlt(dstRect.topLeft(), src, srcRect); } } } KisPaintDeviceSP KisPainter::convertToAlphaAsAlpha(KisPaintDeviceSP src) { const KoColorSpace *srcCS = src->colorSpace(); const QRect processRect = src->extent(); KisPaintDeviceSP dst = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); KisSequentialConstIterator srcIt(src, processRect); KisSequentialIterator dstIt(dst, processRect); do { const quint8 *srcPtr = srcIt.rawDataConst(); quint8 *alpha8Ptr = dstIt.rawData(); const quint8 white = srcCS->intensity8(srcPtr); const quint8 alpha = srcCS->opacityU8(srcPtr); *alpha8Ptr = KoColorSpaceMaths::multiply(alpha, KoColorSpaceMathsTraits::unitValue - white); } while (srcIt.nextPixel() && dstIt.nextPixel()); return dst; } KisPaintDeviceSP KisPainter::convertToAlphaAsGray(KisPaintDeviceSP src) { const KoColorSpace *srcCS = src->colorSpace(); const QRect processRect = src->extent(); KisPaintDeviceSP dst = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); KisSequentialConstIterator srcIt(src, processRect); KisSequentialIterator dstIt(dst, processRect); do { const quint8 *srcPtr = srcIt.rawDataConst(); quint8 *alpha8Ptr = dstIt.rawData(); *alpha8Ptr = srcCS->intensity8(srcPtr); } while (srcIt.nextPixel() && dstIt.nextPixel()); return dst; } void KisPainter::begin(KisPaintDeviceSP device) { begin(device, d->selection); } void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection) { if (!device) return; d->selection = selection; Q_ASSERT(device->colorSpace()); end(); d->device = device; d->colorSpace = device->colorSpace(); d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER); d->pixelSize = device->pixelSize(); } void KisPainter::end() { Q_ASSERT_X(!d->transaction, "KisPainter::end()", "end() was called for the painter having a transaction. " "Please use end/deleteTransaction() instead"); } void KisPainter::beginTransaction(const KUndo2MagicString& transactionName,int timedID) { Q_ASSERT_X(!d->transaction, "KisPainter::beginTransaction()", "You asked for a new transaction while still having " "another one. Please finish the first one with " "end/deleteTransaction() first"); d->transaction = new KisTransaction(transactionName, d->device); Q_CHECK_PTR(d->transaction); d->transaction->undoCommand()->setTimedID(timedID); } void KisPainter::revertTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::revertTransaction()", "No transaction is in progress"); d->transaction->revert(); delete d->transaction; d->transaction = 0; } void KisPainter::endTransaction(KisUndoAdapter *undoAdapter) { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); d->transaction->commit(undoAdapter); delete d->transaction; d->transaction = 0; } void KisPainter::endTransaction(KisPostExecutionUndoAdapter *undoAdapter) { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); d->transaction->commit(undoAdapter); delete d->transaction; d->transaction = 0; } KUndo2Command* KisPainter::endAndTakeTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); KUndo2Command *transactionData = d->transaction->endAndTake(); delete d->transaction; d->transaction = 0; return transactionData; } void KisPainter::deleteTransaction() { if (!d->transaction) return; delete d->transaction; d->transaction = 0; } void KisPainter::putTransaction(KisTransaction* transaction) { Q_ASSERT_X(!d->transaction, "KisPainter::putTransaction()", "You asked for a new transaction while still having " "another one. Please finish the first one with " "end/deleteTransaction() first"); d->transaction = transaction; } KisTransaction* KisPainter::takeTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::takeTransaction()", "No transaction is in progress"); KisTransaction *temp = d->transaction; d->transaction = 0; return temp; } QVector KisPainter::takeDirtyRegion() { QVector vrect = d->dirtyRects; d->dirtyRects.clear(); return vrect; } void KisPainter::addDirtyRect(const QRect & rc) { QRect r = rc.normalized(); if (r.isValid()) { d->dirtyRects.append(rc); } } inline bool KisPainter::Private::tryReduceSourceRect(const KisPaintDevice *srcDev, QRect *srcRect, qint32 *srcX, qint32 *srcY, qint32 *srcWidth, qint32 *srcHeight, qint32 *dstX, qint32 *dstY) { /** * In case of COMPOSITE_COPY and Wrap Around Mode even the pixels * outside the device extent matter, because they will be either * directly copied (former case) or cloned from another area of * the image. */ if (compositeOp->id() != COMPOSITE_COPY && !srcDev->defaultBounds()->wrapAroundMode()) { /** * If srcDev->extent() (the area of the tiles containing * srcDev) is smaller than srcRect, then shrink srcRect to * that size. This is done as a speed optimization, useful for * stack recomposition in KisImage. srcRect won't grow if * srcDev->extent() is larger. */ *srcRect &= srcDev->extent(); if (srcRect->isEmpty()) return true; // Readjust the function paramenters to the new dimensions. *dstX += srcRect->x() - *srcX; // This will only add, not subtract *dstY += srcRect->y() - *srcY; // Idem srcRect->getRect(srcX, srcY, srcWidth, srcHeight); } return false; } void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { // TODO: get selX and selY working as intended /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; // Check that selection has an alpha colorspace, crash if false Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8()); QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect selRect = QRect(selX, selY, srcWidth, srcHeight); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize YET as it would obfuscate the mistake. */ Q_ASSERT(selection->bounds().contains(selRect)); Q_UNUSED(selRect); // only used by the above Q_ASSERT /** * An optimization, which crops the source rect by the bounds of * the source device when it is possible */ if (d->tryReduceSourceRect(srcDev, &srcRect, &srcX, &srcY, &srcWidth, &srcHeight, &dstX, &dstY)) return; /* Create an intermediate byte array to hold information before it is written to the current paint device (d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "dst bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); // Copy the relevant bytes of raw data from srcDev quint8* srcBytes = 0; try { srcBytes = new quint8[srcWidth * srcHeight * srcDev->pixelSize()]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "src bytes"; return; } srcDev->readBytes(srcBytes, srcX, srcY, srcWidth, srcHeight); QRect selBounds = selection->bounds(); const quint8 *selRowStart = selection->data() + (selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize(); /* * This checks whether there is nothing selected. */ if (!d->selection) { /* As there's nothing selected, blit to dstBytes (intermediary bit array), ignoring d->selection (the user selection)*/ d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcBytes; d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize(); d->paramInfo.maskRowStart = selRowStart; d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } else { /* Read the user selection (d->selection) bytes into an array, ready to merge in the next block*/ quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize(); quint8* mergedSelectionBytes = 0; try { mergedSelectionBytes = new quint8[ totalBytes ]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight); // Merge selections here by multiplying them - compositeOP(COMPOSITE_MULT) d->paramInfo.dstRowStart = mergedSelectionBytes; d->paramInfo.dstRowStride = srcWidth * selection->pixelSize(); d->paramInfo.srcRowStart = selRowStart; d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo); // Blit to dstBytes (intermediary bit array) d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcBytes; d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize(); d->paramInfo.maskRowStart = mergedSelectionBytes; d->paramInfo.maskRowStride = srcWidth * selection->pixelSize(); d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); delete[] mergedSelectionBytes; } d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] dstBytes; delete[] srcBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 srcWidth, qint32 srcHeight) { bitBltWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight); } template void KisPainter::bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); if (d->compositeOp->id() == COMPOSITE_COPY) { if(!d->selection && d->isOpacityUnit && srcX == dstX && srcY == dstY && d->device->fastBitBltPossible(srcDev)) { if(useOldSrcData) { d->device->fastBitBltOldData(srcDev, srcRect); } else { d->device->fastBitBlt(srcDev, srcRect); } addDirtyRect(srcRect); return; } } else { /** * An optimization, which crops the source rect by the bounds of * the source device when it is possible */ if (d->tryReduceSourceRect(srcDev, &srcRect, &srcX, &srcY, &srcWidth, &srcHeight, &dstX, &dstY)) return; } qint32 dstY_ = dstY; qint32 srcY_ = srcY; qint32 rowsRemaining = srcHeight; // Read below KisRandomConstAccessorSP srcIt = srcDev->createRandomConstAccessorNG(srcX, srcY); KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG(dstX, dstY); /* Here be a huge block of verbose code that does roughly the same than the other bit blit operations. This one is longer than the rest in an effort to optimize speed and memory use */ if (d->selection) { KisPaintDeviceSP selectionProjection = d->selection->projection(); KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG(dstX, dstY); while (rowsRemaining > 0) { qint32 dstX_ = dstX; qint32 srcX_ = srcX; qint32 columnsRemaining = srcWidth; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_); qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_); qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY_); qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows); rows = qMin(rows, numContiguousSelRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_); qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_); qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX_); qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns); columns = qMin(columns, numContiguousSelColumns); columns = qMin(columns, columnsRemaining); qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_); srcIt->moveTo(srcX_, srcY_); qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_); dstIt->moveTo(dstX_, dstY_); qint32 maskRowStride = maskIt->rowStride(dstX_, dstY_); maskIt->moveTo(dstX_, dstY_); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; // if we don't use the oldRawData, we need to access the rawData of the source device. d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast(srcIt.data())->rawData(); d->paramInfo.srcRowStride = srcRowStride; d->paramInfo.maskRowStart = static_cast(maskIt.data())->rawData(); d->paramInfo.maskRowStride = maskRowStride; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); srcX_ += columns; dstX_ += columns; columnsRemaining -= columns; } srcY_ += rows; dstY_ += rows; rowsRemaining -= rows; } } else { while (rowsRemaining > 0) { qint32 dstX_ = dstX; qint32 srcX_ = srcX; qint32 columnsRemaining = srcWidth; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_); qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_); qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_); qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_); qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns); columns = qMin(columns, columnsRemaining); qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_); srcIt->moveTo(srcX_, srcY_); qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_); dstIt->moveTo(dstX_, dstY_); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; // if we don't use the oldRawData, we need to access the rawData of the source device. d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast(srcIt.data())->rawData(); d->paramInfo.srcRowStride = srcRowStride; d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); srcX_ += columns; dstX_ += columns; columnsRemaining -= columns; } srcY_ += rows; dstY_ += rows; rowsRemaining -= rows; } } addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { bitBltImpl(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight); } void KisPainter::bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect) { bitBlt(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { bitBltImpl(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight); } void KisPainter::bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect) { bitBltOldData(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just * initializing they perform some dummy passes with those parameters, and it must not crash */ if(width == 0 || height == 0 || d->device.isNull()) return; KoColor srcColor(color, d->device->compositionSourceColorSpace()); qint32 dstY = y; qint32 rowsRemaining = height; KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG(x, y); if(d->selection) { KisPaintDeviceSP selectionProjection = d->selection->projection(); KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG(x, y); while(rowsRemaining > 0) { qint32 dstX = x; qint32 columnsRemaining = width; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY); qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY); qint32 rows = qMin(numContiguousDstRows, numContiguousSelRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX); qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX); qint32 columns = qMin(numContiguousDstColumns, numContiguousSelColumns); columns = qMin(columns, columnsRemaining); qint32 dstRowStride = dstIt->rowStride(dstX, dstY); dstIt->moveTo(dstX, dstY); qint32 maskRowStride = maskIt->rowStride(dstX, dstY); maskIt->moveTo(dstX, dstY); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; d->paramInfo.srcRowStart = srcColor.data(); d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel d->paramInfo.maskRowStart = maskIt->oldRawData(); d->paramInfo.maskRowStride = maskRowStride; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); dstX += columns; columnsRemaining -= columns; } dstY += rows; rowsRemaining -= rows; } } else { while(rowsRemaining > 0) { qint32 dstX = x; qint32 columnsRemaining = width; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY); qint32 rows = qMin(numContiguousDstRows, rowsRemaining); while(columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX); qint32 columns = qMin(numContiguousDstColumns, columnsRemaining); qint32 dstRowStride = dstIt->rowStride(dstX, dstY); dstIt->moveTo(dstX, dstY); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; d->paramInfo.srcRowStart = srcColor.data(); d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); dstX += columns; columnsRemaining -= columns; } dstY += rows; rowsRemaining -= rows; } } addDirtyRect(QRect(x, y, width, height)); } void KisPainter::bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect srcBounds = srcDev->bounds(); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */ Q_ASSERT(srcBounds.contains(srcRect)); Q_UNUSED(srcRect); // only used in above assertion /* Create an intermediate byte array to hold information before it is written to the current paint device (aka: d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bltFixed std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); const quint8 *srcRowStart = srcDev->data() + (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize(); d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; if (d->selection) { /* d->selection is a KisPaintDevice, so first a readBytes is performed to get the area of interest... */ KisPaintDeviceSP selectionProjection = d->selection->projection(); quint8* selBytes = 0; try { selBytes = new quint8[srcWidth * srcHeight * selectionProjection->pixelSize()]; } catch (std::bad_alloc) { delete[] dstBytes; return; } selectionProjection->readBytes(selBytes, dstX, dstY, srcWidth, srcHeight); d->paramInfo.maskRowStart = selBytes; d->paramInfo.maskRowStride = srcWidth * selectionProjection->pixelSize(); } // ...and then blit. d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] d->paramInfo.maskRowStart; delete[] dstBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect) { bltFixed(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight) { // TODO: get selX and selY working as intended /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; // Check that selection has an alpha colorspace, crash if false Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8()); QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect selRect = QRect(selX, selY, srcWidth, srcHeight); QRect srcBounds = srcDev->bounds(); QRect selBounds = selection->bounds(); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */ Q_ASSERT(srcBounds.contains(srcRect)); Q_UNUSED(srcRect); // only used in above assertion Q_ASSERT(selBounds.contains(selRect)); Q_UNUSED(selRect); // only used in above assertion /* Create an intermediate byte array to hold information before it is written to the current paint device (aka: d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); const quint8 *srcRowStart = srcDev->data() + (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize(); const quint8 *selRowStart = selection->data() + (selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize(); if (!d->selection) { /* As there's nothing selected, blit to dstBytes (intermediary bit array), ignoring d->selection (the user selection)*/ d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = selRowStart; d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } else { /* Read the user selection (d->selection) bytes into an array, ready to merge in the next block*/ quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize(); quint8 * mergedSelectionBytes = 0; try { mergedSelectionBytes = new quint8[ totalBytes ]; } catch (std::bad_alloc) { warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << totalBytes << "total bytes"; delete[] dstBytes; return; } d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight); // Merge selections here by multiplying them - compositeOp(COMPOSITE_MULT) d->paramInfo.dstRowStart = mergedSelectionBytes; d->paramInfo.dstRowStride = srcWidth * selection->pixelSize(); d->paramInfo.srcRowStart = selRowStart; d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo); // Blit to dstBytes (intermediary bit array) d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = mergedSelectionBytes; d->paramInfo.maskRowStride = srcWidth * selection->pixelSize(); d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); delete[] mergedSelectionBytes; } d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] dstBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, quint32 srcWidth, quint32 srcHeight) { bltFixedWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight); } void KisPainter::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { if (d->device && d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintLine(pi1, pi2, currentDistance); } } void KisPainter::paintPolyline(const vQPointF &points, int index, int numPoints) { if (index >= (int) points.count()) return; if (numPoints < 0) numPoints = points.count(); if (index + numPoints > (int) points.count()) numPoints = points.count() - index; KisDistanceInformation saveDist; for (int i = index; i < index + numPoints - 1; i++) { paintLine(points [i], points [i + 1], &saveDist); } } static void getBezierCurvePoints(const KisVector2D &pos1, const KisVector2D &control1, const KisVector2D &control2, const KisVector2D &pos2, vQPointF& points) { LineEquation line = LineEquation::Through(pos1, pos2); qreal d1 = line.absDistance(control1); qreal d2 = line.absDistance(control2); if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) { points.push_back(toQPointF(pos1)); } else { // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508 KisVector2D l2 = (pos1 + control1) / 2; KisVector2D h = (control1 + control2) / 2; KisVector2D l3 = (l2 + h) / 2; KisVector2D r3 = (control2 + pos2) / 2; KisVector2D r2 = (h + r3) / 2; KisVector2D l4 = (l3 + r2) / 2; getBezierCurvePoints(pos1, l2, l3, l4, points); getBezierCurvePoints(l4, r2, r3, pos2, points); } } void KisPainter::getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF& points) const { ::getBezierCurvePoints(toKisVector2D(pos1), toKisVector2D(control1), toKisVector2D(control2), toKisVector2D(pos2), points); } void KisPainter::paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { if (d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, currentDistance); } } void KisPainter::paintRect(const QRectF &rect) { QRectF normalizedRect = rect.normalized(); vQPointF points; points.push_back(normalizedRect.topLeft()); points.push_back(normalizedRect.bottomLeft()); points.push_back(normalizedRect.bottomRight()); points.push_back(normalizedRect.topRight()); paintPolygon(points); } void KisPainter::paintRect(const qreal x, const qreal y, const qreal w, const qreal h) { paintRect(QRectF(x, y, w, h)); } void KisPainter::paintEllipse(const QRectF &rect) { QRectF r = rect.normalized(); // normalize before checking as negative width and height are empty too if (r.isEmpty()) return; // See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation. // kappa = (4/3*(sqrt(2)-1)) const qreal kappa = 0.5522847498; const qreal lx = (r.width() / 2) * kappa; const qreal ly = (r.height() / 2) * kappa; QPointF center = r.center(); QPointF p0(r.left(), center.y()); QPointF p1(r.left(), center.y() - ly); QPointF p2(center.x() - lx, r.top()); QPointF p3(center.x(), r.top()); vQPointF points; getBezierCurvePoints(p0, p1, p2, p3, points); QPointF p4(center.x() + lx, r.top()); QPointF p5(r.right(), center.y() - ly); QPointF p6(r.right(), center.y()); getBezierCurvePoints(p3, p4, p5, p6, points); QPointF p7(r.right(), center.y() + ly); QPointF p8(center.x() + lx, r.bottom()); QPointF p9(center.x(), r.bottom()); getBezierCurvePoints(p6, p7, p8, p9, points); QPointF p10(center.x() - lx, r.bottom()); QPointF p11(r.left(), center.y() + ly); getBezierCurvePoints(p9, p10, p11, p0, points); paintPolygon(points); } void KisPainter::paintEllipse(const qreal x, const qreal y, const qreal w, const qreal h) { paintEllipse(QRectF(x, y, w, h)); } void KisPainter::paintAt(const KisPaintInformation& pi, KisDistanceInformation *savedDist) { if (d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintAt(pi, savedDist); } } void KisPainter::fillPolygon(const vQPointF& points, FillStyle fillStyle) { if (points.count() < 3) { return; } if (fillStyle == FillStyleNone) { return; } QPainterPath polygonPath; polygonPath.moveTo(points.at(0)); for (int pointIndex = 1; pointIndex < points.count(); pointIndex++) { polygonPath.lineTo(points.at(pointIndex)); } polygonPath.closeSubpath(); d->fillStyle = fillStyle; fillPainterPath(polygonPath); } void KisPainter::paintPolygon(const vQPointF& points) { if (d->fillStyle != FillStyleNone) { fillPolygon(points, d->fillStyle); } if (d->strokeStyle != StrokeStyleNone) { if (points.count() > 1) { KisDistanceInformation distance; for (int i = 0; i < points.count() - 1; i++) { paintLine(KisPaintInformation(points[i]), KisPaintInformation(points[i + 1]), &distance); } paintLine(points[points.count() - 1], points[0], &distance); } } } void KisPainter::paintPainterPath(const QPainterPath& path) { if (d->fillStyle != FillStyleNone) { fillPainterPath(path); } if (d->strokeStyle == StrokeStyleNone) return; QPointF lastPoint, nextPoint; int elementCount = path.elementCount(); KisDistanceInformation saveDist; for (int i = 0; i < elementCount; i++) { QPainterPath::Element element = path.elementAt(i); switch (element.type) { case QPainterPath::MoveToElement: lastPoint = QPointF(element.x, element.y); break; case QPainterPath::LineToElement: nextPoint = QPointF(element.x, element.y); paintLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint), &saveDist); lastPoint = nextPoint; break; case QPainterPath::CurveToElement: nextPoint = QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y); paintBezierCurve(KisPaintInformation(lastPoint), QPointF(path.elementAt(i).x, path.elementAt(i).y), QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y), KisPaintInformation(nextPoint), &saveDist); lastPoint = nextPoint; break; default: continue; } } } void KisPainter::fillPainterPath(const QPainterPath& path) { fillPainterPath(path, QRect()); } void KisPainter::fillPainterPath(const QPainterPath& path, const QRect &requestedRect) { if (d->mirrorHorizontally || d->mirrorVertically) { KisLodTransform lod(d->device); QPointF effectiveAxesCenter = lod.map(d->axesCenter); QTransform C1 = QTransform::fromTranslate(-effectiveAxesCenter.x(), -effectiveAxesCenter.y()); QTransform C2 = QTransform::fromTranslate(effectiveAxesCenter.x(), effectiveAxesCenter.y()); QTransform t; QPainterPath newPath; QRect newRect; if (d->mirrorHorizontally) { t = C1 * QTransform::fromScale(-1,1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } if (d->mirrorVertically) { t = C1 * QTransform::fromScale(1,-1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } if (d->mirrorHorizontally && d->mirrorVertically) { t = C1 * QTransform::fromScale(-1,-1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } } d->fillPainterPathImpl(path, requestedRect); } void KisPainter::Private::fillPainterPathImpl(const QPainterPath& path, const QRect &requestedRect) { if (fillStyle == FillStyleNone) { return; } // Fill the polygon bounding rectangle with the required contents then we'll // create a mask for the actual polygon coverage. if (!fillPainter) { polygon = device->createCompositionSourceDevice(); fillPainter = new KisFillPainter(polygon); } else { polygon->clear(); } Q_CHECK_PTR(polygon); QRectF boundingRect = path.boundingRect(); QRect fillRect = boundingRect.toAlignedRect(); // Expand the rectangle to allow for anti-aliasing. fillRect.adjust(-1, -1, 1, 1); if (requestedRect.isValid()) { fillRect &= requestedRect; } switch (fillStyle) { default: // Fall through case FillStyleGradient: // Currently unsupported, fall through case FillStyleStrokes: // Currently unsupported, fall through warnImage << "Unknown or unsupported fill style in fillPolygon\n"; case FillStyleForegroundColor: fillPainter->fillRect(fillRect, q->paintColor(), OPACITY_OPAQUE_U8); break; case FillStyleBackgroundColor: fillPainter->fillRect(fillRect, q->backgroundColor(), OPACITY_OPAQUE_U8); break; case FillStylePattern: if (pattern) { // if the user hasn't got any patterns installed, we shouldn't crash... fillPainter->fillRect(fillRect, pattern); } break; case FillStyleGenerator: if (generator) { // if the user hasn't got any generators, we shouldn't crash... fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), q->generator()); } break; } if (polygonMaskImage.isNull() || (maskPainter == 0)) { polygonMaskImage = QImage(maskImageWidth, maskImageHeight, QImage::Format_ARGB32_Premultiplied); maskPainter = new QPainter(&polygonMaskImage); maskPainter->setRenderHint(QPainter::Antialiasing, q->antiAliasPolygonFill()); } // Break the mask up into chunks so we don't have to allocate a potentially very large QImage. const QColor black(Qt::black); const QBrush brush(Qt::white); for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += maskImageWidth) { for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += maskImageHeight) { polygonMaskImage.fill(black.rgb()); maskPainter->translate(-x, -y); maskPainter->fillPath(path, brush); maskPainter->translate(x, y); qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, maskImageWidth); qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, maskImageHeight); KisHLineIteratorSP lineIt = polygon->createHLineIteratorNG(x, y, rectWidth); quint8 tmp; for (int row = y; row < y + rectHeight; row++) { QRgb* line = reinterpret_cast(polygonMaskImage.scanLine(row - y)); do { tmp = qRed(line[lineIt->x() - x]); polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1); } while (lineIt->nextPixel()); lineIt->nextRow(); } } } QRect bltRect = !requestedRect.isEmpty() ? requestedRect : fillRect; q->bitBlt(bltRect.x(), bltRect.y(), polygon, bltRect.x(), bltRect.y(), bltRect.width(), bltRect.height()); } void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& pen) { drawPainterPath(path, pen, QRect()); } void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& pen, const QRect &requestedRect) { // we are drawing mask, it has to be white // color of the path is given by paintColor() Q_ASSERT(pen.color() == Qt::white); if (!d->fillPainter) { d->polygon = d->device->createCompositionSourceDevice(); d->fillPainter = new KisFillPainter(d->polygon); } else { d->polygon->clear(); } Q_CHECK_PTR(d->polygon); QRectF boundingRect = path.boundingRect(); QRect fillRect = boundingRect.toAlignedRect(); // take width of the pen into account int penWidth = qRound(pen.widthF()); fillRect.adjust(-penWidth, -penWidth, penWidth, penWidth); // Expand the rectangle to allow for anti-aliasing. fillRect.adjust(-1, -1, 1, 1); if (!requestedRect.isNull()) { fillRect &= requestedRect; } d->fillPainter->fillRect(fillRect, paintColor(), OPACITY_OPAQUE_U8); if (d->polygonMaskImage.isNull() || (d->maskPainter == 0)) { d->polygonMaskImage = QImage(d->maskImageWidth, d->maskImageHeight, QImage::Format_ARGB32_Premultiplied); d->maskPainter = new QPainter(&d->polygonMaskImage); d->maskPainter->setRenderHint(QPainter::Antialiasing, antiAliasPolygonFill()); } // Break the mask up into chunks so we don't have to allocate a potentially very large QImage. const QColor black(Qt::black); QPen oldPen = d->maskPainter->pen(); d->maskPainter->setPen(pen); for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += d->maskImageWidth) { for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += d->maskImageHeight) { d->polygonMaskImage.fill(black.rgb()); d->maskPainter->translate(-x, -y); d->maskPainter->drawPath(path); d->maskPainter->translate(x, y); qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, d->maskImageWidth); qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, d->maskImageHeight); KisHLineIteratorSP lineIt = d->polygon->createHLineIteratorNG(x, y, rectWidth); quint8 tmp; for (int row = y; row < y + rectHeight; row++) { QRgb* line = reinterpret_cast(d->polygonMaskImage.scanLine(row - y)); do { tmp = qRed(line[lineIt->x() - x]); d->polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1); } while (lineIt->nextPixel()); lineIt->nextRow(); } } } d->maskPainter->setPen(oldPen); QRect r = d->polygon->extent(); bitBlt(r.x(), r.y(), d->polygon, r.x(), r.y(), r.width(), r.height()); } inline void KisPainter::compositeOnePixel(quint8 *dst, const KoColor &color) { d->paramInfo.dstRowStart = dst; d->paramInfo.dstRowStride = 0; d->paramInfo.srcRowStart = color.data(); d->paramInfo.srcRowStride = 0; d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = 1; d->paramInfo.cols = 1; d->colorSpace->bitBlt(color.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } /**/ void KisPainter::drawLine(const QPointF& start, const QPointF& end, qreal width, bool antialias){ int x1 = start.x(); int y1 = start.y(); int x2 = end.x(); int y2 = end.y(); if ((x2 == x1 ) && (y2 == y1)) return; int dstX = x2-x1; int dstY = y2-y1; qreal uniC = dstX*y1 - dstY*x1; qreal projectionDenominator = 1.0 / (pow((double)dstX, 2) + pow((double)dstY, 2)); qreal subPixel; if (qAbs(dstX) > qAbs(dstY)){ subPixel = start.x() - x1; }else{ subPixel = start.y() - y1; } qreal halfWidth = width * 0.5 + subPixel; int W_ = qRound(halfWidth) + 1; // save the state int X1_ = x1; int Y1_ = y1; int X2_ = x2; int Y2_ = y2; if (x2device->createRandomAccessorNG(x1, y1); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x1, y1); } for (int y = y1-W_; y < y2+W_ ; y++){ for (int x = x1-W_; x < x2+W_; x++){ projection = ( (x-X1_)* dstX + (y-Y1_)*dstY ) * projectionDenominator; scanX = X1_ + projection * dstX; scanY = Y1_ + projection * dstY; if (((scanX < x1) || (scanX > x2)) || ((scanY < y1) || (scanY > y2))) { AA_ = qMin( sqrt( pow((double)x - X1_, 2) + pow((double)y - Y1_, 2) ), sqrt( pow((double)x - X2_, 2) + pow((double)y - Y2_, 2) )); }else{ AA_ = qAbs(dstY*x - dstX*y + uniC) * denominator; } if (AA_>halfWidth) { continue; } accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x,y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { KoColor mycolor = d->paintColor; if (antialias && AA_ > halfWidth-1.0) { mycolor.colorSpace()->multiplyAlpha(mycolor.data(), 1.0 - (AA_-(halfWidth-1.0)), 1); } compositeOnePixel(accessor->rawData(), mycolor); } } } } /**/ void KisPainter::drawLine(const QPointF & start, const QPointF & end) { drawThickLine(start, end, 1, 1); } void KisPainter::drawDDALine(const QPointF & start, const QPointF & end) { int x = int(start.x()); int y = int(start.y()); int x2 = int(end.x()); int y2 = int(end.y()); // Width and height of the line int xd = x2 - x; int yd = y2 - y; float m = (float)yd / (float)xd; float fx = x; float fy = y; int inc; KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(x, y); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x, y); } accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x,y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } if (fabs(m) > 1.0f) { inc = (yd > 0) ? 1 : -1; m = 1.0f / m; m *= inc; while (y != y2) { y = y + inc; fx = fx + m; x = qRound(fx); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } } } else { inc = (xd > 0) ? 1 : -1; m *= inc; while (x != x2) { x = x + inc; fy = fy + m; y = qRound(fy); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } } } } void KisPainter::drawWobblyLine(const QPointF & start, const QPointF & end) { KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(start.x(), start.y()); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(start.x(), start.y()); } KoColor mycolor(d->paintColor); int x1 = start.x(); int y1 = start.y(); int x2 = end.x(); int y2 = end.y(); // Width and height of the line int xd = (x2 - x1); int yd = (y2 - y1); int x; int y; float fx = (x = x1); float fy = (y = y1); float m = (float)yd / (float)xd; int inc; if (fabs(m) > 1) { inc = (yd > 0) ? 1 : -1; m = 1.0f / m; m *= inc; while (y != y2) { fx = fx + m; y = y + inc; x = qRound(fx); float br1 = int(fx + 1) - fx; float br2 = fx - (int)fx; accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br1)); compositeOnePixel(accessor->rawData(), mycolor); } accessor->moveTo(x + 1, y); if (selectionAccessor) selectionAccessor->moveTo(x + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br2)); compositeOnePixel(accessor->rawData(), mycolor); } } } else { inc = (xd > 0) ? 1 : -1; m *= inc; while (x != x2) { fy = fy + m; x = x + inc; y = qRound(fy); float br1 = int(fy + 1) - fy; float br2 = fy - (int)fy; accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br1)); compositeOnePixel(accessor->rawData(), mycolor); } accessor->moveTo(x, y + 1); if (selectionAccessor) selectionAccessor->moveTo(x, y + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br2)); compositeOnePixel(accessor->rawData(), mycolor); } } } } void KisPainter::drawWuLine(const QPointF & start, const QPointF & end) { KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(start.x(), start.y()); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(start.x(), start.y()); } KoColor lineColor(d->paintColor); int x1 = start.x(); int y1 = start.y(); int x2 = end.x(); int y2 = end.y(); float grad, xd, yd; float xgap, ygap, xend, yend, yf, xf; float brightness1, brightness2; int ix1, ix2, iy1, iy2; quint8 c1, c2; // gradient of line xd = (x2 - x1); yd = (y2 - y1); if (yd == 0) { /* Horizontal line */ int incr = (x1 < x2) ? 1 : -1; ix1 = (int)x1; ix2 = (int)x2; iy1 = (int)y1; while (ix1 != ix2) { ix1 = ix1 + incr; accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), lineColor); } } return; } if (xd == 0) { /* Vertical line */ int incr = (y1 < y2) ? 1 : -1; iy1 = (int)y1; iy2 = (int)y2; ix1 = (int)x1; while (iy1 != iy2) { iy1 = iy1 + incr; accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), lineColor); } } return; } if (fabs(xd) > fabs(yd)) { // horizontal line // line have to be paint from left to right if (x1 > x2) { float tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; xd = (x2 - x1); yd = (y2 - y1); } grad = yd / xd; // nearest X,Y interger coordinates xend = static_cast(x1 + 0.5f); yend = y1 + grad * (xend - x1); xgap = invertFrac(x1 + 0.5f); ix1 = static_cast(xend); iy1 = static_cast(yend); // calc the intensity of the other end point pixel pair. brightness1 = invertFrac(yend) * xgap; brightness2 = frac(yend) * xgap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix1, iy1 + 1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1 + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // calc first Y-intersection for main loop yf = yend + grad; xend = trunc(x2 + 0.5f); yend = y2 + grad * (xend - x2); xgap = invertFrac(x2 - 0.5f); ix2 = static_cast(xend); iy2 = static_cast(yend); brightness1 = invertFrac(yend) * xgap; brightness2 = frac(yend) * xgap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix2, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix2, iy2 + 1); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2 + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // main loop for (int x = ix1 + 1; x <= ix2 - 1; x++) { brightness1 = invertFrac(yf); brightness2 = frac(yf); c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(x, int (yf)); if (selectionAccessor) selectionAccessor->moveTo(x, int (yf)); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(x, int (yf) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, int (yf) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } yf = yf + grad; } } else { //vertical // line have to be painted from left to right if (y1 > y2) { float tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; xd = (x2 - x1); yd = (y2 - y1); } grad = xd / yd; // nearest X,Y interger coordinates yend = static_cast(y1 + 0.5f); xend = x1 + grad * (yend - y1); ygap = invertFrac(y1 + 0.5f); ix1 = static_cast(xend); iy1 = static_cast(yend); // calc the intensity of the other end point pixel pair. brightness1 = invertFrac(xend) * ygap; brightness2 = frac(xend) * ygap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(x1 + 1, y1); if (selectionAccessor) selectionAccessor->moveTo(x1 + 1, y1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // calc first Y-intersection for main loop xf = xend + grad; yend = trunc(y2 + 0.5f); xend = x2 + grad * (yend - y2); ygap = invertFrac(y2 - 0.5f); ix2 = static_cast(xend); iy2 = static_cast(yend); brightness1 = invertFrac(xend) * ygap; brightness2 = frac(xend) * ygap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix2, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix2 + 1, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2 + 1, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // main loop for (int y = iy1 + 1; y <= iy2 - 1; y++) { brightness1 = invertFrac(xf); brightness2 = frac(xf); c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(int (xf), y); if (selectionAccessor) selectionAccessor->moveTo(int (xf), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(int (xf) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(int (xf) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } xf = xf + grad; } }//end-of-else } void KisPainter::drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth) { KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(start.x(), start.y()); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(start.x(), start.y()); } const KoColorSpace *cs = d->device->colorSpace(); KoColor c1(d->paintColor); KoColor c2(d->paintColor); KoColor c3(d->paintColor); KoColor col1(c1); KoColor col2(c1); float grada, gradb, dxa, dxb, dya, dyb, fraca, fracb, xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dstX, dstY; int x, y, ix1, ix2, iy1, iy2; int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b; int tp0, tn0, tp1, tn1; int horizontal = 0; float opacity = 1.0; tp0 = startWidth / 2; tn0 = startWidth / 2; if (startWidth % 2 == 0) // even width startWidth tn0--; tp1 = endWidth / 2; tn1 = endWidth / 2; if (endWidth % 2 == 0) // even width endWidth tn1--; int x0 = qRound(start.x()); int y0 = qRound(start.y()); int x1 = qRound(end.x()); int y1 = qRound(end.y()); dstX = x1 - x0; // run of general line dstY = y1 - y0; // rise of general line if (dstY < 0) dstY = -dstY; if (dstX < 0) dstX = -dstX; if (dstX > dstY) { // horizontalish horizontal = 1; x0a = x0; y0a = y0 - tn0; x0b = x0; y0b = y0 + tp0; x1a = x1; y1a = y1 - tn1; x1b = x1; y1b = y1 + tp1; } else { x0a = x0 - tn0; y0a = y0; x0b = x0 + tp0; y0b = y0; x1a = x1 - tn1; y1a = y1; x1b = x1 + tp1; y1b = y1; } if (horizontal) { // draw endpoints for (int i = y0a; i <= y0b; i++) { accessor->moveTo(x0, i); if (selectionAccessor) selectionAccessor->moveTo(x0, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } for (int i = y1a; i <= y1b; i++) { accessor->moveTo(x1, i); if (selectionAccessor) selectionAccessor->moveTo(x1, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } } else { for (int i = x0a; i <= x0b; i++) { accessor->moveTo(i, y0); if (selectionAccessor) selectionAccessor->moveTo(i, y0); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } for (int i = x1a; i <= x1b; i++) { accessor->moveTo(i, y1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } } //antialias endpoints if (x1 != x0 && y1 != y0) { if (horizontal) { accessor->moveTo(x0a, y0a - 1); if (selectionAccessor) selectionAccessor->moveTo(x0a, y0a - 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c1.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } accessor->moveTo(x1b, y1b + 1); if (selectionAccessor) selectionAccessor->moveTo(x1b, y1b + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c2.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } else { accessor->moveTo(x0a - 1, y0a); if (selectionAccessor) selectionAccessor->moveTo(x0a - 1, y0a); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c1.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } accessor->moveTo(x1b + 1, y1b); if (selectionAccessor) selectionAccessor->moveTo(x1b + 1, y1b); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c2.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } } dxa = x1a - x0a; // run of a dya = y1a - y0a; // rise of a dxb = x1b - x0b; // run of b dyb = y1b - y0b; // rise of b if (horizontal) { // horizontal-ish lines if (x1 < x0) { int xt, yt, wt; KoColor tmp; xt = x1a; x1a = x0a; x0a = xt; yt = y1a; y1a = y0a; y0a = yt; xt = x1b; x1b = x0b; x0b = xt; yt = y1b; y1b = y0b; y0b = yt; xt = x1; x1 = x0; x0 = xt; yt = y1; y1 = y0; y0 = yt; tmp = c1; c1 = c2; c2 = tmp; wt = startWidth; startWidth = endWidth; endWidth = wt; } grada = dya / dxa; gradb = dyb / dxb; ix1 = x0; iy1 = y0; ix2 = x1; iy2 = y1; yfa = y0a + grada; yfb = y0b + gradb; for (x = ix1 + 1; x <= ix2 - 1; x++) { fraca = yfa - int (yfa); b1a = 1 - fraca; b2a = fraca; fracb = yfb - int (yfb); b1b = 1 - fracb; b2b = fracb; // color first pixel of bottom line opacity = ((x - ix1) / dstX) * c2.opacityF() + (1 - (x - ix1) / dstX) * c1.opacityF(); c3.setOpacity(opacity); accessor->moveTo(x, (int)yfa); if (selectionAccessor) selectionAccessor->moveTo(x, (int)yfa); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1a * c3.opacityF() + (1 - b1a) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } // color first pixel of top line if (!(startWidth == 1 && endWidth == 1)) { accessor->moveTo(x, (int)yfb); if (selectionAccessor) selectionAccessor->moveTo(x, (int)yfb); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1b * c3.opacityF() + (1 - b1b) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } // color second pixel of bottom line if (grada != 0 && grada != 1) { // if not flat or exact diagonal accessor->moveTo(x, int (yfa) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, int (yfa) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2a * c3.opacityF() + (1 - b2a) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // color second pixel of top line if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) { accessor->moveTo(x, int (yfb) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, int (yfb) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2b * c3.opacityF() + (1 - b2b) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // fill remaining pixels if (!(startWidth == 1 && endWidth == 1)) { if (yfa < yfb) for (int i = yfa + 1; i <= yfb; i++) { accessor->moveTo(x, i); if (selectionAccessor) selectionAccessor->moveTo(x, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } else for (int i = yfa + 1; i >= yfb; i--) { accessor->moveTo(x, i); if (selectionAccessor) selectionAccessor->moveTo(x, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } } yfa += grada; yfb += gradb; } } else { // vertical-ish lines if (y1 < y0) { int xt, yt, wt; xt = x1a; x1a = x0a; x0a = xt; yt = y1a; y1a = y0a; y0a = yt; xt = x1b; x1b = x0b; x0b = xt; yt = y1b; y1b = y0b; y0b = yt; xt = x1; x1 = x0; x0 = xt; yt = y1; y1 = y0; y0 = yt; KoColor tmp; tmp = c1; c1 = c2; c2 = tmp; wt = startWidth; startWidth = endWidth; endWidth = wt; } grada = dxa / dya; gradb = dxb / dyb; ix1 = x0; iy1 = y0; ix2 = x1; iy2 = y1; xfa = x0a + grada; xfb = x0b + gradb; for (y = iy1 + 1; y <= iy2 - 1; y++) { fraca = xfa - int (xfa); b1a = 1 - fraca; b2a = fraca; fracb = xfb - int (xfb); b1b = 1 - fracb; b2b = fracb; // color first pixel of left line opacity = ((y - iy1) / dstY) * c2.opacityF() + (1 - (y - iy1) / dstY) * c1.opacityF(); c3.setOpacity(opacity); accessor->moveTo(int (xfa), y); if (selectionAccessor) selectionAccessor->moveTo(int (xfa), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1a * c3.opacityF() + (1 - b1a) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } // color first pixel of right line if (!(startWidth == 1 && endWidth == 1)) { accessor->moveTo(int(xfb), y); if (selectionAccessor) selectionAccessor->moveTo(int(xfb), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1b * c3.opacityF() + (1 - b1b) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } // color second pixel of left line if (grada != 0 && grada != 1) { // if not flat or exact diagonal accessor->moveTo(int(xfa) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(int(xfa) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2a * c3.opacityF() + (1 - b2a) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // color second pixel of right line if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) { accessor->moveTo(int(xfb) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(int(xfb) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2b * c3.opacityF() + (1 - b2b) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // fill remaining pixels between current xfa,xfb if (!(startWidth == 1 && endWidth == 1)) { if (xfa < xfb) for (int i = (int) xfa + 1; i <= (int) xfb; i++) { accessor->moveTo(i, y); if (selectionAccessor) selectionAccessor->moveTo(i, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } else for (int i = (int) xfb; i <= (int) xfa + 1; i++) { accessor->moveTo(i, y); if (selectionAccessor) selectionAccessor->moveTo(i, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } } xfa += grada; xfb += gradb; } } } void KisPainter::setProgress(KoUpdater * progressUpdater) { d->progressUpdater = progressUpdater; } const KisPaintDeviceSP KisPainter::device() const { return d->device; } KisPaintDeviceSP KisPainter::device() { return d->device; } void KisPainter::setChannelFlags(QBitArray channelFlags) { Q_ASSERT(channelFlags.isEmpty() || quint32(channelFlags.size()) == d->colorSpace->channelCount()); // Now, if all bits in the channelflags are true, pass an empty channel flags bitarray // because otherwise the compositeops cannot optimize. d->paramInfo.channelFlags = channelFlags; if (!channelFlags.isEmpty() && channelFlags == QBitArray(channelFlags.size(), true)) { d->paramInfo.channelFlags = QBitArray(); } } QBitArray KisPainter::channelFlags() { return d->paramInfo.channelFlags; } void KisPainter::setPattern(const KoPattern * pattern) { d->pattern = pattern; } const KoPattern * KisPainter::pattern() const { return d->pattern; } void KisPainter::setPaintColor(const KoColor& color) { d->paintColor = color; if (d->device) { d->paintColor.convertTo(d->device->compositionSourceColorSpace()); } } const KoColor &KisPainter::paintColor() const { return d->paintColor; } void KisPainter::setBackgroundColor(const KoColor& color) { d->backgroundColor = color; if (d->device) { d->backgroundColor.convertTo(d->device->compositionSourceColorSpace()); } } const KoColor &KisPainter::backgroundColor() const { return d->backgroundColor; } -void KisPainter::setGenerator(const KisFilterConfiguration * generator) +void KisPainter::setGenerator(KisFilterConfigurationSP generator) { d->generator = generator; } -const KisFilterConfiguration * KisPainter::generator() const +const KisFilterConfigurationSP KisPainter::generator() const { return d->generator; } void KisPainter::setFillStyle(FillStyle fillStyle) { d->fillStyle = fillStyle; } KisPainter::FillStyle KisPainter::fillStyle() const { return d->fillStyle; } void KisPainter::setAntiAliasPolygonFill(bool antiAliasPolygonFill) { d->antiAliasPolygonFill = antiAliasPolygonFill; } bool KisPainter::antiAliasPolygonFill() { return d->antiAliasPolygonFill; } void KisPainter::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { d->strokeStyle = strokeStyle; } KisPainter::StrokeStyle KisPainter::strokeStyle() const { return d->strokeStyle; } void KisPainter::setFlow(quint8 flow) { d->paramInfo.flow = float(flow) / 255.0f; } quint8 KisPainter::flow() const { return quint8(d->paramInfo.flow * 255.0f); } void KisPainter::setOpacityUpdateAverage(quint8 opacity) { d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8; d->paramInfo.updateOpacityAndAverage(float(opacity) / 255.0f); } void KisPainter::setOpacity(quint8 opacity) { d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8; d->paramInfo.opacity = float(opacity) / 255.0f; } quint8 KisPainter::opacity() const { return quint8(d->paramInfo.opacity * 255.0f); } void KisPainter::setCompositeOp(const KoCompositeOp * op) { d->compositeOp = op; } const KoCompositeOp * KisPainter::compositeOp() { return d->compositeOp; } /** * TODO: Rename this setCompositeOpId(). See KoCompositeOpRegistry.h */ void KisPainter::setCompositeOp(const QString& op) { d->compositeOp = d->colorSpace->compositeOp(op); } void KisPainter::setSelection(KisSelectionSP selection) { d->selection = selection; } KisSelectionSP KisPainter::selection() { return d->selection; } KoUpdater * KisPainter::progressUpdater() { return d->progressUpdater; } void KisPainter::setGradient(const KoAbstractGradient* gradient) { d->gradient = gradient; } const KoAbstractGradient* KisPainter::gradient() const { return d->gradient; } void KisPainter::setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image) { d->paintOpPreset = preset; KisPaintOp *paintop = KisPaintOpRegistry::instance()->paintOp(preset, this, node, image); Q_ASSERT(paintop); if (paintop) { delete d->paintOp; d->paintOp = paintop; } else { warnKrita << "Could not create paintop for preset " << preset->name(); } } KisPaintOpPresetSP KisPainter::preset() const { return d->paintOpPreset; } KisPaintOp* KisPainter::paintOp() const { return d->paintOp; } void KisPainter::setMirrorInformation(const QPointF& axesCenter, bool mirrorHorizontally, bool mirrorVertically) { d->axesCenter = axesCenter; d->mirrorHorizontally = mirrorHorizontally; d->mirrorVertically = mirrorVertically; } void KisPainter::copyMirrorInformation(KisPainter* painter) { painter->setMirrorInformation(d->axesCenter, d->mirrorHorizontally, d->mirrorVertically); } bool KisPainter::hasMirroring() const { return d->mirrorHorizontally || d->mirrorVertically; } void KisPainter::setMaskImageSize(qint32 width, qint32 height) { d->maskImageWidth = qBound(1, width, 256); d->maskImageHeight = qBound(1, height, 256); d->fillPainter = 0; d->polygonMaskImage = QImage(); } //void KisPainter::setLockAlpha(bool protect) //{ // if(d->paramInfo.channelFlags.isEmpty()) { // d->paramInfo.channelFlags = d->colorSpace->channelFlags(true, true); // } // QBitArray switcher = // d->colorSpace->channelFlags(protect, !protect); // if(protect) { // d->paramInfo.channelFlags &= switcher; // } // else { // d->paramInfo.channelFlags |= switcher; // } // Q_ASSERT(quint32(d->paramInfo.channelFlags.size()) == d->colorSpace->channelCount()); //} //bool KisPainter::alphaLocked() const //{ // QBitArray switcher = d->colorSpace->channelFlags(false, true); // return !(d->paramInfo.channelFlags & switcher).count(true); //} void KisPainter::setRenderingIntent(KoColorConversionTransformation::Intent intent) { d->renderingIntent = intent; } void KisPainter::setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags) { d->conversionFlags = conversionFlags; } void KisPainter::renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab) { if (!d->mirrorHorizontally && !d->mirrorVertically) return; KisFixedPaintDeviceSP dabToProcess = dab; if (preserveDab) { dabToProcess = new KisFixedPaintDevice(*dab); } renderMirrorMask(rc, dabToProcess); } void KisPainter::renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask) { if (!d->mirrorHorizontally && !d->mirrorVertically) return; KisFixedPaintDeviceSP maskToProcess = mask; if (preserveMask) { maskToProcess = new KisFixedPaintDevice(*mask); } renderMirrorMask(rc, dab, sx, sy, maskToProcess); } void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab) { int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPointF effectiveAxesCenter = t.map(d->axesCenter); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); if (d->mirrorHorizontally && d->mirrorVertically){ dab->mirror(true, false); bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height()); dab->mirror(false,true); bltFixed(mirrorX, mirrorY, dab, 0,0,rc.width(),rc.height()); dab->mirror(true, false); bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height()); } else if (d->mirrorHorizontally){ dab->mirror(true, false); bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height()); } else if (d->mirrorVertically){ dab->mirror(false, true); bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height()); } } void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask) { int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPointF effectiveAxesCenter = t.map(d->axesCenter); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); if (d->mirrorHorizontally && d->mirrorVertically){ dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() ); dab->mirror(false,true); mask->mirror(false, true); bltFixedWithFixedSelection(mirrorX,mirrorY, dab, mask, rc.width() ,rc.height() ); dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() ); }else if (d->mirrorHorizontally){ dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() ); }else if (d->mirrorVertically){ dab->mirror(false, true); mask->mirror(false, true); bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() ); } } void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab){ if (d->mirrorHorizontally || d->mirrorVertically){ KisFixedPaintDeviceSP mirrorDab = new KisFixedPaintDevice(dab->colorSpace()); QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) ); mirrorDab->setRect(dabRc); mirrorDab->initialize(); dab->readBytes(mirrorDab->data(),rc); renderMirrorMask( QRect(rc.topLeft(),dabRc.size()), mirrorDab); } } void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask) { if (d->mirrorHorizontally || d->mirrorVertically){ KisFixedPaintDeviceSP mirrorDab = new KisFixedPaintDevice(dab->colorSpace()); QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) ); mirrorDab->setRect(dabRc); mirrorDab->initialize(); dab->readBytes(mirrorDab->data(),QRect(QPoint(sx,sy),rc.size())); renderMirrorMask(rc, mirrorDab, mask); } } void KisPainter::renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab) { QVector rects; int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPointF effectiveAxesCenter = t.map(d->axesCenter); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); rects << rc; if (d->mirrorHorizontally && d->mirrorVertically){ rects << QRect(mirrorX, y, rc.width(), rc.height()); rects << QRect(mirrorX, mirrorY, rc.width(), rc.height()); rects << QRect(x, mirrorY, rc.width(), rc.height()); } else if (d->mirrorHorizontally) { rects << QRect(mirrorX, y, rc.width(), rc.height()); } else if (d->mirrorVertically) { rects << QRect(x, mirrorY, rc.width(), rc.height()); } Q_FOREACH (const QRect &rc, rects) { d->device->clear(rc); } QRect resultRect = dab->extent() | rc; bool intersects = false; for (int i = 1; i < rects.size(); i++) { if (rects[i].intersects(resultRect)) { intersects = true; break; } } /** * If there are no cross-intersections, we can use a fast path * and do no cycling recompositioning */ if (!intersects) { rects.resize(1); } Q_FOREACH (const QRect &rc, rects) { bitBlt(rc.topLeft(), dab, rc); } Q_FOREACH (const QRect &rc, rects) { renderMirrorMask(rc, dab); } } diff --git a/libs/image/kis_painter.h b/libs/image/kis_painter.h index 8ac98988ae..e9ba96d7a7 100644 --- a/libs/image/kis_painter.h +++ b/libs/image/kis_painter.h @@ -1,808 +1,808 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Clarence Dang * Copyright (c) 2008-2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * * 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_PAINTER_H_ #define KIS_PAINTER_H_ #include #include #include #include #include "kundo2magicstring.h" #include "kis_types.h" +#include #include class QPen; class KUndo2Command; class QRect; class QRectF; class QBitArray; class QPainterPath; class KoAbstractGradient; class KoUpdater; class KoColor; class KoCompositeOp; class KisUndoAdapter; class KisPostExecutionUndoAdapter; class KisTransaction; class KoPattern; -class KisFilterConfiguration; class KisPaintInformation; class KisPaintOp; class KisDistanceInformation; /** * KisPainter contains the graphics primitives necessary to draw on a * KisPaintDevice. This is the same kind of abstraction as used in Qt * itself, where you have QPainter and QPaintDevice. * * However, KisPainter works on a tiled image and supports different * color models, and that's a lot more complicated. * * KisPainter supports transactions that can group various paint operations * in one undoable step. * * For more complex operations, you might want to have a look at the subclasses * of KisPainter: KisConvolutionPainter, KisFillPainter and KisGradientPainter * * KisPainter sets a number of default values, like COMPOSITE_OVER for compositeop, * OPACITY_OPAQUE for opacity and no selection for selection. */ class KRITAIMAGE_EXPORT KisPainter { public: /// Construct painter without a device KisPainter(); /// Construct a painter, and begin painting on the device KisPainter(KisPaintDeviceSP device); /// Construct a painter, and begin painting on the device. All actions will be masked by the given selection. KisPainter(KisPaintDeviceSP device, KisSelectionSP selection); virtual ~KisPainter(); public: static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect, KisSelectionSP selection); static KisPaintDeviceSP convertToAlphaAsAlpha(KisPaintDeviceSP src); static KisPaintDeviceSP convertToAlphaAsGray(KisPaintDeviceSP src); /** * Start painting on the specified device. Not undoable. */ void begin(KisPaintDeviceSP device); /** * Start painting on the specified paint device. All actions will be masked by the given selection. */ void begin(KisPaintDeviceSP device, KisSelectionSP selection); /** * Finish painting on the current device */ void end(); /** * If set, the painter action is cancelable, if the action supports that. */ void setProgress(KoUpdater * progressUpdater); /// Begin an undoable paint operation void beginTransaction(const KUndo2MagicString& transactionName = KUndo2MagicString(),int timedID = -1); /// Cancel all the changes made by the painter void revertTransaction(); /// Finish the undoable paint operation void endTransaction(KisUndoAdapter *undoAdapter); /** * Finish transaction and load it to a special adapter for strokes */ void endTransaction(KisPostExecutionUndoAdapter *undoAdapter); /** * Finishes a transaction and returns a pointer to its undo command */ KUndo2Command* endAndTakeTransaction(); /** * Finish the transaction and delete it's undo information. * NOTE: Be careful, because all the previous transactions * will become non-undoable after execution of this method. */ void deleteTransaction(); /// continue a transaction started somewhere else void putTransaction(KisTransaction* transaction); /// take transaction out of the reach of KisPainter KisTransaction* takeTransaction(); /// Returns the current paint device. const KisPaintDeviceSP device() const; KisPaintDeviceSP device(); /** * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param * srcDev onto the current paint device. @param srcX and @param srcY set the x and y * positions of the origin top-left corner, @param dstX and @param dstY those of * the destination. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * The same as @ref bitBlt() but reads data from oldData() part of the device * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight * of @param srcDev on the current paint device. There is parameters * to control where the area begins in each distinct device, explained below. * @param selection can be used as a mask to shape @param srcDev to * something interesting in the same step it is rendered to the current * paint device. @param selection 's colorspace must be alpha8 (the * colorspace for selections/transparency), the rectangle formed by * @param selX, @param selY, @param srcWidth and @param srcHeight must not go * beyond its limits, and they must be different from zero. * @param selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated * */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are * equal to 0. Best used when @param selection and the desired area of @param srcDev have exactly * the same dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 srcWidth, qint32 srcHeight); /** * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param srcDev onto the current * paint device. @param srcX and @param srcY set the x and y positions of the * origin top-left corner, @param dstX and @param dstY those of the destination. * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev must have the same * colorspace as the destination device. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect); /** * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight * of @param srcDev on the current paint device. There is parameters to control * the top-left corner of the area in each respective paint device (@param dstX, * @param dstY, @param srcX, @param srcY). * @param selection can be used as a mask to shape @param srcDev to something * interesting in the same step it is rendered to the current paint device. * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev * must have the same colorspace as the destination device. * @param selection 's colorspace must be alpha8 (the colorspace for * selections/transparency). * The rectangle formed by the respective top-left coordinates of each device * and @param srcWidth and @param srcHeight must not go beyond their limits, and * they must be different from zero. * @param selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the selection stored in fixed device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight); /** * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are * equal to 0. Best used when @param selection and @param srcDev have exactly the same * dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, quint32 srcWidth, quint32 srcHeight); /** * fills a region of width @param width and height @param height of the current * paint device with the color @param color. @param x and @param y set the x and y positions of the * origin top-left corner. * * @param x the destination x-coordinate * @param y the destination y-coordinate * @param width the width of the region to be manipulated * @param height the height of the region to be manipulated * @param color the color the area is filled with */ void fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color); /** * First you need to setup the painter with setMirrorInformation, * then these set of methods provide way to render the devices mirrored * according the axesCenter vertically or horizontally or both. * * @param rc rectangle area covered by dab * @param dab this device will be mirrored in-place, it means that it will be changed */ void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve out dab or do the transformations in-place. * * @param rc rectangle area covered by dab * @param dab the device to render * @param preserveDab states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve our fixed mask or do the transformations in-place. * * @param rc rectangle area covered by dab * @param dab the device to render * @param mask mask to use for rendering * @param preserveMask states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask); /** * A complex method that re-renders a dab on an \p rc area. * The \p rc area and all the dedicated mirroring areas are cleared * before the painting, so this method should be used by paintops * which do not update the canvas incrementally, but instead * regenerate some internal cache \p dab with the COMPOSITE_COPY op. * * \see KisExperimentPaintOp */ void renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab); /** * The methods in this class do not tell the paintdevice to update, but they calculate the * dirty area. This method returns this dirty area and resets it. */ QVector takeDirtyRegion(); /** * Paint a line that connects the dots in points */ void paintPolyline(const QVector &points, int index = 0, int numPoints = -1); /** * Draw a line between pos1 and pos2 using the currently set brush and color. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the line using the spacing setting. * @return the drag distance, that is the remains of the distance between p1 and p2 not covered * because the currenlty set brush has a spacing greater than that distance. */ void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *curentDistance); /** * Draw a Bezier curve between pos1 and pos2 using control points 1 and 2. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the curve using the spacing setting. * @return the drag distance, that is the remains of the distance between p1 and p2 not covered * because the currenlty set brush has a spacing greater than that distance. */ void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); /** * Fill the given vector points with the points needed to draw the Bezier curve between * pos1 and pos2 using control points 1 and 2, excluding the final pos2. */ void getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF& points) const; /** * Paint a rectangle. * @param rect the rectangle to paint. */ void paintRect(const QRectF &rect); /** * Paint a rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintRect(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the ellipse that fills the given rectangle. * * @param rect the rectangle containing the ellipse to paint. */ void paintEllipse(const QRectF &rect); /** * Paint the ellipse that fills the given rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintEllipse(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the polygon with the points given in points. It automatically closes the polygon * by drawing the line from the last point to the first. */ void paintPolygon(const vQPointF& points); /** Draw a spot at pos using the currently set paint op, brush and color */ void paintAt(const KisPaintInformation &pos, KisDistanceInformation *savedDist); /** * Stroke the given QPainterPath. */ void paintPainterPath(const QPainterPath& path); /** * Fills the area enclosed by the given QPainterPath * Convenience method for fillPainterPath(path, rect) */ void fillPainterPath(const QPainterPath& path); /** * Fills the portion of an area enclosed by the given QPainterPath * * \param rect the portion of the path to fill */ void fillPainterPath(const QPainterPath& path, const QRect &requestedRect); /** * Draw the path using the Pen * * if \p requestedRect is null, the entire path is painted */ void drawPainterPath(const QPainterPath& path, const QPen& pen, const QRect &requestedRect); // convenience overload void drawPainterPath(const QPainterPath& path, const QPen& pen); /** * paint an unstroked one-pixel wide line from specified start position to the * specified end position. * */ void drawLine(const QPointF & start, const QPointF & end); /** * paint an unstroked line with thickness from specified start position to the * specified end position. Scanline algorithm is used. */ void drawLine(const QPointF &start, const QPointF &end, qreal width, bool antialias); /** * paints an unstroked, aliased one-pixel line using the DDA algorithm from specified start position to the * specified end position. * */ void drawDDALine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, wobbly one-pixel wide line from the specified start to the specified * end position. * */ void drawWobblyLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, anti-aliased one-pixel wide line from the specified start to the specified * end position using the Wu algorithm */ void drawWuLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked wide line from the specified start to the specified * end position with width varying from @param w1 at the start to @param w2 at * the end. * * XXX: the width should be set in doubles, not integers. */ void drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth); /** * Set the channelflags: a bit array where true means that the * channel corresponding in position with the bit will be read * by the operation, and false means that it will not be affected. * * An empty channelFlags parameter means that all channels are * affected. * * @param the bit array that masks the source channels; only * the channels where the corresponding bit is true will will be * composited onto the destination device. */ void setChannelFlags(QBitArray channelFlags); /// @return the channel flags QBitArray channelFlags(); /** * Set the paintop preset to use. If @param image is given, * the paintop will be created using this image as parameter. * Some paintops really want to know about the image they work * for, e.g. the clone paintop. */ void setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image); /// Return the paintop preset KisPaintOpPresetSP preset() const; /** * Return the active paintop (which is created based on the specified preset and * will be deleted as soon as the KisPainter instance dies). */ KisPaintOp* paintOp() const; void setMirrorInformation(const QPointF &axesCenter, bool mirrorHorizontally, bool mirrorVertically); /** * copy the mirror information to other painter */ void copyMirrorInformation(KisPainter * painter); /** * Returns whether the mirroring methods will do any * work when called */ bool hasMirroring() const; /// Set the current pattern void setPattern(const KoPattern * pattern); /// Returns the currently set pattern const KoPattern * pattern() const; /** * Set the color that will be used to paint with, and convert it * to the color space of the current paint device. */ void setPaintColor(const KoColor& color); /// Returns the color that will be used to paint with const KoColor &paintColor() const; /** * Set the current background color, and convert it * to the color space of the current paint device. */ void setBackgroundColor(const KoColor& color); /// Returns the current background color const KoColor &backgroundColor() const; /// Set the current generator (a generator can be used to fill an area - void setGenerator(const KisFilterConfiguration * generator); + void setGenerator(KisFilterConfigurationSP generator); /// @return the current generator configuration - const KisFilterConfiguration * generator() const; + const KisFilterConfigurationSP generator() const; /// This enum contains the styles with which we can fill things like polygons and ellipses enum FillStyle { FillStyleNone, FillStyleForegroundColor, FillStyleBackgroundColor, FillStylePattern, FillStyleGradient, FillStyleStrokes, - FillStyleGenerator + FillStyleGenerator, }; /// Set the current style with which to fill void setFillStyle(FillStyle fillStyle); /// Returns the current fill style FillStyle fillStyle() const; /// Set whether a polygon's filled area should be anti-aliased or not. The default is true. void setAntiAliasPolygonFill(bool antiAliasPolygonFill); /// Return whether a polygon's filled area should be anti-aliased or not bool antiAliasPolygonFill(); /// The style of the brush stroke around polygons and so enum StrokeStyle { StrokeStyleNone, StrokeStyleBrush }; /// Set the current brush stroke style void setStrokeStyle(StrokeStyle strokeStyle); /// Returns the current brush stroke style StrokeStyle strokeStyle() const; void setFlow(quint8 flow); quint8 flow() const; /** * Sets the opacity of the painting and recalculates the * mean opacity of the stroke. This mean value is used to * make ALPHA_DARKEN painting look correct */ void setOpacityUpdateAverage(quint8 opacity); /// Set the opacity which is used in painting (like filling polygons) void setOpacity(quint8 opacity); /// Returns the opacity that is used in painting quint8 opacity() const; /// Set the composite op for this painter void setCompositeOp(const KoCompositeOp * op); const KoCompositeOp * compositeOp(); /// Set the composite op for this painter by string. /// Note: the colorspace must be set previously! void setCompositeOp(const QString& op); /** * Add the r to the current dirty rect. */ void addDirtyRect(const QRect & r); /** * Reset the selection to the given selection. All painter actions will be * masked by the specified selection. */ void setSelection(KisSelectionSP selection); /** * @return the selection set on this painter. */ KisSelectionSP selection(); void setGradient(const KoAbstractGradient* gradient); const KoAbstractGradient* gradient() const; /** * Set the size of the tile in fillPainterPath, useful when optimizing the use of fillPainterPath * e.g. Spray paintop uses more small tiles, although selections uses bigger tiles. QImage::fill * is quite expensive so with smaller images you can save instructions * Default and maximum size is 256x256 image */ void setMaskImageSize(qint32 width, qint32 height); // /** // * If the alpha channel is locked, the alpha values of the paint device we are painting on // * will not change. // */ // void setLockAlpha(bool protect); // bool alphaLocked() const; /** * set the rendering intent in case pixels need to be converted before painting */ void setRenderingIntent(KoColorConversionTransformation::Intent intent); /** * set the conversion flags in case pixels need to be converted before painting */ void setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags); protected: /// Initialize, set everything to '0' or defaults void init(); /// Fill the polygon defined by points with the fillStyle void fillPolygon(const vQPointF& points, FillStyle fillStyle); private: KisPainter(const KisPainter&); KisPainter& operator=(const KisPainter&); float frac(float value) { float tmp = 0; return modff(value , &tmp); } float invertFrac(float value) { float tmp = 0; return 1.0f - modff(value , &tmp); } protected: KoUpdater * progressUpdater(); private: template void bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); inline void compositeOnePixel(quint8 *dst, const KoColor &color); private: struct Private; Private* const d; }; #endif // KIS_PAINTER_H_ diff --git a/libs/image/kis_properties_configuration.cc b/libs/image/kis_properties_configuration.cc index 1166fed761..22ae5e418a 100644 --- a/libs/image/kis_properties_configuration.cc +++ b/libs/image/kis_properties_configuration.cc @@ -1,314 +1,319 @@ /* * Copyright (c) 2006 Boudewijn Rempt * Copyright (c) 2007,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. */ #include "kis_properties_configuration.h" #include #include #include #include "kis_image.h" #include "kis_transaction.h" #include "kis_undo_adapter.h" #include "kis_painter.h" #include "kis_selection.h" #include "KoID.h" #include "kis_types.h" #include #include struct Q_DECL_HIDDEN KisPropertiesConfiguration::Private { QMap properties; QStringList notSavedProperties; }; KisPropertiesConfiguration::KisPropertiesConfiguration() : d(new Private) { } KisPropertiesConfiguration::~KisPropertiesConfiguration() { delete d; } KisPropertiesConfiguration::KisPropertiesConfiguration(const KisPropertiesConfiguration& rhs) - : KisSerializableConfiguration(rhs) - , d(new Private(*rhs.d)) + : KisSerializableConfiguration(rhs) + , d(new Private(*rhs.d)) { } -void KisPropertiesConfiguration::fromXML(const QString & s) +bool KisPropertiesConfiguration::fromXML(const QString & xml, bool clear) { - clearProperties(); + if (clear) { + clearProperties(); + } QDomDocument doc; - doc.setContent(s); - QDomElement e = doc.documentElement(); - fromXML(e); + bool retval = doc.setContent(xml); + if (retval) { + QDomElement e = doc.documentElement(); + fromXML(e); + } + return retval; } void KisPropertiesConfiguration::fromXML(const QDomElement& e) { QDomNode n = e.firstChild(); while (!n.isNull()) { // We don't nest elements in filter configuration. For now... QDomElement e = n.toElement(); if (!e.isNull()) { if (e.tagName() == "param") { // If the file contains the new type parameter introduced in Krita act on it // Else invoke old behaviour if(e.attributes().contains("type")) { QString type = e.attribute("type"); QString name = e.attribute("name"); QString value = e.text(); if(type == "bytearray") { d->properties[name] = QVariant(QByteArray::fromBase64(value.toLatin1())); } else d->properties[name] = value; } else d->properties[e.attribute("name")] = QVariant(e.text()); } } n = n.nextSibling(); } //dump(); } void KisPropertiesConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { QMap::Iterator it; for (it = d->properties.begin(); it != d->properties.end(); ++it) { if(d->notSavedProperties.contains(it.key())) { continue; } QDomElement e = doc.createElement("param"); e.setAttribute("name", QString(it.key().toLatin1())); QString type = "string"; QVariant v = it.value(); QDomText text; if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { text = doc.createCDATASection(v.value().toString()); } else if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { QDomDocument doc = QDomDocument("color"); QDomElement root = doc.createElement("color"); doc.appendChild(root); v.value().toXML(doc, root); text = doc.createCDATASection(doc.toString()); type = "color"; } else if(v.type() == QVariant::String ) { text = doc.createCDATASection(v.toString()); // XXX: Unittest this! type = "string"; } else if(v.type() == QVariant::ByteArray ) { text = doc.createTextNode(QString::fromLatin1(v.toByteArray().toBase64())); // Arbitrary Data type = "bytearray"; } else { text = doc.createTextNode(v.toString()); type = "internal"; } e.setAttribute("type", type); e.appendChild(text); root.appendChild(e); } } QString KisPropertiesConfiguration::toXML() const { QDomDocument doc = QDomDocument("params"); QDomElement root = doc.createElement("params"); doc.appendChild(root); toXML(doc, root); return doc.toString(); } bool KisPropertiesConfiguration::hasProperty(const QString& name) const { return d->properties.contains(name); } void KisPropertiesConfiguration::setProperty(const QString & name, const QVariant & value) { if (d->properties.find(name) == d->properties.end()) { d->properties.insert(name, value); } else { d->properties[name] = value; } } bool KisPropertiesConfiguration::getProperty(const QString & name, QVariant & value) const { if (d->properties.find(name) == d->properties.end()) { return false; } else { value = d->properties[name]; return true; } } QVariant KisPropertiesConfiguration::getProperty(const QString & name) const { if (d->properties.find(name) == d->properties.end()) { return QVariant(); } else { return d->properties[name]; } } int KisPropertiesConfiguration::getInt(const QString & name, int def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toInt(); else return def; } double KisPropertiesConfiguration::getDouble(const QString & name, double def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toDouble(); else return def; } float KisPropertiesConfiguration::getFloat(const QString & name, float def) const { QVariant v = getProperty(name); if (v.isValid()) return (float)v.toDouble(); else return def; } bool KisPropertiesConfiguration::getBool(const QString & name, bool def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toBool(); else return def; } QString KisPropertiesConfiguration::getString(const QString & name, const QString & def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toString(); else return def; } KisCubicCurve KisPropertiesConfiguration::getCubicCurve(const QString & name, const KisCubicCurve & curve) const { QVariant v = getProperty(name); if (v.isValid()) { if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { return v.value(); } else { KisCubicCurve c; c.fromString(v.toString()); return c; } } else return curve; } KoColor KisPropertiesConfiguration::getColor(const QString& name, const KoColor& color) const { QVariant v = getProperty(name); if (v.isValid()) { if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { return v.value(); } else { QDomDocument doc; doc.setContent(v.toString()); QDomElement e = doc.documentElement().firstChild().toElement(); return KoColor::fromXML(e, Integer16BitsColorDepthID.id(), QHash()); } } else { return color; } } void KisPropertiesConfiguration::dump() const { QMap::Iterator it; for (it = d->properties.begin(); it != d->properties.end(); ++it) { dbgKrita << it.key() << " = " << it.value(); } } void KisPropertiesConfiguration::clearProperties() { d->properties.clear(); } void KisPropertiesConfiguration::setPropertyNotSaved(const QString& name) { d->notSavedProperties.append(name); } QMap KisPropertiesConfiguration::getProperties() const { return d->properties; } void KisPropertiesConfiguration::removeProperty(const QString & name) { d->properties.remove(name); } // --- factory --- struct Q_DECL_HIDDEN KisPropertiesConfigurationFactory::Private { }; KisPropertiesConfigurationFactory::KisPropertiesConfigurationFactory() : d(new Private) { } KisPropertiesConfigurationFactory::~KisPropertiesConfigurationFactory() { delete d; } -KisSerializableConfiguration* KisPropertiesConfigurationFactory::createDefault() +KisSerializableConfigurationSP KisPropertiesConfigurationFactory::createDefault() { return new KisPropertiesConfiguration(); } -KisSerializableConfiguration* KisPropertiesConfigurationFactory::create(const QDomElement& e) +KisSerializableConfigurationSP KisPropertiesConfigurationFactory::create(const QDomElement& e) { - KisPropertiesConfiguration* pc = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP pc = new KisPropertiesConfiguration(); pc->fromXML(e); return pc; } diff --git a/libs/image/kis_properties_configuration.h b/libs/image/kis_properties_configuration.h index 7db74f64af..2815490e99 100644 --- a/libs/image/kis_properties_configuration.h +++ b/libs/image/kis_properties_configuration.h @@ -1,157 +1,165 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_PROPERTIES_CONFIGURATION_H_ #define _KIS_PROPERTIES_CONFIGURATION_H_ #include #include #include #include #include #include class QDomElement; class QDomDocument; #include "kis_serializable_configuration.h" #include "kritaimage_export.h" /** * KisPropertiesConfiguration is a map-based properties class that can * be serialized and deserialized. * * It differs from the base class KisSerializableConfiguration in that * it provides a number of convenience methods to get at the data and */ class KRITAIMAGE_EXPORT KisPropertiesConfiguration : public KisSerializableConfiguration { public: /** * Create a new properties config. */ KisPropertiesConfiguration(); virtual ~KisPropertiesConfiguration(); /** * Deep copy the properties configFile */ KisPropertiesConfiguration(const KisPropertiesConfiguration& rhs); public: /** * Fill the properties configuration object from the XML encoded representation in s. * This function use the "Legacy" style XML of the 1.x .kra file format. + * @param xml the string that will be parsed as xml + * @param clear if true, the properties map will be emptied. + * @return true is the xml document could be parsed */ - virtual void fromXML(const QString&); + virtual bool fromXML(const QString& xml, bool clear = true); + /** * Fill the properties configuration object from the XML encoded representation in s. * This function use the "Legacy" style XML of the 1.x .kra file format. + * + * Note: the existing properties will not be cleared */ virtual void fromXML(const QDomElement&); /** * Create a serialized version of this properties config * This function use the "Legacy" style XML of the 1.x .kra file format. */ virtual void toXML(QDomDocument&, QDomElement&) const; /** * Create a serialized version of this properties config * This function use the "Legacy" style XML of the 1.x .kra file format. */ virtual QString toXML() const; /** * @return true if the map contains a property with the specified name */ bool hasProperty(const QString& name) const; /** * Set the property with name to value. */ virtual void setProperty(const QString & name, const QVariant & value); /** * Set value to the value associated with property name * * XXX: API alert: a setter that is prefixed with get? * * @return false if the specified property did not exist. */ virtual bool getProperty(const QString & name, QVariant & value) const; virtual QVariant getProperty(const QString & name) const; template T getPropertyLazy(const QString & name, const T &defaultValue) const { QVariant value = getProperty(name); return value.isValid() ? value.value() : defaultValue; } int getInt(const QString & name, int def = 0) const; double getDouble(const QString & name, double def = 0.0) const; float getFloat(const QString& name, float def = 0.0) const; bool getBool(const QString & name, bool def = false) const; QString getString(const QString & name, const QString & def = QString()) const; KisCubicCurve getCubicCurve(const QString & name, const KisCubicCurve & curve = KisCubicCurve()) const; KoColor getColor(const QString& name, const KoColor& color = KoColor()) const; QMap getProperties() const; /// Clear the map of properties void clearProperties(); ///Marks a property that should not be saved by toXML void setPropertyNotSaved(const QString & name); void removeProperty(const QString & name); public: void dump() const; private: struct Private; Private* const d; }; +typedef KisSharedPtr KisPropertiesConfigurationSP; + class KRITAIMAGE_EXPORT KisPropertiesConfigurationFactory : public KisSerializableConfigurationFactory { public: KisPropertiesConfigurationFactory(); virtual ~KisPropertiesConfigurationFactory(); - virtual KisSerializableConfiguration* createDefault(); - virtual KisSerializableConfiguration* create(const QDomElement& e); + virtual KisSerializableConfigurationSP createDefault(); + virtual KisSerializableConfigurationSP create(const QDomElement& e); private: struct Private; Private* const d; }; #endif diff --git a/libs/image/kis_selection_based_layer.cpp b/libs/image/kis_selection_based_layer.cpp index f7218d802a..543b2f615a 100644 --- a/libs/image/kis_selection_based_layer.cpp +++ b/libs/image/kis_selection_based_layer.cpp @@ -1,292 +1,292 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 C. Boemann * 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. */ #include "kis_selection_based_layer.h" #include #include "kis_debug.h" #include #include "kis_image.h" #include "kis_painter.h" #include "kis_default_bounds.h" #include "kis_selection.h" #include "kis_pixel_selection.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter.h" struct Q_DECL_HIDDEN KisSelectionBasedLayer::Private { public: Private() : useSelectionInProjection(true) {} KisSelectionSP selection; KisPaintDeviceSP paintDevice; bool useSelectionInProjection; }; KisSelectionBasedLayer::KisSelectionBasedLayer(KisImageWSP image, const QString &name, KisSelectionSP selection, - KisFilterConfiguration *filterConfig, + KisFilterConfigurationSP filterConfig, bool useGeneratorRegistry) : KisLayer(image.data(), name, OPACITY_OPAQUE_U8), KisNodeFilterInterface(filterConfig, useGeneratorRegistry), m_d(new Private()) { if (!selection) initSelection(); else setInternalSelection(selection); m_d->paintDevice = new KisPaintDevice(this, image->colorSpace(), new KisDefaultBounds(image)); connect(image.data(), SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(slotImageSizeChanged())); } KisSelectionBasedLayer::KisSelectionBasedLayer(const KisSelectionBasedLayer& rhs) : KisLayer(rhs) , KisIndirectPaintingSupport() , KisNodeFilterInterface(rhs) , m_d(new Private()) { setInternalSelection(rhs.m_d->selection); m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data()); } KisSelectionBasedLayer::~KisSelectionBasedLayer() { delete m_d; } void KisSelectionBasedLayer::initSelection() { m_d->selection = new KisSelection(new KisDefaultBounds(image())); m_d->selection->pixelSelection()->setDefaultPixel(KoColor(Qt::white, m_d->selection->pixelSelection()->colorSpace())); m_d->selection->setParentNode(this); m_d->selection->updateProjection(); } void KisSelectionBasedLayer::slotImageSizeChanged() { if (m_d->selection) { /** * Make sure exactBounds() of the selection got recalculated after * the image changed */ m_d->selection->pixelSelection()->setDirty(); setDirty(); } } void KisSelectionBasedLayer::setImage(KisImageWSP image) { m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); KisLayer::setImage(image); connect(image.data(), SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(slotImageSizeChanged())); } bool KisSelectionBasedLayer::allowAsChild(KisNodeSP node) const { return node->inherits("KisMask"); } KisPaintDeviceSP KisSelectionBasedLayer::original() const { return m_d->paintDevice; } KisPaintDeviceSP KisSelectionBasedLayer::paintDevice() const { return m_d->selection->pixelSelection(); } bool KisSelectionBasedLayer::needProjection() const { return m_d->selection; } void KisSelectionBasedLayer::setUseSelectionInProjection(bool value) const { m_d->useSelectionInProjection = value; } KisSelectionSP KisSelectionBasedLayer::fetchComposedInternalSelection(const QRect &rect) const { if (!m_d->selection) return 0; m_d->selection->updateProjection(rect); KisSelectionSP tempSelection = m_d->selection; lockTemporaryTarget(); if (hasTemporaryTarget()) { /** * Cloning a selection with COW * FIXME: check whether it's faster than usual bitBlt'ing */ tempSelection = new KisSelection(*tempSelection); KisPainter gc2(tempSelection->pixelSelection()); setupTemporaryPainter(&gc2); gc2.bitBlt(rect.topLeft(), temporaryTarget(), rect); } unlockTemporaryTarget(); return tempSelection; } void KisSelectionBasedLayer::copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect& rect) const { KisSelectionSP tempSelection; if (m_d->useSelectionInProjection) { tempSelection = fetchComposedInternalSelection(rect); } projection->clear(rect); KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect, tempSelection); } QRect KisSelectionBasedLayer::cropChangeRectBySelection(const QRect &rect) const { return m_d->selection ? rect & m_d->selection->selectedRect() : rect; } QRect KisSelectionBasedLayer::needRect(const QRect &rect, PositionToFilthy pos) const { Q_UNUSED(pos); return rect; } void KisSelectionBasedLayer::resetCache(const KoColorSpace *colorSpace) { if (!colorSpace) colorSpace = image()->colorSpace(); if (!m_d->paintDevice || *m_d->paintDevice->colorSpace() != *colorSpace) { m_d->paintDevice = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image())); } else { m_d->paintDevice->clear(); } } KisSelectionSP KisSelectionBasedLayer::internalSelection() const { return m_d->selection; } void KisSelectionBasedLayer::setInternalSelection(KisSelectionSP selection) { if (selection) { m_d->selection = new KisSelection(*selection.data()); m_d->selection->setParentNode(this); m_d->selection->updateProjection(); } else { m_d->selection = 0; } if (selection->pixelSelection()->defaultBounds()->bounds() != image()->bounds()) { qWarning() << "WARNING: KisSelectionBasedLayer::setInternalSelection" << "New selection has suspicious default bounds"; qWarning() << "WARNING:" << ppVar(selection->pixelSelection()->defaultBounds()->bounds()); qWarning() << "WARNING:" << ppVar(image()->bounds()); } } qint32 KisSelectionBasedLayer::x() const { return m_d->selection ? m_d->selection->x() : 0; } qint32 KisSelectionBasedLayer::y() const { return m_d->selection ? m_d->selection->y() : 0; } void KisSelectionBasedLayer::setX(qint32 x) { if (m_d->selection) { m_d->selection->setX(x); } } void KisSelectionBasedLayer::setY(qint32 y) { if (m_d->selection) { m_d->selection->setY(y); } } void KisSelectionBasedLayer::setDirty(const QRect & rect) { KisLayer::setDirty(rect); } void KisSelectionBasedLayer::setDirty() { Q_ASSERT(image()); setDirty(image()->bounds()); } QRect KisSelectionBasedLayer::extent() const { Q_ASSERT(image()); return m_d->selection ? m_d->selection->selectedRect() : image()->bounds(); } QRect KisSelectionBasedLayer::exactBounds() const { Q_ASSERT(image()); return m_d->selection ? m_d->selection->selectedExactRect() : image()->bounds(); } QImage KisSelectionBasedLayer::createThumbnail(qint32 w, qint32 h) { KisSelectionSP originalSelection = internalSelection(); KisPaintDeviceSP originalDevice = original(); return originalDevice && originalSelection ? originalDevice->createThumbnail(w, h, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) : QImage(); } diff --git a/libs/image/kis_selection_based_layer.h b/libs/image/kis_selection_based_layer.h index 513f289c8a..ceb4ef9048 100644 --- a/libs/image/kis_selection_based_layer.h +++ b/libs/image/kis_selection_based_layer.h @@ -1,209 +1,209 @@ /* * Copyright (c) 2006 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_SELECTION_BASED_LAYER_H_ #define KIS_SELECTION_BASED_LAYER_H_ #include #include "kis_types.h" #include "kis_layer.h" #include "kis_indirect_painting_support.h" #include #include "kis_node_filter_interface.h" class KisFilterConfiguration; /** * @class KisSelectionBasedLayer describes base behaviour for * selection base classes like KisAdjustmentLayer and KisGeneratorLayer. * These classes should have a persistent selection that controls * the area where filter/generators are applied. The area outside * this selection is not affected by the layer */ class KRITAIMAGE_EXPORT KisSelectionBasedLayer : public KisLayer, public KisIndirectPaintingSupport, public KisNodeFilterInterface { Q_OBJECT public: /** * creates a new layer with the given selection. * Note that the selection will be _copied_ (with COW, though). * @param image the image to set this layer to * @param name name of the layer * @param selection is a mask used by the layer to know * where to apply the filter/generator. */ - KisSelectionBasedLayer(KisImageWSP image, const QString &name, KisSelectionSP selection, KisFilterConfiguration *filterConfig, bool useGeneratorRegistry = false); + KisSelectionBasedLayer(KisImageWSP image, const QString &name, KisSelectionSP selection, KisFilterConfigurationSP filterConfig, bool useGeneratorRegistry = false); KisSelectionBasedLayer(const KisSelectionBasedLayer& rhs); virtual ~KisSelectionBasedLayer(); /** * tells whether the @node can be a child of this layer * @param node to be connected node * @return tells if to be connected is a child of KisMask */ bool allowAsChild(KisNodeSP node) const; void setImage(KisImageWSP image); KisPaintDeviceSP original() const; KisPaintDeviceSP paintDevice() const; bool needProjection() const; /** * resets cached projection of lower layer to a new device * @return void */ void resetCache(const KoColorSpace *colorSpace = 0); /** * for KisLayer::setDirty(const QRegion&) */ using KisLayer::setDirty; /** * Mark a layer as dirty. We can't use KisLayer's one * as our extent() function doesn't fit for this */ void setDirty(); void setDirty(const QRect & rect); public: /** * Returns the selection of the layer * * Do not mix it with selection() which returns * the currently active selection of the image */ KisSelectionSP internalSelection() const; /** * sets the selection of this layer to a copy of * selection * @param selection the selection to set * @return void */ void setInternalSelection(KisSelectionSP selection); /** * When painted in indirect painting mode, the internal selection * might not contain actual selection, because a part of it is * stored on an indirect painting device. This method returns the * merged copy of the real selection. The area in \p rect only is * guaranteed to be prepared. The content of the rest of the * selection is undefined. */ KisSelectionSP fetchComposedInternalSelection(const QRect &rect) const; /** * gets this layer's x coordinate, taking selection into account * @return x-coordinate value */ qint32 x() const; /** * gets this layer's y coordinate, taking selection into account * @return y-coordinate value */ qint32 y() const; /** * sets this layer's y coordinate, taking selection into account * @param x x coordinate */ void setX(qint32 x); /** * sets this layer's y coordinate, taking selection into account * @param y y coordinate */ void setY(qint32 y); public: /** * gets an approximation of where the bounds on actual data * are in this layer, taking selection into account */ QRect extent() const; /** * returns the exact bounds of where the actual data resides * in this layer, taking selection into account */ QRect exactBounds() const; /** * copies the image and reformats it to thumbnail size * and returns the new thumbnail image. * @param w width of the thumbnail to create * @param h height of the thumbnail to create * @return the thumbnail image created. */ QImage createThumbnail(qint32 w, qint32 h); protected: // override from KisLayer void copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect& rect) const; // override from KisNode QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const; protected: void initSelection(); QRect cropChangeRectBySelection(const QRect &rect) const; /** * Sets if the selection should be used in * copyOriginalToProjection() method. * * Default value is 'true'. The descendants should override it to * get desired behaviour. * * Must be called only once in the child's constructor */ void setUseSelectionInProjection(bool value) const; public Q_SLOTS: void slotImageSizeChanged(); /** * gets this layer. Overriddes function in * KisIndirectPaintingSupport * @return this AdjustmentLayer */ KisLayer* layer() { return this; } private: struct Private; Private * const m_d; }; #endif /* KIS_SELECTION_BASED_LAYER_H_ */ diff --git a/libs/image/kis_serializable_configuration.cc b/libs/image/kis_serializable_configuration.cc index 0365e9601c..41d60a9053 100644 --- a/libs/image/kis_serializable_configuration.cc +++ b/libs/image/kis_serializable_configuration.cc @@ -1,45 +1,56 @@ /* * 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. */ #include "kis_serializable_configuration.h" - #include #include #include -void KisSerializableConfiguration::fromXML(const QString & s) +KisSerializableConfiguration::KisSerializableConfiguration() +{ +} + +KisSerializableConfiguration::KisSerializableConfiguration(const KisSerializableConfiguration &) + : KisShared() +{ +} + +bool KisSerializableConfiguration::fromXML(const QString &s, bool) { QDomDocument doc; - doc.setContent(s); - QDomElement e = doc.documentElement(); - fromXML(e); + bool rv = doc.setContent(s); + if (rv) { + QDomElement e = doc.documentElement(); + fromXML(e); + } + return rv; } QString KisSerializableConfiguration::toXML() const { QDomDocument doc = QDomDocument("params"); QDomElement root = doc.createElement("params"); doc.appendChild(root); toXML(doc, root); return doc.toString(); } KisSerializableConfigurationFactory::~KisSerializableConfigurationFactory() { } diff --git a/libs/image/kis_serializable_configuration.h b/libs/image/kis_serializable_configuration.h index dec4d5a97c..2e3d7448bf 100644 --- a/libs/image/kis_serializable_configuration.h +++ b/libs/image/kis_serializable_configuration.h @@ -1,77 +1,86 @@ /* * 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_SERIALIZABLE_CONFIGURATION_H_ #define _KIS_SERIALIZABLE_CONFIGURATION_H_ class QDomElement; class QDomDocument; class QString; #include "kritaimage_export.h" +#include "kis_shared.h" +#include "kis_shared_ptr.h" /** * This is an interface for objects that are serializable and unserializable. * It can be used together with the factory in case the type of configuration object * is also unknown at creation time. */ -class KRITAIMAGE_EXPORT KisSerializableConfiguration +class KRITAIMAGE_EXPORT KisSerializableConfiguration : public KisShared { public: - virtual ~KisSerializableConfiguration() {}; + KisSerializableConfiguration(); + + virtual ~KisSerializableConfiguration() {} + + KisSerializableConfiguration(const KisSerializableConfiguration &rhs); /** * Fill the object from the XML encoded representation in s. */ - virtual void fromXML(const QString&); + virtual bool fromXML(const QString&, bool); /** * Fill the object from the XML encoded representation in s. */ virtual void fromXML(const QDomElement&) = 0; /** * Create a serialized version of this object */ virtual void toXML(QDomDocument&, QDomElement&) const = 0; /** * Create a serialized version of this object */ virtual QString toXML() const; }; +typedef KisSharedPtr KisSerializableConfigurationSP; + /** * This is an interface for a factory of serializable configuration objects. */ class KRITAIMAGE_EXPORT KisSerializableConfigurationFactory { public: virtual ~KisSerializableConfigurationFactory(); /** * @return an empty object with a sane default configuration */ - virtual KisSerializableConfiguration* createDefault() = 0; + virtual KisSerializableConfigurationSP createDefault() = 0; /** * @return an unserialied version of the configuration */ - virtual KisSerializableConfiguration* create(const QDomElement&) = 0; + virtual KisSerializableConfigurationSP create(const QDomElement&) = 0; }; + #endif diff --git a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp index 25e5e59249..f076def886 100644 --- a/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp +++ b/libs/image/kis_suspend_projection_updates_stroke_strategy.cpp @@ -1,275 +1,275 @@ /* * 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_suspend_projection_updates_stroke_strategy.h" #include #include #include inline uint qHash(const QRect &rc) { return rc.x() + (rc.y() << 16) + (rc.width() << 8) + (rc.height() << 24); } struct KisSuspendProjectionUpdatesStrokeStrategy::Private { KisImageWSP image; bool suspend; class SuspendLod0Updates : public KisProjectionUpdatesFilter { typedef QHash > RectsHash; public: struct Request { Request() {} Request(KisNodeSP _node, QRect _rect) : node(_node), rect(_rect) {} KisNodeSP node; QRect rect; }; public: SuspendLod0Updates() { } bool filter(KisImage *image, KisNode *node, const QRect &rect) { if (image->currentLevelOfDetail() > 0) return false; QMutexLocker l(&m_mutex); m_requestsHash[KisNodeSP(node)].append(rect); return true; } static inline QRect alignRect(const QRect &rc, const int step) { static const int decstep = step - 1; static const int invstep = ~decstep; int x0, y0, x1, y1; rc.getCoords(&x0, &y0, &x1, &y1); x0 &= invstep; y0 &= invstep; x1 |= decstep; y1 |= decstep; QRect result; result.setCoords(x0, y0, x1, y1); return result; } void notifyUpdates(KisNodeGraphListener *listener) { RectsHash::const_iterator it = m_requestsHash.constBegin(); RectsHash::const_iterator end = m_requestsHash.constEnd(); const int step = 64; for (; it != end; ++it) { KisNodeSP node = it.key(); const QVector &rects = it.value(); QVector::const_iterator it = rects.constBegin(); QVector::const_iterator end = rects.constEnd(); QRegion region; for (; it != end; ++it) { region += alignRect(*it, step); } Q_FOREACH (const QRect &rc, region.rects()) { // FIXME: constness: port rPU to SP listener->requestProjectionUpdate(const_cast(node.data()), rc); } } } private: RectsHash m_requestsHash; QMutex m_mutex; }; class SuspendData : public KisStrokeJobData { public: SuspendData() : KisStrokeJobData(SEQUENTIAL) {} }; class ResumeAndIssueGraphUpdatesData : public KisStrokeJobData { public: ResumeAndIssueGraphUpdatesData() : KisStrokeJobData(SEQUENTIAL) {} }; class UpdatesBarrierData : public KisStrokeJobData { public: UpdatesBarrierData() : KisStrokeJobData(BARRIER) {} }; class IssueCanvasUpdatesData : public KisStrokeJobData { public: IssueCanvasUpdatesData(QRect _updateRect) : KisStrokeJobData(CONCURRENT), updateRect(_updateRect) {} QRect updateRect; }; }; KisSuspendProjectionUpdatesStrokeStrategy::KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP image, bool suspend) : KisSimpleStrokeStrategy(suspend ? "suspend_stroke_strategy" : "resume_stroke_strategy"), m_d(new Private) { m_d->image = image; m_d->suspend = suspend; enableJob(JOB_DOSTROKE, true); enableJob(JOB_CANCEL, true); } KisSuspendProjectionUpdatesStrokeStrategy::~KisSuspendProjectionUpdatesStrokeStrategy() { } /** * When the Lod0 stroke is being recalculated in the background we * should block all the updates it issues to avoid user distraction. * The result of the final stroke should be shown to the user in the * very end when everything is fully ready. Ideally the use should not * notice that the image has changed :) * * (Don't mix this process with suspend/resume capabilities of a * single stroke. That is a different system!) * * The process of the Lod0 regeneration consists of the following: * * 1) Suspend stroke executes. It sets a special updates filter on the * image. The filter blocks all the updates and saves them in an * internal structure to be emitted in the future. * * 2) Lod0 strokes are being recalculated. All their updates are * blocked and saved in the filter. * * 3) Resume stroke starts: * * 3.1) First it disables emitting of sigImageUpdated() so the gui * will not get any update notifications. * * 3.2) Then it enables updates themselves. * * 3.3) Initiates all the updates that were requested by the Lod0 * stroke. The node graph is regenerated, but the GUI does * not get this change. * * 3.4) Special barrier job waits for all the updates to finish * and, when they are done, enables GUI notifications again. * * 3.5) In a multithreaded way emits the GUI notifications for the * entire image. Multithreaded way is used to conform the * double-stage update principle of KisCanvas2. */ void KisSuspendProjectionUpdatesStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) { Private::SuspendData *suspendData = dynamic_cast(data); Private::ResumeAndIssueGraphUpdatesData *resumeData = dynamic_cast(data); Private::UpdatesBarrierData *barrierData = dynamic_cast(data); Private::IssueCanvasUpdatesData *canvasUpdates = dynamic_cast(data); if (suspendData) { m_d->image->setProjectionUpdatesFilter( KisProjectionUpdatesFilterSP(new Private::SuspendLod0Updates())); } else if (resumeData) { m_d->image->disableUIUpdates(); resumeAndIssueUpdates(false); } else if (barrierData) { m_d->image->enableUIUpdates(); } else if (canvasUpdates) { m_d->image->notifyProjectionUpdated(canvasUpdates->updateRect); } } -QList KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP /*h*/) +QList KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP /*image*/) { QList jobsData; jobsData << new Private::SuspendData(); return jobsData; } QList KisSuspendProjectionUpdatesStrokeStrategy::createResumeJobsData(KisImageWSP _image) { QList jobsData; jobsData << new Private::ResumeAndIssueGraphUpdatesData(); jobsData << new Private::UpdatesBarrierData(); using KritaUtils::splitRectIntoPatches; using KritaUtils::optimalPatchSize; KisImageSP image = _image; QVector rects = splitRectIntoPatches(image->bounds(), optimalPatchSize()); Q_FOREACH (const QRect &rc, rects) { jobsData << new Private::IssueCanvasUpdatesData(rc); } return jobsData; } void KisSuspendProjectionUpdatesStrokeStrategy::resumeAndIssueUpdates(bool dropUpdates) { KisProjectionUpdatesFilterSP filter = m_d->image->projectionUpdatesFilter(); if (!filter) return; Private::SuspendLod0Updates *localFilter = dynamic_cast(filter.data()); if (localFilter) { m_d->image->setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP()); if (!dropUpdates) { localFilter->notifyUpdates(m_d->image.data()); } } } void KisSuspendProjectionUpdatesStrokeStrategy::cancelStrokeCallback() { /** * We shouldn't emit any ad-hoc updates when cancelling the * stroke. It generates weird temporary holes on the canvas, * making the user feel awful, thinking his image got * corrupted. We will just emit a common refreshGraphAsync() that * will do all the work in a beautiful way */ resumeAndIssueUpdates(true); if (!m_d->suspend) { // FIXME: optimize m_d->image->refreshGraphAsync(); } } diff --git a/libs/image/kis_time_range.h b/libs/image/kis_time_range.h index 656a52576c..438637469b 100644 --- a/libs/image/kis_time_range.h +++ b/libs/image/kis_time_range.h @@ -1,150 +1,150 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TIME_RANGE_H #define __KIS_TIME_RANGE_H #include "kritaimage_export.h" #include #include #include #include #include "kis_types.h" #include class KRITAIMAGE_EXPORT KisTimeRange : public boost::equality_comparable { public: inline KisTimeRange() : m_start(0), m_end(-1) { } inline KisTimeRange(int start, int duration) : m_start(start), m_end(start + duration - 1) { } + inline KisTimeRange(int start, int end, bool) + : m_start(start), + m_end(end) + { + } + bool operator==(const KisTimeRange &rhs) const { return rhs.m_start == m_start && rhs.m_end == m_end; } KisTimeRange& operator|=(const KisTimeRange &rhs) { if (!isValid()) { m_start = rhs.start(); } else if (rhs.isValid()) { m_start = std::min(m_start, rhs.start()); } if (rhs.isInfinite() || isInfinite()) { m_end = std::numeric_limits::min(); } else if (!isValid()) { m_end = rhs.end(); } else { m_end = std::max(m_end, rhs.end()); } return *this; } KisTimeRange& operator&=(const KisTimeRange &rhs) { if (!isValid()) { return *this; } else if (!rhs.isValid()) { m_start = rhs.start(); m_end = rhs.end(); return *this; } else { m_start = std::max(m_start, rhs.start()); } if (isInfinite()) { m_end = rhs.end(); } else if (!rhs.isInfinite()) { m_end = std::min(m_end, rhs.end()); } return *this; } inline int start() const { return m_start; } inline int end() const { return m_end; } inline int duration() const { return m_end >= m_start ? m_end - m_start + 1 : 0; } inline bool isInfinite() const { return m_end == std::numeric_limits::min(); } inline bool isValid() const { return (m_end >= m_start) || (m_end == std::numeric_limits::min() && m_start >= 0); } inline bool contains(int time) const { if (m_end == std::numeric_limits::min()) { return m_start <= time; } return m_start <= time && time <= m_end; } static inline KisTimeRange fromTime(int start, int end) { return KisTimeRange(start, end, true); } static inline KisTimeRange infinite(int start) { return KisTimeRange(start, std::numeric_limits::min(), true); } static void calculateTimeRangeRecursive(const KisNode *node, int time, KisTimeRange &range, bool exclusive); -private: - inline KisTimeRange(int start, int end, bool) - : m_start(start), - m_end(end) - { - } private: int m_start; int m_end; }; namespace KisDomUtils { void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const KisTimeRange &range); bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, KisTimeRange *range); } Q_DECLARE_METATYPE(KisTimeRange); KRITAIMAGE_EXPORT QDebug operator<<(QDebug dbg, const KisTimeRange &r); #endif /* __KIS_TIME_RANGE_H */ diff --git a/libs/image/kis_types.h b/libs/image/kis_types.h index 1e86d4b19a..048969e6e9 100644 --- a/libs/image/kis_types.h +++ b/libs/image/kis_types.h @@ -1,286 +1,291 @@ /* * 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 KISTYPES_H_ #define KISTYPES_H_ #include #include #include #include "kritaimage_export.h" template class KisWeakSharedPtr; template class KisSharedPtr; template class QSharedPointer; template class QWeakPointer; template uint qHash(KisSharedPtr ptr) { return qHash(ptr.data()); } template uint qHash(KisWeakSharedPtr ptr) { return qHash(ptr.data()); } /** * Define lots of shared pointer versions of Krita classes. * Shared pointer classes have the advantage of near automatic * memory management (but beware of circular references) * These types should never be passed by reference, * because that will mess up their reference counter. * * An example of the naming pattern used: * * KisPaintDeviceSP is a KisSharedPtr of KisPaintDevice * KisPaintDeviceWSP is a KisWeakSharedPtr of KisPaintDevice * vKisPaintDeviceSP is a QVector of KisPaintDeviceSP * vKisPaintDeviceSP_it is an iterator of vKisPaintDeviceSP * */ class KisImage; typedef KisSharedPtr KisImageSP; typedef KisWeakSharedPtr KisImageWSP; class KisPaintDevice; typedef KisSharedPtr KisPaintDeviceSP; typedef KisWeakSharedPtr KisPaintDeviceWSP; typedef QVector vKisPaintDeviceSP; typedef vKisPaintDeviceSP::iterator vKisPaintDeviceSP_it; class KisFixedPaintDevice; typedef KisSharedPtr KisFixedPaintDeviceSP; class KisMask; typedef KisSharedPtr KisMaskSP; typedef KisWeakSharedPtr KisMaskWSP; class KisNode; typedef KisSharedPtr KisNodeSP; typedef KisWeakSharedPtr KisNodeWSP; typedef QVector vKisNodeSP; typedef vKisNodeSP::iterator vKisNodeSP_it; typedef vKisNodeSP::const_iterator vKisNodeSP_cit; class KisBaseNode; typedef KisSharedPtr KisBaseNodeSP; typedef KisWeakSharedPtr KisBaseNodeWSP; class KisEffectMask; typedef KisSharedPtr KisEffectMaskSP; typedef KisWeakSharedPtr KisEffectMaskWSP; class KisFilterMask; typedef KisSharedPtr KisFilterMaskSP; typedef KisWeakSharedPtr KisFilterMaskWSP; class KisTransformMask; typedef KisSharedPtr KisTransformMaskSP; typedef KisWeakSharedPtr KisTransformMaskWSP; class KisTransformMaskParamsInterface; typedef QSharedPointer KisTransformMaskParamsInterfaceSP; typedef QWeakPointer KisTransformMaskParamsInterfaceWSP; class KisTransparencyMask; typedef KisSharedPtr KisTransparencyMaskSP; typedef KisWeakSharedPtr KisTransparencyMaskWSP; class KisColorizeMask; typedef KisSharedPtr KisColorizeMaskSP; typedef KisWeakSharedPtr KisColorizeMaskWSP; class KisLayer; typedef KisSharedPtr KisLayerSP; typedef KisWeakSharedPtr KisLayerWSP; class KisShapeLayer; typedef KisSharedPtr KisShapeLayerSP; class KisPaintLayer; typedef KisSharedPtr KisPaintLayerSP; class KisAdjustmentLayer; typedef KisSharedPtr KisAdjustmentLayerSP; class KisGeneratorLayer; typedef KisSharedPtr KisGeneratorLayerSP; class KisCloneLayer; typedef KisSharedPtr KisCloneLayerSP; typedef KisWeakSharedPtr KisCloneLayerWSP; class KisGroupLayer; typedef KisSharedPtr KisGroupLayerSP; typedef KisWeakSharedPtr KisGroupLayerWSP; class KisSelection; typedef KisSharedPtr KisSelectionSP; typedef KisWeakSharedPtr KisSelectionWSP; class KisSelectionComponent; typedef KisSharedPtr KisSelectionComponentSP; class KisBackground; typedef KisSharedPtr KisBackgroundSP; class KisSelectionMask; typedef KisSharedPtr KisSelectionMaskSP; class KisPixelSelection; typedef KisSharedPtr KisPixelSelectionSP; class KisHistogram; typedef KisSharedPtr KisHistogramSP; typedef QVector vKisSegments; class KisFilter; typedef KisSharedPtr KisFilterSP; class KisLayerStyleFilter; typedef KisSharedPtr KisLayerStyleFilterSP; class KisGenerator; typedef KisSharedPtr KisGeneratorSP; class KisConvolutionKernel; typedef KisSharedPtr KisConvolutionKernelSP; class KisAnnotation; typedef KisSharedPtr KisAnnotationSP; typedef QVector vKisAnnotationSP; typedef vKisAnnotationSP::iterator vKisAnnotationSP_it; typedef vKisAnnotationSP::const_iterator vKisAnnotationSP_cit; class KisAnimationFrameCache; typedef KisSharedPtr KisAnimationFrameCacheSP; typedef KisWeakSharedPtr KisAnimationFrameCacheWSP; class KisPaintingAssistant; typedef QSharedPointer KisPaintingAssistantSP; typedef QWeakPointer KisPaintingAssistantWSP; // Repeat iterators class KisHLineIterator2; template class KisRepeatHLineIteratorPixelBase; typedef KisRepeatHLineIteratorPixelBase< KisHLineIterator2 > KisRepeatHLineConstIteratorNG; typedef KisSharedPtr KisRepeatHLineConstIteratorSP; class KisVLineIterator2; template class KisRepeatVLineIteratorPixelBase; typedef KisRepeatVLineIteratorPixelBase< KisVLineIterator2 > KisRepeatVLineConstIteratorNG; typedef KisSharedPtr KisRepeatVLineConstIteratorSP; // NG Iterators class KisHLineIteratorNG; typedef KisSharedPtr KisHLineIteratorSP; class KisHLineConstIteratorNG; typedef KisSharedPtr KisHLineConstIteratorSP; class KisVLineIteratorNG; typedef KisSharedPtr KisVLineIteratorSP; class KisVLineConstIteratorNG; typedef KisSharedPtr KisVLineConstIteratorSP; class KisRandomConstAccessorNG; typedef KisSharedPtr KisRandomConstAccessorSP; class KisRandomAccessorNG; typedef KisSharedPtr KisRandomAccessorSP; class KisRandomSubAccessor; typedef KisSharedPtr KisRandomSubAccessorSP; // Things typedef QVector vQPointF; class KisPaintOpPreset; typedef KisSharedPtr KisPaintOpPresetSP; typedef KisWeakSharedPtr KisPaintOpPresetWSP; class KisPaintOpSettings; typedef KisSharedPtr KisPaintOpSettingsSP; class KisPaintOp; typedef KisSharedPtr KisPaintOpSP; class KoID; typedef QList KoIDList; class KoUpdater; template class QPointer; typedef QPointer KoUpdaterPtr; class KisProcessingVisitor; typedef KisSharedPtr KisProcessingVisitorSP; class KUndo2Command; typedef QSharedPointer KUndo2CommandSP; typedef QList KisNodeList; typedef QSharedPointer KisNodeListSP; typedef QList KisPaintDeviceList; class KisStroke; typedef QSharedPointer KisStrokeSP; typedef QWeakPointer KisStrokeWSP; typedef KisStrokeWSP KisStrokeId; class KisFilterConfiguration; -typedef QSharedPointer KisSafeFilterConfigurationSP; +typedef KisSharedPtr KisFilterConfigurationSP; class KisProjectionUpdatesFilter; typedef QSharedPointer KisProjectionUpdatesFilterSP; class KisAbstractProjectionPlane; typedef QSharedPointer KisAbstractProjectionPlaneSP; typedef QWeakPointer KisAbstractProjectionPlaneWSP; class KisProjectionLeaf; typedef QSharedPointer KisProjectionLeafSP; typedef QWeakPointer KisProjectionLeafWSP; class KisKeyframe; typedef QSharedPointer KisKeyframeSP; typedef QWeakPointer KisKeyframeWSP; + +class KisFilterChain; +typedef KisSharedPtr KisFilterChainSP; + struct KisProofingConfiguration; typedef QSharedPointer KisProofingConfigurationSP; typedef QWeakPointer KisProofingConfigurationWSP; class KisLayerComposition; typedef QSharedPointer KisLayerCompositionSP; typedef QWeakPointer KisLayerCompositionWSP; + #include #include #include #endif // KISTYPES_H_ diff --git a/libs/image/recorder/kis_recorded_action.h b/libs/image/recorder/kis_recorded_action.h index 1b90f6b815..6285be090b 100644 --- a/libs/image/recorder/kis_recorded_action.h +++ b/libs/image/recorder/kis_recorded_action.h @@ -1,76 +1,77 @@ /* * 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_RECORDED_ACTION_H_ #define _KIS_RECORDED_ACTION_H_ class QDomDocument; class QDomElement; class QString; class KisPlayInfo; class KisRecordedActionLoadContext; class KisRecordedActionSaveContext; class KoUpdater; #include +#include #include /** * This class represent an action. */ class KRITAIMAGE_EXPORT KisRecordedAction { public: KisRecordedAction(const QString& id, const QString& name); KisRecordedAction(const KisRecordedAction&); virtual ~KisRecordedAction(); /** * Play the action. */ virtual void play(const KisPlayInfo& _info, KoUpdater* _updater = 0) const = 0; /** * Clone this action. */ virtual KisRecordedAction* clone() const = 0; virtual void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const; public: const QString& id() const; const QString& name() const; void setName(const QString& name); private: struct Private; Private* const d; }; /** * This class is used to create recorded action. */ class KRITAIMAGE_EXPORT KisRecordedActionFactory { public: KisRecordedActionFactory(QString id); virtual ~KisRecordedActionFactory(); virtual KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) = 0; QString id() const; QString name() const; private: struct Private; Private* const d; }; #endif diff --git a/libs/image/recorder/kis_recorded_filter_action.cpp b/libs/image/recorder/kis_recorded_filter_action.cpp index 17d7d1a443..f1708bba22 100644 --- a/libs/image/recorder/kis_recorded_filter_action.cpp +++ b/libs/image/recorder/kis_recorded_filter_action.cpp @@ -1,178 +1,175 @@ /* * 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. */ #include "recorder/kis_recorded_filter_action.h" #include #include #include "kis_image.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_layer.h" #include "kis_node.h" #include "kis_selection.h" #include "kis_transaction.h" #include "kis_undo_adapter.h" #include "kis_selection_mask.h" #include "kis_config_widget.h" #include "kis_node_query_path.h" #include "kis_play_info.h" struct Q_DECL_HIDDEN KisRecordedFilterAction::Private { Private() - : kconfig(0) + : filterConfiguration(0) { } const KisFilter* filter; QRect rect; - KisFilterConfiguration* configuration() { - if (!kconfig) { - kconfig = filter->defaultConfiguration(0); - if (kconfig) { - kconfig->fromXML(configstr); + KisFilterConfigurationSP configuration() { + if (!filterConfiguration) { + filterConfiguration = filter->defaultConfiguration(0); + if (filterConfiguration) { + filterConfiguration->fromXML(configstr); } } - return kconfig; + return filterConfiguration; } - void setConfiguration(KisFilterConfiguration* conf) { - delete kconfig; - kconfig = conf; + void setConfiguration(KisFilterConfigurationSP conf) { + filterConfiguration = conf; configstr = conf->toXML(); } void setConfig(const QString& cfg) { - delete kconfig; - kconfig = 0; + filterConfiguration = 0; configstr = cfg; } const QString& config() { return configstr; } private: QString configstr; - KisFilterConfiguration* kconfig; + KisFilterConfigurationSP filterConfiguration; }; -KisRecordedFilterAction::KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfiguration* fc) : KisRecordedNodeAction("FilterAction", name, path), d(new Private) +KisRecordedFilterAction::KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfigurationSP fc) : KisRecordedNodeAction("FilterAction", name, path), d(new Private) { Q_ASSERT(filter); d->filter = filter; if (fc) { d->setConfig(fc->toXML()); } } KisRecordedFilterAction::KisRecordedFilterAction(const KisRecordedFilterAction& rhs) : KisRecordedNodeAction(rhs), d(new Private(*rhs.d)) { } KisRecordedFilterAction::~KisRecordedFilterAction() { delete d; } void KisRecordedFilterAction::play(KisNodeSP node, const KisPlayInfo& _info, KoUpdater* _updater) const { - KisFilterConfiguration * kfc = d->configuration(); + KisFilterConfigurationSP kfc = d->configuration(); KisPaintDeviceSP dev = node->paintDevice(); KisLayerSP layer = dynamic_cast(node.data()); QRect r1 = dev->extent(); KisTransaction transaction(kundo2_i18n("Filter: \"%1\"", d->filter->name()), dev); KisImageWSP image = _info.image(); r1 = r1.intersected(image->bounds()); if (layer && layer->selection()) { r1 = r1.intersected(layer->selection()->selectedExactRect()); } d->filter->process(dev, dev, layer->selection(), r1, kfc, _updater); node->setDirty(r1); transaction.commit(_info.undoAdapter()); } void KisRecordedFilterAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const { KisRecordedAction::toXML(doc, elt, context); elt.setAttribute("filter", d->filter->id()); // Save configuration - KisFilterConfiguration * kfc = d->configuration(); + KisFilterConfigurationSP kfc = d->configuration(); if (kfc) { QDomElement filterConfigElt = doc.createElement("Params"); kfc->toXML(doc, filterConfigElt); elt.appendChild(filterConfigElt); } } KisRecordedAction* KisRecordedFilterAction::clone() const { return new KisRecordedFilterAction(*this); } const KisFilter* KisRecordedFilterAction::filter() const { return d->filter; } -const KisFilterConfiguration* KisRecordedFilterAction::filterConfiguration() const +const KisFilterConfigurationSP KisRecordedFilterAction::filterConfiguration() const { return d->configuration(); } -void KisRecordedFilterAction::setFilterConfiguration(KisFilterConfiguration* config) +void KisRecordedFilterAction::setFilterConfiguration(KisFilterConfigurationSP config) { d->setConfiguration(config); } KisRecordedFilterActionFactory::KisRecordedFilterActionFactory() : KisRecordedActionFactory("FilterAction") { } KisRecordedFilterActionFactory::~KisRecordedFilterActionFactory() { } KisRecordedAction* KisRecordedFilterActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) { QString name = elt.attribute("name"); KisNodeQueryPath pathnode = KisNodeQueryPath::fromString(elt.attribute("path")); const KisFilterSP filter = KisFilterRegistry::instance()->get(elt.attribute("filter")); if (filter) { - KisFilterConfiguration* config = filter->defaultConfiguration(0); + KisFilterConfigurationSP config = filter->defaultConfiguration(0); QDomElement paramsElt = elt.firstChildElement("Params"); if (config && !paramsElt.isNull()) { config->fromXML(paramsElt); } KisRecordedFilterAction* rfa = new KisRecordedFilterAction(name, pathnode, filter, config); - delete config; return rfa; } else { return 0; } } diff --git a/libs/image/recorder/kis_recorded_filter_action.h b/libs/image/recorder/kis_recorded_filter_action.h index 691b374c4d..ec97cbdc80 100644 --- a/libs/image/recorder/kis_recorded_filter_action.h +++ b/libs/image/recorder/kis_recorded_filter_action.h @@ -1,64 +1,64 @@ /* * 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_RECORDED_FILTER_ACTION_H_ #define _KIS_RECORDED_FILTER_ACTION_H_ #include "recorder/kis_recorded_node_action.h" #include class QString; class KisFilterConfiguration; /** * Action representing a filter. */ class KRITAIMAGE_EXPORT KisRecordedFilterAction : public KisRecordedNodeAction { public: /** * @param config the filter configuration, the ownership of config remains in the caller. */ - KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfiguration* config); + KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfigurationSP config); KisRecordedFilterAction(const KisRecordedFilterAction&); virtual ~KisRecordedFilterAction(); using KisRecordedNodeAction::play; virtual void play(KisNodeSP node, const KisPlayInfo& _info, KoUpdater* _updater = 0) const; virtual void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const; virtual KisRecordedAction* clone() const; const KisFilter* filter() const; - const KisFilterConfiguration* filterConfiguration() const; + const KisFilterConfigurationSP filterConfiguration() const; /** * Set the configuration, and takes the ownership of the config object. */ - void setFilterConfiguration(KisFilterConfiguration* config); + void setFilterConfiguration(KisFilterConfigurationSP config); private: struct Private; Private* const d; }; class KisRecordedFilterActionFactory : public KisRecordedActionFactory { public: KisRecordedFilterActionFactory(); virtual ~KisRecordedFilterActionFactory(); virtual KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*); }; #endif diff --git a/libs/image/recorder/kis_recorded_paint_action.cpp b/libs/image/recorder/kis_recorded_paint_action.cpp index 473f589942..50332e34d5 100644 --- a/libs/image/recorder/kis_recorded_paint_action.cpp +++ b/libs/image/recorder/kis_recorded_paint_action.cpp @@ -1,468 +1,467 @@ /* * Copyright (c) 2007,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. */ #include //MSVC requires that Vc come first #include "recorder/kis_recorded_paint_action.h" #include #include #include #include #include #include #include "kis_node.h" #include "kis_mask_generator.h" #include "kis_painter.h" #include #include "kis_paintop_registry.h" #include "kis_transaction.h" #include "kis_undo_adapter.h" #include #include #include "kis_paint_device.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_play_info.h" #include "kis_node_query_path.h" #include // Recorder #include "kis_recorded_action_factory_registry.h" #include "kis_recorded_action_load_context.h" #include "kis_recorded_action_save_context.h" #include #include #include #include #include struct Q_DECL_HIDDEN KisRecordedPaintAction::Private { KisPaintOpPresetSP paintOpPreset; KoColor foregroundColor; KoColor backgroundColor; qreal opacity; ///< opacity in the range 0.0 -> 100.0 bool paintIncremental; QString compositeOp; KisPainter::StrokeStyle strokeStyle; KisPainter::FillStyle fillStyle; const KoPattern* pattern; const KoAbstractGradient* gradient; - const KisFilterConfiguration* generator; + KisFilterConfigurationSP generator; }; KisRecordedPaintAction::KisRecordedPaintAction(const QString & id, const QString & name, const KisNodeQueryPath& path, const KisPaintOpPresetSP paintOpPreset) : KisRecordedNodeAction(id, name, path) , d(new Private) { if (paintOpPreset) { d->paintOpPreset = paintOpPreset; } d->opacity = 1.0; d->paintIncremental = true; d->compositeOp = COMPOSITE_OVER; d->strokeStyle = KisPainter::StrokeStyleBrush; d->fillStyle = KisPainter::FillStyleNone; d->pattern = 0; d->gradient = 0; - d->generator = 0; } KisRecordedPaintAction::KisRecordedPaintAction(const KisRecordedPaintAction& rhs) : KisRecordedNodeAction(rhs), d(new Private(*rhs.d)) { } KisRecordedPaintAction::~KisRecordedPaintAction() { delete d; } void KisRecordedPaintAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const { KisRecordedAction::toXML(doc, elt, context); // Paint op presset if (d->paintOpPreset) { QDomElement paintopPressetElt = doc.createElement("PaintopPreset"); d->paintOpPreset->toXML(doc, paintopPressetElt); elt.appendChild(paintopPressetElt); } // ForegroundColor QDomElement foregroundColorElt = doc.createElement("ForegroundColor"); d->foregroundColor.toXML(doc, foregroundColorElt); elt.appendChild(foregroundColorElt); // BackgroundColor QDomElement backgroundColorElt = doc.createElement("BackgroundColor"); d->backgroundColor.toXML(doc, backgroundColorElt); elt.appendChild(backgroundColorElt); // Opacity elt.setAttribute("opacity", KisDomUtils::toString(d->opacity)); // paintIncremental elt.setAttribute("paintIncremental", d->paintIncremental); // compositeOp elt.setAttribute("compositeOp", d->compositeOp); // Save stroke style switch(d->strokeStyle) { case KisPainter::StrokeStyleNone: elt.setAttribute("strokeStyle", "None"); break; case KisPainter::StrokeStyleBrush: elt.setAttribute("strokeStyle", "Brush"); break; } // Save fill style switch(d->fillStyle) { case KisPainter::FillStyleNone: elt.setAttribute("fillStyle", "None"); break; case KisPainter::FillStyleForegroundColor: elt.setAttribute("fillStyle", "PaintColor"); break; case KisPainter::FillStyleBackgroundColor: elt.setAttribute("fillStyle", "AlternativeColor"); break; case KisPainter::FillStylePattern: elt.setAttribute("fillStyle", "Pattern"); context->savePattern(d->pattern); elt.setAttribute("pattern", d->pattern->name()); break; case KisPainter::FillStyleGradient: elt.setAttribute("fillStyle", "Gradient"); context->saveGradient(d->gradient); elt.setAttribute("gradient", d->gradient->name()); break; case KisPainter::FillStyleStrokes: elt.setAttribute("fillStyle", "Strokes"); break; case KisPainter::FillStyleGenerator: elt.setAttribute("fillStyle", "Generator"); if (d->generator) { elt.setAttribute("generator", d->generator->name()); QDomElement filterConfigElt = doc.createElement("Generator"); d->generator->toXML(doc, filterConfigElt); elt.appendChild(filterConfigElt); } break; } } KisPaintOpPresetSP KisRecordedPaintAction::paintOpPreset() const { return d->paintOpPreset; } void KisRecordedPaintAction::setPaintOpPreset(KisPaintOpPresetSP preset) { d->paintOpPreset = preset; } qreal KisRecordedPaintAction::opacity() const { return d->opacity; } void KisRecordedPaintAction::setOpacity(qreal opacity) { d->opacity = opacity; } KoColor KisRecordedPaintAction::paintColor() const { return d->foregroundColor; } void KisRecordedPaintAction::setPaintColor(const KoColor& color) { d->foregroundColor = color; } KoColor KisRecordedPaintAction::backgroundColor() const { return d->backgroundColor; } void KisRecordedPaintAction::setBackgroundColor(const KoColor& color) { d->backgroundColor = color; } QString KisRecordedPaintAction::compositeOp() { return d->compositeOp; } void KisRecordedPaintAction::setCompositeOp(const QString& id) { d->compositeOp = id; } void KisRecordedPaintAction::setPaintIncremental(bool v) { d->paintIncremental = v; } void KisRecordedPaintAction::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { d->strokeStyle = strokeStyle; } void KisRecordedPaintAction::setFillStyle(KisPainter::FillStyle fillStyle) { d->fillStyle = fillStyle; } KisPainter::FillStyle KisRecordedPaintAction::fillStyle() const { return d->fillStyle; } void KisRecordedPaintAction::setPattern(const KoPattern* pattern) { d->pattern = pattern; } void KisRecordedPaintAction::setGradient(const KoAbstractGradient* gradient) { d->gradient = gradient; } -void KisRecordedPaintAction::setGenerator(const KisFilterConfiguration * generator) +void KisRecordedPaintAction::setGenerator(const KisFilterConfigurationSP generator) { d->generator = generator; } void KisRecordedPaintAction::play(KisNodeSP node, const KisPlayInfo& info, KoUpdater* _updater) const { dbgUI << "Play recorded paint action on node : " << node->name() ; KisTransaction transaction(node->paintDevice()); KisPaintDeviceSP target = 0; if (d->paintIncremental) { target = node->paintDevice(); } else { target = node->paintDevice()->createCompositionSourceDevice(); } KisPainter* painter = createPainter(target); painter->setProgress(_updater); if (d->paintIncremental) { painter->setCompositeOp(d->compositeOp); painter->setOpacity(d->opacity * 255); } else { painter->setCompositeOp(node->paintDevice()->colorSpace()->compositeOp(COMPOSITE_ALPHA_DARKEN)); painter->setOpacity(OPACITY_OPAQUE_U8); } painter->setPaintColor(d->foregroundColor); painter->setBackgroundColor(d->backgroundColor); painter->setStrokeStyle(d->strokeStyle); painter->setFillStyle(d->fillStyle); painter->setPattern(d->pattern); painter->setGradient(d->gradient); painter->setGenerator(d->generator); if (d->paintOpPreset) { painter->setPaintOpPreset(d->paintOpPreset, node, info.image()); } playPaint(info, painter); if (!d->paintIncremental) { KisPainter painter2(node->paintDevice()); painter2.setCompositeOp(d->compositeOp); painter2.setOpacity(d->opacity * 255); QVector dirtyRects = painter->takeDirtyRegion(); Q_FOREACH (const QRect &rc, dirtyRects) { painter2.bitBlt(rc.topLeft(), target, rc); } node->setDirty(painter2.takeDirtyRegion()); } else { node->setDirty(painter->takeDirtyRegion()); } delete painter; transaction.commit(info.undoAdapter()); } KisPainter* KisRecordedPaintAction::createPainter(KisPaintDeviceSP device) const { return new KisPainter(device); } void KisRecordedPaintActionFactory::setupPaintAction(KisRecordedPaintAction* action, const QDomElement& elt, const KisRecordedActionLoadContext* context) { QString name = elt.attribute("name"); qreal opacity = opacityFromXML(elt); dbgKrita << ppVar(opacity); bool paintIncremental = paintIncrementalFromXML(elt); QString compositeOp = compositeOpFromXML(elt); // Decode colors KoColor bC = backgroundColorFromXML(elt); KoColor fC = paintColorFromXML(elt); action->setName(name); action->setBackgroundColor(bC); action->setPaintColor(fC); action->setOpacity(opacity); action->setPaintIncremental(paintIncremental); action->setCompositeOp(compositeOp); // Load stroke style QString strokeAttr = elt.attribute("strokeStyle", "None"); if (strokeAttr == "Brush" ) { action->setStrokeStyle(KisPainter::StrokeStyleBrush); } else { // "None" action->setStrokeStyle(KisPainter::StrokeStyleNone); } // Save fill style QString fillAttr = elt.attribute("fillStyle", "None"); if (fillAttr == "PaintColor") { action->setFillStyle(KisPainter::FillStyleForegroundColor); } else if(fillAttr == "AlternativeColor") { action->setFillStyle(KisPainter::FillStyleBackgroundColor); } else if(fillAttr == "Pattern") { const KoPattern* pattern = context->pattern(elt.attribute("pattern")); if (pattern) { action->setFillStyle(KisPainter::FillStylePattern); action->setPattern(pattern); } else { action->setFillStyle(KisPainter::FillStyleNone); } } else if(fillAttr == "Gradient") { const KoAbstractGradient* gradient = context->gradient(elt.attribute("gradient")); if (gradient) { action->setFillStyle(KisPainter::FillStyleGradient); action->setGradient(gradient); } else { action->setFillStyle(KisPainter::FillStyleNone); } } else if(fillAttr == "Strokes") { action->setFillStyle(KisPainter::FillStyleStrokes); } else if(fillAttr == "Generator") { KisGeneratorSP g = KisGeneratorRegistry::instance()->value(elt.attribute("generator")); - KisFilterConfiguration* config = 0; + KisFilterConfigurationSP config = 0; if (g) { config = g->defaultConfiguration(0); QDomElement paramsElt = elt.firstChildElement("Generator"); if (config && !paramsElt.isNull()) { config->fromXML(paramsElt); } } if(config) { action->setFillStyle(KisPainter::FillStyleGenerator); action->setGenerator(config); } else { action->setFillStyle(KisPainter::FillStyleNone); } } } KisPaintOpPresetSP KisRecordedPaintActionFactory::paintOpPresetFromXML(const QDomElement& elt) { QDomElement settingsElt = elt.firstChildElement("PaintopPreset"); if (!settingsElt.isNull()) { KisPaintOpPresetSP settings = new KisPaintOpPreset; settings->fromXML(settingsElt); return settings; } else { errImage << "No found"; return 0; } } KoColor KisRecordedPaintActionFactory::paintColorFromXML(const QDomElement& elt) { return colorFromXML(elt, "ForegroundColor"); } KoColor KisRecordedPaintActionFactory::backgroundColorFromXML(const QDomElement& elt) { return colorFromXML(elt, "BackgroundColor"); } KoColor KisRecordedPaintActionFactory::colorFromXML(const QDomElement& elt, const QString& elementName) { QDomElement colorElt = elt.firstChildElement(elementName); KoColor bC; if (!colorElt.isNull()) { bC = KoColor::fromXML(colorElt.firstChildElement(), Integer8BitsColorDepthID.id(), QHash()); bC.setOpacity(quint8(255)); dbgImage << elementName << " color : " << bC.toQColor(); } else { dbgImage << "Warning: no <" << elementName << " /> found"; } return bC; } qreal KisRecordedPaintActionFactory::opacityFromXML(const QDomElement& elt) { return KisDomUtils::toDouble(elt.attribute("opacity", "1.0")); } bool KisRecordedPaintActionFactory::paintIncrementalFromXML(const QDomElement& elt) { return KisDomUtils::toInt(elt.attribute("paintIncremental", "1")); } QString KisRecordedPaintActionFactory::compositeOpFromXML(const QDomElement& elt) { return elt.attribute("compositeOp", COMPOSITE_OVER); } KisNodeQueryPath KisRecordedPaintActionFactory::nodeQueryPathFromXML(const QDomElement& elt) { return KisNodeQueryPath::fromString(elt.attribute("path")); } diff --git a/libs/image/recorder/kis_recorded_paint_action.h b/libs/image/recorder/kis_recorded_paint_action.h index 7a800ba7d0..6c726f95f0 100644 --- a/libs/image/recorder/kis_recorded_paint_action.h +++ b/libs/image/recorder/kis_recorded_paint_action.h @@ -1,110 +1,110 @@ /* * Copyright (c) 2007,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_RECORDED_PAINT_ACTION_H_ #define _KIS_RECORDED_PAINT_ACTION_H_ #include "recorder/kis_recorded_node_action.h" #include "kis_types.h" #include "kis_painter.h" class KisPainter; class KoColor; #include /** * Base class for paint action. */ class KRITAIMAGE_EXPORT KisRecordedPaintAction : public KisRecordedNodeAction { public: KisRecordedPaintAction(const QString & id, const QString & name, const KisNodeQueryPath& path, KisPaintOpPresetSP paintOpPreset); KisRecordedPaintAction(const KisRecordedPaintAction&); ~KisRecordedPaintAction(); virtual void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const; using KisRecordedNodeAction::play; virtual void play(KisNodeSP node, const KisPlayInfo& info, KoUpdater* _updater = 0) const; protected: /** * This function will create a painter for the given device. The default * implementation creates a KisPainter, subclass can reimplement it if * they want to use one of the subclass of KisPainter. */ virtual KisPainter* createPainter(KisPaintDeviceSP device) const; /** * Reimplement this function in a subclass to play the painting. */ virtual void playPaint(const KisPlayInfo&, KisPainter* painter) const = 0; public: KisPaintOpPresetSP paintOpPreset() const; void setPaintOpPreset(KisPaintOpPresetSP preset); /** * @return the opacity in the range 0.0->1.0 */ qreal opacity() const; void setOpacity(qreal ); KoColor paintColor() const; void setPaintColor(const KoColor& color); KoColor backgroundColor() const; void setBackgroundColor(const KoColor& color); QString compositeOp(); void setCompositeOp(const QString& ); void setPaintIncremental(bool ); void setStrokeStyle(KisPainter::StrokeStyle ); void setFillStyle(KisPainter::FillStyle ); KisPainter::FillStyle fillStyle() const; void setPattern(const KoPattern* ); void setGradient(const KoAbstractGradient* gradient); - void setGenerator(const KisFilterConfiguration * generator); + void setGenerator(const KisFilterConfigurationSP generator); private: struct Private; Private* const d; }; class KisRecordedPaintActionFactory : public KisRecordedActionFactory { public: KisRecordedPaintActionFactory(const QString & id) : KisRecordedActionFactory(id) {} virtual ~KisRecordedPaintActionFactory() {} protected: void setupPaintAction(KisRecordedPaintAction* action, const QDomElement& elt, const KisRecordedActionLoadContext*); KisPaintOpPresetSP paintOpPresetFromXML(const QDomElement& elt); KoColor paintColorFromXML(const QDomElement& elt); KoColor backgroundColorFromXML(const QDomElement& elt); KoColor colorFromXML(const QDomElement& elt, const QString& elementName); qreal opacityFromXML(const QDomElement& elt); bool paintIncrementalFromXML(const QDomElement& elt); QString compositeOpFromXML(const QDomElement& elt); KisNodeQueryPath nodeQueryPathFromXML(const QDomElement& elt); }; #endif diff --git a/libs/image/tests/kis_adjustment_layer_test.cpp b/libs/image/tests/kis_adjustment_layer_test.cpp index 7c8740f24b..dca96250c4 100644 --- a/libs/image/tests/kis_adjustment_layer_test.cpp +++ b/libs/image/tests/kis_adjustment_layer_test.cpp @@ -1,117 +1,117 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_adjustment_layer_test.h" #include #include #include #include "kis_adjustment_layer.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter.h" #include "filter/kis_filter_registry.h" #include "kis_image.h" #include "kis_selection.h" #include "kis_types.h" #include "kis_datamanager.h" #include "kis_pixel_selection.h" #include "testutil.h" void KisAdjustmentLayerTest::testCreation() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "adj layer test"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); KisAdjustmentLayerSP test = new KisAdjustmentLayer(image, "test", kfc, 0); } void KisAdjustmentLayerTest::testSetSelection() { KisSelectionSP sel = new KisSelection(); const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "adj layer test"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); sel->pixelSelection()->select(QRect(10, 10, 200, 200), 128); KisAdjustmentLayerSP l1 = new KisAdjustmentLayer(image, "bla", kfc, sel); QCOMPARE(sel->selectedExactRect(), l1->internalSelection()->selectedExactRect()); } void KisAdjustmentLayerTest::testInverted() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "adj layer test"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); KisSelectionSP sel2 = new KisSelection(); sel2->pixelSelection()->invert(); KisAdjustmentLayerSP l2 = new KisAdjustmentLayer(image, "bla", kfc, sel2); QCOMPARE(sel2->selectedExactRect(), l2->internalSelection()->selectedExactRect()); KisSelectionSP sel3 = new KisSelection(); sel3->pixelSelection()->select(QRect(50, -10, 800, 30), 128); l2->setInternalSelection(sel3); } void KisAdjustmentLayerTest::testSelectionParent() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "adj layer test"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); { KisAdjustmentLayerSP adjLayer = new KisAdjustmentLayer(image, "bla", f->defaultConfiguration(0), 0); QCOMPARE(adjLayer->internalSelection()->parentNode(), KisNodeWSP(adjLayer)); } { KisSelectionSP selection = new KisSelection(); KisAdjustmentLayerSP adjLayer = new KisAdjustmentLayer(image, "bla", f->defaultConfiguration(0), selection); QCOMPARE(adjLayer->internalSelection()->parentNode(), KisNodeWSP(adjLayer)); } { KisAdjustmentLayerSP adjLayer = new KisAdjustmentLayer(image, "bla", f->defaultConfiguration(0), 0); KisSelectionSP selection = new KisSelection(); adjLayer->setInternalSelection(selection); QCOMPARE(adjLayer->internalSelection()->parentNode(), KisNodeWSP(adjLayer)); } } QTEST_MAIN(KisAdjustmentLayerTest) diff --git a/libs/image/tests/kis_async_merger_test.cpp b/libs/image/tests/kis_async_merger_test.cpp index d7524f3cf4..29dd24f314 100644 --- a/libs/image/tests/kis_async_merger_test.cpp +++ b/libs/image/tests/kis_async_merger_test.cpp @@ -1,291 +1,291 @@ /* * 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. */ #include "kis_async_merger_test.h" #include "kis_merge_walker.h" #include "kis_full_refresh_walker.h" #include "kis_async_merger.h" #include #include #include #include "kis_image.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include "kis_clone_layer.h" #include "kis_adjustment_layer.h" #include "kis_filter_mask.h" #include "kis_selection.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "../../sdk/tests/testutil.h" /* +-----------+ |root | | group | | blur 1 | | paint 2 | | paint 1 | +-----------+ */ void KisAsyncMergerTest::testMerger() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 640, 441, colorSpace, "merger test"); QImage sourceImage1(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage sourceImage2(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); QImage referenceProjection(QString(FILES_DATA_DIR) + QDir::separator() + "merged_hakonepa.png"); KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace); KisPaintDeviceSP device2 = new KisPaintDevice(colorSpace); device1->convertFromQImage(sourceImage1, 0, 0, 0); device2->convertFromQImage(sourceImage2, 0, 0, 0); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8, device2); KisLayerSP groupLayer = new KisGroupLayer(image, "group", 200/*OPACITY_OPAQUE*/); KisLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(blur1, groupLayer); QRect testRect1(0,0,100,441); QRect testRect2(100,0,400,441); QRect testRect3(500,0,140,441); QRect testRect4(580,381,40,40); QRect cropRect(image->bounds()); KisMergeWalker walker(cropRect); KisAsyncMerger merger; walker.collectRects(paintLayer2, testRect1); merger.startMerge(walker); walker.collectRects(paintLayer2, testRect2); merger.startMerge(walker); walker.collectRects(paintLayer2, testRect3); merger.startMerge(walker); walker.collectRects(paintLayer2, testRect4); merger.startMerge(walker); // Old style merging: has artefacts at x=100 and x=500 // And should be turned on inside KisLayer /* paintLayer2->setDirty(testRect1); QTest::qSleep(3000); paintLayer2->setDirty(testRect2); QTest::qSleep(3000); paintLayer2->setDirty(testRect3); QTest::qSleep(3000); paintLayer2->setDirty(testRect4); QTest::qSleep(3000); */ KisLayerSP rootLayer = image->rootLayer(); QVERIFY(rootLayer->exactBounds() == image->bounds()); QImage resultProjection = rootLayer->projection()->convertToQImage(0); resultProjection.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + "actual_merge_result.png"); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, resultProjection, referenceProjection, 5, 0, 0)); } /** * This in not fully automated test for child obliging in KisAsyncMerger. * It just checks whether devices are shared. To check if the merger * touches originals you can add a debug message to the merger * and take a look. */ /* +-----------+ |root | | group | | paint 1 | +-----------+ */ void KisAsyncMergerTest::debugObligeChild() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 640, 441, colorSpace, "merger test"); QImage sourceImage1(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace); device1->convertFromQImage(sourceImage1, 0, 0, 0); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); image->addNode(groupLayer, image->rootLayer()); image->addNode(paintLayer1, groupLayer); QRect testRect1(0,0,640,441); QRect cropRect(image->bounds()); KisMergeWalker walker(cropRect); KisAsyncMerger merger; walker.collectRects(paintLayer1, testRect1); merger.startMerge(walker); KisLayerSP rootLayer = image->rootLayer(); QVERIFY(rootLayer->original() == groupLayer->projection()); QVERIFY(groupLayer->original() == paintLayer1->projection()); } /* +--------------+ |root | | paint 1 | | invert_mask | | clone_of_1 | +--------------+ */ void KisAsyncMergerTest::testFullRefreshWithClones() { const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 128, 128, colorSpace, "clones test"); KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace); device1->fill(image->bounds(), KoColor( Qt::white, colorSpace)); KisFilterSP filter = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisFilterMaskSP invertMask1 = new KisFilterMask(); invertMask1->initSelection(paintLayer1); invertMask1->setFilter(configuration); KisLayerSP cloneLayer1 = new KisCloneLayer(paintLayer1, image, "clone_of_1", OPACITY_OPAQUE_U8); /** * The clone layer must have a projection to allow us * to read what it got from its source. Just shift it. */ cloneLayer1->setX(10); cloneLayer1->setY(10); image->addNode(cloneLayer1, image->rootLayer()); image->addNode(paintLayer1, image->rootLayer()); image->addNode(invertMask1, paintLayer1); QRect cropRect(image->bounds()); KisFullRefreshWalker walker(cropRect); KisAsyncMerger merger; walker.collectRects(image->rootLayer(), image->bounds()); merger.startMerge(walker); // Wait for additional jobs generated by the clone are finished image->waitForDone(); QRect filledRect(10, 10, image->width() - cloneLayer1->x(), image->height() - cloneLayer1->y()); const int pixelSize = device1->pixelSize(); const int numPixels = filledRect.width() * filledRect.height(); QByteArray bytes(numPixels * pixelSize, 13); cloneLayer1->projection()->readBytes((quint8*)bytes.data(), filledRect); KoColor desiredPixel(Qt::black, colorSpace); quint8 *srcPtr = (quint8*)bytes.data(); quint8 *dstPtr = desiredPixel.data(); for(int i = 0; i < numPixels; i++) { if(memcmp(srcPtr, dstPtr, pixelSize)) { dbgKrita << "expected:" << dstPtr[0] << dstPtr[1] << dstPtr[2] << dstPtr[3]; dbgKrita << "result: " << srcPtr[0] << srcPtr[1] << srcPtr[2] << srcPtr[3]; QFAIL("Failed to compare pixels"); } srcPtr += pixelSize; } } /* +--------------+ |root | | paint 2 | | paint 1 | +--------------+ */ void KisAsyncMergerTest::testSubgraphingWithoutUpdatingParent() { const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 128, 128, colorSpace, "clones test"); KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace); device1->fill(image->bounds(), KoColor(Qt::white, colorSpace)); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisPaintDeviceSP device2 = new KisPaintDevice(colorSpace); device2->fill(image->bounds(), KoColor(Qt::black, colorSpace)); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", 128, device2); image->addNode(paintLayer1, image->rootLayer()); image->addNode(paintLayer2, image->rootLayer()); image->initialRefreshGraph(); QImage refImage(QString(FILES_DATA_DIR) + QDir::separator() + "subgraphing_without_updating.png"); { QImage resultImage = image->projection()->convertToQImage(0); QCOMPARE(resultImage, refImage); } QRect cropRect(image->bounds()); KisRefreshSubtreeWalker walker(cropRect); KisAsyncMerger merger; walker.collectRects(paintLayer2, image->bounds()); merger.startMerge(walker); { QImage resultImage = image->projection()->convertToQImage(0); QCOMPARE(resultImage, refImage); } } QTEST_MAIN(KisAsyncMergerTest) diff --git a/libs/image/tests/kis_bookmarked_configuration_manager_test.cpp b/libs/image/tests/kis_bookmarked_configuration_manager_test.cpp index 6123dcaf78..888cee67c4 100644 --- a/libs/image/tests/kis_bookmarked_configuration_manager_test.cpp +++ b/libs/image/tests/kis_bookmarked_configuration_manager_test.cpp @@ -1,63 +1,63 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_bookmarked_configuration_manager_test.h" #include #include "kis_bookmarked_configuration_manager.h" #include "kis_serializable_configuration.h" class TestConfiguration : public KisSerializableConfiguration { public: using KisSerializableConfiguration::fromXML; using KisSerializableConfiguration::toXML; void fromXML(const QDomElement&) { } void toXML(QDomDocument&, QDomElement&) const { } }; class TestConfigurationFactory : public KisSerializableConfigurationFactory { public: - virtual KisSerializableConfiguration* createDefault() { + virtual KisSerializableConfigurationSP createDefault() { return &tc; } - virtual KisSerializableConfiguration* create(const QDomElement&) { + virtual KisSerializableConfigurationSP create(const QDomElement&) { return &tc; } private: TestConfiguration tc; }; void KisBookmarkedConfigurationManagerTest::testCreation() { TestConfigurationFactory *tcf = new TestConfigurationFactory; KisBookmarkedConfigurationManager test("Test", tcf); } QTEST_MAIN(KisBookmarkedConfigurationManagerTest) diff --git a/libs/image/tests/kis_filter_config_widget_test.cpp b/libs/image/tests/kis_filter_config_widget_test.cpp index caac66d32b..a75b527b73 100644 --- a/libs/image/tests/kis_filter_config_widget_test.cpp +++ b/libs/image/tests/kis_filter_config_widget_test.cpp @@ -1,48 +1,48 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_filter_config_widget_test.h" #include #include "filter/kis_filter_configuration.h" #include "kis_config_widget.h" class TestWidget : public KisConfigWidget { public: TestWidget() : KisConfigWidget(0) { } - void setConfiguration(const KisPropertiesConfiguration *) { + void setConfiguration(const KisPropertiesConfigurationSP ) { } - KisPropertiesConfiguration * configuration() const { + KisPropertiesConfigurationSP configuration() const { return 0; } }; void KisConfigWidgetTest::testCreation() { TestWidget test; } QTEST_MAIN(KisConfigWidgetTest) diff --git a/libs/image/tests/kis_filter_configuration_test.cpp b/libs/image/tests/kis_filter_configuration_test.cpp index 640beec107..689e7dfd8d 100644 --- a/libs/image/tests/kis_filter_configuration_test.cpp +++ b/libs/image/tests/kis_filter_configuration_test.cpp @@ -1,71 +1,71 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_filter_configuration_test.h" #include #include #include #include #include #include "../filter/kis_filter_configuration.h" #include "../filter/kis_filter_registry.h" #include "../filter/kis_filter.h" void KisFilterConfigurationTest::testCreation() { - KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + KisFilterConfigurationSP kfc = new KisFilterConfiguration("test", 1); QVERIFY2(kfc != 0, "Could not create test filter configuration"); QCOMPARE(kfc->version(), 1); QCOMPARE(kfc->name(), QString("test")); delete kfc; } void KisFilterConfigurationTest::testRoundTrip() { - KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + KisFilterConfigurationSP kfc = new KisFilterConfiguration("test", 1); QCOMPARE(kfc->version(), 1); QCOMPARE(kfc->name(), QString("test")); QString s = kfc->toXML(); delete kfc; kfc = new KisFilterConfiguration("test2", 2); kfc->fromXML(s); QCOMPARE(kfc->version(), 1); delete kfc; } void KisFilterConfigurationTest::testSetGetProperty() { - KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + KisFilterConfigurationSP kfc = new KisFilterConfiguration("test", 1); kfc->setProperty("value1", 10); kfc->setProperty("value2", "foo"); QCOMPARE(kfc->getInt("value1"), 10); QCOMPARE(kfc->getString("value2"), QString("foo")); QString s = kfc->toXML(); delete kfc; kfc = new KisFilterConfiguration("test2", 2); kfc->fromXML(s); QCOMPARE(kfc->getInt("value1"), 10); QCOMPARE(kfc->getString("value2"), QString("foo")); delete kfc; } QTEST_MAIN(KisFilterConfigurationTest) diff --git a/libs/image/tests/kis_filter_mask_test.cpp b/libs/image/tests/kis_filter_mask_test.cpp index d32985b940..71f2087d5d 100644 --- a/libs/image/tests/kis_filter_mask_test.cpp +++ b/libs/image/tests/kis_filter_mask_test.cpp @@ -1,125 +1,125 @@ /* * Copyright (c) 2007 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_filter_mask_test.h" #include #include #include "kis_selection.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "kis_filter_mask.h" #include "filter/kis_filter_registry.h" #include "kis_group_layer.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_types.h" #include "kis_image.h" #include "testutil.h" #define IMAGE_WIDTH 1000 #define IMAGE_HEIGHT 1000 void KisFilterMaskTest::testCreation() { KisFilterMaskSP mask = new KisFilterMask(); } #define initImage(image, layer, device, mask) do { \ image = new KisImage(0, IMAGE_WIDTH, IMAGE_HEIGHT, 0, "tests"); \ layer = new KisPaintLayer(image, 0, 100, device); \ image->addNode(layer); \ image->addNode(mask, layer); \ } while(0) void KisFilterMaskTest::testProjectionNotSelected() { KisImageSP image; KisPaintLayerSP layer; const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); KisFilterMaskSP mask = new KisFilterMask(); mask->setFilter(kfc); // Check basic apply(). Shouldn't do anything, since nothing is selected yet. KisPaintDeviceSP projection = new KisPaintDevice(cs); initImage(image, layer, projection, mask); projection->convertFromQImage(qimage, 0, 0, 0); mask->initSelection(layer); mask->createNodeProgressProxy(); mask->select(qimage.rect(), MIN_SELECTED); mask->apply(projection, qimage.rect(), qimage.rect(), KisNode::N_FILTHY); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, qimage, projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtermasktest1.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } void KisFilterMaskTest::testProjectionSelected() { KisImageSP image; KisPaintLayerSP layer; const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); KisFilterMaskSP mask = new KisFilterMask(); mask->setFilter(kfc); mask->createNodeProgressProxy(); KisPaintDeviceSP projection = new KisPaintDevice(cs); initImage(image, layer, projection, mask); projection->convertFromQImage(qimage, 0, 0, 0); mask->initSelection(layer); mask->select(qimage.rect(), MAX_SELECTED); mask->apply(projection, qimage.rect(), qimage.rect(), KisNode::N_FILTHY); QCOMPARE(mask->exactBounds(), QRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtermasktest2.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } QTEST_MAIN(KisFilterMaskTest) diff --git a/libs/image/tests/kis_filter_test.cpp b/libs/image/tests/kis_filter_test.cpp index 95ec6de9b6..2869c9b73b 100644 --- a/libs/image/tests/kis_filter_test.cpp +++ b/libs/image/tests/kis_filter_test.cpp @@ -1,240 +1,240 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_filter_test.h" #include #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_processing_information.h" #include "filter/kis_filter.h" #include "testutil.h" #include "kis_pixel_selection.h" #include #include class TestFilter : public KisFilter { public: TestFilter() : KisFilter(KoID("test", "test"), KoID("test", "test"), "TestFilter") { } void processImpl(KisPaintDeviceSP src, const QRect& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { Q_UNUSED(src); Q_UNUSED(size); Q_UNUSED(config); Q_UNUSED(progressUpdater); } }; void KisFilterTest::testCreation() { TestFilter test; } void KisFilterTest::testWithProgressUpdater() { TestUtil::TestProgressBar * bar = new TestUtil::TestProgressBar(); KoProgressUpdater* pu = new KoProgressUpdater(bar); KoUpdaterPtr updater = pu->startSubtask(); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc, updater); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtertest.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } delete pu; delete bar; } void KisFilterTest::testSingleThreaded() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtertest.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } void KisFilterTest::testDifferentSrcAndDst() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisPaintDeviceSP src = new KisPaintDevice(cs); KisPaintDeviceSP dst = new KisPaintDevice(cs); KisSelectionSP sel = new KisSelection(new KisSelectionDefaultBounds(src)); sel->pixelSelection()->invert(); // select everything sel->updateProjection(); src->convertFromQImage(qimage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(src, dst, sel, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, dst->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dst->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtertest.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } void KisFilterTest::testOldDataApiAfterCopy() { QRect updateRect(0,0,63,63); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); quint8 *whitePixel = new quint8[cs->pixelSize()]; cs->fromQColor(Qt::white, whitePixel); cs->setOpacity(whitePixel, OPACITY_OPAQUE_U8, 1); KisPaintDeviceSP tmp = new KisPaintDevice(cs); KisPaintDeviceSP src = new KisPaintDevice(cs); src->fill(0, 0, 50, 50, whitePixel); /** * Make a full copy here to catch the bug. * Buggy memento manager would make a commit * that is not good. */ KisPaintDeviceSP dst = new KisPaintDevice(*src); /** * This would write go to a new revision in a buggy * memento manager */ dst->clear(updateRect); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); /** * This filter reads from oldRawData, so if we have some * weirdness with transactions it will read from old and non-cleared * version of the device and we will see a black square instead * of empty device in tmp */ f->process(dst, tmp, 0, updateRect, kfc); /** * In theory, both devices: dst and tmp must be empty by now */ KisPaintDeviceSP reference = new KisPaintDevice(cs); QImage refImage = reference->convertToQImage(0,0,0,63,63); QImage dstImage = dst->convertToQImage(0,0,0,63,63); QImage tmpImage = tmp->convertToQImage(0,0,0,63,63); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, refImage, dstImage)); QVERIFY(TestUtil::compareQImages(pt, refImage, tmpImage)); } void KisFilterTest::testBlurFilterApplicationRect() { QRect filterRect(10,10,40,40); QRect src1Rect(5,5,50,50); QRect src2Rect(0,0,60,60); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); quint8 *whitePixel = new quint8[cs->pixelSize()]; cs->fromQColor(Qt::white, whitePixel); cs->setOpacity(whitePixel, OPACITY_OPAQUE_U8, 1); KisPaintDeviceSP src1 = new KisPaintDevice(cs); src1->fill(src1Rect.left(),src1Rect.top(),src1Rect.width(),src1Rect.height(), whitePixel); KisPaintDeviceSP src2 = new KisPaintDevice(cs); src2->fill(src2Rect.left(),src2Rect.top(),src2Rect.width(),src2Rect.height(), whitePixel); KisPaintDeviceSP dst1 = new KisPaintDevice(cs); KisPaintDeviceSP dst2 = new KisPaintDevice(cs); KisFilterSP f = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(src1, dst1, 0, filterRect, kfc); f->process(src2, dst2, 0, filterRect, kfc); KisPaintDeviceSP reference = new KisPaintDevice(cs); reference->fill(filterRect.left(),filterRect.top(),filterRect.width(),filterRect.height(), whitePixel); QImage refImage = reference->convertToQImage(0,10,10,40,40); QImage dst1Image = dst1->convertToQImage(0,10,10,40,40); QImage dst2Image = dst2->convertToQImage(0,10,10,40,40); //dst1Image.save("DST1.png"); //dst2Image.save("DST2.png"); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, refImage, dst1Image)); QVERIFY(TestUtil::compareQImages(pt, refImage, dst2Image)); } QTEST_MAIN(KisFilterTest) diff --git a/libs/image/tests/kis_image_test.cpp b/libs/image/tests/kis_image_test.cpp index 41ec248484..f8495c0424 100644 --- a/libs/image/tests/kis_image_test.cpp +++ b/libs/image/tests/kis_image_test.cpp @@ -1,904 +1,904 @@ /* * Copyright (c) 2005 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. */ #include "kis_image_test.h" #include #include #include #include #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_image.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include "kis_adjustment_layer.h" #include "kis_selection.h" #include #include #include "kis_keyframe_channel.h" #include "kis_selection_mask.h" #include "kis_layer_utils.h" #include "kis_undo_stores.h" #define IMAGE_WIDTH 128 #define IMAGE_HEIGHT 128 void KisImageTest::layerTests() { KisImageSP image = new KisImage(0, IMAGE_WIDTH, IMAGE_WIDTH, 0, "layer tests"); QVERIFY(image->rootLayer() != 0); QVERIFY(image->rootLayer()->firstChild() == 0); KisLayerSP layer = new KisPaintLayer(image, "layer 1", OPACITY_OPAQUE_U8); image->addNode(layer); QVERIFY(image->rootLayer()->firstChild()->objectName() == layer->objectName()); } void KisImageTest::benchmarkCreation() { const QRect imageRect(0,0,3000,2000); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QList images; QList stores; QBENCHMARK { for (int i = 0; i < 10; i++) { stores << new KisSurrogateUndoStore(); } for (int i = 0; i < 10; i++) { KisImageSP image = new KisImage(stores.takeLast(), imageRect.width(), imageRect.height(), cs, "test image"); images << image; } } } #include "testutil.h" #include "kis_stroke_strategy.h" #include class ForbiddenLodStrokeStrategy : public KisStrokeStrategy { public: ForbiddenLodStrokeStrategy(std::function lodCallback) : m_lodCallback(lodCallback) { } KisStrokeStrategy* createLodClone(int levelOfDetail) { Q_UNUSED(levelOfDetail); m_lodCallback(); return 0; } private: std::function m_lodCallback; }; void notifyVar(bool *value) { *value = true; } void KisImageTest::testBlockLevelOfDetail() { TestUtil::MaskParent p; QCOMPARE(p.image->currentLevelOfDetail(), 0); p.image->setDesiredLevelOfDetail(1); p.image->waitForDone(); QCOMPARE(p.image->currentLevelOfDetail(), 0); { bool lodCreated = false; KisStrokeId id = p.image->startStroke( new ForbiddenLodStrokeStrategy( std::bind(¬ifyVar, &lodCreated))); p.image->endStroke(id); p.image->waitForDone(); QVERIFY(lodCreated); } p.image->setLevelOfDetailBlocked(true); { bool lodCreated = false; KisStrokeId id = p.image->startStroke( new ForbiddenLodStrokeStrategy( std::bind(¬ifyVar, &lodCreated))); p.image->endStroke(id); p.image->waitForDone(); QVERIFY(!lodCreated); } p.image->setLevelOfDetailBlocked(false); p.image->setDesiredLevelOfDetail(1); { bool lodCreated = false; KisStrokeId id = p.image->startStroke( new ForbiddenLodStrokeStrategy( std::bind(¬ifyVar, &lodCreated))); p.image->endStroke(id); p.image->waitForDone(); QVERIFY(lodCreated); } } void KisImageTest::testConvertImageColorSpace() { const KoColorSpace *cs8 = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 1000, 1000, cs8, "stest"); KisPaintDeviceSP device1 = new KisPaintDevice(cs8); KisLayerSP paint1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0); image->addNode(paint1, image->root()); image->addNode(blur1, image->root()); image->refreshGraph(); const KoColorSpace *cs16 = KoColorSpaceRegistry::instance()->rgb16(); image->lock(); image->convertImageColorSpace(cs16, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); image->unlock(); QVERIFY(*cs16 == *image->colorSpace()); QVERIFY(*cs16 == *image->root()->colorSpace()); QVERIFY(*cs16 == *paint1->colorSpace()); QVERIFY(*cs16 == *blur1->colorSpace()); QVERIFY(!image->root()->compositeOp()); QVERIFY(*cs16 == *paint1->compositeOp()->colorSpace()); QVERIFY(*cs16 == *blur1->compositeOp()->colorSpace()); image->refreshGraph(); } void KisImageTest::testGlobalSelection() { const KoColorSpace *cs8 = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 1000, 1000, cs8, "stest"); QCOMPARE(image->globalSelection(), KisSelectionSP(0)); QCOMPARE(image->canReselectGlobalSelection(), false); QCOMPARE(image->root()->childCount(), 0U); KisSelectionSP selection1 = new KisSelection(new KisDefaultBounds(image)); KisSelectionSP selection2 = new KisSelection(new KisDefaultBounds(image)); image->setGlobalSelection(selection1); QCOMPARE(image->globalSelection(), selection1); QCOMPARE(image->canReselectGlobalSelection(), false); QCOMPARE(image->root()->childCount(), 1U); image->setGlobalSelection(selection2); QCOMPARE(image->globalSelection(), selection2); QCOMPARE(image->canReselectGlobalSelection(), false); QCOMPARE(image->root()->childCount(), 1U); image->deselectGlobalSelection(); QCOMPARE(image->globalSelection(), KisSelectionSP(0)); QCOMPARE(image->canReselectGlobalSelection(), true); QCOMPARE(image->root()->childCount(), 0U); image->reselectGlobalSelection(); QCOMPARE(image->globalSelection(), selection2); QCOMPARE(image->canReselectGlobalSelection(), false); QCOMPARE(image->root()->childCount(), 1U); // mixed deselecting/setting/reselecting image->deselectGlobalSelection(); QCOMPARE(image->globalSelection(), KisSelectionSP(0)); QCOMPARE(image->canReselectGlobalSelection(), true); QCOMPARE(image->root()->childCount(), 0U); image->setGlobalSelection(selection1); QCOMPARE(image->globalSelection(), selection1); QCOMPARE(image->canReselectGlobalSelection(), false); QCOMPARE(image->root()->childCount(), 1U); } void KisImageTest::testLayerComposition() { KisImageSP image = new KisImage(0, IMAGE_WIDTH, IMAGE_WIDTH, 0, "layer tests"); QVERIFY(image->rootLayer() != 0); QVERIFY(image->rootLayer()->firstChild() == 0); KisLayerSP layer = new KisPaintLayer(image, "layer 1", OPACITY_OPAQUE_U8); image->addNode(layer); KisLayerSP layer2 = new KisPaintLayer(image, "layer 2", OPACITY_OPAQUE_U8); image->addNode(layer2); QVERIFY(layer->visible()); QVERIFY(layer2->visible()); KisLayerComposition comp(image, "comp 1"); comp.store(); layer2->setVisible(false); QVERIFY(layer->visible()); QVERIFY(!layer2->visible()); KisLayerComposition comp2(image, "comp 2"); comp2.store(); comp.apply(); QVERIFY(layer->visible()); QVERIFY(layer2->visible()); comp2.apply(); QVERIFY(layer->visible()); QVERIFY(!layer2->visible()); } #include "testutil.h" #include "kis_group_layer.h" #include "kis_transparency_mask.h" #include "kis_psd_layer_style.h" struct FlattenTestImage { FlattenTestImage() : refRect(0,0,512,512) , p(refRect) { image = p.image; undoStore = p.undoStore; layer1 = p.layer; layer5 = new KisPaintLayer(p.image, "paint5", 0.4 * OPACITY_OPAQUE_U8); layer5->disableAlphaChannel(true); layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8); tmask = new KisTransparencyMask(); // check channel flags // make addition composite op group1 = new KisGroupLayer(p.image, "group1", OPACITY_OPAQUE_U8); layer3 = new KisPaintLayer(p.image, "paint3", OPACITY_OPAQUE_U8); layer4 = new KisPaintLayer(p.image, "paint4", OPACITY_OPAQUE_U8); layer6 = new KisPaintLayer(p.image, "paint6", OPACITY_OPAQUE_U8); layer7 = new KisPaintLayer(p.image, "paint7", OPACITY_OPAQUE_U8); layer8 = new KisPaintLayer(p.image, "paint8", OPACITY_OPAQUE_U8); layer7->setCompositeOpId(COMPOSITE_ADD); layer8->setCompositeOpId(COMPOSITE_ADD); QRect rect1(100, 100, 100, 100); QRect rect2(150, 150, 150, 150); QRect tmaskRect(200,200,100,100); QRect rect3(400, 100, 100, 100); QRect rect4(500, 100, 100, 100); QRect rect5(50, 50, 100, 100); QRect rect6(50, 250, 100, 100); QRect rect7(50, 350, 50, 50); QRect rect8(50, 400, 50, 50); layer1->paintDevice()->fill(rect1, KoColor(Qt::red, p.image->colorSpace())); layer2->paintDevice()->fill(rect2, KoColor(Qt::green, p.image->colorSpace())); tmask->testingInitSelection(tmaskRect, layer2); layer3->paintDevice()->fill(rect3, KoColor(Qt::blue, p.image->colorSpace())); layer4->paintDevice()->fill(rect4, KoColor(Qt::yellow, p.image->colorSpace())); layer5->paintDevice()->fill(rect5, KoColor(Qt::green, p.image->colorSpace())); layer6->paintDevice()->fill(rect6, KoColor(Qt::cyan, p.image->colorSpace())); layer7->paintDevice()->fill(rect7, KoColor(Qt::red, p.image->colorSpace())); layer8->paintDevice()->fill(rect8, KoColor(Qt::green, p.image->colorSpace())); KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->dropShadow()->setEffectEnabled(true); style->dropShadow()->setDistance(10.0); style->dropShadow()->setSpread(80.0); style->dropShadow()->setSize(10); style->dropShadow()->setNoise(0); style->dropShadow()->setKnocksOut(false); style->dropShadow()->setOpacity(80.0); layer2->setLayerStyle(style); layer2->setCompositeOpId(COMPOSITE_ADD); group1->setCompositeOpId(COMPOSITE_ADD); p.image->addNode(layer5); p.image->addNode(layer2); p.image->addNode(tmask, layer2); p.image->addNode(group1); p.image->addNode(layer3, group1); p.image->addNode(layer4, group1); p.image->addNode(layer6); p.image->addNode(layer7); p.image->addNode(layer8); p.image->initialRefreshGraph(); // dbgKrita << ppVar(layer1->exactBounds()); // dbgKrita << ppVar(layer5->exactBounds()); // dbgKrita << ppVar(layer2->exactBounds()); // dbgKrita << ppVar(group1->exactBounds()); // dbgKrita << ppVar(layer3->exactBounds()); // dbgKrita << ppVar(layer4->exactBounds()); TestUtil::ExternalImageChecker chk("flatten", "imagetest"); QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial")); } QRect refRect; TestUtil::MaskParent p; KisImageSP image; KisSurrogateUndoStore *undoStore; KisPaintLayerSP layer1; KisPaintLayerSP layer2; KisTransparencyMaskSP tmask; KisGroupLayerSP group1; KisPaintLayerSP layer3; KisPaintLayerSP layer4; KisPaintLayerSP layer5; KisPaintLayerSP layer6; KisPaintLayerSP layer7; KisPaintLayerSP layer8; }; template KisLayerSP flattenLayerHelper(ContainerTest &p, KisLayerSP layer, bool nothingHappens = false) { QSignalSpy spy(p.image.data(), SIGNAL(sigNodeAddedAsync(KisNodeSP))); //p.image->flattenLayer(layer); KisLayerUtils::flattenLayer(p.image, layer); p.image->waitForDone(); if (nothingHappens) { Q_ASSERT(!spy.count()); return layer; } Q_ASSERT(spy.count() == 1); QList arguments = spy.takeFirst(); KisNodeSP newNode = arguments.first().value(); KisLayerSP newLayer = dynamic_cast(newNode.data()); return newLayer; } void KisImageTest::testFlattenLayer() { FlattenTestImage p; TestUtil::ExternalImageChecker chk("flatten", "imagetest"); { QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD); KisLayerSP newLayer = flattenLayerHelper(p, p.layer2); //KisLayerSP newLayer = p.image->flattenLayer(p.layer2); //p.image->waitForDone(); QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer2_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); } { QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD); KisLayerSP newLayer = flattenLayerHelper(p, p.group1); //KisLayerSP newLayer = p.image->flattenLayer(p.group1); //p.image->waitForDone(); QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "02_group1_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_ADD); QCOMPARE(newLayer->exactBounds(), QRect(400, 100, 200, 100)); } { QCOMPARE(p.layer5->compositeOpId(), COMPOSITE_OVER); QCOMPARE(p.layer5->alphaChannelDisabled(), true); KisLayerSP newLayer = flattenLayerHelper(p, p.layer5, true); //KisLayerSP newLayer = p.image->flattenLayer(p.layer5); //p.image->waitForDone(); QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "03_layer5_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(50, 50, 100, 100)); QCOMPARE(newLayer->alphaChannelDisabled(), true); } } #include template KisLayerSP mergeHelper(ContainerTest &p, KisLayerSP layer) { KisNodeSP parent = layer->parent(); const int newIndex = parent->index(layer) - 1; p.image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); //KisLayerUtils::mergeDown(p.image, layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); p.image->waitForDone(); KisLayerSP newLayer = dynamic_cast(parent->at(newIndex).data()); return newLayer; } void KisImageTest::testMergeDown() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_simple", "imagetest"); { QCOMPARE(p.layer5->compositeOpId(), COMPOSITE_OVER); QCOMPARE(p.layer5->alphaChannelDisabled(), true); KisLayerSP newLayer = mergeHelper(p, p.layer5); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer5_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->alphaChannelDisabled(), false); } { QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.layer2->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.layer2); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "02_layer2_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(100, 100, 213, 217)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } { QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.group1->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.group1); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "03_group1_mergedown_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(100, 100, 500, 217)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } } void KisImageTest::testMergeDownDestinationInheritsAlpha() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_dst_inheritsalpha", "imagetest"); { QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.layer2->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.layer2); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer2_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(50,50, 263, 267)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } } void KisImageTest::testMergeDownDestinationCustomCompositeOp() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_dst_customop", "imagetest"); { QCOMPARE(p.layer6->compositeOpId(), COMPOSITE_OVER); QCOMPARE(p.layer6->alphaChannelDisabled(), false); QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.group1->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.layer6); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer6_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(50, 100, 550, 250)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } } void KisImageTest::testMergeDownDestinationSameCompositeOpLayerStyle() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_sameop_ls", "imagetest"); { QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.group1->alphaChannelDisabled(), false); QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.layer2->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.group1); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_group1_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(197, 100, 403, 217)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } } void KisImageTest::testMergeDownDestinationSameCompositeOp() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_sameop_fastpath", "imagetest"); { QCOMPARE(p.layer8->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.layer8->alphaChannelDisabled(), false); QCOMPARE(p.layer7->compositeOpId(), COMPOSITE_ADD); QCOMPARE(p.layer7->alphaChannelDisabled(), false); KisLayerSP newLayer = mergeHelper(p, p.layer8); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer8_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_ADD); QCOMPARE(newLayer->exactBounds(), QRect(50, 350, 50, 100)); QCOMPARE(newLayer->alphaChannelDisabled(), false); } } #include "kis_image_animation_interface.h" void KisImageTest::testMergeDownMultipleFrames() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergedown_simple", "imagetest"); QSet initialFrames; { KisLayerSP l = p.layer5; l->enableAnimation(); KisKeyframeChannel *channel = l->getKeyframeChannel(KisKeyframeChannel::Content.id()); channel->addKeyframe(10); channel->addKeyframe(20); channel->addKeyframe(30); QCOMPARE(channel->keyframeCount(), 4); initialFrames = KisLayerUtils::fetchLayerFramesRecursive(l); QCOMPARE(initialFrames.size(), 4); } { QCOMPARE(p.layer5->compositeOpId(), COMPOSITE_OVER); QCOMPARE(p.layer5->alphaChannelDisabled(), true); KisLayerSP newLayer = mergeHelper(p, p.layer5); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer5_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->alphaChannelDisabled(), false); QVERIFY(newLayer->isAnimated()); QSet newFrames = KisLayerUtils::fetchLayerFramesRecursive(newLayer); QCOMPARE(newFrames, initialFrames); foreach (int frame, newFrames) { KisImageAnimationInterface *interface = p.image->animationInterface(); int savedSwitchedTime = 0; interface->saveAndResetCurrentTime(frame, &savedSwitchedTime); QCOMPARE(newLayer->exactBounds(), QRect(100,100,100,100)); interface->restoreCurrentTime(&savedSwitchedTime); } p.undoStore->undo(); p.image->waitForDone(); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); } } template KisNodeSP mergeMultipleHelper(ContainerTest &p, QList selectedNodes, KisNodeSP putAfter) { QSignalSpy spy(p.image.data(), SIGNAL(sigNodeAddedAsync(KisNodeSP))); p.image->mergeMultipleLayers(selectedNodes, putAfter); //KisLayerUtils::mergeMultipleLayers(p.image, selectedNodes, putAfter); p.image->waitForDone(); Q_ASSERT(spy.count() == 1); QList arguments = spy.takeFirst(); KisNodeSP newNode = arguments.first().value(); return newNode; } void KisImageTest::testMergeMultiple() { FlattenTestImage p; TestUtil::ExternalImageChecker img("flatten", "imagetest"); TestUtil::ExternalImageChecker chk("mergemultiple", "imagetest"); { QList selectedNodes; selectedNodes << p.layer2 << p.group1 << p.layer6; { KisNodeSP newLayer = mergeMultipleHelper(p, selectedNodes, 0); //KisNodeSP newLayer = p.image->mergeMultipleLayers(selectedNodes, 0); //p.image->waitForDone(); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer8_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(50, 100, 550, 250)); } } p.p.undoStore->undo(); p.image->waitForDone(); // Test reversed order, the result must be the same { QList selectedNodes; selectedNodes << p.layer6 << p.group1 << p.layer2; { KisNodeSP newLayer = mergeMultipleHelper(p, selectedNodes, 0); //KisNodeSP newLayer = p.image->mergeMultipleLayers(selectedNodes, 0); //p.image->waitForDone(); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer8_layerproj")); QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER); QCOMPARE(newLayer->exactBounds(), QRect(50, 100, 550, 250)); } } } void testMergeCrossColorSpaceImpl(bool useProjectionColorSpace, bool swapSpaces) { QRect refRect; TestUtil::MaskParent p; KisPaintLayerSP layer1; KisPaintLayerSP layer2; KisPaintLayerSP layer3; const KoColorSpace *cs2 = useProjectionColorSpace ? p.image->colorSpace() : KoColorSpaceRegistry::instance()->lab16(); const KoColorSpace *cs3 = KoColorSpaceRegistry::instance()->rgb16(); if (swapSpaces) { qSwap(cs2, cs3); } dbgKrita << "Testing testMergeCrossColorSpaceImpl:"; dbgKrita << " " << ppVar(cs2); dbgKrita << " " << ppVar(cs3); layer1 = p.layer; layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8, cs2); layer3 = new KisPaintLayer(p.image, "paint3", OPACITY_OPAQUE_U8, cs3); QRect rect1(100, 100, 100, 100); QRect rect2(150, 150, 150, 150); QRect rect3(250, 250, 200, 200); layer1->paintDevice()->fill(rect1, KoColor(Qt::red, layer1->colorSpace())); layer2->paintDevice()->fill(rect2, KoColor(Qt::green, layer2->colorSpace())); layer3->paintDevice()->fill(rect3, KoColor(Qt::blue, layer3->colorSpace())); p.image->addNode(layer2); p.image->addNode(layer3); p.image->initialRefreshGraph(); { KisLayerSP newLayer = mergeHelper(p, layer3); QCOMPARE(newLayer->colorSpace(), p.image->colorSpace()); p.undoStore->undo(); p.image->waitForDone(); } { layer2->disableAlphaChannel(true); KisLayerSP newLayer = mergeHelper(p, layer3); QCOMPARE(newLayer->colorSpace(), p.image->colorSpace()); p.undoStore->undo(); p.image->waitForDone(); } } void KisImageTest::testMergeCrossColorSpace() { testMergeCrossColorSpaceImpl(true, false); testMergeCrossColorSpaceImpl(true, true); testMergeCrossColorSpaceImpl(false, false); testMergeCrossColorSpaceImpl(false, true); } void KisImageTest::testMergeSelectionMasks() { QRect refRect; TestUtil::MaskParent p; QRect rect1(100, 100, 100, 100); QRect rect2(150, 150, 150, 150); QRect rect3(50, 50, 100, 100); KisPaintLayerSP layer1 = p.layer; layer1->paintDevice()->fill(rect1, KoColor(Qt::red, layer1->colorSpace())); p.image->initialRefreshGraph(); KisSelectionSP sel = new KisSelection(layer1->paintDevice()->defaultBounds()); sel->pixelSelection()->select(rect2, MAX_SELECTED); KisSelectionMaskSP mask1 = new KisSelectionMask(p.image); mask1->initSelection(sel, layer1); p.image->addNode(mask1, layer1); QVERIFY(!layer1->selection()); mask1->setActive(true); QCOMPARE(layer1->selection()->selectedExactRect(), QRect(150,150,150,150)); sel->pixelSelection()->select(rect3, MAX_SELECTED); KisSelectionMaskSP mask2 = new KisSelectionMask(p.image); mask2->initSelection(sel, layer1); p.image->addNode(mask2, layer1); QCOMPARE(layer1->selection()->selectedExactRect(), QRect(150,150,150,150)); mask2->setActive(true); QCOMPARE(layer1->selection()->selectedExactRect(), QRect(50,50,250,250)); QList selectedNodes; selectedNodes << mask2 << mask1; { KisNodeSP newLayer = mergeMultipleHelper(p, selectedNodes, 0); QCOMPARE(newLayer->parent(), KisNodeSP(layer1)); QCOMPARE((int)layer1->childCount(), 1); QCOMPARE(layer1->selection()->selectedExactRect(), QRect(50,50,250,250)); } } void KisImageTest::testFlattenImage() { FlattenTestImage p; KisImageSP image = p.image; TestUtil::ExternalImageChecker img("flatten", "imagetest"); { KisLayerUtils::flattenImage(p.image); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); p.undoStore->undo(); p.image->waitForDone(); QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial")); } } QTEST_GUILESS_MAIN(KisImageTest) diff --git a/libs/image/tests/kis_layer_test.cpp b/libs/image/tests/kis_layer_test.cpp index 00fca30f65..3b3386c30c 100644 --- a/libs/image/tests/kis_layer_test.cpp +++ b/libs/image/tests/kis_layer_test.cpp @@ -1,315 +1,315 @@ /* * Copyright (c) 2007 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_layer_test.h" #include #include #include #include #include #include #include "kis_paint_device.h" #include "kis_selection.h" #include "kis_filter_mask.h" #include "kis_transparency_mask.h" #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" void KisLayerTest::testCreation() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "layer test"); image->lock(); KisLayerSP layer = new TestLayer(image, "test", OPACITY_OPAQUE_U8); QCOMPARE(layer->name(), QString("test")); QCOMPARE(layer->opacity(), OPACITY_OPAQUE_U8); QCOMPARE(layer->image().data(), image.data()); QCOMPARE(layer->colorSpace(), image->colorSpace()); QCOMPARE(layer->visible(), true); QCOMPARE(layer->userLocked(), false); QCOMPARE(layer->temporary(), false); image->addNode(layer, image->rootLayer()); QBitArray channels(4); channels.fill(true); channels.setBit(1, false); layer->setChannelFlags(channels); QVERIFY(layer->channelFlags().count() == 4); QCOMPARE(layer->channelFlags().at(0), true); QCOMPARE(layer->channelFlags().at(1), false); QCOMPARE(layer->channelFlags().at(2), true); QCOMPARE(layer->channelFlags().at(3), true); layer->setOpacity(OPACITY_TRANSPARENT_U8); QCOMPARE(layer->opacity(), OPACITY_TRANSPARENT_U8); layer->setPercentOpacity(100); QCOMPARE(layer->opacity(), OPACITY_OPAQUE_U8); layer->setPercentOpacity(0); QCOMPARE(layer->opacity(), OPACITY_TRANSPARENT_U8); } void KisLayerTest::testOrdering() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "layer test"); image->lock(); KisLayerSP layer1 = new TestLayer(image, "layer1", OPACITY_OPAQUE_U8); KisLayerSP layer2 = new TestLayer(image, "layer2", OPACITY_OPAQUE_U8); KisLayerSP layer3 = new TestLayer(image, "layer3", OPACITY_OPAQUE_U8); QVERIFY(layer1->name() == "layer1"); QVERIFY(layer2->name() == "layer2"); QVERIFY(layer3->name() == "layer3"); /* +---------+ | layer 2 | | layer 3 | | layer 1 | |root | +---------+ */ QVERIFY(image->addNode(layer1, image->rootLayer())); QVERIFY(image->addNode(layer2, image->rootLayer())); QVERIFY(image->addNode(layer3, image->rootLayer(), layer1)); QCOMPARE((int) image->nlayers(), 4); QVERIFY(layer1->parent() == image->root()); QVERIFY(layer2->parent() == image->root()); QVERIFY(layer3->parent() == image->root()); QVERIFY(image->rootLayer()->firstChild() == layer1.data()); QVERIFY(image->rootLayer()->lastChild() == layer2.data()); QVERIFY(image->rootLayer()->at(0) == layer1.data()); QVERIFY(image->rootLayer()->at(1) == layer3.data()); QVERIFY(image->rootLayer()->at(2) == layer2.data()); QVERIFY(image->rootLayer()->index(layer1) == 0); QVERIFY(image->rootLayer()->index(layer3) == 1); QVERIFY(image->rootLayer()->index(layer2) == 2); QVERIFY(layer3->prevSibling() == layer1.data()); QVERIFY(layer2->prevSibling() == layer3.data()); QVERIFY(layer1->prevSibling() == 0); QVERIFY(layer3->nextSibling() == layer2.data()); QVERIFY(layer2->nextSibling() == 0); QVERIFY(layer1->nextSibling() == layer3.data()); /* +---------+ | layer 3 | | layer 2 | | layer 1 | |root | +---------+ */ QVERIFY(image->moveNode(layer2, image->rootLayer(), layer1)); QVERIFY(image->rootLayer()->at(0) == layer1.data()); QVERIFY(image->rootLayer()->at(1) == layer2.data()); QVERIFY(image->rootLayer()->at(2) == layer3.data()); QVERIFY(image->rootLayer()->firstChild() == layer1.data()); QVERIFY(image->rootLayer()->lastChild() == layer3.data()); QVERIFY(image->rootLayer()->index(layer1) == 0); QVERIFY(image->rootLayer()->index(layer2) == 1); QVERIFY(image->rootLayer()->index(layer3) == 2); QVERIFY(layer3->prevSibling() == layer2.data()); QVERIFY(layer2->prevSibling() == layer1.data()); QVERIFY(layer1->prevSibling() == 0); QVERIFY(layer3->nextSibling() == 0); QVERIFY(layer2->nextSibling() == layer3.data()); QVERIFY(layer1->nextSibling() == layer2.data()); } void KisLayerTest::testMoveNode() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "layer test"); image->lock(); KisLayerSP node1 = new TestLayer(image, "layer1", OPACITY_OPAQUE_U8); KisLayerSP node2 = new TestLayer(image, "layer2", OPACITY_OPAQUE_U8); KisLayerSP node3 = new TestLayer(image, "layer3", OPACITY_OPAQUE_U8); node1->setName("node1"); node2->setName("node2"); node3->setName("node3"); QVERIFY(image->addNode(node1)); QVERIFY(image->addNode(node2)); QVERIFY(image->addNode(node3)); QVERIFY(image->root()->at(0) == node1.data()); QVERIFY(image->root()->at(1) == node2.data()); QVERIFY(image->root()->at(2) == node3.data()); QVERIFY(image->moveNode(node3, image->root(), node1)); QVERIFY(image->root()->at(0) == node1.data()); QVERIFY(image->root()->at(1) == node3.data()); QVERIFY(image->root()->at(2) == node2.data()); } void KisLayerTest::testMoveLayer() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "layer test"); image->lock(); KisLayerSP node1 = new TestLayer(image, "layer1", OPACITY_OPAQUE_U8); KisLayerSP node2 = new TestLayer(image, "layer2", OPACITY_OPAQUE_U8); KisLayerSP node3 = new TestLayer(image, "layer3", OPACITY_OPAQUE_U8); node1->setName("node1"); node2->setName("node2"); node3->setName("node3"); QVERIFY(image->addNode(node1)); QVERIFY(image->addNode(node2)); QVERIFY(image->addNode(node3)); QVERIFY(image->root()->at(0) == node1.data()); QVERIFY(image->root()->at(1) == node2.data()); QVERIFY(image->root()->at(2) == node3.data()); QVERIFY(image->moveNode(node3, image->rootLayer(), node1)); QVERIFY(image->root()->at(0) == node1.data()); QVERIFY(image->root()->at(1) == node3.data()); QVERIFY(image->root()->at(2) == node2.data()); } /* +----------+ |root | | paint 1 | | fmask2 | | fmask1 | +----------+ */ void KisLayerTest::testMasksChangeRect() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); KisFilterMaskSP filterMask1 = new KisFilterMask(); KisFilterMaskSP filterMask2 = new KisFilterMask(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration1 = filter->defaultConfiguration(0); - KisFilterConfiguration *configuration2 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration1 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration2 = filter->defaultConfiguration(0); filterMask1->setFilter(configuration1); filterMask2->setFilter(configuration2); image->addNode(filterMask1, paintLayer1); image->addNode(filterMask2, paintLayer1); QVERIFY(paintLayer1->hasEffectMasks()); QRect testRect(10, 10, 100, 100); QRect resultRect; resultRect = paintLayer1->changeRect(testRect, KisNode::N_FILTHY); QVERIFY2(resultRect == QRect(0, 0, 120, 120), "KisNode::N_FILTHY node should take masks into account"); resultRect = paintLayer1->changeRect(testRect, KisNode::N_ABOVE_FILTHY); QVERIFY2(resultRect == testRect, "KisNode::N_ABOVE_FILTHY node should NOT take " "masks into account"); /** * KisNode::N_BELOW_FILTHY, KisNode::N_FILTHY_PROJECTION * should not be use by the caller, because the walker * shoult not visit these node on a forward way. * So the behavoiur here is undefined. * * resultRect = paintLayer1->changeRect(testRect, KisNode::N_BELOW_FILTHY); * resultRect = paintLayer1->changeRect(testRect, KisNode::N_FILTHY_PROJECTION); */ } void KisLayerTest::testMoveLayerWithMaskThreaded() { /** * This test ensures that the layer's original() can be moved * while its projection is still being updated */ const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 2000, 2000, colorSpace, "walker test"); KisLayerSP paintLayer = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); image->addNode(paintLayer, image->rootLayer()); paintLayer->paintDevice()->fill(image->bounds(), KoColor(Qt::black, colorSpace)); KisTransparencyMaskSP transpMask = new KisTransparencyMask(); transpMask->initSelection(paintLayer); image->addNode(transpMask, paintLayer); for(int i = 0; i < 100; i++) { paintLayer->setDirty(); QTest::qSleep(1 + (qrand() & 63)); paintLayer->setX((i*67) % 1873); paintLayer->setY((i*23) % 1873); } } QTEST_MAIN(KisLayerTest) diff --git a/libs/image/tests/kis_properties_configuration_test.cpp b/libs/image/tests/kis_properties_configuration_test.cpp index 7776e79c91..d6bf267045 100644 --- a/libs/image/tests/kis_properties_configuration_test.cpp +++ b/libs/image/tests/kis_properties_configuration_test.cpp @@ -1,99 +1,96 @@ /* * 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. */ #include "kis_properties_configuration_test.h" #include #include "kis_properties_configuration.h" KisPropertiesConfigurationTest::KisPropertiesConfigurationTest() : v1(10), v2("hello"), v3(1242.0), v4(true) { QList pts; pts.push_back(QPointF(0.2, 0.3)); pts.push_back(QPointF(0.5, 0.7)); v5.setPoints(pts); } void KisPropertiesConfigurationTest::testSerialization() { - KisPropertiesConfiguration* config = createConfig(); + KisPropertiesConfigurationSP config = createConfig(); QString xml = config->toXML(); - KisPropertiesConfiguration* decodedConfig = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP decodedConfig = new KisPropertiesConfiguration(); decodedConfig->fromXML(xml); testConfig(decodedConfig); - delete config; - delete decodedConfig; + } void KisPropertiesConfigurationTest::testSetGet() { - KisPropertiesConfiguration* config = createConfig(); + KisPropertiesConfigurationSP config = createConfig(); testConfig(config); - delete config; } void KisPropertiesConfigurationTest::testDefaultValues() { - KisPropertiesConfiguration* config = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP config = new KisPropertiesConfiguration(); QVERIFY(config->getInt("bouh", v1) == v1); QVERIFY(config->getString("bouh", v2) == v2); QVERIFY(config->getDouble("bouh", v3) == v3); QVERIFY(config->getBool("bouh", v4) == v4); QVERIFY(config->getCubicCurve("bouh", v5) == v5); - delete config; } -KisPropertiesConfiguration* KisPropertiesConfigurationTest::createConfig() +KisPropertiesConfigurationSP KisPropertiesConfigurationTest::createConfig() { - KisPropertiesConfiguration* config = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP config = new KisPropertiesConfiguration(); config->setProperty("v1", v1); config->setProperty("v2", v2); config->setProperty("v3", v3); config->setProperty("v4", v4); config->setProperty("v5", qVariantFromValue(v5)); return config; } -void KisPropertiesConfigurationTest::testConfig(KisPropertiesConfiguration* config) +void KisPropertiesConfigurationTest::testConfig(KisPropertiesConfigurationSP config) { QVERIFY(config->getInt("v1", 0) == v1); QVERIFY(config->getString("v2", "") == v2); QVERIFY(config->getDouble("v3", 0.0) == v3); QVERIFY(config->getBool("v4", !v4) == v4); QVERIFY(config->getCubicCurve("v5") == v5); } void KisPropertiesConfigurationTest::testNotSavedValues() { - KisPropertiesConfiguration* config = createConfig(); + KisPropertiesConfigurationSP config = createConfig(); config->setPropertyNotSaved("v3"); testConfig(config); QString s = config->toXML(); - delete config; + config = new KisPropertiesConfiguration(); config->fromXML(s); QVERIFY(config->getInt("v1", 0) == v1); QVERIFY(config->getString("v2", "") == v2); QVERIFY(config->hasProperty("v3") == false); QVERIFY(config->getBool("v4", !v4) == v4); QVERIFY(config->getCubicCurve("v5") == v5); - delete config; + } QTEST_MAIN(KisPropertiesConfigurationTest) diff --git a/libs/image/tests/kis_properties_configuration_test.h b/libs/image/tests/kis_properties_configuration_test.h index 95a04aff76..c9b26d4551 100644 --- a/libs/image/tests/kis_properties_configuration_test.h +++ b/libs/image/tests/kis_properties_configuration_test.h @@ -1,50 +1,49 @@ /* * 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_SERIALIZABLE_CONFIGURATION_TEST_H #define KIS_SERIALIZABLE_CONFIGURATION_TEST_H #include #include "kis_cubic_curve.h" - -class KisPropertiesConfiguration; +#include "kis_properties_configuration.h" class KisPropertiesConfigurationTest : public QObject { Q_OBJECT public: KisPropertiesConfigurationTest(); private Q_SLOTS: void testSetGet(); void testSerialization(); void testDefaultValues(); void testNotSavedValues(); private: - KisPropertiesConfiguration* createConfig(); - void testConfig(KisPropertiesConfiguration* config); + KisPropertiesConfigurationSP createConfig(); + void testConfig(KisPropertiesConfigurationSP config); private: int v1; QString v2; double v3; bool v4; KisCubicCurve v5; }; #endif diff --git a/libs/image/tests/kis_recorded_filter_action_test.cpp b/libs/image/tests/kis_recorded_filter_action_test.cpp index f40e728f31..86675031db 100644 --- a/libs/image/tests/kis_recorded_filter_action_test.cpp +++ b/libs/image/tests/kis_recorded_filter_action_test.cpp @@ -1,45 +1,45 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_recorded_filter_action_test.h" #include #include "recorder/kis_recorded_filter_action.h" #include #include #include "kis_paint_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_image.h" #include "kis_paint_device.h" #include void KisRecordedFilterActionTest::testCreation() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); KisImageSP image = new KisImage(0, 10, 10, cs, "merge test"); KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); KisRecordedFilterAction test("invert", KisNodeQueryPath::absolutePath(layer), f, kfc); } QTEST_MAIN(KisRecordedFilterActionTest) diff --git a/libs/image/tests/kis_simple_update_queue_test.cpp b/libs/image/tests/kis_simple_update_queue_test.cpp index 803c8d1f06..9024f60a92 100644 --- a/libs/image/tests/kis_simple_update_queue_test.cpp +++ b/libs/image/tests/kis_simple_update_queue_test.cpp @@ -1,281 +1,281 @@ /* * Copyright (c) 2010 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_simple_update_queue_test.h" #include #include #include #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "kis_adjustment_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_update_job_item.h" #include "kis_simple_update_queue.h" #include "scheduler_utils.h" #include "lod_override.h" void KisSimpleUpdateQueueTest::testJobProcessing() { KisTestableUpdaterContext context(2); QRect imageRect(0,0,200,200); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "merge test"); KisPaintLayerSP paintLayer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); image->lock(); image->addNode(paintLayer); image->unlock(); QRect dirtyRect1(0,0,50,100); QRect dirtyRect2(0,0,100,100); QRect dirtyRect3(50,0,50,100); QRect dirtyRect4(150,150,50,50); QRect dirtyRect5(dirtyRect4); // theoretically, should be merged with 4 QVector jobs; KisWalkersList walkersList; /** * Process the queue and look what has been added into * the updater context */ KisTestableSimpleUpdateQueue queue; queue.addUpdateJob(paintLayer, dirtyRect1, imageRect, 0); queue.addUpdateJob(paintLayer, dirtyRect2, imageRect, 0); queue.addUpdateJob(paintLayer, dirtyRect3, imageRect, 0); queue.addUpdateJob(paintLayer, dirtyRect4, imageRect, 0); { TestUtil::LodOverride l(1, image); queue.addUpdateJob(paintLayer, dirtyRect5, imageRect, 1); } queue.processQueue(context); jobs = context.getJobs(); QVERIFY(checkWalker(jobs[0]->walker(), dirtyRect2)); QVERIFY(checkWalker(jobs[1]->walker(), dirtyRect4)); QCOMPARE(jobs.size(), 2); QCOMPARE(context.currentLevelOfDetail(), 0); walkersList = queue.getWalkersList(); QCOMPARE(walkersList.size(), 1); QVERIFY(checkWalker(walkersList[0], dirtyRect5, 1)); } void KisSimpleUpdateQueueTest::testSplitUpdate() { testSplit(false); } void KisSimpleUpdateQueueTest::testSplitFullRefresh() { testSplit(true); } void KisSimpleUpdateQueueTest::testSplit(bool useFullRefresh) { QRect imageRect(0,0,1024,1024); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "merge test"); KisPaintLayerSP paintLayer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); image->lock(); image->addNode(paintLayer); image->unlock(); QRect dirtyRect1(0,0,1000,1000); KisTestableSimpleUpdateQueue queue; KisWalkersList& walkersList = queue.getWalkersList(); if(!useFullRefresh) { queue.addUpdateJob(paintLayer, dirtyRect1, imageRect, 0); } else { queue.addFullRefreshJob(paintLayer, dirtyRect1, imageRect, 0); } QCOMPARE(walkersList.size(), 4); QVERIFY(checkWalker(walkersList[0], QRect(0,0,512,512))); QVERIFY(checkWalker(walkersList[1], QRect(512,0,488,512))); QVERIFY(checkWalker(walkersList[2], QRect(0,512,512,488))); QVERIFY(checkWalker(walkersList[3], QRect(512,512,488,488))); queue.optimize(); //must change nothing QCOMPARE(walkersList.size(), 4); QVERIFY(checkWalker(walkersList[0], QRect(0,0,512,512))); QVERIFY(checkWalker(walkersList[1], QRect(512,0,488,512))); QVERIFY(checkWalker(walkersList[2], QRect(0,512,512,488))); QVERIFY(checkWalker(walkersList[3], QRect(512,512,488,488))); } void KisSimpleUpdateQueueTest::testChecksum() { QRect imageRect(0,0,512,512); QRect dirtyRect(100,100,100,100); const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), colorSpace, "test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisAdjustmentLayerSP adjustmentLayer = new KisAdjustmentLayer(image, "adj", 0, 0); image->lock(); image->addNode(paintLayer1, image->rootLayer()); image->addNode(adjustmentLayer, image->rootLayer()); image->unlock(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); KisTestableSimpleUpdateQueue queue; KisWalkersList& walkersList = queue.getWalkersList(); { TestUtil::LodOverride l(1, image); queue.addUpdateJob(adjustmentLayer, dirtyRect, imageRect, 1); QCOMPARE(walkersList[0]->checksumValid(), true); QCOMPARE(walkersList[0]->levelOfDetail(), 1); } adjustmentLayer->setFilter(configuration); { TestUtil::LodOverride l(1, image); QCOMPARE(walkersList[0]->checksumValid(), false); } QVector jobs; KisTestableUpdaterContext context(2); { TestUtil::LodOverride l(1, image); queue.processQueue(context); } jobs = context.getJobs(); { TestUtil::LodOverride l(1, image); QCOMPARE(jobs[0]->walker()->checksumValid(), true); } } void KisSimpleUpdateQueueTest::testMixingTypes() { QRect imageRect(0,0,1024,1024); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "merge test"); KisPaintLayerSP paintLayer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); image->lock(); image->addNode(paintLayer); image->unlock(); QRect dirtyRect1(0,0,200,200); QRect dirtyRect2(0,0,200,200); QRect dirtyRect3(20,20,200,200); KisTestableSimpleUpdateQueue queue; KisWalkersList& walkersList = queue.getWalkersList(); queue.addUpdateJob(paintLayer, dirtyRect1, imageRect, 0); queue.addFullRefreshJob(paintLayer, dirtyRect2, imageRect, 0); queue.addFullRefreshJob(paintLayer, dirtyRect3, imageRect, 0); queue.addUpdateNoFilthyJob(paintLayer, dirtyRect1, imageRect, 0); QCOMPARE(walkersList.size(), 3); QVERIFY(checkWalker(walkersList[0], QRect(0,0,200,200))); QVERIFY(checkWalker(walkersList[1], QRect(0,0,220,220))); QVERIFY(checkWalker(walkersList[2], QRect(0,0,200,200))); QCOMPARE(walkersList[0]->type(), KisBaseRectsWalker::UPDATE); QCOMPARE(walkersList[1]->type(), KisBaseRectsWalker::FULL_REFRESH); QCOMPARE(walkersList[2]->type(), KisBaseRectsWalker::UPDATE_NO_FILTHY); } void KisSimpleUpdateQueueTest::testSpontaneousJobsCompression() { KisTestableSimpleUpdateQueue queue; KisSpontaneousJobsList &jobsList = queue.getSpontaneousJobsList(); QVERIFY(queue.isEmpty()); QCOMPARE(queue.sizeMetric(), 0); QVERIFY(jobsList.isEmpty()); KisSpontaneousJob *job1 = new KisNoopSpontaneousJob(false); KisSpontaneousJob *job2 = new KisNoopSpontaneousJob(false); KisSpontaneousJob *job3 = new KisNoopSpontaneousJob(true); queue.addSpontaneousJob(job1); QVERIFY(!queue.isEmpty()); QCOMPARE(queue.sizeMetric(), 1); QCOMPARE(jobsList.size(), 1); QCOMPARE(jobsList[0], job1); queue.addSpontaneousJob(job2); QVERIFY(!queue.isEmpty()); QCOMPARE(queue.sizeMetric(), 2); QCOMPARE(jobsList.size(), 2); QCOMPARE(jobsList[0], job1); QCOMPARE(jobsList[1], job2); queue.addSpontaneousJob(job3); QVERIFY(!queue.isEmpty()); QCOMPARE(queue.sizeMetric(), 1); QCOMPARE(jobsList.size(), 1); QCOMPARE(jobsList[0], job3); } QTEST_MAIN(KisSimpleUpdateQueueTest) diff --git a/libs/image/tests/kis_update_scheduler_test.cpp b/libs/image/tests/kis_update_scheduler_test.cpp index e07ae3c3a6..b7ce10daab 100644 --- a/libs/image/tests/kis_update_scheduler_test.cpp +++ b/libs/image/tests/kis_update_scheduler_test.cpp @@ -1,432 +1,432 @@ /* * Copyright (c) 2010 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_update_scheduler_test.h" #include #include #include #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "kis_adjustment_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "scheduler_utils.h" #include "kis_update_scheduler.h" #include "kis_updater_context.h" #include "kis_update_job_item.h" #include "kis_simple_update_queue.h" #include "../../sdk/tests/testutil.h" KisImageSP KisUpdateSchedulerTest::buildTestingImage() { QImage sourceImage1(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage sourceImage2(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); QRect imageRect = QRect(QPoint(0,0), sourceImage1.size()); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "merge test"); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8 / 3); KisLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0); paintLayer1->paintDevice()->convertFromQImage(sourceImage1, 0, 0, 0); paintLayer2->paintDevice()->convertFromQImage(sourceImage2, 0, 0, 0); image->lock(); image->addNode(paintLayer1); image->addNode(paintLayer2); image->addNode(blur1); image->unlock(); return image; } void KisUpdateSchedulerTest::testMerge() { KisImageSP image = buildTestingImage(); QRect imageRect = image->bounds(); KisNodeSP rootLayer = image->rootLayer(); KisNodeSP paintLayer1 = rootLayer->firstChild(); QCOMPARE(paintLayer1->name(), QString("paint1")); KisUpdateScheduler scheduler(image.data()); /** * Test synchronous Full Refresh */ scheduler.fullRefresh(rootLayer, image->bounds(), image->bounds()); QCOMPARE(rootLayer->exactBounds(), image->bounds()); QImage resultFRProjection = rootLayer->projection()->convertToQImage(0); resultFRProjection.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + "scheduler_fr_merge_result.png"); /** * Test incremental updates */ rootLayer->projection()->clear(); const qint32 num = 4; qint32 width = imageRect.width() / num; qint32 lastWidth = imageRect.width() - width; QVector dirtyRects(num); for(qint32 i = 0; i < num-1; i++) { dirtyRects[i] = QRect(width*i, 0, width, imageRect.height()); } dirtyRects[num-1] = QRect(width*(num-1), 0, lastWidth, imageRect.height()); for(qint32 i = 0; i < num; i+=2) { scheduler.updateProjection(paintLayer1, dirtyRects[i], image->bounds()); } for(qint32 i = 1; i < num; i+=2) { scheduler.updateProjection(paintLayer1, dirtyRects[i], image->bounds()); } scheduler.waitForDone(); QCOMPARE(rootLayer->exactBounds(), image->bounds()); QImage resultDirtyProjection = rootLayer->projection()->convertToQImage(0); resultDirtyProjection.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + "scheduler_dp_merge_result.png"); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, resultFRProjection, resultDirtyProjection)); } void KisUpdateSchedulerTest::benchmarkOverlappedMerge() { KisImageSP image = buildTestingImage(); KisNodeSP rootLayer = image->rootLayer(); KisNodeSP paintLayer1 = rootLayer->firstChild(); QRect imageRect = image->bounds(); QCOMPARE(paintLayer1->name(), QString("paint1")); QCOMPARE(imageRect, QRect(0,0,640,441)); KisUpdateScheduler scheduler(image.data()); const qint32 xShift = 10; const qint32 yShift = 0; const qint32 numShifts = 64; QBENCHMARK{ QRect dirtyRect(0, 0, 200, imageRect.height()); for(int i = 0; i < numShifts; i++) { // dbgKrita << dirtyRect; scheduler.updateProjection(paintLayer1, dirtyRect, image->bounds()); dirtyRect.translate(xShift, yShift); } scheduler.waitForDone(); } } void KisUpdateSchedulerTest::testLocking() { KisImageSP image = buildTestingImage(); KisNodeSP rootLayer = image->rootLayer(); KisNodeSP paintLayer1 = rootLayer->firstChild(); QRect imageRect = image->bounds(); QCOMPARE(paintLayer1->name(), QString("paint1")); QCOMPARE(imageRect, QRect(0,0,640,441)); KisTestableUpdateScheduler scheduler(image.data(), 2); QRect dirtyRect1(0,0,50,100); QRect dirtyRect2(0,0,100,100); QRect dirtyRect3(50,0,50,100); QRect dirtyRect4(150,150,50,50); KisTestableUpdaterContext *context = scheduler.updaterContext(); QVector jobs; scheduler.updateProjection(paintLayer1, imageRect, imageRect); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); QVERIFY(checkWalker(jobs[0]->walker(), imageRect)); context->clear(); scheduler.lock(); scheduler.updateProjection(paintLayer1, dirtyRect1, imageRect); scheduler.updateProjection(paintLayer1, dirtyRect2, imageRect); scheduler.updateProjection(paintLayer1, dirtyRect3, imageRect); scheduler.updateProjection(paintLayer1, dirtyRect4, imageRect); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), false); QCOMPARE(jobs[1]->isRunning(), false); scheduler.unlock(); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), true); QVERIFY(checkWalker(jobs[0]->walker(), dirtyRect2)); QVERIFY(checkWalker(jobs[1]->walker(), dirtyRect4)); } void KisUpdateSchedulerTest::testExclusiveStrokes() { KisImageSP image = buildTestingImage(); KisNodeSP rootLayer = image->rootLayer(); KisNodeSP paintLayer1 = rootLayer->firstChild(); QRect imageRect = image->bounds(); QCOMPARE(paintLayer1->name(), QString("paint1")); QCOMPARE(imageRect, QRect(0,0,640,441)); QRect dirtyRect1(0,0,50,100); KisTestableUpdateScheduler scheduler(image.data(), 2); KisTestableUpdaterContext *context = scheduler.updaterContext(); QVector jobs; scheduler.updateProjection(paintLayer1, dirtyRect1, imageRect); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); QVERIFY(checkWalker(jobs[0]->walker(), dirtyRect1)); KisStrokeId id = scheduler.startStroke(new KisTestingStrokeStrategy("excl_", true, false)); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); QVERIFY(checkWalker(jobs[0]->walker(), dirtyRect1)); context->clear(); scheduler.endStroke(id); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); COMPARE_NAME(jobs[0], "excl_init"); scheduler.updateProjection(paintLayer1, dirtyRect1, imageRect); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); COMPARE_NAME(jobs[0], "excl_init"); context->clear(); scheduler.processQueues(); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); COMPARE_NAME(jobs[0], "excl_finish"); context->clear(); scheduler.processQueues(); jobs = context->getJobs(); QCOMPARE(jobs[0]->isRunning(), true); QCOMPARE(jobs[1]->isRunning(), false); QVERIFY(checkWalker(jobs[0]->walker(), dirtyRect1)); } void KisUpdateSchedulerTest::testEmptyStroke() { KisImageSP image = buildTestingImage(); KisStrokeId id = image->startStroke(new KisStrokeStrategy()); image->addJob(id, 0); image->endStroke(id); image->waitForDone(); } #include "kis_lazy_wait_condition.h" void KisUpdateSchedulerTest::testLazyWaitCondition() { { dbgKrita << "Not initialized"; KisLazyWaitCondition condition; QVERIFY(!condition.wait(50)); } { dbgKrita << "Initialized, not awake"; KisLazyWaitCondition condition; condition.initWaiting(); QVERIFY(!condition.wait(50)); condition.endWaiting(); } { dbgKrita << "Initialized, awake"; KisLazyWaitCondition condition; condition.initWaiting(); condition.wakeAll(); QVERIFY(condition.wait(50)); condition.endWaiting(); } { dbgKrita << "Initialized, not awake, then awake"; KisLazyWaitCondition condition; condition.initWaiting(); QVERIFY(!condition.wait(50)); condition.wakeAll(); QVERIFY(condition.wait(50)); condition.endWaiting(); } { dbgKrita << "Doublewait"; KisLazyWaitCondition condition; condition.initWaiting(); condition.initWaiting(); QVERIFY(!condition.wait(50)); condition.wakeAll(); QVERIFY(condition.wait(50)); QVERIFY(condition.wait(50)); condition.endWaiting(); } } #define NUM_THREADS 10 #define NUM_CYCLES 500 #define NTH_CHECK 3 class UpdatesBlockTester : public QRunnable { public: UpdatesBlockTester(KisUpdateScheduler *scheduler, KisNodeSP node) : m_scheduler(scheduler), m_node(node) { } void run() { for (int i = 0; i < NUM_CYCLES; i++) { if(i % NTH_CHECK == 0) { m_scheduler->blockUpdates(); QTest::qSleep(1); // a bit of salt for crashiness ;) Q_ASSERT(!m_scheduler->haveUpdatesRunning()); m_scheduler->unblockUpdates(); } else { QRect updateRect(0,0,100,100); updateRect.moveTopLeft(QPoint((i%10)*100, (i%10)*100)); m_scheduler->updateProjection(m_node, updateRect, QRect(0,0,1100,1100)); } } } private: KisUpdateScheduler *m_scheduler; KisNodeSP m_node; }; void KisUpdateSchedulerTest::testBlockUpdates() { KisImageSP image = buildTestingImage(); KisNodeSP rootLayer = image->rootLayer(); KisNodeSP paintLayer1 = rootLayer->firstChild(); KisUpdateScheduler scheduler(image.data()); QThreadPool threadPool; threadPool.setMaxThreadCount(NUM_THREADS); for(int i = 0; i< NUM_THREADS; i++) { UpdatesBlockTester *tester = new UpdatesBlockTester(&scheduler, paintLayer1); threadPool.start(tester); } threadPool.waitForDone(); } #include "kis_update_time_monitor.h" void KisUpdateSchedulerTest::testTimeMonitor() { QVector dirtyRects; KisUpdateTimeMonitor::instance()->startStrokeMeasure(); KisUpdateTimeMonitor::instance()->reportMouseMove(QPointF(100, 0)); KisUpdateTimeMonitor::instance()->reportJobStarted((void*) 10); QTest::qSleep(300); KisUpdateTimeMonitor::instance()->reportJobStarted((void*) 20); QTest::qSleep(100); dirtyRects << QRect(10,10,10,10); KisUpdateTimeMonitor::instance()->reportJobFinished((void*) 10, dirtyRects); QTest::qSleep(100); dirtyRects.clear(); dirtyRects << QRect(30,30,10,10); KisUpdateTimeMonitor::instance()->reportJobFinished((void*) 20, dirtyRects); QTest::qSleep(500); KisUpdateTimeMonitor::instance()->reportUpdateFinished(QRect(10,10,10,10)); QTest::qSleep(300); KisUpdateTimeMonitor::instance()->reportUpdateFinished(QRect(30,30,10,10)); KisUpdateTimeMonitor::instance()->reportMouseMove(QPointF(130, 0)); KisUpdateTimeMonitor::instance()->endStrokeMeasure(); } void KisUpdateSchedulerTest::testLodSync() { KisImageSP image = buildTestingImage(); KisNodeSP rootLayer = image->root(); KisNodeSP paintLayer1 = rootLayer->firstChild(); QCOMPARE(paintLayer1->name(), QString("paint1")); image->setLevelOfDetailBlocked(false); image->setDesiredLevelOfDetail(2); image->explicitRegenerateLevelOfDetail(); image->waitForDone(); } QTEST_MAIN(KisUpdateSchedulerTest) diff --git a/libs/image/tests/kis_walkers_test.cpp b/libs/image/tests/kis_walkers_test.cpp index 02557fe4e5..9181e48eb8 100644 --- a/libs/image/tests/kis_walkers_test.cpp +++ b/libs/image/tests/kis_walkers_test.cpp @@ -1,1226 +1,1226 @@ /* * 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. */ #include "kis_walkers_test.h" #include "kis_base_rects_walker.h" #include "kis_refresh_subtree_walker.h" #include "kis_full_refresh_walker.h" #include #include #include #include "kis_paint_layer.h" #include "kis_group_layer.h" #include "kis_clone_layer.h" #include "kis_adjustment_layer.h" #include "kis_selection.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_filter_mask.h" #include "kis_transparency_mask.h" #define DEBUG_VISITORS QString nodeTypeString(KisMergeWalker::NodePosition position); QString nodeTypePostfix(KisMergeWalker::NodePosition position); /************** Test Implementation Of A Walker *********************/ class KisTestWalker : public KisMergeWalker { public: KisTestWalker() :KisMergeWalker(QRect()) { } QStringList popResult() { QStringList order(m_order); m_order.clear(); return order; } using KisMergeWalker::startTrip; protected: void registerChangeRect(KisProjectionLeafSP node, NodePosition position) { QString postfix; if(!node->isLayer()) { postfix = "[skipped as not-a-layer]"; } #ifdef DEBUG_VISITORS dbgKrita<< "FW:"<< node->node()->name() <<'\t'<< nodeTypeString(position) << postfix; #endif if(postfix.isEmpty()) { m_order.append(node->node()->name()); } } void registerNeedRect(KisProjectionLeafSP node, NodePosition position) { QString postfix; if(!node->isLayer()) { postfix = "[skipped as not-a-layer]"; } #ifdef DEBUG_VISITORS dbgKrita<< "BW:"<< node->node()->name() <<'\t'<< nodeTypeString(position) << postfix; #endif if(postfix.isEmpty()) { m_order.append(node->node()->name() + nodeTypePostfix(position)); } } protected: QStringList m_order; }; /************** Debug And Verify Code *******************************/ struct UpdateTestJob { QString updateAreaName; KisNodeSP startNode; QRect updateRect; QString referenceString; QRect accessRect; bool changeRectVaries; bool needRectVaries; }; void reportStartWith(QString nodeName, QRect rect = QRect()) { dbgKrita; if(!rect.isEmpty()) dbgKrita << "Start with:" << nodeName << rect; else dbgKrita << "Start with:" << nodeName; } QString nodeTypeString(KisMergeWalker::NodePosition position) { QString string; if(position & KisMergeWalker::N_TOPMOST) string="TOP"; else if(position & KisMergeWalker::N_BOTTOMMOST) string="BOT"; else string="NOR"; if(position & KisMergeWalker::N_ABOVE_FILTHY) string+="_ABOVE "; else if(position & KisMergeWalker::N_FILTHY) string+="_FILTH*"; else if(position & KisMergeWalker::N_FILTHY_PROJECTION) string+="_PROJE*"; else if(position & KisMergeWalker::N_FILTHY_ORIGINAL) string+="_ORIGI*_WARNINIG!!!: NOT USED"; else if(position & KisMergeWalker::N_BELOW_FILTHY) string+="_BELOW "; else if(position & KisMergeWalker::N_EXTRA) string+="_EXTRA*"; else qFatal("Impossible happened"); return string; } QString nodeTypePostfix(KisMergeWalker::NodePosition position) { QString string('_'); if(position & KisMergeWalker::N_TOPMOST) string += 'T'; else if(position & KisMergeWalker::N_BOTTOMMOST) string += 'B'; else string += 'N'; if(position & KisMergeWalker::N_ABOVE_FILTHY) string += 'A'; else if(position & KisMergeWalker::N_FILTHY) string += 'F'; else if(position & KisMergeWalker::N_FILTHY_PROJECTION) string += 'P'; else if(position & KisMergeWalker::N_FILTHY_ORIGINAL) string += 'O'; else if(position & KisMergeWalker::N_BELOW_FILTHY) string += 'B'; else if(position & KisMergeWalker::N_EXTRA) string += 'E'; else qFatal("Impossible happened"); return string; } void KisWalkersTest::verifyResult(KisBaseRectsWalker &walker, struct UpdateTestJob &job) { QStringList list; if(!job.referenceString.isEmpty()) { list = job.referenceString.split(','); } verifyResult(walker, list, job.accessRect, job.changeRectVaries, job.needRectVaries); } void KisWalkersTest::verifyResult(KisBaseRectsWalker &walker, QStringList reference, QRect accessRect, bool changeRectVaries, bool needRectVaries) { KisMergeWalker::LeafStack &list = walker.leafStack(); QStringList::const_iterator iter = reference.constBegin(); if(reference.size() != list.size()) { dbgKrita << "*** Seems like the walker returned stack of wrong size" << "( ref:" << reference.size() << "act:" << list.size() << ")"; dbgKrita << "*** We are going to crash soon... just wait..."; } Q_FOREACH (const KisMergeWalker::JobItem &item, list) { #ifdef DEBUG_VISITORS dbgKrita << item.m_leaf->node()->name() << '\t' << item.m_applyRect << '\t' << nodeTypeString(item.m_position); #endif QCOMPARE(item.m_leaf->node()->name(), *iter); iter++; } #ifdef DEBUG_VISITORS dbgKrita << "Result AR:\t" << walker.accessRect(); #endif QCOMPARE(walker.accessRect(), accessRect); QCOMPARE(walker.changeRectVaries(), changeRectVaries); QCOMPARE(walker.needRectVaries(), needRectVaries); } /************** Actual Testing **************************************/ /* +----------+ |root | | layer 5 | | group | | paint 4 | | paint 3 | | adj | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testUsualVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP adjustmentLayer = new KisAdjustmentLayer(image, "adj", 0, 0); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(adjustmentLayer, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); KisTestWalker walker; { QString order("paint3,paint4,group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB," "paint4_TA,paint3_NF,adj_NB,paint2_BB"); QStringList orderList = order.split(','); reportStartWith("paint3"); walker.startTrip(paintLayer3->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } { QString order("adj,paint3,paint4,group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB," "paint4_TA,paint3_NA,adj_NF,paint2_BB"); QStringList orderList = order.split(','); reportStartWith("adj"); walker.startTrip(adjustmentLayer->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } { QString order("group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB"); QStringList orderList = order.split(','); reportStartWith("group"); walker.startTrip(groupLayer->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } } /* +----------+ |root | | layer 5 | | group | | mask 1 | | paint 4 | | paint 3 | | adj | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testVisitingWithTopmostMask() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP adjustmentLayer = new KisAdjustmentLayer(image, "adj", 0, 0); KisFilterMaskSP filterMask1 = new KisFilterMask(); filterMask1->initSelection(groupLayer); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration1 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration1 = filter->defaultConfiguration(0); filterMask1->setFilter(configuration1); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(adjustmentLayer, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); // nasty mask! image->addNode(filterMask1, groupLayer); /** * The results must be the same as for testUsualVisiting */ KisTestWalker walker; { QString order("paint3,paint4,group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB," "paint4_TA,paint3_NF,adj_NB,paint2_BB"); QStringList orderList = order.split(','); reportStartWith("paint3"); walker.startTrip(paintLayer3->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } { QString order("adj,paint3,paint4,group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB," "paint4_TA,paint3_NA,adj_NF,paint2_BB"); QStringList orderList = order.split(','); reportStartWith("adj"); walker.startTrip(adjustmentLayer->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } { QString order("group,paint5,root," "root_TF,paint5_TA,group_NF,paint1_BB"); QStringList orderList = order.split(','); reportStartWith("group"); walker.startTrip(groupLayer->projectionLeaf()); QVERIFY(walker.popResult() == orderList); } } /* +----------+ |root | | layer 5 | | cplx 2 | | group | | paint 4 | | paint 3 | | cplx 1 | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testMergeVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer1 = new ComplexRectsLayer(image, "cplx1", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer2 = new ComplexRectsLayer(image, "cplx2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(complexRectsLayer2, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(complexRectsLayer1, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); QRect testRect(10,10,10,10); // Empty rect to show we don't need any cropping QRect cropRect; KisMergeWalker walker(cropRect); { QString order("root,paint5,cplx2,group,paint1," "paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect(-7,-7,44,44); reportStartWith("paint3"); walker.collectRects(paintLayer3, testRect); verifyResult(walker, orderList, accessRect, true, true); } { QString order("root,paint5,cplx2,group,paint1," "paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect(-10,-10,50,50); reportStartWith("paint2"); walker.collectRects(paintLayer2, testRect); verifyResult(walker, orderList, accessRect, true, true); } { QString order("root,paint5,cplx2,group,paint1"); QStringList orderList = order.split(','); QRect accessRect(3,3,24,24); reportStartWith("paint5"); walker.collectRects(paintLayer5, testRect); verifyResult(walker, orderList, accessRect, false, true); } { /** * Test cropping */ QString order("root,paint5,cplx2,group,paint1," "paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect(0,0,40,40); reportStartWith("paint2 (with cropping)"); walker.setCropRect(image->bounds()); walker.collectRects(paintLayer2, testRect); walker.setCropRect(cropRect); verifyResult(walker, orderList, accessRect, true, true); } { /** * Test uncropped values */ QString order("root,paint5,cplx2,group,paint1," "paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect cropRect(9,9,12,12); QRect accessRect(cropRect); reportStartWith("paint2 (testing uncropped)"); walker.setCropRect(cropRect); walker.collectRects(paintLayer2, testRect); walker.setCropRect(cropRect); verifyResult(walker, orderList, accessRect, true, false); QCOMPARE(walker.uncroppedChangeRect(), QRect(4,4,22,22)); } } /* +------------+ |root | | layer 5 | | cplx 2 | | group | | paint 4 | | cplxacc 1 | | paint 3 | | cplx 1 | | paint 2 | | paint 1 | +------------+ */ void KisWalkersTest::testComplexAccessVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer1 = new ComplexRectsLayer(image, "cplx1", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer2 = new ComplexRectsLayer(image, "cplx2", OPACITY_OPAQUE_U8); KisLayerSP complexAccess = new ComplexAccessLayer(image, "cplxacc1", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(complexRectsLayer2, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(complexRectsLayer1, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(complexAccess, groupLayer); image->addNode(paintLayer4, groupLayer); QRect testRect(10,10,10,10); // Empty rect to show we don't need any cropping QRect cropRect; KisMergeWalker walker(cropRect); { QString order("root,paint5,cplx2,group,paint1," "paint4,cplxacc1,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect = QRect(-7,-7,44,44) | QRect(0,0,30,30).translated(70,0); reportStartWith("paint3"); walker.collectRects(paintLayer3, testRect); verifyResult(walker, orderList, accessRect, true, true); } } void KisWalkersTest::checkNotification(const KisMergeWalker::CloneNotification ¬ification, const QString &name, const QRect &rect) { QCOMPARE(notification.m_layer->name(), name); QCOMPARE(notification.m_dirtyRect, rect); } /* +--------------+ |root | | paint 3 <--+ | | cplx 2 | | | group <--+ | | | cplx 1 | | | | paint 2 | | | | clone 2 -+ | | | clone 1 ---+ | | paint 1 | +--------------+ */ void KisWalkersTest::testCloneNotificationsVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer1 = new ComplexRectsLayer(image, "cplx1", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer2 = new ComplexRectsLayer(image, "cplx2", OPACITY_OPAQUE_U8); KisLayerSP cloneLayer1 = new KisCloneLayer(paintLayer3, image, "clone1", OPACITY_OPAQUE_U8); KisLayerSP cloneLayer2 = new KisCloneLayer(groupLayer, image, "clone2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(cloneLayer1, image->rootLayer()); image->addNode(cloneLayer2, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(complexRectsLayer2, image->rootLayer()); image->addNode(paintLayer3, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(complexRectsLayer1, groupLayer); QRect testRect(10,10,10,10); QRect cropRect(5,5,507,507); KisMergeWalker walker(cropRect); { QString order("root,paint3,cplx2,group,clone2,clone1,paint1," "cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect = QRect(5,5,35,35); reportStartWith("paint2"); walker.collectRects(paintLayer2, testRect); verifyResult(walker, orderList, accessRect, true, true); const KisMergeWalker::CloneNotificationsVector vector = walker.cloneNotifications(); QCOMPARE(vector.size(), 1); checkNotification(vector[0], "group", QRect(7,7,16,16)); } } class TestingRefreshSubtreeWalker : public KisRefreshSubtreeWalker { public: TestingRefreshSubtreeWalker(QRect cropRect) : KisRefreshSubtreeWalker(cropRect) {} UpdateType type() const { return FULL_REFRESH; } }; /* +----------+ |root | | layer 5 | | cplx 2 | | group | | paint 4 | | paint 3 | | cplx 1 | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testRefreshSubtreeVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer1 = new ComplexRectsLayer(image, "cplx1", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer2 = new ComplexRectsLayer(image, "cplx2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(complexRectsLayer2, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(complexRectsLayer1, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); QRect testRect(10,10,10,10); // Empty rect to show we don't need any cropping QRect cropRect; TestingRefreshSubtreeWalker walker(cropRect); { QString order("root,paint5,cplx2,group,paint1," "paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect(-10,-10,50,50); reportStartWith("root"); walker.collectRects(image->rootLayer(), testRect); verifyResult(walker, orderList, accessRect, true, true); } } /* +----------+ |root | | layer 5 | | cplx 2 | | group | | paint 4 | | paint 3 | | cplx 1 | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testFullRefreshVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer1 = new ComplexRectsLayer(image, "cplx1", OPACITY_OPAQUE_U8); KisLayerSP complexRectsLayer2 = new ComplexRectsLayer(image, "cplx2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(complexRectsLayer2, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(complexRectsLayer1, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); QRect testRect(10,10,10,10); // Empty rect to show we don't need any cropping QRect cropRect; KisFullRefreshWalker walker(cropRect); { QString order("root,paint5,cplx2,group,paint1," "group,paint4,paint3,cplx1,paint2"); QStringList orderList = order.split(','); QRect accessRect(-10,-10,50,50); reportStartWith("root"); walker.collectRects(groupLayer, testRect); verifyResult(walker, orderList, accessRect, true, true); } } /* +----------+ |root | | layer 5 | | cache1 | | group | | paint 4 | | paint 3 | | paint 2 | | paint 1 | +----------+ */ void KisWalkersTest::testCachedVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8); KisLayerSP cacheLayer1 = new CacheLayer(image, "cache1", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(groupLayer, image->rootLayer()); image->addNode(cacheLayer1, image->rootLayer()); image->addNode(paintLayer5, image->rootLayer()); image->addNode(paintLayer2, groupLayer); image->addNode(paintLayer3, groupLayer); image->addNode(paintLayer4, groupLayer); QRect testRect(10,10,10,10); // Empty rect to show we don't need any cropping QRect cropRect; KisMergeWalker walker(cropRect); { QString order("root,paint5,cache1,group,paint1," "paint4,paint3,paint2"); QStringList orderList = order.split(','); QRect accessRect(0,0,30,30); reportStartWith("paint3"); walker.collectRects(paintLayer3, testRect); verifyResult(walker, orderList, accessRect, true, true); } { QString order("root,paint5,cache1"); QStringList orderList = order.split(','); QRect accessRect(10,10,10,10); reportStartWith("paint5"); walker.collectRects(paintLayer5, testRect); verifyResult(walker, orderList, accessRect, false, true); } } /* +----------+ |root | | paint 2 | | paint 1 | | fmask2 | | tmask | | fmask1 | +----------+ */ void KisWalkersTest::testMasksVisiting() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(paintLayer2, image->rootLayer()); KisFilterMaskSP filterMask1 = new KisFilterMask(); KisFilterMaskSP filterMask2 = new KisFilterMask(); KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration1 = filter->defaultConfiguration(0); - KisFilterConfiguration *configuration2 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration1 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration2 = filter->defaultConfiguration(0); filterMask1->setFilter(configuration1); filterMask2->setFilter(configuration2); QRect selection1(10, 10, 20, 10); QRect selection2(30, 15, 10, 10); QRect selection3(20, 10, 20, 10); filterMask1->testingInitSelection(selection1, paintLayer1); transparencyMask->testingInitSelection(selection2, paintLayer1); filterMask2->testingInitSelection(selection3, paintLayer1); image->addNode(filterMask1, paintLayer1); image->addNode(transparencyMask, paintLayer1); image->addNode(filterMask2, paintLayer1); QRect testRect(5,5,30,30); // Empty rect to show we don't need any cropping QRect cropRect; KisMergeWalker walker(cropRect); { QString order("root,paint2,paint1"); QStringList orderList = order.split(','); QRect accessRect(0,0,40,40); reportStartWith("tmask"); walker.collectRects(transparencyMask, testRect); verifyResult(walker, orderList, accessRect, true, false); } KisTestWalker twalker; { QString order("paint2,root," "root_TF,paint2_TA,paint1_BP"); QStringList orderList = order.split(','); reportStartWith("tmask"); twalker.startTrip(transparencyMask->projectionLeaf()); QCOMPARE(twalker.popResult(), orderList); } } /* +----------+ |root | | paint 2 | | paint 1 | | fmask2 | | tmask | | fmask1 | +----------+ */ void KisWalkersTest::testMasksVisitingNoFilthy() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(paintLayer2, image->rootLayer()); KisFilterMaskSP filterMask1 = new KisFilterMask(); KisFilterMaskSP filterMask2 = new KisFilterMask(); KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration1 = filter->defaultConfiguration(0); - KisFilterConfiguration *configuration2 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration1 = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration2 = filter->defaultConfiguration(0); filterMask1->setFilter(configuration1); filterMask2->setFilter(configuration2); QRect selection1(10, 10, 20, 10); QRect selection2(30, 15, 10, 10); QRect selection3(20, 10, 20, 10); filterMask1->testingInitSelection(selection1, paintLayer1); transparencyMask->testingInitSelection(selection2, paintLayer1); filterMask2->testingInitSelection(selection3, paintLayer1); image->addNode(filterMask1, paintLayer1); image->addNode(transparencyMask, paintLayer1); image->addNode(filterMask2, paintLayer1); QRect testRect(5,5,30,30); // Empty rect to show we don't need any cropping QRect cropRect; { KisMergeWalker walker(cropRect, KisMergeWalker::NO_FILTHY); QString order("root,paint2,paint1"); QStringList orderList = order.split(','); QRect accessRect(0,0,40,40); reportStartWith("tmask"); walker.collectRects(transparencyMask, testRect); verifyResult(walker, orderList, accessRect, true, false); } { KisMergeWalker walker(cropRect, KisMergeWalker::NO_FILTHY); QString order("root,paint2,paint1"); QStringList orderList = order.split(','); QRect accessRect(5,5,30,30); reportStartWith("paint1"); walker.collectRects(paintLayer1, testRect); verifyResult(walker, orderList, accessRect, false, false); } } /* +----------+ |root | | paint 2 | | paint 1 | | fmask2 | | tmask | | fmask1 | +----------+ */ void KisWalkersTest::testMasksOverlapping() { const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 512, 512, colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); image->addNode(paintLayer1, image->rootLayer()); image->addNode(paintLayer2, image->rootLayer()); KisFilterMaskSP filterMask1 = new KisFilterMask(); KisFilterMaskSP filterMask2 = new KisFilterMask(); KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(); KisFilterSP blurFilter = KisFilterRegistry::instance()->value("blur"); KisFilterSP invertFilter = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(blurFilter); Q_ASSERT(invertFilter); - KisFilterConfiguration *blurConfiguration = blurFilter->defaultConfiguration(0); - KisFilterConfiguration *invertConfiguration = invertFilter->defaultConfiguration(0); + KisFilterConfigurationSP blurConfiguration = blurFilter->defaultConfiguration(0); + KisFilterConfigurationSP invertConfiguration = invertFilter->defaultConfiguration(0); filterMask1->setFilter(invertConfiguration); filterMask2->setFilter(blurConfiguration); QRect selection1(0, 0, 128, 128); QRect selection2(128, 0, 128, 128); QRect selection3(0, 64, 256, 128); filterMask1->testingInitSelection(selection1, paintLayer1); transparencyMask->testingInitSelection(selection2, paintLayer1); filterMask2->testingInitSelection(selection3, paintLayer1); image->addNode(filterMask1, paintLayer1); image->addNode(transparencyMask, paintLayer1); image->addNode(filterMask2, paintLayer1); // Empty rect to show we don't need any cropping QRect cropRect; QRect IMRect(10,10,50,50); QRect TMRect(135,10,40,40); QRect IMTMRect(10,10,256,40); QList updateList; { // FIXME: now we do not crop change rect if COMPOSITE_OVER is used! UpdateTestJob job = {"IM", paintLayer1, IMRect, "", QRect(0,0,0,0), true, false}; updateList.append(job); } { UpdateTestJob job = {"IM", filterMask1, IMRect, "", QRect(0,0,0,0), true, false}; updateList.append(job); } { UpdateTestJob job = {"IM", transparencyMask, IMRect, "root,paint2,paint1", QRect(5,10,60,55), true, false}; updateList.append(job); } { UpdateTestJob job = {"IM", filterMask2, IMRect, "root,paint2,paint1", IMRect, false, false}; updateList.append(job); } /******* Dirty rect: transparency mask *********/ { UpdateTestJob job = {"TM", paintLayer1, TMRect, "root,paint2,paint1", TMRect, false, false}; updateList.append(job); } { UpdateTestJob job = {"TM", filterMask1, TMRect, "root,paint2,paint1", TMRect, false, false}; updateList.append(job); } { UpdateTestJob job = {"TM", transparencyMask, TMRect, "root,paint2,paint1", TMRect, false, false}; updateList.append(job); } { UpdateTestJob job = {"TM", filterMask2, TMRect, "root,paint2,paint1", TMRect, false, false}; updateList.append(job); } /******* Dirty rect: invert + transparency mask *********/ { UpdateTestJob job = {"IMTM", paintLayer1, IMTMRect, "root,paint2,paint1", IMTMRect & selection2, true, false}; updateList.append(job); } { UpdateTestJob job = {"IMTM", filterMask1, IMTMRect, "root,paint2,paint1", IMTMRect & selection2, true, false}; updateList.append(job); } { UpdateTestJob job = {"IMTM", transparencyMask, IMTMRect, "root,paint2,paint1", IMTMRect, false, false}; updateList.append(job); } { UpdateTestJob job = {"IMTM", filterMask2, IMTMRect, "root,paint2,paint1", IMTMRect, false, false}; updateList.append(job); } Q_FOREACH (UpdateTestJob job, updateList) { KisMergeWalker walker(cropRect); reportStartWith(job.startNode->name(), job.updateRect); dbgKrita << "Area:" << job.updateAreaName; walker.collectRects(job.startNode, job.updateRect); verifyResult(walker, job); } } /* +----------+ |root | | adj | | paint 1 | +----------+ */ void KisWalkersTest::testRectsChecksum() { QRect imageRect(0,0,512,512); QRect dirtyRect(100,100,100,100); const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisAdjustmentLayerSP adjustmentLayer = new KisAdjustmentLayer(image, "adj", 0, 0); image->lock(); image->addNode(paintLayer1, image->rootLayer()); image->addNode(adjustmentLayer, image->rootLayer()); image->unlock(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration; + KisFilterConfigurationSP configuration; KisMergeWalker walker(imageRect); walker.collectRects(adjustmentLayer, dirtyRect); QCOMPARE(walker.checksumValid(), true); configuration = filter->defaultConfiguration(0); adjustmentLayer->setFilter(configuration); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); configuration = filter->defaultConfiguration(0); configuration->setProperty("halfWidth", 20); configuration->setProperty("halfHeight", 20); adjustmentLayer->setFilter(configuration); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); configuration = filter->defaultConfiguration(0); configuration->setProperty("halfWidth", 21); configuration->setProperty("halfHeight", 21); adjustmentLayer->setFilter(configuration); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); } void KisWalkersTest::testGraphStructureChecksum() { QRect imageRect(0,0,512,512); QRect dirtyRect(100,100,100,100); const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), colorSpace, "walker test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); image->lock(); image->addNode(paintLayer1, image->rootLayer()); image->unlock(); KisMergeWalker walker(imageRect); walker.collectRects(paintLayer1, dirtyRect); QCOMPARE(walker.checksumValid(), true); image->lock(); image->addNode(paintLayer2, image->rootLayer()); image->unlock(); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); image->lock(); image->moveNode(paintLayer1, image->rootLayer(), paintLayer2); image->unlock(); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); image->lock(); image->removeNode(paintLayer1); image->unlock(); QCOMPARE(walker.checksumValid(), false); walker.recalculate(dirtyRect); QCOMPARE(walker.checksumValid(), true); } QTEST_MAIN(KisWalkersTest) diff --git a/libs/koplugin/KoJsonTrader.cpp b/libs/koplugin/KoJsonTrader.cpp index d0f77fe035..99c07b9e2f 100644 --- a/libs/koplugin/KoJsonTrader.cpp +++ b/libs/koplugin/KoJsonTrader.cpp @@ -1,154 +1,154 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright 2007 David Faure 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 "KoJsonTrader.h" #include "KritaPluginDebug.h" #include #include #include #include #include #include #include #include KoJsonTrader::KoJsonTrader() { // Allow a command line variable KRITA_PLUGIN_PATH to override the automatic search auto requestedPath = QProcessEnvironment::systemEnvironment().value("KRITA_PLUGIN_PATH"); if (!requestedPath.isEmpty()) { m_pluginPath = requestedPath; } else { QList searchDirs; QDir appDir(qApp->applicationDirPath()); appDir.cdUp(); #ifdef Q_OS_MAC // Help Krita run without deployment QDir d(appDir); d.cd("../../../"); searchDirs << d; #endif searchDirs << appDir; // help plugin trader find installed plugins when run from uninstalled tests #ifdef CMAKE_INSTALL_PREFIX searchDirs << QDir(CMAKE_INSTALL_PREFIX); #endif Q_FOREACH (const QDir& dir, searchDirs) { Q_FOREACH (QString entry, dir.entryList()) { QFileInfo info(dir, entry); #ifdef Q_OS_MAC if (info.isDir() && info.fileName().contains("PlugIns")) { m_pluginPath = info.absoluteFilePath(); break; } else if (info.isDir() && (info.fileName().contains("lib"))) { #else if (info.isDir() && info.fileName().contains("lib")) { #endif QDir libDir(info.absoluteFilePath()); // on many systems this will be the actual lib dir (and krita subdir contains plugins) if (libDir.entryList(QStringList() << "kritaplugins").size() > 0) { m_pluginPath = info.absoluteFilePath() + "/kritaplugins"; break; } // on debian at least the actual libdir is a subdir named like "lib/x86_64-linux-gnu" // so search there for the Krita subdir which will contain our plugins Q_FOREACH (QString subEntry, libDir.entryList()) { QFileInfo subInfo(libDir, subEntry); if (subInfo.isDir()) { if (QDir(subInfo.absoluteFilePath()).entryList(QStringList() << "kritaplugins").size() > 0) { m_pluginPath = subInfo.absoluteFilePath() + "/kritaplugins"; break; // will only break inner loop so we need the extra check below } } } if (!m_pluginPath.isEmpty()) { break; } } } if (!m_pluginPath.isEmpty()) { break; } } - qDebug() << "KoJsonTrader will load its plugins from" << m_pluginPath; + debugPlugin << "KoJsonTrader will load its plugins from" << m_pluginPath; } } Q_GLOBAL_STATIC(KoJsonTrader, s_instance) KoJsonTrader* KoJsonTrader::instance() { return s_instance; } QList KoJsonTrader::query(const QString &servicetype, const QString &mimetype) const { QListlist; QDirIterator dirIter(m_pluginPath, QDirIterator::Subdirectories); while (dirIter.hasNext()) { dirIter.next(); if (dirIter.fileInfo().isFile() && dirIter.fileName().startsWith("krita")) { debugPlugin << dirIter.fileName(); QPluginLoader *loader = new QPluginLoader(dirIter.filePath()); QJsonObject json = loader->metaData().value("MetaData").toObject(); debugPlugin << mimetype << json << json.value("X-KDE-ServiceTypes"); if (json.isEmpty()) { delete loader; qWarning() << dirIter.filePath() << "has no json!"; } else { QJsonArray serviceTypes = json.value("X-KDE-ServiceTypes").toArray(); if (serviceTypes.isEmpty()) { qWarning() << dirIter.fileName() << "has no X-KDE-ServiceTypes"; } if (!serviceTypes.contains(QJsonValue(servicetype))) { delete loader; continue; } if (!mimetype.isEmpty()) { QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toString().split(','); mimeTypes += json.value("MimeType").toString().split(';'); mimeTypes += json.value("X-KDE-NativeMimeType").toString(); if (! mimeTypes.contains(mimetype)) { qWarning() << dirIter.filePath() << "doesn't contain mimetype" << mimetype << "in" << mimeTypes; delete loader; continue; } } list.append(loader); } } } return list; } diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index c8f89bf621..ad80c50e1c 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,552 +1,555 @@ # Disable -Wswitch because of the extra definitions we here: # kis_input_manager.cpp: In member function ‘virtual bool KisInputManager::eventFilter(QObject*, QEvent*)’: # warning: case value ‘1001’ not in enumerated type ‘QEvent::Type’ [-Wswitch] # warning: case value ‘1002’ not in enumerated type ‘QEvent::Type’ [-Wswitch] if (CMAKE_COMPILER_IS_GNUCXX) add_definitions(${KDE4_ENABLE_EXCEPTIONS} -Wno-switch) endif () include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ${EXIV2_INCLUDE_DIR} ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) endif () set(kritaui_LIB_SRCS canvas/kis_canvas_widget_base.cpp canvas/kis_canvas2.cpp canvas/kis_canvas_updates_compressor.cpp canvas/kis_canvas_controller.cpp canvas/kis_paintop_transformation_connector.cpp canvas/kis_display_color_converter.cpp canvas/kis_display_filter.cpp canvas/kis_exposure_gamma_correction_interface.cpp canvas/kis_tool_proxy.cpp canvas/kis_canvas_decoration.cc canvas/kis_coordinates_converter.cpp canvas/kis_grid_manager.cpp canvas/kis_grid_decoration.cpp canvas/kis_grid_config.cpp canvas/kis_prescaled_projection.cpp canvas/kis_qpainter_canvas.cpp canvas/kis_projection_backend.cpp canvas/kis_update_info.cpp canvas/kis_image_patch.cpp canvas/kis_image_pyramid.cpp canvas/kis_infinity_manager.cpp canvas/kis_change_guides_command.cpp canvas/kis_guides_decoration.cpp canvas/kis_guides_manager.cpp canvas/kis_guides_config.cpp canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_generator_layer.cpp dialogs/kis_dlg_file_layer.cpp + dialogs/kis_dlg_filter.cpp + dialogs/kis_dlg_stroke_selection_properties.cpp dialogs/kis_dlg_image_properties.cc dialogs/kis_dlg_layer_properties.cc dialogs/kis_dlg_preferences.cc dialogs/slider_and_spin_box_sync.cpp dialogs/kis_dlg_blacklist_cleanup.cpp dialogs/kis_dlg_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp dialogs/kis_dlg_internal_color_selector.cpp flake/kis_node_dummies_graph.cpp flake/kis_dummies_facade_base.cpp flake/kis_dummies_facade.cpp flake/kis_node_shapes_graph.cpp flake/kis_node_shape.cpp flake/kis_shape_controller.cpp flake/kis_shape_layer.cc flake/kis_shape_layer_canvas.cpp flake/kis_shape_selection.cpp flake/kis_shape_selection_canvas.cpp flake/kis_shape_selection_model.cpp flake/kis_take_all_shapes_command.cpp brushhud/kis_uniform_paintop_property_widget.cpp brushhud/kis_brush_hud.cpp brushhud/kis_round_hud_button.cpp brushhud/kis_dlg_brush_hud_config.cpp brushhud/kis_brush_hud_properties_list.cpp brushhud/kis_brush_hud_properties_config.cpp kis_aspect_ratio_locker.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc kis_canvas_resource_provider.cpp kis_derived_resources.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc kis_config_notifier.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_cursor.cc kis_cursor_cache.cpp kis_custom_pattern.cc kis_file_layer.cpp kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc kis_image_manager.cc kis_image_view_converter.cpp kis_import_catcher.cc kis_layer_manager.cc kis_mask_manager.cc kis_mimedata.cpp kis_node_commands_adapter.cpp kis_node_manager.cpp kis_node_juggler_compressed.cpp kis_node_selection_adapter.cpp kis_node_insertion_adapter.cpp kis_node_model.cpp kis_node_filter_proxy_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_painting_assistant.cc kis_painting_assistants_decoration.cpp kis_painting_assistants_manager.cpp kis_paintop_box.cc kis_paintop_option.cpp kis_paintop_options_model.cpp kis_paintop_settings_widget.cpp kis_popup_palette.cpp kis_png_converter.cpp kis_preference_set_registry.cpp kis_resource_server_provider.cpp kis_selection_decoration.cc kis_selection_manager.cc kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp kis_view_plugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_async_action_feedback.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp kra/kis_kra_utils.cpp kra/kis_kra_load_visitor.cpp kra/kis_kra_loader.cpp kra/kis_kra_save_visitor.cpp kra/kis_kra_saver.cpp kra/kis_kra_savexml_visitor.cpp kra/kis_colorize_dom_utils.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 kis_fps_decoration.cpp ora/kis_open_raster_stack_load_visitor.cpp ora/kis_open_raster_stack_save_visitor.cpp ora/ora_load_context.cc ora/ora_save_context.cc recorder/kis_node_query_path_editor.cc recorder/kis_recorded_action_creator.cc recorder/kis_recorded_action_creator_factory.cc recorder/kis_recorded_action_creator_factory_registry.cc recorder/kis_recorded_action_editor_factory.cc recorder/kis_recorded_action_editor_factory_registry.cc recorder/kis_recorded_filter_action_editor.cc recorder/kis_recorded_filter_action_creator.cpp recorder/kis_recorded_paint_action_editor.cc tool/kis_selection_tool_helper.cpp tool/kis_selection_tool_config_widget_helper.cpp tool/kis_rectangle_constraint_widget.cpp tool/kis_shape_tool_helper.cpp tool/kis_tool.cc tool/kis_delegated_tool_policies.cpp tool/kis_tool_freehand.cc tool/kis_speed_smoother.cpp tool/kis_painting_information_builder.cpp tool/kis_stabilized_events_sampler.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp tool/kis_recording_adapter.cpp tool/kis_tool_paint.cc tool/kis_tool_shape.cc tool/kis_tool_ellipse_base.cpp tool/kis_tool_rectangle_base.cpp tool/kis_tool_polyline_base.cpp tool/kis_tool_utils.cpp tool/kis_resources_snapshot.cpp tool/kis_smoothing_options.cpp tool/strokes/freehand_stroke.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp widgets/kis_cmb_composite.cc widgets/kis_cmb_contour.cpp widgets/kis_cmb_gradient.cpp widgets/kis_paintop_list_widget.cpp widgets/kis_cmb_idlist.cc widgets/kis_color_space_selector.cc widgets/kis_advanced_color_space_selector.cc widgets/kis_cie_tongue_widget.cpp widgets/kis_tone_curve_widget.cpp widgets/kis_curve_widget.cpp widgets/kis_custom_image_widget.cc widgets/kis_image_from_clipboard_widget.cpp widgets/kis_double_widget.cc widgets/kis_filter_selector_widget.cc widgets/kis_gradient_chooser.cc widgets/kis_gradient_slider_widget.cc widgets/kis_gradient_slider.cpp widgets/kis_iconwidget.cc widgets/kis_mask_widgets.cpp widgets/kis_meta_data_merge_strategy_chooser_widget.cc widgets/kis_multi_bool_filter_widget.cc widgets/kis_multi_double_filter_widget.cc widgets/kis_multi_integer_filter_widget.cc widgets/kis_multipliers_double_slider_spinbox.cpp widgets/kis_paintop_presets_popup.cpp widgets/kis_tool_options_popup.cpp widgets/kis_paintop_presets_chooser_popup.cpp widgets/kis_pattern_chooser.cc widgets/kis_popup_button.cc widgets/kis_preset_chooser.cpp widgets/kis_progress_widget.cpp widgets/kis_selection_options.cc widgets/kis_scratch_pad.cpp widgets/kis_scratch_pad_event_filter.cpp widgets/kis_preset_selector_strip.cpp widgets/kis_slider_spin_box.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.cpp widgets/squeezedcombobox.cpp widgets/kis_categorized_list_view.cpp widgets/kis_widget_chooser.cpp widgets/kis_tool_button.cpp widgets/kis_floating_message.cpp widgets/kis_lod_availability_widget.cpp widgets/kis_color_label_selector_widget.cpp widgets/kis_color_filter_combo.cpp widgets/kis_elided_label.cpp widgets/kis_spinbox_color_selector.cpp widgets/kis_screen_color_picker.cpp widgets/kis_visual_color_selector.cpp widgets/KoDualColorButton.cpp widgets/kis_color_input.cpp widgets/kis_color_button.cpp input/kis_input_manager.cpp input/kis_input_manager_p.cpp input/kis_extended_modifiers_mapper.cpp input/kis_abstract_input_action.cpp input/kis_tool_invocation_action.cpp input/kis_pan_action.cpp input/kis_alternate_invocation_action.cpp input/kis_rotate_canvas_action.cpp input/kis_zoom_action.cpp input/kis_change_frame_action.cpp input/kis_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp operations/kis_operation.cpp operations/kis_operation_configuration.cpp operations/kis_operation_registry.cpp operations/kis_operation_ui_factory.cpp operations/kis_operation_ui_widget.cpp operations/kis_filter_selection_operation.cpp actions/kis_selection_action_factories.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.cpp kis_transaction_based_command.cpp kis_gui_context_command.cpp kis_gui_context_command_p.cpp input/kis_tablet_debugger.cpp input/kis_input_profile_manager.cpp input/kis_input_profile.cpp input/kis_shortcut_configuration.cpp input/config/kis_input_configuration_page.cpp input/config/kis_edit_profiles_dialog.cpp input/config/kis_input_profile_model.cpp input/config/kis_input_configuration_page_item.cpp input/config/kis_action_shortcuts_model.cpp input/config/kis_input_type_delegate.cpp input/config/kis_input_mode_delegate.cpp input/config/kis_input_button.cpp input/config/kis_input_editor_delegate.cpp input/config/kis_mouse_input_editor.cpp input/config/kis_wheel_input_editor.cpp input/config/kis_key_input_editor.cpp processing/fill_processing_visitor.cpp kis_asl_layer_style_serializer.cpp kis_psd_layer_style_resource.cpp canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisNodeDelegate.cpp kis_node_view_visibility_delegate.cpp KisNodeToolTip.cpp KisNodeView.cpp kis_node_view_color_scheme.cpp KisFilterChain.cpp KisFilterChainLink.cpp KisFilterChainLinkList.cpp KisImportExportFilter.cpp KisFilterEdge.cpp KisFilterEntry.cpp KisFilterGraph.cpp KisImportExportManager.cpp KisFilterVertex.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoStackAction.cpp KisView.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisPaletteModel.cpp kis_palette_delegate.cpp kis_palette_view.cpp KisColorsetChooser.cpp KisSaveGroupVisitor.cpp ) if(WIN32) if (NOT Qt5Gui_PRIVATE_INCLUDE_DIRS) message(FATAL_ERROR "Qt5Gui Private header are missing!") endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp qtlockedfile/qtlockedfile_win.cpp ) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp canvas/kis_animation_player.cpp kis_animation_exporter.cpp kis_animation_importer.cpp ) if(UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support.cpp qtlockedfile/qtlockedfile_unix.cpp ) if(NOT APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/kis_tablet_support_x11.cpp input/wintab/qxcbconnection_xi2.cpp input/wintab/qxcbconnection.cpp input/wintab/kis_xi2_event_filter.cpp ) endif() endif() if(WIN32) #ki18n_wrap_ui( # input/wintab/kis_screen_size_choice_dialog.ui #) endif() ki18n_wrap_ui(kritaui_LIB_SRCS forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggenerators.ui forms/wdgbookmarkedconfigurationseditor.ui forms/wdgapplyprofile.ui forms/wdgcustompattern.ui forms/wdglayerproperties.ui forms/wdgcolorsettings.ui forms/wdgtabletsettings.ui forms/wdgcolorspaceselector.ui forms/wdgcolorspaceselectoradvanced.ui forms/wdgdisplaysettings.ui forms/kis_previewwidgetbase.ui forms/kis_matrix_widget.ui forms/wdgselectionoptions.ui forms/wdggeometryoptions.ui forms/wdgnewimage.ui forms/wdgimageproperties.ui forms/wdgmaskfromselection.ui forms/wdgmasksource.ui forms/wdgfilterdialog.ui forms/wdgmetadatamergestrategychooser.ui forms/wdgpaintoppresets.ui forms/wdgpaintopsettings.ui forms/wdgdlggeneratorlayer.ui forms/wdgdlgfilelayer.ui forms/wdgfilterselector.ui forms/wdgfilternodecreation.ui forms/wdgpaintactioneditor.ui forms/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui + forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui brushhud/kis_dlg_brush_hud_config.ui forms/wdgdlginternalcolorselector.ui dialogs/kis_delayed_save_dialog.ui input/config/kis_input_configuration_page.ui input/config/kis_edit_profiles_dialog.ui input/config/kis_input_configuration_page_item.ui input/config/kis_mouse_input_editor.ui input/config/kis_wheel_input_editor.ui input/config/kis_key_input_editor.ui layerstyles/wdgBevelAndEmboss.ui layerstyles/wdgblendingoptions.ui layerstyles/WdgColorOverlay.ui layerstyles/wdgContour.ui layerstyles/wdgdropshadow.ui layerstyles/WdgGradientOverlay.ui layerstyles/wdgInnerGlow.ui layerstyles/wdglayerstyles.ui layerstyles/WdgPatternOverlay.ui layerstyles/WdgSatin.ui layerstyles/WdgStroke.ui layerstyles/wdgstylesselector.ui layerstyles/wdgTexture.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui ) QT5_WRAP_CPP(kritaui_HEADERS_MOC KisNodePropertyAction_p.h) add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} ) generate_export_header(kritaui BASE_NAME kritaui) target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES} ) if (HAVE_KIO) target_link_libraries(kritaui KF5::KIOCore) endif() if (NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) endif () target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_link_libraries(kritaui LINK_INTERFACE_LIBRARIES kritaimage kritalibbrush kritapigment kritawidgets KF5::Completion KF5::I18n ${GL_INTERFACE_LIBRARIES}) 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/KisDocument.cpp b/libs/ui/KisDocument.cpp index 11058b696d..e6e82da492 100644 --- a/libs/ui/KisDocument.cpp +++ b/libs/ui/KisDocument.cpp @@ -1,2498 +1,2500 @@ /* This file is part of the Krita project * * Copyright (C) 2014 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 "KisMainWindow.h" // XXX: remove #include // XXX: remove #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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Krita Image #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local #include "KisViewManager.h" #include "kis_clipboard.h" #include "widgets/kis_custom_image_widget.h" #include "canvas/kis_canvas2.h" #include "flake/kis_shape_controller.h" #include "kra/kis_kra_loader.h" #include "kra/kis_kra_saver.h" #include "kis_statusbar.h" #include "widgets/kis_progress_widget.h" #include "kis_canvas_resource_provider.h" #include "kis_resource_server_provider.h" #include "kis_node_manager.h" #include "KisPart.h" #include "KisApplication.h" #include "KisDocument.h" #include "KisImportExportManager.h" #include "KisPart.h" #include "KisView.h" #include "kis_async_action_feedback.h" #include "kis_grid_config.h" #include "kis_guides_config.h" #include "kis_image_barrier_lock_adapter.h" #include static const char CURRENT_DTD_VERSION[] = "2.0"; // Define the protocol used here for embedded documents' URL // This used to "store" but QUrl didn't like it, // so let's simply make it "tar" ! #define STORE_PROTOCOL "tar" // The internal path is a hack to make QUrl happy and for document children #define INTERNAL_PROTOCOL "intern" #define INTERNAL_PREFIX "intern:/" // Warning, keep it sync in koStore.cc #include using namespace std; /********************************************************** * * KisDocument * **********************************************************/ namespace { class DocumentProgressProxy : public KoProgressProxy { public: KisMainWindow *m_mainWindow; DocumentProgressProxy(KisMainWindow *mainWindow) : m_mainWindow(mainWindow) { } ~DocumentProgressProxy() { // signal that the job is done setValue(-1); } int maximum() const { return 100; } void setValue(int value) { if (m_mainWindow) { m_mainWindow->slotProgress(value); } } void setRange(int /*minimum*/, int /*maximum*/) { } void setFormat(const QString &/*format*/) { } }; } //static QString KisDocument::newObjectName() { static int s_docIFNumber = 0; QString name; name.setNum(s_docIFNumber++); name.prepend("document_"); return name; } class UndoStack : public KUndo2Stack { public: UndoStack(KisDocument *doc) : m_doc(doc) { } void setIndex(int idx) { KisImageWSP image = this->image(); image->requestStrokeCancellation(); if(image->tryBarrierLock()) { KUndo2Stack::setIndex(idx); image->unlock(); } } void notifySetIndexChangedOneCommand() { KisImageWSP image = this->image(); image->unlock(); image->barrierLock(); } void undo() { KisImageWSP image = this->image(); image->requestUndoDuringStroke(); if(image->tryBarrierLock()) { KUndo2Stack::undo(); image->unlock(); } } void redo() { KisImageWSP image = this->image(); if(image->tryBarrierLock()) { KUndo2Stack::redo(); image->unlock(); } } private: KisImageWSP image() { KisImageWSP currentImage = m_doc->image(); Q_ASSERT(currentImage); return currentImage; } private: KisDocument *m_doc; }; class Q_DECL_HIDDEN KisDocument::Private { public: Private(KisDocument *document) : document(document), // XXX: the part should _not_ be modified from the document docInfo(0), progressUpdater(0), progressProxy(0), - filterManager(0), + importExportManager(0), specialOutputFlag(0), // default is native format isImporting(false), isExporting(false), password(QString()), modifiedAfterAutosave(false), isAutosaving(false), autoErrorHandlingEnabled(true), backupFile(true), backupPath(QString()), doNotSaveExtDoc(false), storeInternal(false), isLoading(false), undoStack(0), m_saveOk(false), m_waitForSave(false), m_duringSaveAs(false), m_bTemp(false), m_bAutoDetectedMime(false), modified(false), readwrite(true), disregardAutosaveFailure(false), nserver(0), macroNestDepth(0), imageIdleWatcher(2000 /*ms*/), kraLoader(0), suppressProgress(false), fileProgressProxy(0) { if (QLocale().measurementSystem() == QLocale::ImperialSystem) { unit = KoUnit::Inch; } else { unit = KoUnit::Centimeter; } } ~Private() { // Don't delete m_d->shapeController because it's in a QObject hierarchy. delete nserver; } KisDocument *document; KoDocumentInfo *docInfo; KoProgressUpdater *progressUpdater; KoProgressProxy *progressProxy; KoUnit unit; - KisImportExportManager *filterManager; // The filter-manager to use when loading/saving [for the options] + KisImportExportManager *importExportManager; // The filter-manager to use when loading/saving [for the options] QByteArray mimeType; // The actual mimetype of the document QByteArray outputMimeType; // The mimetype to use when saving bool confirmNonNativeSave [2] = {true, true}; // used to pop up a dialog when saving for the // first time if the file is in a foreign format // (Save/Save As, Export) int specialOutputFlag; // See KoFileDialog in koMainWindow.cc bool isImporting; bool isExporting; // File --> Import/Export vs File --> Open/Save QString password; // The password used to encrypt an encrypted document QTimer autoSaveTimer; QString lastErrorMessage; // see openFile() int autoSaveDelay; // in seconds, 0 to disable. bool modifiedAfterAutosave; bool isAutosaving; bool autoErrorHandlingEnabled; // usually true bool backupFile; QString backupPath; bool doNotSaveExtDoc; // makes it possible to save only internally stored child documents bool storeInternal; // Store this doc internally even if url is external bool isLoading; // True while loading (openUrl is async) KUndo2Stack *undoStack; KisGuidesConfig guidesConfig; bool isEmpty; KoPageLayout pageLayout; QUrl m_originalURL; // for saveAs QString m_originalFilePath; // for saveAs bool m_saveOk : 1; bool m_waitForSave : 1; bool m_duringSaveAs : 1; bool m_bTemp: 1; // If @p true, @p m_file is a temporary file that needs to be deleted later. bool m_bAutoDetectedMime : 1; // whether the mimetype in the arguments was detected by the part itself QUrl m_url; // Remote (or local) url - the one displayed to the user. QString m_file; // Local file - the only one the part implementation should deal with. QEventLoop m_eventLoop; QMutex savingMutex; bool modified; bool readwrite; QDateTime firstMod; QDateTime lastMod; bool disregardAutosaveFailure; KisNameServer *nserver; qint32 macroNestDepth; KisImageSP image; KisNodeSP preActivatedNode; KisShapeController* shapeController; KoShapeController* koShapeController; KisIdleWatcher imageIdleWatcher; QScopedPointer imageIdleConnection; KisKraLoader* kraLoader; KisKraSaver* kraSaver; bool suppressProgress; KoProgressProxy* fileProgressProxy; QList assistants; KisGridConfig gridConfig; bool openFile() { document->setFileProgressProxy(); document->setUrl(m_url); bool ok = document->openFile(); document->clearFileProgressProxy(); return ok; } bool openLocalFile() { m_bTemp = false; // set the mimetype only if it was not already set (for example, by the host application) if (mimeType.isEmpty()) { // get the mimetype of the file // using findByUrl() to avoid another string -> url conversion QString mime = KisMimeDatabase::mimeTypeForFile(m_url.toLocalFile()); mimeType = mime.toLocal8Bit(); m_bAutoDetectedMime = true; } const bool ret = openFile(); if (ret) { emit document->completed(); } else { emit document->canceled(QString()); } return ret; } // Set m_file correctly for m_url void prepareSaving() { // Local file if ( m_url.isLocalFile() ) { if ( m_bTemp ) // get rid of a possible temp file first { // (happens if previous url was remote) QFile::remove( m_file ); m_bTemp = false; } m_file = m_url.toLocalFile(); } } void setImageAndInitIdleWatcher(KisImageSP _image) { image = _image; imageIdleWatcher.setTrackedImage(image); if (image) { imageIdleConnection.reset( new KisSignalAutoConnection( &imageIdleWatcher, SIGNAL(startedIdleMode()), image.data(), SLOT(explicitRegenerateLevelOfDetail()))); } } class SafeSavingLocker; }; class KisDocument::Private::SafeSavingLocker { public: SafeSavingLocker(KisDocument::Private *_d) : d(_d), m_locked(false), m_imageLock(d->image, true), m_savingLock(&d->savingMutex) { const int realAutoSaveInterval = KisConfig().autoSaveInterval(); const int emergencyAutoSaveInterval = 10; // sec /** * Initial try to lock both objects. Locking the image guards * us from any image composition threads running in the * background, while savingMutex guards us from entering the * saving code twice by autosave and main threads. * * Since we are trying to lock multiple objects, so we should * do it in a safe manner. */ m_locked = std::try_lock(m_imageLock, m_savingLock) < 0; if (!m_locked) { if (d->isAutosaving) { d->disregardAutosaveFailure = true; if (realAutoSaveInterval) { d->document->setAutoSave(emergencyAutoSaveInterval); } } else { d->image->requestStrokeEnd(); QApplication::processEvents(); // one more try... m_locked = std::try_lock(m_imageLock, m_savingLock) < 0; } } if (m_locked) { d->disregardAutosaveFailure = false; } } ~SafeSavingLocker() { if (m_locked) { m_imageLock.unlock(); m_savingLock.unlock(); const int realAutoSaveInterval = KisConfig().autoSaveInterval(); d->document->setAutoSave(realAutoSaveInterval); } } bool successfullyLocked() const { return m_locked; } private: KisDocument::Private *d; bool m_locked; KisImageBarrierLockAdapter m_imageLock; StdLockableWrapper m_savingLock; }; KisDocument::KisDocument() : d(new Private(this)) { d->undoStack = new UndoStack(this); d->undoStack->setParent(this); d->isEmpty = true; - d->filterManager = new KisImportExportManager(this); - d->filterManager->setProgresUpdater(d->progressUpdater); + d->importExportManager = new KisImportExportManager(this); + d->importExportManager->setProgresUpdater(d->progressUpdater); connect(&d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); setAutoSave(defaultAutoSave()); setObjectName(newObjectName()); d->docInfo = new KoDocumentInfo(this); d->pageLayout.width = 0; d->pageLayout.height = 0; d->pageLayout.topMargin = 0; d->pageLayout.bottomMargin = 0; d->pageLayout.leftMargin = 0; d->pageLayout.rightMargin = 0; KConfigGroup cfgGrp( KSharedConfig::openConfig(), "Undo"); d->undoStack->setUndoLimit(cfgGrp.readEntry("UndoLimit", 1000)); d->firstMod = QDateTime::currentDateTime(); d->lastMod = QDateTime::currentDateTime(); connect(d->undoStack, SIGNAL(indexChanged(int)), this, SLOT(slotUndoStackIndexChanged(int))); // preload the krita resources KisResourceServerProvider::instance(); init(); undoStack()->setUndoLimit(KisConfig().undoStackLimit()); setBackupFile(KisConfig().backupFile()); } KisDocument::~KisDocument() { /** * Push a timebomb, which will try to release the memory after * the document has been deleted */ KisPaintDevice::createMemoryReleaseObject()->deleteLater(); d->autoSaveTimer.disconnect(this); d->autoSaveTimer.stop(); - delete d->filterManager; + delete d->importExportManager; // Despite being QObject they needs to be deleted before the image delete d->shapeController; delete d->koShapeController; if (d->image) { d->image->notifyAboutToBeDeleted(); /** * WARNING: We should wait for all the internal image jobs to * finish before entering KisImage's destructor. The problem is, * while execution of KisImage::~KisImage, all the weak shared * pointers pointing to the image enter an inconsistent * state(!). The shared counter is already zero and destruction * has started, but the weak reference doesn't know about it, * because KisShared::~KisShared hasn't been executed yet. So all * the threads running in background and having weak pointers will * enter the KisImage's destructor as well. */ d->image->requestStrokeCancellation(); d->image->waitForDone(); } // clear undo commands that can still point to the image d->undoStack->clear(); KisImageWSP sanityCheckPointer = d->image; // The following line trigger the deletion of the image d->image.clear(); // check if the image has actually been deleted KIS_ASSERT_RECOVER_NOOP(!sanityCheckPointer.isValid()); delete d; } void KisDocument::init() { delete d->nserver; d->nserver = 0; d->nserver = new KisNameServer(1); Q_CHECK_PTR(d->nserver); d->shapeController = new KisShapeController(this, d->nserver); d->koShapeController = new KoShapeController(0, d->shapeController); d->kraSaver = 0; d->kraLoader = 0; } bool KisDocument::reload() { // XXX: reimplement! return false; } -bool KisDocument::exportDocument(const QUrl &_url) +bool KisDocument::exportDocument(const QUrl &_url, KisPropertiesConfigurationSP exportConfiguration) { bool ret; d->isExporting = true; // // Preserve a lot of state here because we need to restore it in order to // be able to fake a File --> Export. Can't do this in saveFile() because, // for a start, KParts has already set url and m_file and because we need // to restore the modified flag etc. and don't want to put a load on anyone // reimplementing saveFile() (Note: importDocument() and exportDocument() // will remain non-virtual). // QUrl oldURL = url(); QString oldFile = localFilePath(); bool wasModified = isModified(); QByteArray oldMimeType = mimeType(); // save... - ret = saveAs(_url); - + ret = saveAs(_url, exportConfiguration); // // This is sooooo hacky :( // Hopefully we will restore enough state. // dbgUI << "Restoring KisDocument state to before export"; // always restore url & m_file because KParts has changed them // (regardless of failure or success) setUrl(oldURL); setLocalFilePath(oldFile); // on successful export we need to restore modified etc. too // on failed export, mimetype/modified hasn't changed anyway if (ret) { setModified(wasModified); d->mimeType = oldMimeType; } - d->isExporting = false; return ret; } -bool KisDocument::saveFile() +bool KisDocument::saveFile(KisPropertiesConfigurationSP exportConfiguration) { // Save it to be able to restore it after a failed save const bool wasModified = isModified(); + // Show the dialog with the options, if any + // The output format is set by koMainWindow, and by openFile QByteArray outputMimeType = d->outputMimeType; if (outputMimeType.isEmpty()) outputMimeType = d->outputMimeType = nativeFormatMimeType(); QApplication::setOverrideCursor(Qt::WaitCursor); if (backupFile()) { Q_ASSERT(url().isLocalFile()); KBackup::backupFile(url().toLocalFile(), d->backupPath); } qApp->processEvents(); bool ret = false; bool suppressErrorDialog = false; KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; setFileProgressUpdater(i18n("Saving Document")); QFileInfo fi(localFilePath()); QString tempororaryFileName; { QTemporaryFile tf(QDir::tempPath() + "/XXXXXX" + fi.baseName() + "." + fi.completeSuffix()); tf.open(); tempororaryFileName = tf.fileName(); } Q_ASSERT(!tempororaryFileName.isEmpty()); if (!isNativeFormat(outputMimeType)) { Private::SafeSavingLocker locker(d); if (locker.successfullyLocked()) { - status = d->filterManager->exportDocument(tempororaryFileName, outputMimeType); + status = d->importExportManager->exportDocument(tempororaryFileName, outputMimeType, exportConfiguration); } else { status = KisImportExportFilter::UsageError; } ret = status == KisImportExportFilter::OK; suppressErrorDialog = (status == KisImportExportFilter::UserCancelled || status == KisImportExportFilter::BadConversionGraph); dbgFile << "Export status was" << status; } else { // Native format => normal save ret = saveNativeFormat(tempororaryFileName); } if (ret) { if (!d->suppressProgress) { QPointer updater = d->progressUpdater->startSubtask(1, "clear undo stack"); updater->setProgress(0); d->undoStack->setClean(); updater->setProgress(100); } else { d->undoStack->setClean(); } QFile tempFile(tempororaryFileName); QString s = localFilePath(); QFile dstFile(s); while (QFileInfo(s).exists()) { s.append("_"); } bool r; if (s != localFilePath()) { r = dstFile.rename(s); if (!r) { setErrorMessage(i18n("Could not rename original file to %1: %2", dstFile.fileName(), dstFile. errorString())); } } if (tempFile.exists()) { r = tempFile.copy(localFilePath()); if (!r) { setErrorMessage(i18n("Copying the temporary file failed: %1 to %2: %3", tempFile.fileName(), dstFile.fileName(), tempFile.errorString())); } else { r = tempFile.remove(); if (!r) { setErrorMessage(i18n("Could not remove temporary file %1: %2", tempFile.fileName(), tempFile.errorString())); } else if (s != localFilePath()) { r = dstFile.remove(); if (!r) { setErrorMessage(i18n("Could not remove saved original file: %1", dstFile.errorString())); } } } } else { setErrorMessage(i18n("The temporary file %1 is gone before we could copy it!", tempFile.fileName())); } if (errorMessage().isEmpty()) { removeAutoSaveFiles(); } else { qWarning() << "Error while saving:" << errorMessage(); } // Restart the autosave timer // (we don't want to autosave again 2 seconds after a real save) setAutoSave(d->autoSaveDelay); d->mimeType = outputMimeType; setConfirmNonNativeSave(isExporting(), false); } else { if (!suppressErrorDialog) { if (errorMessage().isEmpty()) { setErrorMessage(KisImportExportFilter::conversionStatusString(status)); } if (errorMessage().isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save\n%1", localFilePath())); - } else if (errorMessage() != "USER_CANCELED") { + } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save %1\nReason: %2", localFilePath(), errorMessage())); } } // couldn't save file so this new URL is invalid // FIXME: we should restore the current document's true URL instead of // setting it to nothing otherwise anything that depends on the URL // being correct will not work (i.e. the document will be called // "Untitled" which may not be true) // // Update: now the URL is restored in KisMainWindow but really, this // should still be fixed in KisDocument/KParts (ditto for file). // We still resetURL() here since we may or may not have been called // by KisMainWindow - Clarence resetURL(); // As we did not save, restore the "was modified" status setModified(wasModified); } clearFileProgressUpdater(); QApplication::restoreOverrideCursor(); return ret; } QByteArray KisDocument::mimeType() const { return d->mimeType; } void KisDocument::setMimeType(const QByteArray & mimeType) { d->mimeType = mimeType; } void KisDocument::setOutputMimeType(const QByteArray & mimeType, int specialOutputFlag) { d->outputMimeType = mimeType; d->specialOutputFlag = specialOutputFlag; } QByteArray KisDocument::outputMimeType() const { return d->outputMimeType; } int KisDocument::specialOutputFlag() const { return d->specialOutputFlag; } bool KisDocument::confirmNonNativeSave(const bool exporting) const { // "exporting ? 1 : 0" is different from "exporting" because a bool is // usually implemented like an "int", not "unsigned : 1" return d->confirmNonNativeSave [ exporting ? 1 : 0 ]; } void KisDocument::setConfirmNonNativeSave(const bool exporting, const bool on) { d->confirmNonNativeSave [ exporting ? 1 : 0] = on; } bool KisDocument::fileBatchMode() const { - return d->filterManager->getBatchMode(); + return d->importExportManager->getBatchMode(); } void KisDocument::setFileBatchMode(const bool batchMode) { - d->filterManager->setBatchMode(batchMode); + d->importExportManager->setBatchMode(batchMode); } bool KisDocument::isImporting() const { return d->isImporting; } bool KisDocument::isExporting() const { return d->isExporting; } void KisDocument::setAutoErrorHandlingEnabled(bool b) { d->autoErrorHandlingEnabled = b; } bool KisDocument::isAutoErrorHandlingEnabled() const { return d->autoErrorHandlingEnabled; } void KisDocument::slotAutoSave() { if (d->modified && d->modifiedAfterAutosave && !d->isLoading) { // Give a warning when trying to autosave an encrypted file when no password is known (should not happen) if (d->specialOutputFlag == SaveEncrypted && d->password.isNull()) { // That advice should also fix this error from occurring again emit statusBarMessage(i18n("The password of this encrypted document is not known. Autosave aborted! Please save your work manually.")); } else { connect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int))); emit statusBarMessage(i18n("Autosaving...")); d->isAutosaving = true; bool ret = saveNativeFormat(autoSaveFile(localFilePath())); setModified(true); if (ret) { d->modifiedAfterAutosave = false; d->autoSaveTimer.stop(); // until the next change } d->isAutosaving = false; emit clearStatusBarMessage(); disconnect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int))); if (!ret && !d->disregardAutosaveFailure) { emit statusBarMessage(i18n("Error during autosave! Partition full?")); } } } } void KisDocument::setReadWrite(bool readwrite) { d->readwrite = readwrite; setAutoSave(d->autoSaveDelay); Q_FOREACH (KisMainWindow *mainWindow, KisPart::instance()->mainWindows()) { mainWindow->setReadWrite(readwrite); } } void KisDocument::setAutoSave(int delay) { d->autoSaveDelay = delay; if (isReadWrite() && d->autoSaveDelay > 0) d->autoSaveTimer.start(d->autoSaveDelay * 1000); else d->autoSaveTimer.stop(); } KoDocumentInfo *KisDocument::documentInfo() const { return d->docInfo; } bool KisDocument::isModified() const { return d->modified; } bool KisDocument::saveNativeFormat(const QString & file) { Private::SafeSavingLocker locker(d); if (!locker.successfullyLocked()) return false; d->lastErrorMessage.clear(); //dbgUI <<"Saving to store"; KoStore::Backend backend = KoStore::Auto; if (d->specialOutputFlag == SaveAsDirectoryStore) { backend = KoStore::Directory; dbgUI << "Saving as uncompressed XML, using directory store."; } else if (d->specialOutputFlag == SaveAsFlatXML) { dbgUI << "Saving as a flat XML file."; QFile f(file); if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { bool success = saveToStream(&f); f.close(); return success; } else return false; } dbgUI << "KisDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType(); // TODO: use std::auto_ptr or create store on stack [needs API fixing], // to remove all the 'delete store' in all the branches KoStore *store = KoStore::createStore(file, KoStore::Write, d->outputMimeType, backend); if (d->specialOutputFlag == SaveEncrypted && !d->password.isNull()) { store->setPassword(d->password); } if (store->bad()) { d->lastErrorMessage = i18n("Could not create the file for saving"); // more details needed? delete store; return false; } bool result = false; if (!d->isAutosaving) { KisAsyncActionFeedback f(i18n("Saving document..."), 0); result = f.runAction(std::bind(&KisDocument::saveNativeFormatCalligra, this, store)); } else { result = saveNativeFormatCalligra(store); } return result; } bool KisDocument::saveNativeFormatCalligra(KoStore *store) { dbgUI << "Saving root"; if (store->open("root")) { KoStoreDevice dev(store); if (!saveToStream(&dev) || !store->close()) { dbgUI << "saveToStream failed"; delete store; return false; } } else { d->lastErrorMessage = i18n("Not able to write '%1'. Partition full?", QString("maindoc.xml")); delete store; return false; } if (store->open("documentinfo.xml")) { QDomDocument doc = KisDocument::createDomDocument("document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1"); doc = d->docInfo->save(doc); KoStoreDevice dev(store); QByteArray s = doc.toByteArray(); // this is already Utf8! (void)dev.write(s.data(), s.size()); (void)store->close(); } if (!d->isAutosaving) { if (store->open("preview.png")) { // ### TODO: missing error checking (The partition could be full!) savePreview(store); (void)store->close(); } } if (!completeSaving(store)) { delete store; return false; } dbgUI << "Saving done of url:" << url().url(); if (!store->finalize()) { delete store; return false; } // Success delete store; return true; } bool KisDocument::saveToStream(QIODevice *dev) { QDomDocument doc = saveXML(); // Save to buffer QByteArray s = doc.toByteArray(); // utf8 already dev->open(QIODevice::WriteOnly); int nwritten = dev->write(s.data(), s.size()); if (nwritten != (int)s.size()) warnUI << "wrote " << nwritten << "- expected" << s.size(); return nwritten == (int)s.size(); } // Called for embedded documents bool KisDocument::saveToStore(KoStore *_store, const QString & _path) { dbgUI << "Saving document to store" << _path; _store->pushDirectory(); // Use the path as the internal url if (_path.startsWith(STORE_PROTOCOL)) setUrl(QUrl(_path)); else // ugly hack to pass a relative URI setUrl(QUrl(INTERNAL_PREFIX + _path)); // In the current directory we're the king :-) if (_store->open("root")) { KoStoreDevice dev(_store); if (!saveToStream(&dev)) { _store->close(); return false; } if (!_store->close()) return false; } if (!completeSaving(_store)) return false; // Now that we're done leave the directory again _store->popDirectory(); dbgUI << "Saved document to store"; return true; } bool KisDocument::savePreview(KoStore *store) { QPixmap pix = generatePreview(QSize(256, 256)); const QImage preview(pix.toImage().convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly)); KoStoreDevice io(store); if (!io.open(QIODevice::WriteOnly)) return false; if (! preview.save(&io, "PNG")) // ### TODO What is -9 in quality terms? return false; io.close(); return true; } QPixmap KisDocument::generatePreview(const QSize& size) { if (d->image) { QRect bounds = d->image->bounds(); QSize newSize = bounds.size(); newSize.scale(size, Qt::KeepAspectRatio); return QPixmap::fromImage(d->image->convertToQImage(newSize, 0)); } return QPixmap(size); } QString KisDocument::autoSaveFile(const QString & path) const { QString retval; // Using the extension allows to avoid relying on the mime magic when opening const QString extension (".kra"); if (path.isEmpty()) { // Never saved? #ifdef Q_OS_WIN // On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921) retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::tempPath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension); #else // On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's autosave file retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::homePath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension); #endif } else { QFileInfo fi(path); QString dir = fi.absolutePath(); QString filename = fi.fileName(); retval = QString("%1%2.%3-autosave%4").arg(dir).arg(QDir::separator()).arg(filename).arg(extension); } return retval; } bool KisDocument::importDocument(const QUrl &_url) { bool ret; dbgUI << "url=" << _url.url(); d->isImporting = true; // open... ret = openUrl(_url); // reset url & m_file (kindly? set by KisParts::openUrl()) to simulate a // File --> Import if (ret) { dbgUI << "success, resetting url"; resetURL(); setTitleModified(); } d->isImporting = false; return ret; } bool KisDocument::openUrl(const QUrl &_url, KisDocument::OpenUrlFlags flags) { if (!_url.isLocalFile()) { qDebug() << "not a local file" << _url; return false; } dbgUI << "url=" << _url.url(); d->lastErrorMessage.clear(); // Reimplemented, to add a check for autosave files and to improve error reporting if (!_url.isValid()) { d->lastErrorMessage = i18n("Malformed URL\n%1", _url.url()); // ## used anywhere ? return false; } QUrl url(_url); bool autosaveOpened = false; d->isLoading = true; if (url.isLocalFile() && !fileBatchMode()) { QString file = url.toLocalFile(); QString asf = autoSaveFile(file); if (QFile::exists(asf)) { KisApplication *kisApp = static_cast(qApp); kisApp->hideSplashScreen(); //dbgUI <<"asf=" << asf; // ## TODO compare timestamps ? int res = QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("An autosaved file exists for this document.\nDo you want to open it instead?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); switch (res) { case QMessageBox::Yes : url.setPath(asf); autosaveOpened = true; break; case QMessageBox::No : QFile::remove(asf); break; default: // Cancel d->isLoading = false; return false; } } } bool ret = openUrlInternal(url); if (autosaveOpened) { resetURL(); // Force save to act like 'Save As' setReadWrite(true); // enable save button setModified(true); } else { if( !(flags & OPEN_URL_FLAG_DO_NOT_ADD_TO_RECENT_FILES) ) { KisPart::instance()->addRecentURLToAllMainWindows(_url); } if (ret) { // Detect readonly local-files; remote files are assumed to be writable QFileInfo fi(url.toLocalFile()); setReadWrite(fi.isWritable()); } } return ret; } bool KisDocument::openFile() { //dbgUI <<"for" << localFilePath(); if (!QFile::exists(localFilePath())) { QApplication::restoreOverrideCursor(); if (d->autoErrorHandlingEnabled) // Maybe offer to create a new document with that name ? QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("File %1 does not exist.", localFilePath())); d->isLoading = false; return false; } QApplication::setOverrideCursor(Qt::WaitCursor); d->specialOutputFlag = 0; QString filename = localFilePath(); QString typeName = mimeType(); if (typeName.isEmpty()) { typeName = KisMimeDatabase::mimeTypeForFile(filename); } //qDebug() << "mimetypes 4:" << typeName; // Allow to open backup files, don't keep the mimetype application/x-trash. if (typeName == "application/x-trash") { QString path = filename; while (path.length() > 0) { path.chop(1); typeName = KisMimeDatabase::mimeTypeForFile(path); //qDebug() << "\t" << path << typeName; if (!typeName.isEmpty()) { break; } } //qDebug() << "chopped" << filename << "to" << path << "Was trash, is" << typeName; } dbgUI << localFilePath() << "type:" << typeName; QString importedFile = localFilePath(); setFileProgressUpdater(i18n("Opening Document")); if (!isNativeFormat(typeName.toLatin1())) { KisImportExportFilter::ConversionStatus status; - importedFile = d->filterManager->importDocument(localFilePath(), typeName, status); + importedFile = d->importExportManager->importDocument(localFilePath(), typeName, status); if (status != KisImportExportFilter::OK) { QApplication::restoreOverrideCursor(); QString msg = KisImportExportFilter::conversionStatusString(status); if (d->autoErrorHandlingEnabled && !msg.isEmpty()) { QString errorMsg(i18n("Could not open %2.\nReason: %1.\n%3", msg, prettyPathOrUrl(), errorMessage())); QMessageBox::critical(0, i18nc("@title:window", "Krita"), errorMsg); } d->isLoading = false; clearFileProgressUpdater(); return false; } d->isEmpty = false; //qDebug() << "importedFile" << importedFile << "status:" << static_cast(status); } QApplication::restoreOverrideCursor(); bool ok = true; if (!importedFile.isEmpty()) { // Something to load (tmp or native file) ? // The filter, if any, has been applied. It's all native format now. if (!loadNativeFormat(importedFile)) { ok = false; if (d->autoErrorHandlingEnabled) { showLoadingErrorDialog(); } } } if (importedFile != localFilePath()) { // We opened a temporary file (result of an import filter) // Set document URL to empty - we don't want to save in /tmp ! // But only if in readwrite mode (no saving problem otherwise) // -- // But this isn't true at all. If this is the result of an // import, then importedFile=temporary_file.kwd and // file/m_url=foreignformat.ext so m_url is correct! // So don't resetURL() or else the caption won't be set when // foreign files are opened (an annoying bug). // - Clarence // #if 0 if (isReadWrite()) resetURL(); #endif // remove temp file - uncomment this to debug import filters if (!importedFile.isEmpty()) { #ifndef NDEBUG if (!getenv("CALLIGRA_DEBUG_FILTERS")) #endif QFile::remove(importedFile); } } if (ok) { setMimeTypeAfterLoading(typeName); emit sigLoadingFinished(); } if (!d->suppressProgress && d->progressUpdater) { QPointer updater = d->progressUpdater->startSubtask(1, "clear undo stack"); updater->setProgress(0); undoStack()->clear(); updater->setProgress(100); clearFileProgressUpdater(); } else { undoStack()->clear(); } d->isLoading = false; return ok; } KoProgressUpdater *KisDocument::progressUpdater() const { return d->progressUpdater; } void KisDocument::setProgressProxy(KoProgressProxy *progressProxy) { d->progressProxy = progressProxy; } KoProgressProxy* KisDocument::progressProxy() const { if (!d->progressProxy) { KisMainWindow *mainWindow = 0; if (KisPart::instance()->mainwindowCount() > 0) { mainWindow = KisPart::instance()->mainWindows()[0]; } d->progressProxy = new DocumentProgressProxy(mainWindow); } return d->progressProxy; } // shared between openFile and koMainWindow's "create new empty document" code void KisDocument::setMimeTypeAfterLoading(const QString& mimeType) { d->mimeType = mimeType.toLatin1(); d->outputMimeType = d->mimeType; const bool needConfirm = !isNativeFormat(d->mimeType); setConfirmNonNativeSave(false, needConfirm); setConfirmNonNativeSave(true, needConfirm); } // The caller must call store->close() if loadAndParse returns true. bool KisDocument::oldLoadAndParse(KoStore *store, const QString& filename, KoXmlDocument& doc) { //dbgUI <<"Trying to open" << filename; if (!store->open(filename)) { warnUI << "Entry " << filename << " not found!"; d->lastErrorMessage = i18n("Could not find %1", filename); return false; } // Error variables for QDomDocument::setContent QString errorMsg; int errorLine, errorColumn; bool ok = doc.setContent(store->device(), &errorMsg, &errorLine, &errorColumn); store->close(); if (!ok) { errUI << "Parsing error in " << filename << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg << endl; d->lastErrorMessage = i18n("Parsing error in %1 at line %2, column %3\nError message: %4" , filename , errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0, QCoreApplication::UnicodeUTF8)); return false; } dbgUI << "File" << filename << " loaded and parsed"; return true; } bool KisDocument::loadNativeFormat(const QString & file_) { QString file = file_; QFileInfo fileInfo(file); if (!fileInfo.exists()) { // check duplicated from openUrl, but this is useful for templates d->lastErrorMessage = i18n("The file %1 does not exist.", file); return false; } if (!fileInfo.isFile()) { file += "/content.xml"; QFileInfo fileInfo2(file); if (!fileInfo2.exists() || !fileInfo2.isFile()) { d->lastErrorMessage = i18n("%1 is not a file." , file_); return false; } } QApplication::setOverrideCursor(Qt::WaitCursor); dbgUI << file; QFile in; bool isRawXML = false; if (d->specialOutputFlag != SaveAsDirectoryStore) { // Don't try to open a directory ;) in.setFileName(file); if (!in.open(QIODevice::ReadOnly)) { QApplication::restoreOverrideCursor(); d->lastErrorMessage = i18n("Could not open the file for reading (check read permissions)."); return false; } char buf[6]; buf[5] = 0; int pos = 0; do { if (in.read(buf + pos , 1) < 1) { QApplication::restoreOverrideCursor(); in.close(); d->lastErrorMessage = i18n("Could not read the beginning of the file."); return false; } if (QChar(buf[pos]).isSpace()) continue; pos++; } while (pos < 5); isRawXML = (qstrnicmp(buf, "lastErrorMessage = i18n("parsing error in the main document at line %1, column %2\nError message: %3", errorLine, errorColumn, i18n(errorMsg.toUtf8())); res = false; } QApplication::restoreOverrideCursor(); in.close(); d->isEmpty = false; return res; } else { // It's a calligra store (tar.gz, zip, directory, etc.) in.close(); KoStore::Backend backend = (d->specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto; KoStore *store = KoStore::createStore(file, KoStore::Read, "", backend); if (store->bad()) { d->lastErrorMessage = i18n("Not a valid Krita file: %1", file); delete store; QApplication::restoreOverrideCursor(); return false; } // Remember that the file was encrypted if (d->specialOutputFlag == 0 && store->isEncrypted() && !d->isImporting) d->specialOutputFlag = SaveEncrypted; const bool success = loadNativeFormatFromStoreInternal(store); // Retrieve the password after loading the file, only then is it guaranteed to exist if (success && store->isEncrypted() && !d->isImporting) d->password = store->password(); delete store; return success; } } bool KisDocument::loadNativeFormatFromByteArray(QByteArray &data) { bool succes; KoStore::Backend backend = (d->specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto; QBuffer buffer(&data); KoStore *store = KoStore::createStore(&buffer, KoStore::Read, "", backend); if (store->bad()) { delete store; return false; } // Remember that the file was encrypted if (d->specialOutputFlag == 0 && store->isEncrypted() && !d->isImporting) d->specialOutputFlag = SaveEncrypted; succes = loadNativeFormatFromStoreInternal(store); // Retrieve the password after loading the file, only then is it guaranteed to exist if (succes && store->isEncrypted() && !d->isImporting) d->password = store->password(); delete store; return succes; } bool KisDocument::loadNativeFormatFromStoreInternal(KoStore *store) { if (store->hasFile("root") || store->hasFile("maindoc.xml")) { // Fallback to "old" file format (maindoc.xml) KoXmlDocument doc = KoXmlDocument(true); bool ok = oldLoadAndParse(store, "root", doc); if (ok) ok = loadXML(doc, store); if (!ok) { QApplication::restoreOverrideCursor(); return false; } } else { errUI << "ERROR: No maindoc.xml" << endl; d->lastErrorMessage = i18n("Invalid document: no file 'maindoc.xml'."); QApplication::restoreOverrideCursor(); return false; } if (store->hasFile("documentinfo.xml")) { KoXmlDocument doc = KoXmlDocument(true); if (oldLoadAndParse(store, "documentinfo.xml", doc)) { d->docInfo->load(doc); } } else { //dbgUI <<"cannot open document info"; delete d->docInfo; d->docInfo = new KoDocumentInfo(this); } bool res = completeLoading(store); QApplication::restoreOverrideCursor(); d->isEmpty = false; return res; } // For embedded documents bool KisDocument::loadFromStore(KoStore *_store, const QString& url) { if (_store->open(url)) { KoXmlDocument doc = KoXmlDocument(true); doc.setContent(_store->device()); if (!loadXML(doc, _store)) { _store->close(); return false; } _store->close(); } else { dbgKrita << "couldn't open " << url; } _store->pushDirectory(); // Store as document URL if (url.startsWith(STORE_PROTOCOL)) { setUrl(QUrl::fromUserInput(url)); } else { setUrl(QUrl(INTERNAL_PREFIX + url)); _store->enterDirectory(url); } bool result = completeLoading(_store); // Restore the "old" path _store->popDirectory(); return result; } bool KisDocument::loadOdf(KoOdfReadStore & odfStore) { Q_UNUSED(odfStore); setErrorMessage(i18n("Krita does not support the OpenDocument file format.")); return false; } bool KisDocument::saveOdf(SavingContext &documentContext) { Q_UNUSED(documentContext); setErrorMessage(i18n("Krita does not support the OpenDocument file format.")); return false; } bool KisDocument::isStoredExtern() const { return !storeInternal() && hasExternURL(); } void KisDocument::setModified() { d->modified = true; } void KisDocument::setModified(bool mod) { if (mod) { updateEditingTime(false); } if (d->isAutosaving) // ignore setModified calls due to autosaving return; if ( !d->readwrite && d->modified ) { errKrita << "Can't set a read-only document to 'modified' !" << endl; return; } //dbgUI<<" url:" << url.path(); //dbgUI<<" mod="<docInfo->aboutInfo("editing-time").toInt() + d->firstMod.secsTo(d->lastMod))); d->firstMod = now; } else if (firstModDelta > 60 || forceStoreElapsed) { d->docInfo->setAboutInfo("editing-time", QString::number(d->docInfo->aboutInfo("editing-time").toInt() + firstModDelta)); d->firstMod = now; } d->lastMod = now; } QString KisDocument::prettyPathOrUrl() const { QString _url(url().toDisplayString()); #ifdef Q_OS_WIN if (url().isLocalFile()) { _url = QDir::toNativeSeparators(_url); } #endif return _url; } // Get caption from document info (title(), in about page) QString KisDocument::caption() const { QString c; if (documentInfo()) { c = documentInfo()->aboutInfo("title"); } const QString _url(url().fileName()); if (!c.isEmpty() && !_url.isEmpty()) { c = QString("%1 - %2").arg(c).arg(_url); } else if (c.isEmpty()) { c = _url; // Fall back to document URL } return c; } void KisDocument::setTitleModified() { emit titleModified(caption(), isModified()); } bool KisDocument::completeLoading(KoStore* store) { if (!d->image) { if (d->kraLoader->errorMessages().isEmpty()) { setErrorMessage(i18n("Unknown error.")); } else { setErrorMessage(d->kraLoader->errorMessages().join(".\n")); } return false; } d->kraLoader->loadKeyframes(store, url().url(), isStoredExtern()); + d->image->blockUpdates(); d->kraLoader->loadBinaryData(store, d->image, url().url(), isStoredExtern()); - + d->image->unblockUpdates(); bool retval = true; if (!d->kraLoader->errorMessages().isEmpty()) { setErrorMessage(d->kraLoader->errorMessages().join(".\n")); retval = false; } if (retval) { vKisNodeSP preselectedNodes = d->kraLoader->selectedNodes(); if (preselectedNodes.size() > 0) { d->preActivatedNode = preselectedNodes.first(); } // before deleting the kraloader, get the list with preloaded assistants and save it d->assistants = d->kraLoader->assistants(); d->shapeController->setImage(d->image); connect(d->image.data(), SIGNAL(sigImageModified()), this, SLOT(setImageModified())); if (d->image) { d->image->initialRefreshGraph(); } setAutoSave(KisConfig().autoSaveInterval()); emit sigLoadingFinished(); } delete d->kraLoader; d->kraLoader = 0; return retval; - } bool KisDocument::completeSaving(KoStore* store) { d->kraSaver->saveKeyframes(store, url().url(), isStoredExtern()); d->kraSaver->saveBinaryData(store, d->image, url().url(), isStoredExtern(), d->isAutosaving); bool retval = true; if (!d->kraSaver->errorMessages().isEmpty()) { setErrorMessage(d->kraSaver->errorMessages().join(".\n")); retval = false; } delete d->kraSaver; d->kraSaver = 0; emit sigSavingFinished(); return retval; } QDomDocument KisDocument::createDomDocument(const QString& tagName, const QString& version) const { return createDomDocument("krita", tagName, version); } //static QDomDocument KisDocument::createDomDocument(const QString& appName, const QString& tagName, const QString& version) { QDomImplementation impl; QString url = QString("http://www.calligra.org/DTD/%1-%2.dtd").arg(appName).arg(version); QDomDocumentType dtype = impl.createDocumentType(tagName, QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version), url); // The namespace URN doesn't need to include the version number. QString namespaceURN = QString("http://www.calligra.org/DTD/%1").arg(appName); QDomDocument doc = impl.createDocument(namespaceURN, tagName, dtype); doc.insertBefore(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), doc.documentElement()); return doc; } bool KisDocument::loadXML(const KoXmlDocument& doc, KoStore *store) { Q_UNUSED(store); if (d->image) { d->shapeController->setImage(0); d->image = 0; } KoXmlElement root; KoXmlNode node; KisImageSP image; if (doc.doctype().name() != "DOC") { setErrorMessage(i18n("The format is not supported or the file is corrupted")); return false; } root = doc.documentElement(); int syntaxVersion = root.attribute("syntaxVersion", "3").toInt(); if (syntaxVersion > 2) { setErrorMessage(i18n("The file is too new for this version of Krita (%1).", syntaxVersion)); return false; } if (!root.hasChildNodes()) { setErrorMessage(i18n("The file has no layers.")); return false; } if (d->kraLoader) delete d->kraLoader; d->kraLoader = new KisKraLoader(this, syntaxVersion); // Legacy from the multi-image .kra file period. for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isElement()) { if (node.nodeName() == "IMAGE") { KoXmlElement elem = node.toElement(); if (!(image = d->kraLoader->loadXML(elem))) { if (d->kraLoader->errorMessages().isEmpty()) { setErrorMessage(i18n("Unknown error.")); } else { setErrorMessage(d->kraLoader->errorMessages().join(".\n")); } return false; } } else { if (d->kraLoader->errorMessages().isEmpty()) { setErrorMessage(i18n("The file does not contain an image.")); } return false; } } } if (d->image) { // Disconnect existing sig/slot connections d->image->disconnect(this); } d->setImageAndInitIdleWatcher(image); return true; } QDomDocument KisDocument::saveXML() { dbgFile << url(); QDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION); QDomElement root = doc.documentElement(); root.setAttribute("editor", "Krita"); root.setAttribute("syntaxVersion", "2"); if (d->kraSaver) delete d->kraSaver; d->kraSaver = new KisKraSaver(this); root.appendChild(d->kraSaver->saveXML(doc, d->image)); if (!d->kraSaver->errorMessages().isEmpty()) { setErrorMessage(d->kraSaver->errorMessages().join(".\n")); } return doc; } bool KisDocument::isNativeFormat(const QByteArray& mimetype) const { if (mimetype == nativeFormatMimeType()) return true; return extraNativeMimeTypes().contains(mimetype); } int KisDocument::supportedSpecialFormats() const { return 0; // we don't support encryption. } void KisDocument::setErrorMessage(const QString& errMsg) { d->lastErrorMessage = errMsg; } QString KisDocument::errorMessage() const { return d->lastErrorMessage; } void KisDocument::showLoadingErrorDialog() { if (errorMessage().isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not open\n%1", localFilePath())); } - else if (errorMessage() != "USER_CANCELED") { + else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not open %1\nReason: %2", localFilePath(), errorMessage())); } } bool KisDocument::isLoading() const { return d->isLoading; } void KisDocument::removeAutoSaveFiles() { // Eliminate any auto-save file QString asf = autoSaveFile(localFilePath()); // the one in the current dir if (QFile::exists(asf)) QFile::remove(asf); asf = autoSaveFile(QString()); // and the one in $HOME if (QFile::exists(asf)) QFile::remove(asf); } void KisDocument::setBackupFile(bool _b) { d->backupFile = _b; } bool KisDocument::backupFile()const { return d->backupFile; } void KisDocument::setBackupPath(const QString & _path) { d->backupPath = _path; } QString KisDocument::backupPath()const { return d->backupPath; } bool KisDocument::storeInternal() const { return d->storeInternal; } void KisDocument::setStoreInternal(bool i) { d->storeInternal = i; //dbgUI<<"="<storeInternal<<" doc:"<pageLayout; } void KisDocument::setPageLayout(const KoPageLayout &pageLayout) { d->pageLayout = pageLayout; } KoUnit KisDocument::unit() const { return d->unit; } void KisDocument::setUnit(const KoUnit &unit) { if (d->unit != unit) { d->unit = unit; emit unitChanged(unit); } } KUndo2Stack *KisDocument::undoStack() { return d->undoStack; } +KisImportExportManager *KisDocument::importExportManager() const +{ + return d->importExportManager; +} + void KisDocument::addCommand(KUndo2Command *command) { if (command) d->undoStack->push(command); } void KisDocument::beginMacro(const KUndo2MagicString & text) { d->undoStack->beginMacro(text); } void KisDocument::endMacro() { d->undoStack->endMacro(); } void KisDocument::slotUndoStackIndexChanged(int idx) { // even if the document was already modified, call setModified to re-start autosave timer setModified(idx != d->undoStack->cleanIndex()); } void KisDocument::clearUndoHistory() { d->undoStack->clear(); } KisGridConfig KisDocument::gridConfig() const { return d->gridConfig; } void KisDocument::setGridConfig(const KisGridConfig &config) { d->gridConfig = config; } const KisGuidesConfig& KisDocument::guidesConfig() const { return d->guidesConfig; } void KisDocument::setGuidesConfig(const KisGuidesConfig &data) { if (d->guidesConfig == data) return; d->guidesConfig = data; emit sigGuidesConfigChanged(d->guidesConfig); } bool KisDocument::isEmpty() const { return d->isEmpty; } void KisDocument::setEmpty() { d->isEmpty = true; } // static int KisDocument::defaultAutoSave() { return 300; } void KisDocument::resetURL() { setUrl(QUrl()); setLocalFilePath(QString()); } int KisDocument::pageCount() const { return 1; } KoDocumentInfoDlg *KisDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const { return new KoDocumentInfoDlg(parent, docInfo); } bool KisDocument::isReadWrite() const { return d->readwrite; } QUrl KisDocument::url() const { return d->m_url; } bool KisDocument::closeUrl(bool promptToSave) { if (promptToSave) { if ( d->document->isReadWrite() && d->document->isModified()) { Q_FOREACH (KisView *view, KisPart::instance()->views()) { if (view && view->document() == this) { if (!view->queryClose()) { return false; } } } } } // Not modified => ok and delete temp file. d->mimeType = QByteArray(); if ( d->m_bTemp ) { QFile::remove( d->m_file ); d->m_bTemp = false; } // It always succeeds for a read-only part, // but the return value exists for reimplementations // (e.g. pressing cancel for a modified read-write part) return true; } -bool KisDocument::saveAs(const QUrl &kurl) +bool KisDocument::saveAs(const QUrl &kurl, KisPropertiesConfigurationSP exportConfiguration) { if (!kurl.isValid()) { errKrita << "saveAs: Malformed URL " << kurl.url() << endl; return false; } d->m_duringSaveAs = true; d->m_originalURL = d->m_url; d->m_originalFilePath = d->m_file; d->m_url = kurl; // Store where to upload in saveToURL d->prepareSaving(); - bool result = save(); // Save local file and upload local file + bool result = save(exportConfiguration); // Save local file and upload local file if (!result) { d->m_url = d->m_originalURL; d->m_file = d->m_originalFilePath; d->m_duringSaveAs = false; d->m_originalURL = QUrl(); d->m_originalFilePath.clear(); } return result; } - - - -bool KisDocument::save() +bool KisDocument::save(KisPropertiesConfigurationSP exportConfiguration) { qDebug() << "Saving!"; d->m_saveOk = false; if ( d->m_file.isEmpty() ) { // document was created empty d->prepareSaving(); } updateEditingTime(true); d->document->setFileProgressProxy(); d->document->setUrl(url()); - bool ok = d->document->saveFile(); + bool ok = d->document->saveFile(exportConfiguration); d->document->clearFileProgressProxy(); if (ok) { return saveToUrl(); } else { emit canceled(QString()); } return false; } bool KisDocument::waitSaveComplete() { return d->m_saveOk; } void KisDocument::setUrl(const QUrl &url) { d->m_url = url; } QString KisDocument::localFilePath() const { return d->m_file; } void KisDocument::setLocalFilePath( const QString &localFilePath ) { d->m_file = localFilePath; } bool KisDocument::saveToUrl() { if ( d->m_url.isLocalFile() ) { d->document->setModified( false ); emit completed(); // if m_url is a local file there won't be a temp file -> nothing to remove Q_ASSERT( !d->m_bTemp ); d->m_saveOk = true; d->m_duringSaveAs = false; d->m_originalURL = QUrl(); d->m_originalFilePath.clear(); return true; // Nothing to do } return false; } bool KisDocument::openUrlInternal(const QUrl &url) { if ( !url.isValid() ) return false; if (d->m_bAutoDetectedMime) { d->mimeType = QByteArray(); d->m_bAutoDetectedMime = false; } QByteArray mimetype = d->mimeType; if ( !closeUrl() ) return false; d->mimeType = mimetype; setUrl(url); d->m_file.clear(); if (d->m_url.isLocalFile()) { d->m_file = d->m_url.toLocalFile(); return d->openLocalFile(); } return false; } KisImageWSP KisDocument::newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace* colorspace) { KoColor backgroundColor(Qt::white, colorspace); /** * FIXME: check whether this is a good value */ double defaultResolution=1.; newImage(name, width, height, colorspace, backgroundColor, "", defaultResolution); return image(); } bool KisDocument::newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * cs, const KoColor &bgColor, const QString &imageDescription, const double imageResolution) { return newImage(name, width, height, cs, bgColor, false, 1, imageDescription, imageResolution); } bool KisDocument::newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace* cs, const KoColor &bgColor, bool backgroundAsLayer, int numberOfLayers, const QString &description, const double imageResolution) { Q_ASSERT(cs); KisConfig cfg; KisImageSP image; KisPaintLayerSP layer; if (!cs) return false; QApplication::setOverrideCursor(Qt::BusyCursor); image = new KisImage(createUndoStore(), width, height, cs, name); Q_CHECK_PTR(image); connect(image.data(), SIGNAL(sigImageModified()), this, SLOT(setImageModified())); image->setResolution(imageResolution, imageResolution); image->assignImageProfile(cs->profile()); documentInfo()->setAboutInfo("title", name); if (name != i18n("Unnamed") && !name.isEmpty()) { setUrl(QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation) + '/' + name + ".kra")); } documentInfo()->setAboutInfo("abstract", description); layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, cs); Q_CHECK_PTR(layer); if (backgroundAsLayer) { image->setDefaultProjectionColor(KoColor(cs)); if (bgColor.opacityU8() == OPACITY_OPAQUE_U8) { layer->paintDevice()->setDefaultPixel(bgColor); } else { // Hack: with a semi-transparent background color, the projection isn't composited right if we just set the default pixel KisFillPainter painter; painter.begin(layer->paintDevice()); painter.fillRect(0, 0, width, height, bgColor, bgColor.opacityU8()); } } else { image->setDefaultProjectionColor(bgColor); } layer->setDirty(QRect(0, 0, width, height)); image->addNode(layer.data(), image->rootLayer().data()); setCurrentImage(image); for(int i = 1; i < numberOfLayers; ++i) { KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8, cs); image->addNode(layer, image->root(), i); layer->setDirty(QRect(0, 0, width, height)); } cfg.defImageWidth(width); cfg.defImageHeight(height); cfg.defImageResolution(imageResolution); cfg.defColorModel(image->colorSpace()->colorModelId().id()); cfg.setDefaultColorDepth(image->colorSpace()->colorDepthId().id()); cfg.defColorProfile(image->colorSpace()->profile()->name()); QApplication::restoreOverrideCursor(); return true; } KoShapeBasedDocumentBase *KisDocument::shapeController() const { return d->shapeController; } KoShapeLayer* KisDocument::shapeForNode(KisNodeSP layer) const { return d->shapeController->shapeForNode(layer); } vKisNodeSP KisDocument::activeNodes() const { vKisNodeSP nodes; Q_FOREACH (KisView *v, KisPart::instance()->views()) { if (v->document() == this && v->viewManager()) { KisNodeSP activeNode = v->viewManager()->activeNode(); if (activeNode && !nodes.contains(activeNode)) { if (activeNode->inherits("KisMask")) { activeNode = activeNode->parent(); } nodes.append(activeNode); } } } return nodes; } QList KisDocument::assistants() const { return d->assistants; } void KisDocument::setAssistants(const QList value) { d->assistants = value; } void KisDocument::setPreActivatedNode(KisNodeSP activatedNode) { d->preActivatedNode = activatedNode; } KisNodeSP KisDocument::preActivatedNode() const { return d->preActivatedNode; } void KisDocument::prepareForImport() { /* TODO: remove this function? I kept it because it might be useful for * other kind of preparing, but currently it was checking on d->nserver * being null and then calling init() if it was, but the document is always * initialized in the constructor (and init() does other things too). * Moreover, nserver cannot be nulled by some external call.*/ } void KisDocument::setFileProgressUpdater(const QString &text) { - d->suppressProgress = d->filterManager->getBatchMode(); + d->suppressProgress = d->importExportManager->getBatchMode(); if (!d->suppressProgress) { d->progressUpdater = new KoProgressUpdater(d->progressProxy, KoProgressUpdater::Unthreaded); d->progressUpdater->start(100, text); - d->filterManager->setProgresUpdater(d->progressUpdater); + d->importExportManager->setProgresUpdater(d->progressUpdater); connect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int))); connect(KisPart::instance()->currentMainwindow(), SIGNAL(sigProgressCanceled()), this, SIGNAL(sigProgressCanceled())); } } void KisDocument::clearFileProgressUpdater() { if (!d->suppressProgress && d->progressUpdater) { disconnect(KisPart::instance()->currentMainwindow(), SIGNAL(sigProgressCanceled()), this, SIGNAL(sigProgressCanceled())); disconnect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int))); delete d->progressUpdater; - d->filterManager->setProgresUpdater(0); + d->importExportManager->setProgresUpdater(0); d->progressUpdater = 0; } } void KisDocument::setFileProgressProxy() { - if (!d->progressProxy && !d->filterManager->getBatchMode()) { + if (!d->progressProxy && !d->importExportManager->getBatchMode()) { d->fileProgressProxy = progressProxy(); } else { d->fileProgressProxy = 0; } } void KisDocument::clearFileProgressProxy() { if (d->fileProgressProxy) { setProgressProxy(0); delete d->fileProgressProxy; d->fileProgressProxy = 0; } } KisImageWSP KisDocument::image() const { return d->image; } void KisDocument::setCurrentImage(KisImageSP image) { if (!image) return; if (d->image) { // Disconnect existing sig/slot connections d->image->disconnect(this); d->shapeController->setImage(0); } d->setImageAndInitIdleWatcher(image); d->shapeController->setImage(image); setModified(false); connect(d->image, SIGNAL(sigImageModified()), this, SLOT(setImageModified())); d->image->initialRefreshGraph(); setAutoSave(KisConfig().autoSaveInterval()); } void KisDocument::initEmpty() { KisConfig cfg; const KoColorSpace * rgb = KoColorSpaceRegistry::instance()->rgb8(); newImage("", cfg.defImageWidth(), cfg.defImageHeight(), rgb); } void KisDocument::setImageModified() { setModified(true); } KisUndoStore* KisDocument::createUndoStore() { return new KisDocumentUndoStore(this); } bool KisDocument::isAutosaving() const { return d->isAutosaving; } diff --git a/libs/ui/KisDocument.h b/libs/ui/KisDocument.h index c0ec301a17..e0380ee336 100644 --- a/libs/ui/KisDocument.h +++ b/libs/ui/KisDocument.h @@ -1,822 +1,828 @@ /* This file is part of the Krita project * * Copyright (C) 2014 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISDOCUMENT_H #define KISDOCUMENT_H #include #include #include #include #include #include #include +#include #include #include #include #include "kritaui_export.h" class QString; class KUndo2Command; class KoUnit; class KoColor; class KoColorSpace; class KoShapeBasedDocumentBase; class KoShapeLayer; class KoStore; class KoOdfReadStore; class KoDocumentInfo; class KoProgressUpdater; class KoProgressProxy; class KoDocumentInfoDlg; - +class KisImportExportManager; class KisUndoStore; class KisPaintingAssistant; class KisPart; class KisGridConfig; class KisGuidesConfig; class QDomDocument; class KisPart; #define KIS_MIME_TYPE "application/x-krita" /** * The %Calligra document class * * This class provides some functionality each %Calligra document should have. * * @short The %Calligra document class */ class KRITAUI_EXPORT KisDocument : public QObject, public KoDocumentBase { Q_OBJECT Q_PROPERTY(bool backupFile READ backupFile WRITE setBackupFile) Q_PROPERTY(int pageCount READ pageCount) protected: explicit KisDocument(); public: enum OpenUrlFlags { OPEN_URL_FLAG_NONE = 1 << 0, OPEN_URL_FLAG_DO_NOT_ADD_TO_RECENT_FILES = 1 << 1, }; /** * Destructor. * * The destructor does not delete any attached KisView objects and it does not * delete the attached widget as returned by widget(). */ virtual ~KisDocument(); /** * @brief reload Reloads the document from the original url * @return the result of loading the document */ bool reload(); /** * @brief openUrl Open an URL * @param url The URL to open * @param flags Control specific behavior * @return success status */ bool openUrl(const QUrl &url, OpenUrlFlags flags = OPEN_URL_FLAG_NONE); /** * Opens the document given by @p url, without storing the URL * in the KisDocument. * Call this instead of openUrl() to implement KisMainWindow's * File --> Import feature. * * @note This will call openUrl(). To differentiate this from an ordinary * Open operation (in any reimplementation of openUrl() or openFile()) * call isImporting(). */ bool importDocument(const QUrl &url); /** * Saves the document as @p url without changing the state of the * KisDocument (URL, modified flag etc.). Call this instead of * KisParts::ReadWritePart::saveAs() to implement KisMainWindow's * File --> Export feature. * * @note This will call KisDocument::saveAs(). To differentiate this * from an ordinary Save operation (in any reimplementation of * saveFile()) call isExporting(). */ - bool exportDocument(const QUrl &url); + bool exportDocument(const QUrl &url, KisPropertiesConfigurationSP exportConfiguration = 0); /** * @brief Sets whether the document can be edited or is read only. * * This recursively applied to all child documents and * KisView::updateReadWrite is called for every attached * view. */ void setReadWrite(bool readwrite = true); /** * To be preferred when a document exists. It is fast when calling * it multiple times since it caches the result that readNativeFormatMimeType() * delivers. * This comes from the X-KDE-NativeMimeType key in the .desktop file. */ static QByteArray nativeFormatMimeType() { return KIS_MIME_TYPE; } /// Checks whether a given mimetype can be handled natively. bool isNativeFormat(const QByteArray& mimetype) const; /// Returns a list of the mimetypes considered "native", i.e. which can /// be saved by KisDocument without a filter, in *addition* to the main one static QStringList extraNativeMimeTypes() { return QStringList() << KIS_MIME_TYPE; } /// Enum values used by specialOutputFlag - note that it's a bitfield for supportedSpecialFormats enum { /*SaveAsCalligra1dot1 = 1,*/ // old and removed SaveAsDirectoryStore = 2, SaveAsFlatXML = 4, SaveEncrypted = 8 // bitfield! next value is 16 }; /** * Return the set of SupportedSpecialFormats that the application wants to * offer in the "Save" file dialog. */ virtual int supportedSpecialFormats() const; /** * Returns the actual mimetype of the document */ QByteArray mimeType() const; /** * @brief Sets the mime type for the document. * * When choosing "save as" this is also the mime type * selected by default. */ void setMimeType(const QByteArray & mimeType); /** * @brief Set the format in which the document should be saved. * * This is called on loading, and in "save as", so you shouldn't * have to call it. * * @param mimeType the mime type (format) to use. * @param specialOutputFlag is for "save as older version" etc. */ void setOutputMimeType(const QByteArray & mimeType, int specialOutputFlag = 0); QByteArray outputMimeType() const; int specialOutputFlag() const; /** * Returns true if this document was the result of opening a foreign * file format and if the user hasn't yet saved the document (in any * format). * * Used by KisMainWindow to warn the user when s/he lazily presses * CTRL+S to save in the same foreign format, putting all his/her * formatting at risk (normally an export confirmation only comes up * with Save As). * * @param exporting specifies whether this is the setting for a * File --> Export or File --> Save/Save As operation. */ bool confirmNonNativeSave(const bool exporting) const; void setConfirmNonNativeSave(const bool exporting, const bool on); /** * @return true if file operations should inhibit the option dialog */ bool fileBatchMode() const; /** * @param batchMode if true, do not show the option dialog for file operations. */ void setFileBatchMode(const bool batchMode); /** * Sets the error message to be shown to the user (use i18n()!) * when loading or saving fails. * If you asked the user about something and they chose "Cancel", - * set the message to the magic string "USER_CANCELED", to skip the error dialog. */ void setErrorMessage(const QString& errMsg); /** * Return the last error message. Usually KisDocument takes care of * showing it; this method is mostly provided for non-interactive use. */ QString errorMessage() const; /** * Show the last error message in a message box. * The dialog box will mention a loading problem. * openUrl/openFile takes care of doing it, but not loadNativeFormat itself, * so this is often called after loadNativeFormat returned false. */ void showLoadingErrorDialog(); /** * @brief Generates a preview picture of the document * @note The preview is used in the File Dialog and also to create the Thumbnail */ QPixmap generatePreview(const QSize& size); /** * Tells the document that its title has been modified, either because * the modified status changes (this is done by setModified() ) or * because the URL or the document-info's title changed. */ void setTitleModified(); /** * @return true if the document is empty. */ virtual bool isEmpty() const; /** * @brief Sets the document to empty. * * Used after loading a template * (which is not empty, but not the user's input). * * @see isEmpty() */ void setEmpty(); /** * @brief Loads a document from a store. * * You should never have to reimplement. * * @param store The store to load from * @param url An internal url, like tar:/1/2 */ bool loadFromStore(KoStore *store, const QString& url); /// Unused virtual bool loadOdf(KoOdfReadStore & odfStore); /// Unused virtual bool saveOdf(SavingContext &documentContext); /** * @brief Saves a sub-document to a store. * * You should not have to reimplement this. */ virtual bool saveToStore(KoStore *store, const QString& path); /** * Reimplement this method to load the contents of your Calligra document, * from the XML document. This is for the pre-Oasis file format (maindoc.xml). */ virtual bool loadXML(const KoXmlDocument & doc, KoStore *store); /** * Reimplement this to save the contents of the %Calligra document into * a QDomDocument. The framework takes care of saving it to the store. */ QDomDocument saveXML(); /** * Return a correctly created QDomDocument for this KisDocument, * including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element. * @param tagName the name of the tag for the root element * @param version the DTD version (usually the application's version). */ QDomDocument createDomDocument(const QString& tagName, const QString& version) const; /** * Return a correctly created QDomDocument for an old (1.3-style) %Calligra document, * including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element. * This static method can be used e.g. by filters. * @param appName the app's instance name, e.g. words, kspread, kpresenter etc. * @param tagName the name of the tag for the root element, e.g. DOC for words/kpresenter. * @param version the DTD version (usually the application's version). */ static QDomDocument createDomDocument(const QString& appName, const QString& tagName, const QString& version); /** * The first thing to do in loadOasis is get hold of the office:body tag, then its child. * If the child isn't the expected one, the error message can indicate what it is instead. * This method returns a translated name for the type of document, * e.g. i18n("Word Processing") for office:text. */ static QString tagNameToDocumentType(const QString& localName); /** * Loads a document in the native format from a given URL. * Reimplement if your native format isn't XML. * * @param file the file to load - usually KReadOnlyPart::m_file or the result of a filter */ bool loadNativeFormat(const QString & file); /** * Saves the document in native format, to a given file * You should never have to reimplement. * Made public for writing templates. */ bool saveNativeFormat(const QString & file); /** * Saves the document in the native format to the given store. */ bool saveNativeFormatCalligra(KoStore *store); /** * Activate/deactivate/configure the autosave feature. * @param delay in seconds, 0 to disable */ void setAutoSave(int delay); /** * Set whether the next openUrl call should show error message boxes in case * of errors. This is usually the case, but e.g. not when generating thumbnail * previews. */ void setAutoErrorHandlingEnabled(bool b); /** * Checks whether error message boxes should be shown. */ bool isAutoErrorHandlingEnabled() const; /** * Retrieve the default value for autosave in seconds. * Called by the applications to use the correct default in their config */ static int defaultAutoSave(); /** * @return the information concerning this document. * @see KoDocumentInfo */ KoDocumentInfo *documentInfo() const; /** * @return the object to report progress to. * * This is only not zero if loading or saving is in progress. * * One can add more KoUpdaters to it to make the progress reporting more * accurate. If no active progress reporter is present, 0 is returned. **/ KoProgressUpdater *progressUpdater() const; /** * Set a custom progress proxy to use to report loading * progress to. */ void setProgressProxy(KoProgressProxy *progressProxy); KoProgressProxy* progressProxy() const; /** * Return true if url() is a real filename, false if url() is * an internal url in the store, like "tar:/..." */ virtual bool isStoredExtern() const; /** * @return the page layout associated with this document (margins, pageSize, etc). * Override this if you want to provide different sized pages. * * @see KoPageLayout */ KoPageLayout pageLayout(int pageNumber = 0) const; void setPageLayout(const KoPageLayout &pageLayout); /** * Performs a cleanup of unneeded backup files */ void removeAutoSaveFiles(); void setBackupFile(bool _b); bool backupFile()const; /** * Returns true if this document or any of its internal child documents are modified. */ bool isModified() const; /** * Returns true during loading (openUrl can be asynchronous) */ bool isLoading() const; /** * Sets the backup path of the document */ void setBackupPath(const QString & _path); /** * @return path to the backup document */ QString backupPath()const; /** * @return caption of the document * * Caption is of the form "[title] - [url]", * built out of the document info (title) and pretty-printed * document URL. * If the title is not present, only the URL it returned. */ QString caption() const; /** * Sets the document URL to empty URL * KParts doesn't allow this, but %Calligra apps have e.g. templates * After using loadNativeFormat on a template, one wants * to set the url to QUrl() */ void resetURL(); /** * Set when you want an external embedded document to be stored internally */ void setStoreInternal(bool i); /** * @return true when external embedded documents are stored internally */ bool storeInternal() const; bool hasExternURL() const; /** * @internal (public for KisMainWindow) */ void setMimeTypeAfterLoading(const QString& mimeType); /** * @return returns the number of pages in the document. */ virtual int pageCount() const; /** * Returns the unit used to display all measures/distances. */ KoUnit unit() const; /** * Sets the unit used to display all measures/distances. */ void setUnit(const KoUnit &unit); /** * Save the unit to the settings writer * * @param settingsWriter */ bool loadNativeFormatFromByteArray(QByteArray &data); KisGridConfig gridConfig() const; void setGridConfig(const KisGridConfig &config); /// returns the guides data for this document. const KisGuidesConfig& guidesConfig() const; void setGuidesConfig(const KisGuidesConfig &data); void clearUndoHistory(); /** * Sets the modified flag on the document. This means that it has * to be saved or not before deleting it. */ void setModified(bool _mod); void updateEditingTime(bool forceStoreElapsed); /** * Initialize an empty document using default values */ void initEmpty(); /** * Returns the global undo stack */ KUndo2Stack *undoStack(); + /** + * @brief importExportManager gives access to the internal import/export manager + * @return the document's import/export manager + */ + KisImportExportManager *importExportManager() const; + public Q_SLOTS: /** * Adds a command to the undo stack and executes it by calling the redo() function. * @param command command to add to the undo stack */ void addCommand(KUndo2Command *command); /** * Begins recording of a macro command. At the end endMacro needs to be called. * @param text command description */ void beginMacro(const KUndo2MagicString &text); /** * Ends the recording of a macro command. */ void endMacro(); Q_SIGNALS: /** * This signal is emitted when the unit is changed by setUnit(). * It is common to connect views to it, in order to change the displayed units * (e.g. in the rulers) */ void unitChanged(const KoUnit &unit); /** * Progress info while loading or saving. The value is in percents (i.e. a number between 0 and 100) * Your KisDocument-derived class should emit the signal now and then during load/save. * KisMainWindow will take care of displaying a progress bar automatically. */ void sigProgress(int value); /** * Progress cancel button pressed * This is emitted by KisDocument */ void sigProgressCanceled(); /** * Emitted e.g. at the beginning of a save operation * This is emitted by KisDocument and used by KisView to display a statusbar message */ void statusBarMessage(const QString& text); /** * Emitted e.g. at the end of a save operation * This is emitted by KisDocument and used by KisView to clear the statusbar message */ void clearStatusBarMessage(); /** * Emitted when the document is modified */ void modified(bool); void titleModified(const QString &caption, bool isModified); void sigLoadingFinished(); void sigSavingFinished(); void sigGuidesConfigChanged(const KisGuidesConfig &config); private: friend class KisPart; friend class SafeSavingLocker; /** * Generate a name for the document. */ QString newObjectName(); QString autoSaveFile(const QString & path) const; /** * Loads a document * * Applies a filter if necessary, and calls loadNativeFormat in any case * You should not have to reimplement, except for very special cases. * * NOTE: this method also creates a new KisView instance! * * This method is called from the KReadOnlyPart::openUrl method. */ bool openFile(); /** * Saves a document * * Applies a filter if necessary, and calls saveNativeFormat in any case * You should not have to reimplement, except for very special cases. */ - bool saveFile(); + bool saveFile(KisPropertiesConfigurationSP exportConfiguration = 0); /** * Overload this function if you have to load additional files * from a store. This function is called after loadXML() * and after loadChildren() have been called. */ bool completeLoading(KoStore *store); /** * If you want to write additional files to a store, * then you must do it here. * In the implementation, you should prepend the document * url (using url().url()) before the filename, so that everything is kept relative * to this document. For instance it will produce urls such as * tar:/1/pictures/picture0.png, if the doc url is tar:/1 * But do this ONLY if the document is not stored extern (see isStoredExtern() ). * If it is, then the pictures should be saved to tar:/pictures. */ bool completeSaving(KoStore *store); /** @internal */ void setModified(); /** * Returns whether or not the current openUrl() or openFile() call is * actually an import operation (like File --> Import). * This is for informational purposes only. */ bool isImporting() const; /** * Returns whether or not the current saveFile() call is actually an export * operation (like File --> Export). * If this function returns true during saveFile() and you are changing * some sort of state, you _must_ restore it before the end of saveFile(); * otherwise, File --> Export will not work properly. */ bool isExporting() const; /** * Legacy method from KoDocumentBase. Don't use it anywhere * outside KisDocument! */ bool isAutosaving() const; public: QString localFilePath() const; void setLocalFilePath( const QString &localFilePath ); KoDocumentInfoDlg* createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const; bool isReadWrite() const; QUrl url() const; void setUrl(const QUrl &url); bool closeUrl(bool promptToSave = true); - bool saveAs( const QUrl &url ); + bool saveAs(const QUrl &url, KisPropertiesConfigurationSP exportConfigration = 0); public Q_SLOTS: - bool save(); + bool save(KisPropertiesConfigurationSP exportConfiguration = 0); bool waitSaveComplete(); Q_SIGNALS: void completed(); void canceled(const QString &); private Q_SLOTS: void setImageModified(); void slotAutoSave(); /// Called by the undo stack when undo or redo is called void slotUndoStackIndexChanged(int idx); protected: bool oldLoadAndParse(KoStore *store, const QString& filename, KoXmlDocument& doc); public: /** * Create a new image that has this document as a parent and * replace the current image with this image. */ bool newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * cs, const KoColor &bgColor, const QString &imageDescription, const double imageResolution); /** * Create a new image that has this document as a parent and * replace the current image with this image. */ bool newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * cs, const KoColor &bgColor, bool backgroundAsLayer, int numberOfLayers, const QString &imageDescription, const double imageResolution); /** * Create a new image that has this document as a parent and * replace the current image with this image. */ KisImageWSP newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * colorspace); KisImageWSP image() const; /** * Makes an otherwise empty document ready for import/export */ void prepareForImport(); /** * Adds progressproxy for file operations */ void setFileProgressProxy(); /** * Clears progressproxy for file operations */ void clearFileProgressProxy(); /** * Adds progressupdater for file operations */ void setFileProgressUpdater(const QString &text); /** * Clears progressupdater for file operations */ void clearFileProgressUpdater(); /** * Set the current image to the specified image and turn undo on. */ void setCurrentImage(KisImageSP image); KisUndoStore* createUndoStore(); /** * The shape controller matches internal krita image layers with * the flake shape hierarchy. */ KoShapeBasedDocumentBase * shapeController() const; KoShapeLayer* shapeForNode(KisNodeSP layer) const; /** * @return a list of all layers that are active in all current views */ vKisNodeSP activeNodes() const; /** * set the list of nodes that were marked as currently active */ void setPreActivatedNode(KisNodeSP activatedNode); /** * @return the node that was set as active during loading */ KisNodeSP preActivatedNode() const; QList assistants() const; void setAssistants(const QList value); private: void init(); bool saveToStream(QIODevice *dev); bool loadNativeFormatFromStoreInternal(KoStore *store); bool savePreview(KoStore *store); QString prettyPathOrUrl() const; bool saveToUrl(); bool openUrlInternal(const QUrl &url); class Private; Private *const d; }; Q_DECLARE_METATYPE(KisDocument*) #endif diff --git a/libs/ui/KisFilterChain.cpp b/libs/ui/KisFilterChain.cpp index 3ac53f7bdb..2a4e5fe5c8 100644 --- a/libs/ui/KisFilterChain.cpp +++ b/libs/ui/KisFilterChain.cpp @@ -1,350 +1,366 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 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 "KisFilterChain.h" #include "KisImportExportManager.h" // KisImportExportManager::filterAvailable, private API #include "KisDocument.h" #include "KisPart.h" #include "PriorityQueue_p.h" #include "KisFilterGraph.h" #include "KisFilterEdge.h" #include "KisFilterChainLink.h" #include "KisFilterVertex.h" #include #include #include #include // UINT_MAX #include // Those "defines" are needed in the setupConnections method below. // Please always keep the strings and the length in sync! using namespace CalligraFilter; KisFilterChain::KisFilterChain(const KisImportExportManager* manager) : KisShared() , m_manager(manager) , m_state(Beginning) , m_inputDocument(0) , m_outputDocument(0) , m_inputTempFile(0), m_outputTempFile(0) , m_inputQueried(Nil) , m_outputQueried(Nil) , d(0) { } KisFilterChain::~KisFilterChain() { m_chainLinks.deleteAll(); manageIO(); // Called for the 2nd time in a row -> clean up } KisImportExportFilter::ConversionStatus KisFilterChain::invokeChain() { KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; m_state = Beginning; int count = m_chainLinks.count(); // No iterator here, as we need m_chainLinks.current() in outputDocument() m_chainLinks.first(); for (; count > 1 && m_chainLinks.current() && status == KisImportExportFilter::OK; m_chainLinks.next(), --count) { status = m_chainLinks.current()->invokeFilter(); m_state = Middle; manageIO(); } if (!m_chainLinks.current()) { warnFile << "Huh?? Found a null pointer in the chain"; return KisImportExportFilter::StupidError; } if (status == KisImportExportFilter::OK) { if (m_state & Beginning) m_state |= End; else m_state = End; status = m_chainLinks.current()->invokeFilter(); manageIO(); } m_state = Done; if (status == KisImportExportFilter::OK) finalizeIO(); return status; } QString KisFilterChain::chainOutput() const { if (m_state == Done) return m_inputFile; // as we already called manageIO() return QString(); } QString KisFilterChain::inputFile() { if (m_inputQueried == File) return m_inputFile; else if (m_inputQueried != Nil) { warnFile << "You already asked for some different source."; return QString(); } m_inputQueried = File; if (m_state & Beginning) { - if (static_cast(filterManagerDirection()) == - KisImportExportManager::Import) + if (static_cast(filterManagerDirection()) == KisImportExportManager::Import) { m_inputFile = filterManagerImportFile(); - else + } + else { inputFileHelper(filterManagerKisDocument(), filterManagerImportFile()); - } else - if (m_inputFile.isEmpty()) + } + } + else { + if (m_inputFile.isEmpty()) { inputFileHelper(m_inputDocument, QString()); + } + } return m_inputFile; } QString KisFilterChain::outputFile() { - if (m_outputQueried == File) + qDebug() << m_outputQueried << m_outputFile; + + if (m_outputQueried == File) { return m_outputFile; + } + else if (m_outputQueried != Nil) { warnFile << "You already asked for some different destination."; return QString(); } m_outputQueried = File; if (m_state & End) { - if (static_cast(filterManagerDirection()) == - KisImportExportManager::Import) + if (static_cast(filterManagerDirection()) == KisImportExportManager::Import) { outputFileHelper(false); // This (last) one gets deleted by the caller - else + } + else { m_outputFile = filterManagerExportFile(); - } else + } + } + else { outputFileHelper(true); + } return m_outputFile; } +void KisFilterChain::setOutputFile(const QString &outputFile) +{ + m_outputQueried = File; + m_outputFile = outputFile; +} + -KisDocument* KisFilterChain::inputDocument() +KisDocument *KisFilterChain::inputDocument() { - if (m_inputQueried == Document) + if (m_inputQueried == Document) { return m_inputDocument; - else if (m_inputQueried != Nil) { + } + else if (m_inputQueried) { warnFile << "You already asked for some different source."; return 0; } - if ((m_state & Beginning) && - static_cast(filterManagerDirection()) == KisImportExportManager::Export && - filterManagerKisDocument()) { - m_inputDocument = filterManagerKisDocument(); - } - else if (!m_inputDocument) { - m_inputDocument = KisPart::instance()->createDocument(); - } + m_inputDocument = filterManagerKisDocument(); m_inputQueried = Document; return m_inputDocument; } KisDocument* KisFilterChain::outputDocument() { if (m_outputQueried == Document) return m_outputDocument; else if (m_outputQueried != Nil) { warnFile << "You already asked for some different destination."; return 0; } if ((m_state & End) && static_cast(filterManagerDirection()) == KisImportExportManager::Import && filterManagerKisDocument()) m_outputDocument = filterManagerKisDocument(); else m_outputDocument = KisPart::instance()->createDocument(); m_outputQueried = Document; return m_outputDocument; } +KisPropertiesConfigurationSP KisFilterChain::filterManagerExportConfiguration() const +{ + return m_manager->exportConfiguration(); +} + void KisFilterChain::prependChainLink(KisFilterEntrySP filterEntry, const QByteArray& from, const QByteArray& to) { m_chainLinks.prepend(new ChainLink(this, filterEntry, from, to)); } QString KisFilterChain::filterManagerImportFile() const { return m_manager->importFile(); } QString KisFilterChain::filterManagerExportFile() const { return m_manager->exportFile(); } KisDocument* KisFilterChain::filterManagerKisDocument() const { return m_manager->document(); } int KisFilterChain::filterManagerDirection() const { return m_manager->direction(); } void KisFilterChain::manageIO() { m_inputQueried = Nil; m_outputQueried = Nil; delete m_inputTempFile; // autodelete m_inputTempFile = 0; m_inputFile.clear(); if (!m_outputFile.isEmpty()) { if (m_outputTempFile == 0) { m_inputTempFile = new QTemporaryFile; m_inputTempFile->setAutoRemove(true); m_inputTempFile->setFileName(m_outputFile); } else { m_inputTempFile = m_outputTempFile; m_outputTempFile = 0; } m_inputFile = m_outputFile; m_outputFile.clear(); m_inputTempFile = m_outputTempFile; m_outputTempFile = 0; } if (m_inputDocument != filterManagerKisDocument()) delete m_inputDocument; m_inputDocument = m_outputDocument; m_outputDocument = 0; } void KisFilterChain::finalizeIO() { // In case we export (to a file, of course) and the last // filter chose to output a KisDocument we have to save it. // Should be very rare, but well... // Note: m_*input*Document as we already called manageIO() if (m_inputDocument && static_cast(filterManagerDirection()) == KisImportExportManager::Export) { dbgFile << "Saving the output document to the export file " << m_chainLinks.current()->to(); m_inputDocument->setOutputMimeType(m_chainLinks.current()->to()); m_inputDocument->saveNativeFormat(filterManagerExportFile()); m_inputFile = filterManagerExportFile(); } } bool KisFilterChain::createTempFile(QTemporaryFile** tempFile, bool autoDelete) { if (*tempFile) { errFile << "Ooops, why is there already a temp file???" << endl; return false; } *tempFile = new QTemporaryFile(); (*tempFile)->setAutoRemove(autoDelete); return (*tempFile)->open(); } /* Note about Windows & usage of QTemporaryFile The QTemporaryFile objects m_inputTempFile and m_outputTempFile are just used to reserve a temporary file with a unique name which then can be used to store an intermediate format. The filters themselves do not get access to these objects, but can query KisFilterChain only for the filename and then have to open the files themselves with their own file handlers (TODO: change this). On Windows this seems to be a problem and results in content not sync'ed to disk etc. So unless someone finds out which flags might be needed on opening the files on Windows to prevent this behaviour (unless these details are hidden away by the Qt abstraction and cannot be influenced), a workaround is to destruct the QTemporaryFile objects right after creation again and just take the name, to avoid having two file handlers on the same file. A better fix might be to use the QTemporaryFile objects also by the filters, instead of having them open the same file on their own again, but that needs more work and is left for... you :) */ void KisFilterChain::inputFileHelper(KisDocument* document, const QString& alternativeFile) { if (document) { if (!createTempFile(&m_inputTempFile)) { delete m_inputTempFile; m_inputTempFile = 0; m_inputFile.clear(); return; } m_inputFile = m_inputTempFile->fileName(); // See "Note about Windows & usage of QTemporaryFile" above #ifdef Q_OS_WIN m_inputTempFile->close(); m_inputTempFile->setAutoRemove(true); delete m_inputTempFile; m_inputTempFile = 0; #endif document->setOutputMimeType(m_chainLinks.current()->from()); if (!document->saveNativeFormat(m_inputFile)) { delete m_inputTempFile; m_inputTempFile = 0; m_inputFile.clear(); return; } } else m_inputFile = alternativeFile; } void KisFilterChain::outputFileHelper(bool autoDelete) { if (!createTempFile(&m_outputTempFile, autoDelete)) { delete m_outputTempFile; m_outputTempFile = 0; m_outputFile.clear(); } else { m_outputFile = m_outputTempFile->fileName(); // See "Note about Windows & usage of QTemporaryFile" above #ifdef Q_OS_WIN m_outputTempFile->close(); m_outputTempFile->setAutoRemove(true); delete m_outputTempFile; m_outputTempFile = 0; #endif } } int KisFilterChain::weight() const { return m_chainLinks.count(); } diff --git a/libs/ui/KisFilterChain.h b/libs/ui/KisFilterChain.h index 8754f191fb..1731cf63c1 100644 --- a/libs/ui/KisFilterChain.h +++ b/libs/ui/KisFilterChain.h @@ -1,186 +1,183 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 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_FILTER_CHAIN_H #define KIS_FILTER_CHAIN_H #include #include #include #include +#include "kis_shared_ptr.h" -#include "KisImportExportFilter.h" #include "KisFilterEntry.h" +#include "KisImportExportFilter.h" #include "KisFilterChainLinkList.h" #include "kis_shared.h" -#include "kis_shared_ptr.h" #include "kritaui_export.h" class QTemporaryFile; class KisImportExportManager; class KisDocument; namespace CalligraFilter { class Graph; class ChainLink; class Vertex; class Edge; } /** * @brief This class represents a chain of plain @ref KisImportExportFilter instances. * * @author Werner Trobin * @todo the class has no constructor and therefore cannot initialize its private class */ class KRITAUI_EXPORT KisFilterChain : public KisShared { - // Only Calligra::Graph is allowed to construct instances and - // add chain links. - friend class Graph; - friend class KisImportExportManager; - public: + explicit KisFilterChain(const KisImportExportManager *manager); virtual ~KisFilterChain(); /** * The filter manager returned may be 0! */ const KisImportExportManager* manager() const { return m_manager; } /** * Starts the filtering process. * @return The return status of the conversion. KisImportExportFilter::OK * if everything is alright. */ KisImportExportFilter::ConversionStatus invokeChain(); /** * Tells the @ref KisFilterManager the output file of the * filter chain in case of an import operation. If it's * an empty QString we directly manipulated the document. */ QString chainOutput() const; /** * Get the current file to read from. This part of the API * is for the filters in our chain. */ QString inputFile(); + /** * Get the current file to write to. This part of the API * is for the filters in our chain. */ QString outputFile(); + void setOutputFile(const QString &outputFile); /** * This method allows your filter to work directly on the * @ref KisDocument of the application. * This part of the API is for the filters in our chain. * @return The document containing the data. May return 0 on error. */ - KisDocument* inputDocument(); + KisDocument *inputDocument(); /** * This method allows your filter to work directly on the * @ref KisDocument of the application. * This part of the API is for the filters in our chain. * @return The document you have to write to. May return 0 on error. */ - KisDocument* outputDocument(); + KisDocument *outputDocument(); + KisPropertiesConfigurationSP filterManagerExportConfiguration() const; /// returns the amount of filters this chain contains representing the weight int weight() const; private: // ### API for Calligra::Graph: // Construct a filter chain belonging to some KisFilterManager. // The parent filter manager may be 0. friend class CalligraFilter::Graph; - explicit KisFilterChain(const KisImportExportManager* manager); - void prependChainLink(KisFilterEntrySP filterEntry, const QByteArray& from, const QByteArray& to); // These methods are friends of KisFilterManager and provide access // to a private part of its API. As I don't want to include // koFilterManager.h in this header the direction is "int" here. + + friend class KisImportExportManager; + QString filterManagerImportFile() const; QString filterManagerExportFile() const; KisDocument* filterManagerKisDocument() const; int filterManagerDirection() const; - // Helper methods which keep track of all the temp files and documents, // and properly delete them as soon as they are not // needed anymore. void manageIO(); void finalizeIO(); bool createTempFile(QTemporaryFile** tempFile, bool autoDelete = true); void inputFileHelper(KisDocument* document, const QString& alternativeFile); void outputFileHelper(bool autoDelete); // "A whole is that which has beginning, middle, and end" - Aristotle // ...but we also need to signal "Done" state, Mr. Aristotle enum Whole { Beginning = 1, Middle = 2, End = 4, Done = 8 }; // Don't copy or assign filter chains KisFilterChain(const KisFilterChain& rhs); KisFilterChain& operator=(const KisFilterChain& rhs); const KisImportExportManager* const m_manager; CalligraFilter::ChainLinkList m_chainLinks; // stuff needed for bookkeeping int m_state; QString m_inputFile; // Did we pass around plain files? QString m_outputFile; KisDocument* m_inputDocument; // ...or even documents? KisDocument* m_outputDocument; QTemporaryFile* m_inputTempFile; QTemporaryFile* m_outputTempFile; // These two flags keep track of the input/output the // filter (=user) asked for enum IOState { Nil, File, Document }; IOState m_inputQueried, m_outputQueried; class Private; Private * const d; }; -typedef KisSharedPtr KisFilterChainSP; - #endif // __KO_FILTER_CHAIN_H__ diff --git a/libs/ui/KisFilterChainLink.cpp b/libs/ui/KisFilterChainLink.cpp index fc94293117..6768348378 100644 --- a/libs/ui/KisFilterChainLink.cpp +++ b/libs/ui/KisFilterChainLink.cpp @@ -1,101 +1,96 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 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 "KisFilterChainLink.h" #include #include #include #include "KisFilterEntry.h" #include "KisImportExportManager.h" #include "KoProgressUpdater.h" #include "KoUpdater.h" namespace { - const char *const SIGNAL_PREFIX = "commSignal"; - const int SIGNAL_PREFIX_LEN = 10; - const char *const SLOT_PREFIX = "commSlot"; - const int SLOT_PREFIX_LEN = 8; - - KoUpdater *createUpdater(KisFilterChain *chain) + KoUpdater *createUpdater(KisFilterChainSP chain) { QPointer updater = 0; Q_ASSERT(chain); Q_ASSERT(chain->manager()); KoProgressUpdater *pu = chain->manager()->progressUpdater(); if (pu) { updater = pu->startSubtask(1, "filter"); updater->setProgress(0); } return updater; } } namespace CalligraFilter { - ChainLink::ChainLink(KisFilterChain *chain, KisFilterEntrySP filterEntry, + ChainLink::ChainLink(KisFilterChainSP chain, KisFilterEntrySP filterEntry, const QByteArray& from, const QByteArray& to) : m_chain(chain) , m_filterEntry(filterEntry) , m_from(from) , m_to(to) , m_filter(0) , m_updater(createUpdater(chain)) { } ChainLink::~ChainLink() { } KisImportExportFilter::ConversionStatus ChainLink::invokeFilter() { if (!m_filterEntry) { errFile << "This filter entry is null. Strange stuff going on." << endl; return KisImportExportFilter::FilterEntryNull; } m_filter = m_filterEntry->createFilter(m_chain); if (!m_filter) { errFile << "Couldn't create the filter." << endl; return KisImportExportFilter::FilterCreationError; } Q_ASSERT(m_updater); if (m_updater) { // if there is an updater, use that for progress reporting m_filter->setUpdater(m_updater); } - KisImportExportFilter::ConversionStatus status = m_filter->convert(m_from, m_to); + KisImportExportFilter::ConversionStatus status = m_filter->convert(m_from, m_to, m_chain->filterManagerExportConfiguration()); delete m_filter; m_filter = 0; if (m_updater) { m_updater->setProgress(100); } return status; } void ChainLink::dump() const { dbgFile << " Link:" << m_filterEntry->loader()->fileName(); } } diff --git a/libs/ui/KisFilterChainLink.h b/libs/ui/KisFilterChainLink.h index f3bfa1839f..36bce33cd4 100644 --- a/libs/ui/KisFilterChainLink.h +++ b/libs/ui/KisFilterChainLink.h @@ -1,74 +1,74 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 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 KISFILTERCHAINLINK_H #define KISFILTERCHAINLINK_H #include class QByteArray; namespace CalligraFilter { /** * A small private helper class with represents one single filter * (one link of the chain) * @internal */ class ChainLink { public: - ChainLink(KisFilterChain *chain, KisFilterEntrySP filterEntry, + ChainLink(KisFilterChainSP chain, KisFilterEntrySP filterEntry, const QByteArray& from, const QByteArray& to); ~ChainLink(); KisImportExportFilter::ConversionStatus invokeFilter(); QByteArray from() const { return m_from; } QByteArray to() const { return m_to; } // debugging void dump() const; QPointer updater() const { return m_updater; } private: ChainLink(const ChainLink& rhs); ChainLink& operator=(const ChainLink& rhs); - KisFilterChain *m_chain; + KisFilterChainSP m_chain; KisFilterEntrySP m_filterEntry; QByteArray m_from, m_to; // This hack is only needed due to crappy Microsoft design and // circular dependencies in their embedded files :} KisImportExportFilter *m_filter; QPointer const m_updater; }; } #endif // KOFILTERCHAINLINK_H diff --git a/libs/ui/KisFilterEntry.cpp b/libs/ui/KisFilterEntry.cpp index 9e00a1c45b..535933ecde 100644 --- a/libs/ui/KisFilterEntry.cpp +++ b/libs/ui/KisFilterEntry.cpp @@ -1,86 +1,86 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright 2007 David Faure 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 "KisFilterEntry.h" #include "KisDocument.h" #include "KisImportExportFilter.h" #include #include #include #include - +#include #include // UINT_MAX KisFilterEntry::KisFilterEntry(QPluginLoader *loader) : KisShared() , m_loader(loader) { import = loader->metaData().value("MetaData").toObject().value("X-KDE-Import").toString().split(','); export_ = loader->metaData().value("MetaData").toObject().value("X-KDE-Export").toString().split(','); int w = loader->metaData().value("MetaData").toObject().value("X-KDE-Weight").toString().toInt(); weight = w < 0 ? UINT_MAX : static_cast(w); available = loader->metaData().value("MetaData").toObject().value("X-KDE-Available").toString(); } KisFilterEntry::~KisFilterEntry() { delete m_loader; } QList KisFilterEntry::query() { QList lst; QList offers = KoJsonTrader::instance()->query("Krita/FileFilter", QString()); unsigned int max = offers.count(); dbgFile <<"Query returned" << max <<" offers"; Q_FOREACH(QPluginLoader *pluginLoader, offers) { //dbgFile <<" desktopEntryPath=" << (*it)->entryPath() // << " library=" << (*it)->library() << endl; // Append converted offer lst.append(KisFilterEntrySP(new KisFilterEntry(pluginLoader))); } return lst; } -KisImportExportFilter* KisFilterEntry::createFilter(KisFilterChain* chain, QObject* parent) +KisImportExportFilter* KisFilterEntry::createFilter(KisFilterChainSP chain) { KLibFactory *factory = qobject_cast(m_loader->instance()); if (!factory) { warnUI << m_loader->errorString(); return 0; } - QObject* obj = factory->create(parent); + QObject *obj = factory->create(0); if (!obj || !obj->inherits("KisImportExportFilter")) { delete obj; return 0; } KisImportExportFilter* filter = static_cast(obj); - filter->m_chain = chain; + filter->setChain(chain); return filter; } diff --git a/libs/ui/KisFilterEntry.h b/libs/ui/KisFilterEntry.h index cca5e3fe88..01910298fe 100644 --- a/libs/ui/KisFilterEntry.h +++ b/libs/ui/KisFilterEntry.h @@ -1,103 +1,102 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright 2007 David Faure 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_FILTER_ENTRY_H #define KIS_FILTER_ENTRY_H #include #include +#include "kis_types.h" #include "kis_shared.h" #include "kis_shared_ptr.h" #include "kritaui_export.h" class QObject; class QPluginLoader; class KisImportExportFilter; -class KisFilterChain; - class KisFilterEntry; typedef KisSharedPtr KisFilterEntrySP; /** * Represents an available filter. */ class KRITAUI_EXPORT KisFilterEntry : public KisShared { public: //KisFilterEntry() : weight( 0 ) { m_service = 0; } // for QList explicit KisFilterEntry(QPluginLoader *loader); ~KisFilterEntry(); - KisImportExportFilter* createFilter(KisFilterChain* chain, QObject* parent = 0); + KisImportExportFilter *createFilter(KisFilterChainSP chain); /** * The imported mimetype(s). */ QStringList import; /** * The exported mimetype(s). */ QStringList export_; /** * The "weight" of this filter path. Has to be > 0 to be valid. */ unsigned int weight; /** * Do we have to check during runtime? */ QString available; /** * @return TRUE if the filter can import the requested mimetype. */ bool imports(const QString& _mimetype) const { return (import.contains(_mimetype)); } /** * @return TRUE if the filter can export the requested mimetype. */ bool exports(const QString& _m) const { return (export_.contains(_m)); } /** * This function will query KDED to find all available filters. */ static QList query(); QPluginLoader *loader() const { return m_loader; } private: QPluginLoader *m_loader; }; #endif diff --git a/libs/ui/KisFilterGraph.cpp b/libs/ui/KisFilterGraph.cpp index f9d1f09664..df15d649fe 100644 --- a/libs/ui/KisFilterGraph.cpp +++ b/libs/ui/KisFilterGraph.cpp @@ -1,174 +1,174 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 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 "KisFilterGraph.h" #include "KisImportExportManager.h" // KisImportExportManager::filterAvailable, private API #include "KisFilterEntry.h" #include "KisDocument.h" #include "PriorityQueue_p.h" #include "KisFilterEdge.h" #include "KisFilterChainLink.h" #include "KisFilterVertex.h" #include #include #include #include // UINT_MAX namespace CalligraFilter { Graph::Graph(const QByteArray& from) : m_from(from) , m_graphValid(false) , d(0) { buildGraph(); shortestPaths(); // Will return after a single lookup if "from" is invalid (->no check here) } Graph::~Graph() { Q_FOREACH (Vertex* vertex, m_vertices) { delete vertex; } m_vertices.clear(); } void Graph::setSourceMimeType(const QByteArray& from) { if (from == m_from) return; m_from = from; m_graphValid = false; // Initialize with "infinity" ... Q_FOREACH (Vertex* vertex, m_vertices) { vertex->reset(); } // ...and re-run the shortest path search for the new source mime shortestPaths(); } -KisFilterChainSP Graph::chain(const KisImportExportManager* manager, QByteArray& to) const +KisFilterChainSP Graph::chain(const KisImportExportManager *manager, QByteArray &to) const { if (!isValid() || !manager) return KisFilterChainSP(); Q_ASSERT(!to.isEmpty()); const Vertex* vertex = m_vertices.value(to); if (!vertex || vertex->key() == UINT_MAX) return KisFilterChainSP(); - KisFilterChainSP ret(new KisFilterChain(manager)); + KisFilterChainSP filterChain(new KisFilterChain(manager)); // Fill the filter chain with all filters on the path const Vertex* tmp = vertex->predecessor(); while (tmp) { const Edge* const edge = tmp->findEdge(vertex); Q_ASSERT(edge); - ret->prependChainLink(edge->filterEntry(), tmp->mimeType(), vertex->mimeType()); + filterChain->prependChainLink(edge->filterEntry(), tmp->mimeType(), vertex->mimeType()); vertex = tmp; tmp = tmp->predecessor(); } - return ret; + return filterChain; } void Graph::dump() const { #ifndef NDEBUG dbgFile << "+++++++++ Graph::dump +++++++++"; dbgFile << "From:" << m_from; Q_FOREACH (Vertex *vertex, m_vertices) { vertex->dump(" "); } dbgFile << "+++++++++ Graph::dump (done) +++++++++"; #endif } // Query the trader and create the vertices and edges representing // available mime types and filters. void Graph::buildGraph() { // no constraint here - we want *all* :) const QList filters(KisFilterEntry::query()); Q_FOREACH (KisFilterEntrySP filter, filters) { // First add the "starting points" to the dict Q_FOREACH (const QString& import, filter->import) { const QByteArray key = import.toLatin1(); // latin1 is okay here (werner) // already there? if (!m_vertices.contains(key)) m_vertices.insert(key, new Vertex(key)); } Q_FOREACH (const QString& exportIt, filter->export_) { // First make sure the export vertex is in place const QByteArray key = exportIt.toLatin1(); // latin1 is okay here Vertex* exp = m_vertices.value(key); if (!exp) { exp = new Vertex(key); m_vertices.insert(key, exp); } // Then create the appropriate edges Q_FOREACH (const QString& import, filter->import) { m_vertices[import.toLatin1()]->addEdge(new Edge(exp, filter)); } } } } // As all edges (=filters) are required to have a positive weight // we can use Dijkstra's shortest path algorithm from Cormen's // "Introduction to Algorithms" (p. 527) // Note: I did some adaptions as our data structures are slightly // different from the ones used in the book. Further we simply stop // the algorithm is we don't find any node with a weight != Infinity // (==UINT_MAX), as this means that the remaining nodes in the queue // aren't connected anyway. void Graph::shortestPaths() { // Is the requested start mime type valid? Vertex* from = m_vertices.value(m_from); if (!from) return; // Inititalize start vertex from->setKey(0); // Fill the priority queue with all the vertices PriorityQueue queue(m_vertices); while (!queue.isEmpty()) { Vertex *min = queue.extractMinimum(); // Did we already relax all connected vertices? if (min->key() == UINT_MAX) break; min->relaxVertices(queue); } m_graphValid = true; } } diff --git a/libs/ui/KisImportExportFilter.cpp b/libs/ui/KisImportExportFilter.cpp index 1e37ce0273..589bad7d1e 100644 --- a/libs/ui/KisImportExportFilter.cpp +++ b/libs/ui/KisImportExportFilter.cpp @@ -1,171 +1,198 @@ /* This file is part of the KDE libraries Copyright (C) 2001 Werner Trobin 2002 Werner Trobin 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 "KisImportExportFilter.h" #include #include #include #include "KisImportExportManager.h" #include "KoUpdater.h" #include class Q_DECL_HIDDEN KisImportExportFilter::Private { public: QPointer updater; Private() : updater(0) {} + + /** + * Use this pointer to access all information about input/output + * during the conversion. @em Don't use it in the constructor - + * it's invalid while constructing the object! + */ + KisFilterChainSP chain; + }; KisImportExportFilter::KisImportExportFilter(QObject *parent) : QObject(parent) - , m_chain(0) , d(new Private) { } KisDocument *KisImportExportFilter::inputDocument() const { - return m_chain->inputDocument(); + return d->chain->inputDocument(); } KisDocument *KisImportExportFilter::outputDocument() const { - return m_chain->outputDocument(); + return d->chain->outputDocument(); } QString KisImportExportFilter::inputFile() const { - return m_chain->inputFile(); + return d->chain->inputFile(); } QString KisImportExportFilter::outputFile() const { - return m_chain->outputFile(); + return d->chain->outputFile(); } bool KisImportExportFilter::getBatchMode() const { - return m_chain->manager()->getBatchMode(); + return d->chain->manager()->getBatchMode(); } KisImportExportFilter::~KisImportExportFilter() { Q_ASSERT(d->updater); if (d->updater) d->updater->setProgress(100); delete d; } +void KisImportExportFilter::setChain(KisFilterChainSP chain) +{ + d->chain = chain; +} + QString KisImportExportFilter::conversionStatusString(ConversionStatus status) { QString msg; switch (status) { case OK: break; case FilterCreationError: msg = i18n("Could not create the filter plugin"); break; case CreationError: msg = i18n("Could not create the output document"); break; case FileNotFound: msg = i18n("File not found"); break; case StorageCreationError: msg = i18n("Cannot create storage"); break; case BadMimeType: msg = i18n("Bad MIME type"); break; case EmbeddedDocError: msg = i18n("Error in embedded document"); break; case WrongFormat: msg = i18n("Format not recognized"); break; case NotImplemented: msg = i18n("Not implemented"); break; case ParsingError: msg = i18n("Parsing error"); break; case PasswordProtected: msg = i18n("Document is password protected"); break; case InvalidFormat: msg = i18n("Invalid file format"); break; case InternalError: case UnexpectedEOF: case UnexpectedOpcode: case StupidError: // ?? what is this ?? case UsageError: msg = i18n("Internal error"); break; case OutOfMemory: msg = i18n("Out of memory"); break; case FilterEntryNull: msg = i18n("Empty Filter Plugin"); break; case NoDocumentCreated: msg = i18n("Trying to load into the wrong kind of document"); break; case DownloadFailed: msg = i18n("Failed to download remote file"); break; case ProgressCancelled: msg = i18n("Cancelled by user"); break; case BadConversionGraph: msg = i18n("Unknown file type"); break; case UserCancelled: // intentionally we do not prompt the error message here break; default: msg = i18n("Unknown error"); break; } return msg; } +KisPropertiesConfigurationSP KisImportExportFilter::defaultConfiguration(const QByteArray &from, const QByteArray &to) const +{ + return 0; +} + +KisPropertiesConfigurationSP KisImportExportFilter::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + return defaultConfiguration(from, to); +} + +KisConfigWidget *KisImportExportFilter::createConfigurationWidget(QWidget *, const QByteArray &from, const QByteArray &to) const +{ + return 0; +} + void KisImportExportFilter::setUpdater(const QPointer& updater) { Q_ASSERT(updater); if (d->updater && !updater) { disconnect(this, SLOT(slotProgress(int))); } else if (!d->updater && updater) { connect(this, SIGNAL(sigProgress(int)), SLOT(slotProgress(int))); } d->updater = updater; } void KisImportExportFilter::slotProgress(int value) { Q_ASSERT(d->updater); if (d->updater) { d->updater->setValue(value); } } diff --git a/libs/ui/KisImportExportFilter.h b/libs/ui/KisImportExportFilter.h index b064bf4608..c5bc6e6e17 100644 --- a/libs/ui/KisImportExportFilter.h +++ b/libs/ui/KisImportExportFilter.h @@ -1,149 +1,193 @@ /* This file is part of the Calligra libraries Copyright (C) 2001 Werner Trobin 2002 Werner Trobin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_IMPORT_EXPORT_FILTER_H #define KIS_IMPORT_EXPORT_FILTER_H #include #include #include #include +#include +#include +#include -#include "kritaui_export.h" - -class KisFilterChain; class KoUpdater; class KisDocument; +class KisConfigWidget; + +#include "kritaui_export.h" + /** * @brief The base class for import and export filters. * * Derive your filter class from this base class and implement * the @ref convert() method. Don't forget to specify the Q_OBJECT * macro in your class even if you don't use signals or slots. * This is needed as filters are created on the fly. * The m_chain member allows access to the @ref KisFilterChain * which invokes the filter to query for input/output. * * @note Take care: The m_chain pointer is invalid while the constructor * runs due to the implementation -- @em don't use it in the constructor. * After the constructor, when running the @ref convert() method it's * guaranteed to be valid, so no need to check against 0. * * @note If the code is compiled in debug mode, setting CALLIGRA_DEBUG_FILTERS * environment variable to any value disables deletion of temporary files while * importing/exporting. This is useful for testing purposes. * * @author Werner Trobin * @todo the class has no constructor and therefore cannot initialize its private class */ class KRITAUI_EXPORT KisImportExportFilter : public QObject { Q_OBJECT - friend class KisFilterEntry; // needed for the filter chain pointer :( - friend class KisFilterChain; - public: /** * This enum is used to signal the return state of your filter. * Return OK in @ref convert() in case everything worked as expected. * Feel free to add some more error conditions @em before the last item * if it's needed. */ - enum ConversionStatus { OK, StupidError, UsageError, CreationError, FileNotFound, - StorageCreationError, BadMimeType, BadConversionGraph, - EmbeddedDocError, WrongFormat, NotImplemented, - ParsingError, InternalError, UnexpectedEOF, - UnexpectedOpcode, UserCancelled, OutOfMemory, - PasswordProtected, InvalidFormat, FilterEntryNull, - NoDocumentCreated, DownloadFailed, FilterCreationError, + enum ConversionStatus { OK, + StupidError, + UsageError, + CreationError, + FileNotFound, + StorageCreationError, + BadMimeType, + BadConversionGraph, + EmbeddedDocError, + WrongFormat, + NotImplemented, + ParsingError, + InternalError, + UnexpectedEOF, + UnexpectedOpcode, + UserCancelled, + OutOfMemory, + PasswordProtected, + InvalidFormat, + FilterEntryNull, + NoDocumentCreated, + DownloadFailed, + FilterCreationError, ProgressCancelled, JustInCaseSomeBrokenCompilerUsesLessThanAByte = 255 }; virtual ~KisImportExportFilter(); + /** + * @brief setChain set the chain information on the filter. The chain information + * lets the filter know what document it's working on. The filter will not delete + * @param chain the actual filter chain + */ + void setChain(KisFilterChainSP chain); + /** * The filter chain calls this method to perform the actual conversion. * The passed mimetypes should be a pair of those you specified in your * .desktop file. * You @em have to implement this method to make the filter work. * * @param from The mimetype of the source file/document * @param to The mimetype of the destination file/document * @return The error status, see the @ref #ConversionStatus enum. * KisImportExportFilter::OK means that everything is alright. */ - virtual ConversionStatus convert(const QByteArray& from, const QByteArray& to) = 0; + virtual ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0) = 0; /** * Set the updater to which the filter will report progress. * Every emit of the sigProgress signal is reported to the updater. */ void setUpdater(const QPointer& updater); /** * Get the text version of the status value */ static QString conversionStatusString(ConversionStatus status); + /** + * @brief defaultConfiguration defines the default settings for the given import export filter + * @param from The mimetype of the source file/document + * @param to The mimetype of the destination file/document + * @return a serializable KisPropertiesConfiguration object + */ + virtual KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + + /** + * @brief lastSavedConfiguration return the last saved configuration for this filter + * @param from The mimetype of the source file/document + * @param to The mimetype of the destination file/document + * @return a serializable KisPropertiesConfiguration object + */ + virtual KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + + /** + * @brief createConfigurationWidget creates a widget that can be used to define the settings for a given import/export filter + * @param parent the ownder of the widget; the caller is responsible for deleting + * @param from The mimetype of the source file/document + * @param to The mimetype of the destination file/document + * + * @return the widget + */ + virtual KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; + + Q_SIGNALS: /** * Emit this signal with a value in the range of 1...100 to have some * progress feedback for the user in the statusbar of the application. * * @param value The actual progress state. Should always remain in * the range 1..100. */ void sigProgress(int value); protected: /** * This is the constructor your filter has to call, obviously. */ KisImportExportFilter(QObject *parent = 0); KisDocument *inputDocument() const; KisDocument *outputDocument() const; QString inputFile() const; QString outputFile() const; bool getBatchMode() const; private: - /** - * Use this pointer to access all information about input/output - * during the conversion. @em Don't use it in the constructor - - * it's invalid while constructing the object! - */ - KisFilterChain *m_chain; -private: KisImportExportFilter(const KisImportExportFilter& rhs); KisImportExportFilter& operator=(const KisImportExportFilter& rhs); class Private; Private *const d; private Q_SLOTS: void slotProgress(int value); }; #endif diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp index 564844919b..226d4d359c 100644 --- a/libs/ui/KisImportExportManager.cpp +++ b/libs/ui/KisImportExportManager.cpp @@ -1,294 +1,338 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis 2000, 2001 Werner Trobin Copyright (C) 2004 Nicolas Goutte Copyright (C) 2009 Thomas Zander This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisImportExportManager.h" #include #include #include #include #include #include #include #include #include +#include #include #include +#include #include "KoProgressUpdater.h" #include "KoJsonTrader.h" #include #include #include "KisImportExportFilter.h" #include "KisDocument.h" #include #include // static cache for import and export mimetypes QStringList KisImportExportManager::m_importMimeTypes; QStringList KisImportExportManager::m_exportMimeTypes; class Q_DECL_HIDDEN KisImportExportManager::Private { public: bool batch; QByteArray importMimeType; QWeakPointer progressUpdater; Private(KoProgressUpdater *progressUpdater_ = 0) : progressUpdater(progressUpdater_) { } }; KisImportExportManager::KisImportExportManager(KisDocument* document) : m_document(document) , m_graph("") , d(new Private(0)) { d->batch = false; } KisImportExportManager::KisImportExportManager(const QString& location) : m_document(0) , m_importFileName(location) , m_graph("") , d(new Private) { d->batch = false; } KisImportExportManager::KisImportExportManager(const QByteArray& mimeType) : m_document(0) , m_graph("") , d(new Private) { d->batch = false; d->importMimeType = mimeType; } KisImportExportManager::~KisImportExportManager() { delete d; } QString KisImportExportManager::importDocument(const QString& location, const QString& documentMimeType, KisImportExportFilter::ConversionStatus& status) { // Find the mime type for the file to be imported. QString typeName = documentMimeType; if (typeName.isEmpty()) { typeName = KisMimeDatabase::mimeTypeForFile(location); } m_graph.setSourceMimeType(typeName.toLatin1()); // .latin1() is okay here (Werner) if (!m_graph.isValid()) { errFile << "Couldn't create a valid graph for this source mimetype: " << typeName; status = KisImportExportFilter::BadConversionGraph; return QString(); } KisFilterChainSP chain(0); // Are we owned by a KisDocument? if (m_document) { QByteArray mimeType = m_document->nativeFormatMimeType(); QStringList extraMimes = m_document->extraNativeMimeTypes(); int i = 0; int n = extraMimes.count(); chain = m_graph.chain(this, mimeType); while (i < n) { QByteArray extraMime = extraMimes[i].toUtf8(); // TODO check if its the same target mime then continue KisFilterChainSP newChain(0); newChain = m_graph.chain(this, extraMime); if (!chain || (newChain && newChain->weight() < chain->weight())) chain = newChain; ++i; } } else if (!d->importMimeType.isEmpty()) { chain = m_graph.chain(this, d->importMimeType); } else { errFile << "You aren't supposed to use import() from a filter!" << endl; status = KisImportExportFilter::UsageError; return QString(); } if (!chain) { errFile << "Couldn't create a valid filter chain!" << endl; importErrorHelper(typeName); status = KisImportExportFilter::BadConversionGraph; return QString(); } // Okay, let's invoke the filters one after the other m_direction = Import; // vital information! m_importFileName = location; m_exportFileName.clear(); status = chain->invokeChain(); m_importFileName.clear(); // Reset the import URL if (status == KisImportExportFilter::OK) return chain->chainOutput(); return QString(); } -KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, QByteArray& mimeType) +KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, QByteArray& mimeType, KisPropertiesConfigurationSP exportConfiguration) { bool userCancelled = false; // The import url should already be set correctly (null if we have a KisDocument // file manager and to the correct URL if we have an embedded manager) m_direction = Export; // vital information! m_exportFileName = location; + m_exportConfiguration = exportConfiguration; KisFilterChainSP chain; if (m_document) { // We have to pick the right native mimetype as source. QStringList nativeMimeTypes; nativeMimeTypes.append(m_document->nativeFormatMimeType()); nativeMimeTypes += m_document->extraNativeMimeTypes(); QStringList::ConstIterator it = nativeMimeTypes.constBegin(); const QStringList::ConstIterator end = nativeMimeTypes.constEnd(); for (; !chain && it != end; ++it) { m_graph.setSourceMimeType((*it).toLatin1()); if (m_graph.isValid()) chain = m_graph.chain(this, mimeType); } } else { QString t = KisMimeDatabase::mimeTypeForFile(m_importFileName); m_graph.setSourceMimeType(t.toLatin1()); } if (!m_graph.isValid()) { errFile << "Couldn't create a valid graph for this source mimetype."; QApplication::restoreOverrideCursor(); if (!d->batch && !userCancelled) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not export file: the export filter is missing.")); } return KisImportExportFilter::BadConversionGraph; } if (!chain) { // already set when coming from the m_document case chain = m_graph.chain(this, mimeType); } if (!chain) { errFile << "Couldn't create a valid filter chain to " << mimeType << " !" << endl; if (!d->batch) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not export file: the export filter is missing.")); } QApplication::restoreOverrideCursor(); return KisImportExportFilter::BadConversionGraph; } return chain->invokeChain(); } // The static method to figure out to which parts of the // graph this mimetype has a connection to. QStringList KisImportExportManager::mimeFilter(Direction direction) { - // Find the right mimetype by the extension QSet mimeTypes; // mimeTypes << KisDocument::nativeFormatMimeType() << "application/x-krita-paintoppreset" << "image/openraster"; if (direction == KisImportExportManager::Import) { if (m_importMimeTypes.isEmpty()) { KoJsonTrader trader; QListlist = trader.query("Krita/FileFilter", ""); Q_FOREACH(QPluginLoader *loader, list) { QJsonObject json = loader->metaData().value("MetaData").toObject(); Q_FOREACH(const QString &mimetype, json.value("X-KDE-Import").toString().split(",")) { mimeTypes << mimetype; } } qDeleteAll(list); m_importMimeTypes = mimeTypes.toList(); } return m_importMimeTypes; } else if (direction == KisImportExportManager::Export) { if (m_exportMimeTypes.isEmpty()) { KoJsonTrader trader; QListlist = trader.query("Krita/FileFilter", ""); Q_FOREACH(QPluginLoader *loader, list) { QJsonObject json = loader->metaData().value("MetaData").toObject(); Q_FOREACH(const QString &mimetype, json.value("X-KDE-Export").toString().split(",")) { mimeTypes << mimetype; } } qDeleteAll(list); m_exportMimeTypes = mimeTypes.toList(); } qDebug() << m_exportMimeTypes; return m_exportMimeTypes; } return QStringList(); } +KisImportExportFilter *KisImportExportManager::filterForMimeType(const QString &mimetype, KisImportExportManager::Direction direction) +{ + int weight = -1; + KisImportExportFilter *filter = 0; + KoJsonTrader trader; + QListlist = trader.query("Krita/FileFilter", ""); + Q_FOREACH(QPluginLoader *loader, list) { + QJsonObject json = loader->metaData().value("MetaData").toObject(); + QString directionKey = direction == Export ? "X-KDE-Export" : "X-KDE-Import"; + if (json.value(directionKey).toString().split(",").contains(mimetype)) { + KLibFactory *factory = qobject_cast(loader->instance()); + + if (!factory) { + warnUI << loader->errorString(); + continue; + } + + QObject* obj = factory->create(0); + if (!obj || !obj->inherits("KisImportExportFilter")) { + delete obj; + continue; + } + + KisImportExportFilter *f = static_cast(obj); + if (!f) { + delete obj; + continue; + } + + int w = json.value("X-KDE-Weight").toInt(); + if (w > weight) { + delete filter; + filter = f; + f->setObjectName(loader->fileName()); + weight = w; + } + } + } + qDeleteAll(list); + return filter; +} + void KisImportExportManager::importErrorHelper(const QString& mimeType, const bool suppressDialog) { // ###### FIXME: use KLibLoader::lastErrorMessage() here if (!suppressDialog) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not import file of type\n%1. The import filter is missing.", mimeType)); } } void KisImportExportManager::setBatchMode(const bool batch) { d->batch = batch; } bool KisImportExportManager::getBatchMode(void) const { return d->batch; } void KisImportExportManager::setProgresUpdater(KoProgressUpdater *updater) { d->progressUpdater = updater; } KoProgressUpdater* KisImportExportManager::progressUpdater() const { if (d->progressUpdater.isNull()) { // somebody, probably its parent, deleted our progress updater for us return 0; } return d->progressUpdater.data(); } #include diff --git a/libs/ui/KisImportExportManager.h b/libs/ui/KisImportExportManager.h index a449bf8628..bb2b3c0c14 100644 --- a/libs/ui/KisImportExportManager.h +++ b/libs/ui/KisImportExportManager.h @@ -1,180 +1,204 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis 2000, 2001 Werner Trobin Copyright (C) 2004 Nicolas Goutte This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_IMPORT_EXPORT_MANAGER_H #define KIS_IMPORT_EXPORT_MANAGER_H #include #include #include #include #include "KisFilterGraph.h" +#include "KisImportExportFilter.h" #include "kritaui_export.h" class KisFilterChain; class KisDocument; class KoProgressUpdater; /** * @brief The class managing all the filters. * * This class manages all filters for a %Calligra application. Normally * you will not have to use it, since KisMainWindow takes care of loading * and saving documents. * * @ref KisFilter * * @author Kalle Dalheimer * @author Torben Weis * @author Werner Trobin */ class KRITAUI_EXPORT KisImportExportManager : public QObject { Q_OBJECT public: /** * This enum is used to distinguish the import/export cases */ enum Direction { Import = 1, Export = 2 }; /** * Create a filter manager for a document */ explicit KisImportExportManager(KisDocument *document); /** * Create a filter manager for the Shape Collection docker. * @param mimeType the mimetype to import to. */ explicit KisImportExportManager(const QByteArray& mimeType); /** * Create a filter manager for a filter which wants to embed something. * The path it passes is the file to convert. You cannot use * the @ref importDocument() method -- use @ref exportDocument() to convert * the file to the destination mimetype you prefer. * * @param path The location you want to export */ explicit KisImportExportManager(const QString& location); virtual ~KisImportExportManager(); /** * Imports the specified document and returns the resultant filename * (most likely some file in /tmp). * @p path can be either a URL or a filename. * @p documentMimeType gives importDocument a hint about what type * the document may be. It can be left empty. * @p status signals the success/error of the conversion. * If the QString which is returned isEmpty() and the status is OK, * then we imported the file directly into the document. */ QString importDocument(const QString& location, const QString& documentMimeType, KisImportExportFilter::ConversionStatus& status); /** * @brief Exports the given file/document to the specified URL/mimetype. * * If @p mimeType is empty, then the closest matching Calligra part is searched * and when the method returns @p mimeType contains this mimetype. * Oh, well, export is a C++ keyword ;) */ - KisImportExportFilter::ConversionStatus exportDocument(const QString& location, QByteArray& mimeType); + KisImportExportFilter::ConversionStatus exportDocument(const QString& location, QByteArray& mimeType, KisPropertiesConfigurationSP exportConfiguration = 0); ///@name Static API //@{ /** * Suitable for passing to KoFileDialog::setMimeTypeFilters. The default mime * gets set by the "users" of this method, as we do not have enough * information here. * Optionally, @p extraNativeMimeTypes are added after the native mimetype. */ static QStringList mimeFilter(Direction direction); + /** + * @brief filterForMimeType loads the relevant import/export plugin and returns it. The caller + * is responsible for deleting it! + * @param mimetype the mimetype we want to import/export. If there's more than one plugin, the one + * with the highest weight as defined in the json description will be taken + * @param direction import or export + * @return a pointer to the filter plugin or 0 if none could be found + */ + static KisImportExportFilter *filterForMimeType(const QString &mimetype, Direction direction); /** * Set the filter manager is batch mode (no dialog shown) * instead of the interactive mode (dialog shown) */ void setBatchMode(const bool batch); /** * Get if the filter manager is batch mode (true) * or in interactive mode (true) */ bool getBatchMode(void) const; void setProgresUpdater(KoProgressUpdater *updater); /** * Return the KoProgressUpdater or 0 if there is none. **/ KoProgressUpdater *progressUpdater() const; private: // === API for KisFilterChains === (internal) // The friend methods are private in KisFilterChain and // just forward calls to the methods here. Should be // pretty safe. friend QString KisFilterChain::filterManagerImportFile() const; - QString importFile() const { + QString importFile() const + { return m_importFileName; } + friend QString KisFilterChain::filterManagerExportFile() const; - QString exportFile() const { + QString exportFile() const + { return m_exportFileName; } + friend KisDocument *KisFilterChain::filterManagerKisDocument() const; - KisDocument *document() const { + KisDocument *document() const + { return m_document; } + friend int KisFilterChain::filterManagerDirection() const; - int direction() const { + int direction() const + { return static_cast(m_direction); } + friend KisPropertiesConfigurationSP KisFilterChain::filterManagerExportConfiguration() const; + KisPropertiesConfigurationSP exportConfiguration() const + { + return m_exportConfiguration; + } + // Private API KisImportExportManager(const KisImportExportManager& rhs); KisImportExportManager &operator=(const KisImportExportManager& rhs); // Convert file path string or URL string into QUrl QUrl locationToUrl(QString location) const; void importErrorHelper(const QString& mimeType, const bool suppressDialog = false); KisDocument *m_document; QString m_importFileName; QString m_exportFileName; CalligraFilter::Graph m_graph; Direction m_direction; + KisPropertiesConfigurationSP m_exportConfiguration; /// A static cache for the availability checks of filters static QStringList m_importMimeTypes; static QStringList m_exportMimeTypes; class Private; Private * const d; }; #endif // __KO_FILTER_MANAGER_H__ diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index de3e28fc32..92ec27821a 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2519 +1,2458 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port 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 "KisMainWindow.h" #include // qt includes #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 #include #include #include #include #include #include #include #ifdef HAVE_KIO #include #endif #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDockWidgetTitleBar.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include #include #include #include #include #include "KoToolDocker.h" #include #include #include #include #include #include #include "dialogs/kis_about_application.h" #include "dialogs/kis_delayed_save_dialog.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisApplication.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_config_notifier.h" #include "kis_custom_image_widget.h" #include #include "KisDocument.h" #include "KisDocument.h" #include "kis_group_layer.h" #include "kis_icon_utils.h" #include "kis_image_from_clipboard_widget.h" #include "kis_image.h" #include #include "KisImportExportManager.h" #include "kis_mainwindow_observer.h" #include "kis_node.h" #include "KisOpenPane.h" #include "kis_paintop_box.h" #include "KisPart.h" #include "KisPrintJob.h" #include "kis_resource_server_provider.h" #include "kis_signal_compressor_with_param.h" #include "KisView.h" #include "KisViewManager.h" #include "thememanager.h" #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include "kis_animation_exporter.h" #include #ifdef Q_OS_WIN #include #endif class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const { return "sharedtooldocker"; } QDockWidget* createDockWidget() { KoToolDocker* dockWidget = new KoToolDocker(); dockWidget->setTabEnabled(false); return dockWidget; } DockPosition defaultDockPosition() const { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent) : q(parent) - , viewManager(0) - , firstTime(true) - , windowSizeDirty(false) - , readOnly(false) - , isImporting(false) - , isExporting(false) - , noCleanup(false) - , showDocumentInfo(0) - , saveAction(0) - , saveActionAs(0) -// , printAction(0) -// , printActionPreview(0) - , exportPdf(0) - , closeAll(0) -// , reloadFile(0) - , importFile(0) - , exportFile(0) - , undo(0) - , redo(0) - , newWindow(0) - , close(0) - , mdiCascade(0) - , mdiTile(0) - , mdiNextWindow(0) - , mdiPreviousWindow(0) - , toggleDockers(0) - , toggleDockerTitleBars(0) , dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent)) , windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent)) , documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent)) - , helpMenu(0) - , recentFiles(0) - , toolOptionsDocker(0) - , deferredClosingEvent(0) - , themeManager(0) , mdiArea(new QMdiArea(parent)) - , activeSubWindow(0) , windowMapper(new QSignalMapper(parent)) , documentMapper(new QSignalMapper(parent)) - , lastExportSpecialOutputFlag(0) - , geometryInitialized(false) { } ~Private() { qDeleteAll(toolbarList); } - KisMainWindow *q; - KisViewManager *viewManager; + KisMainWindow *q {0}; + KisViewManager *viewManager {0}; QPointer activeView; QPointer progress; QPointer progressCancel; QMutex progressMutex; QList toolbarList; - bool firstTime; - bool windowSizeDirty; - bool readOnly; - bool isImporting; - bool isExporting; - bool noCleanup; + bool firstTime {true}; + bool windowSizeDirty {false}; + bool readOnly {false}; + bool isImporting {false}; + bool isExporting {false}; + bool noCleanup {false}; - KisAction *showDocumentInfo; - KisAction *saveAction; - KisAction *saveActionAs; + KisAction *showDocumentInfo {0}; + KisAction *saveAction {0}; + KisAction *saveActionAs {0}; // KisAction *printAction; // KisAction *printActionPreview; - KisAction *exportPdf; - KisAction *importAnimation; - KisAction *exportAnimation; - KisAction *closeAll; + KisAction *exportPdf {0}; + KisAction *importAnimation {0}; + KisAction *closeAll {0}; // KisAction *reloadFile; - KisAction *importFile; - KisAction *exportFile; - KisAction *undo; - KisAction *redo; - KisAction *newWindow; - KisAction *close; - KisAction *mdiCascade; - KisAction *mdiTile; - KisAction *mdiNextWindow; - KisAction *mdiPreviousWindow; - KisAction *toggleDockers; - KisAction *toggleDockerTitleBars; + KisAction *importFile {0}; + KisAction *exportFile {0}; + KisAction *undo {0}; + KisAction *redo {0}; + KisAction *newWindow {0}; + KisAction *close {0}; + KisAction *mdiCascade {0}; + KisAction *mdiTile {0}; + KisAction *mdiNextWindow {0}; + KisAction *mdiPreviousWindow {0}; + KisAction *toggleDockers {0}; + KisAction *toggleDockerTitleBars {0}; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; - KHelpMenu *helpMenu; + KHelpMenu *helpMenu {0}; - KRecentFilesAction *recentFiles; + KRecentFilesAction *recentFiles {0}; QUrl lastExportUrl; QMap dockWidgetsMap; QMap dockWidgetVisibilityMap; QByteArray dockerStateBeforeHiding; - KoToolDocker *toolOptionsDocker; + KoToolDocker *toolOptionsDocker {0}; - QCloseEvent *deferredClosingEvent; + QCloseEvent *deferredClosingEvent {0}; - Digikam::ThemeManager *themeManager; + Digikam::ThemeManager *themeManager {0}; QMdiArea *mdiArea; - QMdiSubWindow *activeSubWindow; + QMdiSubWindow *activeSubWindow {0}; QSignalMapper *windowMapper; QSignalMapper *documentMapper; QByteArray lastExportedFormat; - int lastExportSpecialOutputFlag; + int lastExportSpecialOutputFlag {0}; QScopedPointer > tabSwitchCompressor; - bool geometryInitialized; + bool geometryInitialized {false}; QMutex savingEntryMutex; KisActionManager * actionManager() { return viewManager->actionManager(); } QTabBar* findTabBarHACK() { QObjectList objects = mdiArea->children(); Q_FOREACH (QObject *object, objects) { QTabBar *bar = qobject_cast(object); if (bar) { return bar; } } return 0; } }; KisMainWindow::KisMainWindow() : KXmlGuiWindow() , d(new Private(this)) { KisConfig cfg; d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); setAcceptDrops(true); setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); setDockNestingEnabled(true); qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events #ifdef Q_OS_MAC setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(documentSaved()), d->viewManager, SLOT(slotDocumentSaved())); connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons())); connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu())); connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); actionCollection()->addAssociatedWidget(this); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); d->toolOptionsDocker->toggleViewAction()->setEnabled(true); } QMap dockwidgetActions; dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction(); Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); QDockWidget *dw = createDockWidget(factory); dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction(); } if (d->toolOptionsDocker) { dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction(); } connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(QList >)), this, SLOT(newOptionWidgets(QList >))); Q_FOREACH (QString title, dockwidgetActions.keys()) { d->dockWidgetMenu->addAction(dockwidgetActions[title]); } Q_FOREACH (QDockWidget *wdg, dockWidgets()) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { wdg->setVisible(true); } } Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) { observer->setObservedCanvas(0); KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer); if (mainwindowObserver) { mainwindowObserver->setMainWindow(d->viewManager); } } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); setCentralWidget(d->mdiArea); connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated())); connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*))); createActions(); setAutoSaveSettings("krita", false); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), viewManager(), false); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { // workaround for KHelpMenu (or rather KAboutData::applicationData()) internally // not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard // not having the app version preset // fixed hopefully in KF5 5.22.0, patch pending QGuiApplication *app = qApp; KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion()); aboutData.setOrganizationDomain(app->organizationDomain().toUtf8()); d->helpMenu = new KHelpMenu(this, aboutData, false); // workaround-less version: // d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false); // The difference between using KActionCollection->addAction() is that // these actions do not get tied to the MainWindow. What does this all do? KActionCollection *actions = d->viewManager->actionCollection(); QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication())); } // KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves QAction *helpAction = actionCollection()->action("help_contents"); helpAction->disconnect(); connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual())); #if 0 //check for colliding shortcuts QSet existingShortcuts; Q_FOREACH (QAction* action, actionCollection()->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } dbgKrita << "shortcut " << action->text() << " " << action->shortcut(); Q_ASSERT(!existingShortcuts.contains(action->shortcut())); existingShortcuts.insert(action->shortcut()); } #endif configChanged(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita.xmlgui")); setXMLFile(":/kxmlgui5/krita.xmlgui"); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { if (toolBar->objectName() == "BrushesAndStuff") { toolBar->setEnabled(false); } KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } else warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } plugActionList("toolbarlist", toolbarList); setToolbarList(toolbarList); applyToolBarLayout(); d->viewManager->updateGUI(); d->viewManager->updateIcons(); #ifdef Q_OS_WIN auto w = qApp->activeWindow(); if (w) QWindowsWindowFunctions::setHasBorderInFullScreen(w->windowHandle(), true); #endif QTimer::singleShot(1000, this, SLOT(checkSanity())); { using namespace std::placeholders; // For _1 placeholder std::function callback( std::bind(&KisMainWindow::switchTab, this, _1)); d->tabSwitchCompressor.reset( new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE)); } } void KisMainWindow::setNoCleanup(bool noCleanup) { d->noCleanup = noCleanup; } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // dbgKrita << "", "").replace("", "") // << "iconText=" << action->iconText().replace("&", "&") // << "shortcut=" << action->shortcut(QAction::ActiveShortcut).toString() // << "defaultShortcut=" << action->shortcut(QAction::DefaultShortcut).toString() // << "isCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "statusTip=" << action->statusTip() // << "/>" ; // } // else { // dbgKrita << "Got a QAction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); if (d->noCleanup) return; delete d->viewManager; delete d; } void KisMainWindow::addView(KisView *view) { if (d->activeView == view) return; if (d->activeView) { d->activeView->disconnect(this); } showView(view); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified(QString,bool))); } } void KisMainWindow::showView(KisView *imageView) { if (imageView && activeView() != imageView) { // XXX: find a better way to initialize this! imageView->setViewManager(d->viewManager); imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager()); imageView->slotLoadingFinished(); QMdiSubWindow *subwin = d->mdiArea->addSubWindow(imageView); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg; subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); /** * Hack alert! * * Here we explicitly request KoToolManager to emit all the tool * activation signals, to reinitialize the tool options docker. * * That is needed due to a design flaw we have in the * initialization procedure. The tool in the KoToolManager is * initialized in KisView::setViewManager() calls, which * happens early enough. During this call the tool manager * requests KoCanvasControllerWidget to emit the signal to * update the widgets in the tool docker. *But* at that moment * of time the view is not yet connected to the main window, * because it happens in KisViewManager::setCurrentView a bit * later. This fact makes the widgets updating signals be lost * and never reach the tool docker. * * So here we just explicitly call the tool activation stub. */ KoToolManager::instance()->initializeCurrentToolForCanvas(); if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } // No, no, no: do not try to call this _before_ the show() has // been called on the view; only when that has happened is the // opengl context active, and very bad things happen if we tell // the dockers to update themselves with a view if the opengl // context is not active. setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { if (KisDlgPreferences::editPreferences()) { KisConfigNotifier::instance()->notifyConfigChanged(); // XXX: should this be changed for the views in other windows as well? Q_FOREACH (QPointer koview, KisPart::instance()->views()) { KisViewManager *view = qobject_cast(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } emit themeChanged(); } void KisMainWindow::updateReloadFileAction(KisDocument *doc) { Q_UNUSED(doc); // d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url) { dbgUI << "KisMainWindow::addRecentURL url=" << url.toDisplayString(); // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) if (path.contains(*it)) ok = false; // it's in the tmp resource #ifdef HAVE_KIO if (ok) { KRecentDocument::add(QUrl::fromLocalFile(path)); } #endif } #ifdef HAVE_KIO else { KRecentDocument::add(url.adjusted(QUrl::StripTrailingSlash)); } #endif if (ok) { d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KMainWindow* window, KMainWindow::memberList()) static_cast(window)->reloadRecentFileList(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries( KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } else { QString caption( d->activeView->document()->caption() ); if (d->readOnly) { caption += ' ' + i18n("(write protected)"); } d->activeView->setWindowTitle(caption); updateCaption(caption, d->activeView->document()->isModified()); if (!d->activeView->document()->url().fileName().isEmpty()) d->saveAction->setToolTip(i18n("Save as %1", d->activeView->document()->url().fileName())); else d->saveAction->setToolTip(i18n("Save")); } } void KisMainWindow::updateCaption(const QString & caption, bool mod) { dbgUI << "KisMainWindow::updateCaption(" << caption << "," << mod << ")"; #ifdef KRITA_ALPHA setCaption(QString("ALPHA %1: %2").arg(KRITA_ALPHA).arg(caption), mod); return; #endif #ifdef KRITA_BETA setCaption(QString("BETA %1: %2").arg(KRITA_BETA).arg(caption), mod); return; #endif #ifdef KRITA_RC setCaption(QString("RELEASE CANDIDATE %1: %2").arg(KRITA_RC).arg(caption), mod); return; #endif setCaption(caption, mod); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url) { if (!QFile(url.toLocalFile()).exists()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url); } bool KisMainWindow::openDocumentInternal(const QUrl &url, KisDocument *newdoc) { if (!url.isLocalFile()) { qDebug() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } if (!newdoc) { newdoc = KisPart::instance()->createDocument(); } d->firstTime = true; connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); bool openRet = (!isImporting()) ? newdoc->openUrl(url) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); updateReloadFileAction(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } return true; } void KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document) { KisView *view = KisPart::instance()->createView(document, resourceManager(), actionCollection(), this); addView(view); emit guiLoadingFinished(); } QStringList KisMainWindow::showOpenFileDialog() { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); dialog.setCaption(isImporting() ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); emit loadCompleted(); } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { dbgUI << "KisMainWindow::slotLoadCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { dbgUI << "KisMainWindow::slotSaveCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { dbgUI << "KisMainWindow::slotSaveCompleted"; KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::hackIsSaving() const { StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); return !l.owns_lock(); } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool silent, int specialOutputFlag) { if (!document) { return true; } /** * Make sure that we cannot enter this method twice! * * The lower level functions may call processEvents() so * double-entry is quite possible to achive. Here we try to lock * the mutex, and if it is failed, just cancel saving. */ StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return false; KisDelayedSaveDialog dlg(document->image(), this); dlg.blockIfImageIsBusy(); if (dlg.result() != QDialog::Accepted) { return false; } bool reset_url; if (document->url().isEmpty()) { reset_url = true; saveas = true; } else { reset_url = false; } connect(document, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); QUrl oldURL = document->url(); QString oldFile = document->localFilePath(); QByteArray _native_format = document->nativeFormatMimeType(); QByteArray oldOutputFormat = document->outputMimeType(); int oldSpecialOutputFlag = document->specialOutputFlag(); QUrl suggestedURL = document->url(); QStringList mimeFilter; if (specialOutputFlag) { mimeFilter = KisMimeDatabase::suffixesForMimeType(_native_format); } else { mimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Export); } if (!mimeFilter.contains(oldOutputFormat) && !isExporting()) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldOutputFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = suggestedURL.fileName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name int c = suggestedFilename.lastIndexOf('.'); const QString ext = KisMimeDatabase::suffixesForMimeType(_native_format).first(); if (!ext.isEmpty()) { if (c < 0) suggestedFilename = suggestedFilename + "." + ext; else suggestedFilename = suggestedFilename.left(c) + "." + ext; } else { // current filename extension wrong anyway if (c > 0) { // this assumes that a . signifies an extension, not just a . suggestedFilename = suggestedFilename.left(c); } } suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument"); dialog.setCaption(i18n("untitled")); if (isExporting() && !d->lastExportUrl.isEmpty()) { dialog.setDefaultDir(d->lastExportUrl.toLocalFile(), true); } else { dialog.setDefaultDir(suggestedURL.toLocalFile(), true); } // Default to all supported file types if user is exporting, otherwise use Krita default dialog.setMimeTypeFilters(mimeFilter, QString(_native_format)); QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { fn.append(KisMimeDatabase::suffixesForMimeType(_native_format).first()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.baseName()); } QByteArray outputFormat = _native_format; if (!specialOutputFlag) { QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile()); outputFormat = outputFormatString.toLatin1(); } if (!isExporting()) justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()) && (specialOutputFlag == oldSpecialOutputFlag); else justChangingFilterOptions = (newURL == d->lastExportUrl) && (outputFormat == d->lastExportedFormat) && (specialOutputFlag == d->lastExportSpecialOutputFlag); bool bOk = true; if (newURL.isEmpty()) { bOk = false; } // adjust URL before doing checks on whether the file exists. if (specialOutputFlag) { QString fileName = newURL.fileName(); if ( specialOutputFlag== KisDocument::SaveAsDirectoryStore) { //dbgKrita << "save to directory: " << newURL.url(); } } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions || document->confirmNonNativeSave(isExporting())) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { // // Note: // If the user is stupid enough to Export to the current URL, // we do _not_ change this operation into a Save As. Reasons // follow: // // 1. A check like "isExporting() && oldURL == newURL" // doesn't _always_ work on case-insensitive filesystems // and inconsistent behaviour is bad. // 2. It is probably not a good idea to change document->mimeType // and friends because the next time the user File/Save's, // (not Save As) they won't be expecting that they are // using their File/Export settings // // As a bad side-effect of this, the modified flag will not // be updated and it is possible that what is currently on // their screen is not what is stored on disk (through loss // of formatting). But if you are dumb enough to change // mimetype but not the filename, then arguably, _you_ are // the "bug" :) // // - Clarence // document->setOutputMimeType(outputFormat, specialOutputFlag); if (!isExporting()) { // Save As ret = document->saveAs(newURL); if (ret) { dbgUI << "Successful Save As!"; addRecentURL(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); document->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } } else { // Export ret = document->exportDocument(newURL); if (ret) { // a few file dialog convenience things d->lastExportUrl = newURL; d->lastExportedFormat = outputFormat; d->lastExportSpecialOutputFlag = specialOutputFlag; } // always restore output format document->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } if (silent) // don't let the document change the window caption document->setTitleModified(); } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving bool needConfirm = document->confirmNonNativeSave(false) && !document->isNativeFormat(oldOutputFormat); if (!needConfirm || (needConfirm && exportConfirmation(oldOutputFormat /* not so old :) */)) ) { // be sure document has the correct outputMimeType! if (isExporting() || document->isModified()) { ret = document->save(); } if (!ret) { dbgUI << "Failed Save!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); } } else ret = false; } if (!ret && reset_url) document->resetURL(); //clean the suggested filename as the save dialog was rejected updateReloadFileAction(document); updateCaption(); return ret; } bool KisMainWindow::exportConfirmation(const QByteArray &/*outputFormat*/) { return true; } void KisMainWindow::undo() { if (activeView()) { activeView()->undoAction()->trigger(); d->undo->setText(activeView()->undoAction()->text()); } } void KisMainWindow::redo() { if (activeView()) { activeView()->redoAction()->trigger(); d->redo->setText(activeView()->redoAction()->text()); } } void KisMainWindow::showEvent(QShowEvent *e) { KXmlGuiWindow::showEvent(e); if (!d->geometryInitialized) { /** * We should move the window only *after* it has been shown on * screen, otherwise it will become owned by a wrong screen, which * will make positioning of all the child widgets wrong. * (see bug https://bugs.kde.org/show_bug.cgi?id=362025) * * This is actually a bug/feature of Qt 5.5.x and it has been * fixed in Qt 5.6.0. So we can avoid this delay on newer versions * of Qt. */ QTimer::singleShot(1, this, SLOT(initializeGeometry())); d->geometryInitialized = true; } } void KisMainWindow::closeEvent(QCloseEvent *e) { d->mdiArea->closeAllSubWindows(); QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only"); if ((action) && (action->isChecked())) { action->setChecked(false); } KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); cfg.writeEntry("ko_geometry", saveGeometry().toBase64()); cfg.writeEntry("ko_windowstate", saveState().toBase64()); { KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); } if(d->activeView && d->activeView->document() && d->activeView->document()->isLoading()) { e->setAccepted(false); return; } QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); if (d->noCleanup) return; Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { KisView *view = dynamic_cast(subwin); if (view) { KisPart::instance()->removeView(view); } } if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency Q_FOREACH (QDockWidget* dockWidget, d->dockWidgetsMap) dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget)); } } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = config->group("MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); // Save collapsable state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x()); dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y()); dockGroup.writeEntry("width", (int) i.value()->widget()->width()); dockGroup.writeEntry("height", (int) i.value()->widget()->height()); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); actionCollection()->action("edit_undo")->setText(activeView()->undoAction()->text()); actionCollection()->action("edit_redo")->setText(activeView()->redoAction()->text()); d->viewManager->setCurrentView(view); } void KisMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisMainWindow::dropEvent(QDropEvent *event) { if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { openDocument(url); } } } void KisMainWindow::dragMoveEvent(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeaveEvent(QDragLeaveEvent * /*event*/) { if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::slotFileNew() { KisOpenPane *startupWidget = 0; const QStringList mimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Import); startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/")); startupWidget->setWindowModality(Qt::WindowModal); KisConfig cfg; int w = cfg.defImageWidth(); int h = cfg.defImageHeight(); const double resolution = cfg.defImageResolution(); const QString colorModel = cfg.defColorModel(); const QString colorDepth = cfg.defaultColorDepth(); const QString colorProfile = cfg.defColorProfile(); CustomDocumentWidgetItem item; item.widget = new KisCustomImageWidget(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.icon = "application-x-krita"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); QSize sz = KisClipboard::instance()->clipSize(); if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { w = sz.width(); h = sz.height(); } item.widget = new KisImageFromClipboard(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.title = i18n("Create from Clipboard"); item.icon = "klipper"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); // calls deleteLater connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*))); // calls deleteLater connect(startupWidget, SIGNAL(openTemplate(const QUrl&)), KisPart::instance(), SLOT(openTemplate(const QUrl&))); startupWidget->exec(); // Cancel calls deleteLater... } void KisMainWindow::slotFileOpen() { QStringList urls = showOpenFileDialog(); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { bool res = openDocument(QUrl::fromLocalFile(url)); if (!res) { warnKrita << "Loading" << url << "failed"; } } } } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl(url)); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document())) emit documentSaved(); } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true)) emit documentSaved(); } KoCanvasResourceManager *KisMainWindow::resourceManager() const { return d->viewManager->resourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } bool KisMainWindow::restoreWorkspace(const QByteArray &state) { QByteArray oldState = saveState(); const bool showTitlebars = KisConfig().showDockerTitleBars(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->hide(); dock->titleBarWidget()->setVisible(showTitlebars); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating()); } } return false; } Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(showTitlebars || (dock->isFloating() && isCollapsed)); } } return success; } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { if(!slotFileCloseAll()) return; close(); Q_FOREACH (QPointer mainWin, KisPart::instance()->mainWindows()) { if (mainWin != this) { if(!mainWin->slotFileCloseAll()) return; mainWin->close(); } } } void KisMainWindow::slotFilePrint() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) { printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point); printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()), activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())), QPrinter::Inch); printJob->startPrinting(KisPrintJob::DeleteWhenDone); } else { delete printJob; } delete printDialog; } void KisMainWindow::slotFilePrintPreview() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KisPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); preview->exec(); delete preview; } KisPrintJob* KisMainWindow::exportToPdf(const QString &pdfFileName) { if (!activeView()) return 0; KoPageLayout pageLayout; pageLayout = activeView()->pageLayout(); return exportToPdf(pageLayout, pdfFileName); } KisPrintJob* KisMainWindow::exportToPdf(KoPageLayout pageLayout, QString pdfFileName) { if (!activeView()) return 0; if (!activeView()->document()) return 0; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KisDocument* pDoc = d->activeView->document(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.fileName(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument"); dialog.setCaption(i18n("Export as PDF")); dialog.setDefaultDir(startUrl.toLocalFile()); dialog.setMimeTypeFilters(QStringList() << "application/pdf"); QUrl url = QUrl::fromUserInput(dialog.filename()); pdfFileName = url.toLocalFile(); if (pdfFileName.isEmpty()) return 0; } KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setDocName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } //before printing check if the printer can handle printing if (!printJob->canPrint()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file")); } printJob->startPrinting(KisPrintJob::DeleteWhenDone); return printJob; } void KisMainWindow::importAnimation() { if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); document->setFileProgressProxy(); document->setFileProgressUpdater(i18n("Import frames")); KisAnimationImporter importer(document); KisImportExportFilter::ConversionStatus status = importer.import(files, firstFrame, step); document->clearFileProgressUpdater(); document->clearFileProgressProxy(); if (status != KisImportExportFilter::OK && status != KisImportExportFilter::InternalError) { QString msg = KisImportExportFilter::conversionStatusString(status); if (!msg.isEmpty()) QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg)); } activeView()->canvasBase()->refetchDataFromImage(); } } -void KisMainWindow::exportAnimation() -{ - if (!activeView()) return; - - KisDocument *document = activeView()->document(); - if (!document) return; - - document->setFileProgressProxy(); - document->setFileProgressUpdater(i18n("Export frames")); - KisAnimationExporterUI exporter(this); - KisImportExportFilter::ConversionStatus status = exporter.exportSequence(document); - document->clearFileProgressUpdater(); - document->clearFileProgressProxy(); - - if (status != KisImportExportFilter::OK && status != KisImportExportFilter::InternalError) { - QString msg = KisImportExportFilter::conversionStatusString(status); - - if (!msg.isEmpty()) - QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish export animation:\n%1", msg)); - } - activeView()->canvasBase()->refetchDataFromImage(); -} - void KisMainWindow::slotConfigureToolbars() { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(KSharedConfig::openConfig()->group("krita")); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg; cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } } void KisMainWindow::slotProgress(int value) { qApp->processEvents(); StdLockableWrapper wrapper(&d->progressMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return; dbgUI << "KisMainWindow::slotProgress" << value; if (value <= -1 || value >= 100) { if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; disconnect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); statusBar()->removeWidget(d->progressCancel); delete d->progressCancel; d->progressCancel = 0; } d->firstTime = true; return; } if (d->firstTime || !d->progress) { // The statusbar might not even be created yet. // So check for that first, and create it if necessary QStatusBar *bar = findChild(); if (!bar) { statusBar()->show(); QApplication::sendPostedEvents(this, QEvent::ChildAdded); } if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; disconnect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); statusBar()->removeWidget(d->progressCancel); delete d->progressCancel; d->progress = 0; } d->progressCancel = new QToolButton(statusBar()); d->progressCancel->setMaximumHeight(statusBar()->fontMetrics().height()); d->progressCancel->setIcon(KisIconUtils::loadIcon("process-stop")); statusBar()->addPermanentWidget(d->progressCancel); d->progress = new QProgressBar(statusBar()); d->progress->setMaximumHeight(statusBar()->fontMetrics().height()); d->progress->setRange(0, 100); statusBar()->addPermanentWidget(d->progress); connect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); d->progress->show(); d->progressCancel->show(); d->firstTime = false; } if (!d->progress.isNull()) { d->progress->setValue(value); } qApp->processEvents(); } void KisMainWindow::slotProgressCanceled() { emit sigProgressCanceled(); } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } void KisMainWindow::slotReloadFile() { KisDocument* document = d->activeView->document(); if (!document || document->url().isEmpty()) return; if (document->isModified()) { bool ok = QMessageBox::question(this, i18nc("@title:window", "Krita"), i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; if (!ok) return; } QUrl url = document->url(); saveWindowSettings(); if (!document->reload()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document")); } return; } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; d->isImporting = true; slotFileOpen(); d->isImporting = false; } void KisMainWindow::slotExportFile() { dbgUI << "slotExportFile()"; d->isExporting = true; slotFileSaveAs(); d->isExporting = false; } bool KisMainWindow::isImporting() const { return d->isImporting; } bool KisMainWindow::isExporting() const { return d->isExporting; } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } KoDockWidgetTitleBar *titleBar = dynamic_cast(dockWidget->titleBarWidget()); // Check if the dock widget is supposed to be collapsable if (!dockWidget->titleBarWidget()) { titleBar = new KoDockWidgetTitleBar(dockWidget); dockWidget->setTitleBarWidget(titleBar); titleBar->setCollapsable(factory->isCollapsable()); } titleBar->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } bool collapsed = factory->defaultCollapsed(); bool locked = false; group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); collapsed = group.readEntry("Collapsed", collapsed); locked = group.readEntry("Locked", locked); //dbgKrita << "docker" << factory->id() << dockWidget << "collapsed" << collapsed << "locked" << locked << "titlebar" << titleBar; if (titleBar && collapsed) titleBar->setCollapsed(true); if (titleBar && locked) titleBar->setLocked(true); d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_MAC dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::setToolbarList(QList toolbarList) { qDeleteAll(d->toolbarList); d->toolbarList = toolbarList; } void KisMainWindow::slotDocumentTitleModified(const QString &caption, bool mod) { updateCaption(caption, mod); updateReloadFileAction(d->activeView ? d->activeView->document() : 0); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = doc->url().toDisplayString(); if (title.isEmpty()) title = doc->image()->objectName(); QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); if (child) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, child->document()->url().toDisplayString()); } else { text = i18n("%1 %2", i + 1, child->document()->url().toDisplayString()); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } updateCaption(); } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg; QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); } KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QBrush brush(cfg.getMDIBackgroundColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } void KisMainWindow::newView(QObject *document) { KisDocument *doc = qobject_cast(document); addViewAndNotifyLoadingCompleted(doc); d->actionManager()->updateGUI(); } void KisMainWindow::newWindow() { KisPart::instance()->createMainWindow()->show(); } void KisMainWindow::closeCurrentWindow() { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Calligra LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resources().isEmpty()) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointerKisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(const QList > &optionWidgetList) { Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_MAC w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::applyDefaultSettings(QPrinter &printer) { if (!d->activeView) return; QString title = d->activeView->document()->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { title = d->activeView->document()->url().fileName(); // strip off the native extension (I don't want foobar.kwd.ps when printing into a file) QString extension = KisMimeDatabase::suffixesForMimeType(d->activeView->document()->outputMimeType()).first(); if (title.endsWith(extension)) { title.chop(extension.length()); } } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint())); // d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview())); // d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo ->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->exportPdf = actionManager->createAction("file_export_pdf"); connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); d->importAnimation = actionManager->createAction("file_import_animation"); + d->importAnimation->setActivationFlags(KisAction::IMAGE_HAS_ANIMATION); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); - d->exportAnimation = actionManager->createAction("file_export_animation"); - connect(d->exportAnimation, SIGNAL(triggered()), this, SLOT(exportAnimation())); - d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); // d->reloadFile = actionManager->createAction("file_reload_file"); // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED); // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); d->toggleDockers = actionManager->createAction("view_toggledockers"); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); d->toggleDockerTitleBars = actionManager->createAction("view_toggledockertitlebars"); { KisConfig cfg; d->toggleDockerTitleBars->setChecked(cfg.showDockerTitleBars()); } connect(d->toggleDockerTitleBars, SIGNAL(toggled(bool)), SLOT(showDockerTitleBars(bool))); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createAction("file_close"); connect(d->close, SIGNAL(triggered()), SLOT(closeCurrentWindow())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to componensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } restoreWorkspace(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray()))); } void KisMainWindow::showManual() { QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::showDockerTitleBars(bool show) { Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(show || (dock->isFloating() && isCollapsed)); } } KisConfig cfg; cfg.setShowDockerTitleBars(show); } void KisMainWindow::moveEvent(QMoveEvent *e) { if (qApp->desktop()->screenNumber(this) != qApp->desktop()->screenNumber(e->oldPos())) { KisConfigNotifier::instance()->notifyConfigChanged(); } } #include diff --git a/libs/ui/KisMainWindow.h b/libs/ui/KisMainWindow.h index dd68b6c7de..d81d2c7781 100644 --- a/libs/ui/KisMainWindow.h +++ b/libs/ui/KisMainWindow.h @@ -1,484 +1,483 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2004 David Faure 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_MAIN_WINDOW_H #define KIS_MAIN_WINDOW_H #include "kritaui_export.h" #include #include #include #include #include #include #include "KisView.h" class QCloseEvent; class QMoveEvent; struct KoPageLayout; class KoCanvasResourceManager; class KisDocument; class KisView; class KisPrintJob; class KoDockFactoryBase; class QDockWidget; class KisView; class KisViewManager; /** * @brief Main window for Krita * * This class is used to represent a main window within a Krita session. Each * main window contains a menubar and some toolbars, and potentially several * views of several canvases. * */ class KRITAUI_EXPORT KisMainWindow : public KXmlGuiWindow, public KoCanvasSupervisor { Q_OBJECT public: /** * Constructor. * * Initializes a Calligra main window (with its basic GUI etc.). */ explicit KisMainWindow(); /** * Destructor. */ virtual ~KisMainWindow(); /** * Update caption from document info - call when document info * (title in the about page) changes. */ void updateCaption(); // If noCleanup is set, KisMainWindow will not delete the root document // or part manager on destruction. void setNoCleanup(bool noCleanup); /** * @brief showView shows the given view. Override this if you want to show * the view in a different way than by making it the central widget, for instance * as an QMdiSubWindow */ virtual void showView(KisView *view); /** * @returns the currently active view */ KisView *activeView() const; /** * Sets the maximum number of recent documents entries. */ void setMaxRecentItems(uint _number); /** * The document opened a URL -> store into recent documents list. */ void addRecentURL(const QUrl &url); /** * Load the desired document and show it. * @param url the URL to open * * @return TRUE on success. */ bool openDocument(const QUrl &url); void setReadWrite(bool readwrite); /// Return the list of dock widgets belonging to this main window. QList dockWidgets() const; QDockWidget* dockWidget(const QString &id); QList canvasObservers() const; KoCanvasResourceManager *resourceManager() const; int viewCount() const; /** * A wrapper around restoreState * @param state the saved state * @return TRUE on success */ bool restoreWorkspace(const QByteArray &state); KisViewManager *viewManager() const; void addViewAndNotifyLoadingCompleted(KisDocument *document); QStringList showOpenFileDialog(); /** * Shows if the main window is saving anything right now. If the * user presses Ctrl+W too fast, then the document can be close * before the saving is completed. I'm not sure if it is fixable * in any way without avoiding using porcessEvents() * everywhere (DK) * * Don't use it unless you have no option. */ bool hackIsSaving() const; Q_SIGNALS: /** * This signal is emitted if the document has been saved successfully. */ void documentSaved(); /// This signal is emitted when this windows has finished loading of a /// document. The document may be opened in another window in the end. /// In this case, the signal means there is no link between the window /// and the document anymore. void loadCompleted(); /// This signal is emitted right after the docker states have been succefully restored from config void restoringDone(); /// This signal is emitted when the color theme changes void themeChanged(); /// This signal is emitted when the shortcut key configuration has changed void keyBindingsChanged(); void guiLoadingFinished(); /// This signal is emitted when the user clicked on the progressbar cancel void sigProgressCanceled(); public Q_SLOTS: /** * Slot for opening a new document. * * If the current document is empty, the new document replaces it. * If not, a new mainwindow will be opened for showing the document. */ void slotFileNew(); /** * Slot for opening a saved file. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpen(); /** * Slot for opening a file among the recently opened files. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpenRecent(const QUrl &); /** * @brief slotPreferences open the preferences dialog */ void slotPreferences(); /** * Saves the current document with the current name. */ void slotFileSave(); KisPrintJob* exportToPdf(const QString &pdfFileName = QString()); void slotProgress(int value); /** * Saves the document, asking for a filename if necessary. * * @param saveas if set to TRUE the user is always prompted for a filename * * @param silent if set to TRUE rootDocument()->setTitleModified will not be called. * * @param specialOutputFlag set to enums defined in KisDocument if save to special output format * * @return TRUE on success, false on error or cancel * (don't display anything in this case, the error dialog box is also implemented here * but restore the original URL in slotFileSaveAs) */ bool saveDocument(KisDocument *document, bool saveas = false, bool silent = false, int specialOutputFlag = 0); /** * Update the option widgets to the argument ones, removing the currently set widgets. */ void newOptionWidgets(const QList > & optionWidgetList); private Q_SLOTS: /** * Save the list of recent files. */ void saveRecentFiles(); void slotLoadCompleted(); void slotLoadCanceled(const QString &); void slotSaveCompleted(); void slotSaveCanceled(const QString &); void forceDockTabFonts(); void slotProgressCanceled(); /** * @internal */ void slotDocumentTitleModified(const QString &caption, bool mod); /** * Prints the actual document. */ void slotFilePrint(); /** * Saves the current document with a new name. */ void slotFileSaveAs(); void slotFilePrintPreview(); KisPrintJob* exportToPdf(KoPageLayout pageLayout, QString pdfFileName = QString()); void importAnimation(); - void exportAnimation(); /** * Show a dialog with author and document information. */ void slotDocumentInfo(); /** * Closes all open documents. */ bool slotFileCloseAll(); /** * @brief showAboutApplication show the about box */ virtual void showAboutApplication(); /** * Closes the mainwindow. */ void slotFileQuit(); /** * Configure toolbars. */ void slotConfigureToolbars(); /** * Post toolbar config. * (Plug action lists back in, etc.) */ void slotNewToolbarConfig(); /** * Shows or hides a toolbar */ void slotToolbarToggled(bool toggle); /** * Toggle full screen on/off. */ void viewFullscreen(bool fullScreen); /** * Toggle docker titlebars on/off. */ void showDockerTitleBars(bool show); /** * Reload file */ void slotReloadFile(); /** * File --> Import * * This will call slotFileOpen(). To differentiate this from an ordinary * call to slotFileOpen() call @ref isImporting(). */ void slotImportFile(); /** * File --> Export * * This will call slotFileSaveAs(). To differentiate this from an ordinary * call to slotFileSaveAs() call @ref isExporting(). */ void slotExportFile(); /** * Hide the dockers */ void toggleDockersVisibility(bool visible); /** * Handle theme changes from theme manager */ void slotThemeChanged(); void undo(); void redo(); void subWindowActivated(); void updateWindowMenu(); void setActiveSubWindow(QWidget *window); void configChanged(); void newView(QObject *document); void newWindow(); void closeCurrentWindow(); void checkSanity(); /// Quits Krita with error message from m_errorMessage. void showErrorAndDie(); protected: void showEvent(QShowEvent * e); void closeEvent(QCloseEvent * e); void resizeEvent(QResizeEvent * e); /// Set the active view, this will update the undo/redo actions virtual void setActiveView(KisView *view); // QWidget overrides virtual void dragEnterEvent(QDragEnterEvent * event); virtual void dropEvent(QDropEvent * event); virtual void dragMoveEvent(QDragMoveEvent * event); virtual void dragLeaveEvent(QDragLeaveEvent * event); void setToolbarList(QList toolbarList); private: /** * Add a the given view to the list of views of this mainwindow. * This is a private implementation. For public usage please use * newView() and addViewAndNotifyLoadingCompleted(). */ void addView(KisView *view); friend class KisApplication; /** * Returns the dockwidget specified by the @p factory. If the dock widget doesn't exist yet it's created. * Add a "view_palette_action_menu" action to your view menu if you want to use closable dock widgets. * @param factory the factory used to create the dock widget if needed * @return the dock widget specified by @p factory (may be 0) */ QDockWidget* createDockWidget(KoDockFactoryBase* factory); bool openDocumentInternal(const QUrl &url, KisDocument *newdoc = 0); /** * Returns whether or not the current slotFileSave[As]() or saveDocument() * call is actually an export operation (like File --> Export). * * If this is true, you must call KisDocument::export() instead of * KisDocument::save() or KisDocument::saveAs(), in any reimplementation of * saveDocument(). */ bool isExporting() const; /** * Returns whether or not the current slotFileOpen() or openDocument() * call is actually an import operation (like File --> Import). * * If this is true, you must call KisDocument::import() instead of * KisDocument::openUrl(), in any reimplementation of openDocument() or * openDocumentInternal(). */ bool isImporting() const; /** * Reloads the recent documents list. */ void reloadRecentFileList(); /** * Updates the window caption based on the document info and path. */ void updateCaption(const QString & caption, bool mod); void updateReloadFileAction(KisDocument *doc); void saveWindowSettings(); QPointeractiveKisView(); void applyDefaultSettings(QPrinter &printer); bool exportConfirmation(const QByteArray &outputFormat); void createActions(); void applyToolBarLayout(); protected: void moveEvent(QMoveEvent *e); private Q_SLOTS: void initializeGeometry(); void showManual(); void switchTab(int index); private: /** * Struct used in the list created by createCustomDocumentWidgets() */ struct CustomDocumentWidgetItem { /// Pointer to the custom document widget QWidget *widget; /// title used in the sidebar. If left empty it will be displayed as "Custom Document" QString title; /// icon used in the sidebar. If left empty it will use the unknown icon QString icon; }; class Private; Private * const d; QString m_errorMessage; bool m_dieOnError; }; #endif diff --git a/libs/ui/actions/kis_selection_action_factories.cpp b/libs/ui/actions/kis_selection_action_factories.cpp index 3bc1a3c7db..db95e95e51 100644 --- a/libs/ui/actions/kis_selection_action_factories.cpp +++ b/libs/ui/actions/kis_selection_action_factories.cpp @@ -1,538 +1,648 @@ /* * Copyright (c) 2012 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_selection_action_factories.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_pixel_selection.h" #include "kis_paint_layer.h" #include "kis_image.h" #include "kis_image_barrier_locker.h" #include "kis_fill_painter.h" #include "kis_transaction.h" #include "kis_iterator_ng.h" #include "kis_processing_applicator.h" #include "kis_group_layer.h" #include "commands/kis_selection_commands.h" #include "commands/kis_image_layer_add_command.h" #include "kis_tool_proxy.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_selection_manager.h" #include "kis_transaction_based_command.h" #include "kis_selection_filters.h" #include "kis_shape_selection.h" #include "KisPart.h" #include "kis_shape_layer.h" #include #include #include +#include "kis_canvas_resource_provider.h" +#include "kis_figure_painting_tool_helper.h" + namespace ActionHelper { void copyFromDevice(KisViewManager *view, KisPaintDeviceSP device, bool makeSharpClip = false) { KisImageWSP image = view->image(); if (!image) return; KisSelectionSP selection = view->selection(); QRect rc = (selection) ? selection->selectedExactRect() : image->bounds(); KisPaintDeviceSP clip = new KisPaintDevice(device->colorSpace()); Q_CHECK_PTR(clip); const KoColorSpace *cs = clip->colorSpace(); // TODO if the source is linked... copy from all linked layers?!? // Copy image data KisPainter::copyAreaOptimized(QPoint(), device, clip, rc); if (selection) { // Apply selection mask. KisPaintDeviceSP selectionProjection = selection->projection(); KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width()); KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width()); const KoColorSpace *selCs = selection->projection()->colorSpace(); for (qint32 y = 0; y < rc.height(); y++) { for (qint32 x = 0; x < rc.width(); x++) { /** * Sharp method is an exact reverse of COMPOSITE_OVER * so if you cover the cut/copied piece over its source * you get an exactly the same image without any seams */ if (makeSharpClip) { qreal dstAlpha = cs->opacityF(layerIt->rawData()); qreal sel = selCs->opacityF(selectionIt->oldRawData()); qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha); float mask = newAlpha / dstAlpha; cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1); } else { cs->applyAlphaU8Mask(layerIt->rawData(), selectionIt->oldRawData(), 1); } layerIt->nextPixel(); selectionIt->nextPixel(); } layerIt->nextRow(); selectionIt->nextRow(); } } KisClipboard::instance()->setClip(clip, rc.topLeft()); } } void KisSelectAllActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Select All")); if (!image->globalSelection()) { ap->applyCommand(new KisSetEmptyGlobalSelectionCommand(image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } struct SelectAll : public KisTransactionBasedCommand { SelectAll(KisImageSP image) : m_image(image) {} KisImageSP m_image; KUndo2Command* paint() { KisSelectionSP selection = m_image->globalSelection(); KisSelectionTransaction transaction(selection->pixelSelection()); selection->pixelSelection()->select(m_image->bounds()); return transaction.endAndTake(); } }; ap->applyCommand(new SelectAll(image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisDeselectActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KUndo2Command *cmd = new KisDeselectGlobalSelectionCommand(image); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisReselectActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KUndo2Command *cmd = new KisReselectGlobalSelectionCommand(image); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view) { KisNodeSP node = view->activeNode(); if (!node || !node->hasEditablePaintDevice()) return; KisSelectionSP selection = view->selection(); QRect selectedRect = selection ? selection->selectedRect() : view->image()->bounds(); Q_UNUSED(selectedRect); KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice(); Q_UNUSED(filled); bool usePattern = false; bool useBgColor = false; if (fillSource.contains("pattern")) { usePattern = true; } else if (fillSource.contains("bg")) { useBgColor = true; } KisProcessingApplicator applicator(view->image(), node, KisProcessingApplicator::NONE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Flood Fill Layer")); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(view->image(), node, 0, view->resourceProvider()->resourceManager()); if (!fillSource.contains("opacity")) { resources->setOpacity(1.0); } KisProcessingVisitorSP visitor = new FillProcessingVisitor(QPoint(0, 0), // start position selection, resources, false, // fast mode usePattern, true, // fill only selection, 0, // feathering radius 0, // sizemod 80, // threshold, false, // unmerged useBgColor); applicator.applyVisitor(visitor, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.end(); } void KisClearActionFactory::run(KisViewManager *view) { // XXX: "Add saving of XML data for Clear action" view->canvasBase()->toolProxy()->deleteSelection(); } void KisImageResizeToSelectionActionFactory::run(KisViewManager *view) { // XXX: "Add saving of XML data for Image Resize To Selection action" KisSelectionSP selection = view->selection(); if (!selection) return; view->image()->cropImage(selection->selectedExactRect()); } void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view) { KisImageSP image = view->image(); if (!image) return; bool haveShapesSelected = view->selectionManager()->haveShapesSelected(); if (haveShapesSelected) { // XXX: "Add saving of XML data for Cut/Copy of shapes" KisImageBarrierLocker locker(image); if (willCut) { view->canvasBase()->toolProxy()->cut(); } else { view->canvasBase()->toolProxy()->copy(); } } else { KisNodeSP node = view->activeNode(); if (!node) return; KisSelectionSP selection = view->selection(); if (selection.isNull()) return; { KisImageBarrierLocker locker(image); KisPaintDeviceSP dev = node->paintDevice(); if (!dev) { dev = node->projection(); } if (!dev) { view->showFloatingMessage( i18nc("floating message when cannot copy from a node", "Cannot copy pixels from this type of layer "), QIcon(), 3000, KisFloatingMessage::Medium); return; } if (dev->exactBounds().isEmpty()) { view->showFloatingMessage( i18nc("floating message when copying empty selection", "Selection is empty: no pixels were copied "), QIcon(), 3000, KisFloatingMessage::Medium); return; } ActionHelper::copyFromDevice(view, dev, makeSharpClip); } if (willCut) { KUndo2Command *command = 0; if (willCut && node->hasEditablePaintDevice()) { struct ClearSelection : public KisTransactionBasedCommand { ClearSelection(KisNodeSP node, KisSelectionSP sel) : m_node(node), m_sel(sel) {} KisNodeSP m_node; KisSelectionSP m_sel; KUndo2Command* paint() { KisSelectionSP cutSelection = m_sel; // Shrinking the cutting area was previously used // for getting seamless cut-paste. Now we use makeSharpClip // instead. // QRect originalRect = cutSelection->selectedExactRect(); // static const int preciseSelectionThreshold = 16; // // if (originalRect.width() > preciseSelectionThreshold || // originalRect.height() > preciseSelectionThreshold) { // cutSelection = new KisSelection(*m_sel); // delete cutSelection->flatten(); // // KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false); // // QRect processingRect = filter->changeRect(originalRect); // filter->process(cutSelection->pixelSelection(), processingRect); // } KisTransaction transaction(m_node->paintDevice()); m_node->paintDevice()->clearSelection(cutSelection); m_node->setDirty(cutSelection->selectedRect()); return transaction.endAndTake(); } }; command = new ClearSelection(node, selection); } KUndo2MagicString actionName = willCut ? kundo2_i18n("Cut") : kundo2_i18n("Copy"); KisProcessingApplicator *ap = beginAction(view, actionName); if (command) { ap->applyCommand(command, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); } KisOperationConfiguration config(id()); config.setProperty("will-cut", willCut); endAction(ap, config.toXML()); } } } void KisCopyMergedActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; image->barrierLock(); KisPaintDeviceSP dev = image->root()->projection(); ActionHelper::copyFromDevice(view, dev); image->unlock(); KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Copy Merged")); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisPasteActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KisPaintDeviceSP clip = KisClipboard::instance()->clip(image->bounds(), true); if (clip) { KisPaintLayer *newLayer = new KisPaintLayer(image.data(), image->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE_U8, clip); KisNodeSP aboveNode = view->activeLayer(); KisNodeSP parentNode = aboveNode ? aboveNode->parent() : image->root(); KUndo2Command *cmd = new KisImageLayerAddCommand(image, newLayer, parentNode, aboveNode); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); endAction(ap, KisOperationConfiguration(id()).toXML()); } else { // XXX: "Add saving of XML data for Paste of shapes" view->canvasBase()->toolProxy()->paste(); } } void KisPasteNewActionFactory::run(KisViewManager *viewManager) { Q_UNUSED(viewManager); KisPaintDeviceSP clip = KisClipboard::instance()->clip(QRect(), true); if (!clip) return; QRect rect = clip->exactBounds(); if (rect.isEmpty()) return; KisDocument *doc = KisPart::instance()->createDocument(); KisImageSP image = new KisImage(doc->createUndoStore(), rect.width(), rect.height(), clip->colorSpace(), i18n("Pasted")); KisPaintLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE_U8, clip->colorSpace()); KisPainter::copyAreaOptimized(QPoint(), clip, layer->paintDevice(), rect); image->addNode(layer.data(), image->rootLayer()); doc->setCurrentImage(image); KisPart::instance()->addDocument(doc); KisMainWindow *win = viewManager->mainWindow(); win->addViewAndNotifyLoadingCompleted(doc); } void KisInvertSelectionOperaton::runFromXML(KisViewManager* view, const KisOperationConfiguration& config) { KisSelectionFilter* filter = new KisInvertSelectionFilter(); runFilter(filter, view, config); } void KisSelectionToVectorActionFactory::run(KisViewManager *view) { KisSelectionSP selection = view->selection(); if (selection->hasShapeSelection() || !selection->outlineCacheValid()) { return; } QPainterPath selectionOutline = selection->outlineCache(); QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); shape->setShapeId(KoPathShapeId); /** * Mark a shape that it belongs to a shape selection */ if(!shape->userData()) { shape->setUserData(new KisShapeSelectionMarker); } KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection")); ap->applyCommand(view->canvasBase()->shapeController()->addShape(shape), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } class KisShapeSelectionPaste : public KoOdfPaste { public: KisShapeSelectionPaste(KisViewManager* view) : m_view(view) { } virtual ~KisShapeSelectionPaste() { } virtual bool process(const KoXmlElement & body, KoOdfReadStore & odfStore) { KoOdfLoadingContext loadingContext(odfStore.styles(), odfStore.store()); KoShapeLoadingContext context(loadingContext, m_view->canvasBase()->shapeController()->resourceManager()); KoXmlElement child; QList shapes; forEachElement(child, body) { KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, context); if (shape) { shapes.append(shape); } } if (!shapes.isEmpty()) { KisSelectionToolHelper helper(m_view->canvasBase(), kundo2_i18n("Convert shapes to vector selection")); helper.addSelectionShapes(shapes); } return true; } private: KisViewManager* m_view; }; void KisShapesToVectorSelectionActionFactory::run(KisViewManager* view) { QList shapes = view->canvasBase()->shapeManager()->selection()->selectedShapes(); KoShapeOdfSaveHelper saveHelper(shapes); KoDrag drag; drag.setOdf(KoOdf::mimeType(KoOdf::Text), saveHelper); QMimeData* mimeData = drag.mimeData(); Q_ASSERT(mimeData->hasFormat(KoOdf::mimeType(KoOdf::Text))); KisShapeSelectionPaste paste(view); paste.paste(KoOdf::Text, mimeData); } void KisSelectionToShapeActionFactory::run(KisViewManager *view) { KisSelectionSP selection = view->selection(); if (!selection->outlineCacheValid()) { return; } QPainterPath selectionOutline = selection->outlineCache(); QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); shape->setShapeId(KoPathShapeId); KoColor fgColor = view->canvasBase()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); KoShapeStroke* border = new KoShapeStroke(1.0, fgColor.toQColor()); shape->setStroke(border); view->document()->shapeController()->addShape(shape); } + +void KisStrokeSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params) +{ + KisImageWSP image = view->image(); + if (!image ) { + + return; + } + + KisSelectionSP selection = view->selection(); + if (!selection) { + + return; + } + + int size = params.lineSize; + + KisPixelSelectionSP pixelSelection = selection->projection(); if (!pixelSelection->outlineCacheValid()) { + pixelSelection->recalculateOutlineCache(); + } + + QPainterPath outline = pixelSelection->outlineCache(); + QColor color = params.color.toQColor(); + + + KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); + if (!currentNode->inherits("KisShapeLayer") && currentNode->childCount() == 0) { + KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager(); + KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; + KisPainter::FillStyle fillStyle = params.fillStyle(); + + KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), + image, + currentNode, + rManager , + strokeStyle, + fillStyle); + helper.setFGColorOverride(params.color); + helper.setSelectionOverride(0); + QPen pen(Qt::red, size); + pen.setJoinStyle(Qt::RoundJoin); + + if (fillStyle != KisPainter::FillStyleNone) { + helper.paintPainterPathQPenFill(outline, pen, params.fillColor); + } + else { + helper.paintPainterPathQPen(outline, pen, params.fillColor); + } + } + else { + + QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); + + KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(outline)); + shape->setShapeId(KoPathShapeId); + + KoShapeStroke* border = new KoShapeStroke(size, color); + shape->setStroke(border); + + view->document()->shapeController()->addShape(shape); + } + image->setModified(); + +} + +void KisStrokeBrushSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params) +{ + KisImageWSP image = view->image(); + if (!image ) { + + return; + } + + KisSelectionSP selection = view->selection(); + if (!selection) { + + return; + } + + KisPixelSelectionSP pixelSelection = selection->projection(); + if (!pixelSelection->outlineCacheValid()) { + pixelSelection->recalculateOutlineCache(); + } + + KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); + if (!currentNode->inherits("KisShapeLayer") && currentNode->childCount() == 0) + { + KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager(); + QPainterPath outline = pixelSelection->outlineCache(); + KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; + KisPainter::FillStyle fillStyle = KisPainter::FillStyleNone; + KoColor color = params.color; + + KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), + image, + currentNode, + rManager , + strokeStyle, + fillStyle); + helper.setFGColorOverride(color); + helper.setSelectionOverride(0); + helper.paintPainterPath(outline); + image->setModified(); + } + + +} diff --git a/libs/ui/actions/kis_selection_action_factories.h b/libs/ui/actions/kis_selection_action_factories.h index 6c4fdbfc84..d5a285805d 100644 --- a/libs/ui/actions/kis_selection_action_factories.h +++ b/libs/ui/actions/kis_selection_action_factories.h @@ -1,123 +1,134 @@ /* * Copyright (c) 2012 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_SELECTION_ACTION_FACTORIES_H #define __KIS_SELECTION_ACTION_FACTORIES_H #include "operations/kis_operation.h" #include "operations/kis_operation_configuration.h" #include "operations/kis_filter_selection_operation.h" +#include "dialogs/kis_dlg_stroke_selection_properties.h" class KRITAUI_EXPORT KisNoParameterActionFactory : public KisOperation { public: KisNoParameterActionFactory(const QString &id) : KisOperation(id) {} void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) { Q_UNUSED(config); run(view); } virtual void run(KisViewManager *view) = 0; }; struct KRITAUI_EXPORT KisSelectAllActionFactory : public KisNoParameterActionFactory { KisSelectAllActionFactory() : KisNoParameterActionFactory("select-all-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisDeselectActionFactory : public KisNoParameterActionFactory { KisDeselectActionFactory() : KisNoParameterActionFactory("deselect-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisReselectActionFactory : public KisNoParameterActionFactory { KisReselectActionFactory() : KisNoParameterActionFactory("reselect-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisFillActionFactory : public KisOperation { KisFillActionFactory() : KisOperation("fill-ui-action") {} void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) { run(config.getString("fill-source", "fg"), view); } /** * \p fillColor may be one of three variants: * - "fg" --- foreground color * - "bg" --- background color * - "pattern" --- current pattern */ void run(const QString &fillSource, KisViewManager *view); }; struct KRITAUI_EXPORT KisClearActionFactory : public KisNoParameterActionFactory { KisClearActionFactory() : KisNoParameterActionFactory("clear-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisImageResizeToSelectionActionFactory : public KisNoParameterActionFactory { KisImageResizeToSelectionActionFactory() : KisNoParameterActionFactory("resize-to-selection-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisCutCopyActionFactory : public KisOperation { KisCutCopyActionFactory() : KisOperation("cut-copy-ui-action") {} void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) { run(config.getBool("will-cut", false), config.getBool("use-sharp-clip", false), view); } void run(bool willCut, bool makeSharpClip, KisViewManager *view); }; struct KRITAUI_EXPORT KisCopyMergedActionFactory : public KisNoParameterActionFactory { KisCopyMergedActionFactory() : KisNoParameterActionFactory("copy-merged-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisPasteActionFactory : public KisNoParameterActionFactory { KisPasteActionFactory() : KisNoParameterActionFactory("paste-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisPasteNewActionFactory : public KisNoParameterActionFactory { KisPasteNewActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {} void run(KisViewManager *view); }; struct KisInvertSelectionOperaton : public KisFilterSelectionOperation { KisInvertSelectionOperaton() : KisFilterSelectionOperation("invertselection") {} void runFromXML(KisViewManager *view, const KisOperationConfiguration &config); }; struct KRITAUI_EXPORT KisSelectionToVectorActionFactory : public KisNoParameterActionFactory { KisSelectionToVectorActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisShapesToVectorSelectionActionFactory : public KisNoParameterActionFactory { KisShapesToVectorSelectionActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {} void run(KisViewManager *view); }; struct KRITAUI_EXPORT KisSelectionToShapeActionFactory : public KisNoParameterActionFactory { KisSelectionToShapeActionFactory() : KisNoParameterActionFactory("selection-to-shape-action") {} void run(KisViewManager *view); }; +struct KRITAUI_EXPORT KisStrokeSelectionActionFactory : public KisOperation { + KisStrokeSelectionActionFactory() : KisOperation("selection-to-shape-action") {} + void run(KisViewManager *view, StrokeSelectionOptions params); +}; + +struct KRITAUI_EXPORT KisStrokeBrushSelectionActionFactory : public KisOperation { + KisStrokeBrushSelectionActionFactory() : KisOperation("selection-to-shape-action") {} + void run(KisViewManager *view, StrokeSelectionOptions params); +}; + #endif /* __KIS_SELECTION_ACTION_FACTORIES_H */ diff --git a/libs/ui/dialogs/kis_dlg_adj_layer_props.cc b/libs/ui/dialogs/kis_dlg_adj_layer_props.cc index 550d9120cb..35509caf68 100644 --- a/libs/ui/dialogs/kis_dlg_adj_layer_props.cc +++ b/libs/ui/dialogs/kis_dlg_adj_layer_props.cc @@ -1,145 +1,144 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_dlg_adj_layer_props.h" #include #include #include #include #include #include "kis_config_widget.h" #include "kis_transaction.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_layer.h" #include "kis_adjustment_layer.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include "kis_node_filter_interface.h" KisDlgAdjLayerProps::KisDlgAdjLayerProps(KisNodeSP node, KisNodeFilterInterface* nfi, KisPaintDeviceSP paintDevice, KisViewManager *view, - KisFilterConfiguration *configuration, + KisFilterConfigurationSP configuration, const QString & layerName, const QString & caption, QWidget *parent, const char *name) : KoDialog(parent) , m_node(node) , m_paintDevice(paintDevice) , m_currentConfigWidget(0) , m_currentFilter(0) , m_currentConfiguration(0) , m_nodeFilterInterface(nfi) { setButtons(Ok | Cancel); setDefaultButton(Ok); setObjectName(name); m_currentConfiguration = configuration; if (m_currentConfiguration) { m_currentFilter = KisFilterRegistry::instance()->get(m_currentConfiguration->name()).data(); } setCaption(caption); QWidget * page = new QWidget(this); page->setObjectName("page widget"); QHBoxLayout * layout = new QHBoxLayout(page); layout->setMargin(0); setMainWidget(page); QVBoxLayout *v1 = new QVBoxLayout(); layout->addLayout(v1); QHBoxLayout *hl = new QHBoxLayout(); v1->addLayout(hl); QLabel * lblName = new QLabel(i18n("Layer name:"), page); lblName->setObjectName("lblName"); hl->addWidget(lblName, 0); m_layerName = new KLineEdit(page); m_layerName->setObjectName("m_layerName"); m_layerName->setText(layerName); m_layerName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); hl->addWidget(m_layerName, 10); connect(m_layerName, SIGNAL(textChanged(const QString &)), this, SLOT(slotNameChanged(const QString &))); if (m_currentFilter) { m_currentConfigWidget = m_currentFilter->createConfigurationWidget(page, paintDevice); if (m_currentConfigWidget) { m_currentConfigWidget->setView(view); m_currentConfigWidget->setConfiguration(m_currentConfiguration); } } if (m_currentFilter == 0 || m_currentConfigWidget == 0) { QLabel * labelNoConfigWidget = new QLabel(i18n("No configuration options are available for this filter"), page); v1->addWidget(labelNoConfigWidget); } else { v1->addWidget(m_currentConfigWidget); connect(m_currentConfigWidget, SIGNAL(sigConfigurationUpdated()), SLOT(slotConfigChanged())); } enableButtonOk(!m_layerName->text().isEmpty()); } void KisDlgAdjLayerProps::slotNameChanged(const QString & text) { enableButtonOk(!text.isEmpty()); } -KisFilterConfiguration * KisDlgAdjLayerProps::filterConfiguration() const +KisFilterConfigurationSP KisDlgAdjLayerProps::filterConfiguration() const { if (m_currentConfigWidget) { - KisFilterConfiguration * config - = dynamic_cast(m_currentConfigWidget->configuration()); + KisFilterConfigurationSP config = dynamic_cast(m_currentConfigWidget->configuration().data()); if (config) { return config; } } return m_currentFilter->defaultConfiguration(m_paintDevice); } QString KisDlgAdjLayerProps::layerName() const { return m_layerName->text(); } void KisDlgAdjLayerProps::slotConfigChanged() { enableButtonOk(true); - KisFilterConfiguration * config = filterConfiguration(); + KisFilterConfigurationSP config = filterConfiguration(); if (config) { m_nodeFilterInterface->setFilter(config); } m_node->setDirty(); } diff --git a/libs/ui/dialogs/kis_dlg_adj_layer_props.h b/libs/ui/dialogs/kis_dlg_adj_layer_props.h index 61daba97e0..384305abe4 100644 --- a/libs/ui/dialogs/kis_dlg_adj_layer_props.h +++ b/libs/ui/dialogs/kis_dlg_adj_layer_props.h @@ -1,78 +1,78 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DLG_ADJ_LAYER_PROPS_H #define KIS_DLG_ADJ_LAYER_PROPS_H #include class QLineEdit; class KisFilter; class KisFilterConfiguration; class KisConfigWidget; class KisNodeFilterInterface; class KisViewManager; #include "kis_types.h" /** * Create a new adjustment layer. */ class KisDlgAdjLayerProps : public KoDialog { Q_OBJECT public: /** * Create a new adjustmentlayer dialog * * @param layerName the name of the adjustment layer * @param caption the caption for the dialog -- create or properties * @param parent the widget parent of this dialog * @param name the QObject name, if any */ KisDlgAdjLayerProps(KisNodeSP node, KisNodeFilterInterface *nfi, KisPaintDeviceSP paintDevice, KisViewManager *view, - KisFilterConfiguration *configuration, + KisFilterConfigurationSP configuration, const QString & layerName, const QString & caption, QWidget *parent = 0, const char *name = 0); - KisFilterConfiguration * filterConfiguration() const; + KisFilterConfigurationSP filterConfiguration() const; QString layerName() const; private Q_SLOTS: void slotNameChanged(const QString &); void slotConfigChanged(); private: KisNodeSP m_node; KisPaintDeviceSP m_paintDevice; KisConfigWidget *m_currentConfigWidget; KisFilter *m_currentFilter; - KisFilterConfiguration *m_currentConfiguration; + KisFilterConfigurationSP m_currentConfiguration; QLineEdit *m_layerName; KisNodeFilterInterface *m_nodeFilterInterface; }; #endif // KIS_DLG_ADJ_LAYER_PROPS_H diff --git a/libs/ui/dialogs/kis_dlg_adjustment_layer.cc b/libs/ui/dialogs/kis_dlg_adjustment_layer.cc index a4cf4b8fc4..153167c680 100644 --- a/libs/ui/dialogs/kis_dlg_adjustment_layer.cc +++ b/libs/ui/dialogs/kis_dlg_adjustment_layer.cc @@ -1,140 +1,140 @@ /* * Copyright (c) 2006 Boudewijn Rempt * Copyright (c) 2008 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. */ #include "kis_dlg_adjustment_layer.h" #include #include #include #include #include #include #include #include #include #include #include #include "filter/kis_filter.h" #include "kis_config_widget.h" #include "filter/kis_filter_configuration.h" #include "kis_paint_device.h" #include "kis_transaction.h" #include "kis_node.h" #include "kis_node_filter_interface.h" #include #include "KisViewManager.h" KisDlgAdjustmentLayer::KisDlgAdjustmentLayer(KisNodeSP node, KisNodeFilterInterface* nfi, KisPaintDeviceSP paintDevice, const QString &layerName, const QString &caption, KisViewManager *view, QWidget *parent) : KoDialog(parent) , m_node(node) , m_nodeFilterInterface(nfi) , m_currentFilter(0) , m_customName(false) , m_layerName(layerName) { setCaption(caption); setButtons(None); QWidget * page = new QWidget(this); wdgFilterNodeCreation.setupUi(page); setMainWidget(page); wdgFilterNodeCreation.filterGalleryToggle->setChecked(wdgFilterNodeCreation.filterSelector->isFilterGalleryVisible()); wdgFilterNodeCreation.filterGalleryToggle->setIcon(QPixmap(":/pics/sidebaricon.png")); wdgFilterNodeCreation.filterGalleryToggle->setMaximumWidth(wdgFilterNodeCreation.filterGalleryToggle->height()); connect(wdgFilterNodeCreation.filterSelector, SIGNAL(sigFilterGalleryToggled(bool)), wdgFilterNodeCreation.filterGalleryToggle, SLOT(setChecked(bool))); connect(wdgFilterNodeCreation.filterGalleryToggle, SIGNAL(toggled(bool)), wdgFilterNodeCreation.filterSelector, SLOT(showFilterGallery(bool))); connect(wdgFilterNodeCreation.filterSelector, SIGNAL(sigSizeChanged()), this, SLOT(slotFilterWidgetSizeChanged())); connect(wdgFilterNodeCreation.buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(wdgFilterNodeCreation.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); wdgFilterNodeCreation.filterSelector->setView(view); wdgFilterNodeCreation.filterSelector->showFilterGallery(KisConfig().showFilterGalleryLayerMaskDialog()); wdgFilterNodeCreation.filterSelector->setPaintDevice(false, paintDevice); wdgFilterNodeCreation.layerName->setText(layerName); connect(wdgFilterNodeCreation.filterSelector, SIGNAL(configurationChanged()), SLOT(slotConfigChanged())); connect(wdgFilterNodeCreation.layerName, SIGNAL(textChanged(QString)), SLOT(slotNameChanged(QString))); slotConfigChanged(); } KisDlgAdjustmentLayer::~KisDlgAdjustmentLayer() { KisConfig().setShowFilterGalleryLayerMaskDialog(wdgFilterNodeCreation.filterSelector->isFilterGalleryVisible()); } void KisDlgAdjustmentLayer::slotNameChanged(const QString &text) { Q_UNUSED(text); m_customName = !text.isEmpty(); enableButtonOk(m_currentFilter); } -KisFilterConfiguration * KisDlgAdjustmentLayer::filterConfiguration() const +KisFilterConfigurationSP KisDlgAdjustmentLayer::filterConfiguration() const { - KisFilterConfiguration* config = wdgFilterNodeCreation.filterSelector->configuration(); + KisFilterConfigurationSP config = wdgFilterNodeCreation.filterSelector->configuration(); Q_ASSERT(config); return config; } QString KisDlgAdjustmentLayer::layerName() const { return wdgFilterNodeCreation.layerName->text(); } void KisDlgAdjustmentLayer::slotConfigChanged() { m_currentFilter = filterConfiguration(); enableButtonOk(m_currentFilter); if (m_currentFilter) { m_nodeFilterInterface->setFilter(m_currentFilter); if (!m_customName) { wdgFilterNodeCreation.layerName->blockSignals(true); wdgFilterNodeCreation.layerName->setText(m_layerName + " (" + wdgFilterNodeCreation.filterSelector->currentFilter()->name() + ")"); wdgFilterNodeCreation.layerName->blockSignals(false); } } m_node->setDirty(); } void KisDlgAdjustmentLayer::adjustSize() { QWidget::adjustSize(); } void KisDlgAdjustmentLayer::slotFilterWidgetSizeChanged() { QMetaObject::invokeMethod(this, "adjustSize", Qt::QueuedConnection); } diff --git a/libs/ui/dialogs/kis_dlg_adjustment_layer.h b/libs/ui/dialogs/kis_dlg_adjustment_layer.h index 0a610f919d..69f6651445 100644 --- a/libs/ui/dialogs/kis_dlg_adjustment_layer.h +++ b/libs/ui/dialogs/kis_dlg_adjustment_layer.h @@ -1,79 +1,79 @@ /* * Copyright (c) 2006 Boudewijn Rempt * Copyright (c) 2008 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 KISDLGAdjustMENTLAYER_H #define KISDLGAdjustMENTLAYER_H #include #include class KisFilterConfiguration; class KisNodeFilterInterface; class KisViewManager; #include "kis_types.h" #include "ui_wdgfilternodecreation.h" /** * Create a new adjustment layer. */ class KisDlgAdjustmentLayer : public KoDialog { Q_OBJECT public: /** * Create a new adjustmentlayer dialog * * @param layerName the name of the adjustment layer * @param paintDevice the paint device that is used as source for the preview * @param caption the caption for the dialog -- create or properties * @param parent the widget parent of this dialog * @param name the QObject name, if any */ KisDlgAdjustmentLayer(KisNodeSP node, KisNodeFilterInterface* nfi, KisPaintDeviceSP paintDevice, const QString & layerName, const QString & caption, KisViewManager *view, QWidget *parent = 0); ~KisDlgAdjustmentLayer(); - KisFilterConfiguration * filterConfiguration() const; + KisFilterConfigurationSP filterConfiguration() const; QString layerName() const; public Q_SLOTS: void adjustSize(); protected Q_SLOTS: void slotNameChanged(const QString &); void slotConfigChanged(); void slotFilterWidgetSizeChanged(); private: KisNodeSP m_node; KisNodeFilterInterface *m_nodeFilterInterface; Ui::WdgFilterNodeCreation wdgFilterNodeCreation; - KisFilterConfiguration *m_currentFilter; + KisFilterConfigurationSP m_currentFilter; bool m_customName; QString m_layerName; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_filter.cpp b/libs/ui/dialogs/kis_dlg_filter.cpp index a1d4589874..41e21b004b 100644 --- a/libs/ui/dialogs/kis_dlg_filter.cpp +++ b/libs/ui/dialogs/kis_dlg_filter.cpp @@ -1,234 +1,234 @@ /* * 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 "kis_dlg_filter.h" #include #include #include #include #include #include #include #include #include #include "kis_selection.h" #include "kis_node_commands_adapter.h" #include "kis_filter_manager.h" #include "ui_wdgfilterdialog.h" struct KisDlgFilter::Private { Private() : currentFilter(0) , resizeCount(0) , view(0) { } KisFilterSP currentFilter; Ui_FilterDialog uiFilterDialog; KisNodeSP node; int resizeCount; KisViewManager *view; KisFilterManager *filterManager; }; KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManager *filterManager, QWidget *parent) : QDialog(parent), d(new Private) { setModal(false); d->uiFilterDialog.setupUi(this); d->node = node; d->view = view; d->filterManager = filterManager; d->uiFilterDialog.filterSelection->setView(view); d->uiFilterDialog.filterSelection->showFilterGallery(KisConfig().showFilterGallery()); d->uiFilterDialog.pushButtonCreateMaskEffect->show(); connect(d->uiFilterDialog.pushButtonCreateMaskEffect, SIGNAL(pressed()), SLOT(createMask())); d->uiFilterDialog.filterGalleryToggle->setChecked(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); d->uiFilterDialog.filterGalleryToggle->setIcon(QPixmap(":/pics/sidebaricon.png")); d->uiFilterDialog.filterGalleryToggle->setMaximumWidth(d->uiFilterDialog.filterGalleryToggle->height()); connect(d->uiFilterDialog.filterSelection, SIGNAL(sigFilterGalleryToggled(bool)), d->uiFilterDialog.filterGalleryToggle, SLOT(setChecked(bool))); connect(d->uiFilterDialog.filterGalleryToggle, SIGNAL(toggled(bool)), d->uiFilterDialog.filterSelection, SLOT(showFilterGallery(bool))); connect(d->uiFilterDialog.filterSelection, SIGNAL(sigSizeChanged()), this, SLOT(slotFilterWidgetSizeChanged())); if (node->inherits("KisMask")) { d->uiFilterDialog.pushButtonCreateMaskEffect->setVisible(false); } d->uiFilterDialog.filterSelection->setPaintDevice(true, d->node->original()); connect(d->uiFilterDialog.buttonBox, SIGNAL(accepted()), SLOT(accept())); connect(d->uiFilterDialog.buttonBox, SIGNAL(rejected()), SLOT(reject())); connect(d->uiFilterDialog.checkBoxPreview, SIGNAL(toggled(bool)), SLOT(enablePreviewToggled(bool))); connect(d->uiFilterDialog.filterSelection, SIGNAL(configurationChanged()), SLOT(filterSelectionChanged())); connect(this, SIGNAL(accepted()), SLOT(slotOnAccept())); connect(this, SIGNAL(rejected()), SLOT(slotOnReject())); KConfigGroup group( KSharedConfig::openConfig(), "filterdialog"); d->uiFilterDialog.checkBoxPreview->setChecked(group.readEntry("showPreview", true)); } KisDlgFilter::~KisDlgFilter() { delete d; } void KisDlgFilter::setFilter(KisFilterSP f) { Q_ASSERT(f); setDialogTitle(f); d->uiFilterDialog.filterSelection->setFilter(f); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(f->supportsAdjustmentLayers()); updatePreview(); } void KisDlgFilter::setDialogTitle(KisFilterSP filter) { setWindowTitle(filter.isNull() ? i18nc("@title:window", "Filter") : i18nc("@title:window", "Filter: %1", filter->name())); } -void KisDlgFilter::startApplyingFilter(KisSafeFilterConfigurationSP config) +void KisDlgFilter::startApplyingFilter(KisFilterConfigurationSP config) { if (!d->uiFilterDialog.filterSelection->configuration()) return; if (d->node->inherits("KisLayer")) { config->setChannelFlags(qobject_cast(d->node.data())->channelFlags()); } d->filterManager->apply(config); } void KisDlgFilter::updatePreview() { if (!d->uiFilterDialog.filterSelection->configuration()) return; if (d->uiFilterDialog.checkBoxPreview->isChecked()) { - KisSafeFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); + KisFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); startApplyingFilter(config); } d->uiFilterDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } void KisDlgFilter::adjustSize() { QWidget::adjustSize(); } void KisDlgFilter::slotFilterWidgetSizeChanged() { QMetaObject::invokeMethod(this, "adjustSize", Qt::QueuedConnection); } void KisDlgFilter::slotOnAccept() { if (!d->filterManager->isStrokeRunning()) { - KisSafeFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); + KisFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); startApplyingFilter(config); } d->filterManager->finish(); d->uiFilterDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); KisConfig().setShowFilterGallery(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); } void KisDlgFilter::slotOnReject() { if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KisConfig().setShowFilterGallery(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); } void KisDlgFilter::createMask() { if (d->node->inherits("KisMask")) return; if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KisLayer *layer = dynamic_cast(d->node.data()); KisFilterMaskSP mask = new KisFilterMask(); mask->initSelection(d->view->selection(), layer); mask->setFilter(d->uiFilterDialog.filterSelection->configuration()); Q_ASSERT(layer->allowAsChild(mask)); KisNodeCommandsAdapter adapter(d->view); adapter.addNode(mask, layer, layer->lastChild()); accept(); } void KisDlgFilter::enablePreviewToggled(bool state) { if (state) { updatePreview(); } else if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KConfigGroup group( KSharedConfig::openConfig(), "filterdialog"); group.writeEntry("showPreview", d->uiFilterDialog.checkBoxPreview->isChecked()); group.config()->sync(); } void KisDlgFilter::filterSelectionChanged() { KisFilterSP filter = d->uiFilterDialog.filterSelection->currentFilter(); setDialogTitle(filter); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(filter.isNull() ? false : filter->supportsAdjustmentLayers()); updatePreview(); } void KisDlgFilter::resizeEvent(QResizeEvent* event) { QDialog::resizeEvent(event); // Workaround, after the initalisation don't center the dialog anymore if(d->resizeCount < 2) { QWidget* canvas = d->view->canvas(); QRect rect(canvas->mapToGlobal(canvas->geometry().topLeft()), size()); int deltaX = (canvas->geometry().width() - geometry().width())/2; int deltaY = (canvas->geometry().height() - geometry().height())/2; rect.translate(deltaX, deltaY); setGeometry(rect); d->resizeCount++; } } diff --git a/libs/ui/dialogs/kis_dlg_filter.h b/libs/ui/dialogs/kis_dlg_filter.h index 7bf9515f0d..9051fa83b9 100644 --- a/libs/ui/dialogs/kis_dlg_filter.h +++ b/libs/ui/dialogs/kis_dlg_filter.h @@ -1,72 +1,72 @@ /* * 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_DLG_FILTER_H_ #define _KIS_DLG_FILTER_H_ #include #include class KisViewManager; class KisFilterManager; class KisDlgFilter : public QDialog { Q_OBJECT public: KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManager *filterManager, QWidget *parent = 0); ~KisDlgFilter(); void setFilter(KisFilterSP f); protected Q_SLOTS: void slotOnAccept(); void slotOnReject(); void createMask(); void enablePreviewToggled(bool state); void filterSelectionChanged(); virtual void resizeEvent(QResizeEvent* ); public Q_SLOTS: void adjustSize(); private: - void startApplyingFilter(KisSafeFilterConfigurationSP config); + void startApplyingFilter(KisFilterConfigurationSP config); void setDialogTitle(KisFilterSP f); void updatePreview(); private Q_SLOTS: void slotFilterWidgetSizeChanged(); private: struct Private; KisDlgFilter::Private* const d; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_generator_layer.cpp b/libs/ui/dialogs/kis_dlg_generator_layer.cpp index 0b76d47480..4f0dff2f44 100644 --- a/libs/ui/dialogs/kis_dlg_generator_layer.cpp +++ b/libs/ui/dialogs/kis_dlg_generator_layer.cpp @@ -1,76 +1,76 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_dlg_generator_layer.h" #include #include #include #include #include #include #include #include #include #include KisDlgGeneratorLayer::KisDlgGeneratorLayer(const QString & name, KisViewManager *view, QWidget *parent) : KoDialog(parent) , m_customName(false) , m_freezeName(false) { setButtons(Ok | Cancel); setDefaultButton(Ok); QWidget * page = new QWidget(this); dlgWidget.setupUi(page); dlgWidget.wdgGenerator->initialize(view); setMainWidget(page); dlgWidget.txtLayerName->setText(name); connect(dlgWidget.txtLayerName, SIGNAL(textChanged(QString)), this, SLOT(slotNameChanged(QString))); } void KisDlgGeneratorLayer::slotNameChanged(const QString & text) { if (m_freezeName) return; m_customName = !text.isEmpty(); enableButtonOk(m_customName); } -void KisDlgGeneratorLayer::setConfiguration(const KisFilterConfiguration * config) +void KisDlgGeneratorLayer::setConfiguration(const KisFilterConfigurationSP config) { dlgWidget.wdgGenerator->setConfiguration(config); } -KisFilterConfiguration * KisDlgGeneratorLayer::configuration() const +KisFilterConfigurationSP KisDlgGeneratorLayer::configuration() const { return dlgWidget.wdgGenerator->configuration(); } QString KisDlgGeneratorLayer::layerName() const { return dlgWidget.txtLayerName->text(); } diff --git a/libs/ui/dialogs/kis_dlg_generator_layer.h b/libs/ui/dialogs/kis_dlg_generator_layer.h index 2e6125fc96..d0c9df3454 100644 --- a/libs/ui/dialogs/kis_dlg_generator_layer.h +++ b/libs/ui/dialogs/kis_dlg_generator_layer.h @@ -1,63 +1,63 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_DLG_GENERATORLAYER_H #define KIS_DLG_GENERATORLAYER_H #include #include class KisFilterConfiguration; class KisViewManager; #include "ui_wdgdlggeneratorlayer.h" #include /** * Create a new generator layer */ class KisDlgGeneratorLayer : public KoDialog { public: Q_OBJECT public: /** * Create a new generator layer * @param name the proposed name for this layer * @param parent the widget parent of this dialog */ KisDlgGeneratorLayer(const QString & name, KisViewManager *view, QWidget *parent); - void setConfiguration(const KisFilterConfiguration * config); - KisFilterConfiguration * configuration() const; + void setConfiguration(const KisFilterConfigurationSP config); + KisFilterConfigurationSP configuration() const; QString layerName() const; protected Q_SLOTS: void slotNameChanged(const QString &); private: Ui_WdgDlgGeneratorLayer dlgWidget; bool m_customName; bool m_freezeName; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_stroke_selection_properties.cpp b/libs/ui/dialogs/kis_dlg_stroke_selection_properties.cpp new file mode 100644 index 0000000000..3233f26b21 --- /dev/null +++ b/libs/ui/dialogs/kis_dlg_stroke_selection_properties.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2016 Kapustin Alexey + * + * 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_stroke_selection_properties.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "KoColorProfile.h" +#include "KoColorSpaceRegistry.h" +#include "KoColor.h" +#include "KoColorConversionTransformation.h" +#include "KoColorPopupAction.h" +#include "kis_icon_utils.h" +#include "KoID.h" +#include "kis_image.h" +#include "kis_annotation.h" +#include "kis_config.h" +#include "kis_signal_compressor.h" +#include "widgets/kis_cmb_idlist.h" +#include "widgets/squeezedcombobox.h" +#include "kis_layer_utils.h" +#include +#include "kis_canvas_resource_provider.h" +#include "KoUnit.h" +#include "kis_display_color_converter.h" + +KisDlgStrokeSelection::KisDlgStrokeSelection(KisImageWSP image, KisViewManager *view, bool isVectorLayer) + : KoDialog(view->mainWindow()) +{ + m_resourceManager = view->mainWindow()->resourceManager(); + + converter = view->canvasBase()->displayColorConverter(); + setButtons(Ok | Cancel); + setDefaultButton(Ok); + setCaption(i18n("Stroke selection properties")); + m_page = new WdgStrokeSelection(this); + + m_image = image; + + setMainWidget(m_page); + resize(m_page->sizeHint()); + + QString filterConfig = KisConfig().exportConfiguration("StrokeSelection"); + KisPropertiesConfiguration cfg; + cfg.fromXML(filterConfig); + + auto &m_options = m_page->m_options; + m_options.color = cfg.getColor("color"); + m_options.lineColorSource = cfg.getInt("lineColorSource"); + m_page->lineColorBox->setCurrentIndex(m_options.lineColorSource); + + m_page->colorSelector->setColor(getSelectedColor().toQColor()); + + m_options.brushSelected = cfg.getBool("useBrush", 0); + m_page->typeBox->setCurrentIndex(m_options.brushSelected? 0 : 1); + + m_options._colorFillSource = cfg.getInt("colorFillSource", 0); + m_page->fillBox->setCurrentIndex(m_options._colorFillSource); + m_options.customColor = cfg.getColor("customColor"); + if (m_options._colorFillSource == static_cast(colorFillSource::CustomColor)) { + m_page->colorFillSelector->setColor(m_options.customColor.toQColor()); + } + else { + m_page->colorFillSelector->setColor(getFillSelectedColor().toQColor()); + } + + m_options.fillColor = cfg.getColor("fillColor"); + if (m_options._colorFillSource == static_cast(colorFillSource::None)) { + m_page->colorFillSelector->setDisabled(true); + } + else { + m_page->colorFillSelector->setDisabled(false); } + + m_options.lineSize = cfg.getInt("lineSize", 1); + m_page->lineSize->setValue(m_options.lineSize); + if (m_options.brushSelected) { + m_page->lineSize->setDisabled(true); + m_page->fillBox->setDisabled(true); + m_page->colorFillSelector->setDisabled(true); + m_page->sizeBox->setDisabled(true); + } + + m_options.lineDimension = cfg.getInt("lineDimension", 0); + m_page->sizeBox->setCurrentIndex(m_options.lineDimension); + + connect(m_page, SIGNAL(colorSelectorChanged()), SLOT(setColorButton())); + connect(m_page, SIGNAL(colorFillSelectorChanged()), SLOT(setColorFillButton())); + connect(m_page->colorFillSelector, SIGNAL(changed(const QColor&)), SLOT(colorFillChanged(const QColor&))); + connect(m_page->colorSelector, SIGNAL(changed(const QColor&)), SLOT(colorChanged(const QColor&))); + + if (isVectorLayer) { + lockVectorLayerFunctions(); + } +} + +KisDlgStrokeSelection::~KisDlgStrokeSelection() +{ + auto &m_options = m_page->m_options; + m_options.lineSize = m_page->lineSize->value(); + + m_options.lineDimension = m_page->sizeBox->currentIndex(); + m_options.lineColorSource = m_page->lineColorBox->currentIndex(); + + KisPropertiesConfiguration cfg; + cfg.setProperty("lineSize", m_options.lineSize); + cfg.setProperty("colorFillSource", m_options._colorFillSource); + cfg.setProperty("useBrush", m_options.brushSelected); + cfg.setProperty("lineDimension", m_options.lineDimension); + cfg.setProperty("lineColorSource", m_options.lineColorSource); + + QVariant colorVariant("KoColor"); + colorVariant.setValue(m_options.customColor); + cfg.setProperty("customColor", colorVariant); + + QVariant _colorVariant("KoColor"); + _colorVariant.setValue(m_options.color); + cfg.setProperty("color", _colorVariant); + + QVariant _cVariant("KoColor"); + _cVariant.setValue(m_options.fillColor); + cfg.setProperty("fillColor", _cVariant); + + KisConfig().setExportConfiguration("StrokeSelection", cfg); + + delete m_page; +} + +KoColor KisDlgStrokeSelection::getSelectedColor() const +{ + KoColor color; + + QString currentSource = m_page->lineColorBox->currentText(); + + if (currentSource == "Foreground color") { + color = m_resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value(); + } + else if (currentSource == "Background color") { + color = m_resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value(); + } + else { + color = m_page->m_options.color; + } + + return color; +} + +KoColor KisDlgStrokeSelection::getFillSelectedColor() const +{ + KoColor color; + + colorFillSource currentSource = static_cast(m_page->fillBox->currentIndex()); + + if (currentSource == colorFillSource::FGColor) { + color = m_resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value(); + } + else if (currentSource == colorFillSource::BGColor) { + color = m_resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value(); + } + else if (currentSource == colorFillSource::PaintColor) { + color = converter->approximateFromRenderedQColor(m_page->colorSelector->color()); + } + else { + color = m_page->m_options.customColor; + } + + return color; +} + + +bool KisDlgStrokeSelection::isBrushSelected() const +{ + int index = m_page->typeBox->currentIndex(); + drawType type = static_cast(index); + + if (type == drawType::brushDraw){ + return true; + } + else { + return false; + } +} + +StrokeSelectionOptions KisDlgStrokeSelection::getParams() const + { + StrokeSelectionOptions params; + + params.lineSize = getLineSize(); + params.color = getSelectedColor(); + params.brushSelected = isBrushSelected(); + params.fillColor = getFillSelectedColor(); + params._colorFillSource = m_page->m_options._colorFillSource; + return params; + +} + +void KisDlgStrokeSelection::lockVectorLayerFunctions() +{ + m_page->colorFillSelector->setEnabled(false); + m_page->lineSize->setEnabled(false); + m_page->sizeBox->setEnabled(false); + m_page->fillBox->setEnabled(false); + m_page->typeBox->setEnabled(false); +} + +void KisDlgStrokeSelection::unlockVectorLayerFunctions() +{ + m_page->colorFillSelector->setEnabled(true); + m_page->lineSize->setEnabled(true); + m_page->sizeBox->setEnabled(true); + m_page->fillBox->setEnabled(true); + m_page->typeBox->setEnabled(true); +} + +void KisDlgStrokeSelection::setColorFillButton() +{ + m_page->colorFillSelector->setColor(getFillSelectedColor().toQColor()); +} + +void KisDlgStrokeSelection::setColorButton() +{ + m_page->colorSelector->setColor(getSelectedColor().toQColor()); +} + + +int KisDlgStrokeSelection::getLineSize() const +{ + int value = m_page->lineSize->value(); + + if (m_page->sizeBox->currentText() == "px") { + return value; + } + else if (m_page->sizeBox->currentText() == "mm"){ + int pixels = static_cast(KoUnit::convertFromUnitToUnit(value,KoUnit(KoUnit::Millimeter), KoUnit(KoUnit::Pixel))); + return pixels; + } + else { + int pixels = static_cast(KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Pixel))); + return pixels; + } +} + +linePosition KisDlgStrokeSelection::getLinePosition() const +{/* TODO + int index = m_page->linePosition->currentIndex(); + switch(index) + { + case(0): + return linePosition::OUTSIDE; + case(1): + return linePosition::INSIDE; + case(2): + return linePosition::CENTER; + default: + return linePosition::CENTER; + }*/ + return linePosition::CENTER; +} + +void KisDlgStrokeSelection::colorChanged(const QColor &newColor) +{ + if (m_page->fillBox->currentText() == "Paint color") { + m_page->colorFillSelector->setColor(newColor); + } + QColor BGColor = m_resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value().toQColor(); + QColor FGColor = m_resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value().toQColor(); + KoColor tempColor= converter->approximateFromRenderedQColor(newColor); + + + if (!(newColor == BGColor) && !(newColor == FGColor)) { + m_page->m_options.color = tempColor; + m_page->lineColorBox->setCurrentIndex(2); //custom color + } +} + +void KisDlgStrokeSelection::colorFillChanged(const QColor &newColor) +{ + QColor PaintColor = m_page->colorSelector->color(); + QColor BGcolor = m_resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value().toQColor(); + QColor FGColor = m_resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value().toQColor(); + KoColor tempColor= converter->approximateFromRenderedQColor(newColor); + + if (!(newColor == FGColor) && !(newColor == BGcolor) && !(newColor == PaintColor)) { + m_page->m_options.customColor = tempColor; + m_page->fillBox->setCurrentIndex(static_cast(colorFillSource::CustomColor)); + } + m_page->m_options.fillColor = tempColor; +} + + + +WdgStrokeSelection::WdgStrokeSelection(QWidget *parent) : QWidget(parent) +{ + setupUi(this); +} + +void WdgStrokeSelection::on_fillBox_currentIndexChanged(int index) +{ + if (index == static_cast(colorFillSource::None)) { + colorFillSelector->setDisabled(true); + } + else { + colorFillSelector->setDisabled(false); + emit colorFillSelectorChanged(); + } + m_options._colorFillSource = index; +} + +void WdgStrokeSelection::on_typeBox_currentIndexChanged(const QString &arg1) +{ + if (arg1 == "Current Brush") { + m_options.brushSelected = true; + lineSize->setDisabled(true); + fillBox->setDisabled(true); + colorFillSelector->setDisabled(true); + sizeBox->setDisabled(true); + } + else { + m_options.brushSelected = false; + lineSize->setDisabled(false); + fillBox->setDisabled(false); + colorFillSelector->setDisabled(false); + sizeBox->setDisabled(false); + } +} + +void WdgStrokeSelection::on_lineColorBox_currentIndexChanged(const QString &arg1) +{ + emit colorSelectorChanged(); +} + + +StrokeSelectionOptions ::StrokeSelectionOptions(): + lineSize(1), + brushSelected(false), + _colorFillSource(0), + lineColorSource(0), + lineDimension(0) +{ + color.fromQColor(Qt::black); + fillColor.fromQColor(Qt::black); + customColor.fromQColor(Qt::black); +} + +KisPainter::FillStyle StrokeSelectionOptions::fillStyle() const +{ + colorFillSource tempColor = static_cast(_colorFillSource); + KisPainter::FillStyle style; + + switch (tempColor) { + case colorFillSource::PaintColor: + style = KisPainter::FillStyleForegroundColor; + break; + case colorFillSource::BGColor: + style = KisPainter::FillStyleBackgroundColor; + break; + case colorFillSource::CustomColor: + style = KisPainter::FillStyleBackgroundColor; + break; + case colorFillSource::None: + style = KisPainter::FillStyleNone; + break; + case colorFillSource::FGColor: + style = KisPainter::FillStyleBackgroundColor; + break; + default: + style = KisPainter::FillStyleBackgroundColor; + } + return style; +} + + diff --git a/libs/ui/dialogs/kis_dlg_stroke_selection_properties.h b/libs/ui/dialogs/kis_dlg_stroke_selection_properties.h new file mode 100644 index 0000000000..42e6efe11e --- /dev/null +++ b/libs/ui/dialogs/kis_dlg_stroke_selection_properties.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016 Alexey Kapustin + * + * 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_DLG_STROKE_SELECTION_PROPERTIES_H_ +#define KIS_DLG_STROKE_SELECTION_PROPERTIES_H_ + +#include +#include "KisProofingConfiguration.h" +#include +#include "KisViewManager.h" +#include "KoStrokeConfigWidget.h" +#include "ui_wdgstrokeselectionproperties.h" +#include +#include + +class KoColorSpace; +class KoColorPopupAction; + +enum class linePosition +{ + OUTSIDE, INSIDE, CENTER +}; + +enum class drawType{ + brushDraw, lineDraw +}; +enum class colorFillSource { + None, PaintColor, BGColor, CustomColor, FGColor +}; + +struct StrokeSelectionOptions { + StrokeSelectionOptions (); + int lineSize; + int _colorFillSource; + int lineColorSource; + bool brushSelected; + int lineDimension; + KoColor color; + KoColor fillColor; + KoColor customColor; + KisPainter::FillStyle fillStyle() const; + void lock(); +}; + +class WdgStrokeSelection : public QWidget, public Ui::WdgStrokeSelection +{ + Q_OBJECT + + +public: + WdgStrokeSelection(QWidget *parent) ; + StrokeSelectionOptions m_options; + +Q_SIGNALS: + void colorFillSelectorChanged(); + void colorSelectorChanged(); + +private Q_SLOTS: + void on_fillBox_currentIndexChanged(int index); + void on_typeBox_currentIndexChanged(const QString &arg1); + void on_lineColorBox_currentIndexChanged(const QString &arg1); + +}; + + +class KisDlgStrokeSelection : public KoDialog +{ + + Q_OBJECT + + +public: + KisDlgStrokeSelection(KisImageWSP image, KisViewManager *view, bool isVectorLayer); + virtual ~KisDlgStrokeSelection(); + int getLineSize() const; + linePosition getLinePosition() const; + KoColor getSelectedColor() const; + bool isBrushSelected() const; + KoColor getFillSelectedColor() const; + StrokeSelectionOptions getParams() const; + void lockVectorLayerFunctions(); + void unlockVectorLayerFunctions(); + +private: + WdgStrokeSelection * m_page; + KisImageWSP m_image; + KoCanvasResourceManager *m_resourceManager; + KisDisplayColorConverter *converter; + +private Q_SLOTS: + void setColorFillButton(); + void setColorButton(); + void colorChanged(const QColor &newColor); + void colorFillChanged(const QColor &newColor); +}; + + + +#endif // KIS_DLG_STROKE_SEL_PROPERTIES_H_ diff --git a/libs/ui/forms/wdgstrokeselectionproperties.ui b/libs/ui/forms/wdgstrokeselectionproperties.ui new file mode 100644 index 0000000000..010612567d --- /dev/null +++ b/libs/ui/forms/wdgstrokeselectionproperties.ui @@ -0,0 +1,210 @@ + + + WdgStrokeSelection + + + + 0 + 0 + 869 + 601 + + + + + 0 + 0 + + + + New Image + + + + + + 0 + + + + Stroke + + + + + + + + 0 + + + + Current Brush + + + + + Line selection + + + + + + + + Fill: + + + + + + + Type: + + + + + + + + + + 1 + + + 1000000 + + + 1 + + + + + + + Width: + + + intSize + + + + + + + + px + + + + + mm + + + + + inch + + + + + + + + + None + + + + + Paint color + + + + + Background color + + + + + Custom color + + + + + Foreground color + + + + + + + + Line: + + + + + + + Color + + + false + + + false + + + false + + + false + + + + + + + + Foreground color + + + + + Background color + + + + + Custom color + + + + + + + + Color + + + + + + + + + + + + + + KColorButton + QPushButton +
kcolorbutton.h
+ 1 +
+
+ + +
diff --git a/libs/ui/kis_action.h b/libs/ui/kis_action.h index 883eb0252c..24cffc19b5 100644 --- a/libs/ui/kis_action.h +++ b/libs/ui/kis_action.h @@ -1,135 +1,136 @@ /* * 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_ACTION_H #define KIS_ACTION_H #include #include #include #include class KisActionManager; /** * KisAction, inheriting from QWidgetAction, is a convenience class for GUI * actions, with Krita's configuration system and GUI states. A widget like a * "save" button may be enabled/disabled, hidden or shown depending on the * state of the application, e.g. whether the image currently being viewed was * modified since it was opened. * * Copies of these actions are created for each MainWindow instance. They are * owned by a KisActionManager, of which there is one for each MainWindow. Most * of these instantiations happen inside the constructor for KisMainWindow as * well as the various functions called in KisViewManager::setupManagers(). * **/ class KRITAUI_EXPORT KisAction : public QWidgetAction { Q_OBJECT public: /** * If you re-order these, you must change the associated values in * krita.action and kritamenu.action! */ enum ActivationFlag { NONE = 0x0000, ///< Always activate ACTIVE_IMAGE = 0x0001, ///< Activate if there is at least one image MULTIPLE_IMAGES = 0x0002, ///< Activate if there is more than one image open CURRENT_IMAGE_MODIFIED = 0x0004, ///< Activate if the current image is modified ACTIVE_NODE = 0x0008, ///< Activate if there's an active node (layer or mask) ACTIVE_DEVICE = 0x0010, ///< Activate if the active node has a paint device, i.e. there are pixels to be modified ACTIVE_LAYER = 0x0020, ///< Activate if the current node is a layer (vector or pixel) ACTIVE_TRANSPARENCY_MASK = 0x0040, ///< Activate if the current node is a transparency mask ACTIVE_SHAPE_LAYER = 0x0080, ///< Activate if the current node is a vector layer PIXELS_SELECTED = 0x0100, ///< Activate if there is an active pixel selection SHAPES_SELECTED = 0x0200, ///< Activate if there is an active vector selection PIXEL_SELECTION_WITH_PIXELS = 0x0400, ///< ??? PIXELS_IN_CLIPBOARD = 0x0800, ///< Activate if the clipboard contains pixels SHAPES_IN_CLIPBOARD = 0x1000, ///< Activate if the clipboard contains vector data - NEVER_ACTIVATE = 0x2000, ///< - LAYERS_IN_CLIPBOARD = 0x4000 + NEVER_ACTIVATE = 0x2000, ///< ??? + LAYERS_IN_CLIPBOARD = 0x4000, ///< ??? + IMAGE_HAS_ANIMATION = 0x8000, ///< Activate if the image has an animation }; Q_DECLARE_FLAGS(ActivationFlags, ActivationFlag) enum ActivationCondition { NO_CONDITION = 0, ACTIVE_NODE_EDITABLE = 0x1, ACTIVE_NODE_EDITABLE_PAINT_DEVICE = 0x2, SELECTION_EDITABLE = 0x4 }; Q_DECLARE_FLAGS(ActivationConditions, ActivationCondition) explicit KisAction(QObject* parent = 0); KisAction(const QString& text, QObject* parent = 0); KisAction(const QIcon& icon, const QString& text, QObject* parent = 0); virtual ~KisAction(); /** * Produces a new KisAction based on .action data files. */ static KisAction *makeKisAction(QString name, QObject *parent); void setDefaultShortcut(const QKeySequence & shortcut); QKeySequence defaultShortcut() const; void setActivationFlags(ActivationFlags flags); ActivationFlags activationFlags(); void setActivationConditions(ActivationConditions conditions); ActivationConditions activationConditions(); void setExcludedNodeTypes(const QStringList &nodeTypes); const QStringList& excludedNodeTypes() const; virtual void setActionEnabled(bool enabled); /** * Set operation id. This will used to run an operation in the KisActionManager */ void setOperationID(const QString& id); Q_SIGNALS: void sigEnableSlaves(bool value); private Q_SLOTS: void slotTriggered(); void slotChanged(); private: friend class KisActionManager; /** * Set the action manager. Only used by KisActionManager */ void setActionManager(KisActionManager* actionManager); class Private; Private* const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationConditions) #endif // KIS_ACTION_H diff --git a/libs/ui/kis_action_manager.cpp b/libs/ui/kis_action_manager.cpp index fa5ca188b7..311b2effad 100644 --- a/libs/ui/kis_action_manager.cpp +++ b/libs/ui/kis_action_manager.cpp @@ -1,459 +1,467 @@ /* * 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 "kis_action_manager.h" #include #include #include #include "KisPart.h" #include "kis_action.h" #include "KisViewManager.h" #include "kis_selection_manager.h" #include "operations/kis_operation_ui_factory.h" #include "operations/kis_operation_registry.h" #include "operations/kis_operation.h" #include "kis_layer.h" #include "KisDocument.h" #include "kis_clipboard.h" - +#include #include "QFile" #include #include #include "QFile" #include #include class Q_DECL_HIDDEN KisActionManager::Private { public: Private() : viewManager(0) {} ~Private() { qDeleteAll(uiRegistry.values()); } KisViewManager* viewManager; QList actions; KoGenericRegistry uiRegistry; KisOperationRegistry operationRegistry; }; KisActionManager::KisActionManager(KisViewManager* viewManager) : d(new Private) { d->viewManager = viewManager; } KisActionManager::~KisActionManager() { #if 0 if ((d->actions.size() > 0)) { QDomDocument doc; QDomElement e = doc.createElement("Actions"); e.setAttribute("version", "2"); doc.appendChild(e); Q_FOREACH (KisAction *action, d->actions) { QDomElement a = doc.createElement("Action"); a.setAttribute("name", action->objectName()); // But seriously, XML is the worst format ever designed auto addElement = [&](QString title, QString content) { QDomElement newNode = doc.createElement(title); QDomText newText = doc.createTextNode(content); newNode.appendChild(newText); a.appendChild(newNode); }; addElement("icon", action->icon().name()); addElement("text", action->text()); addElement("whatsThis" , action->whatsThis()); addElement("toolTip" , action->toolTip()); addElement("iconText" , action->iconText()); addElement("shortcut" , action->shortcut().toString()); addElement("activationFlags" , QString::number(action->activationFlags(),2));; addElement("activationConditions" , QString::number(action->activationConditions(),2)); addElement("defaultShortcut" , action->defaultShortcut().toString()); addElement("isCheckable" , QString((action->isChecked() ? "true" : "false"))); addElement("statusTip", action->statusTip()); e.appendChild(a); } QFile f("ActionManager.action"); f.open(QFile::WriteOnly); f.write(doc.toString().toUtf8()); f.close(); } #endif delete d; } void KisActionManager::setView(QPointer imageView) { Q_UNUSED(imageView); } void KisActionManager::addAction(const QString& name, KisAction* action) { Q_ASSERT(!name.isEmpty()); Q_ASSERT(action); Q_ASSERT(d->viewManager); Q_ASSERT(d->viewManager->actionCollection()); d->viewManager->actionCollection()->addAction(name, action); action->setObjectName(name); action->setParent(d->viewManager->actionCollection()); d->viewManager->actionCollection()->setDefaultShortcut(action, action->defaultShortcut()); d->actions.append(action); action->setActionManager(this); KisActionRegistry::instance()->addAction(name, action); } void KisActionManager::takeAction(KisAction* action) { d->actions.removeOne(action); if (!action->objectName().isEmpty()) { KIS_ASSERT_RECOVER_RETURN(d->viewManager->actionCollection()); d->viewManager->actionCollection()->takeAction(action); } } KisAction *KisActionManager::actionByName(const QString &name) const { Q_FOREACH (KisAction *action, d->actions) { if (action->objectName() == name) { return action; } } return 0; } KisAction *KisActionManager::createAction(const QString &name) { KisAction *a = actionByName(name); // Check if the action already exists if (a) { return a; } // There is some tension here. KisActionManager is supposed to be in control // of global actions, but these actions are supposed to be duplicated. We // will add them to the KisActionRegistry for the time being so we can get // properly categorized shortcuts. a = new KisAction(); auto actionRegistry = KisActionRegistry::instance(); // Add extra properties actionRegistry->propertizeAction(name, a); actionRegistry->addAction(name, a); bool ok; // We will skip this check int activationFlags = actionRegistry->getActionProperty(name, "activationFlags").toInt(&ok, 2); int activationConditions = actionRegistry->getActionProperty(name, "activationConditions").toInt(&ok, 2); a->setActivationFlags((KisAction::ActivationFlags) activationFlags); a->setActivationConditions((KisAction::ActivationConditions) activationConditions); addAction(name, a); return a; } void KisActionManager::updateGUI() { //TODO other flags KisAction::ActivationFlags flags; KisImageWSP image; KisNodeSP node; KisLayerSP layer; KisPaintDeviceSP device; KisDocument* document = 0; KisSelectionManager* selectionManager = 0; KisAction::ActivationConditions conditions = KisAction::NO_CONDITION; if (d->viewManager) { // if there are no views, that means no document is open. // we cannot have nodes (selections), devices, or documents without a view if ( d->viewManager->viewCount() > 0 ) { image = d->viewManager->image(); flags |= KisAction::ACTIVE_IMAGE; + if (image && image->animationInterface()->hasAnimation()) { + flags |= KisAction::IMAGE_HAS_ANIMATION; + } + node = d->viewManager->activeNode(); device = d->viewManager->activeDevice(); document = d->viewManager->document(); selectionManager = d->viewManager->selectionManager(); if (d->viewManager->viewCount() > 1) { flags |= KisAction::MULTIPLE_IMAGES; } if (document && document->isModified()) { flags |= KisAction::CURRENT_IMAGE_MODIFIED; } if (device) { flags |= KisAction::ACTIVE_DEVICE; } } } // is there a selection/mask? // you have to have at least one view(document) open for this to be true if (node) { // if a node exists, we know there is an active layer as well flags |= KisAction::ACTIVE_NODE; layer = dynamic_cast(node.data()); if (layer) { flags |= KisAction::ACTIVE_LAYER; } if (node->inherits("KisTransparencyMask")) { flags |= KisAction::ACTIVE_TRANSPARENCY_MASK; } if (layer && layer->inherits("KisShapeLayer")) { flags |= KisAction::ACTIVE_SHAPE_LAYER; } if (KisClipboard::instance()->hasLayers()) { flags |= KisAction::LAYERS_IN_CLIPBOARD; } if (selectionManager) { if (selectionManager->havePixelsSelected()) { flags |= KisAction::PIXELS_SELECTED; } if (selectionManager->haveShapesSelected()) { flags |= KisAction::SHAPES_SELECTED; } if (selectionManager->havePixelSelectionWithPixels()) { flags |= KisAction::PIXEL_SELECTION_WITH_PIXELS; } if (selectionManager->havePixelsInClipboard()) { flags |= KisAction::PIXELS_IN_CLIPBOARD; } if (selectionManager->haveShapesInClipboard()) { flags |= KisAction::SHAPES_IN_CLIPBOARD; } } if (node->isEditable(false)) { conditions |= KisAction::ACTIVE_NODE_EDITABLE; } if (node->hasEditablePaintDevice()) { conditions |= KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE; } if (d->viewManager->selectionEditable()) { conditions |= KisAction::SELECTION_EDITABLE; } } // loop through all actions in action manager and determine what should be enabled Q_FOREACH (KisAction* action, d->actions) { bool enable; if (action->activationFlags() == KisAction::NONE) { enable = true; } else { enable = action->activationFlags() & flags; // combine action flags with updateGUI flags } enable = enable && (int)(action->activationConditions() & conditions) == (int)action->activationConditions(); if (node && enable) { Q_FOREACH (const QString &type, action->excludedNodeTypes()) { if (node->inherits(type.toLatin1())) { enable = false; break; } } } action->setActionEnabled(enable); } } KisAction *KisActionManager::createStandardAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member) { QAction *standardAction = KStandardAction::create(actionType, receiver, member, 0); KisAction *action = new KisAction(standardAction->icon(), standardAction->text()); const QList defaultShortcuts = standardAction->property("defaultShortcuts").value >(); const QKeySequence defaultShortcut = defaultShortcuts.isEmpty() ? QKeySequence() : defaultShortcuts.at(0); action->setDefaultShortcut(standardAction->shortcut()); #ifdef Q_OS_WIN if (actionType == KStandardAction::SaveAs && defaultShortcuts.isEmpty()) { action->setShortcut(QKeySequence("CTRL+SHIFT+S")); } #endif action->setCheckable(standardAction->isCheckable()); if (action->isCheckable()) { action->setChecked(standardAction->isChecked()); } action->setMenuRole(standardAction->menuRole()); action->setText(standardAction->text()); action->setToolTip(standardAction->toolTip()); if (receiver && member) { if (actionType == KStandardAction::OpenRecent) { QObject::connect(action, SIGNAL(urlSelected(QUrl)), receiver, member); } else if (actionType == KStandardAction::ConfigureToolbars) { QObject::connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection); } else { QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); } } addAction(standardAction->objectName(), action); delete standardAction; return action; } void KisActionManager::registerOperationUIFactory(KisOperationUIFactory* factory) { d->uiRegistry.add(factory); } void KisActionManager::registerOperation(KisOperation* operation) { d->operationRegistry.add(operation); } void KisActionManager::runOperation(const QString& id) { - KisOperationConfiguration* config = new KisOperationConfiguration(id); + KisOperationConfigurationSP config = new KisOperationConfiguration(id); KisOperationUIFactory* uiFactory = d->uiRegistry.get(id); if (uiFactory) { bool gotConfig = uiFactory->fetchConfiguration(d->viewManager, config); if (!gotConfig) { return; } } runOperationFromConfiguration(config); } -void KisActionManager::runOperationFromConfiguration(KisOperationConfiguration* config) +void KisActionManager::runOperationFromConfiguration(KisOperationConfigurationSP config) { KisOperation* operation = d->operationRegistry.get(config->id()); Q_ASSERT(operation); operation->runFromXML(d->viewManager, *config); delete config; } void KisActionManager::dumpActionFlags() { QFile data("actions.txt"); if (data.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream out(&data); out.setCodec("UTF-8"); Q_FOREACH (KisAction* action, d->actions) { KisAction::ActivationFlags flags = action->activationFlags(); out << "-------- " << action->text() << " --------\n"; out << "Action will activate on: \n"; if (flags & KisAction::ACTIVE_IMAGE) { out << " Active image\n"; } if (flags & KisAction::MULTIPLE_IMAGES) { out << " More than one image open\n"; } if (flags & KisAction::CURRENT_IMAGE_MODIFIED) { out << " Active image modified\n"; } if (flags & KisAction::ACTIVE_DEVICE) { out << " Active device\n"; } if (flags & KisAction::ACTIVE_LAYER) { out << " Active layer\n"; } if (flags & KisAction::ACTIVE_TRANSPARENCY_MASK) { out << " Active transparency mask\n"; } if (flags & KisAction::ACTIVE_NODE) { out << " Active node\n"; } if (flags & KisAction::ACTIVE_SHAPE_LAYER) { out << " Active shape layer\n"; } if (flags & KisAction::PIXELS_SELECTED) { out << " Pixels selected\n"; } if (flags & KisAction::SHAPES_SELECTED) { out << " Shapes selected\n"; } if (flags & KisAction::PIXEL_SELECTION_WITH_PIXELS) { out << " Pixel selection with pixels\n"; } if (flags & KisAction::PIXELS_IN_CLIPBOARD) { out << " Pixels in clipboard\n"; } if (flags & KisAction::SHAPES_IN_CLIPBOARD) { out << " Shape in clipboard\n"; } + if (flags & KisAction::IMAGE_HAS_ANIMATION) { + out << " Image has animation\n"; + } + out << "\n\n"; out << "Action will only activate if the following conditions are met: \n"; KisAction::ActivationConditions conditions = action->activationConditions(); if ((int)conditions == 0) { out << " -\n"; } if (conditions & KisAction::ACTIVE_NODE_EDITABLE) { out << " Active Node editable\n"; } if (conditions & KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE) { out << " Active Node has editable paint device\n"; } if (conditions & KisAction::SELECTION_EDITABLE) { out << " Selection is editable\n"; } out << "\n\n"; } } } diff --git a/libs/ui/kis_action_manager.h b/libs/ui/kis_action_manager.h index f89c04c3aa..40aaa27ef1 100644 --- a/libs/ui/kis_action_manager.h +++ b/libs/ui/kis_action_manager.h @@ -1,110 +1,110 @@ /* * 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_ACTION_MANAGER_H #define KIS_ACTION_MANAGER_H #include #include #include "KisView.h" #include "kstandardaction.h" #include "kis_action_registry.h" +#include "operations/kis_operation_configuration.h" class KisViewManager; class KisAction; class KisOperationUIFactory; class KisOperation; -class KisOperationConfiguration; /** * @brief A KisActionManager class keeps track of KisActions. * These actions are always associated with the GUI. That means each MainWindow * will create its own duplicate of these actions. * * KisActionManager enables and disables actions, to grey out buttons according * to the state of the application. * * Some of the primitive actions (load/save and so on) are not defined as * KisActions, but instead KActions, automacially registered through KXMLGUI. * It tracks these actions through the KActionCollection owned by the window. * Ultimately it would be nice to unify these things more fully. * */ class KRITAUI_EXPORT KisActionManager { public: KisActionManager(KisViewManager* viewManager); virtual ~KisActionManager(); void setView(QPointer imageView); /** * Add an existing action to the action manager. */ void addAction(const QString& name, KisAction* action); /** * Stop managing an action. */ void takeAction(KisAction* action); /** * Create a new KisAction. Looks up data from the .action data files. */ KisAction *createAction(const QString &name); /** * Look up an action by name. */ KisAction *actionByName(const QString &name) const; void registerOperationUIFactory(KisOperationUIFactory* factory); void registerOperation(KisOperation* operation); void runOperation(const QString &id); - void runOperationFromConfiguration(KisOperationConfiguration* config); + void runOperationFromConfiguration(KisOperationConfigurationSP config); /** * Update actions handled by kis_action_manager to set enabled. * This is used to grey out buttons that can't be pressed. */ void updateGUI(); /** * Create a KisAction based on a KStandardAction. The KStandardAction is deleted. */ KisAction *createStandardAction(KStandardAction::StandardAction, const QObject *receiver, const char *member); private: void dumpActionFlags(); class Private; Private* const d; }; #endif // KIS_ACTION_MANAGER_H diff --git a/libs/ui/kis_animation_exporter.cpp b/libs/ui/kis_animation_exporter.cpp index e8a102a259..16ed459d5f 100644 --- a/libs/ui/kis_animation_exporter.cpp +++ b/libs/ui/kis_animation_exporter.cpp @@ -1,326 +1,334 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_animation_exporter.h" #include #include #include #include #include "KoFileDialog.h" #include "KisDocument.h" #include "kis_image.h" #include "KisImportExportManager.h" #include "kis_image_animation_interface.h" #include "KisPart.h" #include "KisMainWindow.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include "kis_time_range.h" #include "kis_painter.h" #include "kis_image_lock_hijacker.h" struct KisAnimationExporterUI::Private { QWidget *parentWidget; KisAnimationExportSaver *exporter; Private(QWidget *parent) : parentWidget(parent), exporter(0) {} }; KisAnimationExporterUI::KisAnimationExporterUI(QWidget *parent) : m_d(new Private(parent)) { } KisAnimationExporterUI::~KisAnimationExporterUI() { if (m_d->exporter) { delete m_d->exporter; } } KisImportExportFilter::ConversionStatus KisAnimationExporterUI::exportSequence(KisDocument *document) { KoFileDialog dialog(m_d->parentWidget, KoFileDialog::SaveFile, "exportsequence"); dialog.setCaption(i18n("Export sequence")); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Export)); QString filename = dialog.filename(); // if the user presses cancel, it returns empty if (filename.isEmpty()) return KisImportExportFilter::UserCancelled; const KisTimeRange fullClipRange = document->image()->animationInterface()->fullClipRange(); int firstFrame = fullClipRange.start(); int lastFrame = fullClipRange.end(); m_d->exporter = new KisAnimationExportSaver(document, filename, firstFrame, lastFrame); return m_d->exporter->exportAnimation(); } struct KisAnimationExporter::Private { + Private(KisDocument *document, int fromTime, int toTime) + : document(document) + , image(document->image()) + , firstFrame(fromTime) + , lastFrame(toTime) + , currentFrame(-1) + , batchMode(document->fileBatchMode()) + , isCancelled(false) + , status(KisImportExportFilter::OK) + , tmpDevice(new KisPaintDevice(image->colorSpace())) + { + } + KisDocument *document; KisImageWSP image; int firstFrame; int lastFrame; int currentFrame; bool batchMode; bool isCancelled; KisImportExportFilter::ConversionStatus status; SaveFrameCallback saveFrameCallback; KisPaintDeviceSP tmpDevice; - Private(KisDocument *document, int fromTime, int toTime) - : document(document), - image(document->image()), - firstFrame(fromTime), - lastFrame(toTime), - currentFrame(-1), - batchMode(document->fileBatchMode()), - isCancelled(false), - status(KisImportExportFilter::OK), - tmpDevice(new KisPaintDevice(image->colorSpace())) - { - } + KisPropertiesConfigurationSP exportConfiguration; + }; KisAnimationExporter::KisAnimationExporter(KisDocument *document, int fromTime, int toTime) : m_d(new Private(document, fromTime, toTime)) { connect(m_d->image->animationInterface(), SIGNAL(sigFrameReady(int)), this, SLOT(frameReadyToCopy(int)), Qt::DirectConnection); connect(this, SIGNAL(sigFrameReadyToSave()), this, SLOT(frameReadyToSave()), Qt::QueuedConnection); } KisAnimationExporter::~KisAnimationExporter() { } +void KisAnimationExporter::setExportConfiguration(KisPropertiesConfigurationSP exportConfiguration) +{ + m_d->exportConfiguration = exportConfiguration; +} + void KisAnimationExporter::setSaveFrameCallback(SaveFrameCallback func) { m_d->saveFrameCallback = func; } KisImportExportFilter::ConversionStatus KisAnimationExporter::exportAnimation() { QScopedPointer progress; if (!m_d->batchMode) { QString message = i18n("Export frames..."); progress.reset(new QProgressDialog(message, "", 0, 0, KisPart::instance()->currentMainwindow())); progress->setWindowModality(Qt::ApplicationModal); progress->setCancelButton(0); progress->setMinimumDuration(0); progress->setValue(0); emit m_d->document->statusBarMessage(message); emit m_d->document->sigProgress(0); connect(m_d->document, SIGNAL(sigProgressCanceled()), this, SLOT(cancel())); } /** * HACK ALERT: Here we remove the image lock! We do it in a GUI * thread under the barrier lock held, so it is * guaranteed no other stroke will accidentally be * started by this. And showing an app-modal dialog to * the user will prevent him from doing anything * nasty. */ KisImageLockHijacker badGuy(m_d->image); + Q_UNUSED(badGuy); KIS_ASSERT_RECOVER(!m_d->image->locked()) { return KisImportExportFilter::InternalError; } m_d->status = KisImportExportFilter::OK; m_d->currentFrame = m_d->firstFrame; m_d->image->animationInterface()->requestFrameRegeneration(m_d->currentFrame, m_d->image->bounds()); QEventLoop loop; loop.connect(this, SIGNAL(sigFinished()), SLOT(quit())); loop.exec(); if (!m_d->batchMode) { disconnect(m_d->document, SIGNAL(sigProgressCanceled()), this, SLOT(cancel())); emit m_d->document->sigProgress(100); emit m_d->document->clearStatusBarMessage(); progress.reset(); } return m_d->status; } void KisAnimationExporter::cancel() { m_d->isCancelled = true; } void KisAnimationExporter::frameReadyToCopy(int time) { if (time != m_d->currentFrame) return; QRect rc = m_d->image->bounds(); KisPainter::copyAreaOptimized(rc.topLeft(), m_d->image->projection(), m_d->tmpDevice, rc); emit sigFrameReadyToSave(); } void KisAnimationExporter::frameReadyToSave() { KIS_ASSERT_RECOVER(m_d->saveFrameCallback) { m_d->status = KisImportExportFilter::InternalError; emit sigFinished(); return; } if (m_d->isCancelled) { m_d->status = KisImportExportFilter::UserCancelled; emit sigFinished(); return; } KisImportExportFilter::ConversionStatus result = KisImportExportFilter::OK; int time = m_d->currentFrame; - result = m_d->saveFrameCallback(time, m_d->tmpDevice); + result = m_d->saveFrameCallback(time, m_d->tmpDevice, m_d->exportConfiguration); if (!m_d->batchMode) { emit m_d->document->sigProgress((time - m_d->firstFrame) * 100 / (m_d->lastFrame - m_d->firstFrame)); } - if (result == KisImportExportFilter::OK && - time < m_d->lastFrame) { + qDebug() << result << time << m_d->lastFrame; + if (result == KisImportExportFilter::OK && time < m_d->lastFrame) { m_d->currentFrame = time + 1; m_d->image->animationInterface()->requestFrameRegeneration(m_d->currentFrame, m_d->image->bounds()); } else { emit sigFinished(); } } struct KisAnimationExportSaver::Private { - Private(KisDocument *document, int fromTime, int toTime) - : document(document), - image(document->image()), - firstFrame(fromTime), - lastFrame(toTime), - tmpDoc(KisPart::instance()->createDocument()), - exporter(document, fromTime, toTime) + Private(KisDocument *document, int fromTime, int toTime, int _sequenceNumberingOffset) + : document(document) + , image(document->image()) + , firstFrame(fromTime) + , lastFrame(toTime) + , sequenceNumberingOffset(_sequenceNumberingOffset) + , tmpDoc(KisPart::instance()->createDocument()) + , exporter(document, fromTime, toTime) { tmpDoc->setAutoSave(0); tmpImage = new KisImage(tmpDoc->createUndoStore(), image->bounds().width(), image->bounds().height(), image->colorSpace(), QString()); tmpImage->setResolution(image->xRes(), image->yRes()); tmpDoc->setCurrentImage(tmpImage); KisPaintLayer* paintLayer = new KisPaintLayer(tmpImage, "paint device", 255); tmpImage->addNode(paintLayer, tmpImage->rootLayer(), KisLayerSP(0)); tmpDevice = paintLayer->paintDevice(); } - - KisDocument *document; KisImageWSP image; int firstFrame; int lastFrame; + int sequenceNumberingOffset; QScopedPointer tmpDoc; KisImageSP tmpImage; KisPaintDeviceSP tmpDevice; KisAnimationExporter exporter; QString filenamePrefix; QString filenameSuffix; }; -KisAnimationExportSaver::KisAnimationExportSaver(KisDocument *document, const QString &baseFilename, int fromTime, int toTime) - : m_d(new Private(document, fromTime, toTime)) +KisAnimationExportSaver::KisAnimationExportSaver(KisDocument *document, const QString &baseFilename, int fromTime, int toTime, int sequenceNumberingOffset) + : m_d(new Private(document, fromTime, toTime, sequenceNumberingOffset)) { int baseLength = baseFilename.lastIndexOf("."); if (baseLength > -1) { m_d->filenamePrefix = baseFilename.left(baseLength); m_d->filenameSuffix = baseFilename.right(baseFilename.length() - baseLength); } else { m_d->filenamePrefix = baseFilename; } QString mimefilter = KisMimeDatabase::mimeTypeForFile(baseFilename); m_d->tmpDoc->setOutputMimeType(mimefilter.toLatin1()); m_d->tmpDoc->setFileBatchMode(true); using namespace std::placeholders; // For _1 placeholder - m_d->exporter.setSaveFrameCallback(std::bind(&KisAnimationExportSaver::saveFrameCallback, this, _1, _2)); + m_d->exporter.setSaveFrameCallback(std::bind(&KisAnimationExportSaver::saveFrameCallback, this, _1, _2, _3)); } KisAnimationExportSaver::~KisAnimationExportSaver() { } -KisImportExportFilter::ConversionStatus KisAnimationExportSaver::exportAnimation() +KisImportExportFilter::ConversionStatus KisAnimationExportSaver::exportAnimation(KisPropertiesConfigurationSP cfg) { + m_d->exporter.setExportConfiguration(cfg); return m_d->exporter.exportAnimation(); } -KisImportExportFilter::ConversionStatus KisAnimationExportSaver::saveFrameCallback(int time, KisPaintDeviceSP frame) +KisImportExportFilter::ConversionStatus KisAnimationExportSaver::saveFrameCallback(int time, KisPaintDeviceSP frame, KisPropertiesConfigurationSP exportConfiguration) { - KisImportExportFilter::ConversionStatus status = - KisImportExportFilter::OK; + KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK; - QString frameNumber = QString("%1").arg(time, 4, 10, QChar('0')); + QString frameNumber = QString("%1").arg(time + m_d->sequenceNumberingOffset, 4, 10, QChar('0')); QString filename = m_d->filenamePrefix + frameNumber + m_d->filenameSuffix; QRect rc = m_d->image->bounds(); KisPainter::copyAreaOptimized(rc.topLeft(), frame, m_d->tmpDevice, rc); - - if (!m_d->tmpDoc->exportDocument(QUrl::fromLocalFile(filename))) { + if (!m_d->tmpDoc->exportDocument(QUrl::fromLocalFile(filename), exportConfiguration)) { status = KisImportExportFilter::InternalError; } return status; } QString KisAnimationExportSaver::savedFilesMask() const { return m_d->filenamePrefix + "%04d" + m_d->filenameSuffix; } diff --git a/libs/ui/kis_animation_exporter.h b/libs/ui/kis_animation_exporter.h index 1ba139571b..101b24f76e 100644 --- a/libs/ui/kis_animation_exporter.h +++ b/libs/ui/kis_animation_exporter.h @@ -1,94 +1,104 @@ /* * Copyright (c) 2015 Jouni Pentikäinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_ANIMATION_EXPORTER_H #define KIS_ANIMATION_EXPORTER_H #include "kis_types.h" #include "kritaui_export.h" #include #include class KisDocument; +/** + * @brief The KisAnimationExporterUI class + */ class KRITAUI_EXPORT KisAnimationExporterUI : public QObject { Q_OBJECT public: KisAnimationExporterUI(QWidget *parent); - ~KisAnimationExporterUI(); + virtual ~KisAnimationExporterUI(); KisImportExportFilter::ConversionStatus exportSequence(KisDocument *document); private: struct Private; QScopedPointer m_d; }; +/** + * @brief The KisAnimationExporter class + */ class KRITAUI_EXPORT KisAnimationExporter : public QObject { Q_OBJECT public: - typedef std::function SaveFrameCallback; + typedef std::function SaveFrameCallback; public: KisAnimationExporter(KisDocument *document, int fromTime, int toTime); ~KisAnimationExporter(); + void setExportConfiguration(KisPropertiesConfigurationSP exportConfiguration); KisImportExportFilter::ConversionStatus exportAnimation(); void setSaveFrameCallback(SaveFrameCallback func); Q_SIGNALS: // Internal, used for getting back to main thread void sigFrameReadyToSave(); void sigFinished(); private Q_SLOTS: void frameReadyToCopy(int time); void frameReadyToSave(); void cancel(); private: struct Private; QScopedPointer m_d; }; +/** + * @brief The KisAnimationExportSaver class + */ class KRITAUI_EXPORT KisAnimationExportSaver : public QObject { Q_OBJECT public: - KisAnimationExportSaver(KisDocument *document, const QString &baseFilename, int fromTime, int toTime); + KisAnimationExportSaver(KisDocument *document, const QString &baseFilename, int fromTime, int toTime, int sequenceNumberingOffset = 0); ~KisAnimationExportSaver(); - KisImportExportFilter::ConversionStatus exportAnimation(); + KisImportExportFilter::ConversionStatus exportAnimation(KisPropertiesConfigurationSP cfg = 0); QString savedFilesMask() const; private: - KisImportExportFilter::ConversionStatus saveFrameCallback(int time, KisPaintDeviceSP frame); + KisImportExportFilter::ConversionStatus saveFrameCallback(int time, KisPaintDeviceSP frame, KisPropertiesConfigurationSP exportConfiguration = 0); private: struct Private; const QScopedPointer m_d; }; #endif diff --git a/libs/ui/kis_bookmarked_configurations_editor.cc b/libs/ui/kis_bookmarked_configurations_editor.cc index ca976e0c3c..86eaade0ea 100644 --- a/libs/ui/kis_bookmarked_configurations_editor.cc +++ b/libs/ui/kis_bookmarked_configurations_editor.cc @@ -1,79 +1,79 @@ /* * 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. */ #include "kis_bookmarked_configurations_editor.h" #include "ui_wdgbookmarkedconfigurationseditor.h" #include "kis_bookmarked_configurations_model.h" struct KisBookmarkedConfigurationsEditor::Private { Ui_WdgBookmarkedConfigurationsEditor editorUi; KisBookmarkedConfigurationsModel* model; - const KisSerializableConfiguration* currentConfig; + KisSerializableConfigurationSP currentConfig; }; -KisBookmarkedConfigurationsEditor::KisBookmarkedConfigurationsEditor(QWidget* parent, KisBookmarkedConfigurationsModel* model, const KisSerializableConfiguration* currentConfig) : QDialog(parent), d(new Private) +KisBookmarkedConfigurationsEditor::KisBookmarkedConfigurationsEditor(QWidget* parent, KisBookmarkedConfigurationsModel* model, const KisSerializableConfigurationSP currentConfig) : QDialog(parent), d(new Private) { d->editorUi.setupUi(this); d->model = model; d->currentConfig = currentConfig; d->editorUi.listConfigurations->setModel(d->model); connect(d->editorUi.pushButtonClose, SIGNAL(pressed()), SLOT(accept())); connect(d->editorUi.listConfigurations->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(currentConfigChanged(const QItemSelection&, const QItemSelection&))); currentConfigChanged(d->editorUi.listConfigurations->selectionModel()->selection(), d->editorUi.listConfigurations->selectionModel()->selection()); connect(d->editorUi.pushButtonDelete, SIGNAL(pressed()), SLOT(deleteConfiguration())); connect(d->editorUi.pushButtonBookmarkCurrent, SIGNAL(pressed()), SLOT(addCurrentConfiguration())); if (!d->currentConfig) { d->editorUi.pushButtonBookmarkCurrent->setEnabled(false); } } KisBookmarkedConfigurationsEditor::~KisBookmarkedConfigurationsEditor() { delete d; } void KisBookmarkedConfigurationsEditor::currentConfigChanged(const QItemSelection& selected, const QItemSelection&) { if (d->model) { d->editorUi.pushButtonDelete->setEnabled(!(selected.indexes().isEmpty()) ? d->model->isIndexDeletable(selected.indexes().first()) : false); } } void KisBookmarkedConfigurationsEditor::addCurrentConfiguration() { if (d->model) { d->model->newConfiguration(ki18n("New configuration %1"), d->currentConfig); } } void KisBookmarkedConfigurationsEditor::deleteConfiguration() { if (d->model) { d->model->deleteIndex(d->editorUi.listConfigurations->currentIndex()); } } diff --git a/libs/ui/kis_bookmarked_configurations_editor.h b/libs/ui/kis_bookmarked_configurations_editor.h index 86aebd1774..4e6686fa37 100644 --- a/libs/ui/kis_bookmarked_configurations_editor.h +++ b/libs/ui/kis_bookmarked_configurations_editor.h @@ -1,53 +1,54 @@ /* * 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_BOOKMARKED_CONFIGURATIONS_EDITOR_H_ #define _KIS_BOOKMARKED_CONFIGURATIONS_EDITOR_H_ #include #include +#include + class KisBookmarkedConfigurationsModel; -class KisSerializableConfiguration; class QItemSelection; /** * This dialog is used to edit the content of a bookmark manager */ class KRITAUI_EXPORT KisBookmarkedConfigurationsEditor : public QDialog { Q_OBJECT public: /** * @param parent * @param manager the model representing the bookmark manager * @param currentConfig is used if the user choose to create a new configuration * entry or to replace an existing entry */ - KisBookmarkedConfigurationsEditor(QWidget* parent, KisBookmarkedConfigurationsModel* manager, const KisSerializableConfiguration* currentConfig); + KisBookmarkedConfigurationsEditor(QWidget* parent, KisBookmarkedConfigurationsModel* manager, const KisSerializableConfigurationSP currentConfig); ~KisBookmarkedConfigurationsEditor(); private Q_SLOTS: void currentConfigChanged(const QItemSelection& selected, const QItemSelection&); void addCurrentConfiguration(); void deleteConfiguration(); private: struct Private; Private* const d; }; #endif diff --git a/libs/ui/kis_bookmarked_configurations_model.cc b/libs/ui/kis_bookmarked_configurations_model.cc index 515228d033..dacb0373d5 100644 --- a/libs/ui/kis_bookmarked_configurations_model.cc +++ b/libs/ui/kis_bookmarked_configurations_model.cc @@ -1,161 +1,161 @@ /* * 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. */ #include "kis_bookmarked_configurations_model.h" #include #include #include #include #include struct KisBookmarkedConfigurationsModel::Private { KisBookmarkedConfigurationManager* bookmarkManager; QList configsKey; }; KisBookmarkedConfigurationsModel::KisBookmarkedConfigurationsModel(KisBookmarkedConfigurationManager* bm) : d(new Private) { d->bookmarkManager = bm; d->configsKey = d->bookmarkManager->configurations(); qSort(d->configsKey); } KisBookmarkedConfigurationsModel::~KisBookmarkedConfigurationsModel() { delete d; } KisBookmarkedConfigurationManager* KisBookmarkedConfigurationsModel::bookmarkedConfigurationManager() { return d->bookmarkManager; } int KisBookmarkedConfigurationsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2 + d->configsKey.size(); } QVariant KisBookmarkedConfigurationsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.row()) { case 0: return i18n("Default"); case 1: return i18n("Last Used"); default: return d->configsKey[ index.row() - 2 ]; } } return QVariant(); } bool KisBookmarkedConfigurationsModel::setData(const QModelIndex & index, const QVariant & value, int role) { if (role == Qt::EditRole && index.row() >= 2) { QString name = value.toString(); int idx = index.row() - 2; - KisSerializableConfiguration* config = d->bookmarkManager->load(d->configsKey[idx]); + KisSerializableConfigurationSP config = d->bookmarkManager->load(d->configsKey[idx]); d->bookmarkManager->remove(d->configsKey[idx]); d->bookmarkManager->save(name, config); d->configsKey[idx] = name; emit(dataChanged(index, index)); return true; } return false; } -KisSerializableConfiguration* KisBookmarkedConfigurationsModel::configuration(const QModelIndex &index) const +KisSerializableConfigurationSP KisBookmarkedConfigurationsModel::configuration(const QModelIndex &index) const { if (!index.isValid()) return 0; switch (index.row()) { case 0: dbgKrita << "loading default" << endl; return d->bookmarkManager->load(KisBookmarkedConfigurationManager::ConfigDefault); break; case 1: return d->bookmarkManager->load(KisBookmarkedConfigurationManager::ConfigLastUsed); break; default: return d->bookmarkManager->load(d->configsKey[ index.row() - 2 ]); } } QModelIndex KisBookmarkedConfigurationsModel::indexFor(const QString& name) const { int idx = d->configsKey.indexOf(name); if (idx == -1) return QModelIndex(); return createIndex(idx + 2, 0); } bool KisBookmarkedConfigurationsModel::isIndexDeletable(const QModelIndex &index) const { if (!index.isValid() || index.row() < 2) return false; return true; } -void KisBookmarkedConfigurationsModel::newConfiguration(KLocalizedString baseName, const KisSerializableConfiguration* config) +void KisBookmarkedConfigurationsModel::newConfiguration(KLocalizedString baseName, const KisSerializableConfigurationSP config) { saveConfiguration(d->bookmarkManager->uniqueName(baseName), config); } -void KisBookmarkedConfigurationsModel::saveConfiguration(const QString & name, const KisSerializableConfiguration* config) +void KisBookmarkedConfigurationsModel::saveConfiguration(const QString & name, const KisSerializableConfigurationSP config) { d->bookmarkManager->save(name, config); if (!d->configsKey.contains(name)) { beginInsertRows(QModelIndex(), d->configsKey.count() + 2, d->configsKey.count() + 2); d->configsKey << name; endInsertRows(); } } void KisBookmarkedConfigurationsModel::deleteIndex(const QModelIndex &index) { if (!index.isValid() || index.row() < 2) return ; int idx = index.row() - 2; d->bookmarkManager->remove(d->configsKey[idx]); beginRemoveRows(QModelIndex(), idx + 2, idx + 2); d->configsKey.removeAt(idx); endRemoveRows(); } Qt::ItemFlags KisBookmarkedConfigurationsModel::flags(const QModelIndex & index) const { if (!index.isValid()) return 0; switch (index.row()) { case 0: return Qt::ItemIsSelectable | Qt::ItemIsEnabled; case 1: if (d->bookmarkManager->exists(KisBookmarkedConfigurationManager::ConfigLastUsed)) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } else { return 0; } default: return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } } diff --git a/libs/ui/kis_bookmarked_configurations_model.h b/libs/ui/kis_bookmarked_configurations_model.h index 866dcf9b5d..11f00bde8d 100644 --- a/libs/ui/kis_bookmarked_configurations_model.h +++ b/libs/ui/kis_bookmarked_configurations_model.h @@ -1,91 +1,91 @@ /* * 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_BOOKMARKED_CONFIGURATIONS_MODEL_H_ #define _KIS_BOOKMARKED_CONFIGURATIONS_MODEL_H_ #include #include class KLocalizedString; class KisBookmarkedConfigurationManager; -class KisSerializableConfiguration; +#include /** * This class provides the basic functionality for a model of a bookmark * of configurations. */ class KRITAUI_EXPORT KisBookmarkedConfigurationsModel : public QAbstractListModel { public: /** * Initialized thee model with the bookmarks manager */ KisBookmarkedConfigurationsModel(KisBookmarkedConfigurationManager*); ~KisBookmarkedConfigurationsModel(); /** * @return the bookmarked configuration manager associated with this model. */ KisBookmarkedConfigurationManager* bookmarkedConfigurationManager(); /** * @return the number of configurations (the minimum is always 2, the default * configuration and the last used configuration are always present) */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** * When role == Qt::DisplayRole, this function will return the name of the * configuration. */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); /** * @return the configuration at the given index */ - KisSerializableConfiguration* configuration(const QModelIndex &index) const; + KisSerializableConfigurationSP configuration(const QModelIndex &index) const; /** * @return the index corresponding to the @p name . */ QModelIndex indexFor(const QString& name) const; /** * @return true if the configuration at the given index can be removed */ virtual bool isIndexDeletable(const QModelIndex &index) const; /** * @return the flags associated to the index */ Qt::ItemFlags flags(const QModelIndex & index) const; /** * Insert a new configuration. */ - virtual void newConfiguration(KLocalizedString baseName, const KisSerializableConfiguration* config); + virtual void newConfiguration(KLocalizedString baseName, const KisSerializableConfigurationSP config); /** * Save a configuration to the bookmark manager. */ - virtual void saveConfiguration(const QString & name, const KisSerializableConfiguration* config); + virtual void saveConfiguration(const QString & name, const KisSerializableConfigurationSP config); /** * Delete the configuration at the given index. (if possible) */ virtual void deleteIndex(const QModelIndex &index); private: struct Private; Private* const d; }; #endif diff --git a/libs/ui/kis_bookmarked_filter_configurations_model.cc b/libs/ui/kis_bookmarked_filter_configurations_model.cc index 3e5d0fa499..db86ef3919 100644 --- a/libs/ui/kis_bookmarked_filter_configurations_model.cc +++ b/libs/ui/kis_bookmarked_filter_configurations_model.cc @@ -1,59 +1,59 @@ /* * 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. */ #include "kis_bookmarked_filter_configurations_model.h" #include #include #include struct KisBookmarkedFilterConfigurationsModel::Private { KisPaintDeviceSP thumb; KisFilterSP filter; }; KisBookmarkedFilterConfigurationsModel::KisBookmarkedFilterConfigurationsModel(KisPaintDeviceSP thumb, KisFilterSP filter) : KisBookmarkedConfigurationsModel(filter->bookmarkManager()), d(new Private) { d->thumb = thumb; d->filter = filter; } KisBookmarkedFilterConfigurationsModel::~KisBookmarkedFilterConfigurationsModel() { delete d; } QVariant KisBookmarkedFilterConfigurationsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } return KisBookmarkedConfigurationsModel::data(index, role); } -KisFilterConfiguration* KisBookmarkedFilterConfigurationsModel::configuration(const QModelIndex &index) const +KisFilterConfigurationSP KisBookmarkedFilterConfigurationsModel::configuration(const QModelIndex &index) const { - KisFilterConfiguration* config = dynamic_cast(KisBookmarkedConfigurationsModel::configuration(index)); + KisFilterConfigurationSP config = dynamic_cast(KisBookmarkedConfigurationsModel::configuration(index).data()); if (config) return config; return d->filter->defaultConfiguration(d->thumb); } diff --git a/libs/ui/kis_bookmarked_filter_configurations_model.h b/libs/ui/kis_bookmarked_filter_configurations_model.h index b6307c5733..d969809bb5 100644 --- a/libs/ui/kis_bookmarked_filter_configurations_model.h +++ b/libs/ui/kis_bookmarked_filter_configurations_model.h @@ -1,51 +1,51 @@ /* * 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_BOOKMARKED_FILTER_CONFIGURATIONS_MODEL_H_ #define _KIS_BOOKMARKED_FILTER_CONFIGURATIONS_MODEL_H_ #include "kis_bookmarked_configurations_model.h" #include "kis_types.h" -class KisFilterConfiguration; +#include /** * Use this model to get the list of configuration for a Filter. */ class KisBookmarkedFilterConfigurationsModel : public KisBookmarkedConfigurationsModel { Q_OBJECT public: /** * @param thumb a 100x100 thumbnail used to preview the filters * @param filter the filter */ KisBookmarkedFilterConfigurationsModel(KisPaintDeviceSP thumb, KisFilterSP filter); ~KisBookmarkedFilterConfigurationsModel(); virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @return the filter configuration */ - KisFilterConfiguration* configuration(const QModelIndex &index) const; + KisFilterConfigurationSP configuration(const QModelIndex &index) const; private: struct Private; Private* const d; }; #endif diff --git a/libs/ui/kis_canvas_controls_manager.cpp b/libs/ui/kis_canvas_controls_manager.cpp index 525af10fd5..3c96050117 100644 --- a/libs/ui/kis_canvas_controls_manager.cpp +++ b/libs/ui/kis_canvas_controls_manager.cpp @@ -1,279 +1,279 @@ /* * Copyright (c) 2003-2009 Boudewijn Rempt * Copyright (c) 2014 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_canvas_controls_manager.h" #include #include #include #include "kis_action.h" #include "kis_action_manager.h" #include "KisViewManager.h" #include "kis_canvas2.h" #include "kis_canvas_resource_provider.h" #include #include #include #include #include #include #include const int STEP = 25; KisCanvasControlsManager::KisCanvasControlsManager(KisViewManager * view) : m_view(view) { } KisCanvasControlsManager::~KisCanvasControlsManager() { } void KisCanvasControlsManager::setup(KisActionManager *actionManager) { KisAction *lighterColor = actionManager->createAction("make_brush_color_lighter"); connect(lighterColor, SIGNAL(triggered()), SLOT(makeColorLighter())); KisAction *darkerColor = actionManager->createAction("make_brush_color_darker"); connect(darkerColor, SIGNAL(triggered()), SLOT(makeColorDarker())); KisAction *saturatedColor = actionManager->createAction("make_brush_color_saturated"); connect(saturatedColor, SIGNAL(triggered()), SLOT(makeColorSaturated())); KisAction *desaturatedColor = actionManager->createAction("make_brush_color_desaturated"); connect(desaturatedColor, SIGNAL(triggered()), SLOT(makeColorDesaturated())); - + KisAction *hueClockwise = actionManager->createAction("shift_brush_color_clockwise"); connect(hueClockwise, SIGNAL(triggered()), SLOT(shiftHueClockWise())); KisAction *hueCounterClockwise = actionManager->createAction("shift_brush_color_counter_clockwise"); connect(hueCounterClockwise, SIGNAL(triggered()), SLOT(shiftHueCounterClockWise())); - + KisAction *moreRed = actionManager->createAction("make_brush_color_redder"); connect(moreRed, SIGNAL(triggered()), SLOT(makeColorRed())); - + KisAction *moreGreen = actionManager->createAction("make_brush_color_greener"); connect(moreGreen, SIGNAL(triggered()), SLOT(makeColorGreen())); - + KisAction *moreBlue = actionManager->createAction("make_brush_color_bluer"); connect(moreBlue, SIGNAL(triggered()), SLOT(makeColorBlue())); KisAction *moreYellow = actionManager->createAction("make_brush_color_yellower"); connect(moreYellow, SIGNAL(triggered()), SLOT(makeColorYellow())); - + KisAction *increaseOpacity = actionManager->createAction("increase_opacity"); connect(increaseOpacity, SIGNAL(triggered()), SLOT(increaseOpacity())); KisAction *decreaseOpacity = actionManager->createAction("decrease_opacity"); connect(decreaseOpacity, SIGNAL(triggered()), SLOT(decreaseOpacity())); } void KisCanvasControlsManager::setView(QPointerimageView) { Q_UNUSED(imageView); } void KisCanvasControlsManager::transformColor(int step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; KConfigGroup hotkeycfg = KSharedConfig::openConfig()->group("colorhotkeys"); int steps = hotkeycfg.readEntry("steps_lightness", 10); KoColor color = m_view->resourceProvider()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); if (color.colorSpace()->colorModelId().id()=="CMYKA" || color.colorSpace()->colorModelId().id()=="XYZA"){ QColor rgb = color.toQColor(); int h = 0, s = 0, v = 0; rgb.getHsv(&h,&s,&v); if ((v < 255) || ((s == 0) || (s == 255))) { v += step; v = qBound(0,v,255); } else { s += -step; s = qBound(0,s,255); } rgb.setHsv(h,s,v); color.fromQColor(rgb); } else if (step<0){ color.colorSpace()->decreaseLuminosity(color.data(), 1.0/steps); } else { color.colorSpace()->increaseLuminosity(color.data(), 1.0/steps); } m_view->resourceProvider()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, color); } void KisCanvasControlsManager::transformSaturation(int step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; KConfigGroup hotkeycfg = KSharedConfig::openConfig()->group("colorhotkeys"); int steps = hotkeycfg.readEntry("steps_saturation", 10); KoColor color = m_view->resourceProvider()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); if (color.colorSpace()->colorModelId().id()=="CMYKA" || color.colorSpace()->colorModelId().id()=="XYZA"){ QColor rgb = color.toQColor(); int h = 0, s = 0, v = 0; rgb.getHsl(&h,&s,&v); s += step; s = qBound(0,s,255); rgb.setHsl(h,s,v); color.fromQColor(rgb); } else if (step<0){ color.colorSpace()->decreaseSaturation(color.data(), 1.0/steps); } else { color.colorSpace()->increaseSaturation(color.data(), 1.0/steps); } m_view->resourceProvider()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, color); } void KisCanvasControlsManager::transformHue(int step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; KConfigGroup hotkeycfg = KSharedConfig::openConfig()->group("colorhotkeys"); int steps = hotkeycfg.readEntry("steps_hue", 36); KoColor color = m_view->resourceProvider()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); if (color.colorSpace()->colorModelId().id()=="CMYKA" || color.colorSpace()->colorModelId().id()=="XYZA"){ QColor rgb = color.toQColor(); int h = 0, s = 0, v = 0; rgb.getHsl(&h,&s,&v); h += step; if (h>360.0 || h<0.0){h=fmod(h, 360.0);} rgb.setHsl(h,s,v); color.fromQColor(rgb); } else if (step<0){ color.colorSpace()->increaseHue(color.data(), 1.0/steps); } else { color.colorSpace()->decreaseHue(color.data(), 1.0/steps); } m_view->resourceProvider()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, color); } void KisCanvasControlsManager::transformRed(int step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; KConfigGroup hotkeycfg = KSharedConfig::openConfig()->group("colorhotkeys"); int steps = hotkeycfg.readEntry("steps_redgreen", 10); KoColor color = m_view->resourceProvider()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); if (step<0){ color.colorSpace()->increaseGreen(color.data(), 1.0/steps); } else { color.colorSpace()->increaseRed(color.data(), 1.0/steps); } m_view->resourceProvider()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, color); } void KisCanvasControlsManager::transformBlue(int step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; KConfigGroup hotkeycfg = KSharedConfig::openConfig()->group("colorhotkeys"); int steps = hotkeycfg.readEntry("steps_blueyellow", 10); KoColor color = m_view->resourceProvider()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); if (step<0){ color.colorSpace()->increaseYellow(color.data(), 1.0/steps); } else { color.colorSpace()->increaseBlue(color.data(), 1.0/steps); } m_view->resourceProvider()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, color); } void KisCanvasControlsManager::makeColorDarker() { transformColor(-STEP); } void KisCanvasControlsManager::makeColorLighter() { transformColor(STEP); } void KisCanvasControlsManager::makeColorDesaturated() { transformSaturation(-STEP); } void KisCanvasControlsManager::makeColorSaturated() { transformSaturation(STEP); } void KisCanvasControlsManager::shiftHueClockWise() { transformHue(STEP); } void KisCanvasControlsManager::shiftHueCounterClockWise() { transformHue(-STEP); } void KisCanvasControlsManager::makeColorRed() { transformRed(STEP); } void KisCanvasControlsManager::makeColorGreen() { transformRed(-STEP); } void KisCanvasControlsManager::makeColorBlue() { transformBlue(STEP); } void KisCanvasControlsManager::makeColorYellow() { transformBlue(-STEP); } void KisCanvasControlsManager::stepAlpha(float step) { if (!m_view) return; if (!m_view->canvasBase()) return; if (!m_view->resourceProvider()->resourceManager()) return; qreal alpha = m_view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::Opacity).toDouble(); alpha += step; alpha = qBound(0.0, alpha, 1.0); m_view->canvasBase()->resourceManager ()->setResource(KisCanvasResourceProvider::Opacity, alpha); // FIXME: DK: should we uncomment it back? - //KisLockedPropertiesProxy *p = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_view->resourceProvider()->currentPreset()->settings()); + //KisLockedPropertiesProxySP p = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_view->resourceProvider()->currentPreset()->settings()); //p->setProperty("OpacityValue", alpha); } void KisCanvasControlsManager::increaseOpacity() { stepAlpha(0.1f); } void KisCanvasControlsManager::decreaseOpacity() { stepAlpha(-0.1f); } diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp index 6eb7a20e7a..d9347bd87f 100644 --- a/libs/ui/kis_canvas_resource_provider.cpp +++ b/libs/ui/kis_canvas_resource_provider.cpp @@ -1,554 +1,540 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_canvas_resource_provider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "KisViewManager.h" #include "canvas/kis_canvas2.h" KisCanvasResourceProvider::KisCanvasResourceProvider(KisViewManager * view) : m_view(view) { m_fGChanged = true; m_enablefGChange = true; // default to true, so that colour history is working without popup palette } KisCanvasResourceProvider::~KisCanvasResourceProvider() { disconnect(); // in case Qt gets confused } KoCanvasResourceManager* KisCanvasResourceProvider::resourceManager() { return m_resourceManager; } void KisCanvasResourceProvider::setResourceManager(KoCanvasResourceManager *resourceManager) { m_resourceManager = resourceManager; QVariant v; v.setValue(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); m_resourceManager->setResource(KoCanvasResourceManager::ForegroundColor, v); v.setValue(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); m_resourceManager->setResource(KoCanvasResourceManager::BackgroundColor, v); setCurrentCompositeOp(COMPOSITE_OVER); setMirrorHorizontal(false); setMirrorVertical(false); m_resourceManager->setResource(HdrExposure, 0.0); m_resourceManager->setResource(HdrGamma, 1.0); m_resourceManager->setResource(EffectiveZoom, 1.0); connect(m_resourceManager, SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(slotCanvasResourceChanged(int,QVariant))); m_resourceManager->setResource(KoCanvasResourceManager::ApplicationSpeciality, KoCanvasResourceManager::NoAdvancedText); } KoCanvasBase * KisCanvasResourceProvider::canvas() const { return m_view->canvasBase(); } KoColor KisCanvasResourceProvider::bgColor() const { return m_resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value(); } KoColor KisCanvasResourceProvider::fgColor() const { return m_resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value(); } float KisCanvasResourceProvider::HDRExposure() const { return static_cast(m_resourceManager->resource(HdrExposure).toDouble()); } void KisCanvasResourceProvider::setHDRExposure(float exposure) { m_resourceManager->setResource(HdrExposure, static_cast(exposure)); } float KisCanvasResourceProvider::HDRGamma() const { return static_cast(m_resourceManager->resource(HdrGamma).toDouble()); } void KisCanvasResourceProvider::setHDRGamma(float gamma) { m_resourceManager->setResource(HdrGamma, static_cast(gamma)); } KoPattern * KisCanvasResourceProvider::currentPattern() const { if (m_resourceManager->hasResource(CurrentPattern)) { return m_resourceManager->resource(CurrentPattern).value(); } else { return 0; } } -KisFilterConfiguration * KisCanvasResourceProvider::currentGeneratorConfiguration() const -{ - return m_resourceManager->resource(CurrentGeneratorConfiguration).value(); -} - - KoAbstractGradient* KisCanvasResourceProvider::currentGradient() const { if (m_resourceManager->hasResource(CurrentGradient)) { return m_resourceManager->resource(CurrentGradient).value(); } else { return 0; } } KisImageWSP KisCanvasResourceProvider::currentImage() const { return m_view->image(); } KisNodeSP KisCanvasResourceProvider::currentNode() const { return m_view->activeNode(); } KisPaintOpPresetSP KisCanvasResourceProvider::currentPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(CurrentPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(CurrentPaintOpPreset, v); } KisPaintOpPresetSP KisCanvasResourceProvider::previousPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(PreviousPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPreviousPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPreviousPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(PreviousPaintOpPreset, v); } void KisCanvasResourceProvider::slotPatternActivated(KoResource * res) { KoPattern *pattern = dynamic_cast(res); QVariant v; v.setValue(pattern); m_resourceManager->setResource(CurrentPattern, v); emit sigPatternChanged(pattern); } -void KisCanvasResourceProvider::slotGeneratorConfigurationActivated(KisFilterConfiguration * res) -{ - KisFilterConfiguration * generatorConfiguration = dynamic_cast(res); - QVariant v; - v.setValue(generatorConfiguration); - m_resourceManager->setResource(CurrentGeneratorConfiguration, v); -} - void KisCanvasResourceProvider::slotGradientActivated(KoResource *res) { KoAbstractGradient * gradient = dynamic_cast(res); QVariant v; v.setValue(gradient); m_resourceManager->setResource(CurrentGradient, v); emit sigGradientChanged(gradient); } void KisCanvasResourceProvider::setBGColor(const KoColor& c) { QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceManager::BackgroundColor, v); emit sigBGColorChanged(c); } void KisCanvasResourceProvider::setFGColor(const KoColor& c) { m_fGChanged = true; QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceManager::ForegroundColor, v); emit sigFGColorChanged(c); } void KisCanvasResourceProvider::slotSetFGColor(const KoColor& c) { setFGColor(c); } void KisCanvasResourceProvider::slotSetBGColor(const KoColor& c) { setBGColor(c); } void KisCanvasResourceProvider::slotNodeActivated(const KisNodeSP node) { QVariant v; v.setValue(KisNodeWSP(node)); m_resourceManager->setResource(CurrentKritaNode, v); emit sigNodeChanged(currentNode()); } void KisCanvasResourceProvider::slotImageSizeChanged() { if (KisImageWSP image = m_view->image()) { float fw = image->width() / image->xRes(); float fh = image->height() / image->yRes(); QSizeF postscriptSize(fw, fh); m_resourceManager->setResource(KoCanvasResourceManager::PageSize, postscriptSize); } } void KisCanvasResourceProvider::slotOnScreenResolutionChanged() { KisImageWSP image = m_view->image(); KisCanvas2 *canvas = m_view->canvasBase(); if(!image || !canvas) return; qreal zoomX, zoomY; canvas->coordinatesConverter()->zoom(&zoomX, &zoomY); qreal scaleX = zoomX / image->xRes(); qreal scaleY = zoomY / image->yRes(); emit sigOnScreenResolutionChanged(scaleX, scaleY); } void KisCanvasResourceProvider::slotCanvasResourceChanged(int key, const QVariant & res) { if(key == KoCanvasResourceManager::ForegroundColor || key == KoCanvasResourceManager::BackgroundColor) { KoAbstractGradient* resource = KoResourceServerProvider::instance()->gradientServer()->resources()[0]; KoStopGradient* stopGradient = dynamic_cast(resource); if(stopGradient) { QList stops; stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), fgColor().colorSpace())); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } resource = KoResourceServerProvider::instance()->gradientServer()->resources()[1]; stopGradient = dynamic_cast(resource); if(stopGradient) { QList stops; stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, bgColor()); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } } switch (key) { case(KoCanvasResourceManager::ForegroundColor): m_fGChanged = true; emit sigFGColorChanged(res.value()); break; case(KoCanvasResourceManager::BackgroundColor): emit sigBGColorChanged(res.value()); break; case(CurrentPattern): emit sigPatternChanged(static_cast(res.value())); break; case(CurrentGradient): emit sigGradientChanged(static_cast(res.value())); break; case(CurrentKritaNode) : emit sigNodeChanged(currentNode()); break; case (Opacity): { emit sigOpacityChanged(res.toDouble()); } default: ; // Do nothing }; } void KisCanvasResourceProvider::setCurrentCompositeOp(const QString& compositeOp) { m_resourceManager->setResource(CurrentCompositeOp, QVariant::fromValue(compositeOp)); } QString KisCanvasResourceProvider::currentCompositeOp() const { return m_resourceManager->resource(CurrentCompositeOp).value(); } bool KisCanvasResourceProvider::eraserMode() const { return m_resourceManager->resource(EraserMode).toBool(); } void KisCanvasResourceProvider::setEraserMode(bool value) { m_resourceManager->setResource(EraserMode, QVariant::fromValue(value)); } void KisCanvasResourceProvider::slotPainting() { if (m_fGChanged && m_enablefGChange) { emit sigFGColorUsed(fgColor()); m_fGChanged = false; } } void KisCanvasResourceProvider::slotResetEnableFGChange(bool b) { m_enablefGChange = b; } QList > KisCanvasResourceProvider::perspectiveGrids() const { return m_perspectiveGrids; } void KisCanvasResourceProvider::addPerspectiveGrid(KisAbstractPerspectiveGrid* grid) { m_perspectiveGrids.append(grid); } void KisCanvasResourceProvider::removePerspectiveGrid(KisAbstractPerspectiveGrid* grid) { m_perspectiveGrids.removeOne(grid); } void KisCanvasResourceProvider::clearPerspectiveGrids() { m_perspectiveGrids.clear(); } void KisCanvasResourceProvider::setMirrorHorizontal(bool mirrorHorizontal) { m_resourceManager->setResource(MirrorHorizontal, mirrorHorizontal); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontal() const { return m_resourceManager->resource(MirrorHorizontal).toBool(); } void KisCanvasResourceProvider::setMirrorVertical(bool mirrorVertical) { m_resourceManager->setResource(MirrorVertical, mirrorVertical); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVertical() const { return m_resourceManager->resource(MirrorVertical).toBool(); } void KisCanvasResourceProvider::setMirrorHorizontalLock(bool isLocked) { m_resourceManager->setResource(MirrorHorizontalLock, isLocked); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontalLock() { return m_resourceManager->resource(MirrorHorizontalLock).toBool(); } void KisCanvasResourceProvider::setMirrorVerticalLock(bool isLocked) { m_resourceManager->setResource(MirrorVerticalLock, isLocked); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVerticalHideDecorations() { return m_resourceManager->resource(MirrorVerticalHideDecorations).toBool(); } void KisCanvasResourceProvider::setMirrorVerticalHideDecorations(bool hide) { m_resourceManager->setResource(MirrorVerticalHideDecorations, hide); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorHorizontalHideDecorations() { return m_resourceManager->resource(MirrorHorizontalHideDecorations).toBool(); } void KisCanvasResourceProvider::setMirrorHorizontalHideDecorations(bool hide) { m_resourceManager->setResource(MirrorHorizontalHideDecorations, hide); emit mirrorModeChanged(); } bool KisCanvasResourceProvider::mirrorVerticalLock() { return m_resourceManager->resource(MirrorVerticalLock).toBool(); } void KisCanvasResourceProvider::mirrorVerticalMoveCanvasToCenter() { emit moveMirrorVerticalCenter(); } void KisCanvasResourceProvider::mirrorHorizontalMoveCanvasToCenter() { emit moveMirrorHorizontalCenter(); } void KisCanvasResourceProvider::setOpacity(qreal opacity) { m_resourceManager->setResource(Opacity, opacity); } qreal KisCanvasResourceProvider::opacity() const { return m_resourceManager->resource(Opacity).toReal(); } void KisCanvasResourceProvider::setFlow(qreal flow) { m_resourceManager->setResource(Flow, flow); } qreal KisCanvasResourceProvider::flow() const { return m_resourceManager->resource(Flow).toReal(); } void KisCanvasResourceProvider::setSize(qreal size) { m_resourceManager->setResource(Size, size); } qreal KisCanvasResourceProvider::size() const { return m_resourceManager->resource(Size).toReal(); } void KisCanvasResourceProvider::setSelectionAction(int action) { m_resourceManager->setResource(SelectionAction, action); emit sigSelectionActionChanged(action); } int KisCanvasResourceProvider::selectionAction() { return m_resourceManager->resource(SelectionAction).toInt(); } void KisCanvasResourceProvider::setSelectionMode(int mode) { m_resourceManager->setResource(SelectionMode, mode); emit sigSelectionModeChanged(mode); } int KisCanvasResourceProvider::selectionMode() { return m_resourceManager->resource(SelectionMode).toInt(); } void KisCanvasResourceProvider::setGlobalAlphaLock(bool lock) { m_resourceManager->setResource(GlobalAlphaLock, lock); } bool KisCanvasResourceProvider::globalAlphaLock() const { return m_resourceManager->resource(GlobalAlphaLock).toBool(); } void KisCanvasResourceProvider::setDisablePressure(bool value) { m_resourceManager->setResource(DisablePressure, value); } bool KisCanvasResourceProvider::disablePressure() const { return m_resourceManager->resource(DisablePressure).toBool(); } void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResource* workspace) { emit sigLoadingWorkspace(workspace); } void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResource* workspace) { emit sigSavingWorkspace(workspace); } diff --git a/libs/ui/kis_canvas_resource_provider.h b/libs/ui/kis_canvas_resource_provider.h index 3dc9ac95ab..1e4cc49d38 100644 --- a/libs/ui/kis_canvas_resource_provider.h +++ b/libs/ui/kis_canvas_resource_provider.h @@ -1,248 +1,245 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_CANVAS_RESOURCE_PROVIDER_H_ #define KIS_CANVAS_RESOURCE_PROVIDER_H_ #include #include #include #include #include "kis_types.h" #include "kritaui_export.h" class KisWorkspaceResource; class KoColorProfile; class KoAbstractGradient; class KoResource; class KoCanvasBase; class KisViewManager; class KoPattern; class KisFilterConfiguration; #include /** * KisCanvasResourceProvider contains the per-window current settings that * influence painting, like paintop, color, gradients and so on. */ class KRITAUI_EXPORT KisCanvasResourceProvider : public QObject { Q_OBJECT public: enum Resources { HdrExposure = KoCanvasResourceManager::KritaStart + 1, CurrentPattern, CurrentGradient, CurrentDisplayProfile, CurrentImage, CurrentKritaNode, CurrentPaintOpPreset, CurrentGeneratorConfiguration, CurrentCompositeOp, CurrentEffectiveCompositeOp, LodAvailability, EraserMode, MirrorHorizontal, MirrorVertical, MirrorHorizontalLock, MirrorVerticalLock, MirrorVerticalHideDecorations, MirrorHorizontalHideDecorations, MirrorAxesCenter, Opacity, Flow, Size, HdrGamma, GlobalAlphaLock, DisablePressure, PreviousPaintOpPreset, EffectiveZoom, ///<-Used only by painting tools for non-displaying purposes PresetAllowsLod, SelectionAction, SelectionMode }; KisCanvasResourceProvider(KisViewManager * view); ~KisCanvasResourceProvider(); void setResourceManager(KoCanvasResourceManager *resourceManager); KoCanvasResourceManager* resourceManager(); KoCanvasBase * canvas() const; KoColor bgColor() const; void setBGColor(const KoColor& c); KoColor fgColor() const; void setFGColor(const KoColor& c); float HDRExposure() const; void setHDRExposure(float exposure); float HDRGamma() const; void setHDRGamma(float gamma); bool eraserMode() const; void setEraserMode(bool value); KoPattern *currentPattern() const; KoAbstractGradient *currentGradient() const; KisImageWSP currentImage() const; KisNodeSP currentNode() const; KisPaintOpPresetSP currentPreset() const; void setPaintOpPreset(const KisPaintOpPresetSP preset); KisPaintOpPresetSP previousPreset() const; void setPreviousPaintOpPreset(const KisPaintOpPresetSP preset); - KisFilterConfiguration* currentGeneratorConfiguration() const; - void setCurrentCompositeOp(const QString& compositeOp); QString currentCompositeOp() const; QList > perspectiveGrids() const; void addPerspectiveGrid(KisAbstractPerspectiveGrid*); void removePerspectiveGrid(KisAbstractPerspectiveGrid*); void clearPerspectiveGrids(); void setMirrorHorizontal(bool mirrorHorizontal); bool mirrorHorizontal() const; void setMirrorVertical(bool mirrorVertical); bool mirrorVertical() const; // options for horizontal and vertical mirror toolbar void setMirrorHorizontalLock(bool isLocked); bool mirrorHorizontalLock(); void setMirrorVerticalLock(bool isLocked); bool mirrorVerticalLock(); void setMirrorVerticalHideDecorations(bool hide); bool mirrorVerticalHideDecorations(); void setMirrorHorizontalHideDecorations(bool hide); bool mirrorHorizontalHideDecorations(); void mirrorVerticalMoveCanvasToCenter(); void mirrorHorizontalMoveCanvasToCenter(); void setOpacity(qreal opacity); qreal opacity() const; void setFlow(qreal opacity); qreal flow() const; void setSize(qreal size); qreal size() const; void setGlobalAlphaLock(bool lock); bool globalAlphaLock() const; void setDisablePressure(bool value); bool disablePressure() const; ///Notify that the workspace is saved and settings should be saved to it void notifySavingWorkspace(KisWorkspaceResource* workspace); ///Notify that the workspace is loaded and settings can be read void notifyLoadingWorkspace(KisWorkspaceResource* workspace); int selectionAction(); void setSelectionAction(int action); int selectionMode(); void setSelectionMode(int mode); public Q_SLOTS: void slotSetFGColor(const KoColor& c); void slotSetBGColor(const KoColor& c); void slotPatternActivated(KoResource *pattern); void slotGradientActivated(KoResource *gradient); void slotNodeActivated(const KisNodeSP node); - void slotGeneratorConfigurationActivated(KisFilterConfiguration * generatorConfiguration); void slotPainting(); /** * Set the image size in pixels. The resource provider will store * the image size in postscript points. */ // FIXME: this slot doesn't catch the case when image resolution is changed void slotImageSizeChanged(); void slotOnScreenResolutionChanged(); // This is a flag to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible void slotResetEnableFGChange(bool); private Q_SLOTS: void slotCanvasResourceChanged(int key, const QVariant & res); Q_SIGNALS: void sigFGColorChanged(const KoColor &); void sigBGColorChanged(const KoColor &); void sigGradientChanged(KoAbstractGradient *); void sigPatternChanged(KoPattern *); void sigNodeChanged(const KisNodeSP); void sigDisplayProfileChanged(const KoColorProfile *); void sigFGColorUsed(const KoColor&); void sigOnScreenResolutionChanged(qreal scaleX, qreal scaleY); void sigOpacityChanged(qreal); void sigSavingWorkspace(KisWorkspaceResource* workspace); void sigLoadingWorkspace(KisWorkspaceResource* workspace); void sigSelectionActionChanged(const int); void sigSelectionModeChanged(const int); void mirrorModeChanged(); void moveMirrorVerticalCenter(); void moveMirrorHorizontalCenter(); private: KisViewManager * m_view; KoCanvasResourceManager *m_resourceManager; bool m_fGChanged; QList > m_perspectiveGrids; // This is a flag to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible bool m_enablefGChange; }; #endif diff --git a/libs/ui/kis_filter_manager.cc b/libs/ui/kis_filter_manager.cc index 5148da4a3f..36712121e9 100644 --- a/libs/ui/kis_filter_manager.cc +++ b/libs/ui/kis_filter_manager.cc @@ -1,351 +1,351 @@ /* * Copyright (c) 2007 Boudewijn Rempt * 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. */ #include "kis_filter_manager.h" #include #include #include #include #include #include #include // krita/image #include #include #include #include // krita/ui #include "KisViewManager.h" #include "kis_canvas2.h" #include #include "kis_action.h" #include "kis_action_manager.h" #include "kis_canvas_resource_provider.h" #include "dialogs/kis_dlg_filter.h" #include "strokes/kis_filter_stroke_strategy.h" #include "krita_utils.h" struct KisFilterManager::Private { Private() : reapplyAction(0) , actionCollection(0) , actionManager(0) , view(0) { } KisAction* reapplyAction; QHash filterActionMenus; QHash filters2Action; KActionCollection *actionCollection; KisActionManager *actionManager; KisViewManager *view; - KisSafeFilterConfigurationSP lastConfiguration; - KisSafeFilterConfigurationSP currentlyAppliedConfiguration; + KisFilterConfigurationSP lastConfiguration; + KisFilterConfigurationSP currentlyAppliedConfiguration; KisStrokeId currentStrokeId; QRect initialApplyRect; QSignalMapper actionsMapper; QPointer filterDialog; }; KisFilterManager::KisFilterManager(KisViewManager * view) : d(new Private) { d->view = view; } KisFilterManager::~KisFilterManager() { delete d; } void KisFilterManager::setView(QPointerimageView) { Q_UNUSED(imageView); } void KisFilterManager::setup(KActionCollection * ac, KisActionManager *actionManager) { d->actionCollection = ac; d->actionManager = actionManager; // Setup reapply action d->reapplyAction = d->actionManager->createAction("filter_apply_again"); d->reapplyAction->setEnabled(false); connect(d->reapplyAction, SIGNAL(triggered()), SLOT(reapplyLastFilter())); connect(&d->actionsMapper, SIGNAL(mapped(const QString&)), SLOT(showFilterDialog(const QString&))); // Setup list of filters QStringList keys = KisFilterRegistry::instance()->keys(); keys.sort(); Q_FOREACH (const QString &filterName, keys) { insertFilter(filterName); } connect(KisFilterRegistry::instance(), SIGNAL(filterAdded(QString)), SLOT(insertFilter(const QString &))); } void KisFilterManager::insertFilter(const QString & filterName) { Q_ASSERT(d->actionCollection); KisFilterSP filter = KisFilterRegistry::instance()->value(filterName); Q_ASSERT(filter); if (d->filters2Action.contains(filter.data())) { warnKrita << "Filter" << filterName << " has already been inserted"; return; } KoID category = filter->menuCategory(); KActionMenu* actionMenu = d->filterActionMenus[ category.id()]; if (!actionMenu) { actionMenu = new KActionMenu(category.name(), this); d->actionCollection->addAction(category.id(), actionMenu); d->filterActionMenus[category.id()] = actionMenu; } KisAction *action = new KisAction(filter->menuEntry(), this); action->setDefaultShortcut(filter->shortcut()); action->setActivationFlags(KisAction::ACTIVE_DEVICE); d->actionManager->addAction(QString("krita_filter_%1").arg(filterName), action); d->filters2Action[filter.data()] = action; actionMenu->addAction(action); d->actionsMapper.setMapping(action, filterName); connect(action, SIGNAL(triggered()), &d->actionsMapper, SLOT(map())); } void KisFilterManager::updateGUI() { if (!d->view) return; bool enable = false; KisNodeSP activeNode = d->view->activeNode(); enable = activeNode && activeNode->hasEditablePaintDevice(); d->reapplyAction->setEnabled(enable); for (QHash::iterator it = d->filters2Action.begin(); it != d->filters2Action.end(); ++it) { bool localEnable = enable; it.value()->setEnabled(localEnable); } } void KisFilterManager::reapplyLastFilter() { if (!d->lastConfiguration) return; apply(d->lastConfiguration); finish(); } void KisFilterManager::showFilterDialog(const QString &filterId) { if (d->filterDialog && d->filterDialog->isVisible()) { KisFilterSP filter = KisFilterRegistry::instance()->value(filterId); d->filterDialog->setFilter(filter); return; } connect(d->view->image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(slotStrokeCancelRequested()), Qt::UniqueConnection); connect(d->view->image(), SIGNAL(sigStrokeEndRequested()), SLOT(slotStrokeEndRequested()), Qt::UniqueConnection); /** * The UI should show only after every running stroke is finished, * so a virtual barrier is added here. */ d->view->image()->waitForDone(); Q_ASSERT(d->view); Q_ASSERT(d->view->activeNode()); KisPaintDeviceSP dev = d->view->activeNode()->paintDevice(); if (!dev) { warnKrita << "KisFilterManager::showFilterDialog(): Filtering was requested for illegal active layer!" << d->view->activeNode(); return; } KisFilterSP filter = KisFilterRegistry::instance()->value(filterId); if (dev->colorSpace()->willDegrade(filter->colorSpaceIndependence())) { // Warning bells! if (filter->colorSpaceIndependence() == TO_LAB16) { if (QMessageBox::warning(d->view->mainWindow(), i18nc("@title:window", "Krita"), i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ", filter->name(), dev->colorSpace()->name()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) return; } else if (filter->colorSpaceIndependence() == TO_RGBA16) { if (QMessageBox::warning(d->view->mainWindow(), i18nc("@title:window", "Krita"), i18n("The %1 filter will convert your %2 data to 16-bit RGBA and vice versa. ", filter->name() , dev->colorSpace()->name()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) return; } } if (filter->showConfigurationWidget()) { if (!d->filterDialog) { d->filterDialog = new KisDlgFilter(d->view , d->view->activeNode(), this, d->view->mainWindow()); d->filterDialog->setAttribute(Qt::WA_DeleteOnClose); } d->filterDialog->setFilter(filter); d->filterDialog->setVisible(true); } else { - apply(KisSafeFilterConfigurationSP(filter->defaultConfiguration(d->view->activeNode()->original()))); + apply(KisFilterConfigurationSP(filter->defaultConfiguration(d->view->activeNode()->original()))); finish(); } } -void KisFilterManager::apply(KisSafeFilterConfigurationSP filterConfig) +void KisFilterManager::apply(KisFilterConfigurationSP filterConfig) { KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); KisImageWSP image = d->view->image(); if (d->currentStrokeId) { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::CancelSilentlyMarker); image->cancelStroke(d->currentStrokeId); d->currentStrokeId.clear(); } else { image->waitForDone(); d->initialApplyRect = d->view->activeNode()->exactBounds(); } QRect applyRect = d->initialApplyRect; KisPaintDeviceSP paintDevice = d->view->activeNode()->paintDevice(); if (paintDevice && filter->needsTransparentPixels(filterConfig.data(), paintDevice->colorSpace())) { applyRect |= image->bounds(); } KisPostExecutionUndoAdapter *undoAdapter = image->postExecutionUndoAdapter(); KoCanvasResourceManager *resourceManager = d->view->resourceProvider()->resourceManager(); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image, d->view->activeNode(), undoAdapter, resourceManager); d->currentStrokeId = image->startStroke(new KisFilterStrokeStrategy(filter, - KisSafeFilterConfigurationSP(filterConfig), + KisFilterConfigurationSP(filterConfig), resources)); QRect processRect = filter->changedRect(applyRect, filterConfig.data(), 0); processRect &= image->bounds(); if (filter->supportsThreading()) { QSize size = KritaUtils::optimalPatchSize(); QVector rects = KritaUtils::splitRectIntoPatches(processRect, size); Q_FOREACH (const QRect &rc, rects) { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::Data(rc, true)); } } else { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::Data(processRect, false)); } d->currentlyAppliedConfiguration = filterConfig; } void KisFilterManager::finish() { Q_ASSERT(d->currentStrokeId); d->view->image()->endStroke(d->currentStrokeId); KisFilterSP filter = KisFilterRegistry::instance()->value(d->currentlyAppliedConfiguration->name()); if (filter->bookmarkManager()) { filter->bookmarkManager()->save(KisBookmarkedConfigurationManager::ConfigLastUsed, d->currentlyAppliedConfiguration.data()); } d->lastConfiguration = d->currentlyAppliedConfiguration; d->reapplyAction->setEnabled(true); d->reapplyAction->setText(i18n("Apply Filter Again: %1", filter->name())); d->currentStrokeId.clear(); d->currentlyAppliedConfiguration.clear(); } void KisFilterManager::cancel() { Q_ASSERT(d->currentStrokeId); d->view->image()->cancelStroke(d->currentStrokeId); d->currentStrokeId.clear(); d->currentlyAppliedConfiguration.clear(); } bool KisFilterManager::isStrokeRunning() const { return d->currentStrokeId; } void KisFilterManager::slotStrokeEndRequested() { if (d->currentStrokeId && d->filterDialog) { d->filterDialog->accept(); } } void KisFilterManager::slotStrokeCancelRequested() { if (d->currentStrokeId && d->filterDialog) { d->filterDialog->reject(); } } diff --git a/libs/ui/kis_filter_manager.h b/libs/ui/kis_filter_manager.h index 3a6d69e346..86a1d19bd5 100644 --- a/libs/ui/kis_filter_manager.h +++ b/libs/ui/kis_filter_manager.h @@ -1,68 +1,68 @@ /* * Copyright (c) 2005 Boudewijn Rempt * 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_FILTER_MANAGER_ #define _KIS_FILTER_MANAGER_ #include #include #include class KisViewManager; class KActionCollection; class KisActionManager; class KisView; /** * Create all the filter actions for the specified view and implement re-apply filter */ class KRITAUI_EXPORT KisFilterManager : public QObject { Q_OBJECT public: KisFilterManager(KisViewManager * parent); ~KisFilterManager(); void setView(QPointerimageView); void setup(KActionCollection * ac, KisActionManager *actionManager); void updateGUI(); - void apply(KisSafeFilterConfigurationSP filterConfig); + void apply(KisFilterConfigurationSP filterConfig); void finish(); void cancel(); bool isStrokeRunning() const; private Q_SLOTS: void insertFilter(const QString &name); void showFilterDialog(const QString &filterId); void reapplyLastFilter(); void slotStrokeEndRequested(); void slotStrokeCancelRequested(); private: struct Private; Private * const d; }; #endif diff --git a/libs/ui/kis_layer_manager.cc b/libs/ui/kis_layer_manager.cc index 38cb3cf9b4..6c33bb2a54 100644 --- a/libs/ui/kis_layer_manager.cc +++ b/libs/ui/kis_layer_manager.cc @@ -1,831 +1,831 @@ /* * Copyright (C) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_manager.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 #include #include #include #include #include #include #include #include #include #include #include #include #include "KisImportExportManager.h" #include "kis_config.h" #include "kis_cursor.h" #include "dialogs/kis_dlg_adj_layer_props.h" #include "dialogs/kis_dlg_adjustment_layer.h" #include "dialogs/kis_dlg_layer_properties.h" #include "dialogs/kis_dlg_generator_layer.h" #include "dialogs/kis_dlg_file_layer.h" #include "dialogs/kis_dlg_layer_style.h" #include "KisDocument.h" #include "kis_filter_manager.h" #include "kis_node_visitor.h" #include "kis_paint_layer.h" #include "commands/kis_image_commands.h" #include "commands/kis_layer_command.h" #include "commands/kis_node_commands.h" #include "kis_canvas_resource_provider.h" #include "kis_selection_manager.h" #include "kis_statusbar.h" #include "KisViewManager.h" #include "kis_zoom_manager.h" #include "canvas/kis_canvas2.h" #include "widgets/kis_meta_data_merge_strategy_chooser_widget.h" #include "widgets/kis_wdg_generator.h" #include "kis_progress_widget.h" #include "kis_node_commands_adapter.h" #include "kis_node_manager.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisPart.h" #include "kis_raster_keyframe_channel.h" #include "kis_signal_compressor_with_param.h" #include "kis_abstract_projection_plane.h" #include "commands_new/kis_set_layer_style_command.h" #include "kis_post_execution_undo_adapter.h" #include "kis_selection_mask.h" #include "kis_layer_utils.h" #include "lazybrush/kis_colorize_mask.h" #include "KisSaveGroupVisitor.h" KisLayerManager::KisLayerManager(KisViewManager * view) : m_view(view) , m_imageView(0) , m_imageFlatten(0) , m_imageMergeLayer(0) , m_groupLayersSave(0) , m_imageResizeToLayer(0) , m_flattenLayer(0) , m_rasterizeLayer(0) , m_commandsAdapter(new KisNodeCommandsAdapter(m_view)) , m_layerStyle(0) { } KisLayerManager::~KisLayerManager() { delete m_commandsAdapter; } void KisLayerManager::setView(QPointerview) { m_imageView = view; } KisLayerSP KisLayerManager::activeLayer() { if (m_imageView) { return m_imageView->currentLayer(); } return 0; } KisPaintDeviceSP KisLayerManager::activeDevice() { if (activeLayer()) { return activeLayer()->paintDevice(); } return 0; } void KisLayerManager::activateLayer(KisLayerSP layer) { if (m_imageView) { emit sigLayerActivated(layer); layersUpdated(); if (layer) { m_view->resourceProvider()->slotNodeActivated(layer.data()); } } } void KisLayerManager::setup(KisActionManager* actionManager) { m_imageFlatten = actionManager->createAction("flatten_image"); connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage())); m_imageMergeLayer = actionManager->createAction("merge_layer"); connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer())); m_flattenLayer = actionManager->createAction("flatten_layer"); connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer())); m_rasterizeLayer = actionManager->createAction("rasterize_layer"); connect(m_rasterizeLayer, SIGNAL(triggered()), this, SLOT(rasterizeLayer())); m_groupLayersSave = actionManager->createAction("save_groups_as_images"); connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers())); m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated"); connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated())); m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer"); connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer())); KisAction *action = actionManager->createAction("trim_to_image"); connect(action, SIGNAL(triggered()), this, SLOT(trimToImage())); m_layerStyle = actionManager->createAction("layer_style"); connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle())); } void KisLayerManager::updateGUI() { KisImageWSP image = m_view->image(); KisLayerSP layer; qint32 nlayers = 0; if (image) { layer = activeLayer(); nlayers = image->nlayers(); } // XXX these should be named layer instead of image m_imageFlatten->setEnabled(nlayers > 1); m_imageMergeLayer->setEnabled(nlayers > 1 && layer && layer->prevSibling()); m_flattenLayer->setEnabled(nlayers > 1 && layer && layer->firstChild()); if (m_view->statusBar()) m_view->statusBar()->setProfile(image); } void KisLayerManager::imageResizeToActiveLayer() { KisLayerSP layer; KisImageWSP image = m_view->image(); if (image && (layer = activeLayer())) { QRect cropRect = layer->projection()->nonDefaultPixelArea(); if (!cropRect.isEmpty()) { image->cropImage(cropRect); } else { m_view->showFloatingMessage( i18nc("floating message in layer manager", "Layer is empty "), QIcon(), 2000, KisFloatingMessage::Low); } } } void KisLayerManager::trimToImage() { KisImageWSP image = m_view->image(); if (image) { image->cropImage(image->bounds()); } } void KisLayerManager::layerProperties() { if (!m_view) return; if (!m_view->document()) return; KisLayerSP layer = activeLayer(); QList selectedNodes = m_view->nodeManager()->selectedNodes(); const bool multipleLayersSelected = selectedNodes.size() > 1; if (!layer) return; KisAdjustmentLayerSP alayer = KisAdjustmentLayerSP(dynamic_cast(layer.data())); KisGeneratorLayerSP glayer = KisGeneratorLayerSP(dynamic_cast(layer.data())); if (alayer && !multipleLayersSelected) { KisPaintDeviceSP dev = alayer->projection(); KisDlgAdjLayerProps dlg(alayer, alayer.data(), dev, m_view, alayer->filter().data(), alayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops"); dlg.resize(dlg.minimumSizeHint()); - KisSafeFilterConfigurationSP configBefore(alayer->filter()); + KisFilterConfigurationSP configBefore(alayer->filter()); KIS_ASSERT_RECOVER_RETURN(configBefore); QString xmlBefore = configBefore->toXML(); if (dlg.exec() == QDialog::Accepted) { alayer->setName(dlg.layerName()); - KisSafeFilterConfigurationSP configAfter(dlg.filterConfiguration()); + KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(alayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, false); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } else { - KisSafeFilterConfigurationSP configAfter(dlg.filterConfiguration()); + KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { alayer->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data())); alayer->setDirty(); } } } else if (glayer && !multipleLayersSelected) { KisDlgGeneratorLayer dlg(glayer->name(), m_view, m_view->mainWindow()); dlg.setCaption(i18n("Fill Layer Properties")); - KisSafeFilterConfigurationSP configBefore(glayer->filter()); + KisFilterConfigurationSP configBefore(glayer->filter()); Q_ASSERT(configBefore); QString xmlBefore = configBefore->toXML(); dlg.setConfiguration(configBefore.data()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { glayer->setName(dlg.layerName()); - KisSafeFilterConfigurationSP configAfter(dlg.configuration()); + KisFilterConfigurationSP configAfter(dlg.configuration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(glayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, true); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } } else { // If layer == normal painting layer, vector layer, or group layer QList selectedNodes = m_view->nodeManager()->selectedNodes(); KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view); dialog->resize(dialog->minimumSizeHint()); dialog->setAttribute(Qt::WA_DeleteOnClose); Qt::WindowFlags flags = dialog->windowFlags(); dialog->setWindowFlags(flags | Qt::WindowStaysOnTopHint | Qt::Dialog); dialog->show(); } } void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source) { KisImageWSP image = m_view->image(); if (!image) return; KisLayer *srcLayer = dynamic_cast(source.data()); if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) { image->flattenLayer(srcLayer); return; } KisPaintDeviceSP srcDevice = source->paintDevice() ? source->projection() : source->original(); bool putBehind = false; QString newCompositeOp = source->compositeOpId(); KisColorizeMask *colorizeMask = dynamic_cast(source.data()); if (colorizeMask) { srcDevice = colorizeMask->coloringProjection(); putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND; if (putBehind) { newCompositeOp = COMPOSITE_OVER; } } if (!srcDevice) return; KisPaintDeviceSP clone; if (*srcDevice->colorSpace() != *srcDevice->compositionSourceColorSpace()) { clone = new KisPaintDevice(srcDevice->compositionSourceColorSpace()); QRect rc(srcDevice->extent()); KisPainter::copyAreaOptimized(rc.topLeft(), srcDevice, clone, rc); } else { clone = new KisPaintDevice(*srcDevice); } KisLayerSP layer = new KisPaintLayer(image, source->name(), source->opacity(), clone); layer->setCompositeOpId(newCompositeOp); KisNodeSP parent = source->parent(); KisNodeSP above = source; while (parent && !parent->allowAsChild(layer)) { above = above->parent(); parent = above ? above->parent() : 0; } if (putBehind && above == source->parent()) { above = above->prevSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a Paint Layer")); m_commandsAdapter->addNode(layer, parent, above); m_commandsAdapter->removeNode(source); m_commandsAdapter->endMacro(); } void KisLayerManager::convertGroupToAnimated() { KisGroupLayerSP group = dynamic_cast(activeLayer().data()); if (group.isNull()) return; KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8); animatedLayer->enableAnimation(); KisRasterKeyframeChannel *contentChannel = dynamic_cast( animatedLayer->getKeyframeChannel(KisKeyframeChannel::Content.id())); KIS_ASSERT_RECOVER_RETURN(contentChannel); KisNodeSP child = group->firstChild(); int time = 0; while (child) { contentChannel->importFrame(time, child->projection(), NULL); time++; child = child->nextSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer")); m_commandsAdapter->addNode(animatedLayer, group->parent(), group); m_commandsAdapter->removeNode(group); m_commandsAdapter->endMacro(); } void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above) { Q_ASSERT(activeNode); parent = activeNode; above = parent->lastChild(); while (parent && (!parent->allowAsChild(node) || parent->userLocked())) { above = parent; parent = parent->parent(); } if (!parent) { warnKrita << "KisLayerManager::adjustLayerPosition:" << "No node accepted newly created node"; parent = m_view->image()->root(); above = parent->lastChild(); } } void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisLayerSP layer, bool updateImage) { KisNodeSP parent; KisNodeSP above; adjustLayerPosition(layer, activeNode, parent, above); KisGroupLayer *group = dynamic_cast(parent.data()); const bool parentForceUpdate = group && !group->projectionIsValid(); updateImage |= parentForceUpdate; m_commandsAdapter->addNode(layer, parent, above, updateImage, updateImage); } KisLayerSP KisLayerManager::addLayer(KisNodeSP activeNode) { KisLayerSP layer = KisLayerUtils::constructDefaultLayer(m_view->image()); addLayerCommon(activeNode, layer, false); return layer; } void KisLayerManager::addGroupLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisGroupLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8), false); } void KisLayerManager::addCloneLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisCloneLayer(activeLayer(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8)); } void KisLayerManager::addShapeLayer(KisNodeSP activeNode) { if (!m_view) return; if (!m_view->document()) return; KisImageWSP image = m_view->image(); KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8); addLayerCommon(activeNode, layer, false); } void KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisSelectionSP selection = m_view->selection(); KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection); image->refreshGraph(); KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original()); KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(), i18n("New Filter Layer"), m_view); dlg.resize(dlg.minimumSizeHint()); // ensure that the device may be free'd by the dialog // when it is not needed anymore previewDevice = 0; if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) { // XXX: add messagebox warning if there's no filter set! m_commandsAdapter->undoLastCommand(); } else { adjl->setName(dlg.layerName()); } } KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name, - KisFilterConfiguration * filter, KisSelectionSP selection) + KisFilterConfigurationSP filter, KisSelectionSP selection) { KisImageWSP image = m_view->image(); KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter, selection); addLayerCommon(activeNode, layer); return layer; } void KisLayerManager::addGeneratorLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisDlgGeneratorLayer dlg(image->nextLayerName(), m_view, m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { KisSelectionSP selection = m_view->selection(); - KisFilterConfiguration * generator = dlg.configuration(); + KisFilterConfigurationSP generator = dlg.configuration(); QString name = dlg.layerName(); addLayerCommon(activeNode, new KisGeneratorLayer(image, name, generator, selection)); } } void KisLayerManager::rotateLayer(double radians) { if (!m_view->image()) return; KisLayerSP layer = activeLayer(); if (!layer) return; m_view->image()->rotateNode(layer, radians); } void KisLayerManager::shearLayer(double angleX, double angleY) { if (!m_view->image()) return; KisLayerSP layer = activeLayer(); if (!layer) return; m_view->image()->shearNode(layer, angleX, angleY); } void KisLayerManager::flattenImage() { KisImageWSP image = m_view->image(); if (image) { bool doIt = true; if (image->nHiddenLayers() > 0) { int answer = QMessageBox::warning(m_view->mainWindow(), i18nc("@title:window", "Flatten Image"), i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer != QMessageBox::Yes) { doIt = false; } } if (doIt) { image->flatten(); } } } inline bool isSelectionMask(KisNodeSP node) { return dynamic_cast(node.data()); } bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image) { bool result = false; KisNodeSP prevNode = currentNode->prevSibling(); if (isSelectionMask(currentNode) && prevNode && isSelectionMask(prevNode)) { QList mergedNodes; mergedNodes.append(currentNode); mergedNodes.append(prevNode); image->mergeMultipleLayers(mergedNodes, currentNode); result = true; } return result; } void KisLayerManager::mergeLayer() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; QList selectedNodes = m_view->nodeManager()->selectedNodes(); if (selectedNodes.size() > 1) { image->mergeMultipleLayers(selectedNodes, m_view->activeNode()); } else if (!tryMergeSelectionMasks(m_view->activeNode(), image)) { if (!layer->prevSibling()) return; KisLayer *prevLayer = dynamic_cast(layer->prevSibling().data()); if (!prevLayer) return; if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) { image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); } else { const KisMetaData::MergeStrategy* strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow()); if (!strategy) return; image->mergeDown(layer, strategy); } } m_view->updateGUI(); } void KisLayerManager::flattenLayer() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; image->flattenLayer(layer); m_view->updateGUI(); } void KisLayerManager::rasterizeLayer() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; KisPaintLayerSP paintLayer = new KisPaintLayer(image, layer->name(), layer->opacity()); KisPainter gc(paintLayer->paintDevice()); QRect rc = layer->projection()->exactBounds(); gc.bitBlt(rc.topLeft(), layer->projection(), rc); m_commandsAdapter->beginMacro(kundo2_i18n("Rasterize Layer")); m_commandsAdapter->addNode(paintLayer.data(), layer->parent().data(), layer.data()); int childCount = layer->childCount(); for (int i = 0; i < childCount; i++) { m_commandsAdapter->moveNode(layer->firstChild(), paintLayer, paintLayer->lastChild()); } m_commandsAdapter->removeNode(layer); m_commandsAdapter->endMacro(); updateGUI(); } void KisLayerManager::layersUpdated() { KisLayerSP layer = activeLayer(); if (!layer) return; m_view->updateGUI(); } void KisLayerManager::saveGroupLayers() { QStringList listMimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Export); KoDialog dlg; QWidget *page = new QWidget(&dlg); dlg.setMainWidget(page); QBoxLayout *layout = new QVBoxLayout(page); KisFileNameRequester *urlRequester = new KisFileNameRequester(page); urlRequester->setMode(KoFileDialog::SaveFile); if (m_view->document()->url().isLocalFile()) { urlRequester->setStartDir(QFileInfo(m_view->document()->url().toLocalFile()).absolutePath()); } urlRequester->setMimeTypeFilters(listMimeFilter); urlRequester->setFileName(m_view->document()->url().toLocalFile()); layout->addWidget(urlRequester); QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page); chkInvisible->setChecked(false); layout->addWidget(chkInvisible); QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page); chkDepth->setChecked(true); layout->addWidget(chkDepth); if (!dlg.exec()) return; QString path = urlRequester->fileName(); if (path.isEmpty()) return; QFileInfo f(path); QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName()); if (mimeType.isEmpty()) { mimeType = "image/png"; } QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first(); QString basename = f.baseName(); KisImageWSP image = m_view->image(); if (!image) return; KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType); image->rootLayer()->accept(v); } bool KisLayerManager::activeLayerHasSelection() { return (activeLayer()->selection() != 0); } void KisLayerManager::addFileLayer(KisNodeSP activeNode) { QString basePath; QUrl url = m_view->document()->url(); if (url.isLocalFile()) { basePath = QFileInfo(url.toLocalFile()).absolutePath(); } KisImageWSP image = m_view->image(); KisDlgFileLayer dlg(basePath, image->nextLayerName(), m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { QString name = dlg.layerName(); QString fileName = dlg.fileName(); if(fileName.isEmpty()){ QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); return; } KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution(); addLayerCommon(activeNode, new KisFileLayer(image, basePath, fileName, scalingMethod, name, OPACITY_OPAQUE_U8)); } } void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg) { KisSetLayerStyleCommand::updateLayerStyle(layer, dlg->style()->clone()); } void KisLayerManager::layerStyle() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; KisPSDLayerStyleSP oldStyle; if (layer->layerStyle()) { oldStyle = layer->layerStyle()->clone(); } else { oldStyle = toQShared(new KisPSDLayerStyle()); } KisDlgLayerStyle dlg(oldStyle->clone(), m_view->resourceProvider()); std::function updateCall(std::bind(updateLayerStyles, layer, &dlg)); SignalToFunctionProxy proxy(updateCall); connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start())); if (dlg.exec() == QDialog::Accepted) { KisPSDLayerStyleSP newStyle = dlg.style(); KUndo2CommandSP command = toQShared( new KisSetLayerStyleCommand(layer, oldStyle, newStyle)); image->postExecutionUndoAdapter()->addCommand(command); } } diff --git a/libs/ui/kis_layer_manager.h b/libs/ui/kis_layer_manager.h index 03f39f3c97..b61554aff9 100644 --- a/libs/ui/kis_layer_manager.h +++ b/libs/ui/kis_layer_manager.h @@ -1,134 +1,134 @@ /* * Copyright (C) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LAYER_MANAGER #define KIS_LAYER_MANAGER #include #include #include #include "kis_adjustment_layer.h" #include "kis_types.h" #include "KisView.h" #include class KisViewManager; class KisNodeCommandsAdapter; class KisAction; class KisActionManager; /** * KisLayerManager takes care of the gui around working with layers: * adding, removing, editing. It also keeps track of the active layer * for this view. */ class KisLayerManager : public QObject { Q_OBJECT public: KisLayerManager(KisViewManager * view); ~KisLayerManager(); void setView(QPointerview); Q_SIGNALS: void sigLayerActivated(KisLayerSP layer); private: friend class KisNodeManager; /** * Activate the specified layer. The layer may be 0. */ void activateLayer(KisLayerSP layer); KisLayerSP activeLayer(); KisPaintDeviceSP activeDevice(); void setup(KisActionManager *actionManager); void updateGUI(); void rotateLayer(double radians); void shearLayer(double angleX, double angleY); private Q_SLOTS: void mergeLayer(); void imageResizeToActiveLayer(); void trimToImage(); void layerProperties(); void flattenImage(); void flattenLayer(); void rasterizeLayer(); void layersUpdated(); void saveGroupLayers(); bool activeLayerHasSelection(); void convertNodeToPaintLayer(KisNodeSP source); void convertGroupToAnimated(); KisLayerSP addLayer(KisNodeSP activeNode); void addGroupLayer(KisNodeSP activeNode); void addCloneLayer(KisNodeSP activeNode); void addShapeLayer(KisNodeSP activeNode); void addAdjustmentLayer(KisNodeSP activeNode); - KisAdjustmentLayerSP addAdjustmentLayer(KisNodeSP activeNode, const QString & name, KisFilterConfiguration * filter, KisSelectionSP selection); + KisAdjustmentLayerSP addAdjustmentLayer(KisNodeSP activeNode, const QString & name, KisFilterConfigurationSP filter, KisSelectionSP selection); void addGeneratorLayer(KisNodeSP activeNode); void addFileLayer(KisNodeSP activeNode); void layerStyle(); private: void adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above); void addLayerCommon(KisNodeSP activeNode, KisLayerSP layer, bool updateImage = true); private: KisViewManager * m_view; QPointerm_imageView; KisAction *m_imageFlatten; KisAction *m_imageMergeLayer; KisAction *m_groupLayersSave; KisAction *m_convertGroupAnimated; KisAction *m_imageResizeToLayer; KisAction *m_flattenLayer; KisAction *m_rasterizeLayer; KisNodeCommandsAdapter* m_commandsAdapter; KisAction *m_layerStyle; }; #endif diff --git a/libs/ui/kis_mask_manager.cc b/libs/ui/kis_mask_manager.cc index c46640f4f4..e2deb51aea 100644 --- a/libs/ui/kis_mask_manager.cc +++ b/libs/ui/kis_mask_manager.cc @@ -1,306 +1,306 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2006 * * 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_mask_manager.h" #include #include #include #include #include #include #include #include "KisDocument.h" #include "KisViewManager.h" #include #include #include #include #include #include #include #include #include #include "dialogs/kis_dlg_adjustment_layer.h" #include "widgets/kis_mask_widgets.h" #include #include #include #include "dialogs/kis_dlg_adj_layer_props.h" #include #include #include #include #include "kis_node_commands_adapter.h" #include "commands/kis_selection_commands.h" #include "kis_iterator_ng.h" KisMaskManager::KisMaskManager(KisViewManager * view) : m_view(view) , m_imageView(0) , m_commandsAdapter(new KisNodeCommandsAdapter(m_view)) { } void KisMaskManager::setView(QPointerimageView) { m_imageView = imageView; } void KisMaskManager::setup(KActionCollection *actionCollection, KisActionManager *actionManager) { Q_UNUSED(actionCollection); Q_UNUSED(actionManager); } void KisMaskManager::updateGUI() { // XXX: enable/disable menu items according to whether there's a mask selected currently // XXX: disable the selection mask item if there's already a selection mask // YYY: doesn't KisAction do that already? } KisMaskSP KisMaskManager::activeMask() { if (m_imageView) { return m_imageView->currentMask(); } return 0; } KisPaintDeviceSP KisMaskManager::activeDevice() { KisMaskSP mask = activeMask(); return mask ? mask->paintDevice() : 0; } void KisMaskManager::activateMask(KisMaskSP mask) { Q_UNUSED(mask); } void KisMaskManager::masksUpdated() { m_view->updateGUI(); } void KisMaskManager::adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above) { Q_ASSERT(node); Q_ASSERT(activeNode); if (!avoidActiveNode && activeNode->allowAsChild(node)) { parent = activeNode; above = activeNode->lastChild(); } else if (activeNode->parent() && activeNode->parent()->allowAsChild(node)) { parent = activeNode->parent(); above = activeNode; } else { KisNodeSP t = activeNode; while ((t = t->nextSibling())) { if (t->allowAsChild(node)) { parent = t; above = t->lastChild(); break; } } if (!t) { t = activeNode; while ((t = t->prevSibling())) { if (t->allowAsChild(node)) { parent = t; above = t->lastChild(); break; } } } if (!t && activeNode->parent()) { adjustMaskPosition(node, activeNode->parent(), true, parent, above); } else if (!t) { KisImageWSP image = m_view->image(); KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace()); m_commandsAdapter->addNode(layer, activeNode, 0); parent = layer; above = 0; } } } void KisMaskManager::createMaskCommon(KisMaskSP mask, KisNodeSP activeNode, KisPaintDeviceSP copyFrom, const KUndo2MagicString& macroName, const QString &nodeType, const QString &nodeName, bool suppressSelection, bool avoidActiveNode, bool updateImage) { m_commandsAdapter->beginMacro(macroName); KisNodeSP parent; KisNodeSP above; adjustMaskPosition(mask, activeNode, avoidActiveNode, parent, above); KisLayerSP parentLayer = dynamic_cast(parent.data()); Q_ASSERT(parentLayer); if (!suppressSelection) { if (copyFrom) { mask->initSelection(copyFrom, parentLayer); } else { mask->initSelection(m_view->selection(), parentLayer); } } //counting number of KisSelectionMask QList masks = parentLayer->childNodes(QStringList(nodeType),KoProperties()); int number = masks.count() + 1; mask->setName(nodeName + QString(" ") + QString::number(number)); m_commandsAdapter->addNode(mask, parentLayer, above, updateImage, updateImage); m_commandsAdapter->endMacro(); masksUpdated(); } void KisMaskManager::createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode) { KisSelectionMaskSP mask = new KisSelectionMask(m_view->image()); createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Selection Mask"), "KisSelectionMask", i18n("Selection"), false, avoidActiveNode, false); mask->setActive(true); } void KisMaskManager::createTransparencyMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode) { KisMaskSP mask = new KisTransparencyMask(); createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Transparency Mask"), "KisTransparencyMask", i18n("Transparency Mask"), false, avoidActiveNode); } void KisMaskManager::createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool avoidActiveNode) { KisFilterMaskSP mask = new KisFilterMask(); createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Filter Mask"), "KisFilterMask", i18n("Filter Mask"), false, avoidActiveNode); /** * FIXME: We'll use layer's original for creation of a thumbnail. * Actually, we can't use it's projection as newly created mask * may be going to be inserted in the middle of the masks stack */ KisPaintDeviceSP originalDevice = mask->parent()->original(); KisDlgAdjustmentLayer dialog(mask, mask.data(), originalDevice, mask->name(), i18n("New Filter Mask"), m_view); // If we are supposed to not disturb the user, don't start asking them about things. if(quiet) { - KisFilterConfiguration *filter = KisFilterRegistry::instance()->values().first()->defaultConfiguration(originalDevice); + KisFilterConfigurationSP filter = KisFilterRegistry::instance()->values().first()->defaultConfiguration(originalDevice); if (filter) { mask->setFilter(filter); mask->setName(mask->name()); } return; } if (dialog.exec() == QDialog::Accepted) { - KisFilterConfiguration *filter = dialog.filterConfiguration(); + KisFilterConfigurationSP filter = dialog.filterConfiguration(); if (filter) { QString name = dialog.layerName(); mask->setFilter(filter); mask->setName(name); } } else { m_commandsAdapter->undoLastCommand(); } } void KisMaskManager::createColorizeMask(KisNodeSP activeNode) { KisColorizeMaskSP mask = new KisColorizeMask(); createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Colorize Mask"), "KisColorizeMask", i18n("Colorize Mask"), true, false); mask->initializeCompositeOp(); mask->setColorSpace(mask->parent()->colorSpace()); } void KisMaskManager::createTransformMask(KisNodeSP activeNode) { KisTransformMaskSP mask = new KisTransformMask(); createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Transform Mask"), "KisTransformMask", i18n("Transform Mask"), true, false); } void KisMaskManager::maskProperties() { if (!activeMask()) return; if (activeMask()->inherits("KisFilterMask")) { KisFilterMask *mask = static_cast(activeMask().data()); KisLayerSP layer = dynamic_cast(mask->parent().data()); if (! layer) return; KisPaintDeviceSP dev = layer->original(); if (!dev) { return; } KisDlgAdjLayerProps dlg(layer, mask, dev, m_view, mask->filter().data(), mask->name(), i18n("Filter Mask Properties"), m_view->mainWindow(), "dlgeffectmaskprops"); - KisSafeFilterConfigurationSP configBefore(mask->filter()); + KisFilterConfigurationSP configBefore(mask->filter()); Q_ASSERT(configBefore); QString xmlBefore = configBefore->toXML(); if (dlg.exec() == QDialog::Accepted) { - KisSafeFilterConfigurationSP configAfter(dlg.filterConfiguration()); + KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); mask->setName(dlg.layerName()); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(mask, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, false); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } else { - KisSafeFilterConfigurationSP configAfter(dlg.filterConfiguration()); + KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { mask->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data())); mask->setDirty(); } } } else { // Not much to show for transparency or selection masks? } } diff --git a/libs/ui/kis_node_manager.cpp b/libs/ui/kis_node_manager.cpp index 06cc7ba543..b09ee2e188 100644 --- a/libs/ui/kis_node_manager.cpp +++ b/libs/ui/kis_node_manager.cpp @@ -1,1310 +1,1318 @@ /* * Copyright (C) 2007 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_node_manager.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 "KisPart.h" #include "canvas/kis_canvas2.h" #include "kis_shape_controller.h" #include "kis_canvas_resource_provider.h" #include "KisViewManager.h" #include "KisDocument.h" #include "kis_mask_manager.h" #include "kis_group_layer.h" #include "kis_layer_manager.h" #include "kis_selection_manager.h" #include "kis_node_commands_adapter.h" #include "kis_action.h" #include "kis_action_manager.h" #include "kis_processing_applicator.h" #include "kis_sequential_iterator.h" #include "kis_transaction.h" #include "kis_node_selection_adapter.h" #include "kis_node_insertion_adapter.h" #include "kis_node_juggler_compressed.h" #include "kis_clipboard.h" #include "kis_node_dummies_graph.h" #include "kis_mimedata.h" #include "kis_layer_utils.h" #include "krita_utils.h" #include "processing/kis_mirror_processing_visitor.h" #include "KisView.h" struct KisNodeManager::Private { Private(KisNodeManager *_q, KisViewManager *v) : q(_q) , view(v) , imageView(0) , layerManager(v) , maskManager(v) , commandsAdapter(v) , nodeSelectionAdapter(new KisNodeSelectionAdapter(q)) , nodeInsertionAdapter(new KisNodeInsertionAdapter(q)) { } KisNodeManager * q; KisViewManager * view; QPointerimageView; KisLayerManager layerManager; KisMaskManager maskManager; KisNodeCommandsAdapter commandsAdapter; QScopedPointer nodeSelectionAdapter; QScopedPointer nodeInsertionAdapter; KisNodeList selectedNodes; QPointer nodeJuggler; bool activateNodeImpl(KisNodeSP node); QSignalMapper nodeCreationSignalMapper; QSignalMapper nodeConversionSignalMapper; void saveDeviceAsImage(KisPaintDeviceSP device, const QString &defaultName, const QRect &bounds, qreal xRes, qreal yRes, quint8 opacity); void mergeTransparencyMaskAsAlpha(bool writeToLayers); KisNodeJugglerCompressed* lazyGetJuggler(const KUndo2MagicString &actionName); }; bool KisNodeManager::Private::activateNodeImpl(KisNodeSP node) { Q_ASSERT(view); Q_ASSERT(view->canvasBase()); Q_ASSERT(view->canvasBase()->globalShapeManager()); Q_ASSERT(imageView); if (node && node == q->activeNode()) { return false; } // Set the selection on the shape manager to the active layer // and set call KoSelection::setActiveLayer( KoShapeLayer* layer ) // with the parent of the active layer. KoSelection *selection = view->canvasBase()->globalShapeManager()->selection(); Q_ASSERT(selection); selection->deselectAll(); if (!node) { selection->setActiveLayer(0); imageView->setCurrentNode(0); maskManager.activateMask(0); layerManager.activateLayer(0); } else { KoShape * shape = view->document()->shapeForNode(node); Q_ASSERT(shape); selection->select(shape); KoShapeLayer * shapeLayer = dynamic_cast(shape); Q_ASSERT(shapeLayer); // shapeLayer->setGeometryProtected(node->userLocked()); // shapeLayer->setVisible(node->visible()); selection->setActiveLayer(shapeLayer); imageView->setCurrentNode(node); if (KisLayerSP layer = dynamic_cast(node.data())) { maskManager.activateMask(0); layerManager.activateLayer(layer); } else if (KisMaskSP mask = dynamic_cast(node.data())) { maskManager.activateMask(mask); // XXX_NODE: for now, masks cannot be nested. layerManager.activateLayer(static_cast(node->parent().data())); } } return true; } KisNodeManager::KisNodeManager(KisViewManager *view) : m_d(new Private(this, view)) { connect(&m_d->layerManager, SIGNAL(sigLayerActivated(KisLayerSP)), SIGNAL(sigLayerActivated(KisLayerSP))); } KisNodeManager::~KisNodeManager() { delete m_d; } void KisNodeManager::setView(QPointerimageView) { m_d->maskManager.setView(imageView); m_d->layerManager.setView(imageView); if (m_d->imageView) { KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(shapeController); shapeController->disconnect(SIGNAL(sigActivateNode(KisNodeSP)), this); m_d->imageView->image()->disconnect(this); } m_d->imageView = imageView; if (m_d->imageView) { KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(shapeController); connect(shapeController, SIGNAL(sigActivateNode(KisNodeSP)), SLOT(slotNonUiActivatedNode(KisNodeSP))); connect(m_d->imageView->image(), SIGNAL(sigIsolatedModeChanged()),this, SLOT(slotUpdateIsolateModeAction())); connect(m_d->imageView->image(), SIGNAL(sigRequestNodeReselection(KisNodeSP, const KisNodeList&)),this, SLOT(slotImageRequestNodeReselection(KisNodeSP, const KisNodeList&))); m_d->imageView->resourceProvider()->slotNodeActivated(m_d->imageView->currentNode()); } } #define NEW_LAYER_ACTION(id, layerType) \ { \ action = actionManager->createAction(id); \ m_d->nodeCreationSignalMapper.setMapping(action, layerType); \ connect(action, SIGNAL(triggered()), \ &m_d->nodeCreationSignalMapper, SLOT(map())); \ } #define CONVERT_NODE_ACTION_2(id, layerType, exclude) \ { \ action = actionManager->createAction(id); \ action->setExcludedNodeTypes(QStringList(exclude)); \ actionManager->addAction(id, action); \ m_d->nodeConversionSignalMapper.setMapping(action, layerType); \ connect(action, SIGNAL(triggered()), \ &m_d->nodeConversionSignalMapper, SLOT(map())); \ } #define CONVERT_NODE_ACTION(id, layerType) \ CONVERT_NODE_ACTION_2(id, layerType, layerType) void KisNodeManager::setup(KActionCollection * actionCollection, KisActionManager* actionManager) { m_d->layerManager.setup(actionManager); m_d->maskManager.setup(actionCollection, actionManager); KisAction * action = actionManager->createAction("mirrorNodeX"); connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeX())); action = actionManager->createAction("mirrorNodeY"); connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeY())); action = actionManager->createAction("activateNextLayer"); connect(action, SIGNAL(triggered()), this, SLOT(activateNextNode())); action = actionManager->createAction("activatePreviousLayer"); connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousNode())); action = actionManager->createAction("save_node_as_image"); connect(action, SIGNAL(triggered()), this, SLOT(saveNodeAsImage())); action = actionManager->createAction("duplicatelayer"); connect(action, SIGNAL(triggered()), this, SLOT(duplicateActiveNode())); action = actionManager->createAction("copy_layer_clipboard"); connect(action, SIGNAL(triggered()), this, SLOT(copyLayersToClipboard())); action = actionManager->createAction("cut_layer_clipboard"); connect(action, SIGNAL(triggered()), this, SLOT(cutLayersToClipboard())); action = actionManager->createAction("paste_layer_from_clipboard"); connect(action, SIGNAL(triggered()), this, SLOT(pasteLayersFromClipboard())); action = actionManager->createAction("create_quick_group"); connect(action, SIGNAL(triggered()), this, SLOT(createQuickGroup())); action = actionManager->createAction("create_quick_clipping_group"); connect(action, SIGNAL(triggered()), this, SLOT(createQuickClippingGroup())); action = actionManager->createAction("quick_ungroup"); connect(action, SIGNAL(triggered()), this, SLOT(quickUngroup())); action = actionManager->createAction("select_all_layers"); connect(action, SIGNAL(triggered()), this, SLOT(selectAllNodes())); action = actionManager->createAction("select_visible_layers"); connect(action, SIGNAL(triggered()), this, SLOT(selectVisibleNodes())); action = actionManager->createAction("select_locked_layers"); connect(action, SIGNAL(triggered()), this, SLOT(selectLockedNodes())); action = actionManager->createAction("select_invisible_layers"); connect(action, SIGNAL(triggered()), this, SLOT(selectInvisibleNodes())); action = actionManager->createAction("select_unlocked_layers"); connect(action, SIGNAL(triggered()), this, SLOT(selectUnlockedNodes())); + action = actionManager->createAction("new_from_visible"); + connect(action, SIGNAL(triggered()), this, SLOT(createFromVisible())); + NEW_LAYER_ACTION("add_new_paint_layer", "KisPaintLayer"); NEW_LAYER_ACTION("add_new_group_layer", "KisGroupLayer"); NEW_LAYER_ACTION("add_new_clone_layer", "KisCloneLayer"); NEW_LAYER_ACTION("add_new_shape_layer", "KisShapeLayer"); NEW_LAYER_ACTION("add_new_adjustment_layer", "KisAdjustmentLayer"); NEW_LAYER_ACTION("add_new_fill_layer", "KisGeneratorLayer"); NEW_LAYER_ACTION("add_new_file_layer", "KisFileLayer"); NEW_LAYER_ACTION("add_new_transparency_mask", "KisTransparencyMask"); NEW_LAYER_ACTION("add_new_filter_mask", "KisFilterMask"); NEW_LAYER_ACTION("add_new_colorize_mask", "KisColorizeMask"); NEW_LAYER_ACTION("add_new_transform_mask", "KisTransformMask"); NEW_LAYER_ACTION("add_new_selection_mask", "KisSelectionMask"); connect(&m_d->nodeCreationSignalMapper, SIGNAL(mapped(const QString &)), this, SLOT(createNode(const QString &))); CONVERT_NODE_ACTION("convert_to_paint_layer", "KisPaintLayer"); CONVERT_NODE_ACTION_2("convert_to_selection_mask", "KisSelectionMask", QStringList() << "KisSelectionMask" << "KisColorizeMask"); CONVERT_NODE_ACTION_2("convert_to_filter_mask", "KisFilterMask", QStringList() << "KisFilterMask" << "KisColorizeMask"); CONVERT_NODE_ACTION_2("convert_to_transparency_mask", "KisTransparencyMask", QStringList() << "KisTransparencyMask" << "KisColorizeMask"); CONVERT_NODE_ACTION("convert_to_animated", "animated"); connect(&m_d->nodeConversionSignalMapper, SIGNAL(mapped(const QString &)), this, SLOT(convertNode(const QString &))); action = actionManager->createAction("isolate_layer"); connect(action, SIGNAL(triggered(bool)), this, SLOT(toggleIsolateMode(bool))); action = actionManager->createAction("split_alpha_into_mask"); connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaIntoMask())); action = actionManager->createAction("split_alpha_write"); connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaWrite())); // HINT: we can save even when the nodes are not editable action = actionManager->createAction("split_alpha_save_merged"); connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaSaveMerged())); connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(slotUpdateIsolateModeAction())); connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(slotTryFinishIsolatedMode())); } void KisNodeManager::updateGUI() { // enable/disable all relevant actions m_d->layerManager.updateGUI(); m_d->maskManager.updateGUI(); } KisNodeSP KisNodeManager::activeNode() { if (m_d->imageView) { return m_d->imageView->currentNode(); } return 0; } KisLayerSP KisNodeManager::activeLayer() { return m_d->layerManager.activeLayer(); } const KoColorSpace* KisNodeManager::activeColorSpace() { if (m_d->maskManager.activeDevice()) { return m_d->maskManager.activeDevice()->colorSpace(); } else { Q_ASSERT(m_d->layerManager.activeLayer()); if (m_d->layerManager.activeLayer()->parentLayer()) return m_d->layerManager.activeLayer()->parentLayer()->colorSpace(); else return m_d->view->image()->colorSpace(); } } void KisNodeManager::moveNodeAt(KisNodeSP node, KisNodeSP parent, int index) { if (parent->allowAsChild(node)) { if (node->inherits("KisSelectionMask") && parent->inherits("KisLayer")) { KisSelectionMask *m = dynamic_cast(node.data()); KisLayer *l = dynamic_cast(parent.data()); KisSelectionMaskSP selMask = l->selectionMask(); if (m && m->active() && l && l->selectionMask()) selMask->setActive(false); } m_d->commandsAdapter.moveNode(node, parent, index); } } void KisNodeManager::moveNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) { KUndo2MagicString actionName = kundo2_i18n("Move Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->moveNode(nodes, parent, aboveThis); } void KisNodeManager::copyNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) { KUndo2MagicString actionName = kundo2_i18n("Copy Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->copyNode(nodes, parent, aboveThis); } void KisNodeManager::addNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis) { KUndo2MagicString actionName = kundo2_i18n("Add Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->addNode(nodes, parent, aboveThis); } void KisNodeManager::toggleIsolateActiveNode() { KisImageWSP image = m_d->view->image(); KisNodeSP activeNode = this->activeNode(); KIS_ASSERT_RECOVER_RETURN(activeNode); if (activeNode == image->isolatedModeRoot()) { toggleIsolateMode(false); } else { toggleIsolateMode(true); } } void KisNodeManager::toggleIsolateMode(bool checked) { KisImageWSP image = m_d->view->image(); if (checked) { KisNodeSP activeNode = this->activeNode(); // Transform and colorize masks don't have pixel data... if (activeNode->inherits("KisTransformMask") || activeNode->inherits("KisColorizeMask")) return; KIS_ASSERT_RECOVER_RETURN(activeNode); if (!image->startIsolatedMode(activeNode)) { KisAction *action = m_d->view->actionManager()->actionByName("isolate_layer"); action->setChecked(false); } } else { image->stopIsolatedMode(); } } void KisNodeManager::slotUpdateIsolateModeAction() { KisAction *action = m_d->view->actionManager()->actionByName("isolate_layer"); Q_ASSERT(action); KisNodeSP activeNode = this->activeNode(); KisNodeSP isolatedRootNode = m_d->view->image()->isolatedModeRoot(); action->setChecked(isolatedRootNode && isolatedRootNode == activeNode); } void KisNodeManager::slotTryFinishIsolatedMode() { KisNodeSP isolatedRootNode = m_d->view->image()->isolatedModeRoot(); if (!isolatedRootNode) return; this->toggleIsolateMode(true); } void KisNodeManager::createNode(const QString & nodeType, bool quiet, KisPaintDeviceSP copyFrom) { KisNodeSP activeNode = this->activeNode(); if (!activeNode) { activeNode = m_d->view->image()->root(); } KIS_ASSERT_RECOVER_RETURN(activeNode); if (activeNode->systemLocked()) { return; } // XXX: make factories for this kind of stuff, // with a registry if (nodeType == "KisPaintLayer") { m_d->layerManager.addLayer(activeNode); } else if (nodeType == "KisGroupLayer") { m_d->layerManager.addGroupLayer(activeNode); } else if (nodeType == "KisAdjustmentLayer") { m_d->layerManager.addAdjustmentLayer(activeNode); } else if (nodeType == "KisGeneratorLayer") { m_d->layerManager.addGeneratorLayer(activeNode); } else if (nodeType == "KisShapeLayer") { m_d->layerManager.addShapeLayer(activeNode); } else if (nodeType == "KisCloneLayer") { m_d->layerManager.addCloneLayer(activeNode); } else if (nodeType == "KisTransparencyMask") { m_d->maskManager.createTransparencyMask(activeNode, copyFrom, false); } else if (nodeType == "KisFilterMask") { m_d->maskManager.createFilterMask(activeNode, copyFrom, quiet, false); } else if (nodeType == "KisColorizeMask") { m_d->maskManager.createColorizeMask(activeNode); } else if (nodeType == "KisTransformMask") { m_d->maskManager.createTransformMask(activeNode); } else if (nodeType == "KisSelectionMask") { m_d->maskManager.createSelectionMask(activeNode, copyFrom, false); } else if (nodeType == "KisFileLayer") { m_d->layerManager.addFileLayer(activeNode); } } +void KisNodeManager::createFromVisible() +{ + KisLayerUtils::newLayerFromVisible(m_d->view->image(), m_d->view->image()->root()->lastChild()); +} + KisLayerSP KisNodeManager::createPaintLayer() { KisNodeSP activeNode = this->activeNode(); if (!activeNode) { activeNode = m_d->view->image()->root(); } return m_d->layerManager.addLayer(activeNode); } void KisNodeManager::convertNode(const QString &nodeType) { KisNodeSP activeNode = this->activeNode(); if (!activeNode) return; if (nodeType == "KisPaintLayer") { m_d->layerManager.convertNodeToPaintLayer(activeNode); } else if (nodeType == "KisSelectionMask" || nodeType == "KisFilterMask" || nodeType == "KisTransparencyMask") { KisPaintDeviceSP copyFrom = activeNode->paintDevice() ? activeNode->paintDevice() : activeNode->projection(); m_d->commandsAdapter.beginMacro(kundo2_i18n("Convert to a Selection Mask")); if (nodeType == "KisSelectionMask") { m_d->maskManager.createSelectionMask(activeNode, copyFrom, true); } else if (nodeType == "KisFilterMask") { m_d->maskManager.createFilterMask(activeNode, copyFrom, false, true); } else if (nodeType == "KisTransparencyMask") { m_d->maskManager.createTransparencyMask(activeNode, copyFrom, true); } m_d->commandsAdapter.removeNode(activeNode); m_d->commandsAdapter.endMacro(); } else { warnKrita << "Unsupported node conversion type:" << nodeType; } } void KisNodeManager::slotSomethingActivatedNodeImpl(KisNodeSP node) { KIS_ASSERT_RECOVER_RETURN(node != activeNode()); if (m_d->activateNodeImpl(node)) { emit sigUiNeedChangeActiveNode(node); emit sigNodeActivated(node); nodesUpdated(); if (node) { bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked(); if (toggled) { m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine); } } } } void KisNodeManager::slotNonUiActivatedNode(KisNodeSP node) { if (node == activeNode()) return; slotSomethingActivatedNodeImpl(node); if (node) { bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked(); if (toggled) { m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine); } } } void KisNodeManager::slotUiActivatedNode(KisNodeSP node) { if (node == activeNode()) return; slotSomethingActivatedNodeImpl(node); if (node) { QStringList vectorTools = QStringList() << "InteractionTool" << "KarbonPatternTool" << "KarbonGradientTool" << "KarbonCalligraphyTool" << "CreateShapesTool" << "PathTool"; QStringList pixelTools = QStringList() << "KritaShape/KisToolBrush" << "KritaShape/KisToolDyna" << "KritaShape/KisToolMultiBrush" << "KritaFill/KisToolFill" << "KritaFill/KisToolGradient"; if (node->inherits("KisShapeLayer")) { if (pixelTools.contains(KoToolManager::instance()->activeToolId())) { KoToolManager::instance()->switchToolRequested("InteractionTool"); } } else { if (vectorTools.contains(KoToolManager::instance()->activeToolId())) { KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush"); } } } } void KisNodeManager::nodesUpdated() { KisNodeSP node = activeNode(); if (!node) return; m_d->layerManager.layersUpdated(); m_d->maskManager.masksUpdated(); m_d->view->updateGUI(); m_d->view->selectionManager()->selectionChanged(); } KisPaintDeviceSP KisNodeManager::activePaintDevice() { return m_d->maskManager.activeMask() ? m_d->maskManager.activeDevice() : m_d->layerManager.activeDevice(); } void KisNodeManager::nodeProperties(KisNodeSP node) { if (selectedNodes().size() > 1 || node->inherits("KisLayer")) { m_d->layerManager.layerProperties(); } else if (node->inherits("KisMask")) { m_d->maskManager.maskProperties(); } } qint32 KisNodeManager::convertOpacityToInt(qreal opacity) { /** * Scales opacity from the range 0...100 * to the integer range 0...255 */ return qMin(255, int(opacity * 2.55 + 0.5)); } void KisNodeManager::setNodeOpacity(KisNodeSP node, qint32 opacity, bool finalChange) { if (!node) return; if (node->opacity() == opacity) return; if (!finalChange) { node->setOpacity(opacity); node->setDirty(); } else { m_d->commandsAdapter.setOpacity(node, opacity); } } void KisNodeManager::setNodeCompositeOp(KisNodeSP node, const KoCompositeOp* compositeOp) { if (!node) return; if (node->compositeOp() == compositeOp) return; m_d->commandsAdapter.setCompositeOp(node, compositeOp); } void KisNodeManager::slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes) { if (activeNode) { slotNonUiActivatedNode(activeNode); } if (!selectedNodes.isEmpty()) { slotSetSelectedNodes(selectedNodes); } } void KisNodeManager::slotSetSelectedNodes(const KisNodeList &nodes) { m_d->selectedNodes = nodes; emit sigUiNeedChangeSelectedNodes(nodes); } KisNodeList KisNodeManager::selectedNodes() { return m_d->selectedNodes; } KisNodeSelectionAdapter* KisNodeManager::nodeSelectionAdapter() const { return m_d->nodeSelectionAdapter.data(); } KisNodeInsertionAdapter* KisNodeManager::nodeInsertionAdapter() const { return m_d->nodeInsertionAdapter.data(); } void KisNodeManager::nodeOpacityChanged(qreal opacity, bool finalChange) { KisNodeSP node = activeNode(); setNodeOpacity(node, convertOpacityToInt(opacity), finalChange); } void KisNodeManager::nodeCompositeOpChanged(const KoCompositeOp* op) { KisNodeSP node = activeNode(); setNodeCompositeOp(node, op); } void KisNodeManager::duplicateActiveNode() { KUndo2MagicString actionName = kundo2_i18n("Duplicate Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->duplicateNode(selectedNodes()); } KisNodeJugglerCompressed* KisNodeManager::Private::lazyGetJuggler(const KUndo2MagicString &actionName) { KisImageWSP image = view->image(); if (!nodeJuggler || (nodeJuggler && !nodeJuggler->canMergeAction(actionName))) { nodeJuggler = new KisNodeJugglerCompressed(actionName, image, q, 750); nodeJuggler->setAutoDelete(true); } return nodeJuggler; } void KisNodeManager::raiseNode() { KUndo2MagicString actionName = kundo2_i18n("Raise Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->raiseNode(selectedNodes()); } void KisNodeManager::lowerNode() { KUndo2MagicString actionName = kundo2_i18n("Lower Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->lowerNode(selectedNodes()); } void KisNodeManager::removeSingleNode(KisNodeSP node) { if (!node || !node->parent()) { return; } KisNodeList nodes; nodes << node; removeSelectedNodes(nodes); } void KisNodeManager::removeSelectedNodes(KisNodeList nodes) { KUndo2MagicString actionName = kundo2_i18n("Remove Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->removeNode(nodes); } void KisNodeManager::removeNode() { removeSelectedNodes(selectedNodes()); } void KisNodeManager::mirrorNodeX() { KisNodeSP node = activeNode(); KUndo2MagicString commandName; if (node->inherits("KisLayer")) { commandName = kundo2_i18n("Mirror Layer X"); } else if (node->inherits("KisMask")) { commandName = kundo2_i18n("Mirror Mask X"); } mirrorNode(node, commandName, Qt::Horizontal); } void KisNodeManager::mirrorNodeY() { KisNodeSP node = activeNode(); KUndo2MagicString commandName; if (node->inherits("KisLayer")) { commandName = kundo2_i18n("Mirror Layer Y"); } else if (node->inherits("KisMask")) { commandName = kundo2_i18n("Mirror Mask Y"); } mirrorNode(node, commandName, Qt::Vertical); } inline bool checkForGlobalSelection(KisNodeSP node) { return dynamic_cast(node.data()) && node->parent() && !node->parent()->parent(); } void KisNodeManager::activateNextNode() { KisNodeSP activeNode = this->activeNode(); if (!activeNode) return; KisNodeSP node = activeNode->nextSibling(); while (node && node->childCount() > 0 && node->isEditable()) { node = node->firstChild(); } if (!node && activeNode->parent() && activeNode->parent()->parent()) { node = activeNode->parent(); } while(node && checkForGlobalSelection(node)) { node = node->nextSibling(); } if (node) { slotNonUiActivatedNode(node); } } void KisNodeManager::activatePreviousNode() { KisNodeSP activeNode = this->activeNode(); if (!activeNode) return; KisNodeSP node; if (activeNode->childCount() > 0 && activeNode->isEditable()) { node = activeNode->lastChild(); } else { node = activeNode->prevSibling(); } while (!node && activeNode->parent()) { node = activeNode->parent()->prevSibling(); activeNode = activeNode->parent(); } while(node && checkForGlobalSelection(node)) { node = node->prevSibling(); } if (node) { slotNonUiActivatedNode(node); } } void KisNodeManager::mergeLayer() { m_d->layerManager.mergeLayer(); } void KisNodeManager::rotate(double radians) { // XXX: implement rotation for masks as well m_d->layerManager.rotateLayer(radians); } void KisNodeManager::rotate180() { rotate(M_PI); } void KisNodeManager::rotateLeft90() { rotate(-M_PI / 2); } void KisNodeManager::rotateRight90() { rotate(M_PI / 2); } void KisNodeManager::shear(double angleX, double angleY) { // XXX: implement shear for masks as well m_d->layerManager.shearLayer(angleX, angleY); } void KisNodeManager::scale(double sx, double sy, KisFilterStrategy *filterStrategy) { KisNodeSP node = activeNode(); KIS_ASSERT_RECOVER_RETURN(node); m_d->view->image()->scaleNode(node, sx, sy, filterStrategy); nodesUpdated(); } void KisNodeManager::mirrorNode(KisNodeSP node, const KUndo2MagicString& actionName, Qt::Orientation orientation) { KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(m_d->view->image(), node, KisProcessingApplicator::RECURSIVE, emitSignals, actionName); KisProcessingVisitorSP visitor = new KisMirrorProcessingVisitor(m_d->view->image()->bounds(), orientation); applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); nodesUpdated(); } void KisNodeManager::Private::saveDeviceAsImage(KisPaintDeviceSP device, const QString &defaultName, const QRect &bounds, qreal xRes, qreal yRes, quint8 opacity) { KoFileDialog dialog(view->mainWindow(), KoFileDialog::SaveFile, "savenodeasimage"); dialog.setCaption(i18n("Export \"%1\"", defaultName)); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Export)); QString filename = dialog.filename(); if (filename.isEmpty()) return; QUrl url = QUrl::fromLocalFile(filename); if (url.isEmpty()) return; QString mimefilter = KisMimeDatabase::mimeTypeForFile(filename);; QScopedPointer d(KisPart::instance()->createDocument()); d->prepareForImport(); KisImageSP dst = new KisImage(d->createUndoStore(), bounds.width(), bounds.height(), device->compositionSourceColorSpace(), defaultName); dst->setResolution(xRes, yRes); d->setCurrentImage(dst); KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", opacity); paintLayer->paintDevice()->makeCloneFrom(device, bounds); dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0)); dst->initialRefreshGraph(); d->setOutputMimeType(mimefilter.toLatin1()); d->exportDocument(url); } void KisNodeManager::saveNodeAsImage() { KisNodeSP node = activeNode(); if (!node) { warnKrita << "BUG: Save Node As Image was called without any node selected"; return; } KisImageWSP image = m_d->view->image(); QRect saveRect = image->bounds() | node->exactBounds(); KisPaintDeviceSP device = node->paintDevice(); if (!device) { device = node->projection(); } m_d->saveDeviceAsImage(device, node->name(), saveRect, image->xRes(), image->yRes(), node->opacity()); } void KisNodeManager::slotSplitAlphaIntoMask() { KisNodeSP node = activeNode(); // guaranteed by KisActionManager KIS_ASSERT_RECOVER_RETURN(node->hasEditablePaintDevice()); KisPaintDeviceSP srcDevice = node->paintDevice(); const KoColorSpace *srcCS = srcDevice->colorSpace(); const QRect processRect = srcDevice->exactBounds() | srcDevice->defaultBounds()->bounds(); KisPaintDeviceSP selectionDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); m_d->commandsAdapter.beginMacro(kundo2_i18n("Split Alpha into a Mask")); KisTransaction transaction(kundo2_noi18n("__split_alpha_channel__"), srcDevice); KisSequentialIterator srcIt(srcDevice, processRect); KisSequentialIterator dstIt(selectionDevice, processRect); do { quint8 *srcPtr = srcIt.rawData(); quint8 *alpha8Ptr = dstIt.rawData(); *alpha8Ptr = srcCS->opacityU8(srcPtr); srcCS->setOpacity(srcPtr, OPACITY_OPAQUE_U8, 1); } while (srcIt.nextPixel() && dstIt.nextPixel()); m_d->commandsAdapter.addExtraCommand(transaction.endAndTake()); createNode("KisTransparencyMask", false, selectionDevice); m_d->commandsAdapter.endMacro(); } void KisNodeManager::Private::mergeTransparencyMaskAsAlpha(bool writeToLayers) { KisNodeSP node = q->activeNode(); KisNodeSP parentNode = node->parent(); // guaranteed by KisActionManager KIS_ASSERT_RECOVER_RETURN(node->inherits("KisTransparencyMask")); if (writeToLayers && !parentNode->hasEditablePaintDevice()) { QMessageBox::information(view->mainWindow(), i18nc("@title:window", "Layer %1 is not editable").arg(parentNode->name()), i18n("Cannot write alpha channel of " "the parent layer \"%1\".\n" "The operation will be cancelled.").arg(parentNode->name())); return; } KisPaintDeviceSP dstDevice; if (writeToLayers) { KIS_ASSERT_RECOVER_RETURN(parentNode->paintDevice()); dstDevice = parentNode->paintDevice(); } else { KisPaintDeviceSP copyDevice = parentNode->paintDevice(); if (!copyDevice) { copyDevice = parentNode->original(); } dstDevice = new KisPaintDevice(*copyDevice); } const KoColorSpace *dstCS = dstDevice->colorSpace(); KisPaintDeviceSP selectionDevice = node->paintDevice(); KIS_ASSERT_RECOVER_RETURN(selectionDevice->colorSpace()->pixelSize() == 1); const QRect processRect = selectionDevice->exactBounds() | dstDevice->exactBounds() | selectionDevice->defaultBounds()->bounds(); QScopedPointer transaction; if (writeToLayers) { commandsAdapter.beginMacro(kundo2_i18n("Write Alpha into a Layer")); transaction.reset(new KisTransaction(kundo2_noi18n("__write_alpha_channel__"), dstDevice)); } KisSequentialIterator srcIt(selectionDevice, processRect); KisSequentialIterator dstIt(dstDevice, processRect); do { quint8 *alpha8Ptr = srcIt.rawData(); quint8 *dstPtr = dstIt.rawData(); dstCS->setOpacity(dstPtr, *alpha8Ptr, 1); } while (srcIt.nextPixel() && dstIt.nextPixel()); if (writeToLayers) { commandsAdapter.addExtraCommand(transaction->endAndTake()); commandsAdapter.removeNode(node); commandsAdapter.endMacro(); } else { KisImageWSP image = view->image(); QRect saveRect = image->bounds(); saveDeviceAsImage(dstDevice, parentNode->name(), saveRect, image->xRes(), image->yRes(), OPACITY_OPAQUE_U8); } } void KisNodeManager::slotSplitAlphaWrite() { m_d->mergeTransparencyMaskAsAlpha(true); } void KisNodeManager::slotSplitAlphaSaveMerged() { m_d->mergeTransparencyMaskAsAlpha(false); } void KisNodeManager::cutLayersToClipboard() { KisNodeList nodes = this->selectedNodes(); KisNodeSP root = m_d->view->image()->root(); if (nodes.isEmpty()) return; KisClipboard::instance()->setLayers(nodes, root, false); KUndo2MagicString actionName = kundo2_i18n("Cut Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->removeNode(nodes); } void KisNodeManager::copyLayersToClipboard() { KisNodeList nodes = this->selectedNodes(); KisNodeSP root = m_d->view->image()->root(); KisClipboard::instance()->setLayers(nodes, root, true); } void KisNodeManager::pasteLayersFromClipboard() { const QMimeData *data = KisClipboard::instance()->layersMimeData(); if (!data) return; KisNodeSP activeNode = this->activeNode(); KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(shapeController); KisDummiesFacadeBase *dummiesFacade = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(dummiesFacade); const bool copyNode = false; KisImageSP image = m_d->view->image(); KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode); KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0; KisMimeData::insertMimeLayers(data, image, shapeController, parentDummy, aboveThisDummy, copyNode, nodeInsertionAdapter()); } void KisNodeManager::createQuickGroupImpl(KisNodeJugglerCompressed *juggler, const QString &overrideGroupName, KisNodeSP *newGroup, KisNodeSP *newLastChild) { KisNodeSP active = activeNode(); if (!active) return; KisImageSP image = m_d->view->image(); QString groupName = !overrideGroupName.isEmpty() ? overrideGroupName : image->nextLayerName(); KisGroupLayerSP group = new KisGroupLayer(image.data(), groupName, OPACITY_OPAQUE_U8); KisNodeList nodes1; nodes1 << group; KisNodeList nodes2; nodes2 = KisLayerUtils::sortMergableNodes(image->root(), selectedNodes()); KisLayerUtils::filterMergableNodes(nodes2); if (KisLayerUtils::checkIsChildOf(active, nodes2)) { active = nodes2.first(); } KisNodeSP parent = active->parent(); KisNodeSP aboveThis = active; juggler->addNode(nodes1, parent, aboveThis); juggler->moveNode(nodes2, group, 0); *newGroup = group; *newLastChild = nodes2.last(); } void KisNodeManager::createQuickGroup() { KUndo2MagicString actionName = kundo2_i18n("Quick Group"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); KisNodeSP parent; KisNodeSP above; createQuickGroupImpl(juggler, "", &parent, &above); } void KisNodeManager::createQuickClippingGroup() { KUndo2MagicString actionName = kundo2_i18n("Quick Clipping Group"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); KisNodeSP parent; KisNodeSP above; KisImageSP image = m_d->view->image(); createQuickGroupImpl(juggler, image->nextLayerName(i18nc("default name for a clipping group layer", "Clipping Group")), &parent, &above); KisPaintLayerSP maskLayer = new KisPaintLayer(image.data(), i18nc("default name for quick clip group mask layer", "Mask Layer"), OPACITY_OPAQUE_U8, image->colorSpace()); maskLayer->disableAlphaChannel(true); juggler->addNode(KisNodeList() << maskLayer, parent, above); } void KisNodeManager::quickUngroup() { KisNodeSP active = activeNode(); if (!active) return; KisNodeSP parent = active->parent(); KisNodeSP aboveThis = active; KUndo2MagicString actionName = kundo2_i18n("Quick Ungroup"); if (parent && dynamic_cast(active.data())) { KisNodeList nodes = active->childNodes(QStringList(), KoProperties()); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->moveNode(nodes, parent, active); juggler->removeNode(KisNodeList() << active); } else if (parent && parent->parent()) { KisNodeSP grandParent = parent->parent(); KisNodeList allChildNodes = parent->childNodes(QStringList(), KoProperties()); KisNodeList allSelectedNodes = selectedNodes(); const bool removeParent = KritaUtils::compareListsUnordered(allChildNodes, allSelectedNodes); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->moveNode(allSelectedNodes, grandParent, parent); if (removeParent) { juggler->removeNode(KisNodeList() << parent); } } } void KisNodeManager::selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps) { KisImageSP image = m_d->view->image(); KisNodeList nodes = KisLayerUtils::findNodesWithProps(image->root(), props, true); KisNodeList selectedNodes = this->selectedNodes(); if (KritaUtils::compareListsUnordered(nodes, selectedNodes)) { nodes = KisLayerUtils::findNodesWithProps(image->root(), invertedProps, true); } if (!nodes.isEmpty()) { slotImageRequestNodeReselection(nodes.last(), nodes); } } void KisNodeManager::selectAllNodes() { KoProperties props; selectLayersImpl(props, props); } void KisNodeManager::selectVisibleNodes() { KoProperties props; props.setProperty("visible", true); KoProperties invertedProps; invertedProps.setProperty("visible", false); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectLockedNodes() { KoProperties props; props.setProperty("locked", true); KoProperties invertedProps; invertedProps.setProperty("locked", false); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectInvisibleNodes() { KoProperties props; props.setProperty("visible", false); KoProperties invertedProps; invertedProps.setProperty("visible", true); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectUnlockedNodes() { KoProperties props; props.setProperty("locked", false); KoProperties invertedProps; invertedProps.setProperty("locked", true); selectLayersImpl(props, invertedProps); } diff --git a/libs/ui/kis_node_manager.h b/libs/ui/kis_node_manager.h index 5efb4e06ef..490c248b0f 100644 --- a/libs/ui/kis_node_manager.h +++ b/libs/ui/kis_node_manager.h @@ -1,251 +1,255 @@ /* * Copyright (C) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_NODE_MANAGER #define KIS_NODE_MANAGER #include #include #include "kis_types.h" #include class KActionCollection; class KoCompositeOp; class KoColorSpace; class KUndo2MagicString; class KisFilterStrategy; class KisViewManager; class KisActionManager; class KisView; class KisNodeSelectionAdapter; class KisNodeInsertionAdapter; class KisNodeJugglerCompressed; class KoProperties; /** * The node manager passes requests for new layers or masks on to the mask and layer * managers. */ class KRITAUI_EXPORT KisNodeManager : public QObject { Q_OBJECT public: KisNodeManager(KisViewManager * view); ~KisNodeManager(); void setView(QPointerimageView); Q_SIGNALS: /// emitted whenever a node is selected. void sigNodeActivated(KisNodeSP node); /// emitted whenever a different layer is selected. void sigLayerActivated(KisLayerSP layer); /// for the layer box: this sets the current node in the layerbox /// without telling the node manager that the node is activated, /// preventing loops (I think...) void sigUiNeedChangeActiveNode(KisNodeSP node); void sigUiNeedChangeSelectedNodes(const KisNodeList &nodes); public: void setup(KActionCollection * collection, KisActionManager* actionManager); void updateGUI(); /// Convenience function to get the active layer or mask KisNodeSP activeNode(); /// convenience function to get the active layer. If a mask is /// active, it's parent layer is the active layer. KisLayerSP activeLayer(); /// Get the paint device the user wants to paint on now KisPaintDeviceSP activePaintDevice(); /** * @return the active color space used for composition, meaning the color space * of the active mask, or the color space of the parent of the active layer */ const KoColorSpace* activeColorSpace(); /** * Sets opacity for the node in a universal way (masks/layers) */ void setNodeOpacity(KisNodeSP node, qint32 opacity, bool finalChange); /** * Sets compositeOp for the node in a universal way (masks/layers) */ void setNodeCompositeOp(KisNodeSP node, const KoCompositeOp* compositeOp); KisNodeList selectedNodes(); KisNodeSelectionAdapter* nodeSelectionAdapter() const; KisNodeInsertionAdapter* nodeInsertionAdapter() const; public Q_SLOTS: /** * Explicitly activates \p node * The UI will be noticed that active node has been changed. * Both sigNodeActivated and sigUiNeedChangeActiveNode are emitted. * * WARNING: normally you needn't call this method manually. It is * automatically called when a node is added to the graph. If you * have some special cases when you need to activate a node, consider * adding them to KisDummiesFacadeBase instead. Calling this method * directly should be the last resort. * * \see slotUiActivatedNode for comparison */ void slotNonUiActivatedNode(KisNodeSP node); /** * Activates \p node. * All non-ui listeners are notified with sigNodeActivated, * sigUiNeedChangeActiveNode is *not* emitted. * * \see activateNode */ void slotUiActivatedNode(KisNodeSP node); /** * Adds a list of nodes without searching appropriate position for * it. You *must* ensure that the nodes are allowed to be added * to the parent, otherwise you'll get an assert. */ void addNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis); /** * Moves a list of nodes without searching appropriate position * for it. You *must* ensure that the nodes are allowed to be * added to the parent, otherwise you'll get an assert. */ void moveNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis); /** * Copies a list of nodes without searching appropriate position * for it. You *must* ensure that the nodes are allowed to be * added to the parent, otherwise you'll get an assert. */ void copyNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis); + /** + * Create new layer from actually visible + */ + void createFromVisible(); void toggleIsolateActiveNode(); void toggleIsolateMode(bool checked); void slotUpdateIsolateModeAction(); void slotTryFinishIsolatedMode(); void moveNodeAt(KisNodeSP node, KisNodeSP parent, int index); void createNode(const QString& nodeType, bool quiet = false, KisPaintDeviceSP copyFrom = 0); void convertNode(const QString &nodeType); void nodesUpdated(); void nodeProperties(KisNodeSP node); void nodeOpacityChanged(qreal opacity, bool finalChange); void nodeCompositeOpChanged(const KoCompositeOp* op); void duplicateActiveNode(); void removeNode(); void mirrorNodeX(); void mirrorNodeY(); void mirrorNode(KisNodeSP node, const KUndo2MagicString& commandName, Qt::Orientation orientation); void activateNextNode(); void activatePreviousNode(); /** * move the active node up the nodestack. */ void raiseNode(); /** * move the active node down the nodestack */ void lowerNode(); void rotate(double radians); void rotate180(); void rotateLeft90(); void rotateRight90(); void saveNodeAsImage(); // merges the active layer with the layer below it. void mergeLayer(); void slotSplitAlphaIntoMask(); void slotSplitAlphaWrite(); void slotSplitAlphaSaveMerged(); /** * @brief slotSetSelectedNodes set the list of nodes selected in the layerbox. Selected nodes are not necessarily active nodes. * @param nodes the selected nodes */ void slotSetSelectedNodes(const KisNodeList &nodes); void slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes); void cutLayersToClipboard(); void copyLayersToClipboard(); void pasteLayersFromClipboard(); void createQuickGroup(); void createQuickClippingGroup(); void quickUngroup(); void selectAllNodes(); void selectVisibleNodes(); void selectLockedNodes(); void selectInvisibleNodes(); void selectUnlockedNodes(); public: void shear(double angleX, double angleY); void scale(double sx, double sy, KisFilterStrategy *filterStrategy); void removeSingleNode(KisNodeSP node); KisLayerSP createPaintLayer(); private: /** * Scales opacity from the range 0...1 * to the integer range 0...255 */ qint32 convertOpacityToInt(qreal opacity); void removeSelectedNodes(KisNodeList selectedNodes); void slotSomethingActivatedNodeImpl(KisNodeSP node); void createQuickGroupImpl(KisNodeJugglerCompressed *juggler, const QString &overrideGroupName, KisNodeSP *newGroup, KisNodeSP *newLastChild); void selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps); struct Private; Private * const m_d; }; #endif diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc index de1756d1f2..945688abbb 100644 --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -1,1267 +1,1268 @@ /* * 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 "kis_canvas2.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "kis_resource_server_provider.h" #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "widgets/kis_popup_button.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) , m_presetUpdateCompressor(200, KisSignalCompressor::FIRST_ACTIVE) { 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")); 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 KisPopupButton(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); // pen pressure m_disablePressureButton = new KisHighlightedToolButton(this); m_disablePressureButton->setFixedSize(iconsize, iconsize); m_disablePressureButton->setCheckable(true); m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure"); m_disablePressureButton->setDefaultAction(m_disablePressureAction); // horizontal and vertical mirror toolbar buttons // mirror tool options for the X Mirror QMenu *toolbarMenuXMirror = new QMenu(); KisAction* hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations"); hideCanvasDecorationsX->setCheckable(true); hideCanvasDecorationsX->setText(i18n("Hide Mirror Line")); toolbarMenuXMirror->addAction(hideCanvasDecorationsX); KisAction* lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock"); lockActionX->setText(i18n("Lock")); lockActionX->setCheckable(true); toolbarMenuXMirror->addAction(lockActionX); KisAction* moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter"); moveToCenterActionX->setCheckable(false); moveToCenterActionX->setText(i18n("Move to Canvas Center")); toolbarMenuXMirror->addAction(moveToCenterActionX); // mirror tool options for the Y Mirror QMenu *toolbarMenuYMirror = new QMenu(); KisAction* hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations"); hideCanvasDecorationsY->setCheckable(true); hideCanvasDecorationsY->setText(i18n("Hide Mirror Line")); toolbarMenuYMirror->addAction(hideCanvasDecorationsY); KisAction* lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock"); lockActionY->setText(i18n("Lock")); lockActionY->setCheckable(true); toolbarMenuYMirror->addAction(lockActionY); KisAction* moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter"); moveToCenterActionY->setCheckable(false); moveToCenterActionY->setText(i18n("Move to Canvas Center")); 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.0, 1.0, 2); slOpacity->setValue(1.0); slOpacity->setSingleStep(0.05); slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width())); slOpacity->setFixedHeight(iconsize); slOpacity->setBlockUpdateSignalOnDrag(true); slFlow->setRange(0.0, 1.0, 2); slFlow->setValue(1.0); slFlow->setSingleStep(0.05); slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width())); slFlow->setFixedHeight(iconsize); slFlow->setBlockUpdateSignalOnDrag(true); slSize->setRange(0, 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); QWidget* compositePressure = new QWidget(this); QHBoxLayout* pressureLayout = new QHBoxLayout(compositePressure); pressureLayout->addWidget(m_disablePressureButton); pressureLayout->setSpacing(4); pressureLayout->setContentsMargins(0, 0, 0, 0); action = new QWidgetAction(this); view->actionCollection()->addAction("pressure_action", action); action->setText(i18n("Pressure usage (small button)")); action->setDefaultWidget(compositePressure); 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_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider); m_brushEditorPopupButton->setPopupWidget(m_presetsPopup); m_presetsPopup->switchDetached(false); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons())); m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup(); m_presetsChooserPopup->setFixedSize(500, 600); 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(savePresetClicked()) , SLOT(slotSaveActivePreset())); 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_presetsChooserPopup, SIGNAL(resourceSelected(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))); 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())); m_favoriteResourceManager = new KisFavoriteResourceManager(this); 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()); } KisPaintopBox::~KisPaintopBox() { KisConfig cfg; QMapIterator iter(m_tabletToolMap); while (iter.hasNext()) { iter.next(); 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 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); if (preset) { setCurrentPaintop(preset->paintOp(), 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) { KisPaintOpPreset* preset = dynamic_cast(resource); if (preset) { if (!preset->settings()->isLoadable()) return; setCurrentPaintopAndReload(preset->paintOp(), preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::setCurrentPaintopAndReload(const KoID& paintop, KisPaintOpPresetSP preset) { if (!m_dirtyPresetsEnabled) { KisSignalsBlocker blocker(m_optionWidget); if (!preset->load()) { warnKrita << "failed to load the preset."; } } setCurrentPaintop(paintop, preset); } void KisPaintopBox::setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP preset) { m_presetConnections.clear(); if (m_resourceProvider->currentPreset()) { m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset()); if (m_optionWidget) { m_optionWidget->hide(); } m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = m_resourceProvider->currentPreset(); m_tabletToolMap[m_currTabletToolID].preset = m_resourceProvider->currentPreset(); m_tabletToolMap[m_currTabletToolID].paintOpID = m_resourceProvider->currentPreset()->paintOp(); } preset = (!preset) ? activePreset(paintop) : preset; Q_ASSERT(preset && preset->settings()); 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_presetUpdateCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateOptionsWidget())); - m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfiguration*))); - m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfiguration*)), this, SLOT(slotDropLockedOption(KisPropertiesConfiguration*))); + 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 KisPaintOpFactory* paintOp = KisPaintOpRegistry::instance()->get(paintop.id()); QString pixFilename = KoResourcePaths::findResource("kis_images", paintOp->pixmap()); m_brushEditorPopupButton->setIcon(QIcon(pixFilename)); m_presetsPopup->setCurrentPaintOp(paintop.id()); if (m_presetsPopup->currentPaintOp() != 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"; } // preset -> compressor m_presetConnections.addConnection( preset->updateProxy(), SIGNAL(sigSettingsChanged()), - &m_presetUpdateCompressor, SLOT(start())); + &m_presetUpdateCompressor, SLOT(start())); } void KisPaintopBox::slotUpdateOptionsWidget() { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); KIS_SAFE_ASSERT_RECOVER_RETURN(preset); KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget); KisSignalsBlocker b(m_optionWidget); m_optionWidget->setConfigurationSafe(preset->settings().data()); m_presetsPopup->resourceSelected(preset.data()); m_presetsPopup->updateViewSettings(); } 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; } } } 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); slider->setValue(value); } } void KisPaintopBox::slotSetPaintop(const QString& paintOpId) { if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) { KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name()); setCurrentPaintop(id); } } void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice) { TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice); if (toolData == m_tabletToolMap.end()) { KisConfig cfg; KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(false); KisPaintOpPresetSP preset; if (inputDevice.pointer() == QTabletEvent::Eraser) { preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), "Eraser_circle")); } else { preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), "Basic_tip_default")); } if (!preset) { preset = rserver->resourceByName("Basic_tip_default"); } if (preset) { setCurrentPaintop(preset->paintOp(), preset); } } else { setCurrentPaintop(toolData->paintOpID, toolData->preset); } m_currTabletToolID = TabletToolID(inputDevice); } 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()); } m_presetsChooserPopup->canvasResourceChanged(preset.data(), 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::slotSaveActivePreset() { KisPaintOpPresetSP curPreset = m_resourceProvider->currentPreset(); if (!curPreset) return; m_favoriteResourceManager->setBlockUpdates(true); KisPaintOpPresetSP newPreset = curPreset->clone(); KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QString saveLocation = rServer->saveLocation(); QString presetName = m_presetsPopup->getPresetName(); QString presetFilename = saveLocation + presetName + newPreset->defaultFileExtension(); QStringList tags; KisPaintOpPresetSP resource = rServer->resourceByName(presetName); if (resource) { tags = rServer->assignedTagsList(resource.data()); rServer->removeResourceAndBlacklist(resource); } newPreset->setImage(m_presetsPopup->cutOutOverlay()); newPreset->setFilename(presetFilename); newPreset->setName(presetName); newPreset->setPresetDirty(false); rServer->addResource(newPreset); Q_FOREACH (const QString & tag, tags) { rServer->addTag(newPreset.data(), tag); } // HACK ALERT! the server does not notify the observers // automatically, so we need to call theupdate manually! rServer->tagCategoryMembersChanged(); restoreResource(newPreset.data()); m_favoriteResourceManager->setBlockUpdates(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); } 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 (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 size 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); qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value(); qreal flow = m_sliderChooser[n]->getWidget("flow")->value(); 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); - KisLockedPropertiesProxy *propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings()); + 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()); delete propertiesProxy; } 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 | ENABLE_SIZE | ENABLE_FLOW); slotUpdatePreset(); m_presetsEnabled = true; } else { setWidgetState(DISABLE_PRESETS | DISABLE_SIZE | DISABLE_FLOW); m_presetsEnabled = false; } } else setWidgetState(DISABLE_ALL); } void KisPaintopBox::slotPreviousFavoritePreset() { if (!m_favoriteResourceManager) return; int i = 0; Q_FOREACH (KisPaintOpPresetSP preset, m_favoriteResourceManager->favoritePresetList()) { if (m_resourceProvider->currentPreset() && m_resourceProvider->currentPreset()->name() == preset->name()) { if (i > 0) { m_favoriteResourceManager->slotChangeActivePaintop(i - 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1); } return; } i++; } } void KisPaintopBox::slotNextFavoritePreset() { if (!m_favoriteResourceManager) return; int i = 0; Q_FOREACH (KisPaintOpPresetSP preset, m_favoriteResourceManager->favoritePresetList()) { if (m_resourceProvider->currentPreset()->name() == preset->name()) { if (i < m_favoriteResourceManager->numFavoritePresets() - 1) { m_favoriteResourceManager->slotChangeActivePaintop(i + 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(0); } return; } i++; } } void KisPaintopBox::slotSwitchToPreviousPreset() { if (m_resourceProvider->previousPreset()) { setCurrentPaintop(m_resourceProvider->previousPreset()->paintOp(), m_resourceProvider->previousPreset()); } } 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_disablePressureButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureButton->actions()[0]->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 { m_optionWidget->writeConfigurationSafe(const_cast(m_resourceProvider->currentPreset()->settings().data())); //m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); // TODO!!!!!!!! //m_presetsPopup->updateViewSettings(); } -void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfiguration* p) +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(KisPropertiesConfiguration* p) +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->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_disablePressureButton->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureButton->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/kis_paintop_box.h b/libs/ui/kis_paintop_box.h index 8b71e94fd4..0d27bb1159 100644 --- a/libs/ui/kis_paintop_box.h +++ b/libs/ui/kis_paintop_box.h @@ -1,254 +1,254 @@ /* * kis_paintop_box.h - part of KImageShop/Krayon/Krita * * Copyright (c) 2004-2008 Boudewijn Rempt (boud@valdyas.org) * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_BOX_H_ #define KIS_PAINTOP_BOX_H_ #include #include #include #include #include #include #include #include #include #include #include "kritaui_export.h" #include "kis_signal_auto_connection.h" #include "kis_signal_compressor.h" class QToolButton; class QString; class QHBoxLayout; class KoColorSpace; class KoResource; class KoCanvasController; class KisViewManager; class KisCanvasResourceProvider; class KisPopupButton; class KisToolOptionsPopup; class KisPaintOpPresetsPopup; class KisPaintOpPresetsChooserPopup; class KisPaintOpConfigWidget; class KisCompositeOpComboBox; class KisWidgetChooser; class KisFavoriteResourceManager; class KisAction; /** * This widget presents all paintops that a user can paint with. * Paintops represent real-world tools or the well-known Shoup * computer equivalents that do nothing but change color. * * To incorporate the dirty preset functionality and locked settings * the following slots are added * void slotReloadPreset(); void slotGuiChangedCurrentPreset(); - void slotSaveLockedOptionToPreset(KisPropertiesConfiguration* p); - void slotDropLockedOption(KisPropertiesConfiguration* p); + void slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p); + void slotDropLockedOption(KisPropertiesConfigurationSP p); void slotDirtyPresetToggled(bool); Everytime a value is changed in a preset, the preset is made dirty through the onChange() function. For Locked Settings however, a changed Locked Setting will not cause a preset to become dirty. That is becuase it borrows its values from the KisLockedPropertiesServer. Hence the dirty state of the Preset is kept consistent before and after a writeConfiguration operation in most cases. * XXX: When we have a lot of paintops, replace the listbox * with a table, and for every category a combobox. * * XXX: instead of text, use pretty pictures. */ class KRITAUI_EXPORT KisPaintopBox : public QWidget { Q_OBJECT enum { ENABLE_PRESETS = 0x0001, DISABLE_PRESETS = 0x0002, ENABLE_COMPOSITEOP = 0x0004, DISABLE_COMPOSITEOP = 0x0008, ENABLE_OPACITY = 0x0010, DISABLE_OPACITY = 0x0020, ENABLE_FLOW = 0x0040, DISABLE_FLOW = 0x0080, ENABLE_SIZE = 0x0100, DISABLE_SIZE = 0x0200, ENABLE_ALL = 0x5555, DISABLE_ALL = 0xAAAA }; public: KisPaintopBox(KisViewManager* view, QWidget* parent, const char* name); ~KisPaintopBox(); void restoreResource(KoResource* resource); /** * Update the option widgets to the argument ones, removing the currently set widgets. */ void newOptionWidgets(const QList > & optionWidgetList); KisFavoriteResourceManager *favoriteResourcesManager() { return m_favoriteResourceManager; } public Q_SLOTS: void slotColorSpaceChanged(const KoColorSpace* colorSpace); void slotInputDeviceChanged(const KoInputDevice & inputDevice); void slotCanvasResourceChanged(int key, const QVariant& v); void resourceSelected(KoResource* resource); private: void setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP preset = 0); void setCurrentPaintopAndReload(const KoID& paintop, KisPaintOpPresetSP preset); KisPaintOpPresetSP defaultPreset(const KoID& paintOp); KisPaintOpPresetSP activePreset(const KoID& paintOp); void updateCompositeOp(QString compositeOpID); void setWidgetState(int flags); void setSliderValue(const QString& sliderID, qreal value); void sliderChanged(int n); private Q_SLOTS: void slotSaveActivePreset(); void slotUpdatePreset(); void slotSetupDefaultPreset(); void slotNodeChanged(const KisNodeSP node); void slotToggleEraseMode(bool checked); void slotSetCompositeMode(int index); void slotSetPaintop(const QString& paintOpId); void slotHorizontalMirrorChanged(bool value); void slotVerticalMirrorChanged(bool value); void slotSlider1Changed(); void slotSlider2Changed(); void slotSlider3Changed(); void slotToolChanged(KoCanvasController* canvas, int toolId); void slotPreviousFavoritePreset(); void slotNextFavoritePreset(); void slotSwitchToPreviousPreset(); void slotUnsetEraseMode(); void slotToggleAlphaLockMode(bool); void slotDisablePressureMode(bool); void slotReloadPreset(); void slotGuiChangedCurrentPreset(); - void slotSaveLockedOptionToPreset(KisPropertiesConfiguration* p); - void slotDropLockedOption(KisPropertiesConfiguration* p); + void slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p); + void slotDropLockedOption(KisPropertiesConfigurationSP p); void slotDirtyPresetToggled(bool); void slotEraserBrushSizeToggled(bool); void slotEraserBrushOpacityToggled(bool); void slotUpdateSelectionIcon(); void slotLockXMirrorToggle(bool); void slotLockYMirrorToggle(bool); void slotMoveToCenterMirrorX(); void slotMoveToCenterMirrorY(); void slotHideDecorationMirrorX(bool); void slotHideDecorationMirrorY(bool); void slotUpdateOptionsWidget(); private: KisCanvasResourceProvider* m_resourceProvider; QHBoxLayout* m_layout; QWidget* m_paintopWidget; KisPaintOpConfigWidget* m_optionWidget; KisPopupButton* m_toolOptionsPopupButton; KisPopupButton* m_brushEditorPopupButton; KisPopupButton* m_presetSelectorPopupButton; KisCompositeOpComboBox* m_cmbCompositeOp; QToolButton* m_eraseModeButton; QToolButton* m_alphaLockButton; QToolButton* m_disablePressureButton; QToolButton* m_hMirrorButton; QToolButton* m_vMirrorButton; KisToolOptionsPopup* m_toolOptionsPopup; KisPaintOpPresetsPopup* m_presetsPopup; KisPaintOpPresetsChooserPopup* m_presetsChooserPopup; KisViewManager* m_viewManager; KisPopupButton* m_workspaceWidget; KisWidgetChooser* m_sliderChooser[3]; QMap m_paintopOptionWidgets; KisFavoriteResourceManager* m_favoriteResourceManager; QToolButton* m_reloadButton; KisAction* m_eraseAction; KisAction* m_reloadAction; KisAction* m_disablePressureAction; QString m_currCompositeOpID; KisNodeWSP m_previousNode; KisAction* m_hMirrorAction; KisAction* m_vMirrorAction; struct TabletToolID { TabletToolID(const KoInputDevice& dev) { uniqueID = dev.uniqueTabletId(); // Only the eraser is special, and we don't look at Cursor pointer = QTabletEvent::Pen; if (dev.pointer() == QTabletEvent::Eraser) { pointer = QTabletEvent::Eraser; } } bool operator == (const TabletToolID& id) const { return pointer == id.pointer && uniqueID == id.uniqueID; } bool operator < (const TabletToolID& id) const { if (uniqueID == id.uniqueID) return pointer < id.pointer; return uniqueID < id.uniqueID; } QTabletEvent::PointerType pointer; qint64 uniqueID; }; struct TabletToolData { KoID paintOpID; KisPaintOpPresetSP preset; }; typedef QMap TabletToolMap; typedef QMap PaintOpPresetMap; TabletToolMap m_tabletToolMap; PaintOpPresetMap m_paintOpPresetMap; TabletToolID m_currTabletToolID; bool m_presetsEnabled; bool m_blockUpdate; bool m_dirtyPresetsEnabled; bool m_eraserBrushSizeEnabled; bool m_eraserBrushOpacityEnabled; KisSignalAutoConnectionsStore m_presetConnections; KisSignalCompressor m_presetUpdateCompressor; }; #endif //KIS_PAINTOP_BOX_H_ diff --git a/libs/ui/kis_paintop_option.cpp b/libs/ui/kis_paintop_option.cpp index 3f35b2fca2..b3300bbfbe 100644 --- a/libs/ui/kis_paintop_option.cpp +++ b/libs/ui/kis_paintop_option.cpp @@ -1,131 +1,131 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_paintop_option.h" #include struct KisPaintOpOption::Private { public: bool checked; QString label; KisPaintOpOption::PaintopCategory category; QWidget *configurationPage; bool updatesBlocked; bool isWritingSettings; }; KisPaintOpOption::KisPaintOpOption(PaintopCategory category, bool checked) : m_checkable(true) , m_d(new Private()) { m_d->checked = checked; m_d->category = category; m_d->updatesBlocked = false; m_d->isWritingSettings = false; m_d->configurationPage = 0; } KisPaintOpOption::~KisPaintOpOption() { delete m_d; } void KisPaintOpOption::emitSettingChanged() { KIS_ASSERT_RECOVER_RETURN(!m_d->isWritingSettings); if (!m_d->updatesBlocked) { emit sigSettingChanged(); } } -void KisPaintOpOption::startReadOptionSetting(const KisPropertiesConfiguration* setting) +void KisPaintOpOption::startReadOptionSetting(const KisPropertiesConfigurationSP setting) { m_d->updatesBlocked = true; readOptionSetting(setting); m_d->updatesBlocked = false; } -void KisPaintOpOption::startWriteOptionSetting(KisPropertiesConfiguration* setting) const +void KisPaintOpOption::startWriteOptionSetting(KisPropertiesConfigurationSP setting) const { m_d->isWritingSettings = true; writeOptionSetting(setting); m_d->isWritingSettings = false; } void KisPaintOpOption::lodLimitations(KisPaintopLodLimitations *l) const { Q_UNUSED(l); } KisPaintOpOption::PaintopCategory KisPaintOpOption::category() const { return m_d->category; } bool KisPaintOpOption::isChecked() const { return m_d->checked; } bool KisPaintOpOption::isCheckable() const { return m_checkable; } void KisPaintOpOption::setChecked(bool checked) { m_d->checked = checked; emitSettingChanged(); } void KisPaintOpOption::setImage(KisImageWSP image) { Q_UNUSED(image); } void KisPaintOpOption::setNode(KisNodeWSP node) { Q_UNUSED(node); } void KisPaintOpOption::setConfigurationPage(QWidget * page) { m_d->configurationPage = page; } QWidget* KisPaintOpOption::configurationPage() const { return m_d->configurationPage; } void KisPaintOpOption::setLocked(bool value) { m_locked = value; } bool KisPaintOpOption::isLocked ()const { return m_locked; } diff --git a/libs/ui/kis_paintop_option.h b/libs/ui/kis_paintop_option.h index f098a6812f..3bd4ab2394 100644 --- a/libs/ui/kis_paintop_option.h +++ b/libs/ui/kis_paintop_option.h @@ -1,119 +1,119 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_OPTION_H #define KIS_PAINTOP_OPTION_H #include #include #include #include class QWidget; class QString; class KisPaintopLodLimitations; /** * Base interface for paintop options. A paintop option * can be enabled/disabled, has a configuration page * (for example, a curve), a user-visible name and can * be serialized and deserialized into KisPaintOpPresets * * Options are disabled by default. */ class KRITAUI_EXPORT KisPaintOpOption : public QObject { Q_OBJECT public: enum PaintopCategory { GENERAL, COLOR, TEXTURE, FILTER }; KisPaintOpOption(KisPaintOpOption::PaintopCategory category, bool checked); virtual ~KisPaintOpOption(); KisPaintOpOption::PaintopCategory category() const; virtual bool isCheckable() const; virtual bool isChecked() const; virtual void setChecked(bool checked); void setLocked(bool value); bool isLocked() const; /** * Reimplement this to use the image in the option widget */ virtual void setImage(KisImageWSP image); virtual void setNode(KisNodeWSP node); - void startReadOptionSetting(const KisPropertiesConfiguration* setting); - void startWriteOptionSetting(KisPropertiesConfiguration* setting) const; + void startReadOptionSetting(const KisPropertiesConfigurationSP setting); + void startWriteOptionSetting(KisPropertiesConfigurationSP setting) const; QWidget* configurationPage() const; virtual void lodLimitations(KisPaintopLodLimitations *l) const; protected: void setConfigurationPage(QWidget * page); protected: /** * Re-implement this to save the configuration to the paint configuration. */ - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const { + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const { Q_UNUSED(setting); } /** * Re-implement this to set te widgets with the values in @param setting. */ - virtual void readOptionSetting(const KisPropertiesConfiguration* setting) { + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting) { Q_UNUSED(setting); } protected Q_SLOTS: void emitSettingChanged(); Q_SIGNALS: /** * emit this whenever a setting has changed. It will update the preview */ void sigSettingChanged(); protected: bool m_checkable; bool m_locked; private: struct Private; Private* const m_d; }; #endif diff --git a/libs/ui/kis_paintop_settings_widget.cpp b/libs/ui/kis_paintop_settings_widget.cpp index 73c94398d3..667037fe53 100644 --- a/libs/ui/kis_paintop_settings_widget.cpp +++ b/libs/ui/kis_paintop_settings_widget.cpp @@ -1,236 +1,234 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) Silvio Heinrich , (C) 2011 - * + * * 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_paintop_settings_widget.h" #include "kis_paintop_option.h" #include "kis_paintop_options_model.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct KisPaintOpSettingsWidget::Private { QList paintOpOptions; KisCategorizedListView* optionsList; KisPaintOpOptionListModel* model; QStackedWidget* optionsStack; }; KisPaintOpSettingsWidget::KisPaintOpSettingsWidget(QWidget * parent) : KisPaintOpConfigWidget(parent) , m_d(new Private()) { setObjectName("KisPaintOpPresetsWidget"); m_d->model = new KisPaintOpOptionListModel(this); m_d->optionsList = new KisCategorizedListView(false, this); m_d->optionsList->setModel(m_d->model); m_d->optionsList->setItemDelegate(new KisCategorizedItemDelegate(m_d->optionsList)); m_d->optionsList->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); m_d->optionsList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_d->optionsList->setSizePolicy(policy); m_d->optionsStack = new QStackedWidget(this); policy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_d->optionsStack->setSizePolicy(policy); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(m_d->optionsList); layout->addWidget(m_d->optionsStack); layout->setStretch(0, 0); layout->setStretch(1, 1); m_saveLockedOption = false; connect(m_d->optionsList, SIGNAL(activated(const QModelIndex&)), this, SLOT(changePage(const QModelIndex&))); connect(m_d->optionsList, SIGNAL(clicked(QModelIndex)), this, SLOT(changePage(const QModelIndex&))); connect(m_d->optionsList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(lockProperties(const QModelIndex&))); connect(m_d->optionsList, SIGNAL(rightClickedMenuDropSettingsTriggered()), this, SLOT(slotLockPropertiesDrop())); connect(m_d->optionsList, SIGNAL(rightClickedMenuSaveSettingsTriggered()), this, SLOT(slotLockPropertiesSave())); connect(m_d->optionsList, SIGNAL(sigEntryChecked(QModelIndex)), this, SLOT(slotEntryChecked(QModelIndex))); } KisPaintOpSettingsWidget::~KisPaintOpSettingsWidget() { qDeleteAll(m_d->paintOpOptions); delete m_d; } void KisPaintOpSettingsWidget::addPaintOpOption(KisPaintOpOption *option, const QString &label) { if (!option->configurationPage()) return; m_d->model->addPaintOpOption(option, m_d->optionsStack->count(), label); connect(option, SIGNAL(sigSettingChanged()), SIGNAL(sigConfigurationItemChanged())); m_d->optionsStack->addWidget(option->configurationPage()); m_d->paintOpOptions << option; } -void KisPaintOpSettingsWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisPaintOpSettingsWidget::setConfiguration(const KisPropertiesConfigurationSP config) { Q_ASSERT(!config->getString("paintop").isEmpty()); - KisLockedPropertiesProxy* propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); + KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); int indexcount = 0; Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { option->startReadOptionSetting(propertiesProxy); if (KisLockedPropertiesServer::instance()->propertiesFromLocked()) { option->setLocked(true); } else { option->setLocked(false); } KisLockedPropertiesServer::instance()->setPropertiesFromLocked(false); KisOptionInfo info; info.option = option; info.index = indexcount; m_d->model->categoriesMapper()->itemFromRow(m_d->model->indexOf(info).row())->setLocked(option->isLocked()); m_d->model->categoriesMapper()->itemFromRow(m_d->model->indexOf(info).row())->setLockable(true); m_d->model->signalDataChanged(m_d->model->indexOf(info)); indexcount++; } KisPaintOpConfigWidget::setConfiguration(propertiesProxy); - delete propertiesProxy; } -void KisPaintOpSettingsWidget::writeConfiguration(KisPropertiesConfiguration *config) const +void KisPaintOpSettingsWidget::writeConfiguration(KisPropertiesConfigurationSP config) const { - KisLockedPropertiesProxy* propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); + KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(config); Q_FOREACH (const KisPaintOpOption* option, m_d->paintOpOptions) { option->startWriteOptionSetting(propertiesProxy); } KisPaintOpConfigWidget::writeConfiguration(propertiesProxy); - delete propertiesProxy; } KisPaintopLodLimitations KisPaintOpSettingsWidget::lodLimitations() const { KisPaintopLodLimitations l; Q_FOREACH (const KisPaintOpOption* option, m_d->paintOpOptions) { if (option->isCheckable() && !option->isChecked()) continue; option->lodLimitations(&l); } return l; } void KisPaintOpSettingsWidget::setImage(KisImageWSP image) { Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { option->setImage(image); } } void KisPaintOpSettingsWidget::setNode(KisNodeWSP node) { Q_FOREACH (KisPaintOpOption* option, m_d->paintOpOptions) { option->setNode(node); } } void KisPaintOpSettingsWidget::changePage(const QModelIndex& index) { KisOptionInfo info; QPalette palette; palette.setColor(QPalette::Base, QColor(255,200,200)); palette.setColor(QPalette::Text, Qt::black); if(m_d->model->entryAt(info, index)) { m_d->optionsStack->setCurrentIndex(info.index); } notifyPageChanged(); } void KisPaintOpSettingsWidget::notifyPageChanged() { } void KisPaintOpSettingsWidget::lockProperties(const QModelIndex& index) { KisOptionInfo info; if (m_d->model->entryAt(info, index)) { m_d->optionsList->setCurrentIndex(index); - KisPropertiesConfiguration* p = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP p = new KisPropertiesConfiguration(); info.option->startWriteOptionSetting(p); if (!info.option->isLocked()){ KisLockedPropertiesServer::instance()->addToLockedProperties(p); info.option->setLocked(true); m_d->model->categoriesMapper()->itemFromRow(index.row())->setLocked(true); } else { KisLockedPropertiesServer::instance()->removeFromLockedProperties(p); info.option->setLocked(false); m_d->model->categoriesMapper()->itemFromRow(index.row())->setLocked(false); if (m_saveLockedOption){ emit sigSaveLockedConfig(p); } else { emit sigDropLockedConfig(p); } m_saveLockedOption = false; } m_d->model->signalDataChanged(index); } } void KisPaintOpSettingsWidget::slotLockPropertiesDrop() { m_saveLockedOption = false; lockProperties(m_d->optionsList->currentIndex()); } void KisPaintOpSettingsWidget::slotLockPropertiesSave() { m_saveLockedOption = true; lockProperties(m_d->optionsList->currentIndex()); } void KisPaintOpSettingsWidget::slotEntryChecked(const QModelIndex &index) { Q_UNUSED(index); emit sigConfigurationItemChanged(); } diff --git a/libs/ui/kis_paintop_settings_widget.h b/libs/ui/kis_paintop_settings_widget.h index d9c265cfc6..959b3ec4eb 100644 --- a/libs/ui/kis_paintop_settings_widget.h +++ b/libs/ui/kis_paintop_settings_widget.h @@ -1,80 +1,80 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_SETTINGS_WIDGET_H #define KIS_PAINTOP_SETTINGS_WIDGET_H #include #include class KisPaintOpOption; class KisPropertiesConfiguration; class KisPaintOpConfigWidget; class KisPaintopLodLimitations; /** * A common widget for enabling/disabling and determining * the effect of tablet pressure, tilt and rotation and * other paintop settings. */ class KRITAUI_EXPORT KisPaintOpSettingsWidget : public KisPaintOpConfigWidget { Q_OBJECT public: KisPaintOpSettingsWidget(QWidget * parent = 0); ~KisPaintOpSettingsWidget(); void addPaintOpOption(KisPaintOpOption * option, const QString &label); /// Reimplemented - virtual void setConfiguration(const KisPropertiesConfiguration * config); + virtual void setConfiguration(const KisPropertiesConfigurationSP config); /// Reimplemented - virtual void writeConfiguration(KisPropertiesConfiguration *config) const; + virtual void writeConfiguration(KisPropertiesConfigurationSP config) const; virtual KisPaintopLodLimitations lodLimitations() const; ///Reimplemented, sets image on option widgets virtual void setImage(KisImageWSP image); ///Reimplemented, sets node on option widgets virtual void setNode(KisNodeWSP node); private Q_SLOTS: void changePage(const QModelIndex&); void lockProperties(const QModelIndex& index); void slotLockPropertiesDrop(); void slotLockPropertiesSave(); void slotEntryChecked(const QModelIndex &index); protected: virtual void notifyPageChanged(); private: struct Private; Private* const m_d; bool m_saveLockedOption; }; #endif diff --git a/libs/ui/kis_selection_manager.cc b/libs/ui/kis_selection_manager.cc index 19a6b73f24..8057aac8ae 100644 --- a/libs/ui/kis_selection_manager.cc +++ b/libs/ui/kis_selection_manager.cc @@ -1,583 +1,620 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2007 Sven Langkamp * * The outline algorith uses the limn algorithm of fontutils by * Karl Berry and Kathryn Hargreaves * * 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_selection_manager.h" #include #include #include #include #include #include #include #include #include #include #include "KoCanvasController.h" #include "KoChannelInfo.h" #include "KoIntegerMaths.h" #include #include #include #include #include #include #include #include #include #include #include "kis_adjustment_layer.h" #include "kis_node_manager.h" #include "canvas/kis_canvas2.h" #include "kis_config.h" #include "kis_convolution_painter.h" #include "kis_convolution_kernel.h" #include "kis_debug.h" #include "KisDocument.h" #include "kis_fill_painter.h" #include "kis_group_layer.h" #include "kis_layer.h" #include "kis_statusbar.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_painter.h" #include "kis_transaction.h" #include "kis_selection.h" #include "kis_types.h" #include "kis_canvas_resource_provider.h" #include "kis_undo_adapter.h" #include "kis_pixel_selection.h" #include "flake/kis_shape_selection.h" #include "commands/kis_selection_commands.h" #include "kis_selection_mask.h" #include "flake/kis_shape_layer.h" #include "kis_selection_decoration.h" #include "canvas/kis_canvas_decoration.h" #include "kis_node_commands_adapter.h" #include "kis_iterator_ng.h" #include "kis_clipboard.h" #include "KisViewManager.h" #include "kis_selection_filters.h" #include "kis_figure_painting_tool_helper.h" #include "KisView.h" +#include "dialogs/kis_dlg_stroke_selection_properties.h" #include "actions/kis_selection_action_factories.h" #include "kis_action.h" #include "kis_action_manager.h" #include "operations/kis_operation_configuration.h" - +//new +#include "kis_recorded_path_paint_action.h" +#include "kis_node_query_path.h" +#include "kis_tool_shape.h" KisSelectionManager::KisSelectionManager(KisViewManager * view) : m_view(view), m_doc(0), m_imageView(0), m_adapter(new KisNodeCommandsAdapter(view)), m_copy(0), m_copyMerged(0), m_cut(0), m_paste(0), m_pasteNew(0), m_cutToNewLayer(0), m_selectAll(0), m_deselect(0), m_clear(0), m_reselect(0), m_invert(0), m_copyToNewLayer(0), m_fillForegroundColor(0), m_fillBackgroundColor(0), m_fillPattern(0), m_imageResizeToSelection(0), m_selectionDecoration(0) { m_clipboard = KisClipboard::instance(); } KisSelectionManager::~KisSelectionManager() { } void KisSelectionManager::setup(KisActionManager* actionManager) { m_cut = actionManager->createStandardAction(KStandardAction::Cut, this, SLOT(cut())); m_copy = actionManager->createStandardAction(KStandardAction::Copy, this, SLOT(copy())); m_paste = actionManager->createStandardAction(KStandardAction::Paste, this, SLOT(paste())); KisAction *action = actionManager->createAction("copy_sharp"); connect(action, SIGNAL(triggered()), this, SLOT(copySharp())); action = actionManager->createAction("cut_sharp"); connect(action, SIGNAL(triggered()), this, SLOT(cutSharp())); m_pasteNew = actionManager->createAction("paste_new"); connect(m_pasteNew, SIGNAL(triggered()), this, SLOT(pasteNew())); m_pasteAt = actionManager->createAction("paste_at"); connect(m_pasteAt, SIGNAL(triggered()), this, SLOT(pasteAt())); m_copyMerged = actionManager->createAction("copy_merged"); connect(m_copyMerged, SIGNAL(triggered()), this, SLOT(copyMerged())); m_selectAll = actionManager->createAction("select_all"); connect(m_selectAll, SIGNAL(triggered()), this, SLOT(selectAll())); m_deselect = actionManager->createAction("deselect"); connect(m_deselect, SIGNAL(triggered()), this, SLOT(deselect())); m_clear = actionManager->createAction("clear"); connect(m_clear, SIGNAL(triggered()), SLOT(clear())); m_reselect = actionManager->createAction("reselect"); connect(m_reselect, SIGNAL(triggered()), this, SLOT(reselect())); m_invert = actionManager->createAction("invert"); m_invert->setOperationID("invertselection"); actionManager->registerOperation(new KisInvertSelectionOperaton); m_copyToNewLayer = actionManager->createAction("copy_selection_to_new_layer"); connect(m_copyToNewLayer, SIGNAL(triggered()), this, SLOT(copySelectionToNewLayer())); m_cutToNewLayer = actionManager->createAction("cut_selection_to_new_layer"); connect(m_cutToNewLayer, SIGNAL(triggered()), this, SLOT(cutToNewLayer())); m_fillForegroundColor = actionManager->createAction("fill_selection_foreground_color"); connect(m_fillForegroundColor, SIGNAL(triggered()), this, SLOT(fillForegroundColor())); m_fillBackgroundColor = actionManager->createAction("fill_selection_background_color"); connect(m_fillBackgroundColor, SIGNAL(triggered()), this, SLOT(fillBackgroundColor())); m_fillPattern = actionManager->createAction("fill_selection_pattern"); connect(m_fillPattern, SIGNAL(triggered()), this, SLOT(fillPattern())); m_fillForegroundColorOpacity = actionManager->createAction("fill_selection_foreground_color_opacity"); connect(m_fillForegroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillForegroundColorOpacity())); m_fillBackgroundColorOpacity = actionManager->createAction("fill_selection_background_color_opacity"); connect(m_fillBackgroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillBackgroundColorOpacity())); m_fillPatternOpacity = actionManager->createAction("fill_selection_pattern_opacity"); connect(m_fillPatternOpacity, SIGNAL(triggered()), this, SLOT(fillPatternOpacity())); m_strokeShapes = actionManager->createAction("stroke_shapes"); connect(m_strokeShapes, SIGNAL(triggered()), this, SLOT(paintSelectedShapes())); m_toggleDisplaySelection = actionManager->createAction("toggle_display_selection"); connect(m_toggleDisplaySelection, SIGNAL(triggered()), this, SLOT(toggleDisplaySelection())); m_toggleDisplaySelection->setChecked(true); m_imageResizeToSelection = actionManager->createAction("resizeimagetoselection"); connect(m_imageResizeToSelection, SIGNAL(triggered()), this, SLOT(imageResizeToSelection())); action = actionManager->createAction("convert_to_vector_selection"); connect(action, SIGNAL(triggered()), SLOT(convertToVectorSelection())); action = actionManager->createAction("convert_shapes_to_vector_selection"); connect(action, SIGNAL(triggered()), SLOT(convertShapesToVectorSelection())); action = actionManager->createAction("convert_selection_to_shape"); connect(action, SIGNAL(triggered()), SLOT(convertToShape())); m_toggleSelectionOverlayMode = actionManager->createAction("toggle-selection-overlay-mode"); connect(m_toggleSelectionOverlayMode, SIGNAL(triggered()), SLOT(slotToggleSelectionDecoration())); + m_strokeSelected = actionManager->createAction("stroke_selection"); + connect(m_strokeSelected, SIGNAL(triggered()), SLOT(slotStrokeSelection())); + QClipboard *cb = QApplication::clipboard(); connect(cb, SIGNAL(dataChanged()), SLOT(clipboardDataChanged())); } void KisSelectionManager::setView(QPointerimageView) { if (m_imageView && m_imageView->canvasBase()) { disconnect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), this, SLOT(clipboardDataChanged())); KoSelection *selection = m_imageView->canvasBase()->globalShapeManager()->selection(); selection->disconnect(this, SLOT(shapeSelectionChanged())); KisSelectionDecoration *decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data()); if (decoration) { disconnect(SIGNAL(currentSelectionChanged()), decoration); } m_imageView->image()->undoAdapter()->disconnect(this); m_selectionDecoration = 0; } m_imageView = imageView; if (m_imageView) { KoSelection * selection = m_imageView->canvasBase()->globalShapeManager()->selection(); Q_ASSERT(selection); connect(selection, SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged())); KisSelectionDecoration* decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data()); if (!decoration) { decoration = new KisSelectionDecoration(m_imageView); decoration->setVisible(true); m_imageView->canvasBase()->addDecoration(decoration); } m_selectionDecoration = decoration; connect(this, SIGNAL(currentSelectionChanged()), decoration, SLOT(selectionChanged())); connect(m_imageView->image()->undoAdapter(), SIGNAL(selectionChanged()), SLOT(selectionChanged())); connect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), SLOT(clipboardDataChanged())); } } void KisSelectionManager::clipboardDataChanged() { m_view->updateGUI(); } bool KisSelectionManager::havePixelsSelected() { KisSelectionSP activeSelection = m_view->selection(); return activeSelection && !activeSelection->selectedRect().isEmpty(); } bool KisSelectionManager::havePixelsInClipboard() { return m_clipboard->hasClip(); } bool KisSelectionManager::haveShapesSelected() { if (m_view && m_view->canvasBase() && m_view->canvasBase()->shapeManager() && m_view->canvasBase()->shapeManager()->selection()->count()) { return m_view->canvasBase()->shapeManager()->selection()->count() > 0; } return false; } bool KisSelectionManager::haveShapesInClipboard() { KisShapeLayer *shapeLayer = dynamic_cast(m_view->activeLayer().data()); if (shapeLayer) { const QMimeData* data = QApplication::clipboard()->mimeData(); if (data) { QStringList mimeTypes = m_view->canvasBase()->toolProxy()->supportedPasteMimeTypes(); Q_FOREACH (const QString & mimeType, mimeTypes) { if (data->hasFormat(mimeType)) { return true; } } } } return false; } bool KisSelectionManager::havePixelSelectionWithPixels() { KisSelectionSP selection = m_view->selection(); if (selection && selection->hasPixelSelection()) { return !selection->pixelSelection()->selectedRect().isEmpty(); } return false; } void KisSelectionManager::updateGUI() { Q_ASSERT(m_view); Q_ASSERT(m_clipboard); if (!m_view || !m_clipboard) return; bool havePixelsSelected = this->havePixelsSelected(); bool havePixelsInClipboard = this->havePixelsInClipboard(); bool haveShapesSelected = this->haveShapesSelected(); bool haveShapesInClipboard = this->haveShapesInClipboard(); bool haveDevice = m_view->activeDevice(); KisLayerSP activeLayer = m_view->activeLayer(); KisImageWSP image = activeLayer ? activeLayer->image() : 0; bool canReselect = image && image->canReselectGlobalSelection(); bool canDeselect = image && image->globalSelection(); m_clear->setEnabled(haveDevice || havePixelsSelected || haveShapesSelected); m_cut->setEnabled(havePixelsSelected || haveShapesSelected); m_copy->setEnabled(havePixelsSelected || haveShapesSelected); m_paste->setEnabled(havePixelsInClipboard || haveShapesInClipboard); m_pasteAt->setEnabled(havePixelsInClipboard || haveShapesInClipboard); // FIXME: how about pasting shapes? m_pasteNew->setEnabled(havePixelsInClipboard); m_selectAll->setEnabled(true); m_deselect->setEnabled(canDeselect); m_reselect->setEnabled(canReselect); // m_load->setEnabled(true); // m_save->setEnabled(havePixelsSelected); updateStatusBar(); emit signalUpdateGUI(); } void KisSelectionManager::updateStatusBar() { if (m_view && m_view->statusBar()) { m_view->statusBar()->setSelection(m_view->image()); } } void KisSelectionManager::selectionChanged() { m_view->updateGUI(); emit currentSelectionChanged(); } void KisSelectionManager::cut() { KisCutCopyActionFactory factory; factory.run(true, false, m_view); } void KisSelectionManager::copy() { KisCutCopyActionFactory factory; factory.run(false, false, m_view); } void KisSelectionManager::cutSharp() { KisCutCopyActionFactory factory; factory.run(true, true, m_view); } void KisSelectionManager::copySharp() { KisCutCopyActionFactory factory; factory.run(false, true, m_view); } void KisSelectionManager::copyMerged() { KisCopyMergedActionFactory factory; factory.run(m_view); } void KisSelectionManager::paste() { KisPasteActionFactory factory; factory.run(m_view); } void KisSelectionManager::pasteAt() { //XXX } void KisSelectionManager::pasteNew() { KisPasteNewActionFactory factory; factory.run(m_view); } void KisSelectionManager::selectAll() { KisSelectAllActionFactory factory; factory.run(m_view); } void KisSelectionManager::deselect() { KisDeselectActionFactory factory; factory.run(m_view); } void KisSelectionManager::invert() { if(m_invert) m_invert->trigger(); } void KisSelectionManager::reselect() { KisReselectActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertToVectorSelection() { KisSelectionToVectorActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertShapesToVectorSelection() { KisShapesToVectorSelectionActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertToShape() { KisSelectionToShapeActionFactory factory; factory.run(m_view); } void KisSelectionManager::clear() { KisClearActionFactory factory; factory.run(m_view); } void KisSelectionManager::fillForegroundColor() { KisFillActionFactory factory; factory.run("fg", m_view); } void KisSelectionManager::fillBackgroundColor() { KisFillActionFactory factory; factory.run("bg", m_view); } void KisSelectionManager::fillPattern() { KisFillActionFactory factory; factory.run("pattern", m_view); } void KisSelectionManager::fillForegroundColorOpacity() { KisFillActionFactory factory; factory.run("fg_opacity", m_view); } void KisSelectionManager::fillBackgroundColorOpacity() { KisFillActionFactory factory; factory.run("bg_opacity", m_view); } void KisSelectionManager::fillPatternOpacity() { KisFillActionFactory factory; factory.run("pattern_opacity", m_view); } void KisSelectionManager::copySelectionToNewLayer() { copy(); paste(); } void KisSelectionManager::cutToNewLayer() { cut(); paste(); } void KisSelectionManager::toggleDisplaySelection() { KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration); m_selectionDecoration->toggleVisibility(); m_toggleDisplaySelection->blockSignals(true); m_toggleDisplaySelection->setChecked(m_selectionDecoration->visible()); m_toggleDisplaySelection->blockSignals(false); emit displaySelectionChanged(); } bool KisSelectionManager::displaySelection() { return m_toggleDisplaySelection->isChecked(); } void KisSelectionManager::shapeSelectionChanged() { KoShapeManager* shapeManager = m_view->canvasBase()->globalShapeManager(); KoSelection * selection = shapeManager->selection(); QList selectedShapes = selection->selectedShapes(); KoShapeStroke* border = new KoShapeStroke(0, Qt::lightGray); Q_FOREACH (KoShape* shape, shapeManager->shapes()) { if (dynamic_cast(shape->parent())) { if (selectedShapes.contains(shape)) shape->setStroke(border); else shape->setStroke(0); } } m_view->updateGUI(); } void KisSelectionManager::imageResizeToSelection() { KisImageResizeToSelectionActionFactory factory; factory.run(m_view); } void KisSelectionManager::paintSelectedShapes() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = m_view->activeLayer(); if (!layer) return; QList shapes = m_view->canvasBase()->shapeManager()->selection()->selectedShapes(); KisPaintLayerSP paintLayer = new KisPaintLayer(image, i18n("Stroked Shapes"), OPACITY_OPAQUE_U8); KUndo2MagicString actionName = kundo2_i18n("Stroke Shapes"); m_adapter->beginMacro(actionName); m_adapter->addNode(paintLayer.data(), layer->parent().data(), layer.data()); KisFigurePaintingToolHelper helper(actionName, image, paintLayer.data(), m_view->resourceProvider()->resourceManager(), KisPainter::StrokeStyleBrush, KisPainter::FillStyleNone); Q_FOREACH (KoShape* shape, shapes) { QTransform matrix = shape->absoluteTransformation(0) * QTransform::fromScale(image->xRes(), image->yRes()); QPainterPath mapedOutline = matrix.map(shape->outline()); helper.paintPainterPath(mapedOutline); } m_adapter->endMacro(); } void KisSelectionManager::slotToggleSelectionDecoration() { KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration); KisSelectionDecoration::Mode mode = m_selectionDecoration->mode() ? KisSelectionDecoration::Ants : KisSelectionDecoration::Mask; m_selectionDecoration->setMode(mode); emit displaySelectionChanged(); } bool KisSelectionManager::showSelectionAsMask() const { if (m_selectionDecoration) { return m_selectionDecoration->mode() == KisSelectionDecoration::Mask; } return false; } +void KisSelectionManager::slotStrokeSelection() +{ + KisImageWSP image = m_view->image(); + + if (!image ) { + + return; + } + KisNodeSP currentNode = m_view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); + bool isVectorLayer = false; + if (currentNode->inherits("KisShapeLayer")) { + isVectorLayer = true; + } + QPointer dlg = new KisDlgStrokeSelection(image, m_view, isVectorLayer); + + if (dlg->exec() == QDialog::Accepted) { + StrokeSelectionOptions params = dlg->getParams(); + if (params.brushSelected){ + KisStrokeBrushSelectionActionFactory factory; + factory.run(m_view, params); + } + else { + KisStrokeSelectionActionFactory factory; + factory.run(m_view, params); + } + } + delete dlg; + + +} diff --git a/libs/ui/kis_selection_manager.h b/libs/ui/kis_selection_manager.h index e368771b86..9c640baa24 100644 --- a/libs/ui/kis_selection_manager.h +++ b/libs/ui/kis_selection_manager.h @@ -1,176 +1,181 @@ /* * Copyright (c) 2004 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_SELECTION_MANAGER_ #define KIS_SELECTION_MANAGER_ #include #include #include #include #include "KisView.h" #include class KisActionManager; class KisAction; class QAction; class KoViewConverter; class KisDocument; class KisViewManager; class KisClipboard; class KisNodeCommandsAdapter; class KisView; class KisSelectionFilter; class KisSelectionDecoration; /** * The selection manager is responsible selections * and the clipboard. */ class KRITAUI_EXPORT KisSelectionManager : public QObject { Q_OBJECT Q_PROPERTY(bool displaySelection READ displaySelection NOTIFY displaySelectionChanged); Q_PROPERTY(bool havePixelsSelected READ havePixelsSelected NOTIFY currentSelectionChanged); public: KisSelectionManager(KisViewManager * view); virtual ~KisSelectionManager(); void setup(KisActionManager* actionManager); void setView(QPointerimageView); public: /** * This function return if the selection should be displayed */ bool displaySelection(); bool showSelectionAsMask() const; public Q_SLOTS: void updateGUI(); void selectionChanged(); void clipboardDataChanged(); void cut(); void copy(); void cutSharp(); void copySharp(); void copyMerged(); void paste(); void pasteNew(); void pasteAt(); void cutToNewLayer(); void selectAll(); void deselect(); void invert(); void clear(); void fillForegroundColor(); void fillBackgroundColor(); void fillPattern(); void fillForegroundColorOpacity(); void fillBackgroundColorOpacity(); void fillPatternOpacity(); void reselect(); void convertToVectorSelection(); void convertShapesToVectorSelection(); void convertToShape(); void copySelectionToNewLayer(); void toggleDisplaySelection(); void shapeSelectionChanged(); void imageResizeToSelection(); void paintSelectedShapes(); void slotToggleSelectionDecoration(); + void slotStrokeSelection(); + Q_SIGNALS: void currentSelectionChanged(); void signalUpdateGUI(); void displaySelectionChanged(); + void strokeSelected(); public: bool havePixelsSelected(); bool havePixelsInClipboard(); bool haveShapesSelected(); bool haveShapesInClipboard(); /// Checks if the current selection is editabl and has some pixels selected in the pixel selection bool havePixelSelectionWithPixels(); // the following functions are needed for the siox tool // they might be also useful on its own void erode(); void dilate(); void paint(QPainter& gc, const KoViewConverter &converter); private: void fill(const KoColor& color, bool fillWithPattern, const QString& transactionText); void updateStatusBar(); void copyFromDevice(KisPaintDeviceSP device); void applySelectionFilter(KisSelectionFilter *filter); KisViewManager * m_view; KisDocument * m_doc; QPointerm_imageView; KisClipboard * m_clipboard; KisNodeCommandsAdapter* m_adapter; KisAction *m_copy; KisAction *m_copyMerged; KisAction *m_cut; KisAction *m_paste; KisAction *m_pasteAt; KisAction *m_pasteNew; KisAction *m_cutToNewLayer; KisAction *m_selectAll; KisAction *m_deselect; KisAction *m_clear; KisAction *m_reselect; KisAction *m_invert; KisAction *m_copyToNewLayer; KisAction *m_fillForegroundColor; KisAction *m_fillBackgroundColor; KisAction *m_fillPattern; KisAction *m_fillForegroundColorOpacity; KisAction *m_fillBackgroundColorOpacity; KisAction *m_fillPatternOpacity; KisAction *m_imageResizeToSelection; KisAction *m_strokeShapes; KisAction *m_toggleDisplaySelection; KisAction *m_toggleSelectionOverlayMode; + KisAction *m_strokeSelected; + QList m_pluginActions; QPointer m_selectionDecoration; }; #endif // KIS_SELECTION_MANAGER_ diff --git a/libs/ui/kra/kis_kra_load_visitor.cpp b/libs/ui/kra/kis_kra_load_visitor.cpp index 6e4ab299ec..bf093b7ff6 100644 --- a/libs/ui/kra/kis_kra_load_visitor.cpp +++ b/libs/ui/kra/kis_kra_load_visitor.cpp @@ -1,594 +1,594 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 C. Boemann * * 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 "kra/kis_kra_load_visitor.h" #include "kis_kra_tags.h" #include "flake/kis_shape_layer.h" #include #include #include #include #include #include #include // kritaimage #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_transform_mask_params_factory_registry.h" #include #include #include #include #include "kis_shape_selection.h" #include "kis_colorize_dom_utils.h" #include "kis_dom_utils.h" #include "kis_raster_keyframe_channel.h" #include "kis_paint_device_frames_interface.h" using namespace KRA; QString expandEncodedDirectory(const QString& _intern) { QString intern = _intern; QString result; int pos; while ((pos = intern.indexOf('/')) != -1) { if (QChar(intern.at(0)).isDigit()) result += "part"; result += intern.left(pos + 1); // copy numbers (or "pictures") + "/" intern = intern.mid(pos + 1); // remove the dir we just processed } if (!intern.isEmpty() && QChar(intern.at(0)).isDigit()) result += "part"; result += intern; return result; } KisKraLoadVisitor::KisKraLoadVisitor(KisImageWSP image, KoStore *store, QMap &layerFilenames, const QString & name, int syntaxVersion) : KisNodeVisitor(), m_layerFilenames(layerFilenames) { m_external = false; m_image = image; m_store = store; m_name = name; m_store->pushDirectory(); if (m_name.startsWith("/")) { m_name.remove(0, 1); } if (!m_store->enterDirectory(m_name)) { QStringList directories = m_store->directoryList(); dbgKrita << directories; if (directories.size() > 0) { dbgFile << "Could not locate the directory, maybe some encoding issue? Grab the first directory, that'll be the image one." << m_name << directories; m_name = directories.first(); } else { dbgFile << "Could not enter directory" << m_name << ", probably an old-style file with 'part' added."; m_name = expandEncodedDirectory(m_name); } } else { m_store->popDirectory(); } m_syntaxVersion = syntaxVersion; } void KisKraLoadVisitor::setExternalUri(const QString &uri) { m_external = true; m_uri = uri; } bool KisKraLoadVisitor::visit(KisExternalLayer * layer) { bool result = false; if (KisShapeLayer* shapeLayer = dynamic_cast(layer)) { if (!loadMetaData(layer)) { return false; } m_store->pushDirectory(); m_store->enterDirectory(getLocation(layer, DOT_SHAPE_LAYER)) ; result = shapeLayer->loadLayer(m_store); m_store->popDirectory(); } result = visitAll(layer) && result; return result; } bool KisKraLoadVisitor::visit(KisPaintLayer *layer) { dbgFile << "Visit: " << layer->name() << " colorSpace: " << layer->colorSpace()->id(); if (!loadPaintDevice(layer->paintDevice(), getLocation(layer))) { return false; } if (!loadProfile(layer->paintDevice(), getLocation(layer, DOT_ICC))) { return false; } if (!loadMetaData(layer)) { return false; } if (m_syntaxVersion == 1) { // Check whether there is a file with a .mask extension in the // layer directory, if so, it's an old-style transparency mask // that should be converted. QString location = getLocation(layer, ".mask"); if (m_store->open(location)) { KisSelectionSP selection = KisSelectionSP(new KisSelection()); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); if (!pixelSelection->read(m_store->device())) { pixelSelection->disconnect(); } else { KisTransparencyMask* mask = new KisTransparencyMask(); mask->setSelection(selection); m_image->addNode(mask, layer, layer->firstChild()); } m_store->close(); } } bool result = visitAll(layer); return result; } bool KisKraLoadVisitor::visit(KisGroupLayer *layer) { if (*layer->colorSpace() != *m_image->colorSpace()) { layer->resetCache(m_image->colorSpace()); } if (!loadMetaData(layer)) { return false; } bool result = visitAll(layer); return result; } bool KisKraLoadVisitor::visit(KisAdjustmentLayer* layer) { // Adjustmentlayers are tricky: there's the 1.x style and the 2.x // style, which has selections with selection components bool result = true; if (m_syntaxVersion == 1) { KisSelectionSP selection = new KisSelection(); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); result = loadPaintDevice(pixelSelection, getLocation(layer, ".selection")); layer->setInternalSelection(selection); } else if (m_syntaxVersion == 2) { result = loadSelection(getLocation(layer), layer->internalSelection()); } else { // We use the default, empty selection } if (!loadMetaData(layer)) { return false; } loadFilterConfiguration(layer->filter().data(), getLocation(layer, DOT_FILTERCONFIG)); result = visitAll(layer); return result; } bool KisKraLoadVisitor::visit(KisGeneratorLayer* layer) { if (!loadMetaData(layer)) { return false; } bool result = true; result = loadSelection(getLocation(layer), layer->internalSelection()); result = loadFilterConfiguration(layer->filter().data(), getLocation(layer, DOT_FILTERCONFIG)); layer->update(); result = visitAll(layer); return result; } bool KisKraLoadVisitor::visit(KisCloneLayer *layer) { if (!loadMetaData(layer)) { return false; } // the layer might have already been lazily initialized // from the mask loading code if (layer->copyFrom()) { return true; } KisNodeSP srcNode = layer->copyFromInfo().findNode(m_image->rootLayer()); KisLayerSP srcLayer = dynamic_cast(srcNode.data()); Q_ASSERT(srcLayer); layer->setCopyFrom(srcLayer); // Clone layers have no data except for their masks bool result = visitAll(layer); return result; } void KisKraLoadVisitor::initSelectionForMask(KisMask *mask) { KisLayer *cloneLayer = dynamic_cast(mask->parent().data()); if (cloneLayer) { // the clone layers should be initialized out of order // and lazily, because their original() is still not // initialized cloneLayer->accept(*this); } KisLayer *parentLayer = dynamic_cast(mask->parent().data()); // the KisKraLoader must have already set the parent for us Q_ASSERT(parentLayer); mask->initSelection(parentLayer); } bool KisKraLoadVisitor::visit(KisFilterMask *mask) { initSelectionForMask(mask); bool result = true; result = loadSelection(getLocation(mask), mask->selection()); result = loadFilterConfiguration(mask->filter().data(), getLocation(mask, DOT_FILTERCONFIG)); return result; } bool KisKraLoadVisitor::visit(KisTransformMask *mask) { QString location = getLocation(mask, DOT_TRANSFORMCONFIG); if (m_store->hasFile(location)) { QByteArray data; m_store->open(location); data = m_store->read(m_store->size()); m_store->close(); if (!data.isEmpty()) { QDomDocument doc; doc.setContent(data); QDomElement rootElement = doc.documentElement(); QDomElement main; if (!KisDomUtils::findOnlyElement(rootElement, "main", &main/*, &m_errorMessages*/)) { return false; } QString id = main.attribute("id", "not-valid"); if (id == "not-valid") { m_errorMessages << i18n("Could not load \"id\" of the transform mask"); return false; } QDomElement data; if (!KisDomUtils::findOnlyElement(rootElement, "data", &data, &m_errorMessages)) { return false; } KisTransformMaskParamsInterfaceSP params = KisTransformMaskParamsFactoryRegistry::instance()->createParams(id, data); if (!params) { m_errorMessages << i18n("Could not create transform mask params"); return false; } mask->setTransformParams(params); return true; } } return false; } bool KisKraLoadVisitor::visit(KisTransparencyMask *mask) { initSelectionForMask(mask); return loadSelection(getLocation(mask), mask->selection()); } bool KisKraLoadVisitor::visit(KisSelectionMask *mask) { initSelectionForMask(mask); return loadSelection(getLocation(mask), mask->selection()); } bool KisKraLoadVisitor::visit(KisColorizeMask *mask) { m_store->pushDirectory(); QString location = getLocation(mask, DOT_COLORIZE_MASK); m_store->enterDirectory(location) ; QByteArray data; if (!m_store->extractFile("content.xml", data)) return false; QDomDocument doc; if (!doc.setContent(data)) return false; QVector strokes; if (!KisDomUtils::loadValue(doc.documentElement(), COLORIZE_KEYSTROKES_SECTION, &strokes, mask->colorSpace())) return false; int i = 0; Q_FOREACH (const KisLazyFillTools::KeyStroke &stroke, strokes) { const QString fileName = QString("%1_%2").arg(COLORIZE_KEYSTROKE).arg(i++); loadPaintDevice(stroke.dev, fileName); } mask->setKeyStrokesDirect(QList::fromVector(strokes)); loadPaintDevice(mask->coloringProjection(), COLORIZE_COLORING_DEVICE); m_store->popDirectory(); return true; } QStringList KisKraLoadVisitor::errorMessages() const { return m_errorMessages; } struct SimpleDevicePolicy { bool read(KisPaintDeviceSP dev, QIODevice *stream) { return dev->read(stream); } void setDefaultPixel(KisPaintDeviceSP dev, const KoColor &defaultPixel) const { return dev->setDefaultPixel(defaultPixel); } }; struct FramedDevicePolicy { FramedDevicePolicy(int frameId) : m_frameId(frameId) {} bool read(KisPaintDeviceSP dev, QIODevice *stream) { return dev->framesInterface()->readFrame(stream, m_frameId); } void setDefaultPixel(KisPaintDeviceSP dev, const KoColor &defaultPixel) const { return dev->framesInterface()->setFrameDefaultPixel(defaultPixel, m_frameId); } int m_frameId; }; bool KisKraLoadVisitor::loadPaintDevice(KisPaintDeviceSP device, const QString& location) { // Layer data KisPaintDeviceFramesInterface *frameInterface = device->framesInterface(); QList frames; if (frameInterface) { frames = device->framesInterface()->frames(); } if (!frameInterface || frames.count() <= 1) { return loadPaintDeviceFrame(device, location, SimpleDevicePolicy()); } else { KisRasterKeyframeChannel *keyframeChannel = device->keyframeChannel(); for (int i = 0; i < frames.count(); i++) { int id = frames[i]; QString frameFilename = getLocation(keyframeChannel->frameFilename(id)); Q_ASSERT(!frameFilename.isEmpty()); if (!loadPaintDeviceFrame(device, frameFilename, FramedDevicePolicy(id))) { return false; } } } return true; } template bool KisKraLoadVisitor::loadPaintDeviceFrame(KisPaintDeviceSP device, const QString &location, DevicePolicy policy) { if (m_store->open(location)) { if (!policy.read(device, m_store->device())) { m_errorMessages << i18n("Could not read pixel data: %1.", location); device->disconnect(); m_store->close(); return false; } m_store->close(); } else { m_errorMessages << i18n("Could not load pixel data: %1.", location); return false; } if (m_store->open(location + ".defaultpixel")) { int pixelSize = device->colorSpace()->pixelSize(); if (m_store->size() == pixelSize) { KoColor color(Qt::transparent, device->colorSpace()); m_store->read((char*)color.data(), pixelSize); policy.setDefaultPixel(device, color); } m_store->close(); } return true; } bool KisKraLoadVisitor::loadProfile(KisPaintDeviceSP device, const QString& location) { if (m_store->hasFile(location)) { m_store->open(location); QByteArray data; data.resize(m_store->size()); dbgFile << "Data to load: " << m_store->size() << " from " << location << " with color space " << device->colorSpace()->id(); int read = m_store->read(data.data(), m_store->size()); dbgFile << "Profile size: " << data.size() << " " << m_store->atEnd() << " " << m_store->device()->bytesAvailable() << " " << read; m_store->close(); // Create a colorspace with the embedded profile const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(device->colorSpace()->colorModelId().id(), device->colorSpace()->colorDepthId().id(), data); if (device->setProfile(profile)) { return true; } } m_errorMessages << i18n("Could not load profile %1.", location); return false; } -bool KisKraLoadVisitor::loadFilterConfiguration(KisFilterConfiguration* kfc, const QString& location) +bool KisKraLoadVisitor::loadFilterConfiguration(KisFilterConfigurationSP kfc, const QString& location) { if (m_store->hasFile(location)) { QByteArray data; m_store->open(location); data = m_store->read(m_store->size()); m_store->close(); if (!data.isEmpty()) { QString xml(data); QDomDocument doc; doc.setContent(data); QDomElement e = doc.documentElement(); if (e.tagName() == "filterconfig") { kfc->fromLegacyXML(e); } else { kfc->fromXML(e); } return true; } } m_errorMessages << i18n("Could not filter configuration %1.", location); return false; } bool KisKraLoadVisitor::loadMetaData(KisNode* node) { dbgFile << "Load metadata for " << node->name(); KisLayer* layer = qobject_cast(node); if (!layer) return true; bool result = true; KisMetaData::IOBackend* backend = KisMetaData::IOBackendRegistry::instance()->get("xmp"); if (!backend || !backend->supportLoading()) { if (backend) dbgFile << "Backend " << backend->id() << " does not support loading."; else dbgFile << "Could not load the XMP backenda t all"; return true; } QString location = getLocation(node, QString(".") + backend->id() + DOT_METADATA); dbgFile << "going to load " << backend->id() << ", " << backend->name() << " from " << location; if (m_store->hasFile(location)) { QByteArray data; m_store->open(location); data = m_store->read(m_store->size()); m_store->close(); QBuffer buffer(&data); if (!backend->loadFrom(layer->metaData(), &buffer)) { m_errorMessages << i18n("Could not load metadata for layer %1.", layer->name()); result = false; } } return result; } bool KisKraLoadVisitor::loadSelection(const QString& location, KisSelectionSP dstSelection) { // Pixel selection bool result = true; QString pixelSelectionLocation = location + DOT_PIXEL_SELECTION; if (m_store->hasFile(pixelSelectionLocation)) { KisPixelSelectionSP pixelSelection = dstSelection->pixelSelection(); result = loadPaintDevice(pixelSelection, pixelSelectionLocation); if (!result) { m_errorMessages << i18n("Could not load raster selection %1.", location); } pixelSelection->invalidateOutlineCache(); } // Shape selection QString shapeSelectionLocation = location + DOT_SHAPE_SELECTION; if (m_store->hasFile(shapeSelectionLocation + "/content.xml")) { m_store->pushDirectory(); m_store->enterDirectory(shapeSelectionLocation) ; KisShapeSelection* shapeSelection = new KisShapeSelection(m_image, dstSelection); dstSelection->setShapeSelection(shapeSelection); result = shapeSelection->loadSelection(m_store); m_store->popDirectory(); if (!result) { m_errorMessages << i18n("Could not load vector selection %1.", location); } } return result; } QString KisKraLoadVisitor::getLocation(KisNode* node, const QString& suffix) { return getLocation(m_layerFilenames[node], suffix); } QString KisKraLoadVisitor::getLocation(const QString &filename, const QString& suffix) { QString location = m_external ? QString() : m_uri; location += m_name + LAYER_PATH + filename + suffix; return location; } diff --git a/libs/ui/kra/kis_kra_load_visitor.h b/libs/ui/kra/kis_kra_load_visitor.h index 9d301b7f74..fba9463351 100644 --- a/libs/ui/kra/kis_kra_load_visitor.h +++ b/libs/ui/kra/kis_kra_load_visitor.h @@ -1,91 +1,91 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 C. Boemann * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_KRA_LOAD_VISITOR_H_ #define KIS_KRA_LOAD_VISITOR_H_ #include #include // kritaimage #include "kis_types.h" #include "kis_node_visitor.h" class KisFilterConfiguration; class KoStore; class KisKraLoadVisitor : public KisNodeVisitor { public: KisKraLoadVisitor(KisImageWSP image, KoStore *store, QMap &layerFilenames, const QString & name, int syntaxVersion); public: void setExternalUri(const QString &uri); bool visit(KisNode*) { return true; } bool visit(KisExternalLayer *); bool visit(KisPaintLayer *layer); bool visit(KisGroupLayer *layer); bool visit(KisAdjustmentLayer* layer); bool visit(KisGeneratorLayer* layer); bool visit(KisCloneLayer *layer); bool visit(KisFilterMask *mask); bool visit(KisTransformMask *mask); bool visit(KisTransparencyMask *mask); bool visit(KisSelectionMask *mask); bool visit(KisColorizeMask *mask); QStringList errorMessages() const; private: bool loadPaintDevice(KisPaintDeviceSP device, const QString& location); template bool loadPaintDeviceFrame(KisPaintDeviceSP device, const QString &location, DevicePolicy policy); bool loadProfile(KisPaintDeviceSP device, const QString& location); - bool loadFilterConfiguration(KisFilterConfiguration* kfc, const QString& location); + bool loadFilterConfiguration(KisFilterConfigurationSP kfc, const QString& location); bool loadMetaData(KisNode* node); void initSelectionForMask(KisMask *mask); bool loadSelection(const QString& location, KisSelectionSP dstSelection); QString getLocation(KisNode* node, const QString& suffix = QString()); QString getLocation(const QString &filename, const QString &suffix = QString()); private: KisImageWSP m_image; KoStore *m_store; bool m_external; QString m_uri; QMap m_layerFilenames; QString m_name; int m_syntaxVersion; QStringList m_errorMessages; }; #endif // KIS_KRA_LOAD_VISITOR_H_ diff --git a/libs/ui/kra/kis_kra_loader.cpp b/libs/ui/kra/kis_kra_loader.cpp index 2e7c442bd9..28b7c1167d 100644 --- a/libs/ui/kra/kis_kra_loader.cpp +++ b/libs/ui/kra/kis_kra_loader.cpp @@ -1,1158 +1,1159 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2007 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kra/kis_kra_loader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lazybrush/kis_colorize_mask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_resource_server_provider.h" #include "kis_keyframe_channel.h" +#include #include "KisDocument.h" #include "kis_config.h" #include "kis_kra_tags.h" #include "kis_kra_utils.h" #include "kis_kra_load_visitor.h" #include "kis_dom_utils.h" #include "kis_image_animation_interface.h" #include "kis_time_range.h" #include "kis_grid_config.h" #include "kis_guides_config.h" #include "kis_image_config.h" #include "KisProofingConfiguration.h" #include "kis_layer_properties_icons.h" #include "kis_node_view_color_scheme.h" /* Color model id comparison through the ages: 2.4 2.5 2.6 ideal ALPHA ALPHA ALPHA ALPHAU8 CMYK CMYK CMYK CMYKAU8 CMYKAF32 CMYKAF32 CMYKA16 CMYKAU16 CMYKAU16 GRAYA GRAYA GRAYA GRAYAU8 GrayF32 GRAYAF32 GRAYAF32 GRAYA16 GRAYAU16 GRAYAU16 LABA LABA LABA LABAU16 LABAF32 LABAF32 LABAU8 LABAU8 RGBA RGBA RGBA RGBAU8 RGBA16 RGBA16 RGBA16 RGBAU16 RgbAF32 RGBAF32 RGBAF32 RgbAF16 RgbAF16 RGBAF16 XYZA16 XYZA16 XYZA16 XYZAU16 XYZA8 XYZA8 XYZAU8 XyzAF16 XyzAF16 XYZAF16 XyzAF32 XYZAF32 XYZAF32 YCbCrA YCBCRA8 YCBCRA8 YCBCRAU8 YCbCrAU16 YCBCRAU16 YCBCRAU16 YCBCRF32 YCBCRF32 */ using namespace KRA; struct KisKraLoader::Private { public: KisDocument* document; QString imageName; // used to be stored in the image, is now in the documentInfo block QString imageComment; // used to be stored in the image, is now in the documentInfo block QMap layerFilenames; // temp storage during loading int syntaxVersion; // version of the fileformat we are loading vKisNodeSP selectedNodes; // the nodes that were active when saving the document. QMap assistantsFilenames; QList assistants; QMap keyframeFilenames; QStringList errorMessages; }; void convertColorSpaceNames(QString &colorspacename, QString &profileProductName) { if (colorspacename == "Grayscale + Alpha") { colorspacename = "GRAYA"; profileProductName.clear(); } else if (colorspacename == "RgbAF32") { colorspacename = "RGBAF32"; profileProductName.clear(); } else if (colorspacename == "RgbAF16") { colorspacename = "RGBAF16"; profileProductName.clear(); } else if (colorspacename == "CMYKA16") { colorspacename = "CMYKAU16"; } else if (colorspacename == "GrayF32") { colorspacename = "GRAYAF32"; profileProductName.clear(); } else if (colorspacename == "GRAYA16") { colorspacename = "GRAYAU16"; } else if (colorspacename == "XyzAF16") { colorspacename = "XYZAF16"; profileProductName.clear(); } else if (colorspacename == "XyzAF32") { colorspacename = "XYZAF32"; profileProductName.clear(); } else if (colorspacename == "YCbCrA") { colorspacename = "YCBCRA8"; } else if (colorspacename == "YCbCrAU16") { colorspacename = "YCBCRAU16"; } } KisKraLoader::KisKraLoader(KisDocument * document, int syntaxVersion) : m_d(new Private()) { m_d->document = document; m_d->syntaxVersion = syntaxVersion; } KisKraLoader::~KisKraLoader() { delete m_d; } KisImageSP KisKraLoader::loadXML(const KoXmlElement& element) { QString attr; KisImageSP image = 0; QString name; qint32 width; qint32 height; QString profileProductName; double xres; double yres; QString colorspacename; const KoColorSpace * cs; if ((attr = element.attribute(MIME)) == NATIVE_MIMETYPE) { if ((m_d->imageName = element.attribute(NAME)).isNull()) { m_d->errorMessages << i18n("Image does not have a name."); return KisImageSP(0); } if ((attr = element.attribute(WIDTH)).isNull()) { m_d->errorMessages << i18n("Image does not specify a width."); return KisImageSP(0); } width = KisDomUtils::toInt(attr); if ((attr = element.attribute(HEIGHT)).isNull()) { m_d->errorMessages << i18n("Image does not specify a height."); return KisImageSP(0); } height = KisDomUtils::toInt(attr); m_d->imageComment = element.attribute(DESCRIPTION); xres = 100.0 / 72.0; if (!(attr = element.attribute(X_RESOLUTION)).isNull()) { qreal value = KisDomUtils::toDouble(attr); if (value > 1.0) { xres = value / 72.0; } } yres = 100.0 / 72.0; if (!(attr = element.attribute(Y_RESOLUTION)).isNull()) { qreal value = KisDomUtils::toDouble(attr); if (value > 1.0) { yres = value / 72.0; } } if ((colorspacename = element.attribute(COLORSPACE_NAME)).isNull()) { // An old file: take a reasonable default. // Krita didn't support anything else in those // days anyway. colorspacename = "RGBA"; } profileProductName = element.attribute(PROFILE); // A hack for an old colorspacename convertColorSpaceNames(colorspacename, profileProductName); QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id(); QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id(); if (profileProductName.isNull()) { // no mention of profile so get default profile"; cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); } else { cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName); } if (cs == 0) { // try once more without the profile cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); if (cs == 0) { m_d->errorMessages << i18n("Image specifies an unsupported color model: %1.", colorspacename); return KisImageSP(0); } } KisImageConfig cfgImage; KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); if (!(attr = element.attribute(PROOFINGPROFILENAME)).isNull()) { proofingConfig->proofingProfile = attr; } if (!(attr = element.attribute(PROOFINGMODEL)).isNull()) { proofingConfig->proofingModel = attr; } if (!(attr = element.attribute(PROOFINGDEPTH)).isNull()) { proofingConfig->proofingDepth = attr; } if (!(attr = element.attribute(PROOFINGINTENT)).isNull()) { proofingConfig->intent = (KoColorConversionTransformation::Intent) KisDomUtils::toInt(attr); } if (!(attr = element.attribute(PROOFINGADAPTATIONSTATE)).isNull()) { proofingConfig->adaptationState = KisDomUtils::toDouble(attr); } if (m_d->document) { image = new KisImage(m_d->document->createUndoStore(), width, height, cs, name); } else { image = new KisImage(0, width, height, cs, name); } image->setResolution(xres, yres); loadNodes(element, image, const_cast(image->rootLayer().data())); KoXmlNode child; for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if(e.tagName() == CANVASPROJECTIONCOLOR) { if (e.hasAttribute(COLORBYTEDATA)) { QByteArray colorData = QByteArray::fromBase64(e.attribute(COLORBYTEDATA).toLatin1()); KoColor color((const quint8*)colorData.data(), image->colorSpace()); image->setDefaultProjectionColor(color); } } if(e.tagName()== PROOFINGWARNINGCOLOR) { QDomDocument dom; KoXml::asQDomElement(dom, e); QDomElement eq = dom.firstChildElement(); proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id(), QHash()); } if (e.tagName().toLower() == "animation") { loadAnimationMetadata(e, image); } } image->setProofingConfiguration(proofingConfig); for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if(e.tagName() == "compositions") { loadCompositions(e, image); } } } KoXmlNode child; for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if (e.tagName() == "grid") { loadGrid(e); } else if (e.tagName() == "guides") { loadGuides(e); } else if (e.tagName() == "assistants") { loadAssistantsList(e); } } return image; } void KisKraLoader::loadBinaryData(KoStore * store, KisImageSP image, const QString & uri, bool external) { // icc profile: if present, this overrides the profile product name loaded in loadXML. QString location = external ? QString() : uri; location += m_d->imageName + ICC_PATH; if (store->hasFile(location)) { if (store->open(location)) { QByteArray data; data.resize(store->size()); bool res = (store->read(data.data(), store->size()) > -1); store->close(); if (res) { const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(image->colorSpace()->colorModelId().id(), image->colorSpace()->colorDepthId().id(), data); if (profile && profile->valid()) { res = image->assignImageProfile(profile); } if (!res) { profile = KoColorSpaceRegistry::instance()->profileByName(KoColorSpaceRegistry::instance()->colorSpaceFactory(image->colorSpace()->id())->defaultProfile()); Q_ASSERT(profile && profile->valid()); image->assignImageProfile(profile); } } } } //load the embed proofing profile, it only needs to be loaded into Krita, not assigned. location = external ? QString() : uri; location += m_d->imageName + ICC_PROOFING_PATH; if (store->hasFile(location)) { if (store->open(location)) { QByteArray proofingData; proofingData.resize(store->size()); bool proofingProfileRes = (store->read(proofingData.data(), store->size())>-1); store->close(); if (proofingProfileRes) { const KoColorProfile *proofingProfile = KoColorSpaceRegistry::instance()->createColorProfile(image->proofingConfiguration()->proofingModel, image->proofingConfiguration()->proofingDepth, proofingData); if (proofingProfile->valid()){ //if (KoColorSpaceEngineRegistry::instance()->get("icc")) { // KoColorSpaceEngineRegistry::instance()->get("icc")->addProfile(proofingProfile->fileName()); //} KoColorSpaceRegistry::instance()->addProfile(proofingProfile); } } } } // Load the layers data: if there is a profile associated with a layer it will be set now. KisKraLoadVisitor visitor(image, store, m_d->layerFilenames, m_d->imageName, m_d->syntaxVersion); if (external) { visitor.setExternalUri(uri); } image->rootLayer()->accept(visitor); if (!visitor.errorMessages().isEmpty()) { m_d->errorMessages.append(visitor.errorMessages()); } // annotations // exif location = external ? QString() : uri; location += m_d->imageName + EXIF_PATH; if (store->hasFile(location)) { QByteArray data; store->open(location); data = store->read(store->size()); store->close(); image->addAnnotation(KisAnnotationSP(new KisAnnotation("exif", "", data))); } // layer styles location = external ? QString() : uri; location += m_d->imageName + LAYER_STYLES_PATH; if (store->hasFile(location)) { KisPSDLayerStyleCollectionResource *collection = new KisPSDLayerStyleCollectionResource("Embedded Styles.asl"); collection->setName(i18nc("Auto-generated layer style collection name for embedded styles (collection)", "<%1> (embedded)", m_d->imageName)); KIS_ASSERT_RECOVER_NOOP(!collection->valid()); store->open(location); { KoStoreDevice device(store); device.open(QIODevice::ReadOnly); /** * ASL loading code cannot work with non-sequential IO devices, * so convert the device beforehand! */ QByteArray buf = device.readAll(); QBuffer raDevice(&buf); raDevice.open(QIODevice::ReadOnly); collection->loadFromDevice(&raDevice); } store->close(); if (collection->valid()) { KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); server->addResource(collection, false); collection->assignAllLayerStyles(image->root()); } else { warnKrita << "WARNING: Couldn't load layer styles library from .kra!"; delete collection; } } if (m_d->document && m_d->document->documentInfo()->aboutInfo("title").isNull()) m_d->document->documentInfo()->setAboutInfo("title", m_d->imageName); if (m_d->document && m_d->document->documentInfo()->aboutInfo("comment").isNull()) m_d->document->documentInfo()->setAboutInfo("comment", m_d->imageComment); loadAssistants(store, uri, external); } void KisKraLoader::loadKeyframes(KoStore *store, const QString uri, bool external) { QMap::iterator it; for (it = m_d->keyframeFilenames.begin(); it != m_d->keyframeFilenames.end(); it++) { KisNodeSP node = it.key(); QString filename = it.value(); QString location = (external ? QString() : uri) + m_d->imageName + LAYER_PATH + filename; loadNodeKeyframes(store, location, node); } } void KisKraLoader::loadNodeKeyframes(KoStore *store, const QString &location, KisNodeSP node) { if (!store->open(location)) { m_d->errorMessages << i18n("Could not load keyframes from %1.", location); return; } QString errorMsg; int errorLine; int errorColumn; KoXmlDocument doc = KoXmlDocument(true); bool ok = doc.setContent(store->device(), &errorMsg, &errorLine, &errorColumn); store->close(); if (!ok) { m_d->errorMessages << i18n("parsing error in the keyframe file %1 at line %2, column %3\nError message: %4", location, errorLine, errorColumn, i18n(errorMsg.toUtf8())); return; } QDomDocument dom; KoXml::asQDomElement(dom, doc.documentElement()); QDomElement root = dom.firstChildElement(); for (QDomElement child = root.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) { if (child.nodeName().toUpper() == "CHANNEL") { QString id = child.attribute("name"); KisKeyframeChannel *channel = node->getKeyframeChannel(id); if (!channel) { m_d->errorMessages << i18n("unknown keyframe channel type: %1 in %2", id, location); continue; } channel->loadXML(child); } } } vKisNodeSP KisKraLoader::selectedNodes() const { return m_d->selectedNodes; } QList KisKraLoader::assistants() const { return m_d->assistants; } QStringList KisKraLoader::errorMessages() const { return m_d->errorMessages; } void KisKraLoader::loadAssistants(KoStore *store, const QString &uri, bool external) { QString file_path; QString location; QMap handleMap; KisPaintingAssistant* assistant = 0; QMap::const_iterator loadedAssistant = m_d->assistantsFilenames.constBegin(); while (loadedAssistant != m_d->assistantsFilenames.constEnd()){ const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(loadedAssistant.value()); if (factory) { assistant = factory->createPaintingAssistant(); location = external ? QString() : uri; location += m_d->imageName + ASSISTANTS_PATH; file_path = location + loadedAssistant.key(); assistant->loadXml(store, handleMap, file_path); //If an assistant has too few handles than it should according to it's own setup, just don't load it// if (assistant->handles().size()==assistant->numHandles()){ m_d->assistants.append(toQShared(assistant)); } } loadedAssistant++; } } void KisKraLoader::loadAnimationMetadata(const KoXmlElement &element, KisImageSP image) { QDomDocument qDom; KoXml::asQDomElement(qDom, element); QDomElement qElement = qDom.firstChildElement(); float framerate; KisTimeRange range; int currentTime; KisImageAnimationInterface *animation = image->animationInterface(); if (KisDomUtils::loadValue(qElement, "framerate", &framerate)) { animation->setFramerate(framerate); } if (KisDomUtils::loadValue(qElement, "range", &range)) { animation->setFullClipRange(range); } if (KisDomUtils::loadValue(qElement, "currentTime", ¤tTime)) { animation->switchCurrentTimeAsync(currentTime); } } KisNodeSP KisKraLoader::loadNodes(const KoXmlElement& element, KisImageSP image, KisNodeSP parent) { KoXmlNode node = element.firstChild(); KoXmlNode child; if (!node.isNull()) { if (node.isElement()) { if (node.nodeName().toUpper() == LAYERS.toUpper() || node.nodeName().toUpper() == MASKS.toUpper()) { for (child = node.lastChild(); !child.isNull(); child = child.previousSibling()) { KisNodeSP node = loadNode(child.toElement(), image, parent); if (node) { image->nextLayerName(); // Make sure the nameserver is current with the number of nodes. image->addNode(node, parent); if (node->inherits("KisLayer") && child.childNodesCount() > 0) { loadNodes(child.toElement(), image, node); } } } } } } return parent; } KisNodeSP KisKraLoader::loadNode(const KoXmlElement& element, KisImageSP image, KisNodeSP parent) { // Nota bene: If you add new properties to layers, you should // ALWAYS define a default value in case the property is not // present in the layer definition: this helps a LOT with backward // compatibility. QString name = element.attribute(NAME, "No Name"); QUuid id = QUuid(element.attribute(UUID, QUuid().toString())); qint32 x = element.attribute(X, "0").toInt(); qint32 y = element.attribute(Y, "0").toInt(); qint32 opacity = element.attribute(OPACITY, QString::number(OPACITY_OPAQUE_U8)).toInt(); if (opacity < OPACITY_TRANSPARENT_U8) opacity = OPACITY_TRANSPARENT_U8; if (opacity > OPACITY_OPAQUE_U8) opacity = OPACITY_OPAQUE_U8; const KoColorSpace* colorSpace = 0; if ((element.attribute(COLORSPACE_NAME)).isNull()) { dbgFile << "No attribute color space for layer: " << name; colorSpace = image->colorSpace(); } else { QString colorspacename = element.attribute(COLORSPACE_NAME); QString profileProductName; convertColorSpaceNames(colorspacename, profileProductName); QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id(); QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id(); dbgFile << "Searching color space: " << colorspacename << colorspaceModel << colorspaceDepth << " for layer: " << name; // use default profile - it will be replaced later in completeLoading colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); dbgFile << "found colorspace" << colorSpace; if (!colorSpace) { m_d->errorMessages << i18n("Layer %1 specifies an unsupported color model: %2.", name, colorspacename); return 0; } } const bool visible = element.attribute(VISIBLE, "1") == "0" ? false : true; const bool locked = element.attribute(LOCKED, "0") == "0" ? false : true; const bool collapsed = element.attribute(COLLAPSED, "0") == "0" ? false : true; int colorLabelIndex = element.attribute(COLOR_LABEL, "0").toInt(); QVector labels = KisNodeViewColorScheme::instance()->allColorLabels(); if (colorLabelIndex >= labels.size()) { colorLabelIndex = labels.size() - 1; } // Now find out the layer type and do specific handling QString nodeType; if (m_d->syntaxVersion == 1) { nodeType = element.attribute("layertype"); if (nodeType.isEmpty()) { nodeType = PAINT_LAYER; } } else { nodeType = element.attribute(NODE_TYPE); } if (nodeType.isEmpty()) { m_d->errorMessages << i18n("Layer %1 has an unsupported type.", name); return 0; } KisNodeSP node = 0; if (nodeType == PAINT_LAYER) node = loadPaintLayer(element, image, name, colorSpace, opacity); else if (nodeType == GROUP_LAYER) node = loadGroupLayer(element, image, name, colorSpace, opacity); else if (nodeType == ADJUSTMENT_LAYER) node = loadAdjustmentLayer(element, image, name, colorSpace, opacity); else if (nodeType == SHAPE_LAYER) node = loadShapeLayer(element, image, name, colorSpace, opacity); else if (nodeType == GENERATOR_LAYER) node = loadGeneratorLayer(element, image, name, colorSpace, opacity); else if (nodeType == CLONE_LAYER) node = loadCloneLayer(element, image, name, colorSpace, opacity); else if (nodeType == FILTER_MASK) node = loadFilterMask(element, parent); else if (nodeType == TRANSFORM_MASK) node = loadTransformMask(element, parent); else if (nodeType == TRANSPARENCY_MASK) node = loadTransparencyMask(element, parent); else if (nodeType == SELECTION_MASK) node = loadSelectionMask(image, element, parent); else if (nodeType == COLORIZE_MASK) node = loadColorizeMask(image, element, parent, colorSpace); else if (nodeType == FILE_LAYER) { node = loadFileLayer(element, image, name, opacity); } else { m_d->errorMessages << i18n("Layer %1 has an unsupported type: %2.", name, nodeType); return 0; } // Loading the node went wrong. Return empty node and leave to // upstream to complain to the user if (!node) { m_d->errorMessages << i18n("Failure loading layer %1 of type: %2.", name, nodeType); return 0; } node->setVisible(visible, true); node->setUserLocked(locked); node->setCollapsed(collapsed); node->setColorLabelIndex(colorLabelIndex); node->setX(x); node->setY(y); node->setName(name); if (! id.isNull()) // if no uuid in file, new one has been generated already node->setUuid(id); if (node->inherits("KisLayer") || node->inherits("KisColorizeMask")) { QString compositeOpName = element.attribute(COMPOSITE_OP, "normal"); node->setCompositeOpId(compositeOpName); } if (node->inherits("KisLayer")) { KisLayer* layer = qobject_cast(node.data()); QBitArray channelFlags = stringToFlags(element.attribute(CHANNEL_FLAGS, ""), colorSpace->channelCount()); layer->setChannelFlags(channelFlags); if (element.hasAttribute(LAYER_STYLE_UUID)) { QString uuidString = element.attribute(LAYER_STYLE_UUID); QUuid uuid(uuidString); if (!uuid.isNull()) { KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle()); dumbLayerStyle->setUuid(uuid); layer->setLayerStyle(dumbLayerStyle); } else { warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString; } } } if (node->inherits("KisGroupLayer")) { if (element.hasAttribute(PASS_THROUGH_MODE)) { bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0"; KisGroupLayer *group = qobject_cast(node.data()); group->setPassThroughMode(value); } } if (node->inherits("KisPaintLayer")) { KisPaintLayer* layer = qobject_cast(node.data()); QBitArray channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount()); layer->setChannelLockFlags(channelLockFlags); bool onionEnabled = element.attribute(ONION_SKIN_ENABLED, "0") == "0" ? false : true; layer->setOnionSkinEnabled(onionEnabled); bool timelineEnabled = element.attribute(VISIBLE_IN_TIMELINE, "0") == "0" ? false : true; layer->setUseInTimeline(timelineEnabled); } if (element.attribute(FILE_NAME).isNull()) { m_d->layerFilenames[node.data()] = name; } else { m_d->layerFilenames[node.data()] = element.attribute(FILE_NAME); } if (element.hasAttribute("selected") && element.attribute("selected") == "true") { m_d->selectedNodes.append(node); } if (element.hasAttribute(KEYFRAME_FILE)) { node->enableAnimation(); m_d->keyframeFilenames.insert(node.data(), element.attribute(KEYFRAME_FILE)); } return node; } KisNodeSP KisKraLoader::loadPaintLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); KisPaintLayer* layer; layer = new KisPaintLayer(image, name, opacity, cs); Q_CHECK_PTR(layer); // Load exif info /*TODO: write and use the legacy stuff to load that exif tag for( KoXmlNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() ) { KoXmlElement e = node.toElement(); if ( !e.isNull() && e.tagName() == "ExifInfo" ) { layer->paintDevice()->exifInfo()->load(e); } }*/ // TODO load metadata return layer; } KisNodeSP KisKraLoader::loadFileLayer(const KoXmlElement& element, KisImageSP image, const QString& name, quint32 opacity) { QString filename = element.attribute("source", QString()); if (filename.isNull()) return 0; bool scale = (element.attribute("scale", "true") == "true"); int scalingMethod = element.attribute("scalingmethod", "-1").toInt(); if (scalingMethod < 0) { if (scale) { scalingMethod = KisFileLayer::ToImagePPI; } else { scalingMethod = KisFileLayer::None; } } QString documentPath; if (m_d->document) { documentPath = m_d->document->url().toLocalFile(); } QFileInfo info(documentPath); QString basePath = info.absolutePath(); QString fullPath = basePath + QDir::separator() + filename; // Entering the event loop to show the messagebox will delete the image, so up the ref by one image->ref(); if (!QFileInfo(fullPath).exists()) { qApp->setOverrideCursor(Qt::ArrowCursor); QString msg = i18nc( "@info", "The file associated to a file layer with the name \"%1\" is not found." "Expected path:" "%2" "Do you want to locate it manually?", name, fullPath); int result = QMessageBox::warning(0, i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (result == QMessageBox::Yes) { KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); dialog.setDefaultDir(basePath); QString url = dialog.filename(); if (!QFileInfo(basePath).exists()) { filename = url; } else { QDir d(basePath); filename = d.relativeFilePath(url); } } qApp->restoreOverrideCursor(); } KisLayer *layer = new KisFileLayer(image, basePath, filename, (KisFileLayer::ScalingMethod)scalingMethod, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadGroupLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); Q_UNUSED(cs); QString attr; KisGroupLayer* layer; layer = new KisGroupLayer(image, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadAdjustmentLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { // XXX: do something with filterversion? Q_UNUSED(cs); QString attr; KisAdjustmentLayer* layer; QString filtername; if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid adjustmentlayer! We should warn about it! warnFile << "No filter in adjustment layer"; return 0; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); // We'll load the configuration and the selection later. layer = new KisAdjustmentLayer(image, name, kfc, 0); Q_CHECK_PTR(layer); layer->setOpacity(opacity); return layer; } KisNodeSP KisKraLoader::loadShapeLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); Q_UNUSED(cs); QString attr; KoShapeBasedDocumentBase * shapeController = 0; if (m_d->document) { shapeController = m_d->document->shapeController(); } KisShapeLayer* layer = new KisShapeLayer(shapeController, image, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadGeneratorLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(cs); // XXX: do something with generator version? KisGeneratorLayer* layer; QString generatorname = element.attribute(GENERATOR_NAME); if (generatorname.isNull()) { // XXX: Invalid generator layer! We should warn about it! warnFile << "No generator in generator layer"; return 0; } KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorname); if (!generator) { warnFile << "No generator for generatorname" << generatorname << ""; return 0; // XXX: We don't have this generator. We should warn about it! } - KisFilterConfiguration * kgc = generator->defaultConfiguration(0); + KisFilterConfigurationSP kgc = generator->defaultConfiguration(0); // We'll load the configuration and the selection later. layer = new KisGeneratorLayer(image, name, kgc, 0); Q_CHECK_PTR(layer); layer->setOpacity(opacity); return layer; } KisNodeSP KisKraLoader::loadCloneLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(cs); KisCloneLayerSP layer = new KisCloneLayer(0, image, name, opacity); KisCloneInfo info; if (! (element.attribute(CLONE_FROM_UUID)).isNull()) { info = KisCloneInfo(QUuid(element.attribute(CLONE_FROM_UUID))); } else { if ((element.attribute(CLONE_FROM)).isNull()) { return 0; } else { info = KisCloneInfo(element.attribute(CLONE_FROM)); } } layer->setCopyFromInfo(info); if ((element.attribute(CLONE_TYPE)).isNull()) { return 0; } else { layer->setCopyType((CopyLayerType) element.attribute(CLONE_TYPE).toInt()); } return layer; } KisNodeSP KisKraLoader::loadFilterMask(const KoXmlElement& element, KisNodeSP parent) { Q_UNUSED(parent); QString attr; KisFilterMask* mask; QString filtername; // XXX: should we check the version? if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid filter layer! We should warn about it! warnFile << "No filter in filter layer"; return 0; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); // We'll load the configuration and the selection later. mask = new KisFilterMask(); mask->setFilter(kfc); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadTransformMask(const KoXmlElement& element, KisNodeSP parent) { Q_UNUSED(element); Q_UNUSED(parent); KisTransformMask* mask; /** * We'll load the transform configuration later on a stage * of binary data loading */ mask = new KisTransformMask(); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadTransparencyMask(const KoXmlElement& element, KisNodeSP parent) { Q_UNUSED(element); Q_UNUSED(parent); KisTransparencyMask* mask = new KisTransparencyMask(); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadSelectionMask(KisImageSP image, const KoXmlElement& element, KisNodeSP parent) { Q_UNUSED(parent); KisSelectionMaskSP mask = new KisSelectionMask(image); bool active = element.attribute(ACTIVE, "1") == "0" ? false : true; mask->setActive(active); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadColorizeMask(KisImageSP image, const KoXmlElement& element, KisNodeSP parent, const KoColorSpace *colorSpace) { Q_UNUSED(parent); KisColorizeMaskSP mask = new KisColorizeMask(); bool editKeystrokes = element.attribute(COLORIZE_EDIT_KEYSTROKES, "1") == "0" ? false : true; bool showColoring = element.attribute(COLORIZE_SHOW_COLORING, "1") == "0" ? false : true; KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, editKeystrokes, image); KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, showColoring, image); mask->setColorSpace(colorSpace); return mask; } void KisKraLoader::loadCompositions(const KoXmlElement& elem, KisImageSP image) { KoXmlNode child; for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) { KoXmlElement e = child.toElement(); QString name = e.attribute("name"); bool exportEnabled = e.attribute("exportEnabled", "1") == "0" ? false : true; KisLayerCompositionSP composition(new KisLayerComposition(image, name)); composition->setExportEnabled(exportEnabled); KoXmlNode value; for (value = child.lastChild(); !value.isNull(); value = value.previousSibling()) { KoXmlElement e = value.toElement(); QUuid uuid(e.attribute("uuid")); bool visible = e.attribute("visible", "1") == "0" ? false : true; composition->setVisible(uuid, visible); bool collapsed = e.attribute("collapsed", "1") == "0" ? false : true; composition->setCollapsed(uuid, collapsed); } image->addComposition(composition); } } void KisKraLoader::loadAssistantsList(const KoXmlElement &elem) { KoXmlNode child; int count = 0; for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) { KoXmlElement e = child.toElement(); QString type = e.attribute("type"); QString file_name = e.attribute("filename"); m_d->assistantsFilenames.insert(file_name,type); count++; } } void KisKraLoader::loadGrid(const KoXmlElement& elem) { QDomDocument dom; KoXml::asQDomElement(dom, elem); QDomElement domElement = dom.firstChildElement(); KisGridConfig config; config.loadDynamicDataFromXml(domElement); config.loadStaticData(); m_d->document->setGridConfig(config); } void KisKraLoader::loadGuides(const KoXmlElement& elem) { QDomDocument dom; KoXml::asQDomElement(dom, elem); QDomElement domElement = dom.firstChildElement(); KisGuidesConfig guides; guides.loadFromXml(domElement); m_d->document->setGuidesConfig(guides); } diff --git a/libs/ui/kra/kis_kra_save_visitor.cpp b/libs/ui/kra/kis_kra_save_visitor.cpp index 931c5f5dcc..4bc56c4385 100644 --- a/libs/ui/kra/kis_kra_save_visitor.cpp +++ b/libs/ui/kra/kis_kra_save_visitor.cpp @@ -1,535 +1,535 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 C. Boemann * Copyright (c) 2007-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 "kra/kis_kra_save_visitor.h" #include "kra/kis_kra_tags.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 "lazybrush/kis_colorize_mask.h" #include #include #include #include #include "kis_config.h" #include "kis_store_paintdevice_writer.h" #include "flake/kis_shape_selection.h" #include "kis_raster_keyframe_channel.h" #include "kis_paint_device_frames_interface.h" #include "lazybrush/kis_lazy_fill_tools.h" #include #include "kis_colorize_dom_utils.h" #include "kis_dom_utils.h" using namespace KRA; KisKraSaveVisitor::KisKraSaveVisitor(KoStore *store, const QString & name, QMap nodeFileNames) : KisNodeVisitor() , m_store(store) , m_external(false) , m_name(name) , m_nodeFileNames(nodeFileNames) , m_writer(new KisStorePaintDeviceWriter(store)) { } KisKraSaveVisitor::~KisKraSaveVisitor() { delete m_writer; } void KisKraSaveVisitor::setExternalUri(const QString &uri) { m_external = true; m_uri = uri; } bool KisKraSaveVisitor::visit(KisExternalLayer * layer) { bool result = false; if (KisShapeLayer* shapeLayer = dynamic_cast(layer)) { if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } m_store->pushDirectory(); QString location = getLocation(layer, DOT_SHAPE_LAYER); result = m_store->enterDirectory(location); if (!result) { m_errorMessages << i18n("Failed to open %1.", location); } else { result = shapeLayer->saveLayer(m_store); m_store->popDirectory(); } } else if (KisFileLayer *fileLayer = dynamic_cast(layer)) { Q_UNUSED(fileLayer); // We don't save data for file layers, but we still want to save the masks. result = true; } return result && visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisPaintLayer *layer) { if (!savePaintDevice(layer->paintDevice(), getLocation(layer))) { m_errorMessages << i18n("Failed to save the pixel data for layer %1.", layer->name()); return false; } if (!saveAnnotations(layer)) { m_errorMessages << i18n("Failed to save the annotations for layer %1.", layer->name()); return false; } if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } return visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisGroupLayer *layer) { if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } return visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisAdjustmentLayer* layer) { if (!layer->filter()) { m_errorMessages << i18n("Failed to save the filter layer %1: it has no filter.", layer->name()); return false; } if (!saveSelection(layer)) { m_errorMessages << i18n("Failed to save the selection for filter layer %1.", layer->name()); return false; } if (!saveFilterConfiguration(layer)) { m_errorMessages << i18n("Failed to save the filter configuration for filter layer %1.", layer->name()); return false; } if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } return visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisGeneratorLayer * layer) { if (!saveSelection(layer)) { m_errorMessages << i18n("Failed to save the selection for layer %1.", layer->name()); return false; } if (!saveFilterConfiguration(layer)) { m_errorMessages << i18n("Failed to save the generator configuration for layer %1.", layer->name()); return false; } if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } return visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisCloneLayer *layer) { // Clone layers do not have a profile if (!saveMetaData(layer)) { m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name()); return false; } return visitAllInverse(layer); } bool KisKraSaveVisitor::visit(KisFilterMask *mask) { if (!mask->filter()) { m_errorMessages << i18n("Failed to save filter mask %1. It has no filter.", mask->name()); return false; } if (!saveSelection(mask)) { m_errorMessages << i18n("Failed to save the selection for filter mask %1.", mask->name()); return false; } if (!saveFilterConfiguration(mask)) { m_errorMessages << i18n("Failed to save the filter configuration for filter mask %1.", mask->name()); return false; } return true; } bool KisKraSaveVisitor::visit(KisTransformMask *mask) { QDomDocument doc("transform_params"); QDomElement root = doc.createElement("transform_params"); QDomElement main = doc.createElement("main"); main.setAttribute("id", mask->transformParams()->id()); QDomElement data = doc.createElement("data"); mask->transformParams()->toXML(&data); doc.appendChild(root); root.appendChild(main); root.appendChild(data); QString location = getLocation(mask, DOT_TRANSFORMCONFIG); if (m_store->open(location)) { QByteArray a = doc.toByteArray(); bool retval = true; retval = (m_store->write(a) == a.size()); if (!retval) { warnFile << "Could not write transform mask configuration"; } if (!m_store->close()) { warnFile << "Could not close store after writing transform mask configuration"; retval = false; } return retval; } return false; } bool KisKraSaveVisitor::visit(KisTransparencyMask *mask) { if (!saveSelection(mask)) { m_errorMessages << i18n("Failed to save the selection for transparency mask %1.", mask->name()); return false; } return true; } bool KisKraSaveVisitor::visit(KisSelectionMask *mask) { if (!saveSelection(mask)) { m_errorMessages << i18n("Failed to save the selection for local selection %1.", mask->name()); return false; } return true; } bool KisKraSaveVisitor::visit(KisColorizeMask *mask) { m_store->pushDirectory(); QString location = getLocation(mask, DOT_COLORIZE_MASK); bool result = m_store->enterDirectory(location); if (!result) { m_errorMessages << i18n("Failed to open %1.", location); return false; } if (!m_store->open("content.xml")) return false; KoStoreDevice storeDev(m_store); QDomDocument doc("doc"); QDomElement root = doc.createElement("colorize"); doc.appendChild(root); KisDomUtils::saveValue(&root, COLORIZE_KEYSTROKES_SECTION, QVector::fromList(mask->fetchKeyStrokesDirect())); QTextStream stream(&storeDev); stream << doc; if (!m_store->close()) return false; int i = 0; Q_FOREACH (const KisLazyFillTools::KeyStroke &stroke, mask->fetchKeyStrokesDirect()) { const QString fileName = QString("%1_%2").arg(COLORIZE_KEYSTROKE).arg(i++); savePaintDevice(stroke.dev, fileName); } savePaintDevice(mask->coloringProjection(), COLORIZE_COLORING_DEVICE); m_store->popDirectory(); return true; } QStringList KisKraSaveVisitor::errorMessages() const { return m_errorMessages; } struct SimpleDevicePolicy { bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) { return dev->write(store); } KoColor defaultPixel(KisPaintDeviceSP dev) const { return dev->defaultPixel(); } }; struct FramedDevicePolicy { FramedDevicePolicy(int frameId) : m_frameId(frameId) {} bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) { return dev->framesInterface()->writeFrame(store, m_frameId); } KoColor defaultPixel(KisPaintDeviceSP dev) const { return dev->framesInterface()->frameDefaultPixel(m_frameId); } int m_frameId; }; bool KisKraSaveVisitor::savePaintDevice(KisPaintDeviceSP device, QString location) { // Layer data KisConfig cfg; m_store->setCompressionEnabled(cfg.compressKra()); KisPaintDeviceFramesInterface *frameInterface = device->framesInterface(); QList frames; if (frameInterface) { frames = frameInterface->frames(); } if (!frameInterface || frames.count() <= 1) { savePaintDeviceFrame(device, location, SimpleDevicePolicy()); } else { KisRasterKeyframeChannel *keyframeChannel = device->keyframeChannel(); for (int i = 0; i < frames.count(); i++) { int id = frames[i]; QString frameFilename = getLocation(keyframeChannel->frameFilename(id)); Q_ASSERT(!frameFilename.isEmpty()); if (!savePaintDeviceFrame(device, frameFilename, FramedDevicePolicy(id))) { return false; } } } m_store->setCompressionEnabled(true); return true; } template bool KisKraSaveVisitor::savePaintDeviceFrame(KisPaintDeviceSP device, QString location, DevicePolicy policy) { if (m_store->open(location)) { if (!policy.write(device, *m_writer)) { device->disconnect(); m_store->close(); return false; } m_store->close(); } if (m_store->open(location + ".defaultpixel")) { m_store->write((char*)policy.defaultPixel(device).data(), device->colorSpace()->pixelSize()); m_store->close(); } return true; } bool KisKraSaveVisitor::saveAnnotations(KisLayer* layer) { if (!layer) return false; if (!layer->paintDevice()) return false; if (!layer->paintDevice()->colorSpace()) return false; if (layer->paintDevice()->colorSpace()->profile()) { const KoColorProfile *profile = layer->paintDevice()->colorSpace()->profile(); KisAnnotationSP annotation; if (profile) { QByteArray profileRawData = profile->rawData(); if (!profileRawData.isEmpty()) { if (profile->type() == "icc") { annotation = new KisAnnotation(ICC, profile->name(), profile->rawData()); } else { annotation = new KisAnnotation(PROFILE, profile->name(), profile->rawData()); } } } if (annotation) { // save layer profile if (m_store->open(getLocation(layer, DOT_ICC))) { m_store->write(annotation->annotation()); m_store->close(); } else { return false; } } } return true; } bool KisKraSaveVisitor::saveSelection(KisNode* node) { KisSelectionSP selection; if (node->inherits("KisMask")) { selection = static_cast(node)->selection(); } else if (node->inherits("KisAdjustmentLayer")) { selection = static_cast(node)->internalSelection(); } else if (node->inherits("KisGeneratorLayer")) { selection = static_cast(node)->internalSelection(); } else { return false; } bool retval = true; if (selection->hasPixelSelection()) { KisPaintDeviceSP dev = selection->pixelSelection(); if (!savePaintDevice(dev, getLocation(node, DOT_PIXEL_SELECTION))) { m_errorMessages << i18n("Failed to save the pixel selection data for layer %1.", node->name()); retval = false; } } if (selection->hasShapeSelection()) { m_store->pushDirectory(); retval = m_store->enterDirectory(getLocation(node, DOT_SHAPE_SELECTION)); if (retval) { KisShapeSelection* shapeSelection = dynamic_cast(selection->shapeSelection()); if (!shapeSelection) { retval = false; } if (retval && !shapeSelection->saveSelection(m_store)) { m_errorMessages << i18n("Failed to save the vector selection data for layer %1.", node->name()); retval = false; } } m_store->popDirectory(); } return retval; } bool KisKraSaveVisitor::saveFilterConfiguration(KisNode* node) { KisNodeFilterInterface *filterInterface = dynamic_cast(node); - KisSafeFilterConfigurationSP filter; + KisFilterConfigurationSP filter; if (filterInterface) { filter = filterInterface->filter(); } bool retval = false; if (filter) { QString location = getLocation(node, DOT_FILTERCONFIG); if (m_store->open(location)) { QString s = filter->toXML(); retval = (m_store->write(s.toUtf8(), qstrlen(s.toUtf8())) == qstrlen(s.toUtf8())); m_store->close(); } } return retval; } bool KisKraSaveVisitor::saveMetaData(KisNode* node) { if (!node->inherits("KisLayer")) return true; KisMetaData::Store* metadata = (static_cast(node))->metaData(); if (metadata->isEmpty()) return true; // Serialize all the types of metadata there are KisMetaData::IOBackend* backend = KisMetaData::IOBackendRegistry::instance()->get("xmp"); if (!backend->supportSaving()) { dbgFile << "Backend " << backend->id() << " does not support saving."; return false; } QString location = getLocation(node, QString(".") + backend->id() + DOT_METADATA); dbgFile << "going to save " << backend->id() << ", " << backend->name() << " to " << location; QBuffer buffer; // not that the metadata backends every return anything but true... bool retval = backend->saveTo(metadata, &buffer); if (!retval) { m_errorMessages << i18n("The metadata backend failed to save the metadata for %1", node->name()); } else { QByteArray data = buffer.data(); dbgFile << "\t information size is" << data.size(); if (data.size() > 0 && m_store->open(location)) { retval = m_store->write(data, data.size()); m_store->close(); } if (!retval) { m_errorMessages << i18n("Could not write for %1 metadata to the file.", node->name()); } } return retval; } QString KisKraSaveVisitor::getLocation(KisNode* node, const QString& suffix) { Q_ASSERT(m_nodeFileNames.contains(node)); return getLocation(m_nodeFileNames[node], suffix); } QString KisKraSaveVisitor::getLocation(const QString &filename, const QString& suffix) { QString location = m_external ? QString() : m_uri; location += m_name + LAYER_PATH + filename + suffix; return location; } diff --git a/libs/ui/operations/kis_operation_configuration.h b/libs/ui/operations/kis_operation_configuration.h index f506fe710f..87791f48c3 100644 --- a/libs/ui/operations/kis_operation_configuration.h +++ b/libs/ui/operations/kis_operation_configuration.h @@ -1,36 +1,41 @@ /* * Copyright (c) 2012 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_OPERATION_CONFIGURATION_H #define __KIS_OPERATION_CONFIGURATION_H #include #include #include "kis_properties_configuration.h" class KRITAUI_EXPORT KisOperationConfiguration : public KisPropertiesConfiguration { public: KisOperationConfiguration(); + virtual ~KisOperationConfiguration() {} KisOperationConfiguration(const QString &id); QString id() const; +private: + Q_DISABLE_COPY(KisOperationConfiguration) }; +typedef KisSharedPtr KisOperationConfigurationSP; + #endif /* __KIS_OPERATION_CONFIGURATION_H */ diff --git a/libs/ui/operations/kis_operation_ui_factory.h b/libs/ui/operations/kis_operation_ui_factory.h index 3b31104591..b80cfe0d2b 100644 --- a/libs/ui/operations/kis_operation_ui_factory.h +++ b/libs/ui/operations/kis_operation_ui_factory.h @@ -1,55 +1,56 @@ /* * 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_OPERATION_UI_FACTORY_H #define KIS_OPERATION_UI_FACTORY_H #include "kritaui_export.h" #include +#include "operations/kis_operation_configuration.h" class KisViewManager; -class KisOperationConfiguration; + class KRITAUI_EXPORT KisOperationUIFactory { public: /** * Construct a Ui factory * @param id the id for the ui, has to be the same as the operation id of the KisAction */ KisOperationUIFactory(const QString &id); virtual ~KisOperationUIFactory(); /** * id for the UI registry */ QString id() const; /** * Fetch the configuration for a QWidget or other UI * @param view the view * @param configuration the into which the setting will be written */ - virtual bool fetchConfiguration(KisViewManager* view, KisOperationConfiguration* configuration) = 0; - + virtual bool fetchConfiguration(KisViewManager* view, KisOperationConfigurationSP configuration) = 0; + private: class Private; Private* const d; }; #endif // KIS_OPERATION_UI_FACTORY_H diff --git a/libs/ui/operations/kis_operation_ui_widget.h b/libs/ui/operations/kis_operation_ui_widget.h index b8a083d65a..d2dafd3775 100644 --- a/libs/ui/operations/kis_operation_ui_widget.h +++ b/libs/ui/operations/kis_operation_ui_widget.h @@ -1,54 +1,53 @@ /* * 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_OPERATION_UI_WIDGET_H #define KIS_OPERATION_UI_WIDGET_H #include #include - -class KisOperationConfiguration; +#include "operations/kis_operation_configuration.h" /** * Base class for the QWidget based operation config widgets */ class KRITAUI_EXPORT KisOperationUIWidget : public QWidget { public: explicit KisOperationUIWidget(const QString& caption, QWidget* parent = 0); virtual ~KisOperationUIWidget(); /** - * Caption of the operation widget, used in dialog caption + * Caption of the operation widget, used in dialog caption */ QString caption() const; /** * Fetch the setting from the config widet * @param config configuration to which the setting will be written */ - virtual void getConfiguration(KisOperationConfiguration* config) = 0; + virtual void getConfiguration(KisOperationConfigurationSP config) = 0; private: class Private; Private* const d; }; #endif // KIS_OPERATION_UI_WIDGET_H diff --git a/libs/ui/operations/kis_operation_ui_widget_factory.h b/libs/ui/operations/kis_operation_ui_widget_factory.h index 927ab8e5cf..a4de6dc089 100644 --- a/libs/ui/operations/kis_operation_ui_widget_factory.h +++ b/libs/ui/operations/kis_operation_ui_widget_factory.h @@ -1,71 +1,71 @@ /* * 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_OPERATION_UI_WIDGET_FACTORY_H #define KIS_OPERATION_UI_WIDGET_FACTORY_H #include #include #include "kis_operation_ui_factory.h" #include "operations/kis_operation_ui_widget.h" #include "KisViewManager.h" /** * Factory to get operation configurations from QWidget based operation widgets * T has to be a KisOperationUIWidget */ template class KisOperationUIWidgetFactory : public KisOperationUIFactory { public: KisOperationUIWidgetFactory(const QString &id) : KisOperationUIFactory(id) { } virtual ~KisOperationUIWidgetFactory() { } /** * Reimplemented. Show a dialog the widget specify as T * @param view the view * @param configuration the configuration to the operation * @returns true if the configuration could be constructed (not canceled) */ - virtual bool fetchConfiguration(KisViewManager* view, KisOperationConfiguration* configuration) { + virtual bool fetchConfiguration(KisViewManager* view, KisOperationConfigurationSP configuration) { KoDialog * dialog = new KoDialog(view->mainWindow()); Q_CHECK_PTR(dialog); T* configWidget = new T(dialog, view); dialog->setCaption(configWidget->caption()); dialog->setMainWidget(configWidget); bool success = false; if (dialog->exec() == QDialog::Accepted) { configWidget->getConfiguration(configuration); success = true; } delete dialog; return success; } }; #endif // KIS_OPERATION_UI_WIDGET_FACTORY_H diff --git a/libs/ui/ora/kis_open_raster_stack_load_visitor.cpp b/libs/ui/ora/kis_open_raster_stack_load_visitor.cpp index 222207b99d..dacdbc22a6 100644 --- a/libs/ui/ora/kis_open_raster_stack_load_visitor.cpp +++ b/libs/ui/ora/kis_open_raster_stack_load_visitor.cpp @@ -1,233 +1,234 @@ /* * Copyright (c) 2006-2007,2009 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. */ #include "kis_open_raster_stack_load_visitor.h" #include #include #include // Includes from krita/image #include #include #include #include #include #include +#include #include #include #include #include #include "KisDocument.h" #include "kis_open_raster_load_context.h" struct KisOpenRasterStackLoadVisitor::Private { KisImageWSP image; vKisNodeSP activeNodes; KisUndoStore* undoStore; KisOpenRasterLoadContext* loadContext; double xRes; double yRes; }; KisOpenRasterStackLoadVisitor::KisOpenRasterStackLoadVisitor(KisUndoStore* undoStore, KisOpenRasterLoadContext* orlc) : d(new Private) { d->undoStore = undoStore; d->loadContext = orlc; } KisOpenRasterStackLoadVisitor::~KisOpenRasterStackLoadVisitor() { delete d; } KisImageWSP KisOpenRasterStackLoadVisitor::image() { return d->image; } vKisNodeSP KisOpenRasterStackLoadVisitor::activeNodes() { return d->activeNodes; } void KisOpenRasterStackLoadVisitor::loadImage() { QDomDocument doc = d->loadContext->loadStack(); for (QDomNode node = doc.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isElement() && node.nodeName() == "image") { // it's the image root QDomElement subelem = node.toElement(); int width = 0; if (!subelem.attribute("w").isNull()) { width = subelem.attribute("w").toInt(); } int height = 0; if (!subelem.attribute("h").isNull()) { height = subelem.attribute("h").toInt(); } d->xRes = 75.0/72; // Setting the default value of the X Resolution = 75ppi if (!subelem.attribute("xres").isNull()){ d->xRes = (KisDomUtils::toDouble(subelem.attribute("xres")) / 72); } d->yRes = 75.0/72; if (!subelem.attribute("yres").isNull()){ d->yRes = (KisDomUtils::toDouble(subelem.attribute("yres")) / 72); } dbgFile << ppVar(width) << ppVar(height); d->image = new KisImage(d->undoStore, width, height, KoColorSpaceRegistry::instance()->rgb8(), "OpenRaster Image (name)"); for (QDomNode node2 = node.firstChild(); !node2.isNull(); node2 = node2.nextSibling()) { if (node2.isElement() && node2.nodeName() == "stack") { // it's the root layer ! QDomElement subelem2 = node2.toElement(); loadGroupLayer(subelem2, d->image->rootLayer()); break; } } } } } void KisOpenRasterStackLoadVisitor::loadLayerInfo(const QDomElement& elem, KisLayerSP layer) { layer->setName(elem.attribute("name")); layer->setX(elem.attribute("x").toInt()); layer->setY(elem.attribute("y").toInt()); if (elem.attribute("visibility") == "hidden") { layer->setVisible(false); } else { layer->setVisible(true); } if (elem.hasAttribute("edit-locked")) { layer->setUserLocked(elem.attribute("edit-locked") == "true"); } if (elem.hasAttribute("selected") && elem.attribute("selected") == "true") { d->activeNodes.append(layer); } QString compop = elem.attribute("composite-op"); if (compop.startsWith("svg:")) { if (compop == "svg:clear") layer->setCompositeOpId(COMPOSITE_CLEAR); if (compop == "svg:src-over") layer->setCompositeOpId(COMPOSITE_OVER); if (compop == "svg:add") layer->setCompositeOpId(COMPOSITE_ADD); if (compop == "svg:multiply") layer->setCompositeOpId(COMPOSITE_MULT); if (compop == "svg:screen") layer->setCompositeOpId(COMPOSITE_SCREEN); if (compop == "svg:overlay") layer->setCompositeOpId(COMPOSITE_OVERLAY); if (compop == "svg:darken") layer->setCompositeOpId(COMPOSITE_DARKEN); if (compop == "svg:lighten") layer->setCompositeOpId(COMPOSITE_LIGHTEN); if (compop == "svg:color-dodge") layer->setCompositeOpId(COMPOSITE_DODGE); if (compop == "svg:color-burn") layer->setCompositeOpId(COMPOSITE_BURN); if (compop == "svg:hard-light") layer->setCompositeOpId(COMPOSITE_HARD_LIGHT); if (compop == "svg:soft-light") layer->setCompositeOpId(COMPOSITE_SOFT_LIGHT_SVG); if (compop == "svg:difference") layer->setCompositeOpId(COMPOSITE_DIFF); if (compop == "svg:color") layer->setCompositeOpId(COMPOSITE_COLOR); if (compop == "svg:luminosity") layer->setCompositeOpId(COMPOSITE_LUMINIZE); if (compop == "svg:hue") layer->setCompositeOpId(COMPOSITE_HUE); if (compop == "svg:saturation") layer->setCompositeOpId(COMPOSITE_SATURATION); if (compop == "svg:exclusion") layer->setCompositeOpId(COMPOSITE_EXCLUSION); } else if (compop.startsWith("krita:")) { compop = compop.remove(0, 6); layer->setCompositeOpId(compop); } else { // to fix old bugs in krita's ora export if (compop == "color-dodge") layer->setCompositeOpId(COMPOSITE_DODGE); if (compop == "difference") layer->setCompositeOpId(COMPOSITE_DIFF); } } void KisOpenRasterStackLoadVisitor::loadAdjustmentLayer(const QDomElement& elem, KisAdjustmentLayerSP aL) { loadLayerInfo(elem, aL); } void KisOpenRasterStackLoadVisitor::loadPaintLayer(const QDomElement& elem, KisPaintLayerSP pL) { loadLayerInfo(elem, pL); dbgFile << "Loading was unsuccessful"; } void KisOpenRasterStackLoadVisitor::loadGroupLayer(const QDomElement& elem, KisGroupLayerSP gL) { dbgFile << "Loading group layer"; loadLayerInfo(elem, gL); for (QDomNode node = elem.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isElement()) { QDomElement subelem = node.toElement(); if (node.nodeName() == "stack") { double opacity = 1.0; if (!subelem.attribute("opacity").isNull()) { opacity = KisDomUtils::toDouble(subelem.attribute("opacity", "1.0")); } KisGroupLayerSP layer = new KisGroupLayer(d->image, "", opacity * 255); d->image->addNode(layer.data(), gL.data(), 0); loadGroupLayer(subelem, layer); } else if (node.nodeName() == "layer") { QString filename = subelem.attribute("src"); if (!filename.isNull()) { double opacity = 1.0; opacity = KisDomUtils::toDouble(subelem.attribute("opacity", "1.0")); KisImageWSP pngImage = d->loadContext->loadDeviceData(filename); if (pngImage) { // If ORA doesn't have resolution info, load the default value(75 ppi) else fetch from stack.xml d->image->setResolution(d->xRes, d->yRes); // now get the device KisPaintDeviceSP device = pngImage->projection(); delete pngImage.data(); KisPaintLayerSP layer = new KisPaintLayer(gL->image() , "", opacity * 255, device); d->image->addNode(layer.data(), gL.data(), 0); loadPaintLayer(subelem, layer); dbgFile << "Loading was successful"; } } } else if (node.nodeName() == "filter") { QString filterType = subelem.attribute("type"); QStringList filterTypeSplit = filterType.split(':'); KisFilterSP f = 0; if (filterTypeSplit[0] == "applications" && filterTypeSplit[1] == "krita") { f = KisFilterRegistry::instance()->value(filterTypeSplit[2]); } - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); KisAdjustmentLayerSP layer = new KisAdjustmentLayer(gL->image() , "", kfc, KisSelectionSP(0)); d->image->addNode(layer.data(), gL.data(), 0); loadAdjustmentLayer(subelem, layer); } else { dbgFile << "Unknown element : " << node.nodeName(); } } } } diff --git a/libs/ui/recorder/kis_recorded_filter_action_creator.cpp b/libs/ui/recorder/kis_recorded_filter_action_creator.cpp index 844a2bfbc8..60b768be53 100644 --- a/libs/ui/recorder/kis_recorded_filter_action_creator.cpp +++ b/libs/ui/recorder/kis_recorded_filter_action_creator.cpp @@ -1,75 +1,77 @@ /* * Copyright (c) 2011 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. */ #include "kis_recorded_filter_action_creator.h" #include #include #include #include #include #include #include #include #include +#include - -KisRecordedFilterActionCreator::KisRecordedFilterActionCreator(QWidget* parent , Qt::WindowFlags f) : KisRecordedActionCreator(parent, f) +KisRecordedFilterActionCreator::KisRecordedFilterActionCreator(QWidget* parent , Qt::WindowFlags f) + : KisRecordedActionCreator(parent, f) { m_filterModel = new KisFiltersModel(true, 0); m_filterTree = new QTreeView(this); m_filterTree->setModel(m_filterModel); m_filterTree->header()->setVisible(false); QGridLayout* layout = new QGridLayout(); setLayout(layout); layout->addWidget(m_filterTree, 0, 0, 1, 1); } KisRecordedFilterActionCreator::~KisRecordedFilterActionCreator() { delete m_filterTree; delete m_filterModel; } KisRecordedAction* KisRecordedFilterActionCreator::createAction() const { const KisFilter* filter = m_filterModel->indexToFilter(m_filterTree->currentIndex()); if(!filter) return 0; return new KisRecordedFilterAction(filter->name(), KisNodeQueryPath::fromString(""), filter, filter->defaultConfiguration(0)); } -KisRecordedFilterActionCreatorFactory::KisRecordedFilterActionCreatorFactory() : KisRecordedActionCreatorFactory("filter", i18nc("recorded filter action", "Apply Filter")) +KisRecordedFilterActionCreatorFactory::KisRecordedFilterActionCreatorFactory() + : KisRecordedActionCreatorFactory("filter", i18nc("recorded filter action", "Apply Filter")) { } KisRecordedFilterActionCreatorFactory::~KisRecordedFilterActionCreatorFactory() { } bool KisRecordedFilterActionCreatorFactory::requireCreator() const { - return true; + return true; } KisRecordedActionCreator* KisRecordedFilterActionCreatorFactory::createCreator(QWidget* parent) const { - return new KisRecordedFilterActionCreator(parent); + return new KisRecordedFilterActionCreator(parent); } diff --git a/libs/ui/recorder/kis_recorded_filter_action_editor.cc b/libs/ui/recorder/kis_recorded_filter_action_editor.cc index 1a9e33479b..82a39ae679 100644 --- a/libs/ui/recorder/kis_recorded_filter_action_editor.cc +++ b/libs/ui/recorder/kis_recorded_filter_action_editor.cc @@ -1,96 +1,97 @@ /* * Copyright (c) 2009 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. */ +#include #include "kis_recorded_filter_action_editor.h" #include #include #include #include #include #include #include #include "kis_node_query_path_editor.h" #include #include KisRecordedFilterActionEditor::KisRecordedFilterActionEditor(QWidget* parent, KisRecordedAction* action) : QWidget(parent) , m_action(dynamic_cast(action)) , m_gridLayout(new QGridLayout(this)) { Q_ASSERT(m_action); // Create the node query path editor m_nodeQueryPathEditor = new KisNodeQueryPathEditor(this); m_nodeQueryPathEditor->setNodeQueryPath(m_action->nodeQueryPath()); connect(m_nodeQueryPathEditor, SIGNAL(nodeQueryPathChanged()), SLOT(nodeQueryPathChanged())); m_gridLayout->addWidget(m_nodeQueryPathEditor, 1, 0); // Create the filter editor m_configWidget = m_action->filter()->createConfigurationWidget(this, new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8())); if (m_configWidget) { m_gridLayout->addWidget(m_configWidget); // FIXME: pass the view object to the config widget //m_configWidget->setView(view); m_configWidget->setConfiguration(m_action->filterConfiguration()); connect(m_configWidget, SIGNAL(sigConfigurationItemChanged()), SLOT(configurationUpdated())); } else { m_gridLayout->addWidget(new QLabel(i18n("No configuration option."), this)); } } KisRecordedFilterActionEditor::~KisRecordedFilterActionEditor() { } void KisRecordedFilterActionEditor::configurationUpdated() { - KisFilterConfiguration* config = dynamic_cast(m_configWidget->configuration()); + KisFilterConfigurationSP config = dynamic_cast(m_configWidget->configuration().data()); if (config) { m_action->setFilterConfiguration(config); emit(actionEdited()); } } void KisRecordedFilterActionEditor::nodeQueryPathChanged() { m_action->setNodeQueryPath(m_nodeQueryPathEditor->nodeQueryPath()); emit(actionEdited()); } KisRecordedFilterActionEditorFactory::KisRecordedFilterActionEditorFactory() { } KisRecordedFilterActionEditorFactory::~KisRecordedFilterActionEditorFactory() { } QWidget* KisRecordedFilterActionEditorFactory::createEditor(QWidget* parent, KisRecordedAction* action) const { return new KisRecordedFilterActionEditor(parent, action); } bool KisRecordedFilterActionEditorFactory::canEdit(const KisRecordedAction* action) const { return action->id() == "FilterAction"; } diff --git a/libs/ui/tests/filter_stroke_test.cpp b/libs/ui/tests/filter_stroke_test.cpp index 81e5c02ca5..5f2c80efae 100644 --- a/libs/ui/tests/filter_stroke_test.cpp +++ b/libs/ui/tests/filter_stroke_test.cpp @@ -1,93 +1,93 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "filter_stroke_test.h" #include #include "stroke_testing_utils.h" #include "strokes/kis_filter_stroke_strategy.h" #include "kis_resources_snapshot.h" #include "kis_image.h" #include "filter/kis_filter.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" class FilterStrokeTester : public utils::StrokeTester { public: FilterStrokeTester(const QString &filterName) : StrokeTester(QString("filter_") + filterName, QSize(500, 500), ""), m_filterName(filterName) { setBaseFuzziness(5); } protected: using utils::StrokeTester::initImage; using utils::StrokeTester::addPaintingJobs; void initImage(KisImageWSP image, KisNodeSP activeNode) { QImage src(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); activeNode->original()->convertFromQImage(src, 0); image->refreshGraph(); } KisStrokeStrategy* createStroke(bool indirectPainting, KisResourcesSnapshotSP resources, KisImageWSP image) { Q_UNUSED(image); Q_UNUSED(indirectPainting); KisFilterSP filter = KisFilterRegistry::instance()->value(m_filterName); Q_ASSERT(filter); - KisFilterConfiguration *filterConfig = filter->defaultConfiguration(0); + KisFilterConfigurationSP filterConfig = filter->defaultConfiguration(0); Q_ASSERT(filterConfig); - return new KisFilterStrokeStrategy(filter, KisSafeFilterConfigurationSP(filterConfig), resources); + return new KisFilterStrokeStrategy(filter, KisFilterConfigurationSP(filterConfig), resources); } void addPaintingJobs(KisImageWSP image, KisResourcesSnapshotSP resources) { Q_UNUSED(resources); image->addJob(strokeId(), new KisFilterStrokeStrategy:: Data(QRect(100,100,100,100), true)); image->addJob(strokeId(), new KisFilterStrokeStrategy:: Data(QRect(200,100,100,100), true)); image->addJob(strokeId(), new KisFilterStrokeStrategy:: Data(QRect(100,200,100,100), true)); } private: QString m_filterName; }; void FilterStrokeTest::testBlurFilter() { FilterStrokeTester tester("blur"); tester.test(); } QTEST_MAIN(FilterStrokeTest) diff --git a/libs/ui/tests/kis_kra_saver_test.cpp b/libs/ui/tests/kis_kra_saver_test.cpp index b77bfeee69..931db2019b 100644 --- a/libs/ui/tests/kis_kra_saver_test.cpp +++ b/libs/ui/tests/kis_kra_saver_test.cpp @@ -1,401 +1,401 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_kra_saver_test.h" #include #include #include #include #include #include #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter.h" #include "KisDocument.h" #include "kis_image.h" #include "kis_pixel_selection.h" #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "kis_clone_layer.h" #include "kis_adjustment_layer.h" #include "kis_shape_layer.h" #include "kis_filter_mask.h" #include "kis_transparency_mask.h" #include "kis_selection_mask.h" #include "kis_selection.h" #include "kis_fill_painter.h" #include "kis_shape_selection.h" #include "util.h" #include "testutil.h" #include "kis_keyframe_channel.h" #include "kis_image_animation_interface.h" #include "kis_layer_properties_icons.h" #include "kis_transform_mask_params_interface.h" #include #include void KisKraSaverTest::initTestCase() { KisFilterRegistry::instance(); KisGeneratorRegistry::instance(); } void KisKraSaverTest::testRoundTrip() { KisDocument* doc = createCompleteDocument(); KoColor bgColor(Qt::red, doc->image()->colorSpace()); doc->image()->setDefaultProjectionColor(bgColor); doc->saveNativeFormat("roundtriptest.kra"); QStringList list; KisCountVisitor cv1(list, KoProperties()); doc->image()->rootLayer()->accept(cv1); KisDocument *doc2 = KisPart::instance()->createDocument(); doc2->loadNativeFormat("roundtriptest.kra"); KisCountVisitor cv2(list, KoProperties()); doc2->image()->rootLayer()->accept(cv2); QCOMPARE(cv1.count(), cv2.count()); // check whether the BG color is saved correctly QCOMPARE(doc2->image()->defaultProjectionColor(), bgColor); // test round trip of a transform mask KisNodeSP tnode = TestUtil::findNode(doc2->image()->rootLayer(), "testTransformMask"); QVERIFY(tnode); KisTransformMask *tmask = dynamic_cast(tnode.data()); QVERIFY(tmask); KisDumbTransformMaskParams *params = dynamic_cast(tmask->transformParams().data()); QVERIFY(params); QTransform t = params->testingGetTransform(); QCOMPARE(t, createTestingTransform()); delete doc2; delete doc; } void KisKraSaverTest::testSaveEmpty() { KisDocument* doc = createEmptyDocument(); doc->saveNativeFormat("emptytest.kra"); QStringList list; KisCountVisitor cv1(list, KoProperties()); doc->image()->rootLayer()->accept(cv1); KisDocument *doc2 = KisPart::instance()->createDocument(); doc2->loadNativeFormat("emptytest.kra"); KisCountVisitor cv2(list, KoProperties()); doc2->image()->rootLayer()->accept(cv2); QCOMPARE(cv1.count(), cv2.count()); delete doc2; delete doc; } #include #include "generator/kis_generator_registry.h" #include -void testRoundTripFillLayerImpl(const QString &testName, KisFilterConfiguration *config) +void testRoundTripFillLayerImpl(const QString &testName, KisFilterConfigurationSP config) { TestUtil::ExternalImageChecker chk(testName, "fill_layer"); QRect refRect(0,0,512,512); TestUtil::MaskParent p(refRect); QScopedPointer doc(KisPart::instance()->createDocument()); doc->setCurrentImage(p.image); doc->documentInfo()->setAboutInfo("title", p.image->objectName()); KisSelectionSP selection; KisGeneratorLayerSP glayer = new KisGeneratorLayer(p.image, "glayer", config, selection); p.image->addNode(glayer, p.image->root(), KisNodeSP()); glayer->setDirty(); p.image->waitForDone(); chk.checkImage(p.image, "00_initial_layer_update"); doc->saveNativeFormat("roundtrip_fill_layer_test.kra"); QScopedPointer doc2(KisPart::instance()->createDocument()); doc2->loadNativeFormat("roundtrip_fill_layer_test.kra"); doc2->image()->waitForDone(); chk.checkImage(doc2->image(), "01_fill_layer_round_trip"); QVERIFY(chk.testPassed()); } void KisKraSaverTest::testRoundTripFillLayerColor() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisGeneratorSP generator = KisGeneratorRegistry::instance()->get("color"); Q_ASSERT(generator); // warning: we pass null paint device to the default constructed value - KisFilterConfiguration *config = generator->factoryConfiguration(0); + KisFilterConfigurationSP config = generator->factoryConfiguration(0); Q_ASSERT(config); QVariant v; v.setValue(KoColor(Qt::red, cs)); config->setProperty("color", v); testRoundTripFillLayerImpl("fill_layer_color", config); } void KisKraSaverTest::testRoundTripFillLayerPattern() { KisGeneratorSP generator = KisGeneratorRegistry::instance()->get("pattern"); Q_ASSERT(generator); // warning: we pass null paint device to the default constructed value - KisFilterConfiguration *config = generator->factoryConfiguration(0); + KisFilterConfigurationSP config = generator->factoryConfiguration(0); Q_ASSERT(config); QVariant v; v.setValue(QString("11_drawed_furry.png")); config->setProperty("pattern", v); testRoundTripFillLayerImpl("fill_layer_pattern", config); } #include "kis_psd_layer_style.h" void KisKraSaverTest::testRoundTripLayerStyles() { TestUtil::ExternalImageChecker chk("kra_saver_test", "layer_styles"); QRect imageRect(0,0,512,512); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image"); KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisPaintLayerSP layer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisPaintLayerSP layer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); image->addNode(layer1); image->addNode(layer2); image->addNode(layer3); QScopedPointer doc(KisPart::instance()->createDocument()); doc->setCurrentImage(image); doc->documentInfo()->setAboutInfo("title", image->objectName()); layer1->paintDevice()->fill(QRect(100, 100, 100, 100), KoColor(Qt::red, cs)); layer2->paintDevice()->fill(QRect(200, 200, 100, 100), KoColor(Qt::green, cs)); layer3->paintDevice()->fill(QRect(300, 300, 100, 100), KoColor(Qt::blue, cs)); KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->dropShadow()->setEffectEnabled(true); style->dropShadow()->setAngle(-90); style->dropShadow()->setUseGlobalLight(false); layer1->setLayerStyle(style->clone()); style->dropShadow()->setAngle(180); style->dropShadow()->setUseGlobalLight(true); layer2->setLayerStyle(style->clone()); style->dropShadow()->setAngle(90); style->dropShadow()->setUseGlobalLight(false); layer3->setLayerStyle(style->clone()); image->initialRefreshGraph(); chk.checkImage(image, "00_initial_layers"); doc->saveNativeFormat("roundtrip_layer_styles.kra"); QScopedPointer doc2(KisPart::instance()->createDocument()); doc2->loadNativeFormat("roundtrip_layer_styles.kra"); doc2->image()->waitForDone(); chk.checkImage(doc2->image(), "00_initial_layers"); QVERIFY(chk.testPassed()); } void KisKraSaverTest::testRoundTripAnimation() { QRect imageRect(0,0,512,512); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image"); KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); image->addNode(layer1); layer1->paintDevice()->fill(QRect(100, 100, 50, 50), KoColor(Qt::black, cs)); layer1->paintDevice()->setDefaultPixel(KoColor(Qt::red, cs)); KUndo2Command parentCommand; KisKeyframeChannel *rasterChannel = layer1->getKeyframeChannel(KisKeyframeChannel::Content.id()); rasterChannel->addKeyframe(10, &parentCommand); image->animationInterface()->switchCurrentTimeAsync(10); image->waitForDone(); layer1->paintDevice()->fill(QRect(200, 50, 10, 10), KoColor(Qt::black, cs)); layer1->paintDevice()->moveTo(25, 15); layer1->paintDevice()->setDefaultPixel(KoColor(Qt::green, cs)); rasterChannel->addKeyframe(20, &parentCommand); image->animationInterface()->switchCurrentTimeAsync(20); image->waitForDone(); layer1->paintDevice()->fill(QRect(150, 200, 30, 30), KoColor(Qt::black, cs)); layer1->paintDevice()->moveTo(100, 50); layer1->paintDevice()->setDefaultPixel(KoColor(Qt::blue, cs)); QScopedPointer doc(KisPart::instance()->createDocument()); doc->setCurrentImage(image); doc->saveNativeFormat("roundtrip_animation.kra"); QScopedPointer doc2(KisPart::instance()->createDocument()); doc2->loadNativeFormat("roundtrip_animation.kra"); KisImageSP image2 = doc2->image(); KisNodeSP node = image2->root()->firstChild(); QVERIFY(node->inherits("KisPaintLayer")); KisPaintLayerSP layer2 = qobject_cast(node.data()); cs = layer2->paintDevice()->colorSpace(); QCOMPARE(image2->animationInterface()->currentTime(), 20); KisKeyframeChannel *channel = layer2->getKeyframeChannel(KisKeyframeChannel::Content.id()); QCOMPARE(channel->keyframeCount(), 3); image2->animationInterface()->switchCurrentTimeAsync(0); image2->waitForDone(); QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(64, 64, 128, 128)); QCOMPARE(layer2->paintDevice()->x(), 0); QCOMPARE(layer2->paintDevice()->y(), 0); QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::red, cs)); image2->animationInterface()->switchCurrentTimeAsync(10); image2->waitForDone(); QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(217, 15, 64, 64)); QCOMPARE(layer2->paintDevice()->x(), 25); QCOMPARE(layer2->paintDevice()->y(), 15); QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::green, cs)); image2->animationInterface()->switchCurrentTimeAsync(20); image2->waitForDone(); QCOMPARE(layer2->paintDevice()->nonDefaultPixelArea(), QRect(228, 242, 64, 64)); QCOMPARE(layer2->paintDevice()->x(), 100); QCOMPARE(layer2->paintDevice()->y(), 50); QCOMPARE(layer2->paintDevice()->defaultPixel(), KoColor(Qt::blue, cs)); } #include "lazybrush/kis_lazy_fill_tools.h" void KisKraSaverTest::testRoundTripColorizeMask() { QRect imageRect(0,0,512,512); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); const KoColorSpace * weirdCS = KoColorSpaceRegistry::instance()->rgb16(); QScopedPointer doc(KisPart::instance()->createDocument()); KisImageSP image = new KisImage(new KisSurrogateUndoStore(), imageRect.width(), imageRect.height(), cs, "test image"); doc->setCurrentImage(image); KisPaintLayerSP layer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, weirdCS); image->addNode(layer1); KisColorizeMaskSP mask = new KisColorizeMask(); image->addNode(mask, layer1); mask->initializeCompositeOp(); mask->setColorSpace(layer1->colorSpace()); { KisPaintDeviceSP key1 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); key1->fill(QRect(50,50,10,20), KoColor(Qt::black, key1->colorSpace())); mask->testingAddKeyStroke(key1, KoColor(Qt::green, layer1->colorSpace())); // KIS_DUMP_DEVICE_2(key1, refRect, "key1", "dd"); } { KisPaintDeviceSP key2 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); key2->fill(QRect(150,50,10,20), KoColor(Qt::black, key2->colorSpace())); mask->testingAddKeyStroke(key2, KoColor(Qt::red, layer1->colorSpace())); // KIS_DUMP_DEVICE_2(key2, refRect, "key2", "dd"); } { KisPaintDeviceSP key3 = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); key3->fill(QRect(0,0,10,10), KoColor(Qt::black, key3->colorSpace())); mask->testingAddKeyStroke(key3, KoColor(Qt::blue, layer1->colorSpace()), true); // KIS_DUMP_DEVICE_2(key3, refRect, "key3", "dd"); } KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, false, image); KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, false, image); doc->saveNativeFormat("roundtrip_colorize.kra"); QScopedPointer doc2(KisPart::instance()->createDocument()); doc2->loadNativeFormat("roundtrip_colorize.kra"); KisImageSP image2 = doc2->image(); KisNodeSP node = image2->root()->firstChild()->firstChild(); KisColorizeMaskSP mask2 = dynamic_cast(node.data()); QVERIFY(mask2); QCOMPARE(mask2->compositeOpId(), mask->compositeOpId()); QCOMPARE(mask2->colorSpace(), mask->colorSpace()); QCOMPARE(KisLayerPropertiesIcons::nodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool(), false); QCOMPARE(KisLayerPropertiesIcons::nodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, true).toBool(), false); QList strokes = mask->fetchKeyStrokesDirect(); qDebug() << ppVar(strokes.size()); QCOMPARE(strokes[0].dev->exactBounds(), QRect(50,50,10,20)); QCOMPARE(strokes[0].isTransparent, false); QCOMPARE(strokes[0].color.colorSpace(), weirdCS); QCOMPARE(strokes[1].dev->exactBounds(), QRect(150,50,10,20)); QCOMPARE(strokes[1].isTransparent, false); QCOMPARE(strokes[1].color.colorSpace(), weirdCS); QCOMPARE(strokes[2].dev->exactBounds(), QRect(0,0,10,10)); QCOMPARE(strokes[2].isTransparent, true); QCOMPARE(strokes[2].color.colorSpace(), weirdCS); } QTEST_MAIN(KisKraSaverTest) diff --git a/libs/ui/tests/kis_node_manager_test.cpp b/libs/ui/tests/kis_node_manager_test.cpp index b113a5175f..b1685a86e7 100644 --- a/libs/ui/tests/kis_node_manager_test.cpp +++ b/libs/ui/tests/kis_node_manager_test.cpp @@ -1,291 +1,291 @@ /* * Copyright (c) 2012 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_node_manager_test.h" #include - +#include #include "ui_manager_test.h" class NodeManagerTester : public TestUtil::UiManagerTest { public: NodeManagerTester() : UiManagerTest(false, true, "node_manager_test") { nodeManager = view->nodeManager(); } void activateShapeLayer() { KisNodeSP shape = findNode(image->root(), "shape"); Q_ASSERT(shape); nodeManager->slotNonUiActivatedNode(shape); } KisNodeSP findCloneLayer() { return findNode(image->root(), "clone1"); } void activateCloneLayer() { KisNodeSP node = findCloneLayer(); Q_ASSERT(node); nodeManager->slotNonUiActivatedNode(findCloneLayer()); } KisNodeSP findBlurLayer() { return findNode(image->root(), "blur1"); } void activateBlurLayer() { KisNodeSP node = findBlurLayer(); Q_ASSERT(node); nodeManager->slotNonUiActivatedNode(findBlurLayer()); } void checkUndoWait() { undoStore->undo(); QTest::qWait(1000); image->waitForDone(); QVERIFY(checkLayersInitial()); } KisNodeManager *nodeManager; }; void testRotateNode(bool useShapeLayer, const QString &name) { NodeManagerTester t; if(useShapeLayer) { t.activateShapeLayer(); } t.nodeManager->rotate(M_PI / 6.0); QTest::qWait(1000); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy(name)); t.checkUndoWait(); t.startConcurrentTask(); t.nodeManager->rotate(M_PI / 6.0); QTest::qWait(1000); t.image->waitForDone(); if (!useShapeLayer) { QEXPECT_FAIL("", "The user may run Rotate Layer concurrently. It will cause wrong image/selection size fetched for the crop. There is some barrier needed. At least it doesn't crash.", Continue); } QVERIFY(t.checkLayersFuzzy(name)); } void testShearNode(bool useShapeLayer, const QString &name) { NodeManagerTester t; if(useShapeLayer) { t.activateShapeLayer(); } t.nodeManager->shear(30, 0); QTest::qWait(1000); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy(name)); t.checkUndoWait(); t.startConcurrentTask(); t.nodeManager->shear(30, 0); QTest::qWait(1000); t.image->waitForDone(); QEXPECT_FAIL("", "The user may run Shear Layer concurrently. It will cause wrong image/selection size fetched for the crop. There is some barrier needed. At least it doesn't crash.", Continue); QVERIFY(t.checkLayersFuzzy(name)); } void testScaleNode(bool useShapeLayer, const QString &name) { KisFilterStrategy *strategy = new KisBicubicFilterStrategy(); NodeManagerTester t; if(useShapeLayer) { t.activateShapeLayer(); } t.nodeManager->scale(0.5, 0.5, strategy); QTest::qWait(1000); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy(name)); t.checkUndoWait(); t.startConcurrentTask(); t.nodeManager->scale(0.5, 0.5, strategy); QTest::qWait(1000); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy(name)); delete strategy; } void testMirrorNode(bool useShapeLayer, const QString &name, bool mirrorX) { NodeManagerTester t; if(useShapeLayer) { t.activateShapeLayer(); } if (mirrorX) { t.nodeManager->mirrorNodeX(); } else { t.nodeManager->mirrorNodeY(); } QTest::qWait(1000); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy(name)); t.checkUndoWait(); t.startConcurrentTask(); if (mirrorX) { t.nodeManager->mirrorNodeX(); } else { t.nodeManager->mirrorNodeY(); } QTest::qWait(1000); t.image->waitForDone(); QEXPECT_FAIL("", "The user may run Mirror Layer concurrently, but it is not ported to strokes yet. At least it doesn't crash.", Continue); QVERIFY(t.checkLayersFuzzy(name)); } void KisNodeManagerTest::testRotatePaintNode() { testRotateNode(false, "paint_rotated_30"); } void KisNodeManagerTest::testShearPaintNode() { testShearNode(false, "paint_shear_30"); } void KisNodeManagerTest::testScalePaintNode() { testScaleNode(false, "paint_scale_0.5"); } void KisNodeManagerTest::testMirrorXPaintNode() { testMirrorNode(false, "paint_mirrorX", true); } void KisNodeManagerTest::testMirrorYPaintNode() { testMirrorNode(false, "paint_mirrorY", false); } void KisNodeManagerTest::testRotateShapeNode() { testRotateNode(true, "shape_rotated_30"); } void KisNodeManagerTest::testShearShapeNode() { testShearNode(true, "shape_shear_30"); } void KisNodeManagerTest::testScaleShapeNode() { testScaleNode(true, "shape_scale_0.5"); } void KisNodeManagerTest::testMirrorShapeNode() { testMirrorNode(true, "shape_mirrorX", true); } void KisNodeManagerTest::testConvertCloneToPaintLayer() { NodeManagerTester t; t.activateCloneLayer(); QVERIFY(t.checkLayersInitial()); t.nodeManager->convertNode("KisPaintLayer"); KisNodeSP node = t.findCloneLayer(); QTest::qWait(1000); t.image->waitForDone(); QVERIFY(dynamic_cast(node.data())); // No visible change should happen! QVERIFY(t.checkLayersInitial()); } void testConvertToSelectionMask(bool fromClone) { NodeManagerTester t; if (fromClone) { t.activateCloneLayer(); } else { t.activateBlurLayer(); } QVERIFY(t.checkLayersInitial()); QVERIFY(!t.image->globalSelection()); t.nodeManager->convertNode("KisSelectionMask"); QTest::qWait(1000); t.image->waitForDone(); KisNodeSP node; if (fromClone) { node = t.findCloneLayer(); } else { node = t.findBlurLayer(); } QVERIFY(!node); KisSelectionSP selection = t.image->globalSelection(); QVERIFY(selection); QVERIFY(!selection->outlineCacheValid() || !selection->outlineCache().isEmpty()); QString testName = fromClone ? "selection_from_clone_layer" : "selection_from_blur_layer"; QVERIFY(t.checkSelectionOnly(testName)); } void KisNodeManagerTest::testConvertCloneToSelectionMask() { testConvertToSelectionMask(true); } void KisNodeManagerTest::testConvertBlurToSelectionMask() { testConvertToSelectionMask(false); } QTEST_MAIN(KisNodeManagerTest) diff --git a/libs/ui/tests/kis_selection_manager_test.cpp b/libs/ui/tests/kis_selection_manager_test.cpp index db638c5eba..d35731b86c 100644 --- a/libs/ui/tests/kis_selection_manager_test.cpp +++ b/libs/ui/tests/kis_selection_manager_test.cpp @@ -1,418 +1,418 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_selection_manager_test.h" #include #include #include "ui_manager_test.h" class SelectionManagerTester : public TestUtil::UiManagerTest { public: SelectionManagerTester(bool useSelection) : UiManagerTest(useSelection, false, "selection_manager_test") { Q_ASSERT(selectionManager); } }; void KisSelectionManagerTest::testFillForegroundWithoutSelection() { SelectionManagerTester t(false); t.selectionManager->fillForegroundColor(); t.image->waitForDone(); QVERIFY(t.checkLayers("fill_foreground_without_selection")); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->fillForegroundColor(); t.image->waitForDone(); QVERIFY(t.checkLayers("fill_foreground_without_selection")); } void KisSelectionManagerTest::testFillForegroundWithSelection() { SelectionManagerTester t(true); t.selectionManager->fillForegroundColor(); t.image->waitForDone(); QVERIFY(t.checkLayers("fill_foreground_with_selection")); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->fillForegroundColor(); t.image->waitForDone(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); QVERIFY(t.checkLayers("fill_foreground_with_selection")); } void KisSelectionManagerTest::testFillBackgroundWithSelection() { SelectionManagerTester t(true); t.selectionManager->fillBackgroundColor(); t.image->waitForDone(); QVERIFY(t.checkLayers("fill_background_with_selection")); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->fillBackgroundColor(); t.image->waitForDone(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); QVERIFY(t.checkLayers("fill_background_with_selection")); } void KisSelectionManagerTest::testFillPatternWithSelection() { SelectionManagerTester t(true); t.selectionManager->fillPattern(); t.image->waitForDone(); QVERIFY(t.checkLayers("fill_pattern_with_selection")); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->fillPattern(); t.image->waitForDone(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); QVERIFY(t.checkLayers("fill_pattern_with_selection")); } void KisSelectionManagerTest::testResizeToSelection() { SelectionManagerTester t(true); t.selectionManager->imageResizeToSelection(); t.image->waitForDone(); QVERIFY(t.checkLayers("resize_to_selection")); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->imageResizeToSelection(); t.image->waitForDone(); QEXPECT_FAIL("", "The user may run Resize to Selection concurrently. It will cause wrong image/selection size fetched for the crop. There is some barrier needed. At least it doesn't crash.", Continue); QVERIFY(t.checkLayers("resize_to_selection")); } void KisSelectionManagerTest::testSelectAll() { SelectionManagerTester t(true); t.selectionManager->selectAll(); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("select_all")); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->selectAll(); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("select_all")); } void KisSelectionManagerTest::testDeselectReselect() { SelectionManagerTester t(true); t.selectionManager->deselect(); t.image->waitForDone(); QVERIFY(t.checkNoSelection()); t.checkUndo(); t.startConcurrentTask(); t.selectionManager->deselect(); t.image->waitForDone(); QVERIFY(t.checkNoSelection()); t.selectionManager->reselect(); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("initial")); t.undoStore->undo(); t.image->waitForDone(); QVERIFY(t.checkNoSelection()); t.startConcurrentTask(); t.selectionManager->reselect(); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("initial")); } void KisSelectionManagerTest::testCopyPaste() { SelectionManagerTester t(true); t.selectionManager->copy(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayers("copy_paste")); t.checkUndo(); t.startConcurrentTask(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.selectionManager->copy(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayers("copy_paste")); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.checkUndo(); t.startConcurrentTask(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayers("copy_paste")); } void KisSelectionManagerTest::testCopyPasteMerged() { SelectionManagerTester t(true); t.selectionManager->copyMerged(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy("copy_paste_merged")); t.checkUndo(); t.startConcurrentTask(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.selectionManager->copyMerged(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayersFuzzy("copy_paste_merged")); } void KisSelectionManagerTest::testCutPaste() { SelectionManagerTester t(true); t.selectionManager->cut(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayers("cut_paste")); t.checkDoubleUndo(); t.startConcurrentTask(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); t.selectionManager->cut(); t.selectionManager->paste(); t.image->waitForDone(); QVERIFY(t.checkLayers("cut_paste")); } void KisSelectionManagerTest::testInvertSelection() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("invertselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("invertselection"); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkLayers("invert_selection")); t.checkUndo(); t.startConcurrentTask(); QEXPECT_FAIL("", "Fix some race condition on clone layers!", Continue); config = new KisOperationConfiguration("invertselection"); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkLayers("invert_selection")); } void KisSelectionManagerTest::testFeatherSelection() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("featherselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("featherselection"); config->setProperty("radius", 10); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("feather_selection")); t.checkUndo(); t.startConcurrentTask(); config = new KisOperationConfiguration("featherselection"); config->setProperty("radius", 10); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("feather_selection")); } void KisSelectionManagerTest::testGrowSelectionSimplified() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("growselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("growselection"); config->setProperty("x-radius", 10); config->setProperty("y-radius", 5); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("grow_selection")); } void KisSelectionManagerTest::testShrinkSelectionUnlockedSimplified() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("shrinkselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("shrinkselection"); config->setProperty("x-radius", 10); config->setProperty("y-radius", 5); config->setProperty("edgeLock", false); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("shrink_selection_unlocked")); } void KisSelectionManagerTest::testShrinkSelectionLockedSimplified() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("shrinkselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("shrinkselection"); config->setProperty("x-radius", 10); config->setProperty("y-radius", 5); config->setProperty("edgeLock", true); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("shrink_selection_locked")); } void KisSelectionManagerTest::testSmoothSelectionSimplified() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("smoothselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("smoothselection"); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("smooth_selection")); } void KisSelectionManagerTest::testErodeSelectionSimplified() { // SelectionManagerTester t(true); // // t.selectionManager->erode(); // t.image->waitForDone(); // QVERIFY(t.checkSelectionOnly("erode_selection")); } void KisSelectionManagerTest::testDilateSelectionSimplified() { // SelectionManagerTester t(true); // // t.selectionManager->dilate(); // t.image->waitForDone(); // QVERIFY(t.checkSelectionOnly("dilate_selection")); } void KisSelectionManagerTest::testBorderSelectionSimplified() { SelectionManagerTester t(true); - KisOperationConfiguration* config = new KisOperationConfiguration("borderselection"); + KisOperationConfigurationSP config = new KisOperationConfiguration("borderselection"); config->setProperty("x-radius", 10); config->setProperty("y-radius", 5); t.actionManager->runOperationFromConfiguration(config); t.image->waitForDone(); QVERIFY(t.checkSelectionOnly("border_selection")); } #include void KisSelectionManagerTest::testScanline16bit() { const int THRESHOLD = 20; QString fileName = TestUtil::fetchDataFileLazy("flood_fill_16bit.kra"); QVERIFY(QFile::exists(fileName)); KisDocument *doc = KisPart::instance()->createDocument(); doc->loadNativeFormat(fileName); KisPaintDeviceSP dev = doc->image()->root()->firstChild()->paintDevice(); QVERIFY(dev); dbgKrita << ppVar(dev->colorSpace()); QRect imageRect = doc->image()->bounds(); dbgKrita << ppVar(imageRect); QPoint startPoint = imageRect.center(); dbgKrita << ppVar(startPoint); KisPixelSelectionSP pixelSelection = new KisPixelSelection(); { KisScanlineFill gc(dev, startPoint, imageRect); gc.setThreshold(THRESHOLD); gc.fillSelection(pixelSelection); QImage resultImage = pixelSelection->convertToQImage(0, imageRect); QVERIFY(TestUtil::checkQImage(resultImage, "selection_manager_test", "scanline", "16bit_thres_20")); } const KoColorSpace *rgb8CS = KoColorSpaceRegistry::instance()->rgb8(); pixelSelection->clear(); dev->convertTo(rgb8CS); { KisScanlineFill gc(dev, startPoint, imageRect); gc.setThreshold(THRESHOLD); gc.fillSelection(pixelSelection); QImage resultImage = pixelSelection->convertToQImage(0, imageRect); QVERIFY(TestUtil::checkQImage(resultImage, "selection_manager_test", "scanline", "8bit_thres_20")); } } QTEST_MAIN(KisSelectionManagerTest) diff --git a/libs/ui/tests/kis_zoom_and_pan_test.cpp b/libs/ui/tests/kis_zoom_and_pan_test.cpp index dabb3e89ff..a8392de3de 100644 --- a/libs/ui/tests/kis_zoom_and_pan_test.cpp +++ b/libs/ui/tests/kis_zoom_and_pan_test.cpp @@ -1,764 +1,765 @@ /* * Copyright (c) 2012 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_zoom_and_pan_test.h" #include #include +#include #include "testutil.h" #include "qimage_based_test.h" #include #include "kis_config.h" #include "KisMainWindow.h" #include "KoZoomController.h" #include "KisDocument.h" #include "KisPart.h" #include "KisViewManager.h" #include "KisView.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_coordinates_converter.h" #include "kis_filter_strategy.h" class ZoomAndPanTester : public TestUtil::QImageBasedTest { public: ZoomAndPanTester() // we are not going to use our own QImage sets,so // just exploit the set of the selection manager test : QImageBasedTest("selection_manager_test") { m_undoStore = new KisSurrogateUndoStore(); m_image = createImage(m_undoStore); m_image->initialRefreshGraph(); QVERIFY(checkLayersInitial(m_image)); m_doc = KisPart::instance()->createDocument(); m_doc->setCurrentImage(m_image); m_mainWindow = KisPart::instance()->createMainWindow(); m_view = new KisView(m_doc, m_mainWindow->resourceManager(), m_mainWindow->actionCollection(), m_mainWindow); m_image->refreshGraph(); m_mainWindow->show(); } ~ZoomAndPanTester() { m_image->waitForDone(); QApplication::processEvents(); delete m_mainWindow; delete m_doc; /** * The event queue may have up to 200k events * by the time all the tests are finished. Removing * all of them may last forever, so clear them after * every single test is finished */ QApplication::removePostedEvents(0); } QPointer view() { return m_view; } KisMainWindow* mainWindow() { return m_mainWindow; } KisImageWSP image() { return m_image; } KisCanvas2* canvas() { return m_view->canvasBase(); } QWidget* canvasWidget() { return m_view->canvasBase()->canvasWidget(); } KoZoomController* zoomController() { return m_view->zoomController(); } KisCanvasController* canvasController() { return dynamic_cast(m_view->canvasController()); } const KisCoordinatesConverter* coordinatesConverter() { return m_view->canvasBase()->coordinatesConverter(); } private: KisSurrogateUndoStore *m_undoStore; KisImageSP m_image; KisDocument *m_doc; QPointerm_view; KisMainWindow *m_mainWindow; }; template inline bool compareWithRounding(const P &pt0, const P &pt1, T tolerance) { return qAbs(pt0.x() - pt1.x()) <= tolerance && qAbs(pt0.y() - pt1.y()) <= tolerance; } bool verifyOffset(ZoomAndPanTester &t, const QPoint &offset) { if (t.coordinatesConverter()->documentOffset() != offset) { dbgKrita << "########################"; dbgKrita << "Expected Offset:" << offset; dbgKrita << "Actual values:"; dbgKrita << "Offset:" << t.coordinatesConverter()->documentOffset(); dbgKrita << "wsize:" << t.canvasWidget()->size(); dbgKrita << "vport:" << t.canvasController()->viewportSize(); dbgKrita << "pref:" << t.canvasController()->preferredCenter(); dbgKrita << "########################"; } return t.coordinatesConverter()->documentOffset() == offset; } bool KisZoomAndPanTest::checkPan(ZoomAndPanTester &t, QPoint shift) { QPoint oldOffset = t.coordinatesConverter()->documentOffset(); QPointF oldPrefCenter = t.canvasController()->preferredCenter(); t.canvasController()->pan(shift); QPoint newOffset = t.coordinatesConverter()->documentOffset(); QPointF newPrefCenter = t.canvasController()->preferredCenter(); QPointF newTopLeft = t.coordinatesConverter()->imageRectInWidgetPixels().topLeft(); QPoint expectedOffset = oldOffset + shift; QPointF expectedPrefCenter = oldPrefCenter + shift; // no tolerance accepted for pan bool offsetAsExpected = newOffset == expectedOffset; // rounding can happen due to the scroll bars being the main // source of the offset bool preferredCenterAsExpected = compareWithRounding(expectedPrefCenter, newPrefCenter, 1.0); bool topLeftAsExpected = newTopLeft.toPoint() == -newOffset; if (!offsetAsExpected || !preferredCenterAsExpected || !topLeftAsExpected) { dbgKrita << "***** PAN *****************"; if(!offsetAsExpected) { dbgKrita << " ### Offset invariant broken"; } if(!preferredCenterAsExpected) { dbgKrita << " ### Preferred center invariant broken"; } if(!topLeftAsExpected) { dbgKrita << " ### TopLeft invariant broken"; } dbgKrita << ppVar(expectedOffset); dbgKrita << ppVar(expectedPrefCenter); dbgKrita << ppVar(oldOffset) << ppVar(newOffset); dbgKrita << ppVar(oldPrefCenter) << ppVar(newPrefCenter); dbgKrita << ppVar(newTopLeft); dbgKrita << "***************************"; } return offsetAsExpected && preferredCenterAsExpected && topLeftAsExpected; } bool KisZoomAndPanTest::checkInvariants(const QPointF &baseFlakePoint, const QPoint &oldOffset, const QPointF &oldPreferredCenter, qreal oldZoom, const QPoint &newOffset, const QPointF &newPreferredCenter, qreal newZoom, const QPointF &newTopLeft, const QSize &oldDocumentSize) { qreal k = newZoom / oldZoom; QPointF expectedOffset = oldOffset + (k - 1) * baseFlakePoint; QPointF expectedPreferredCenter = oldPreferredCenter + (k - 1) * baseFlakePoint; qreal oldPreferredCenterFractionX = 1.0 * oldPreferredCenter.x() / oldDocumentSize.width(); qreal oldPreferredCenterFractionY = 1.0 * oldPreferredCenter.y() / oldDocumentSize.height(); qreal roundingTolerance = qMax(qreal(1.0), qMax(oldPreferredCenterFractionX, oldPreferredCenterFractionY) / k); /** * In the computation of the offset two roundings happen: * first for the computation of oldOffset and the second * for the computation of newOffset. So the maximum tolerance * should equal 2. */ bool offsetAsExpected = compareWithRounding(expectedOffset, QPointF(newOffset), 2 * roundingTolerance); /** * Rounding for the preferred center happens due to the rounding * of the document size while zooming. The wider the step of the * zooming, the bigger tolerance should be */ bool preferredCenterAsExpected = compareWithRounding(expectedPreferredCenter, newPreferredCenter, roundingTolerance); bool topLeftAsExpected = newTopLeft.toPoint() == -newOffset; if (!offsetAsExpected || !preferredCenterAsExpected || !topLeftAsExpected) { dbgKrita << "***** ZOOM ****************"; if(!offsetAsExpected) { dbgKrita << " ### Offset invariant broken"; } if(!preferredCenterAsExpected) { dbgKrita << " ### Preferred center invariant broken"; } if(!topLeftAsExpected) { dbgKrita << " ### TopLeft invariant broken"; } dbgKrita << ppVar(expectedOffset); dbgKrita << ppVar(expectedPreferredCenter); dbgKrita << ppVar(oldOffset) << ppVar(newOffset); dbgKrita << ppVar(oldPreferredCenter) << ppVar(newPreferredCenter); dbgKrita << ppVar(oldPreferredCenterFractionX); dbgKrita << ppVar(oldPreferredCenterFractionY); dbgKrita << ppVar(oldZoom) << ppVar(newZoom); dbgKrita << ppVar(baseFlakePoint); dbgKrita << ppVar(newTopLeft); dbgKrita << ppVar(roundingTolerance); dbgKrita << "***************************"; } return offsetAsExpected && preferredCenterAsExpected && topLeftAsExpected; } bool KisZoomAndPanTest::checkZoomWithAction(ZoomAndPanTester &t, qreal newZoom, bool limitedZoom) { QPoint oldOffset = t.coordinatesConverter()->documentOffset(); QPointF oldPrefCenter = t.canvasController()->preferredCenter(); qreal oldZoom = t.zoomController()->zoomAction()->effectiveZoom(); QSize oldDocumentSize = t.canvasController()->documentSize(); t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, newZoom); QPointF newTopLeft = t.coordinatesConverter()->imageRectInWidgetPixels().topLeft(); return checkInvariants(oldPrefCenter, oldOffset, oldPrefCenter, oldZoom, t.coordinatesConverter()->documentOffset(), t.canvasController()->preferredCenter(), limitedZoom ? oldZoom : newZoom, newTopLeft, oldDocumentSize); } bool KisZoomAndPanTest::checkZoomWithWheel(ZoomAndPanTester &t, const QPoint &widgetPoint, qreal zoomCoeff, bool limitedZoom) { QPoint oldOffset = t.coordinatesConverter()->documentOffset(); QPointF oldPrefCenter = t.canvasController()->preferredCenter(); qreal oldZoom = t.zoomController()->zoomAction()->effectiveZoom(); QSize oldDocumentSize = t.canvasController()->documentSize(); t.canvasController()->zoomRelativeToPoint(widgetPoint, zoomCoeff); QPointF newTopLeft = t.coordinatesConverter()->imageRectInWidgetPixels().topLeft(); return checkInvariants(oldOffset + widgetPoint, oldOffset, oldPrefCenter, oldZoom, t.coordinatesConverter()->documentOffset(), t.canvasController()->preferredCenter(), limitedZoom ? oldZoom : zoomCoeff * oldZoom, newTopLeft, oldDocumentSize); } void KisZoomAndPanTest::testZoom100ChangingWidgetSize() { ZoomAndPanTester t; QCOMPARE(t.image()->size(), QSize(640,441)); QCOMPARE(t.image()->xRes(), 1.0); QCOMPARE(t.image()->yRes(), 1.0); t.canvasController()->resize(QSize(1000,1000)); t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, 1.0); t.canvasController()->setPreferredCenter(QPoint(320,220)); QCOMPARE(t.canvasWidget()->size(), QSize(983,983)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QVERIFY(verifyOffset(t, QPoint(-171,-271))); t.canvasController()->resize(QSize(700,700)); QCOMPARE(t.canvasWidget()->size(), QSize(683,683)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QVERIFY(verifyOffset(t, QPoint(-171,-271))); t.canvasController()->setPreferredCenter(QPoint(320,220)); QVERIFY(verifyOffset(t, QPoint(-21,-121))); t.canvasController()->resize(QSize(400,400)); QCOMPARE(t.canvasWidget()->size(), QSize(383,383)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QVERIFY(verifyOffset(t, QPoint(-21,-121))); t.canvasController()->setPreferredCenter(QPoint(320,220)); QVERIFY(verifyOffset(t, QPoint(129,29))); t.canvasController()->pan(QPoint(100,100)); QVERIFY(verifyOffset(t, QPoint(229,129))); } void KisZoomAndPanTest::initializeViewport(ZoomAndPanTester &t, bool fullscreenMode, bool rotate, bool mirror) { QCOMPARE(t.image()->size(), QSize(640,441)); QCOMPARE(t.image()->xRes(), 1.0); QCOMPARE(t.image()->yRes(), 1.0); t.canvasController()->resize(QSize(500,500)); t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, 1.0); t.canvasController()->setPreferredCenter(QPoint(320,220)); QCOMPARE(t.canvasWidget()->size(), QSize(483,483)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QVERIFY(verifyOffset(t, QPoint(79,-21))); if (fullscreenMode) { QCOMPARE(t.canvasController()->preferredCenter(), QPointF(320,220)); QAction *action = t.view()->viewManager()->actionCollection()->action("view_show_canvas_only"); action->setChecked(true); QVERIFY(verifyOffset(t, QPoint(79,-21))); QCOMPARE(t.canvasController()->preferredCenter(), QPointF(329,220)); t.canvasController()->resize(QSize(483,483)); QCOMPARE(t.canvasWidget()->size(), QSize(483,483)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QVERIFY(verifyOffset(t, QPoint(79,-21))); /** * FIXME: here is a small flaw in KoCanvasControllerWidget * We cannot set the center point explicitly, because it'll be rounded * up by recenterPreferred function, so real center point will be * different. Make the preferredCenter() return real center of the * image instead of the set value */ QCOMPARE(t.canvasController()->preferredCenter(), QPointF(320.5,220)); } if (rotate) { t.canvasController()->rotateCanvas(90); QVERIFY(verifyOffset(t, QPoint(-21,79))); QVERIFY(compareWithRounding(QPointF(220,320), t.canvasController()->preferredCenter(), 2)); QCOMPARE(t.coordinatesConverter()->imageRectInWidgetPixels().topLeft().toPoint(), -t.coordinatesConverter()->documentOffset()); } if (mirror) { t.canvasController()->mirrorCanvas(true); QVERIFY(verifyOffset(t, QPoint(78, -21))); QVERIFY(compareWithRounding(QPointF(320,220), t.canvasController()->preferredCenter(), 2)); QCOMPARE(t.coordinatesConverter()->imageRectInWidgetPixels().topLeft().toPoint(), -t.coordinatesConverter()->documentOffset()); } } void KisZoomAndPanTest::testSequentialActionZoomAndPan(bool fullscreenMode, bool rotate, bool mirror) { ZoomAndPanTester t; initializeViewport(t, fullscreenMode, rotate, mirror); QVERIFY(checkZoomWithAction(t, 0.5)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithAction(t, 0.25)); QVERIFY(checkPan(t, QPoint(-100,-100))); QVERIFY(checkZoomWithAction(t, 0.35)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithAction(t, 0.45)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithAction(t, 0.85)); QVERIFY(checkPan(t, QPoint(-100,-100))); QVERIFY(checkZoomWithAction(t, 2.35)); QVERIFY(checkPan(t, QPoint(100,100))); } void KisZoomAndPanTest::testSequentialWheelZoomAndPan(bool fullscreenMode, bool rotate, bool mirror) { ZoomAndPanTester t; initializeViewport(t, fullscreenMode, rotate, mirror); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 0.5)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 0.5)); QVERIFY(checkPan(t, QPoint(-100,-100))); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 1.25)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 1.5)); QVERIFY(checkPan(t, QPoint(100,100))); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 2.5)); QVERIFY(checkPan(t, QPoint(-100,-100))); // check one point which is outside the widget QVERIFY(checkZoomWithWheel(t, QPoint(-100,100), 2.5)); QVERIFY(checkPan(t, QPoint(-100,-100))); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 0.5)); QVERIFY(checkPan(t, QPoint(-100,-100))); } void KisZoomAndPanTest::testSequentialActionZoomAndPan() { testSequentialActionZoomAndPan(false, false, false); } void KisZoomAndPanTest::testSequentialActionZoomAndPanFullscreen() { testSequentialActionZoomAndPan(true, false, false); } void KisZoomAndPanTest::testSequentialActionZoomAndPanRotate() { testSequentialActionZoomAndPan(false, true, false); } void KisZoomAndPanTest::testSequentialActionZoomAndPanRotateFullscreen() { testSequentialActionZoomAndPan(true, true, false); } void KisZoomAndPanTest::testSequentialActionZoomAndPanMirror() { testSequentialActionZoomAndPan(false, false, true); } void KisZoomAndPanTest::testSequentialWheelZoomAndPan() { testSequentialWheelZoomAndPan(false, false, false); } void KisZoomAndPanTest::testSequentialWheelZoomAndPanFullscreen() { testSequentialWheelZoomAndPan(true, false, false); } void KisZoomAndPanTest::testSequentialWheelZoomAndPanRotate() { testSequentialWheelZoomAndPan(false, true, false); } void KisZoomAndPanTest::testSequentialWheelZoomAndPanRotateFullscreen() { testSequentialWheelZoomAndPan(true, true, false); } void KisZoomAndPanTest::testSequentialWheelZoomAndPanMirror() { testSequentialWheelZoomAndPan(false, false, true); } void KisZoomAndPanTest::testZoomOnBorderZoomLevels() { ZoomAndPanTester t; initializeViewport(t, false, false, false); QPoint widgetPoint(100,100); warnKrita << "WARNING: testZoomOnBorderZoomLevels() is disabled due to some changes in KoZoomMode::minimum/maximumZoom()"; return; // test min zoom level t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, KoZoomMode::minimumZoom()); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 0.5, true)); QVERIFY(checkZoomWithAction(t, KoZoomMode::minimumZoom() * 0.5, true)); // test max zoom level t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, KoZoomMode::maximumZoom()); QVERIFY(checkZoomWithWheel(t, QPoint(100,100), 2.0, true)); QVERIFY(checkZoomWithAction(t, KoZoomMode::maximumZoom() * 2.0, true)); } inline QTransform correctionMatrix(qreal angle) { return QTransform(0,0,0,sin(M_PI * angle / 180),0,0,0,0,1); } bool KisZoomAndPanTest::checkRotation(ZoomAndPanTester &t, qreal angle) { // save old values QPoint oldOffset = t.coordinatesConverter()->documentOffset(); QPointF oldCenteringCorrection = t.coordinatesConverter()->centeringCorrection(); QPointF oldPreferredCenter = t.canvasController()->preferredCenter(); QPointF oldRealCenterPoint = t.coordinatesConverter()->widgetToImage(t.coordinatesConverter()->widgetCenterPoint()); QSize oldDocumentSize = t.canvasController()->documentSize(); qreal baseAngle = t.coordinatesConverter()->rotationAngle(); t.canvasController()->rotateCanvas(angle); // save result values QPoint newOffset = t.coordinatesConverter()->documentOffset(); QPointF newCenteringCorrection = t.coordinatesConverter()->centeringCorrection(); QPointF newPreferredCenter = t.canvasController()->preferredCenter(); QPointF newRealCenterPoint = t.coordinatesConverter()->widgetToImage(t.coordinatesConverter()->widgetCenterPoint()); QSize newDocumentSize = t.canvasController()->documentSize(); // calculate theoretical preferred center QTransform rot; rot.rotate(angle); QSizeF dSize = t.coordinatesConverter()->imageSizeInFlakePixels(); QPointF dPoint(dSize.width(), dSize.height()); QPointF expectedPreferredCenter = (oldPreferredCenter - dPoint * correctionMatrix(baseAngle)) * rot + dPoint * correctionMatrix(baseAngle + angle); // calculate theoretical offset based on the real preferred center QPointF wPoint(t.canvasWidget()->size().width(), t.canvasWidget()->size().height()); QPointF expectedOldOffset = oldPreferredCenter - 0.5 * wPoint; QPointF expectedNewOffset = newPreferredCenter - 0.5 * wPoint; bool preferredCenterAsExpected = compareWithRounding(expectedPreferredCenter, newPreferredCenter, 2); bool oldOffsetAsExpected = compareWithRounding(expectedOldOffset + oldCenteringCorrection, QPointF(oldOffset), 2); bool newOffsetAsExpected = compareWithRounding(expectedNewOffset + newCenteringCorrection, QPointF(newOffset), 3); qreal zoom = t.zoomController()->zoomAction()->effectiveZoom(); bool realCenterPointAsExpected = compareWithRounding(oldRealCenterPoint, newRealCenterPoint, 2/zoom); if (!oldOffsetAsExpected || !newOffsetAsExpected || !preferredCenterAsExpected || !realCenterPointAsExpected) { dbgKrita << "***** ROTATE **************"; if(!oldOffsetAsExpected) { dbgKrita << " ### Old offset invariant broken"; } if(!newOffsetAsExpected) { dbgKrita << " ### New offset invariant broken"; } if(!preferredCenterAsExpected) { dbgKrita << " ### Preferred center invariant broken"; } if(!realCenterPointAsExpected) { dbgKrita << " ### *Real* center invariant broken"; } dbgKrita << ppVar(expectedOldOffset); dbgKrita << ppVar(expectedNewOffset); dbgKrita << ppVar(expectedPreferredCenter); dbgKrita << ppVar(oldOffset) << ppVar(newOffset); dbgKrita << ppVar(oldCenteringCorrection) << ppVar(newCenteringCorrection); dbgKrita << ppVar(oldPreferredCenter) << ppVar(newPreferredCenter); dbgKrita << ppVar(oldRealCenterPoint) << ppVar(newRealCenterPoint); dbgKrita << ppVar(oldDocumentSize) << ppVar(newDocumentSize); dbgKrita << ppVar(baseAngle) << "deg"; dbgKrita << ppVar(angle) << "deg"; dbgKrita << "***************************"; } return preferredCenterAsExpected && oldOffsetAsExpected && newOffsetAsExpected && realCenterPointAsExpected; } void KisZoomAndPanTest::testRotation(qreal vastScrolling, qreal zoom) { KisConfig cfg; cfg.setVastScrolling(vastScrolling); ZoomAndPanTester t; QCOMPARE(t.image()->size(), QSize(640,441)); QCOMPARE(t.image()->xRes(), 1.0); QCOMPARE(t.image()->yRes(), 1.0); QPointF preferredCenter = zoom * t.image()->bounds().center(); t.canvasController()->resize(QSize(500,500)); t.zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, zoom); t.canvasController()->setPreferredCenter(preferredCenter.toPoint()); QCOMPARE(t.canvasWidget()->size(), QSize(483,483)); QCOMPARE(t.canvasWidget()->size(), t.canvasController()->viewportSize()); QPointF realCenterPoint = t.coordinatesConverter()->widgetToImage(t.coordinatesConverter()->widgetCenterPoint()); QPointF expectedCenterPoint = QPointF(t.image()->bounds().center()); if(!compareWithRounding(realCenterPoint, expectedCenterPoint, 2/zoom)) { dbgKrita << "Failed to set initial center point"; dbgKrita << ppVar(expectedCenterPoint) << ppVar(realCenterPoint); QFAIL("FAIL: Failed to set initial center point"); } QVERIFY(checkRotation(t, 30)); QVERIFY(checkRotation(t, 20)); QVERIFY(checkRotation(t, 10)); QVERIFY(checkRotation(t, 5)); QVERIFY(checkRotation(t, 5)); QVERIFY(checkRotation(t, 5)); if(vastScrolling < 0.5 && zoom < 1) { warnKrita << "Disabling a few tests for vast scrolling =" << vastScrolling << ". See comment for more"; /** * We have to disable a couple of tests here for the case when * vastScrolling value is 0.2. The problem is that the centering * correction applied to the offset in * KisCanvasController::rotateCanvas pollutes the preferredCenter * value, because KoCnvasControllerWidget has no access to this * correction and cannot calculate the real value of the center of * the image. To fix this bug the calculation of correction * (aka "origin") should be moved to the KoCanvasControllerWidget * itself which would cause quite huge changes (including the change * of the external interface of it). Namely, we would have to * *calculate* offset from the value of the scroll bars, but not * use their values directly: * * offset = scrollBarValue - origin * * So now we just disable these unittests and allow a couple * of "jumping" bugs appear in vastScrolling < 0.5 modes, which * is, actually, not the default case. */ } else { QVERIFY(checkRotation(t, 5)); QVERIFY(checkRotation(t, 5)); QVERIFY(checkRotation(t, 5)); } } void KisZoomAndPanTest::testRotation_VastScrolling_1_0() { testRotation(0.9, 1.0); } void KisZoomAndPanTest::testRotation_VastScrolling_0_5() { testRotation(0.9, 0.5); } void KisZoomAndPanTest::testRotation_NoVastScrolling_1_0() { testRotation(0.2, 1.0); } void KisZoomAndPanTest::testRotation_NoVastScrolling_0_5() { testRotation(0.2, 0.5); } void KisZoomAndPanTest::testImageRescaled_0_5() { ZoomAndPanTester t; QApplication::processEvents(); initializeViewport(t, false, false, false); QApplication::processEvents(); QVERIFY(checkPan(t, QPoint(200,200))); QApplication::processEvents(); QPointF oldStillPoint = t.coordinatesConverter()->imageRectInWidgetPixels().center(); KisFilterStrategy *strategy = new KisBilinearFilterStrategy(); t.image()->scaleImage(QSize(320, 220), t.image()->xRes(), t.image()->yRes(), strategy); t.image()->waitForDone(); QApplication::processEvents(); delete strategy; QPointF newStillPoint = t.coordinatesConverter()->imageRectInWidgetPixels().center(); QVERIFY(compareWithRounding(oldStillPoint, newStillPoint, 1.0)); } void KisZoomAndPanTest::testImageCropped() { ZoomAndPanTester t; QApplication::processEvents(); initializeViewport(t, false, false, false); QApplication::processEvents(); QVERIFY(checkPan(t, QPoint(-150,-150))); QApplication::processEvents(); QPointF oldStillPoint = t.coordinatesConverter()->imageToWidget(QPointF(150,150)); t.image()->cropImage(QRect(100,100,100,100)); t.image()->waitForDone(); QApplication::processEvents(); QPointF newStillPoint = t.coordinatesConverter()->imageToWidget(QPointF(50,50)); QVERIFY(compareWithRounding(oldStillPoint, newStillPoint, 1.0)); } QTEST_MAIN(KisZoomAndPanTest) diff --git a/libs/ui/tests/util.h b/libs/ui/tests/util.h index 56f931379f..63f6c69040 100644 --- a/libs/ui/tests/util.h +++ b/libs/ui/tests/util.h @@ -1,226 +1,226 @@ /* * Copyright (c) 2008 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _UTIL_H_ #define _UTIL_H_ #include #include #include #include #include #include #include #include #include #include #include "kis_types.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter.h" #include "KisDocument.h" #include "KisPart.h" #include "kis_image.h" #include "kis_pixel_selection.h" #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "kis_clone_layer.h" #include "kis_adjustment_layer.h" #include "kis_shape_layer.h" #include "kis_filter_mask.h" #include "kis_transparency_mask.h" #include "kis_selection_mask.h" #include "kis_selection.h" #include "kis_fill_painter.h" #include "kis_shape_selection.h" #include "kis_default_bounds.h" #include "kis_transform_mask_params_interface.h" KisSelectionSP createPixelSelection(KisPaintDeviceSP paintDevice) { KisSelectionSP pixelSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice)); KisFillPainter gc(pixelSelection->pixelSelection()); gc.fillRect(10, 10, 200, 200, KoColor(gc.device()->colorSpace())); gc.fillRect(150, 150, 200, 200, KoColor(QColor(100, 100, 100, 100), gc.device()->colorSpace())); gc.end(); return pixelSelection; } KisSelectionSP createVectorSelection(KisPaintDeviceSP paintDevice, KisImageWSP image) { KisSelectionSP vectorSelection = new KisSelection(new KisSelectionDefaultBounds(paintDevice)); KoPathShape* path = new KoPathShape(); path->setShapeId(KoPathShapeId); path->moveTo(QPointF(10, 10)); path->lineTo(QPointF(10, 10) + QPointF(100, 0)); path->lineTo(QPointF(100, 100)); path->lineTo(QPointF(10, 10) + QPointF(0, 100)); path->close(); path->normalize(); KisShapeSelection* shapeSelection = new KisShapeSelection(image, vectorSelection); shapeSelection->addShape(path); vectorSelection->setShapeSelection(shapeSelection); return vectorSelection; } QTransform createTestingTransform() { return QTransform(1,2,3,4,5,6,7,8,9); } KisDocument* createCompleteDocument() { KisImageWSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip"); KisDocument *doc = qobject_cast(KisPart::instance()->createDocument()); doc->setCurrentImage(image); doc->documentInfo()->setAboutInfo("title", image->objectName()); KisGroupLayerSP group1 = new KisGroupLayer(image, "group1", 50); KisGroupLayerSP group2 = new KisGroupLayer(image, "group2", 100); KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paintlayer1", OPACITY_OPAQUE_U8); paintLayer1->setUserLocked(true); QBitArray channelFlags(4); channelFlags[0] = true; channelFlags[2] = true; paintLayer1->setChannelFlags(channelFlags); { KisFillPainter gc(paintLayer1->paintDevice()); gc.fillRect(10, 10, 200, 200, KoColor(Qt::red, paintLayer1->paintDevice()->colorSpace())); gc.end(); } KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paintlayer2", OPACITY_TRANSPARENT_U8, KoColorSpaceRegistry::instance()->lab16()); paintLayer2->setVisible(false); { KisFillPainter gc(paintLayer2->paintDevice()); gc.fillRect(0, 0, 900, 1024, KoColor(QColor(10, 20, 30), paintLayer2->paintDevice()->colorSpace())); gc.end(); } KisCloneLayerSP cloneLayer1 = new KisCloneLayer(group1, image, "clonelayer1", 150); cloneLayer1->setX(100); cloneLayer1->setY(100); KisSelectionSP pixelSelection = createPixelSelection(paintLayer1->paintDevice()); - KisFilterConfiguration* kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(group2->projection()); + KisFilterConfigurationSP kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(group2->projection()); Q_ASSERT(kfc); KisAdjustmentLayerSP adjustmentLayer1 = new KisAdjustmentLayer(image, "adjustmentLayer1", kfc, pixelSelection); kfc = 0; // kfc cannot be shared! KisSelectionSP vectorSelection = createVectorSelection(paintLayer2->paintDevice(), image); kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(group2->projection()); KisAdjustmentLayerSP adjustmentLayer2 = new KisAdjustmentLayer(image, "adjustmentLayer2", kfc, vectorSelection); kfc = 0; // kfc cannot be shared! image->addNode(paintLayer1); image->addNode(group1); image->addNode(paintLayer2, group1); image->addNode(group2); image->addNode(cloneLayer1, group2); image->addNode(adjustmentLayer1, group2); // KoShapeContainer * parentContainer = // dynamic_cast(doc->shapeForNode(group1)); KoPathShape* path = new KoPathShape(); path->setShapeId(KoPathShapeId); path->moveTo(QPointF(10, 10)); path->lineTo(QPointF(10, 10) + QPointF(100, 0)); path->lineTo(QPointF(100, 100)); path->lineTo(QPointF(10, 10) + QPointF(0, 100)); path->close(); path->normalize(); KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image, "shapeLayer1", 75); shapeLayer->addShape(path); image->addNode(shapeLayer, group1); image->addNode(adjustmentLayer2, group1); KisFilterMaskSP filterMask1 = new KisFilterMask(); filterMask1->setName("filterMask1"); kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(group2->projection()); filterMask1->setFilter(kfc); kfc = 0; // kfc cannot be shared! filterMask1->setSelection(createPixelSelection(paintLayer1->paintDevice())); image->addNode(filterMask1, paintLayer1); KisFilterMaskSP filterMask2 = new KisFilterMask(); filterMask2->setName("filterMask2"); kfc = KisFilterRegistry::instance()->get("pixelize")->defaultConfiguration(group2->projection()); filterMask2->setFilter(kfc); kfc = 0; // kfc cannot be shared! filterMask2->setSelection(createVectorSelection(paintLayer2->paintDevice(), image)); image->addNode(filterMask2, paintLayer2); KisTransparencyMaskSP transparencyMask1 = new KisTransparencyMask(); transparencyMask1->setName("transparencyMask1"); transparencyMask1->setSelection(createPixelSelection(paintLayer1->paintDevice())); image->addNode(transparencyMask1, group1); KisTransparencyMaskSP transparencyMask2 = new KisTransparencyMask(); transparencyMask2->setName("transparencyMask2"); transparencyMask2->setSelection(createPixelSelection(paintLayer1->paintDevice())); image->addNode(transparencyMask2, group2); KisSelectionMaskSP selectionMask1 = new KisSelectionMask(image); image->addNode(selectionMask1, paintLayer1); selectionMask1->setName("selectionMask1"); selectionMask1->setSelection(createPixelSelection(paintLayer1->paintDevice())); KisSelectionMaskSP selectionMask2 = new KisSelectionMask(image); selectionMask2->setName("selectionMask2"); selectionMask2->setSelection(createPixelSelection(paintLayer2->paintDevice())); image->addNode(selectionMask2, paintLayer2); KisTransformMaskSP transformMask = new KisTransformMask(); transformMask->setName("testTransformMask"); transformMask->setTransformParams(KisTransformMaskParamsInterfaceSP( new KisDumbTransformMaskParams(createTestingTransform()))); image->addNode(transformMask, paintLayer2); return doc; } KisDocument *createEmptyDocument() { KisImageWSP image = new KisImage(0, 1024, 1024, KoColorSpaceRegistry::instance()->rgb8(), "test for roundtrip"); KisDocument *doc = qobject_cast(KisPart::instance()->createDocument()); doc->setCurrentImage(image); doc->documentInfo()->setAboutInfo("title", image->objectName()); return doc; } #endif diff --git a/libs/ui/tool/kis_figure_painting_tool_helper.cpp b/libs/ui/tool/kis_figure_painting_tool_helper.cpp index bf7eb8fa71..02507ab240 100644 --- a/libs/ui/tool/kis_figure_painting_tool_helper.cpp +++ b/libs/ui/tool/kis_figure_painting_tool_helper.cpp @@ -1,115 +1,152 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_figure_painting_tool_helper.h" #include #include "kis_resources_snapshot.h" #include #include "kis_image.h" #include "kis_painter.h" KisFigurePaintingToolHelper::KisFigurePaintingToolHelper(const KUndo2MagicString &name, KisImageWSP image, KisNodeSP currentNode, KoCanvasResourceManager *resourceManager, KisPainter::StrokeStyle strokeStyle, KisPainter::FillStyle fillStyle) { m_strokesFacade = image.data(); m_resources = new KisResourcesSnapshot(image, currentNode, image->postExecutionUndoAdapter(), resourceManager); m_resources->setStrokeStyle(strokeStyle); m_resources->setFillStyle(fillStyle); PainterInfo *painterInfo = new PainterInfo(); KisStrokeStrategy *stroke = new FreehandStrokeStrategy(m_resources->needsIndirectPainting(), m_resources->indirectPaintingCompositeOp(), m_resources, painterInfo, name); m_strokeId = m_strokesFacade->startStroke(stroke); } KisFigurePaintingToolHelper::~KisFigurePaintingToolHelper() { m_strokesFacade->endStroke(m_strokeId); } void KisFigurePaintingToolHelper::paintLine(const KisPaintInformation &pi0, const KisPaintInformation &pi1) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, pi0, pi1)); } void KisFigurePaintingToolHelper::paintPolyline(const vQPointF &points) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, FreehandStrokeStrategy::Data::POLYLINE, points)); } void KisFigurePaintingToolHelper::paintPolygon(const vQPointF &points) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, FreehandStrokeStrategy::Data::POLYGON, points)); } void KisFigurePaintingToolHelper::paintRect(const QRectF &rect) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, FreehandStrokeStrategy::Data::RECT, rect)); } void KisFigurePaintingToolHelper::paintEllipse(const QRectF &rect) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, FreehandStrokeStrategy::Data::ELLIPSE, rect)); } void KisFigurePaintingToolHelper::paintPainterPath(const QPainterPath &path) { m_strokesFacade->addJob(m_strokeId, new FreehandStrokeStrategy::Data(m_resources->currentNode(), 0, FreehandStrokeStrategy::Data::PAINTER_PATH, path)); } +void KisFigurePaintingToolHelper::setFGColorOverride(const KoColor &color) +{ + m_resources->setFGColorOverride(color); +} + +void KisFigurePaintingToolHelper::setBGColorOverride(const KoColor &color) +{ + m_resources->setBGColorOverride(color); +} + +void KisFigurePaintingToolHelper::setSelectionOverride(KisSelectionSP m_selection) +{ + m_resources->setSelectionOverride(m_selection); +} + +void KisFigurePaintingToolHelper::setBrush(const KisPaintOpPresetSP &brush) +{ + m_resources->setBrush(brush); +} + +void KisFigurePaintingToolHelper::paintPainterPathQPen(const QPainterPath path, const QPen &pen, const KoColor &color) +{ + m_strokesFacade->addJob(m_strokeId, + new FreehandStrokeStrategy::Data(m_resources->currentNode(), + 0, + FreehandStrokeStrategy::Data::QPAINTER_PATH, + path, pen, color)); +} + +void KisFigurePaintingToolHelper::paintPainterPathQPenFill(const QPainterPath path, const QPen &pen, const KoColor &color) +{ + m_strokesFacade->addJob(m_strokeId, + new FreehandStrokeStrategy::Data(m_resources->currentNode(), + 0, + FreehandStrokeStrategy::Data::QPAINTER_PATH_FILL, + path, pen, color)); +} diff --git a/libs/ui/tool/kis_figure_painting_tool_helper.h b/libs/ui/tool/kis_figure_painting_tool_helper.h index f28c6bd2e2..297018289b 100644 --- a/libs/ui/tool/kis_figure_painting_tool_helper.h +++ b/libs/ui/tool/kis_figure_painting_tool_helper.h @@ -1,59 +1,65 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_FIGURE_PAINTING_TOOL_HELPER_H #define __KIS_FIGURE_PAINTING_TOOL_HELPER_H #include "kis_types.h" #include "kritaui_export.h" #include #include "strokes/freehand_stroke.h" class KoCanvasResourceManager; class KisStrokesFacade; class KRITAUI_EXPORT KisFigurePaintingToolHelper { protected: typedef FreehandStrokeStrategy::PainterInfo PainterInfo; public: KisFigurePaintingToolHelper(const KUndo2MagicString &name, KisImageWSP image, KisNodeSP currentNode, KoCanvasResourceManager *resourceManager, KisPainter::StrokeStyle strokeStyle, KisPainter::FillStyle fillStyle); ~KisFigurePaintingToolHelper(); void paintLine(const KisPaintInformation &pi0, const KisPaintInformation &pi1); void paintPolyline(const vQPointF &points); void paintPolygon(const vQPointF &points); void paintRect(const QRectF &rect); void paintEllipse(const QRectF &rect); void paintPainterPath(const QPainterPath &path); + void setFGColorOverride(const KoColor &color); + void setBGColorOverride(const KoColor &color); + void setSelectionOverride(KisSelectionSP m_selection); + void setBrush(const KisPaintOpPresetSP &brush); + void paintPainterPathQPen(const QPainterPath, const QPen &pen, const KoColor &color); + void paintPainterPathQPenFill(const QPainterPath, const QPen &pen, const KoColor &color); private: KisStrokeId m_strokeId; KisResourcesSnapshotSP m_resources; KisStrokesFacade *m_strokesFacade; }; #endif /* __KIS_FIGURE_PAINTING_TOOL_HELPER_H */ diff --git a/libs/ui/tool/kis_resources_snapshot.cpp b/libs/ui/tool/kis_resources_snapshot.cpp index 3c846699bc..23ae81113c 100644 --- a/libs/ui/tool/kis_resources_snapshot.cpp +++ b/libs/ui/tool/kis_resources_snapshot.cpp @@ -1,332 +1,358 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_resources_snapshot.h" #include #include #include #include #include #include #include #include #include "kis_canvas_resource_provider.h" #include "filter/kis_filter_configuration.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "recorder/kis_recorded_paint_action.h" #include "kis_selection.h" #include "kis_selection_mask.h" struct KisResourcesSnapshot::Private { Private() : currentPattern(0) , currentGradient(0) , currentGenerator(0) , compositeOp(0) { } KisImageSP image; KisDefaultBoundsBaseSP bounds; KisPostExecutionUndoAdapter *undoAdapter; KoColor currentFgColor; KoColor currentBgColor; KoPattern *currentPattern; KoAbstractGradient *currentGradient; KisPaintOpPresetSP currentPaintOpPreset; KisNodeSP currentNode; qreal currentExposure; - KisFilterConfiguration *currentGenerator; + KisFilterConfigurationSP currentGenerator; QPointF axesCenter; bool mirrorMaskHorizontal; bool mirrorMaskVertical; quint8 opacity; QString compositeOpId; const KoCompositeOp *compositeOp; KisPainter::StrokeStyle strokeStyle; KisPainter::FillStyle fillStyle; bool globalAlphaLock; qreal effectiveZoom; bool presetAllowsLod; + KisSelectionSP selection; }; KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisPostExecutionUndoAdapter *undoAdapter, KoCanvasResourceManager *resourceManager, KisDefaultBoundsBaseSP bounds) : m_d(new Private()) { m_d->image = image; if (!bounds) { bounds = new KisDefaultBounds(m_d->image); } m_d->bounds = bounds; m_d->undoAdapter = undoAdapter; - m_d->currentFgColor = resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value(); m_d->currentBgColor = resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value(); m_d->currentPattern = resourceManager->resource(KisCanvasResourceProvider::CurrentPattern).value(); m_d->currentGradient = resourceManager->resource(KisCanvasResourceProvider::CurrentGradient).value(); /** * We should deep-copy the preset, so that long-runnign actions * will have correct brush parameters. Theoretically this cloniong * can be expensive, but according to measurements, it takes * something like 0.1 ms for an average preset. */ m_d->currentPaintOpPreset = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value()->clone(); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ m_d->currentExposure = resourceManager->resource(KisCanvasResourceProvider::HdrExposure).toDouble(); m_d->currentGenerator = resourceManager->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); m_d->axesCenter = resourceManager->resource(KisCanvasResourceProvider::MirrorAxesCenter).toPointF(); if (m_d->axesCenter.isNull()){ QRect bounds = m_d->bounds->bounds(); m_d->axesCenter = QPointF(0.5 * bounds.width(), 0.5 * bounds.height()); } m_d->mirrorMaskHorizontal = resourceManager->resource(KisCanvasResourceProvider::MirrorHorizontal).toBool(); m_d->mirrorMaskVertical = resourceManager->resource(KisCanvasResourceProvider::MirrorVertical).toBool(); qreal normOpacity = resourceManager->resource(KisCanvasResourceProvider::Opacity).toDouble(); m_d->opacity = quint8(normOpacity * OPACITY_OPAQUE_U8); m_d->compositeOpId = resourceManager->resource(KisCanvasResourceProvider::CurrentEffectiveCompositeOp).toString(); setCurrentNode(currentNode); /** * Fill and Stroke styles are not a part of the resource manager * so the tools should set them manually * TODO: port stroke and fill styles to be a part * of the resource manager */ m_d->strokeStyle = KisPainter::StrokeStyleBrush; m_d->fillStyle = KisPainter::FillStyleNone; m_d->globalAlphaLock = resourceManager->resource(KisCanvasResourceProvider::GlobalAlphaLock).toBool(); m_d->effectiveZoom = resourceManager->resource(KisCanvasResourceProvider::EffectiveZoom).toDouble(); m_d->presetAllowsLod = resourceManager->resource(KisCanvasResourceProvider::PresetAllowsLod).toBool(); + m_d->selection = m_d->image->globalSelection(); } KisResourcesSnapshot::~KisResourcesSnapshot() { delete m_d; } void KisResourcesSnapshot::setupPainter(KisPainter* painter) { painter->setPaintColor(m_d->currentFgColor); painter->setBackgroundColor(m_d->currentBgColor); painter->setGenerator(m_d->currentGenerator); painter->setPattern(m_d->currentPattern); painter->setGradient(m_d->currentGradient); QBitArray lockflags = channelLockFlags(); if (lockflags.size() > 0) { painter->setChannelFlags(lockflags); } painter->setOpacity(m_d->opacity); painter->setCompositeOp(m_d->compositeOp); painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical); painter->setStrokeStyle(m_d->strokeStyle); painter->setFillStyle(m_d->fillStyle); /** * The paintOp should be initialized the last, because it may * ask the painter for some options while initialization */ painter->setPaintOpPreset(m_d->currentPaintOpPreset, m_d->currentNode, m_d->image); } void KisResourcesSnapshot::setupPaintAction(KisRecordedPaintAction *action) { action->setPaintOpPreset(m_d->currentPaintOpPreset); action->setPaintIncremental(!needsIndirectPainting()); action->setPaintColor(m_d->currentFgColor); action->setBackgroundColor(m_d->currentBgColor); action->setGenerator(m_d->currentGenerator); action->setGradient(m_d->currentGradient); action->setPattern(m_d->currentPattern); action->setOpacity(m_d->opacity / qreal(OPACITY_OPAQUE_U8)); action->setCompositeOp(m_d->compositeOp->id()); action->setStrokeStyle(m_d->strokeStyle); action->setFillStyle(m_d->fillStyle); } KisPostExecutionUndoAdapter* KisResourcesSnapshot::postExecutionUndoAdapter() const { return m_d->undoAdapter; } void KisResourcesSnapshot::setCurrentNode(KisNodeSP node) { m_d->currentNode = node; KisPaintDeviceSP device; if(m_d->currentNode && (device = m_d->currentNode->paintDevice())) { m_d->compositeOp = device->colorSpace()->compositeOp(m_d->compositeOpId); if(!m_d->compositeOp) { m_d->compositeOp = device->colorSpace()->compositeOp(COMPOSITE_OVER); } } } void KisResourcesSnapshot::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { m_d->strokeStyle = strokeStyle; } void KisResourcesSnapshot::setFillStyle(KisPainter::FillStyle fillStyle) { m_d->fillStyle = fillStyle; } KisNodeSP KisResourcesSnapshot::currentNode() const { return m_d->currentNode; } KisImageSP KisResourcesSnapshot::image() const { return m_d->image; } bool KisResourcesSnapshot::needsIndirectPainting() const { return !m_d->currentPaintOpPreset->settings()->paintIncremental(); } QString KisResourcesSnapshot::indirectPaintingCompositeOp() const { return m_d->currentPaintOpPreset->settings()->indirectPaintingCompositeOp(); } KisSelectionSP KisResourcesSnapshot::activeSelection() const { /** * It is possible to have/use the snapshot without the image. Such * usecase is present for example in the scratchpad. */ - KisSelectionSP selection = m_d->image ? m_d->image->globalSelection() : 0; + if (!m_d->selection) { + + return 0; + } + + m_d->selection = m_d->image ? m_d->image->globalSelection() : 0; KisLayerSP layer = dynamic_cast(m_d->currentNode.data()); KisSelectionMaskSP mask; if((layer = dynamic_cast(m_d->currentNode.data()))) { - selection = layer->selection(); + m_d->selection = layer->selection(); } else if ((mask = dynamic_cast(m_d->currentNode.data())) && - mask->selection() == selection) { + mask->selection() == m_d->selection) { - selection = 0; + m_d->selection = 0; } - return selection; + return m_d->selection; } bool KisResourcesSnapshot::needsAirbrushing() const { return m_d->currentPaintOpPreset->settings()->isAirbrushing(); } int KisResourcesSnapshot::airbrushingRate() const { return m_d->currentPaintOpPreset->settings()->rate(); } void KisResourcesSnapshot::setOpacity(qreal opacity) { m_d->opacity = opacity * OPACITY_OPAQUE_U8; } quint8 KisResourcesSnapshot::opacity() const { return m_d->opacity; } const KoCompositeOp* KisResourcesSnapshot::compositeOp() const { return m_d->compositeOp; } QString KisResourcesSnapshot::compositeOpId() const { return m_d->compositeOpId; } KoPattern* KisResourcesSnapshot::currentPattern() const { return m_d->currentPattern; } KoColor KisResourcesSnapshot::currentFgColor() const { return m_d->currentFgColor; } KoColor KisResourcesSnapshot::currentBgColor() const { return m_d->currentBgColor; } KisPaintOpPresetSP KisResourcesSnapshot::currentPaintOpPreset() const { return m_d->currentPaintOpPreset; } QBitArray KisResourcesSnapshot::channelLockFlags() const { QBitArray channelFlags; KisPaintLayer *paintLayer; if ((paintLayer = dynamic_cast(m_d->currentNode.data()))) { channelFlags = paintLayer->channelLockFlags(); if (m_d->globalAlphaLock) { if (channelFlags.isEmpty()) { channelFlags = paintLayer->colorSpace()->channelFlags(true, true); } channelFlags &= paintLayer->colorSpace()->channelFlags(true, false); } } return channelFlags; } qreal KisResourcesSnapshot::effectiveZoom() const { return m_d->effectiveZoom; } bool KisResourcesSnapshot::presetAllowsLod() const { return m_d->presetAllowsLod; } + +void KisResourcesSnapshot::setFGColorOverride(const KoColor &color) +{ + m_d->currentFgColor = color; +} + +void KisResourcesSnapshot::setBGColorOverride(const KoColor &color) +{ + m_d->currentBgColor = color; +} + +void KisResourcesSnapshot::setSelectionOverride(KisSelectionSP m_selection) +{ + m_d->selection = m_selection; +} + +void KisResourcesSnapshot::setBrush(const KisPaintOpPresetSP &brush) +{ + m_d->currentPaintOpPreset = brush; +} diff --git a/libs/ui/tool/kis_resources_snapshot.h b/libs/ui/tool/kis_resources_snapshot.h index 6b3614c511..ca9ca141a9 100644 --- a/libs/ui/tool/kis_resources_snapshot.h +++ b/libs/ui/tool/kis_resources_snapshot.h @@ -1,98 +1,103 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_RESOURCES_SNAPSHOT_H #define __KIS_RESOURCES_SNAPSHOT_H #include "kis_shared.h" #include "kis_shared_ptr.h" #include "kis_types.h" #include "kritaui_export.h" #include "kis_painter.h" #include "kis_default_bounds.h" class KoCanvasResourceManager; class KoCompositeOp; class KisPainter; class KisPostExecutionUndoAdapter; class KisRecordedPaintAction; class KoPattern; /** * @brief The KisResourcesSnapshot class takes a snapshot of the various resources * like colors and settings used at the begin of a stroke or a recording so subsequent * changes don't impact the running stroke. The main reason for the snapshot is that the * user can *change* the options while the stroke is being executed in the background. */ class KRITAUI_EXPORT KisResourcesSnapshot : public KisShared { public: KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisPostExecutionUndoAdapter *undoAdapter, KoCanvasResourceManager *resourceManager, KisDefaultBoundsBaseSP bounds = 0); ~KisResourcesSnapshot(); void setupPainter(KisPainter *painter); // XXX: This was marked as KDE_DEPRECATED, but no althernative was // given in the apidox. void setupPaintAction(KisRecordedPaintAction *action); KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const; void setCurrentNode(KisNodeSP node); void setStrokeStyle(KisPainter::StrokeStyle strokeStyle); void setFillStyle(KisPainter::FillStyle fillStyle); KisNodeSP currentNode() const; KisImageSP image() const; bool needsIndirectPainting() const; QString indirectPaintingCompositeOp() const; /** * \return currently active selection. Note that it will return * null if current node *is* the current selection. This * is done to avoid recursive selection application when * painting on selectgion masks. */ KisSelectionSP activeSelection() const; bool needsAirbrushing() const; int airbrushingRate() const; void setOpacity(qreal opacity); quint8 opacity() const; const KoCompositeOp* compositeOp() const; QString compositeOpId() const; KoPattern* currentPattern() const; KoColor currentFgColor() const; KoColor currentBgColor() const; KisPaintOpPresetSP currentPaintOpPreset() const; /// @return the channel lock flags of the current node with the global override applied QBitArray channelLockFlags() const; qreal effectiveZoom() const; bool presetAllowsLod() const; + void setFGColorOverride(const KoColor &color); + void setBGColorOverride(const KoColor &color); + void setSelectionOverride(KisSelectionSP selection); + void setBrush(const KisPaintOpPresetSP &brush); + private: struct Private; Private * const m_d; }; typedef KisSharedPtr KisResourcesSnapshotSP; #endif /* __KIS_RESOURCES_SNAPSHOT_H */ diff --git a/libs/ui/tool/kis_tool.cc b/libs/ui/tool/kis_tool.cc index 9ccce24f09..1369151f78 100644 --- a/libs/ui/tool/kis_tool.cc +++ b/libs/ui/tool/kis_tool.cc @@ -1,694 +1,694 @@ /* * Copyright (c) 2006, 2010 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_tool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl_canvas2.h" #include "kis_canvas_resource_provider.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "filter/kis_filter_configuration.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" #include #include #include "kis_resources_snapshot.h" #include #include "kis_action_registry.h" #include "kis_tool_utils.h" struct Q_DECL_HIDDEN KisTool::Private { QCursor cursor; // the cursor that should be shown on tool activation. // From the canvas resources KoPattern* currentPattern{0}; KoAbstractGradient* currentGradient{0}; KoColor currentFgColor; KoColor currentBgColor; float currentExposure{1.0}; - KisFilterConfiguration* currentGenerator{0}; + KisFilterConfigurationSP currentGenerator; QWidget* optionWidget{0}; ToolMode m_mode{HOVER_MODE}; bool m_isActive{false}; }; KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor) : KoToolBase(canvas) , d(new Private) { d->cursor = cursor; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle())); connect(this, SIGNAL(isActiveChanged()), SLOT(resetCursorStyle())); KActionCollection *collection = this->canvas()->canvasController()->actionCollection(); if (!collection->action("toggle_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("toggle_fg_bg", collection); collection->addAction("toggle_fg_bg", toggleFgBg); } if (!collection->action("reset_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("reset_fg_bg", collection); collection->addAction("reset_fg_bg", toggleFgBg); } addAction("toggle_fg_bg", dynamic_cast(collection->action("toggle_fg_bg"))); addAction("reset_fg_bg", dynamic_cast(collection->action("reset_fg_bg"))); } KisTool::~KisTool() { delete d; } void KisTool::activate(ToolActivation toolActivation, const QSet &shapes) { Q_UNUSED(toolActivation); Q_UNUSED(shapes); resetCursorStyle(); if (!canvas()) return; if (!canvas()->resourceManager()) return; d->currentFgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); d->currentBgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::BackgroundColor).value(); if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentPattern)) { d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGradient)) { d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); } KisPaintOpPresetSP preset = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && preset->settings()) { preset->settings()->activate(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::HdrExposure)) { d->currentExposure = static_cast(canvas()->resourceManager()->resource(KisCanvasResourceProvider::HdrExposure).toDouble()); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration)) { d->currentGenerator = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); } connect(actions().value("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection); connect(actions().value("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection); connect(image(), SIGNAL(sigUndoDuringStrokeRequested()), SLOT(requestUndoDuringStroke()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(requestStrokeCancellation()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeEndRequested()), SLOT(requestStrokeEnd()), Qt::UniqueConnection); d->m_isActive = true; emit isActiveChanged(); } void KisTool::deactivate() { bool result = true; result &= disconnect(image().data(), SIGNAL(sigUndoDuringStrokeRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeCancellationRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeEndRequested()), this, 0); result &= disconnect(actions().value("toggle_fg_bg"), 0, this, 0); result &= disconnect(actions().value("reset_fg_bg"), 0, this, 0); if (!result) { warnKrita << "WARNING: KisTool::deactivate() failed to disconnect" << "some signal connections. Your actions might be executed twice!"; } d->m_isActive = false; emit isActiveChanged(); } void KisTool::requestUndoDuringStroke() { /** * Default implementation just cancells the stroke */ requestStrokeCancellation(); } void KisTool::requestStrokeCancellation() { } void KisTool::requestStrokeEnd() { } void KisTool::canvasResourceChanged(int key, const QVariant & v) { switch (key) { case(KoCanvasResourceManager::ForegroundColor): d->currentFgColor = v.value(); break; case(KoCanvasResourceManager::BackgroundColor): d->currentBgColor = v.value(); break; case(KisCanvasResourceProvider::CurrentPattern): d->currentPattern = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentGradient): d->currentGradient = static_cast(v.value()); break; case(KisCanvasResourceProvider::HdrExposure): d->currentExposure = static_cast(v.toDouble()); break; case(KisCanvasResourceProvider::CurrentGeneratorConfiguration): d->currentGenerator = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentPaintOpPreset): emit statusTextChanged(v.value()->name()); break; case(KisCanvasResourceProvider::CurrentKritaNode): resetCursorStyle(); break; default: break; // Do nothing }; } void KisTool::updateSettingsViews() { } QPointF KisTool::widgetCenterInWidgetPixels() { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); const KisCoordinatesConverter *converter = kritaCanvas->coordinatesConverter(); return converter->flakeToWidget(converter->flakeCenterPoint()); } QPointF KisTool::convertDocumentToWidget(const QPointF& pt) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); return kritaCanvas->coordinatesConverter()->documentToWidget(pt); } QPointF KisTool::convertToPixelCoord(KoPointerEvent *e) { if (!image()) return e->point; return image()->documentToPixel(e->point); } QPointF KisTool::convertToPixelCoord(const QPointF& pt) { if (!image()) return pt; return image()->documentToPixel(pt); } QPointF KisTool::convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!image()) return e->point; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); return image()->documentToPixel(pos); } QPointF KisTool::convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset) { if (!image()) return pt; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return image()->documentToPixel(pos); } QPoint KisTool::convertToIntPixelCoord(KoPointerEvent *e) { if (!image()) return e->point.toPoint(); return image()->documentToIntPixel(e->point); } QPointF KisTool::viewToPixel(const QPointF &viewCoord) const { if (!image()) return viewCoord; return image()->documentToPixel(canvas()->viewConverter()->viewToDocument(viewCoord)); } QRectF KisTool::convertToPt(const QRectF &rect) { if (!image()) return rect; QRectF r; //We add 1 in the following to the extreme coords because a pixel always has size r.setCoords(int(rect.left()) / image()->xRes(), int(rect.top()) / image()->yRes(), int(1 + rect.right()) / image()->xRes(), int(1 + rect.bottom()) / image()->yRes()); return r; } QPointF KisTool::pixelToView(const QPoint &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QPointF KisTool::pixelToView(const QPointF &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QRectF KisTool::pixelToView(const QRectF &pixelRect) const { if (!image()) return pixelRect; QPointF topLeft = pixelToView(pixelRect.topLeft()); QPointF bottomRight = pixelToView(pixelRect.bottomRight()); return QRectF(topLeft, bottomRight); } QPainterPath KisTool::pixelToView(const QPainterPath &pixelPolygon) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPolygon); } QPolygonF KisTool::pixelToView(const QPolygonF &pixelPath) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPath); } void KisTool::updateCanvasPixelRect(const QRectF &pixelRect) { canvas()->updateCanvas(convertToPt(pixelRect)); } void KisTool::updateCanvasViewRect(const QRectF &viewRect) { canvas()->updateCanvas(canvas()->viewConverter()->viewToDocument(viewRect)); } KisImageWSP KisTool::image() const { // For now, krita tools only work in krita, not for a krita shape. Krita shapes are for 2.1 KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (kisCanvas) { return kisCanvas->currentImage(); } return 0; } QCursor KisTool::cursor() const { return d->cursor; } void KisTool::notifyModified() const { if (image()) { image()->setModified(); } } KoPattern * KisTool::currentPattern() { return d->currentPattern; } KoAbstractGradient * KisTool::currentGradient() { return d->currentGradient; } KisPaintOpPresetSP KisTool::currentPaintOpPreset() { return canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); } KisNodeSP KisTool::currentNode() const { KisNodeSP node = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); return node; } KisNodeList KisTool::selectedNodes() const { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->nodeManager()->selectedNodes(); } KoColor KisTool::currentFgColor() { return d->currentFgColor; } KoColor KisTool::currentBgColor() { return d->currentBgColor; } KisImageWSP KisTool::currentImage() { return image(); } -KisFilterConfiguration * KisTool::currentGenerator() +KisFilterConfigurationSP KisTool::currentGenerator() { return d->currentGenerator; } void KisTool::setMode(ToolMode mode) { d->m_mode = mode; } KisTool::ToolMode KisTool::mode() const { return d->m_mode; } KisTool::AlternateAction KisTool::actionToAlternateAction(ToolAction action) { KIS_ASSERT_RECOVER_RETURN_VALUE(action != Primary, Secondary); return (AlternateAction)action; } void KisTool::activatePrimaryAction() { resetCursorStyle(); } void KisTool::deactivatePrimaryAction() { resetCursorStyle(); } void KisTool::beginPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::beginPrimaryDoubleClickAction(KoPointerEvent *event) { beginPrimaryAction(event); } void KisTool::continuePrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } bool KisTool::primaryActionSupportsHiResEvents() const { return false; } void KisTool::activateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::deactivateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action) { beginAlternateAction(event, action); } void KisTool::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::mouseDoubleClickEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseTripleClickEvent(KoPointerEvent *event) { mouseDoubleClickEvent(event); } void KisTool::mousePressEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseMoveEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::deleteSelection() { KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), 0, this->canvas()->resourceManager()); if (!KisToolUtils::clearImage(image(), resources->currentNode(), resources->activeSelection())) { KoToolBase::deleteSelection(); } } void KisTool::setupPaintAction(KisRecordedPaintAction* action) { action->setPaintColor(currentFgColor()); action->setBackgroundColor(currentBgColor()); } QWidget* KisTool::createOptionWidget() { d->optionWidget = new QLabel(i18n("No options")); d->optionWidget->setObjectName("SpecialSpacer"); return d->optionWidget; } #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #define PROGRAM_VERTEX_ATTRIBUTE 0 void KisTool::paintToolOutline(QPainter* painter, const QPainterPath &path) { KisOpenGLCanvas2 *canvasWidget = dynamic_cast(canvas()->canvasWidget()); if (canvasWidget) { painter->beginNativePainting(); canvasWidget->paintToolOutline(path); painter->endNativePainting(); } else { painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter->setPen(QColor(128, 255, 128)); painter->drawPath(path); } } void KisTool::resetCursorStyle() { useCursor(d->cursor); } bool KisTool::overrideCursorIfNotEditable() { // override cursor for canvas iff this tool is active // and we can't paint on the active layer if (isActive()) { KisNodeSP node = currentNode(); if (node && !node->isEditable()) { canvas()->setCursor(Qt::ForbiddenCursor); return true; } } return false; } bool KisTool::isActive() const { return d->m_isActive; } void KisTool::slotToggleFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); KoColor newFg = resourceManager->backgroundColor(); KoColor newBg = resourceManager->foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ resourceManager->setBackgroundColor(newBg); resourceManager->setForegroundColor(newFg); } void KisTool::slotResetFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); // see a comment in slotToggleFgBg() resourceManager->setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); resourceManager->setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } void KisTool::setCurrentNodeLocked(bool locked) { if (currentNode()) { currentNode()->setSystemLocked(locked, false); } } bool KisTool::nodeEditable() { KisNodeSP node = currentNode(); if (!node) { return false; } bool nodeEditable = node->isEditable(); if (!nodeEditable) { KisCanvas2 * kiscanvas = static_cast(canvas()); QString message; if (!node->visible() && node->userLocked()) { message = i18n("Layer is locked and invisible."); } else if (node->userLocked()) { message = i18n("Layer is locked."); } else if(!node->visible()) { message = i18n("Layer is invisible."); } else { message = i18n("Group not editable."); } kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked")); } return nodeEditable; } bool KisTool::selectionEditable() { KisCanvas2 * kisCanvas = static_cast(canvas()); KisViewManager * view = kisCanvas->viewManager(); bool editable = view->selectionEditable(); if (!editable) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()->showFloatingMessage(i18n("Local selection is locked."), KisIconUtils::loadIcon("object-locked")); } return editable; } void KisTool::listenToModifiers(bool listen) { Q_UNUSED(listen); } bool KisTool::listeningToModifiers() { return false; } diff --git a/libs/ui/tool/kis_tool.h b/libs/ui/tool/kis_tool.h index ceb88339c7..20de907b4f 100644 --- a/libs/ui/tool/kis_tool.h +++ b/libs/ui/tool/kis_tool.h @@ -1,371 +1,371 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TOOL_H_ #define KIS_TOOL_H_ #include #include #include #include #include #include #include #define PRESS_CONDITION(_event, _mode, _button, _modifier) \ (this->mode() == (_mode) && (_event)->button() == (_button) && \ (_event)->modifiers() == (_modifier)) #define PRESS_CONDITION_WB(_event, _mode, _button, _modifier) \ (this->mode() == (_mode) && (_event)->button() & (_button) && \ (_event)->modifiers() == (_modifier)) #define PRESS_CONDITION_OM(_event, _mode, _button, _modifier) \ (this->mode() == (_mode) && (_event)->button() == (_button) && \ ((_event)->modifiers() & (_modifier) || \ (_event)->modifiers() == Qt::NoModifier)) #define RELEASE_CONDITION(_event, _mode, _button) \ (this->mode() == (_mode) && (_event)->button() == (_button)) #define RELEASE_CONDITION_WB(_event, _mode, _button) \ (this->mode() == (_mode) && (_event)->button() & (_button)) #define MOVE_CONDITION(_event, _mode) (this->mode() == (_mode)) #ifdef __GNUC__ #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come to" << __func__ << "while being mode" << _mode << "!" #else #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come while being mode" << _mode << "!" #endif #define CHECK_MODE_SANITY_OR_RETURN(_mode) if (mode() != _mode) { WARN_WRONG_MODE(mode()); return; } class KoCanvasBase; class KoPattern; class KoAbstractGradient; class KisFilterConfiguration; class QPainter; class QPainterPath; class QPolygonF; class KisRecordedPaintAction; /// Definitions of the toolgroups of Krita static const QString TOOL_TYPE_SHAPE = "0 Krita/Shape"; // Geometric shapes like ellipses and lines static const QString TOOL_TYPE_FREEHAND = "1 Krita/Freehand"; // Freehand drawing tools static const QString TOOL_TYPE_TRANSFORM = "2 Krita/Transform"; // Tools that transform the layer; static const QString TOOL_TYPE_FILL = "3 Krita/Fill"; // Tools that fill parts of the canvas static const QString TOOL_TYPE_VIEW = "4 Krita/View"; // Tools that affect the canvas: pan, zoom, etc. static const QString TOOL_TYPE_SELECTED = "5 Krita/Select"; // Tools that select pixels //activation id for Krita tools, Krita tools are always active and handle locked and invisible layers by themself static const QString KRITA_TOOL_ACTIVATION_ID = "flake/always"; class KRITAUI_EXPORT KisTool : public KoToolBase { Q_OBJECT Q_PROPERTY(bool isActive READ isActive NOTIFY isActiveChanged) public: enum { FLAG_USES_CUSTOM_PRESET=0x01, FLAG_USES_CUSTOM_COMPOSITEOP=0x02 }; KisTool(KoCanvasBase * canvas, const QCursor & cursor); virtual ~KisTool(); virtual int flags() const { return 0; } void deleteSelection(); // KoToolBase Implementation. public: /** * Called by KisToolProxy when the primary action of the tool is * going to be started now, that is when all the modifiers are * pressed and the only thing left is just to press the mouse * button. On coming of this callback the tool is supposed to * prepare the cursor and/or the outline to show the user shat is * going to happen next */ virtual void activatePrimaryAction(); /** * Called by KisToolProxy when the primary is no longer possible * to be started now, e.g. when its modifiers and released. The * tool is supposed revert all the preparetions it has doen in * activatePrimaryAction(). */ virtual void deactivatePrimaryAction(); /** * Called by KisToolProxy when a primary action for the tool is * started. The \p event stores the original event that * started the stroke. The \p event is _accepted_ by default. If * the tool decides to ignore this particular action (e.g. when * the node is not editable), it should call event->ignore(). Then * no further continuePrimaryAction() or endPrimaryAction() will * be called until the next user action. */ virtual void beginPrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is in progress * of pointer movement. If the tool has ignored the event in * beginPrimaryAction(), this method will not be called. */ virtual void continuePrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is being * finished, that is while mouseRelease or tabletRelease event. * If the tool has ignored the event in beginPrimaryAction(), this * method will not be called. */ virtual void endPrimaryAction(KoPointerEvent *event); /** * The same as beginPrimaryAction(), but called when the stroke is * started by a double-click * * \see beginPrimaryAction() */ virtual void beginPrimaryDoubleClickAction(KoPointerEvent *event); /** * Returns true if the tool can handle (and wants to handle) a * very tight flow of input events from the tablet */ virtual bool primaryActionSupportsHiResEvents() const; enum ToolAction { Primary, AlternateChangeSize, AlternatePickFgNode, AlternatePickBgNode, AlternatePickFgImage, AlternatePickBgImage, AlternateSecondary, AlternateThird, AlternateFourth, AlternateFifth, Alternate_NONE = 10000 }; // Technically users are allowed to configure this, but nobody ever would do that. // So these can basically be thought of as aliases to ctrl+click, etc. enum AlternateAction { ChangeSize = AlternateChangeSize, // Default: Shift+Left click PickFgNode = AlternatePickFgNode, // Default: Ctrl+Alt+Left click PickBgNode = AlternatePickBgNode, // Default: Ctrl+Alt+Right click PickFgImage = AlternatePickFgImage, // Default: Ctrl+Left click PickBgImage = AlternatePickBgImage, // Default: Ctrl+Right click Secondary = AlternateSecondary, Third = AlternateThird, Fourth = AlternateFourth, Fifth = AlternateFifth, NONE = 10000 }; static AlternateAction actionToAlternateAction(ToolAction action); virtual void activateAlternateAction(AlternateAction action); virtual void deactivateAlternateAction(AlternateAction action); virtual void beginAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void continueAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void endAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action); void mousePressEvent(KoPointerEvent *event); void mouseDoubleClickEvent(KoPointerEvent *event); void mouseTripleClickEvent(KoPointerEvent *event); void mouseReleaseEvent(KoPointerEvent *event); void mouseMoveEvent(KoPointerEvent *event); bool isActive() const; public Q_SLOTS: virtual void activate(ToolActivation toolActivation, const QSet &shapes); virtual void deactivate(); virtual void canvasResourceChanged(int key, const QVariant & res); // Implement this slot in case there are any widgets or properties which need // to be updated after certain operations, to reflect the inner state correctly. // At the moment this is used for smoothing options in the freehand brush, but // this will likely be expanded. virtual void updateSettingsViews(); Q_SIGNALS: void isActiveChanged(); protected: // conversion methods are also needed by the paint information builder friend class KisToolPaintingInformationBuilder; /// Convert from native (postscript points) to image pixel /// coordinates. QPointF convertToPixelCoord(KoPointerEvent *e); QPointF convertToPixelCoord(const QPointF& pt); QPointF convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset = QPointF(), bool useModifiers = true); QPointF convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset = QPointF()); protected: QPointF widgetCenterInWidgetPixels(); QPointF convertDocumentToWidget(const QPointF& pt); /// Convert from native (postscript points) to integer image pixel /// coordinates. This truncates the floating point components and /// should be used in preference to QPointF::toPoint(), which rounds, /// to ensure the cursor acts on the pixel it is visually over. QPoint convertToIntPixelCoord(KoPointerEvent *e); QRectF convertToPt(const QRectF &rect); QPointF viewToPixel(const QPointF &viewCoord) const; /// Convert an integer pixel coordinate into a view coordinate. /// The view coordinate is at the centre of the pixel. QPointF pixelToView(const QPoint &pixelCoord) const; /// Convert a floating point pixel coordinate into a view coordinate. QPointF pixelToView(const QPointF &pixelCoord) const; /// Convert a pixel rectangle into a view rectangle. QRectF pixelToView(const QRectF &pixelRect) const; /// Convert a pixel path into a view path QPainterPath pixelToView(const QPainterPath &pixelPath) const; /// Convert a pixel polygon into a view path QPolygonF pixelToView(const QPolygonF &pixelPolygon) const; /// Update the canvas for the given rectangle in image pixel coordinates. void updateCanvasPixelRect(const QRectF &pixelRect); /// Update the canvas for the given rectangle in view coordinates. void updateCanvasViewRect(const QRectF &viewRect); virtual QWidget* createOptionWidget(); /** * To determine whether this tool will change its behavior when * modifier keys are pressed */ virtual bool listeningToModifiers(); /** * Request that this tool no longer listen to modifier keys * (Responding to the request is optional) */ virtual void listenToModifiers(bool listen); protected: KisImageWSP image() const; QCursor cursor() const; /// Call this to set the document modified void notifyModified() const; KisImageWSP currentImage(); KoPattern* currentPattern(); KoAbstractGradient *currentGradient(); KisNodeSP currentNode() const; KisNodeList selectedNodes() const; KoColor currentFgColor(); KoColor currentBgColor(); KisPaintOpPresetSP currentPaintOpPreset(); - KisFilterConfiguration *currentGenerator(); + KisFilterConfigurationSP currentGenerator(); virtual void setupPaintAction(KisRecordedPaintAction* action); /// paint the path which is in view coordinates, default paint mode is XOR_MODE, BW_MODE is also possible /// never apply transformations to the painter, they would be useless, if drawing in OpenGL mode. The coordinates in the path should be in view coordinates. void paintToolOutline(QPainter * painter, const QPainterPath &path); /// Sets the systemLocked for the current node, this will not deactivate the tool buttons void setCurrentNodeLocked(bool locked); /// Checks checks if the current node is editable bool nodeEditable(); /// Checks checks if the selection is editable, only applies to local selection as global selection is always editable bool selectionEditable(); /// Override the cursor appropriately if current node is not editable bool overrideCursorIfNotEditable(); protected: enum ToolMode { HOVER_MODE, PAINT_MODE, SECONDARY_PAINT_MODE, MIRROR_AXIS_SETUP_MODE, GESTURE_MODE, PAN_MODE, OTHER // not used now }; virtual void setMode(ToolMode mode); virtual ToolMode mode() const; protected Q_SLOTS: /** * Called whenever the configuration settings change. */ virtual void resetCursorStyle(); /** * Called when the user requested undo while the stroke is * active. If you tool supports undo of the part of its actions, * override this method and do the needed work there. * * NOTE: Default implementation forwards this request to * requestStrokeCancellation() method, so that the stroke * would be cancelled. */ virtual void requestUndoDuringStroke(); /** * Called when the user requested the cancellation of the current * stroke. If you tool supports cancelling, override this method * and do the needed work there */ virtual void requestStrokeCancellation(); /** * Called when the image decided that the stroke should better be * ended. If you tool supports long strokes, override this method * and do the needed work there */ virtual void requestStrokeEnd(); private Q_SLOTS: void slotToggleFgBg(); void slotResetFgBg(); private: struct Private; Private* const d; }; #endif // KIS_TOOL_H_ diff --git a/libs/ui/tool/kis_tool_freehand_helper.cpp b/libs/ui/tool/kis_tool_freehand_helper.cpp index e73c8a456b..52e088dcb3 100644 --- a/libs/ui/tool/kis_tool_freehand_helper.cpp +++ b/libs/ui/tool/kis_tool_freehand_helper.cpp @@ -1,854 +1,854 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_freehand_helper.h" #include #include #include #include #include #include #include "kis_painting_information_builder.h" #include "kis_recording_adapter.h" #include "kis_image.h" #include "kis_painter.h" #include #include #include "kis_update_time_monitor.h" #include "kis_stabilized_events_sampler.h" #include "kis_config.h" #include //#define DEBUG_BEZIER_CURVES struct KisToolFreehandHelper::Private { KisPaintingInformationBuilder *infoBuilder; KisRecordingAdapter *recordingAdapter; KisStrokesFacade *strokesFacade; KUndo2MagicString transactionText; bool haveTangent; QPointF previousTangent; bool hasPaintAtLeastOnce; QTime strokeTime; QTimer strokeTimeoutTimer; QVector painterInfos; KisResourcesSnapshotSP resources; KisStrokeId strokeId; KisPaintInformation previousPaintInformation; KisPaintInformation olderPaintInformation; KisSmoothingOptionsSP smoothingOptions; QTimer airbrushingTimer; QList history; QList distanceHistory; KisPaintOpUtils::PositionHistory lastOutlinePos; // Stabilizer data QQueue stabilizerDeque; QTimer stabilizerPollTimer; KisStabilizedEventsSampler stabilizedSampler; int canvasRotation; bool canvasMirroredH; KisPaintInformation getStabilizedPaintInfo(const QQueue &queue, const KisPaintInformation &lastPaintInfo); qreal effectiveSmoothnessDistance() const; }; KisToolFreehandHelper::KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder, const KUndo2MagicString &transactionText, KisRecordingAdapter *recordingAdapter) : m_d(new Private()) { m_d->infoBuilder = infoBuilder; m_d->recordingAdapter = recordingAdapter; m_d->transactionText = transactionText; m_d->smoothingOptions = KisSmoothingOptionsSP(new KisSmoothingOptions()); m_d->canvasRotation = 0; m_d->strokeTimeoutTimer.setSingleShot(true); connect(&m_d->strokeTimeoutTimer, SIGNAL(timeout()), SLOT(finishStroke())); connect(&m_d->airbrushingTimer, SIGNAL(timeout()), SLOT(doAirbrushing())); connect(&m_d->stabilizerPollTimer, SIGNAL(timeout()), SLOT(stabilizerPollAndPaint())); } KisToolFreehandHelper::~KisToolFreehandHelper() { delete m_d; } void KisToolFreehandHelper::setSmoothness(KisSmoothingOptionsSP smoothingOptions) { m_d->smoothingOptions = smoothingOptions; } KisSmoothingOptionsSP KisToolFreehandHelper::smoothingOptions() const { return m_d->smoothingOptions; } QPainterPath KisToolFreehandHelper::paintOpOutline(const QPointF &savedCursorPos, const KoPointerEvent *event, - const KisPaintOpSettings *globalSettings, + const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const { - const KisPaintOpSettings *settings = globalSettings; + KisPaintOpSettingsSP settings = globalSettings; KisPaintInformation info = m_d->infoBuilder->hover(savedCursorPos, event); info.setCanvasRotation(m_d->canvasRotation); info.setCanvasHorizontalMirrorState( m_d->canvasMirroredH ); KisDistanceInformation distanceInfo(m_d->lastOutlinePos.pushThroughHistory(savedCursorPos), 0); if (!m_d->painterInfos.isEmpty()) { settings = m_d->resources->currentPaintOpPreset()->settings(); info = m_d->previousPaintInformation; /** * When LoD mode is active it may happen that the helper has * already started a stroke, but it painted noting, because * all the work is being calculated by the scaled-down LodN * stroke. So at first we try to fetch the data from the lodN * stroke ("buddy") and then check if there is at least * something has been painted with this distance information * object. */ KisDistanceInformation *buddyDistance = m_d->painterInfos.first()->buddyDragDistance(); if (buddyDistance) { /** * Tiny hack alert: here we fetch the distance information * directly from the LodN stroke. Ideally, we should * upscale its data, but here we just override it with our * local copy of the coordinates. */ distanceInfo = *buddyDistance; distanceInfo.overrideLastValues(m_d->lastOutlinePos.pushThroughHistory(savedCursorPos), 0); } else if (m_d->painterInfos.first()->dragDistance->isStarted()) { distanceInfo = *m_d->painterInfos.first()->dragDistance; } } KisPaintInformation::DistanceInformationRegistrar registrar = info.registerDistanceInformation(&distanceInfo); QPainterPath outline = settings->brushOutline(info, mode); if (m_d->resources && m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER && m_d->smoothingOptions->useDelayDistance()) { const qreal R = m_d->smoothingOptions->delayDistance() / m_d->resources->effectiveZoom(); outline.addEllipse(info.pos(), R, R); } return outline; } void KisToolFreehandHelper::initPaint(KoPointerEvent *event, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisPostExecutionUndoAdapter *undoAdapter, KisNodeSP overrideNode, KisDefaultBoundsBaseSP bounds) { KisPaintInformation pi = m_d->infoBuilder->startStroke(event, elapsedStrokeTime(), resourceManager); initPaintImpl(pi, resourceManager, image, currentNode, strokesFacade, undoAdapter, overrideNode, bounds); } bool KisToolFreehandHelper::isRunning() const { return m_d->strokeId; } void KisToolFreehandHelper::initPaintImpl(const KisPaintInformation &previousPaintInformation, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisPostExecutionUndoAdapter *undoAdapter, KisNodeSP overrideNode, KisDefaultBoundsBaseSP bounds) { Q_UNUSED(overrideNode); m_d->strokesFacade = strokesFacade; m_d->haveTangent = false; m_d->previousTangent = QPointF(); m_d->hasPaintAtLeastOnce = false; m_d->strokeTime.start(); m_d->previousPaintInformation = previousPaintInformation; createPainters(m_d->painterInfos, m_d->previousPaintInformation.pos(), m_d->previousPaintInformation.currentTime()); m_d->resources = new KisResourcesSnapshot(image, currentNode, undoAdapter, resourceManager, bounds); if(overrideNode) { m_d->resources->setCurrentNode(overrideNode); } if(m_d->recordingAdapter) { m_d->recordingAdapter->startStroke(image, m_d->resources); } KisStrokeStrategy *stroke = new FreehandStrokeStrategy(m_d->resources->needsIndirectPainting(), m_d->resources->indirectPaintingCompositeOp(), m_d->resources, m_d->painterInfos, m_d->transactionText); m_d->strokeId = m_d->strokesFacade->startStroke(stroke); m_d->history.clear(); m_d->distanceHistory.clear(); if(m_d->resources->needsAirbrushing()) { m_d->airbrushingTimer.setInterval(m_d->resources->airbrushingRate()); m_d->airbrushingTimer.start(); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { stabilizerStart(m_d->previousPaintInformation); } } void KisToolFreehandHelper::paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2) { if (tangent1.isNull() || tangent2.isNull()) return; const qreal maxSanePoint = 1e6; QPointF controlTarget1; QPointF controlTarget2; // Shows the direction in which control points go QPointF controlDirection1 = pi1.pos() + tangent1; QPointF controlDirection2 = pi2.pos() - tangent2; // Lines in the direction of the control points QLineF line1(pi1.pos(), controlDirection1); QLineF line2(pi2.pos(), controlDirection2); // Lines to check whether the control points lay on the opposite // side of the line QLineF line3(controlDirection1, controlDirection2); QLineF line4(pi1.pos(), pi2.pos()); QPointF intersection; if (line3.intersect(line4, &intersection) == QLineF::BoundedIntersection) { qreal controlLength = line4.length() / 2; line1.setLength(controlLength); line2.setLength(controlLength); controlTarget1 = line1.p2(); controlTarget2 = line2.p2(); } else { QLineF::IntersectType type = line1.intersect(line2, &intersection); if (type == QLineF::NoIntersection || intersection.manhattanLength() > maxSanePoint) { intersection = 0.5 * (pi1.pos() + pi2.pos()); // dbgKrita << "WARINING: there is no intersection point " // << "in the basic smoothing algoriths"; } controlTarget1 = intersection; controlTarget2 = intersection; } // shows how near to the controlTarget the value raises qreal coeff = 0.8; qreal velocity1 = QLineF(QPointF(), tangent1).length(); qreal velocity2 = QLineF(QPointF(), tangent2).length(); if (velocity1 == 0.0 || velocity2 == 0.0) { velocity1 = 1e-6; velocity2 = 1e-6; warnKrita << "WARNING: Basic Smoothing: Velocity is Zero! Please report a bug:" << ppVar(velocity1) << ppVar(velocity2); } qreal similarity = qMin(velocity1/velocity2, velocity2/velocity1); // the controls should not differ more than 50% similarity = qMax(similarity, qreal(0.5)); // when the controls are symmetric, their size should be smaller // to avoid corner-like curves coeff *= 1 - qMax(qreal(0.0), similarity - qreal(0.8)); Q_ASSERT(coeff > 0); QPointF control1; QPointF control2; if (velocity1 > velocity2) { control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1; coeff *= similarity; control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2; } else { control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2; coeff *= similarity; control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1; } paintBezierCurve(pi1, control1, control2, pi2); } qreal KisToolFreehandHelper::Private::effectiveSmoothnessDistance() const { const qreal effectiveSmoothnessDistance = !smoothingOptions->useScalableDistance() ? smoothingOptions->smoothnessDistance() : smoothingOptions->smoothnessDistance() / resources->effectiveZoom(); return effectiveSmoothnessDistance; } void KisToolFreehandHelper::paint(KoPointerEvent *event) { KisPaintInformation info = m_d->infoBuilder->continueStroke(event, elapsedStrokeTime()); info.setCanvasRotation( m_d->canvasRotation ); info.setCanvasHorizontalMirrorState( m_d->canvasMirroredH ); KisUpdateTimeMonitor::instance()->reportMouseMove(info.pos()); /** * Smooth the coordinates out using the history and the * distance. This is a heavily modified version of an algo used in * Gimp and described in https://bugs.kde.org/show_bug.cgi?id=281267 and * http://www24.atwiki.jp/sigetch_2007/pages/17.html. The main * differences are: * * 1) It uses 'distance' instead of 'velocity', since time * measurements are too unstable in realworld environment * * 2) There is no 'Quality' parameter, since the number of samples * is calculated automatically * * 3) 'Tail Aggressiveness' is used for controling the end of the * stroke * * 4) The formila is a little bit different: 'Distance' parameter * stands for $3 \Sigma$ */ if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::WEIGHTED_SMOOTHING && m_d->smoothingOptions->smoothnessDistance() > 0.0) { { // initialize current distance QPointF prevPos; if (!m_d->history.isEmpty()) { const KisPaintInformation &prevPi = m_d->history.last(); prevPos = prevPi.pos(); } else { prevPos = m_d->previousPaintInformation.pos(); } qreal currentDistance = QVector2D(info.pos() - prevPos).length(); m_d->distanceHistory.append(currentDistance); } m_d->history.append(info); qreal x = 0.0; qreal y = 0.0; if (m_d->history.size() > 3) { const qreal sigma = m_d->effectiveSmoothnessDistance() / 3.0; // '3.0' for (3 * sigma) range qreal gaussianWeight = 1 / (sqrt(2 * M_PI) * sigma); qreal gaussianWeight2 = sigma * sigma; qreal distanceSum = 0.0; qreal scaleSum = 0.0; qreal pressure = 0.0; qreal baseRate = 0.0; Q_ASSERT(m_d->history.size() == m_d->distanceHistory.size()); for (int i = m_d->history.size() - 1; i >= 0; i--) { qreal rate = 0.0; const KisPaintInformation nextInfo = m_d->history.at(i); double distance = m_d->distanceHistory.at(i); Q_ASSERT(distance >= 0.0); qreal pressureGrad = 0.0; if (i < m_d->history.size() - 1) { pressureGrad = nextInfo.pressure() - m_d->history.at(i + 1).pressure(); const qreal tailAgressiveness = 40.0 * m_d->smoothingOptions->tailAggressiveness(); if (pressureGrad > 0.0 ) { pressureGrad *= tailAgressiveness * (1.0 - nextInfo.pressure()); distance += pressureGrad * 3.0 * sigma; // (3 * sigma) --- holds > 90% of the region } } if (gaussianWeight2 != 0.0) { distanceSum += distance; rate = gaussianWeight * exp(-distanceSum * distanceSum / (2 * gaussianWeight2)); } if (m_d->history.size() - i == 1) { baseRate = rate; } else if (baseRate / rate > 100) { break; } scaleSum += rate; x += rate * nextInfo.pos().x(); y += rate * nextInfo.pos().y(); if (m_d->smoothingOptions->smoothPressure()) { pressure += rate * nextInfo.pressure(); } } if (scaleSum != 0.0) { x /= scaleSum; y /= scaleSum; if (m_d->smoothingOptions->smoothPressure()) { pressure /= scaleSum; } } if ((x != 0.0 && y != 0.0) || (x == info.pos().x() && y == info.pos().y())) { info.setPos(QPointF(x, y)); if (m_d->smoothingOptions->smoothPressure()) { info.setPressure(pressure); } m_d->history.last() = info; } } } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::SIMPLE_SMOOTHING || m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::WEIGHTED_SMOOTHING) { // Now paint between the coordinates, using the bezier curve interpolation if (!m_d->haveTangent) { m_d->haveTangent = true; m_d->previousTangent = (info.pos() - m_d->previousPaintInformation.pos()) / qMax(qreal(1.0), info.currentTime() - m_d->previousPaintInformation.currentTime()); } else { QPointF newTangent = (info.pos() - m_d->olderPaintInformation.pos()) / qMax(qreal(1.0), info.currentTime() - m_d->olderPaintInformation.currentTime()); paintBezierSegment(m_d->olderPaintInformation, m_d->previousPaintInformation, m_d->previousTangent, newTangent); m_d->previousTangent = newTangent; } m_d->olderPaintInformation = m_d->previousPaintInformation; m_d->strokeTimeoutTimer.start(100); } else if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::NO_SMOOTHING){ paintLine(m_d->previousPaintInformation, info); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { m_d->stabilizedSampler.addEvent(info); } else { m_d->previousPaintInformation = info; } if(m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.start(); } } void KisToolFreehandHelper::endPaint() { if (!m_d->hasPaintAtLeastOnce) { paintAt(m_d->previousPaintInformation); } else if (m_d->smoothingOptions->smoothingType() != KisSmoothingOptions::NO_SMOOTHING) { finishStroke(); } m_d->strokeTimeoutTimer.stop(); if(m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.stop(); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { stabilizerEnd(); } /** * There might be some timer events still pending, so * we should cancel them. Use this flag for the purpose. * Please note that we are not in MT here, so no mutex * is needed */ m_d->painterInfos.clear(); m_d->strokesFacade->endStroke(m_d->strokeId); m_d->strokeId.clear(); if(m_d->recordingAdapter) { m_d->recordingAdapter->endStroke(); } } void KisToolFreehandHelper::cancelPaint() { if (!m_d->strokeId) return; m_d->strokeTimeoutTimer.stop(); if (m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.stop(); } if (m_d->stabilizerPollTimer.isActive()) { m_d->stabilizerPollTimer.stop(); } // see a comment in endPaint() m_d->painterInfos.clear(); m_d->strokesFacade->cancelStroke(m_d->strokeId); m_d->strokeId.clear(); if(m_d->recordingAdapter) { //FIXME: not implemented //m_d->recordingAdapter->cancelStroke(); } } int KisToolFreehandHelper::elapsedStrokeTime() const { return m_d->strokeTime.elapsed(); } void KisToolFreehandHelper::stabilizerStart(KisPaintInformation firstPaintInfo) { // FIXME: Ugly hack, this is no a "distance" in any way int sampleSize = qRound(m_d->effectiveSmoothnessDistance()); sampleSize = qMax(3, sampleSize); // Fill the deque with the current value repeated until filling the sample m_d->stabilizerDeque.clear(); for (int i = sampleSize; i > 0; i--) { m_d->stabilizerDeque.enqueue(firstPaintInfo); } // Poll and draw regularly KisConfig cfg; m_d->stabilizerPollTimer.setInterval(cfg.stabilizerSampleSize()); m_d->stabilizerPollTimer.start(); m_d->stabilizedSampler.clear(); } KisPaintInformation KisToolFreehandHelper::Private::getStabilizedPaintInfo(const QQueue &queue, const KisPaintInformation &lastPaintInfo) { KisPaintInformation result(lastPaintInfo); if (queue.size() > 1) { QQueue::const_iterator it = queue.constBegin(); QQueue::const_iterator end = queue.constEnd(); /** * The first point is going to be overridden by lastPaintInfo, skip it. */ it++; int i = 2; if (smoothingOptions->stabilizeSensors()) { while (it != end) { qreal k = qreal(i - 1) / i; // coeff for uniform averaging result = KisPaintInformation::mix(k, *it, result); it++; i++; } } else{ while (it != end) { qreal k = qreal(i - 1) / i; // coeff for uniform averaging result = KisPaintInformation::mixOnlyPosition(k, *it, result); it++; i++; } } } return result; } void KisToolFreehandHelper::stabilizerPollAndPaint() { KisStabilizedEventsSampler::iterator it; KisStabilizedEventsSampler::iterator end; std::tie(it, end) = m_d->stabilizedSampler.range(); for (; it != end; ++it) { KisPaintInformation sampledInfo = *it; bool canPaint = true; if (m_d->smoothingOptions->useDelayDistance()) { const qreal R = m_d->smoothingOptions->delayDistance() / m_d->resources->effectiveZoom(); QPointF diff = sampledInfo.pos() - m_d->previousPaintInformation.pos(); qreal dx = sqrt(pow2(diff.x()) + pow2(diff.y())); canPaint = dx > R; } if (canPaint) { KisPaintInformation newInfo = m_d->getStabilizedPaintInfo(m_d->stabilizerDeque, sampledInfo); paintLine(m_d->previousPaintInformation, newInfo); m_d->previousPaintInformation = newInfo; // Push the new entry through the queue m_d->stabilizerDeque.dequeue(); m_d->stabilizerDeque.enqueue(sampledInfo); emit requestExplicitUpdateOutline(); } else if (m_d->stabilizerDeque.head().pos() != m_d->previousPaintInformation.pos()) { QQueue::iterator it = m_d->stabilizerDeque.begin(); QQueue::iterator end = m_d->stabilizerDeque.end(); while (it != end) { *it = m_d->previousPaintInformation; ++it; } } } m_d->stabilizedSampler.clear(); } void KisToolFreehandHelper::stabilizerEnd() { // Stop the timer m_d->stabilizerPollTimer.stop(); // Finish the line if (m_d->smoothingOptions->finishStabilizedCurve()) { // In each iteration we add the latest paint info and delete the oldest // After `sampleSize` iterations the deque will be filled with the latest // value and we will have reached the end point. m_d->stabilizedSampler.addFinishingEvent(m_d->stabilizerDeque.size()); stabilizerPollAndPaint(); } } const KisPaintOp* KisToolFreehandHelper::currentPaintOp() const { return !m_d->painterInfos.isEmpty() ? m_d->painterInfos.first()->painter->paintOp() : 0; } void KisToolFreehandHelper::finishStroke() { if (m_d->haveTangent) { m_d->haveTangent = false; QPointF newTangent = (m_d->previousPaintInformation.pos() - m_d->olderPaintInformation.pos()) / (m_d->previousPaintInformation.currentTime() - m_d->olderPaintInformation.currentTime()); paintBezierSegment(m_d->olderPaintInformation, m_d->previousPaintInformation, m_d->previousTangent, newTangent); } } void KisToolFreehandHelper::doAirbrushing() { if(!m_d->painterInfos.isEmpty()) { paintAt(m_d->previousPaintInformation); } } void KisToolFreehandHelper::paintAt(int painterInfoId, const KisPaintInformation &pi) { m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(m_d->resources->currentNode(), painterInfoId, pi)); if(m_d->recordingAdapter) { m_d->recordingAdapter->addPoint(pi); } } void KisToolFreehandHelper::paintLine(int painterInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2) { m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(m_d->resources->currentNode(), painterInfoId, pi1, pi2)); if(m_d->recordingAdapter) { m_d->recordingAdapter->addLine(pi1, pi2); } } void KisToolFreehandHelper::paintBezierCurve(int painterInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) { #ifdef DEBUG_BEZIER_CURVES KisPaintInformation tpi1; KisPaintInformation tpi2; tpi1 = pi1; tpi2 = pi2; tpi1.setPressure(0.3); tpi2.setPressure(0.3); paintLine(tpi1, tpi2); tpi1.setPressure(0.6); tpi2.setPressure(0.3); tpi1.setPos(pi1.pos()); tpi2.setPos(control1); paintLine(tpi1, tpi2); tpi1.setPos(pi2.pos()); tpi2.setPos(control2); paintLine(tpi1, tpi2); #endif m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(m_d->resources->currentNode(), painterInfoId, pi1, control1, control2, pi2)); if(m_d->recordingAdapter) { m_d->recordingAdapter->addCurve(pi1, control1, control2, pi2); } } void KisToolFreehandHelper::createPainters(QVector &painterInfos, const QPointF &lastPosition, int lastTime) { painterInfos << new PainterInfo(lastPosition, lastTime); } void KisToolFreehandHelper::paintAt(const KisPaintInformation &pi) { paintAt(0, pi); } void KisToolFreehandHelper::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) { paintLine(0, pi1, pi2); } void KisToolFreehandHelper::paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) { paintBezierCurve(0, pi1, control1, control2, pi2); } int KisToolFreehandHelper::canvasRotation() { return m_d->canvasRotation; } void KisToolFreehandHelper::setCanvasRotation(int rotation) { - m_d->canvasRotation = rotation; + m_d->canvasRotation = rotation; } bool KisToolFreehandHelper::canvasMirroredH() { return m_d->canvasMirroredH; } void KisToolFreehandHelper::setCanvasHorizontalMirrorState(bool mirrored) { - m_d->canvasMirroredH = mirrored; + m_d->canvasMirroredH = mirrored; } diff --git a/libs/ui/tool/kis_tool_freehand_helper.h b/libs/ui/tool/kis_tool_freehand_helper.h index 771651a383..cd3ae67678 100644 --- a/libs/ui/tool/kis_tool_freehand_helper.h +++ b/libs/ui/tool/kis_tool_freehand_helper.h @@ -1,153 +1,153 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TOOL_FREEHAND_HELPER_H #define __KIS_TOOL_FREEHAND_HELPER_H #include #include "kis_types.h" #include "kritaui_export.h" #include #include "kis_default_bounds.h" #include #include "kis_smoothing_options.h" #include "strokes/freehand_stroke.h" class KoPointerEvent; class KoCanvasResourceManager; class KisPaintingInformationBuilder; class KisRecordingAdapter; class KisStrokesFacade; class KisPostExecutionUndoAdapter; class KisPaintOp; class KRITAUI_EXPORT KisToolFreehandHelper : public QObject { Q_OBJECT protected: typedef FreehandStrokeStrategy::PainterInfo PainterInfo; public: KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder, const KUndo2MagicString &transactionText = KUndo2MagicString(), KisRecordingAdapter *recordingAdapter = 0); ~KisToolFreehandHelper(); void setSmoothness(KisSmoothingOptionsSP smoothingOptions); KisSmoothingOptionsSP smoothingOptions() const; bool isRunning() const; void initPaint(KoPointerEvent *event, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisPostExecutionUndoAdapter *undoAdapter, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); void paint(KoPointerEvent *event); void endPaint(); const KisPaintOp* currentPaintOp() const; QPainterPath paintOpOutline(const QPointF &savedCursorPos, const KoPointerEvent *event, - const KisPaintOpSettings *globalSettings, + const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const; int canvasRotation(); void setCanvasRotation(int rotation = 0); bool canvasMirroredH(); void setCanvasHorizontalMirrorState (bool mirrored = false); Q_SIGNALS: /** * The signal is emitted when the outline should be updated * explicitly by the tool. Used by Stabilizer option, because it * paints on internal timer events instead of the on every paint() * event */ void requestExplicitUpdateOutline(); protected: void cancelPaint(); int elapsedStrokeTime() const; void initPaintImpl(const KisPaintInformation &previousPaintInformation, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade, KisPostExecutionUndoAdapter *undoAdapter, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); protected: virtual void createPainters(QVector &painterInfos, const QPointF &lastPosition, int lastTime); // lo-level methods for painting primitives void paintAt(int painterInfoId, const KisPaintInformation &pi); void paintLine(int painterInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2); void paintBezierCurve(int painterInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); // hi-level methods for painting primitives virtual void paintAt(const KisPaintInformation &pi); virtual void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); virtual void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); private: void paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2); void stabilizerStart(KisPaintInformation firstPaintInfo); void stabilizerEnd(); private Q_SLOTS: void finishStroke(); void doAirbrushing(); void stabilizerPollAndPaint(); private: struct Private; Private * const m_d; }; #endif /* __KIS_TOOL_FREEHAND_HELPER_H */ diff --git a/libs/ui/tool/strokes/freehand_stroke.cpp b/libs/ui/tool/strokes/freehand_stroke.cpp index d3b329c838..322b80f004 100644 --- a/libs/ui/tool/strokes/freehand_stroke.cpp +++ b/libs/ui/tool/strokes/freehand_stroke.cpp @@ -1,141 +1,150 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "freehand_stroke.h" #include "kis_canvas_resource_provider.h" #include #include #include "kis_painter.h" #include "kis_update_time_monitor.h" #include struct FreehandStrokeStrategy::Private { Private(KisResourcesSnapshotSP _resources) : resources(_resources) {} KisStrokeRandomSource randomSource; KisResourcesSnapshotSP resources; }; FreehandStrokeStrategy::FreehandStrokeStrategy(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp, KisResourcesSnapshotSP resources, PainterInfo *painterInfo, const KUndo2MagicString &name) : KisPainterBasedStrokeStrategy("FREEHAND_STROKE", name, resources, painterInfo), m_d(new Private(resources)) { init(needsIndirectPainting, indirectPaintingCompositeOp); } FreehandStrokeStrategy::FreehandStrokeStrategy(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp, KisResourcesSnapshotSP resources, QVector painterInfos, const KUndo2MagicString &name) : KisPainterBasedStrokeStrategy("FREEHAND_STROKE", name, resources, painterInfos), m_d(new Private(resources)) { init(needsIndirectPainting, indirectPaintingCompositeOp); } FreehandStrokeStrategy::FreehandStrokeStrategy(const FreehandStrokeStrategy &rhs, int levelOfDetail) : KisPainterBasedStrokeStrategy(rhs, levelOfDetail), m_d(new Private(*rhs.m_d)) { m_d->randomSource.setLevelOfDetail(levelOfDetail); } FreehandStrokeStrategy::~FreehandStrokeStrategy() { KisUpdateTimeMonitor::instance()->endStrokeMeasure(); } void FreehandStrokeStrategy::init(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp) { setNeedsIndirectPainting(needsIndirectPainting); setIndirectPaintingCompositeOp(indirectPaintingCompositeOp); setSupportsWrapAroundMode(true); enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE); KisUpdateTimeMonitor::instance()->startStrokeMeasure(); } void FreehandStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) { Data *d = dynamic_cast(data); PainterInfo *info = painterInfos()[d->painterInfoId]; KisUpdateTimeMonitor::instance()->reportPaintOpPreset(info->painter->preset()); KisRandomSourceSP rnd = m_d->randomSource.source(); switch(d->type) { case Data::POINT: d->pi1.setRandomSource(rnd); info->painter->paintAt(d->pi1, info->dragDistance); break; case Data::LINE: d->pi1.setRandomSource(rnd); d->pi2.setRandomSource(rnd); info->painter->paintLine(d->pi1, d->pi2, info->dragDistance); break; case Data::CURVE: d->pi1.setRandomSource(rnd); d->pi2.setRandomSource(rnd); info->painter->paintBezierCurve(d->pi1, d->control1, d->control2, d->pi2, info->dragDistance); break; case Data::POLYLINE: info->painter->paintPolyline(d->points, 0, d->points.size()); break; case Data::POLYGON: info->painter->paintPolygon(d->points); break; case Data::RECT: info->painter->paintRect(d->rect); break; case Data::ELLIPSE: info->painter->paintEllipse(d->rect); break; case Data::PAINTER_PATH: info->painter->paintPainterPath(d->path); + break; + case Data::QPAINTER_PATH: + info->painter->drawPainterPath(d->path, d->pen); + break; + case Data::QPAINTER_PATH_FILL: { + info->painter->setBackgroundColor(d->customColor); + info->painter->fillPainterPath(d->path);} + info->painter->drawPainterPath(d->path, d->pen); + }; QVector dirtyRects = info->painter->takeDirtyRegion(); KisUpdateTimeMonitor::instance()->reportJobFinished(data, dirtyRects); d->node->setDirty(dirtyRects); } KisStrokeStrategy* FreehandStrokeStrategy::createLodClone(int levelOfDetail) { if (!m_d->resources->presetAllowsLod()) return 0; FreehandStrokeStrategy *clone = new FreehandStrokeStrategy(*this, levelOfDetail); clone->setUndoEnabled(false); return clone; } diff --git a/libs/ui/tool/strokes/freehand_stroke.h b/libs/ui/tool/strokes/freehand_stroke.h index 8f0e4a4087..a63d39a4a6 100644 --- a/libs/ui/tool/strokes/freehand_stroke.h +++ b/libs/ui/tool/strokes/freehand_stroke.h @@ -1,180 +1,194 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __FREEHAND_STROKE_H #define __FREEHAND_STROKE_H #include "kritaui_export.h" #include "kis_types.h" #include "kis_node.h" #include "kis_painter_based_stroke_strategy.h" #include #include #include "kis_lod_transform.h" +#include "KoColor.h" class KRITAUI_EXPORT FreehandStrokeStrategy : public KisPainterBasedStrokeStrategy { public: class Data : public KisStrokeJobData { public: enum DabType { POINT, LINE, CURVE, POLYLINE, POLYGON, RECT, ELLIPSE, - PAINTER_PATH + PAINTER_PATH, + QPAINTER_PATH, + QPAINTER_PATH_FILL }; Data(KisNodeSP _node, int _painterInfoId, const KisPaintInformation &_pi) : node(_node), painterInfoId(_painterInfoId), type(POINT), pi1(_pi) {} Data(KisNodeSP _node, int _painterInfoId, const KisPaintInformation &_pi1, const KisPaintInformation &_pi2) : node(_node), painterInfoId(_painterInfoId), type(LINE), pi1(_pi1), pi2(_pi2) {} Data(KisNodeSP _node, int _painterInfoId, const KisPaintInformation &_pi1, const QPointF &_control1, const QPointF &_control2, const KisPaintInformation &_pi2) : node(_node), painterInfoId(_painterInfoId), type(CURVE), pi1(_pi1), pi2(_pi2), control1(_control1), control2(_control2) {} Data(KisNodeSP _node, int _painterInfoId, DabType _type, const vQPointF &_points) : node(_node), painterInfoId(_painterInfoId), type(_type), points(_points) {} Data(KisNodeSP _node, int _painterInfoId, DabType _type, const QRectF &_rect) : node(_node), painterInfoId(_painterInfoId), type(_type), rect(_rect) {} Data(KisNodeSP _node, int _painterInfoId, DabType _type, const QPainterPath &_path) : node(_node), painterInfoId(_painterInfoId), type(_type), path(_path) {} + Data(KisNodeSP _node, int _painterInfoId, + DabType _type, + const QPainterPath &_path, + const QPen &_pen, const KoColor &_customColor) + : node(_node), painterInfoId(_painterInfoId), + type(_type), path(_path), + pen(_pen), customColor(_customColor) + {} + KisStrokeJobData* createLodClone(int levelOfDetail) { return new Data(*this, levelOfDetail); } private: Data(const Data &rhs, int levelOfDetail) : KisStrokeJobData(rhs), node(rhs.node), painterInfoId(rhs.painterInfoId), type(rhs.type) { KisLodTransform t(levelOfDetail); switch(type) { case Data::POINT: pi1 = t.map(rhs.pi1); break; case Data::LINE: pi1 = t.map(rhs.pi1); pi2 = t.map(rhs.pi2); break; case Data::CURVE: pi1 = t.map(rhs.pi1); pi2 = t.map(rhs.pi2); control1 = t.map(rhs.control1); control2 = t.map(rhs.control2); break; case Data::POLYLINE: points = t.map(rhs.points); break; case Data::POLYGON: points = t.map(rhs.points); break; case Data::RECT: rect = t.map(rhs.rect); break; case Data::ELLIPSE: rect = t.map(rhs.rect); break; case Data::PAINTER_PATH: path = t.map(rhs.path); }; } public: KisNodeSP node; int painterInfoId; DabType type; KisPaintInformation pi1; KisPaintInformation pi2; QPointF control1; QPointF control2; vQPointF points; QRectF rect; QPainterPath path; + QPen pen; + KoColor customColor; }; public: FreehandStrokeStrategy(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp, KisResourcesSnapshotSP resources, PainterInfo *painterInfo, const KUndo2MagicString &name); FreehandStrokeStrategy(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp, KisResourcesSnapshotSP resources, QVector painterInfos, const KUndo2MagicString &name); ~FreehandStrokeStrategy(); void doStrokeCallback(KisStrokeJobData *data); KisStrokeStrategy* createLodClone(int levelOfDetail); protected: FreehandStrokeStrategy(const FreehandStrokeStrategy &rhs, int levelOfDetail); private: void init(bool needsIndirectPainting, const QString &indirectPaintingCompositeOp); private: struct Private; const QScopedPointer m_d; }; #endif /* __FREEHAND_STROKE_H */ diff --git a/libs/ui/tool/strokes/kis_filter_stroke_strategy.cpp b/libs/ui/tool/strokes/kis_filter_stroke_strategy.cpp index 7d22ea0ff0..5fd75634c7 100644 --- a/libs/ui/tool/strokes/kis_filter_stroke_strategy.cpp +++ b/libs/ui/tool/strokes/kis_filter_stroke_strategy.cpp @@ -1,209 +1,209 @@ /* * 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_filter_stroke_strategy.h" #include #include #include #include struct KisFilterStrokeStrategy::Private { Private() : updatesFacade(0), cancelSilently(false), secondaryTransaction(0), levelOfDetail(0) { } Private(const Private &rhs) : filter(rhs.filter), filterConfig(rhs.filterConfig), node(rhs.node), updatesFacade(rhs.updatesFacade), cancelSilently(rhs.cancelSilently), filterDevice(), filterDeviceBounds(), secondaryTransaction(0), progressHelper(), levelOfDetail(0) { KIS_ASSERT_RECOVER_RETURN(!rhs.filterDevice); KIS_ASSERT_RECOVER_RETURN(rhs.filterDeviceBounds.isEmpty()); KIS_ASSERT_RECOVER_RETURN(!rhs.secondaryTransaction); KIS_ASSERT_RECOVER_RETURN(!rhs.progressHelper); KIS_ASSERT_RECOVER_RETURN(!rhs.levelOfDetail); } KisFilterSP filter; - KisSafeFilterConfigurationSP filterConfig; + KisFilterConfigurationSP filterConfig; KisNodeSP node; KisUpdatesFacade *updatesFacade; bool cancelSilently; KisPaintDeviceSP filterDevice; QRect filterDeviceBounds; KisTransaction *secondaryTransaction; QScopedPointer progressHelper; int levelOfDetail; }; KisFilterStrokeStrategy::KisFilterStrokeStrategy(KisFilterSP filter, - KisSafeFilterConfigurationSP filterConfig, + KisFilterConfigurationSP filterConfig, KisResourcesSnapshotSP resources) : KisPainterBasedStrokeStrategy("FILTER_STROKE", kundo2_i18n("Filter \"%1\"", filter->name()), resources, QVector(),false), m_d(new Private()) { m_d->filter = filter; m_d->filterConfig = filterConfig; m_d->node = resources->currentNode(); m_d->updatesFacade = resources->image().data(); m_d->cancelSilently = false; m_d->secondaryTransaction = 0; m_d->levelOfDetail = 0; setSupportsWrapAroundMode(true); enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE); } KisFilterStrokeStrategy::KisFilterStrokeStrategy(const KisFilterStrokeStrategy &rhs, int levelOfDetail) : KisPainterBasedStrokeStrategy(rhs, levelOfDetail), m_d(new Private(*rhs.m_d)) { // only non-started transaction are allowed KIS_ASSERT_RECOVER_NOOP(!m_d->secondaryTransaction); m_d->levelOfDetail = levelOfDetail; } KisFilterStrokeStrategy::~KisFilterStrokeStrategy() { delete m_d; } void KisFilterStrokeStrategy::initStrokeCallback() { KisPainterBasedStrokeStrategy::initStrokeCallback(); KisPaintDeviceSP dev = targetDevice(); m_d->filterDeviceBounds = dev->extent(); if (activeSelection() || (dev->colorSpace() != dev->compositionSourceColorSpace() && *dev->colorSpace() != *dev->compositionSourceColorSpace())) { m_d->filterDevice = dev->createCompositionSourceDevice(dev); m_d->secondaryTransaction = new KisTransaction(m_d->filterDevice); if (activeSelection()) { m_d->filterDeviceBounds &= activeSelection()->selectedRect(); } } else { m_d->filterDevice = dev; } m_d->progressHelper.reset(new KisProcessingVisitor::ProgressHelper(m_d->node)); } void KisFilterStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) { Data *d = dynamic_cast(data); CancelSilentlyMarker *cancelJob = dynamic_cast(data); if (d) { const QRect rc = d->processRect; if (!m_d->filterDeviceBounds.intersects( m_d->filter->neededRect(rc, m_d->filterConfig.data(), m_d->levelOfDetail))) { return; } m_d->filter->processImpl(m_d->filterDevice, rc, m_d->filterConfig.data(), m_d->progressHelper->updater()); if (m_d->secondaryTransaction) { KisPainter::copyAreaOptimized(rc.topLeft(), m_d->filterDevice, targetDevice(), rc, activeSelection()); // Free memory m_d->filterDevice->clear(rc); } m_d->node->setDirty(rc); } else if (cancelJob) { m_d->cancelSilently = true; } else { qFatal("KisFilterStrokeStrategy: job type is not known"); } } void KisFilterStrokeStrategy::cancelStrokeCallback() { delete m_d->secondaryTransaction; m_d->filterDevice = 0; KisProjectionUpdatesFilterSP prevUpdatesFilter; if (m_d->cancelSilently) { /** * TODO: Projection updates filter is not recursive, please * redesign this part */ prevUpdatesFilter = m_d->updatesFacade->projectionUpdatesFilter(); if (prevUpdatesFilter) { m_d->updatesFacade->setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP()); } m_d->updatesFacade->disableDirtyRequests(); } KisPainterBasedStrokeStrategy::cancelStrokeCallback(); if (m_d->cancelSilently) { m_d->updatesFacade->enableDirtyRequests(); if (prevUpdatesFilter) { m_d->updatesFacade->setProjectionUpdatesFilter(prevUpdatesFilter); prevUpdatesFilter.clear(); } } } void KisFilterStrokeStrategy::finishStrokeCallback() { delete m_d->secondaryTransaction; m_d->filterDevice = 0; KisPainterBasedStrokeStrategy::finishStrokeCallback(); } KisStrokeStrategy* KisFilterStrokeStrategy::createLodClone(int levelOfDetail) { if (!m_d->filter->supportsLevelOfDetail(m_d->filterConfig.data(), levelOfDetail)) return 0; KisFilterStrokeStrategy *clone = new KisFilterStrokeStrategy(*this, levelOfDetail); clone->setUndoEnabled(false); return clone; } diff --git a/libs/ui/tool/strokes/kis_filter_stroke_strategy.h b/libs/ui/tool/strokes/kis_filter_stroke_strategy.h index ada25d3829..831f454a2c 100644 --- a/libs/ui/tool/strokes/kis_filter_stroke_strategy.h +++ b/libs/ui/tool/strokes/kis_filter_stroke_strategy.h @@ -1,84 +1,84 @@ /* * 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. */ #ifndef __KIS_FILTER_STROKE_STRATEGY_H #define __KIS_FILTER_STROKE_STRATEGY_H #include "kis_types.h" #include "kis_painter_based_stroke_strategy.h" #include "kis_lod_transform.h" class KRITAUI_EXPORT KisFilterStrokeStrategy : public KisPainterBasedStrokeStrategy { public: class Data : public KisStrokeJobData { public: Data(const QRect &_processRect, bool concurrent) : KisStrokeJobData(concurrent ? CONCURRENT : SEQUENTIAL), processRect(_processRect) {} KisStrokeJobData* createLodClone(int levelOfDetail) { return new Data(*this, levelOfDetail); } QRect processRect; private: Data(const Data &rhs, int levelOfDetail) : KisStrokeJobData(rhs) { KisLodTransform t(levelOfDetail); processRect = t.map(rhs.processRect); } }; class CancelSilentlyMarker : public KisStrokeJobData { public: CancelSilentlyMarker() : KisStrokeJobData(SEQUENTIAL) {} KisStrokeJobData* createLodClone(int /*levelOfDetail*/) { return new CancelSilentlyMarker(*this); } }; public: KisFilterStrokeStrategy(KisFilterSP filter, - KisSafeFilterConfigurationSP filterConfig, + KisFilterConfigurationSP filterConfig, KisResourcesSnapshotSP resources); KisFilterStrokeStrategy(const KisFilterStrokeStrategy &rhs, int levelOfDetail); ~KisFilterStrokeStrategy(); void initStrokeCallback(); void doStrokeCallback(KisStrokeJobData *data); void cancelStrokeCallback(); void finishStrokeCallback(); KisStrokeStrategy* createLodClone(int levelOfDetail); private: struct Private; Private* const m_d; }; #endif /* __KIS_FILTER_STROKE_STRATEGY_H */ diff --git a/libs/ui/widgets/KoDualColorButton.h b/libs/ui/widgets/KoDualColorButton.h index dada703c2a..998affad00 100644 --- a/libs/ui/widgets/KoDualColorButton.h +++ b/libs/ui/widgets/KoDualColorButton.h @@ -1,186 +1,186 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Daniel M. Duley 2006 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KODUALCOLORBUTTON_H #define KODUALCOLORBUTTON_H -#include "kritawidgets_export.h" +#include #include #include class KoColor; class KoColorSpace; /** * @short A widget for selecting two related colors. * * KoDualColorButton allows the user to select two cascaded colors (usually a * foreground and background color). Other features include drag and drop * from other KDE color widgets, a reset to black and white control, and a * swap colors control. * * When the user clicks on the foreground or background rectangle the * rectangle is first sunken and the selectionChanged() signal is emitted. * Further clicks will present a color dialog and emit either the foregroundColorChanged() * or backgroundColorChanged() if a new color is selected. * * Note: With drag and drop when dropping a color the current selected color * will be set, while when dragging a color it will use whatever color * rectangle the mouse was pressed inside. * * @author Daniel M. Duley */ -class KRITAWIDGETS_EXPORT KoDualColorButton : public QWidget +class KRITAUI_EXPORT KoDualColorButton : public QWidget { Q_OBJECT Q_ENUMS( Selection ) Q_PROPERTY( KoColor foregroundColor READ foregroundColor WRITE setForegroundColor ) Q_PROPERTY( KoColor backgroundColor READ backgroundColor WRITE setBackgroundColor ) Q_PROPERTY( bool popDialog READ popDialog WRITE setPopDialog ) public: enum Selection { Foreground, Background }; /** * Constructs a new KoDualColorButton with the supplied foreground and * background colors. * * @param parent The parent widget of the KoDualColorButton. * @param dialogParent The parent widget of the color selection dialog. */ KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, QWidget *parent = 0, QWidget* dialogParent = 0 ); KoDualColorButton(const KoColor &foregroundColor, const KoColor &backgroundColor, const KoColorDisplayRendererInterface *displayRenderer, QWidget *parent = 0, QWidget* dialogParent = 0 ); /** * Destroys the KoDualColorButton. */ ~KoDualColorButton(); /** * Returns the current foreground color. */ KoColor foregroundColor() const; /** * Returns the current background color. */ KoColor backgroundColor() const; /** * Returns if a dialog with a color chooser will be popped up when clicking * If false then you could/should connect to the pleasePopDialog signal * and pop your own dialog. Just set the current color afterwards. */ bool popDialog() const; /** * Returns the minimum size needed to display the widget and all its * controls. */ virtual QSize sizeHint() const; public Q_SLOTS: /** * Sets the foreground color. */ void setForegroundColor( const KoColor &color ); /** * Sets the background color. */ void setBackgroundColor( const KoColor &color ); void slotSetForeGroundColorFromDialog (const KoColor color); void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); /** * @brief setColorSpace * set ColorSpace so we can lock the selector. Right now this'll be changed per view-change. * @param cs */ void setColorSpace(const KoColorSpace *cs); /** * @brief getColorFromDisplayRenderer * convenience function to get the right qcolor from the display renderer, including checking * whether the display renderer actually exists. * @param c the kocolor to convert. * @return the qcolor to use for display. */ QColor getColorFromDisplayRenderer(KoColor c); /** * Sets if a dialog with a color chooser should be popped up when clicking * If you set this to false then you could connect to the pleasePopDialog signal * and pop your own dialog. Just set the current color afterwards. */ void setPopDialog( bool popDialog ); Q_SIGNALS: /** * Emitted when the foreground color is changed. */ void foregroundColorChanged( const KoColor &color ); /** * Emitted when the background color is changed. */ void backgroundColorChanged( const KoColor &color ); /** * Emitted when the user clicks one of the two color patches. * You should/could pop you own color chooser dialog in response. * Also see the popDialog attribute. */ void pleasePopDialog( const KoColor &color ); protected: /** * Sets the supplied rectangles to the proper size and position for the * current widget size. You can reimplement this to change the layout * of the widget. Restrictions are that the swap control will always * be at the top right, the reset control will always be at the bottom * left, and you must leave at least a 14x14 space in those corners. */ virtual void metrics( QRect &foregroundRect, QRect &backgroundRect ); virtual void paintEvent( QPaintEvent *event ); virtual void mousePressEvent( QMouseEvent *event ); virtual void mouseMoveEvent( QMouseEvent *event ); virtual void mouseReleaseEvent( QMouseEvent *event ); virtual void dragEnterEvent( QDragEnterEvent *event ); virtual void dropEvent( QDropEvent *event ); virtual void changeEvent(QEvent *event); private: class Private; Private *const d; }; #endif diff --git a/libs/ui/widgets/kis_cmb_idlist.cc b/libs/ui/widgets/kis_cmb_idlist.cc index 3bf44107f0..66e6b7b4c8 100644 --- a/libs/ui/widgets/kis_cmb_idlist.cc +++ b/libs/ui/widgets/kis_cmb_idlist.cc @@ -1,97 +1,99 @@ /* * kis_cmb_idlist.cc - part of KImageShop/Krayon/Krita * * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "widgets/kis_cmb_idlist.h" #include #include #include KisCmbIDList::KisCmbIDList(QWidget * parent, const char * name) : QComboBox(parent) { setObjectName(name); setEditable(false); connect(this, SIGNAL(activated(int)), this, SLOT(slotIDActivated(int))); connect(this, SIGNAL(highlighted(int)), this, SLOT(slotIDHighlighted(int))); } KisCmbIDList::~KisCmbIDList() { } void KisCmbIDList::setIDList(const QList & list) { + clear(); m_list = list; + qSort(m_list.begin(), m_list.end(), KoID::compareNames); for (qint32 i = 0; i < m_list.count(); ++i) { addItem(m_list.at(i).name()); } } KoID KisCmbIDList::currentItem() const { qint32 i = QComboBox::currentIndex(); if (i > m_list.count() - 1 || i < 0) return KoID(); return m_list[i]; } void KisCmbIDList::setCurrent(const KoID id) { qint32 index = m_list.indexOf(id); if (index >= 0) { QComboBox::setCurrentIndex(index); } else { m_list.push_back(id); addItem(id.name()); QComboBox::setCurrentIndex(m_list.count() - 1); } } void KisCmbIDList::setCurrent(const QString & s) { for (qint32 i = 0; i < m_list.count(); ++i) { if (m_list.at(i).id() == s) { QComboBox::setCurrentIndex(i); break; } } } void KisCmbIDList::slotIDActivated(int i) { if (i > m_list.count() - 1) return; emit activated(m_list[i]); } void KisCmbIDList::slotIDHighlighted(int i) { if (i > m_list.count() - 1) return; emit highlighted(m_list[i]); } diff --git a/libs/ui/widgets/kis_cmb_idlist.h b/libs/ui/widgets/kis_cmb_idlist.h index f3b56accb8..746f18814a 100644 --- a/libs/ui/widgets/kis_cmb_idlist.h +++ b/libs/ui/widgets/kis_cmb_idlist.h @@ -1,61 +1,67 @@ /* * kis_cmb_imagetype.h - part of KImageShop/Krayon/Krita * * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_CMB_IDLIST_H_ #define KIS_CMB_IDLIST_H_ #include #include #include /** * A combobox that is associated with a list of KoID's. The * descriptive (i18n'ed) text is displayed, but the various * signals return a KoID. */ class KRITAUI_EXPORT KisCmbIDList: public QComboBox { Q_OBJECT public: KisCmbIDList(QWidget * parent = 0, const char * name = 0); virtual ~KisCmbIDList(); public: + /** + * @brief setIDList clears the combobox and sorts + * the given list by user-visible name and then adds + * the items to the combobox + * @param list the (unsorted) list of KoID's + */ void setIDList(const QList & list); void setCurrent(const KoID id); void setCurrent(const QString & s); KoID currentItem() const; Q_SIGNALS: void activated(const KoID &); void highlighted(const KoID &); private Q_SLOTS: void slotIDActivated(int i); void slotIDHighlighted(int i); private: QList m_list; }; #endif diff --git a/libs/ui/widgets/kis_custom_image_widget.cc b/libs/ui/widgets/kis_custom_image_widget.cc index 2269c8a6ba..19ebb485a9 100644 --- a/libs/ui/widgets/kis_custom_image_widget.cc +++ b/libs/ui/widgets/kis_custom_image_widget.cc @@ -1,469 +1,465 @@ /* This file is part of the Calligra project * Copyright (C) 2005 Thomas Zander * Copyright (C) 2005 C. Boemann * Copyright (C) 2007 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_custom_image_widget.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 "kis_config.h" #include "KisPart.h" #include "kis_clipboard.h" #include "KisDocument.h" #include "widgets/kis_cmb_idlist.h" #include "widgets/squeezedcombobox.h" KisCustomImageWidget::KisCustomImageWidget(QWidget* parent, qint32 defWidth, qint32 defHeight, double resolution, const QString& defColorModel, const QString& defColorDepth, const QString& defColorProfile, const QString& imageName) : WdgNewImage(parent) { setObjectName("KisCustomImageWidget"); m_openPane = qobject_cast(parent); Q_ASSERT(m_openPane); txtName->setText(imageName); m_widthUnit = KoUnit(KoUnit::Pixel, resolution); doubleWidth->setValue(defWidth); doubleWidth->setDecimals(0); m_width = m_widthUnit.fromUserValue(defWidth); cmbWidthUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll)); cmbWidthUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll)); m_heightUnit = KoUnit(KoUnit::Pixel, resolution); doubleHeight->setValue(defHeight); doubleHeight->setDecimals(0); m_height = m_heightUnit.fromUserValue(defHeight); cmbHeightUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll)); cmbHeightUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll)); doubleResolution->setValue(72.0 * resolution); doubleResolution->setDecimals(0); imageGroupSpacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); grpClipboard->hide(); sliderOpacity->setRange(0, 100, 0); sliderOpacity->setValue(100); sliderOpacity->setSuffix("%"); connect(cmbPredefined, SIGNAL(activated(int)), SLOT(predefinedClicked(int))); connect(doubleResolution, SIGNAL(valueChanged(double)), this, SLOT(resolutionChanged(double))); connect(cmbWidthUnit, SIGNAL(activated(int)), this, SLOT(widthUnitChanged(int))); connect(doubleWidth, SIGNAL(valueChanged(double)), this, SLOT(widthChanged(double))); connect(cmbHeightUnit, SIGNAL(activated(int)), this, SLOT(heightUnitChanged(int))); connect(doubleHeight, SIGNAL(valueChanged(double)), this, SLOT(heightChanged(double))); connect(createButton, SIGNAL(clicked()), this, SLOT(createImage())); createButton->setDefault(true); bnPortrait->setIcon(KisIconUtils::loadIcon("portrait")); connect(bnPortrait, SIGNAL(clicked()), SLOT(setPortrait())); connect(bnLandscape, SIGNAL(clicked()), SLOT(setLandscape())); bnLandscape->setIcon(KisIconUtils::loadIcon("landscape")); connect(doubleWidth, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape())); connect(doubleHeight, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape())); connect(bnSaveAsPredefined, SIGNAL(clicked()), this, SLOT(saveAsPredefined())); colorSpaceSelector->setCurrentColorModel(KoID(defColorModel)); colorSpaceSelector->setCurrentColorDepth(KoID(defColorDepth)); colorSpaceSelector->setCurrentProfile(defColorProfile); //connect(chkFromClipboard,SIGNAL(stateChanged(int)),this,SLOT(clipboardDataChanged())); connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); connect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, SLOT(clipboardDataChanged())); connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), this, SLOT(clipboardDataChanged())); connect(colorSpaceSelector, SIGNAL(selectionChanged(bool)), createButton, SLOT(setEnabled(bool))); KisConfig cfg; intNumLayers->setValue(cfg.numDefaultLayers()); KoColor bcol(KoColorSpaceRegistry::instance()->rgb8()); bcol.fromQColor(cfg.defaultBackgroundColor()); cmbColor->setColor(bcol); setBackgroundOpacity(cfg.defaultBackgroundOpacity()); KisConfig::BackgroundStyle bgStyle = cfg.defaultBackgroundStyle(); if (bgStyle == KisConfig::LAYER) { radioBackgroundAsLayer->setChecked(true); } else { radioBackgroundAsProjection->setChecked(true); } fillPredefined(); switchPortraitLandscape(); // this makes the portrait and landscape buttons more // obvious what is selected by changing the higlight color QPalette p = QApplication::palette(); QPalette palette_highlight(p ); QColor c = p.color(QPalette::Highlight); palette_highlight.setColor(QPalette::Button, c); bnLandscape->setPalette(palette_highlight); bnPortrait->setPalette(palette_highlight); } void KisCustomImageWidget::showEvent(QShowEvent *) { fillPredefined(); this->createButton->setFocus(); this->createButton->setEnabled(true); } KisCustomImageWidget::~KisCustomImageWidget() { - qDeleteAll(m_predefined); m_predefined.clear(); } void KisCustomImageWidget::resolutionChanged(double res) { if (m_widthUnit.type() == KoUnit::Pixel) { m_widthUnit.setFactor(res / 72.0); m_width = m_widthUnit.fromUserValue(doubleWidth->value()); } if (m_heightUnit.type() == KoUnit::Pixel) { m_heightUnit.setFactor(res / 72.0); m_height = m_heightUnit.fromUserValue(doubleHeight->value()); } } void KisCustomImageWidget::widthUnitChanged(int index) { doubleWidth->blockSignals(true); m_widthUnit = KoUnit::fromListForUi(index, KoUnit::ListAll); if (m_widthUnit.type() == KoUnit::Pixel) { doubleWidth->setDecimals(0); m_widthUnit.setFactor(doubleResolution->value() / 72.0); } else { doubleWidth->setDecimals(2); } doubleWidth->setValue(KoUnit::ptToUnit(m_width, m_widthUnit)); doubleWidth->blockSignals(false); } void KisCustomImageWidget::widthChanged(double value) { m_width = m_widthUnit.fromUserValue(value); } void KisCustomImageWidget::heightUnitChanged(int index) { doubleHeight->blockSignals(true); m_heightUnit = KoUnit::fromListForUi(index, KoUnit::ListAll); if (m_heightUnit.type() == KoUnit::Pixel) { doubleHeight->setDecimals(0); m_heightUnit.setFactor(doubleResolution->value() / 72.0); } else { doubleHeight->setDecimals(2); } doubleHeight->setValue(KoUnit::ptToUnit(m_height, m_heightUnit)); doubleHeight->blockSignals(false); } void KisCustomImageWidget::heightChanged(double value) { m_height = m_heightUnit.fromUserValue(value); } void KisCustomImageWidget::createImage() { createButton->setEnabled(false); KisDocument *doc = createNewImage(); if (doc) { doc->setModified(false); emit m_openPane->documentSelected(doc); } } KisDocument* KisCustomImageWidget::createNewImage() { const KoColorSpace * cs = colorSpaceSelector->currentColorSpace(); if (cs->colorModelId() == RGBAColorModelID && cs->colorDepthId() == Integer8BitsColorDepthID) { const KoColorProfile *profile = cs->profile(); if (profile->name().contains("linear") || profile->name().contains("scRGB") || profile->info().contains("linear") || profile->info().contains("scRGB")) { int result = QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Linear gamma RGB color spaces are not supposed to be used " "in 8-bit integer modes. It is suggested to use 16-bit integer " "or any floating point colorspace for linear profiles.\n\n" "Press \"Continue\" to create a 8-bit integer linear RGB color space " "or \"Cancel\" to return to the settings dialog."), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Cancel) { dbgKrita << "Model RGB8" << "NOT SUPPORTED"; dbgKrita << ppVar(cs->name()); dbgKrita << ppVar(cs->profile()->name()); dbgKrita << ppVar(cs->profile()->info()); return 0; } } } KisDocument *doc = static_cast(KisPart::instance()->createDocument()); qint32 width, height; double resolution; resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt width = static_cast(0.5 + KoUnit::ptToUnit(m_width, KoUnit(KoUnit::Pixel, resolution))); height = static_cast(0.5 + KoUnit::ptToUnit(m_height, KoUnit(KoUnit::Pixel, resolution))); QColor qc = cmbColor->color().toQColor(); qc.setAlpha(backgroundOpacity()); KoColor bgColor(qc, cs); bool backgroundAsLayer = radioBackgroundAsLayer->isChecked(); doc->newImage(txtName->text(), width, height, cs, bgColor, backgroundAsLayer, intNumLayers->value(), txtDescription->toPlainText(), resolution); KisConfig cfg; cfg.setNumDefaultLayers(intNumLayers->value()); cfg.setDefaultBackgroundOpacity(backgroundOpacity()); cfg.setDefaultBackgroundColor(cmbColor->color().toQColor()); cfg.setDefaultBackgroundStyle(backgroundAsLayer ? KisConfig::LAYER : KisConfig::PROJECTION); return doc; } void KisCustomImageWidget::setNumberOfLayers(int layers) { intNumLayers->setValue(layers); } quint8 KisCustomImageWidget::backgroundOpacity() const { qint32 opacity = sliderOpacity->value(); if (!opacity) return 0; return (opacity * 255) / 100; } void KisCustomImageWidget::setBackgroundOpacity(quint8 value) { sliderOpacity->setValue((value * 100) / 255); } void KisCustomImageWidget::clipboardDataChanged() { } - - void KisCustomImageWidget::fillPredefined() { cmbPredefined->clear(); - qDeleteAll(m_predefined); m_predefined.clear(); cmbPredefined->addItem(""); QStringList definitions = KoResourcePaths::findAllResources("data", "predefined_image_sizes/*.predefinedimage", KoResourcePaths::Recursive); definitions.sort(); if (!definitions.empty()) { Q_FOREACH (const QString &definition, definitions) { QFile f(definition); f.open(QIODevice::ReadOnly); if (f.exists()) { QString xml = QString::fromUtf8(f.readAll()); - KisPropertiesConfiguration *predefined = new KisPropertiesConfiguration; + KisPropertiesConfigurationSP predefined = new KisPropertiesConfiguration; predefined->fromXML(xml); if (predefined->hasProperty("name") && predefined->hasProperty("width") && predefined->hasProperty("height") && predefined->hasProperty("resolution") && predefined->hasProperty("x-unit") && predefined->hasProperty("y-unit")) { m_predefined << predefined; cmbPredefined->addItem(predefined->getString("name")); } } } } cmbPredefined->setCurrentIndex(0); } void KisCustomImageWidget::predefinedClicked(int index) { if (index < 1 || index > m_predefined.size()) return; - KisPropertiesConfiguration *predefined = m_predefined[index - 1]; + KisPropertiesConfigurationSP predefined = m_predefined[index - 1]; txtPredefinedName->setText(predefined->getString("name")); doubleResolution->setValue(predefined->getDouble("resolution")); cmbWidthUnit->setCurrentIndex(predefined->getInt("x-unit")); cmbHeightUnit->setCurrentIndex(predefined->getInt("y-unit")); widthUnitChanged(cmbWidthUnit->currentIndex()); heightUnitChanged(cmbHeightUnit->currentIndex()); doubleWidth->setValue(predefined->getDouble("width")); doubleHeight->setValue(predefined->getDouble("height")); } void KisCustomImageWidget::saveAsPredefined() { QString fileName = txtPredefinedName->text(); if (fileName.isEmpty()) { return; } QString saveLocation = KoResourcePaths::saveLocation("data", "predefined_image_sizes/", true); QFile f(saveLocation + '/' + fileName.replace(' ', '_').replace('(', '_').replace(')', '_') + ".predefinedimage"); f.open(QIODevice::WriteOnly | QIODevice::Truncate); - KisPropertiesConfiguration *predefined = new KisPropertiesConfiguration(); + KisPropertiesConfigurationSP predefined = new KisPropertiesConfiguration(); predefined->setProperty("name", txtPredefinedName->text()); predefined->setProperty("width", doubleWidth->value()); predefined->setProperty("height", doubleHeight->value()); predefined->setProperty("resolution", doubleResolution->value()); predefined->setProperty("x-unit", cmbWidthUnit->currentIndex()); predefined->setProperty("y-unit", cmbHeightUnit->currentIndex()); QString xml = predefined->toXML(); f.write(xml.toUtf8()); f.flush(); f.close(); int i = 0; bool found = false; - Q_FOREACH (KisPropertiesConfiguration *pr, m_predefined) { + Q_FOREACH (KisPropertiesConfigurationSP pr, m_predefined) { if (pr->getString("name") == txtPredefinedName->text()) { found = true; break; } ++i; } if (found) { m_predefined[i] = predefined; } else { m_predefined.append(predefined); cmbPredefined->addItem(txtPredefinedName->text()); } } void KisCustomImageWidget::setLandscape() { if (doubleWidth->value() < doubleHeight->value()) { switchWidthHeight(); } } void KisCustomImageWidget::setPortrait() { if (doubleWidth->value() > doubleHeight->value()) { switchWidthHeight(); } } void KisCustomImageWidget::switchWidthHeight() { double width = doubleWidth->value(); double height = doubleHeight->value(); doubleHeight->blockSignals(true); doubleWidth->blockSignals(true); cmbWidthUnit->blockSignals(true); cmbHeightUnit->blockSignals(true); doubleWidth->setValue(height); doubleHeight->setValue(width); cmbWidthUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll)); cmbHeightUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll)); doubleHeight->blockSignals(false); doubleWidth->blockSignals(false); cmbWidthUnit->blockSignals(false); cmbHeightUnit->blockSignals(false); switchPortraitLandscape(); widthChanged(doubleWidth->value()); heightChanged(doubleHeight->value()); } void KisCustomImageWidget::switchPortraitLandscape() { if(doubleWidth->value() > doubleHeight->value()) bnLandscape->setChecked(true); else bnPortrait->setChecked(true); } diff --git a/libs/ui/widgets/kis_custom_image_widget.h b/libs/ui/widgets/kis_custom_image_widget.h index 724ecf2f1e..ea5e43735a 100644 --- a/libs/ui/widgets/kis_custom_image_widget.h +++ b/libs/ui/widgets/kis_custom_image_widget.h @@ -1,100 +1,100 @@ /* This file is part of the Calligra project * Copyright (C) 2005 Thomas Zander * Copyright (C) 2005 C. Boemann * * 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_CUSTOM_IMAGE_WIDGET_H #define KIS_CUSTOM_IMAGE_WIDGET_H #include "kis_global.h" #include "KoUnit.h" #include "kis_properties_configuration.h" #include "KisOpenPane.h" #include class KisDocument; class KisDocument; enum CustomImageWidgetType { CUSTOM_DOCUMENT, NEW_IMG_FROM_CB }; class WdgNewImage : public QWidget, public Ui::WdgNewImage { Q_OBJECT public: WdgNewImage(QWidget *parent) : QWidget(parent) { setupUi(this); } }; /** * The 'Custom Document' widget in the Krita startup widget. * This class embeds the image size and colorspace to allow the user to select the image properties * for a new empty image document. */ class KisCustomImageWidget : public WdgNewImage { Q_OBJECT public: /** * Constructor. Please note that this class is being used/created by KisDoc. * @param parent the parent widget * @param doc the document that wants to be altered */ KisCustomImageWidget(QWidget *parent, qint32 defWidth, qint32 defHeight, double resolution, const QString & defColorModel, const QString & defColorDepth, const QString & defColorProfile, const QString & imageName); virtual ~KisCustomImageWidget(); private Q_SLOTS: void widthUnitChanged(int index); void widthChanged(double value); void heightUnitChanged(int index); void heightChanged(double value); void resolutionChanged(double value); void clipboardDataChanged(); void predefinedClicked(int index); void saveAsPredefined(); void setLandscape(); void setPortrait(); void switchWidthHeight(); void createImage(); void switchPortraitLandscape(); protected: KisDocument *createNewImage(); /// Set the number of layers that will be created void setNumberOfLayers(int layers); KisOpenPane *m_openPane; private: double m_width, m_height; quint8 backgroundOpacity() const; void setBackgroundOpacity(quint8 value); void fillPredefined(); void showEvent(QShowEvent *); KoUnit m_widthUnit, m_heightUnit; - QList m_predefined; + QList m_predefined; }; #endif diff --git a/libs/ui/widgets/kis_filter_selector_widget.cc b/libs/ui/widgets/kis_filter_selector_widget.cc index 06624a8fdf..baff8c8674 100644 --- a/libs/ui/widgets/kis_filter_selector_widget.cc +++ b/libs/ui/widgets/kis_filter_selector_widget.cc @@ -1,320 +1,319 @@ /* * Copyright (c) 2007-2008 Cyrille Berger * Copyright (c) 2009 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_filter_selector_widget.h" #include #include #include #include #include #include #include #include "ui_wdgfilterselector.h" #include #include #include #include #include #include "kis_default_bounds.h" // From krita/ui #include "kis_bookmarked_configurations_editor.h" #include "kis_bookmarked_filter_configurations_model.h" #include "kis_filters_model.h" #include "kis_config.h" class ThumbnailBounds : public KisDefaultBounds { public: ThumbnailBounds() : KisDefaultBounds() {} virtual ~ThumbnailBounds() {} QRect bounds() const { return QRect(0, 0, 100, 100); } private: Q_DISABLE_COPY(ThumbnailBounds) }; struct KisFilterSelectorWidget::Private { QWidget* currentCentralWidget; KisConfigWidget* currentFilterConfigurationWidget; KisFilterSP currentFilter; KisPaintDeviceSP paintDevice; Ui_FilterSelector uiFilterSelector; KisPaintDeviceSP thumb; KisBookmarkedFilterConfigurationsModel* currentBookmarkedFilterConfigurationsModel; KisFiltersModel* filtersModel; QGridLayout *widgetLayout; KisViewManager *view; bool showFilterGallery; }; KisFilterSelectorWidget::KisFilterSelectorWidget(QWidget* parent) : d(new Private) { Q_UNUSED(parent); setObjectName("KisFilterSelectorWidget"); d->currentCentralWidget = 0; d->currentFilterConfigurationWidget = 0; d->currentBookmarkedFilterConfigurationsModel = 0; d->currentFilter = 0; d->filtersModel = 0; d->view = 0; d->showFilterGallery = true; d->uiFilterSelector.setupUi(this); d->widgetLayout = new QGridLayout(d->uiFilterSelector.centralWidgetHolder); d->widgetLayout->setContentsMargins(0,0,0,0); d->widgetLayout->setHorizontalSpacing(0); showFilterGallery(false); connect(d->uiFilterSelector.filtersSelector, SIGNAL(clicked(const QModelIndex&)), SLOT(setFilterIndex(const QModelIndex &))); connect(d->uiFilterSelector.filtersSelector, SIGNAL(activated(const QModelIndex&)), SLOT(setFilterIndex(const QModelIndex &))); connect(d->uiFilterSelector.comboBoxPresets, SIGNAL(activated(int)), SLOT(slotBookmarkedFilterConfigurationSelected(int))); connect(d->uiFilterSelector.pushButtonEditPressets, SIGNAL(pressed()), SLOT(editConfigurations())); } KisFilterSelectorWidget::~KisFilterSelectorWidget() { delete d->filtersModel; delete d->currentBookmarkedFilterConfigurationsModel; delete d->currentCentralWidget; delete d->widgetLayout; delete d; } void KisFilterSelectorWidget::setView(KisViewManager *view) { d->view = view; } void KisFilterSelectorWidget::setPaintDevice(bool showAll, KisPaintDeviceSP _paintDevice) { if (!_paintDevice) return; if (d->filtersModel) delete d->filtersModel; d->paintDevice = _paintDevice; d->thumb = d->paintDevice->createThumbnailDevice(100, 100); d->thumb->setDefaultBounds(new ThumbnailBounds()); d->filtersModel = new KisFiltersModel(showAll, d->thumb); d->uiFilterSelector.filtersSelector->setFilterModel(d->filtersModel); d->uiFilterSelector.filtersSelector->header()->setVisible(false); KisConfig cfg; QModelIndex idx = d->filtersModel->indexForFilter(cfg.readEntry("FilterSelector/LastUsedFilter", "levels")); if (!idx.isValid()) { idx = d->filtersModel->indexForFilter("levels"); } if (isFilterGalleryVisible()) { d->uiFilterSelector.filtersSelector->activateFilter(idx); } } void KisFilterSelectorWidget::showFilterGallery(bool visible) { if (d->showFilterGallery == visible) { return; } d->showFilterGallery = visible; update(); emit sigFilterGalleryToggled(visible); emit sigSizeChanged(); } bool KisFilterSelectorWidget::isFilterGalleryVisible() const { return d->showFilterGallery; } KisFilterSP KisFilterSelectorWidget::currentFilter() const { return d->currentFilter; } void KisFilterSelectorWidget::setFilter(KisFilterSP f) { Q_ASSERT(f); Q_ASSERT(d->filtersModel); setWindowTitle(f->name()); dbgKrita << "setFilter: " << f; d->currentFilter = f; delete d->currentCentralWidget; { bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(f->id())); d->uiFilterSelector.filtersSelector->blockSignals(v); } KisConfigWidget* widget = d->currentFilter->createConfigurationWidget(d->uiFilterSelector.centralWidgetHolder, d->paintDevice); if (!widget) { // No widget, so display a label instead d->uiFilterSelector.comboBoxPresets->setEnabled(false); d->uiFilterSelector.pushButtonEditPressets->setEnabled(false); d->currentFilterConfigurationWidget = 0; d->currentCentralWidget = new QLabel(i18n("No configuration options"), d->uiFilterSelector.centralWidgetHolder); d->uiFilterSelector.scrollArea->setMinimumSize(d->currentCentralWidget->sizeHint()); qobject_cast(d->currentCentralWidget)->setAlignment(Qt::AlignCenter); } else { d->uiFilterSelector.comboBoxPresets->setEnabled(true); d->uiFilterSelector.pushButtonEditPressets->setEnabled(true); d->currentFilterConfigurationWidget = widget; d->currentCentralWidget = widget; widget->layout()->setContentsMargins(0,0,0,0); d->currentFilterConfigurationWidget->setView(d->view); d->currentFilterConfigurationWidget->blockSignals(true); d->currentFilterConfigurationWidget->setConfiguration( d->currentFilter->defaultConfiguration(d->paintDevice)); d->currentFilterConfigurationWidget->blockSignals(false); d->uiFilterSelector.scrollArea->setContentsMargins(0,0,0,0); d->uiFilterSelector.scrollArea->setMinimumWidth(widget->sizeHint().width() + 18); connect(d->currentFilterConfigurationWidget, SIGNAL(sigConfigurationUpdated()), this, SIGNAL(configurationChanged())); } // Change the list of presets delete d->currentBookmarkedFilterConfigurationsModel; d->currentBookmarkedFilterConfigurationsModel = new KisBookmarkedFilterConfigurationsModel(d->thumb, f); d->uiFilterSelector.comboBoxPresets->setModel(d->currentBookmarkedFilterConfigurationsModel); // Add the widget to the layout d->currentCentralWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->widgetLayout->addWidget(d->currentCentralWidget, 0 , 0); update(); } void KisFilterSelectorWidget::setFilterIndex(const QModelIndex& idx) { if (!idx.isValid()) return; Q_ASSERT(d->filtersModel); KisFilter* filter = const_cast(d->filtersModel->indexToFilter(idx)); if (filter) { setFilter(filter); } else { if (d->currentFilter) { bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); QModelIndex idx = d->filtersModel->indexForFilter(d->currentFilter->id()); d->uiFilterSelector.filtersSelector->setCurrentIndex(idx); d->uiFilterSelector.filtersSelector->scrollTo(idx); d->uiFilterSelector.filtersSelector->blockSignals(v); } } KisConfig cfg; cfg.writeEntry("FilterSelector/LastUsedFilter", d->currentFilter->id()); emit(configurationChanged()); } void KisFilterSelectorWidget::slotBookmarkedFilterConfigurationSelected(int index) { if (d->currentFilterConfigurationWidget) { QModelIndex modelIndex = d->currentBookmarkedFilterConfigurationsModel->index(index, 0); - KisFilterConfiguration* config = d->currentBookmarkedFilterConfigurationsModel->configuration(modelIndex); + KisFilterConfigurationSP config = d->currentBookmarkedFilterConfigurationsModel->configuration(modelIndex); d->currentFilterConfigurationWidget->setConfiguration(config); } } void KisFilterSelectorWidget::editConfigurations() { - KisSerializableConfiguration* config = + KisSerializableConfigurationSP config = d->currentFilterConfigurationWidget ? d->currentFilterConfigurationWidget->configuration() : 0; KisBookmarkedConfigurationsEditor editor(this, d->currentBookmarkedFilterConfigurationsModel, config); editor.exec(); } void KisFilterSelectorWidget::update() { d->uiFilterSelector.filtersSelector->setVisible(d->showFilterGallery); if (d->showFilterGallery) { setMinimumWidth(qMax(sizeHint().width(), 700)); d->uiFilterSelector.scrollArea->setMinimumHeight(400); setMinimumHeight(d->uiFilterSelector.widget->sizeHint().height()); if (d->currentFilter) { bool v = d->uiFilterSelector.filtersSelector->blockSignals(true); d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(d->currentFilter->id())); d->uiFilterSelector.filtersSelector->blockSignals(v); } } else { if (d->currentCentralWidget) { d->uiFilterSelector.scrollArea->setMinimumHeight(qMin(400, d->currentCentralWidget->sizeHint().height())); } setMinimumSize(d->uiFilterSelector.widget->sizeHint()); } } -KisFilterConfiguration* KisFilterSelectorWidget::configuration() +KisFilterConfigurationSP KisFilterSelectorWidget::configuration() { if (d->currentFilterConfigurationWidget) { - KisFilterConfiguration * config - = dynamic_cast(d->currentFilterConfigurationWidget->configuration()); + KisFilterConfigurationSP config = dynamic_cast(d->currentFilterConfigurationWidget->configuration().data()); if (config) { return config; } } else if (d->currentFilter) { return d->currentFilter->defaultConfiguration(d->paintDevice); } return 0; } void KisFilterTree::setFilterModel(QAbstractItemModel *model) { m_model = model; } void KisFilterTree::activateFilter(QModelIndex idx) { setModel(m_model); selectionModel()->select(idx, QItemSelectionModel::SelectCurrent); expand(idx); scrollTo(idx); emit activated(idx); } void KisFilterSelectorWidget::setVisible(bool visible) { QWidget::setVisible(visible); if (visible) { update(); } } diff --git a/libs/ui/widgets/kis_filter_selector_widget.h b/libs/ui/widgets/kis_filter_selector_widget.h index d3ebf2825b..2deec1ba4c 100644 --- a/libs/ui/widgets/kis_filter_selector_widget.h +++ b/libs/ui/widgets/kis_filter_selector_widget.h @@ -1,142 +1,142 @@ /* * Copyright (c) 2007-2008 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_FILTER_SELECTOR_WIDGET_H_ #define _KIS_FILTER_SELECTOR_WIDGET_H_ #include #include #include #include #include #include #include class QModelIndex; class KisFilterConfiguration; class KisViewManager; class QAbstractItemModel; class QHideEvent; class QShowEvent; /** * XXX */ class KisFilterSelectorWidget : public QWidget { Q_OBJECT public: KisFilterSelectorWidget(QWidget* parent); ~KisFilterSelectorWidget(); void setFilter(KisFilterSP f); void setView(KisViewManager *view); void setPaintDevice(bool showAll, KisPaintDeviceSP); - KisFilterConfiguration* configuration(); + KisFilterConfigurationSP configuration(); bool isFilterGalleryVisible() const; KisFilterSP currentFilter() const; public Q_SLOTS: void setVisible(bool visible); void showFilterGallery(bool visible); protected Q_SLOTS: void slotBookmarkedFilterConfigurationSelected(int); void setFilterIndex(const QModelIndex&); void editConfigurations(); void update(); Q_SIGNALS: void configurationChanged(); void sigFilterGalleryToggled(bool visible); void sigSizeChanged(); private: struct Private; Private* const d; }; class KisFilterTree: public QTreeView { Q_OBJECT public: KisFilterTree(QWidget *parent) : QTreeView(parent) { connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(update_scroll_area(QModelIndex))); connect(this, SIGNAL(collapsed(QModelIndex)), this, SLOT(update_scroll_area(QModelIndex))); } void setFilterModel(QAbstractItemModel * model); void activateFilter(QModelIndex idx); QSize minimumSizeHint() const { return QSize(200, QTreeView::sizeHint().height()); } QSize sizeHint() const { return QSize(header()->width(), QTreeView::sizeHint().height()); } void setModel(QAbstractItemModel *model) { QTreeView::setModel(model); if (header()->visualIndex(0) != -1) { header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); } } protected: void resizeEvent(QResizeEvent *event) { if (event->size().width() > 10) { setModel(m_model); } else { setModel(0); } QTreeView::resizeEvent(event); } void showEvent(QShowEvent * event) { setModel(m_model); QTreeView::showEvent(event); } void hideEvent(QHideEvent * event) { setModel(0); QTreeView::hideEvent(event); } private Q_SLOTS: void update_scroll_area(const QModelIndex& i) { resizeColumnToContents(i.column()); } private: QAbstractItemModel *m_model; }; #endif diff --git a/libs/ui/widgets/kis_multi_bool_filter_widget.cc b/libs/ui/widgets/kis_multi_bool_filter_widget.cc index 7eb0fe7be3..87de712a3a 100644 --- a/libs/ui/widgets/kis_multi_bool_filter_widget.cc +++ b/libs/ui/widgets/kis_multi_bool_filter_widget.cc @@ -1,80 +1,80 @@ /* * Copyright (c) 2005 Michael Thaler * * 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_multi_bool_filter_widget.h" #include #include #include #include #include #include KisBoolWidgetParam::KisBoolWidgetParam(bool ninitvalue, const QString & nlabel, const QString & nname) : initvalue(ninitvalue), label(nlabel), name(nname) { } KisMultiBoolFilterWidget::KisMultiBoolFilterWidget(const QString & filterid, QWidget * parent, const QString & caption, vKisBoolWidgetParam iwparam) : KisConfigWidget(parent) , m_filterid(filterid) { qint32 nbboolWidgets = iwparam.size(); this->setWindowTitle(caption); QVBoxLayout *widgetLayout = new QVBoxLayout(this); widgetLayout->setMargin(nbboolWidgets + 1); widgetLayout->setContentsMargins(0,0,0,0); for (qint32 i = 0; i < nbboolWidgets; ++i) { QCheckBox * cb = new QCheckBox(this); cb->setObjectName(iwparam[i].name); cb->setChecked(iwparam[i].initvalue); cb->setText(iwparam[i].label); connect(cb, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); widgetLayout->addWidget(cb); m_boolWidgets.append(cb); } widgetLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding)); widgetLayout->addStretch(); } -void KisMultiBoolFilterWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisMultiBoolFilterWidget::setConfiguration(const KisPropertiesConfigurationSP config) { if (!config) return; for (int i = 0; i < nbValues(); ++i) { bool val = config->getBool(m_boolWidgets[i]->objectName(), true); m_boolWidgets[i]->setChecked(val); } } -KisPropertiesConfiguration* KisMultiBoolFilterWidget::configuration() const +KisPropertiesConfigurationSP KisMultiBoolFilterWidget::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration(m_filterid, 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(m_filterid, 0); for (int i = 0; i < nbValues(); ++i) { config->setProperty(m_boolWidgets[i]->objectName(), valueAt(i)); } return config; } diff --git a/libs/ui/widgets/kis_multi_bool_filter_widget.h b/libs/ui/widgets/kis_multi_bool_filter_widget.h index 7a569c2328..4d00e7021b 100644 --- a/libs/ui/widgets/kis_multi_bool_filter_widget.h +++ b/libs/ui/widgets/kis_multi_bool_filter_widget.h @@ -1,70 +1,70 @@ /* * Copyright (c) 2005 Michael Thaler * * 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_MULTI_BOOL_FILTER_WIDGET_H_ #define _KIS_MULTI_BOOL_FILTER_WIDGET_H_ #include #include #include #include "kritaui_export.h" #include class KisPropertiesConfiguration; struct KisBoolWidgetParam { KRITAUI_EXPORT KisBoolWidgetParam(bool ninitvalue, const QString & label, const QString & name); bool initvalue; QString label; QString name; }; typedef std::vector vKisBoolWidgetParam; class KRITAUI_EXPORT KisMultiBoolFilterWidget : public KisConfigWidget { Q_OBJECT public: KisMultiBoolFilterWidget(const QString & filterid, QWidget * parent, const QString & caption, vKisBoolWidgetParam iwparam); - virtual void setConfiguration(const KisPropertiesConfiguration* cfg); + virtual void setConfiguration(const KisPropertiesConfigurationSP cfg); - virtual KisPropertiesConfiguration* configuration() const; + virtual KisPropertiesConfigurationSP configuration() const; public: inline qint32 nbValues() const { return m_boolWidgets.count(); } inline bool valueAt(qint32 i) const { return m_boolWidgets[i]->isChecked(); } private: QVector m_boolWidgets; QString m_filterid; }; #endif diff --git a/libs/ui/widgets/kis_multi_double_filter_widget.cc b/libs/ui/widgets/kis_multi_double_filter_widget.cc index 4a7fd922eb..704351653e 100644 --- a/libs/ui/widgets/kis_multi_double_filter_widget.cc +++ b/libs/ui/widgets/kis_multi_double_filter_widget.cc @@ -1,122 +1,122 @@ /* * Copyright (c) 2004 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. */ #include "widgets/kis_multi_double_filter_widget.h" #include #include #include #include #include #include #include #include KisDelayedActionDoubleInput::KisDelayedActionDoubleInput(QWidget * parent, const QString & name) : KisDoubleParseSpinBox(parent) { setObjectName(name); m_timer = new QTimer(this); m_timer->setObjectName(name); m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), SLOT(slotValueChanged())); connect(this, SIGNAL(valueChanged(double)), SLOT(slotTimeToUpdate())); } void KisDelayedActionDoubleInput::slotTimeToUpdate() { m_timer->start(50); } void KisDelayedActionDoubleInput::slotValueChanged() { emit valueChangedDelayed(value()); } void KisDelayedActionDoubleInput::cancelDelayedSignal() { m_timer->stop(); } KisDoubleWidgetParam::KisDoubleWidgetParam(double nmin, double nmax, double ninitvalue, const QString & nlabel, const QString & nname) : min(nmin), max(nmax), initvalue(ninitvalue), label(nlabel), name(nname) { } KisMultiDoubleFilterWidget::KisMultiDoubleFilterWidget(const QString & filterid, QWidget * parent, const QString & caption, vKisDoubleWidgetParam dwparam) : KisConfigWidget(parent), m_filterid(filterid) { m_nbdoubleWidgets = dwparam.size(); this->setWindowTitle(caption); QGridLayout *widgetLayout = new QGridLayout(this); widgetLayout->setColumnStretch(1, 1); widgetLayout->setContentsMargins(0,0,0,0); widgetLayout->setHorizontalSpacing(0); m_doubleWidgets = new KisDelayedActionDoubleInput*[ m_nbdoubleWidgets ]; for (qint32 i = 0; i < m_nbdoubleWidgets; ++i) { m_doubleWidgets[i] = new KisDelayedActionDoubleInput(this, dwparam[i].name); m_doubleWidgets[i]->setRange(dwparam[i].min, dwparam[i].max); m_doubleWidgets[i]->setValue(dwparam[i].initvalue); m_doubleWidgets[i]->cancelDelayedSignal(); connect(m_doubleWidgets[i], SIGNAL(valueChangedDelayed(double)), SIGNAL(sigConfigurationItemChanged())); QLabel* lbl = new QLabel(dwparam[i].label + ':', this); widgetLayout->addWidget(lbl, i , 0); widgetLayout->addWidget(m_doubleWidgets[i], i , 1); } widgetLayout->setRowStretch(m_nbdoubleWidgets,1); QSpacerItem * sp = new QSpacerItem(1, 1); widgetLayout->addItem(sp, m_nbdoubleWidgets, 0); } -void KisMultiDoubleFilterWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisMultiDoubleFilterWidget::setConfiguration(const KisPropertiesConfigurationSP config) { if (!config) return; for (int i = 0; i < m_nbdoubleWidgets ; ++i) { KisDelayedActionDoubleInput * w = m_doubleWidgets[i]; if (w) { double val = config->getDouble(m_doubleWidgets[i]->objectName()); m_doubleWidgets[i]->setValue(val); m_doubleWidgets[i]->cancelDelayedSignal(); } } } -KisPropertiesConfiguration* KisMultiDoubleFilterWidget::configuration() const +KisPropertiesConfigurationSP KisMultiDoubleFilterWidget::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration(m_filterid, 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(m_filterid, 0); for (int i = 0; i < nbValues(); ++i) { config->setProperty(m_doubleWidgets[i]->objectName(), m_doubleWidgets[i]->value()); } return config; } diff --git a/libs/ui/widgets/kis_multi_double_filter_widget.h b/libs/ui/widgets/kis_multi_double_filter_widget.h index 88b63c2163..199bf8f2f2 100644 --- a/libs/ui/widgets/kis_multi_double_filter_widget.h +++ b/libs/ui/widgets/kis_multi_double_filter_widget.h @@ -1,84 +1,84 @@ /* * Copyright (c) 2004 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_MULTI_DOUBLE_FILTER_WIDGET_H_ #define _KIS_MULTI_DOUBLE_FILTER_WIDGET_H_ #include #include #include #include "kritaui_export.h" #include "kis_double_parse_spin_box.h" class KisDelayedActionDoubleInput : public KisDoubleParseSpinBox { Q_OBJECT public: KisDelayedActionDoubleInput(QWidget * parent, const QString & name); void cancelDelayedSignal(); private Q_SLOTS: void slotValueChanged(); void slotTimeToUpdate(); Q_SIGNALS: void valueChangedDelayed(double value); private: QTimer * m_timer; }; struct KRITAUI_EXPORT KisDoubleWidgetParam { KisDoubleWidgetParam(double nmin, double nmax, double ninitvalue, const QString & label, const QString & nname); double min; double max; double initvalue; QString label; QString name; }; typedef std::vector vKisDoubleWidgetParam; class KRITAUI_EXPORT KisMultiDoubleFilterWidget : public KisConfigWidget { Q_OBJECT public: KisMultiDoubleFilterWidget(const QString & filterid, QWidget * parent, const QString & caption, vKisDoubleWidgetParam dwparam); - virtual void setConfiguration(const KisPropertiesConfiguration * cfg); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP cfg); + virtual KisPropertiesConfigurationSP configuration() const; public: inline qint32 nbValues() const { return m_nbdoubleWidgets; } inline double valueAt(qint32 i) { return m_doubleWidgets[i]->value(); } private: KisDelayedActionDoubleInput** m_doubleWidgets; qint32 m_nbdoubleWidgets; QString m_filterid; }; #endif diff --git a/libs/ui/widgets/kis_multi_integer_filter_widget.cc b/libs/ui/widgets/kis_multi_integer_filter_widget.cc index ba8d7415f5..b7388c20f4 100644 --- a/libs/ui/widgets/kis_multi_integer_filter_widget.cc +++ b/libs/ui/widgets/kis_multi_integer_filter_widget.cc @@ -1,155 +1,154 @@ /* * Copyright (c) 2004 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. */ #include "widgets/kis_multi_integer_filter_widget.h" #include #include #include #include #include #include #include KisDelayedActionIntegerInput::KisDelayedActionIntegerInput(QWidget * parent, const QString & name) : KisIntParseSpinBox(parent) { setObjectName(name); m_timer = new QTimer(this); m_timer->setObjectName(name); m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), SLOT(slotValueChanged())); connect(this, SIGNAL(valueChanged(int)), SLOT(slotTimeToUpdate())); } void KisDelayedActionIntegerInput::slotTimeToUpdate() { m_timer->start(50); } void KisDelayedActionIntegerInput::slotValueChanged() { emit valueChangedDelayed(value()); } void KisDelayedActionIntegerInput::cancelDelayedSignal() { m_timer->stop(); } KisIntegerWidgetParam::KisIntegerWidgetParam(qint32 nmin, qint32 nmax, qint32 ninitvalue, const QString & label, const QString & nname) : min(nmin) , max(nmax) , initvalue(ninitvalue) , label(label) , name(nname) { } KisMultiIntegerFilterWidget::KisMultiIntegerFilterWidget(const QString& filterid, QWidget* parent, const QString& caption, vKisIntegerWidgetParam iwparam) : KisConfigWidget(parent) , m_filterid(filterid) , m_config(new KisFilterConfiguration(filterid, 0)) { this->setWindowTitle(caption); QGridLayout *widgetLayout = new QGridLayout(this); widgetLayout->setColumnStretch(1, 1); widgetLayout->setContentsMargins(0,0,0,0); widgetLayout->setHorizontalSpacing(0); for (uint i = 0; i < iwparam.size(); ++i) { KisDelayedActionIntegerInput *widget = new KisDelayedActionIntegerInput(this, iwparam[i].name); widget->setRange(iwparam[i].min, iwparam[i].max); widget->setValue(iwparam[i].initvalue); widget->cancelDelayedSignal(); connect(widget, SIGNAL(valueChangedDelayed(int)), SIGNAL(sigConfigurationItemChanged())); QLabel* lbl = new QLabel(iwparam[i].label + ':', this); widgetLayout->addWidget(lbl, i , 0); widgetLayout->addWidget(widget, i , 1); m_integerWidgets.append(widget); } widgetLayout->setRowStretch(iwparam.size(),1); QSpacerItem * sp = new QSpacerItem(1, 1); widgetLayout->addItem(sp, iwparam.size(), 0); } KisMultiIntegerFilterWidget::~KisMultiIntegerFilterWidget() { - delete m_config; } -void KisMultiIntegerFilterWidget::setConfiguration(const KisPropertiesConfiguration* config) +void KisMultiIntegerFilterWidget::setConfiguration(const KisPropertiesConfigurationSP config) { if (!config) return; if (!m_config) { m_config = new KisFilterConfiguration(m_filterid, 0); } m_config->fromXML(config->toXML()); for (int i = 0; i < nbValues(); ++i) { KisDelayedActionIntegerInput* w = m_integerWidgets[i]; if (w) { int val = config->getInt(m_integerWidgets[i]->objectName()); m_integerWidgets[i]->setValue(val); m_integerWidgets[i]->cancelDelayedSignal(); } } } -KisPropertiesConfiguration* KisMultiIntegerFilterWidget::configuration() const +KisPropertiesConfigurationSP KisMultiIntegerFilterWidget::configuration() const { - KisFilterConfiguration *config = new KisFilterConfiguration(m_filterid, 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(m_filterid, 0); if (m_config) { config->fromXML(m_config->toXML()); } for (int i = 0; i < nbValues(); ++i) { KisDelayedActionIntegerInput* w = m_integerWidgets[i]; if (w) { config->setProperty(w->objectName(), w->value()); } } return config; } qint32 KisMultiIntegerFilterWidget::nbValues() const { return m_integerWidgets.size(); } qint32 KisMultiIntegerFilterWidget::valueAt(qint32 i) { if (i < m_integerWidgets.size()) { return m_integerWidgets[i]->value(); } else { warnKrita << "Trying to access integer widget" << i << "but there are only" << m_integerWidgets.size() << "widgets"; return 0; } } diff --git a/libs/ui/widgets/kis_multi_integer_filter_widget.h b/libs/ui/widgets/kis_multi_integer_filter_widget.h index 81d1fc3d0d..aecf14a432 100644 --- a/libs/ui/widgets/kis_multi_integer_filter_widget.h +++ b/libs/ui/widgets/kis_multi_integer_filter_widget.h @@ -1,85 +1,85 @@ /* * Copyright (c) 2004 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_MULTI_INTEGER_FILTER_WIDGET_H_ #define _KIS_MULTI_INTEGER_FILTER_WIDGET_H_ #include #include "kritaui_export.h" #include #include #include #include "kis_int_parse_spin_box.h" #include class KisDelayedActionIntegerInput : public KisIntParseSpinBox { Q_OBJECT public: KisDelayedActionIntegerInput(QWidget * parent, const QString & name); void cancelDelayedSignal(); private Q_SLOTS: void slotValueChanged(); void slotTimeToUpdate(); Q_SIGNALS: void valueChangedDelayed(int value); private: QTimer * m_timer; }; struct KRITAUI_EXPORT KisIntegerWidgetParam { KisIntegerWidgetParam(qint32 nmin, qint32 nmax, qint32 ninitvalue, const QString& label, const QString& nname); qint32 min; qint32 max; qint32 initvalue; QString label; QString name; }; typedef std::vector vKisIntegerWidgetParam; class KRITAUI_EXPORT KisMultiIntegerFilterWidget : public KisConfigWidget { Q_OBJECT public: KisMultiIntegerFilterWidget(const QString& filterid, QWidget* parent, const QString& caption, vKisIntegerWidgetParam iwparam); ~KisMultiIntegerFilterWidget(); - virtual void setConfiguration(const KisPropertiesConfiguration* config); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); + virtual KisPropertiesConfigurationSP configuration() const; private: qint32 nbValues() const; qint32 valueAt(qint32 i); QVector m_integerWidgets; QString m_filterid; - KisPropertiesConfiguration* m_config; + KisPropertiesConfigurationSP m_config; }; #endif diff --git a/libs/ui/widgets/kis_screen_color_picker.cpp b/libs/ui/widgets/kis_screen_color_picker.cpp index 7e549436f7..ade1b63392 100644 --- a/libs/ui/widgets/kis_screen_color_picker.cpp +++ b/libs/ui/widgets/kis_screen_color_picker.cpp @@ -1,273 +1,273 @@ /* * 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_wrapped_rect.h" #include "KisPart.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) { QVBoxLayout *layout = new QVBoxLayout(); this->setLayout(layout); m_d->screenColorPickerButton = new QPushButton(); m_d->screenColorPickerButton->setIcon(kisIcon("krita_tool_color_picker")); 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())); #ifdef Q_OS_WIN32 - m_d->updateTimer = new QTimer(q); + 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() { } 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(); #ifndef QT_NO_CURSOR grabMouse(Qt::CrossCursor); #else grabMouse(); #endif #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) { //Q_Q(QColorDialog); #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() { //Q_Q(QColorDialog); //cp->setCrossVisible(true); 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() { #ifndef QT_NO_CURSOR //Q_Q(QColorDialog); 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_dummyTransparentWindow.setPosition(newGlobalPos); + m_d->dummyTransparentWindow.setPosition(newGlobalPos); #endif } #endif // ! QT_NO_CURSOR } 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_spinbox_color_selector.cpp b/libs/ui/widgets/kis_spinbox_color_selector.cpp index 42e6788aa6..0630590b59 100644 --- a/libs/ui/widgets/kis_spinbox_color_selector.cpp +++ b/libs/ui/widgets/kis_spinbox_color_selector.cpp @@ -1,241 +1,242 @@ /* * 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 "kis_spinbox_color_selector.h" #include #include #include "kis_double_parse_spin_box.h" #include "kis_int_parse_spin_box.h" #include "kis_signal_compressor.h" #include "KoChannelInfo.h" #include "KoColorSpaceTraits.h" #include "KoColorSpaceMaths.h" #include "KoColorSpaceRegistry.h" struct KisSpinboxColorSelector::Private { QList spinBoxList; QList doubleSpinBoxList; KoColor color; - const KoColorSpace *cs; + const KoColorSpace *cs {0}; bool chooseAlpha = false; }; -KisSpinboxColorSelector::KisSpinboxColorSelector(QWidget *parent) : QWidget(parent) , m_d(new Private) +KisSpinboxColorSelector::KisSpinboxColorSelector(QWidget *parent) + : QWidget(parent) + , m_d(new Private) { this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - KoColor color = KoColor(); m_d->color = color; slotSetColorSpace(m_d->color.colorSpace()); } KisSpinboxColorSelector::~KisSpinboxColorSelector() { } void KisSpinboxColorSelector::slotSetColor(KoColor color) { m_d->color = color; if (m_d->color.colorSpace() != m_d->cs) { slotSetColorSpace(m_d->color.colorSpace()); } updateSpinboxesWithNewValues(); } void KisSpinboxColorSelector::slotSetColorSpace(const KoColorSpace *cs) { if (cs == m_d->cs) { return; } m_d->cs = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile()); //remake spinboxes if (this->layout()) { qDeleteAll(this->children()); } m_d->spinBoxList.clear(); m_d->doubleSpinBoxList.clear(); QFormLayout *layout = new QFormLayout(this); QList channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); Q_FOREACH (KoChannelInfo* channel, channels) { QString inputLabel = channel->name(); switch (channel->channelValueType()) { case KoChannelInfo::UINT8: { KisIntParseSpinBox *input = new KisIntParseSpinBox(this); input->setMinimum(0); input->setMaximum(0xFF); m_d->spinBoxList.append(input); layout->addRow(inputLabel,input); if (input) { connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); } if (channel->channelType()==KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { input->setEnabled(false); input->blockSignals(true); } } break; case KoChannelInfo::UINT16: { KisIntParseSpinBox *input = new KisIntParseSpinBox(this); input->setMinimum(0); input->setMaximum(0xFFFF); m_d->spinBoxList.append(input); layout->addRow(inputLabel,input); if (input) { connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); } if (channel->channelType()==KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { input->setEnabled(false); input->blockSignals(true); } } break; case KoChannelInfo::UINT32: { KisIntParseSpinBox *input = new KisIntParseSpinBox(this); input->setMinimum(0); input->setMaximum(0xFFFFFFFF); m_d->spinBoxList.append(input); layout->addRow(inputLabel,input); if (input) { connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); } if (channel->channelType()==KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { input->setEnabled(false); input->blockSignals(true); } } break; case KoChannelInfo::FLOAT16: case KoChannelInfo::FLOAT32: { KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this); input->setMinimum(0); input->setMaximum(KoColorSpaceMathsTraits::max); input->setSingleStep(0.1); m_d->doubleSpinBoxList.append(input); qDebug()<<"add "<name()<<"doubleSpinBoxList "<doubleSpinBoxList.size(); layout->addRow(inputLabel,input); if (input) { connect(input, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateFromSpinBoxes())); } if (channel->channelType()==KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { input->setEnabled(false); input->blockSignals(true); } } break; default: Q_ASSERT(false); } } this->setLayout(layout); } void KisSpinboxColorSelector::createColorFromSpinboxValues() { KoColor newColor; int channelcount = m_d->cs->channelCount(); quint8 *data = new quint8[m_d->cs->pixelSize()]; QVector channelValues(channelcount); channelValues.fill(1.0); QList channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); for (int i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) { int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels()); if (channels.at(i)->channelValueType()==KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)){ int value = m_d->spinBoxList.at(i)->value(); channelValues[channelposition] = KoColorSpaceMaths::scaleToA(value); } else if (channels.at(i)->channelValueType()==KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)){ channelValues[channelposition] = KoColorSpaceMaths::scaleToA(m_d->spinBoxList.at(i)->value()); } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 || channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 || channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) { channelValues[channelposition] = m_d->doubleSpinBoxList.at(i)->value(); } } m_d->cs->fromNormalisedChannelsValue(data, channelValues); newColor.setColor(data, m_d->cs); newColor.setOpacity(m_d->color.opacityU8()); m_d->color = newColor; } void KisSpinboxColorSelector::slotUpdateFromSpinBoxes() { createColorFromSpinboxValues(); emit sigNewColor(m_d->color); } void KisSpinboxColorSelector::updateSpinboxesWithNewValues() { int channelcount = m_d->cs->channelCount(); QVector channelValues(channelcount); channelValues.fill(1.0); m_d->cs->normalisedChannelsValue(m_d->color.data(), channelValues); QList channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); int i; /*while (QLayoutItem *item = this->layout()->takeAt(0)) { item->widget()->blockSignals(true); }*/ for (i=0; ispinBoxList.size(); i++) { m_d->spinBoxList.at(i)->blockSignals(true); } for (i=0; idoubleSpinBoxList.size(); i++) { m_d->doubleSpinBoxList.at(i)->blockSignals(true); } for (i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) { int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels()); if (channels.at(i)->channelValueType() == KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)) { int value = KoColorSpaceMaths::scaleToA(channelValues[channelposition]); m_d->spinBoxList.at(i)->setValue(value); } else if (channels.at(i)->channelValueType() == KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)) { m_d->spinBoxList.at(i)->setValue(KoColorSpaceMaths::scaleToA(channelValues[channelposition])); } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 || channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 || channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) { m_d->doubleSpinBoxList.at(i)->setValue(channelValues[channelposition]); } } for (i=0; ispinBoxList.size(); i++) { m_d->spinBoxList.at(i)->blockSignals(false); } for (i=0; idoubleSpinBoxList.size(); i++) { m_d->doubleSpinBoxList.at(i)->blockSignals(false); } /*while (QLayoutItem *item = this->layout()->takeAt(0)) { item->widget()->blockSignals(false); }*/ } diff --git a/libs/ui/widgets/kis_visual_color_selector.cpp b/libs/ui/widgets/kis_visual_color_selector.cpp index 6b61894d0a..23d0b779c3 100644 --- a/libs/ui/widgets/kis_visual_color_selector.cpp +++ b/libs/ui/widgets/kis_visual_color_selector.cpp @@ -1,1604 +1,1606 @@ /* * 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 "kis_visual_color_selector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorConversions.h" #include "KoColorDisplayRendererInterface.h" #include "KoChannelInfo.h" #include #include #include "kis_signal_compressor.h" struct KisVisualColorSelector::Private { KoColor currentcolor; - const KoColorSpace *currentCS; + const KoColorSpace *currentCS {0}; QList widgetlist; - bool updateSelf = false; - bool updateLonesome = false; //for Modal dialogs. - bool circular = false; - const KoColorDisplayRendererInterface *displayRenderer = 0; + bool updateSelf {false}; + bool updateLonesome {false}; //for Modal dialogs. + bool circular {false}; + const KoColorDisplayRendererInterface *displayRenderer {0}; KisVisualColorSelector::Configuration acs_config; //Current coordinates. - KisSignalCompressor *updateTimer = 0; + KisSignalCompressor *updateTimer {0}; QVector currentCoordinates; }; -KisVisualColorSelector::KisVisualColorSelector(QWidget *parent) : QWidget(parent), m_d(new Private) +KisVisualColorSelector::KisVisualColorSelector(QWidget *parent) + : QWidget(parent) + , m_d(new Private) { this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); QVBoxLayout *layout = new QVBoxLayout; this->setLayout(layout); KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); m_d->acs_config = Configuration::fromString(cfg.readEntry("colorSelectorConfiguration", KisVisualColorSelector::Configuration().toString())); } KisVisualColorSelector::~KisVisualColorSelector() { } void KisVisualColorSelector::slotSetColor(KoColor c) { - if (m_d->updateSelf==false) { + if (m_d->updateSelf == false) { m_d->currentcolor = c; if (m_d->currentCS != c.colorSpace()) { slotsetColorSpace(c.colorSpace()); } } updateSelectorElements(QObject::sender()); } void KisVisualColorSelector::slotsetColorSpace(const KoColorSpace *cs) { if (m_d->currentCS != cs) { m_d->currentCS = cs; slotRebuildSelectors(); } } void KisVisualColorSelector::setConfig(bool forceCircular, bool forceSelfUpdate) { m_d->updateLonesome = forceSelfUpdate; m_d->circular = forceCircular; } KoColor KisVisualColorSelector::getCurrentColor() { return m_d->currentcolor; } void KisVisualColorSelector::ConfigurationChanged() { m_d->updateTimer = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); m_d->updateTimer->start(); connect(m_d->updateTimer, SIGNAL(timeout()), SLOT(slotRebuildSelectors()), Qt::UniqueConnection); } void KisVisualColorSelector::slotRebuildSelectors() { KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); m_d->acs_config = Configuration::fromString(cfg.readEntry("colorSelectorConfiguration", KisVisualColorSelector::Configuration().toString())); if (this->children().at(0)) { qDeleteAll(this->children()); } m_d->widgetlist.clear(); QLayout *layout = new QHBoxLayout; //redraw all the widgets. int sizeValue = qMin(width(), height()); int borderWidth = qMax(sizeValue*0.1, 20.0); if (m_d->currentCS->colorChannelCount() == 1) { KisVisualColorSelectorShape *bar; if (m_d->circular==false) { bar = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::onedimensional,KisVisualColorSelectorShape::Channel, m_d->currentCS, 0, 0,m_d->displayRenderer, borderWidth); bar->setMaximumWidth(width()*0.1); bar->setMaximumHeight(height()); } else { bar= new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::onedimensional,KisVisualColorSelectorShape::Channel, m_d->currentCS, 0, 0,m_d->displayRenderer, borderWidth, KisVisualEllipticalSelectorShape::borderMirrored); layout->setMargin(0); } connect (bar, SIGNAL(sigNewColor(KoColor)), this, SLOT(updateFromWidgets(KoColor))); layout->addWidget(bar); m_d->widgetlist.append(bar); } else if (m_d->currentCS->colorChannelCount() == 3) { QRect newrect(0,0, this->geometry().width(), this->geometry().height()); KisVisualColorSelectorShape::ColorModel modelS = KisVisualColorSelectorShape::HSV; int channel1 = 0; int channel2 = 1; int channel3 = 2; switch(m_d->acs_config.subTypeParameter) { case H: channel1 = 0; break; case hsyS: case hsiS: case hslS: case hsvS: channel1 = 1; break; case V: case L: case I: case Y: channel1 = 2; break; } switch(m_d->acs_config.mainTypeParameter) { case hsySH: modelS = KisVisualColorSelectorShape::HSY; channel2 = 0; channel3 = 1; break; case hsiSH: modelS = KisVisualColorSelectorShape::HSI; channel2 = 0; channel3 = 1; break; case hslSH: modelS = KisVisualColorSelectorShape::HSL; channel2 = 0; channel3 = 1; break; case hsvSH: modelS = KisVisualColorSelectorShape::HSV; channel2 = 0; channel3 = 1; break; case YH: modelS = KisVisualColorSelectorShape::HSY; channel2 = 0; channel3 = 2; break; case LH: modelS = KisVisualColorSelectorShape::HSL; channel2 = 0; channel3 = 2; break; case IH: modelS = KisVisualColorSelectorShape::HSL; channel2 = 0; channel3 = 2; break; case VH: modelS = KisVisualColorSelectorShape::HSV; channel2 = 0; channel3 = 2; break; case SY: modelS = KisVisualColorSelectorShape::HSY; channel2 = 1; channel3 = 2; break; case SI: modelS = KisVisualColorSelectorShape::HSI; channel2 = 1; channel3 = 2; break; case SL: modelS = KisVisualColorSelectorShape::HSL; channel2 = 1; channel3 = 2; break; case SV: case SV2: modelS = KisVisualColorSelectorShape::HSV; channel2 = 1; channel3 = 2; break; } if (m_d->acs_config.mainType==Triangle) { modelS = KisVisualColorSelectorShape::HSV; //Triangle only really works in HSV mode. } KisVisualColorSelectorShape *bar; if (m_d->acs_config.subType==Ring) { bar = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::onedimensional, modelS, m_d->currentCS, channel1, channel1, m_d->displayRenderer, borderWidth,KisVisualEllipticalSelectorShape::border); bar->resize(sizeValue, sizeValue); } else if (m_d->acs_config.subType==Slider && m_d->circular==false) { bar = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::onedimensional, modelS, m_d->currentCS, channel1, channel1, m_d->displayRenderer, borderWidth); bar->setMaximumWidth(borderWidth); bar->setMinimumWidth(borderWidth); bar->setMinimumHeight(sizeValue); } else if (m_d->acs_config.subType==Slider && m_d->circular==true) { bar = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::onedimensional, modelS, m_d->currentCS, channel1, channel1, m_d->displayRenderer, borderWidth, KisVisualEllipticalSelectorShape::borderMirrored); bar->resize(sizeValue, sizeValue); } bar->setColor(m_d->currentcolor); m_d->widgetlist.append(bar); KisVisualColorSelectorShape *block; if (m_d->acs_config.mainType==Triangle) { block = new KisVisualTriangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional, modelS, m_d->currentCS, channel2, channel3, m_d->displayRenderer); block->setGeometry(bar->getSpaceForTriangle(newrect)); } else if (m_d->acs_config.mainType==Square) { block = new KisVisualRectangleSelectorShape(this, KisVisualColorSelectorShape::twodimensional, modelS, m_d->currentCS, channel2, channel3, m_d->displayRenderer); block->setGeometry(bar->getSpaceForSquare(newrect)); } else { block = new KisVisualEllipticalSelectorShape(this, KisVisualColorSelectorShape::twodimensional, modelS, m_d->currentCS, channel2, channel3, m_d->displayRenderer); block->setGeometry(bar->getSpaceForCircle(newrect)); } block->setColor(m_d->currentcolor); connect (bar, SIGNAL(sigNewColor(KoColor)), block, SLOT(setColorFromSibling(KoColor))); connect (block, SIGNAL(sigNewColor(KoColor)), SLOT(updateFromWidgets(KoColor))); connect (bar, SIGNAL(sigHSXchange()), SLOT(HSXwrangler())); connect (block, SIGNAL(sigHSXchange()), SLOT(HSXwrangler())); m_d->widgetlist.append(block); } else if (m_d->currentCS->colorChannelCount() == 4) { KisVisualRectangleSelectorShape *block = new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional,KisVisualColorSelectorShape::Channel, m_d->currentCS, 0, 1); KisVisualRectangleSelectorShape *block2 = new KisVisualRectangleSelectorShape(this, KisVisualRectangleSelectorShape::twodimensional,KisVisualColorSelectorShape::Channel, m_d->currentCS, 2, 3); block->setMaximumWidth(width()*0.5); block->setMaximumHeight(height()); block2->setMaximumWidth(width()*0.5); block2->setMaximumHeight(height()); block->setColor(m_d->currentcolor); block2->setColor(m_d->currentcolor); connect (block, SIGNAL(sigNewColor(KoColor)), block2, SLOT(setColorFromSibling(KoColor))); connect (block2, SIGNAL(sigNewColor(KoColor)), SLOT(updateFromWidgets(KoColor))); layout->addWidget(block); layout->addWidget(block2); m_d->widgetlist.append(block); m_d->widgetlist.append(block2); } this->setLayout(layout); } void KisVisualColorSelector::setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer) { m_d->displayRenderer = displayRenderer; if (m_d->widgetlist.size()>0) { Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) { shape->setDisplayRenderer(displayRenderer); } } } void KisVisualColorSelector::updateSelectorElements(QObject *source) { //first lock all elements from sending updates, then update all elements. Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) { shape->blockSignals(true); } Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) { if (shape!=source) { if (m_d->updateSelf) { shape->setColorFromSibling(m_d->currentcolor); } else { shape->setColor(m_d->currentcolor); } } } Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) { shape->blockSignals(false); } } void KisVisualColorSelector::updateFromWidgets(KoColor c) { m_d->currentcolor = c; m_d->updateSelf = true; if (m_d->updateLonesome) { slotSetColor(c); } else { Q_EMIT sigNewColor(c); } } void KisVisualColorSelector::leaveEvent(QEvent *) { m_d->updateSelf = false; } void KisVisualColorSelector::resizeEvent(QResizeEvent *) { int sizeValue = qMin(width(), height()); int borderWidth = qMax(sizeValue*0.1, 20.0); QRect newrect(0,0, this->geometry().width(), this->geometry().height()); if (!m_d->currentCS) { slotsetColorSpace(m_d->currentcolor.colorSpace()); } if (m_d->currentCS->colorChannelCount()==3) { if (m_d->acs_config.subType==Ring) { m_d->widgetlist.at(0)->resize(sizeValue,sizeValue); } else if (m_d->acs_config.subType==Slider && m_d->circular==false) { m_d->widgetlist.at(0)->setMaximumWidth(borderWidth); m_d->widgetlist.at(0)->setMinimumWidth(borderWidth); m_d->widgetlist.at(0)->setMinimumHeight(sizeValue); m_d->widgetlist.at(0)->setMaximumHeight(sizeValue); } else if (m_d->acs_config.subType==Slider && m_d->circular==true) { m_d->widgetlist.at(0)->resize(sizeValue,sizeValue); } m_d->widgetlist.at(0)->setBorderWidth(borderWidth); if (m_d->acs_config.mainType==Triangle) { m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForTriangle(newrect)); } else if (m_d->acs_config.mainType==Square) { m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForSquare(newrect)); } else if (m_d->acs_config.mainType==Wheel) { m_d->widgetlist.at(1)->setGeometry(m_d->widgetlist.at(0)->getSpaceForCircle(newrect)); } } Q_FOREACH (KisVisualColorSelectorShape *shape, m_d->widgetlist) { shape->update(); } } void KisVisualColorSelector::HSXwrangler() { m_d->currentCoordinates = QVector (3); QVector w1 = m_d->widgetlist.at(0)->getHSX(m_d->currentCoordinates, true); QVector w2 = m_d->widgetlist.at(1)->getHSX(m_d->currentCoordinates, true); QVector ch(3); ch[0] = m_d->widgetlist.at(0)->getChannels().at(0); ch[1] = m_d->widgetlist.at(1)->getChannels().at(0); ch[2] = m_d->widgetlist.at(1)->getChannels().at(1); m_d->currentCoordinates[ch[0]] = w1[ch[0]]; m_d->currentCoordinates[ch[1]] = w2[ch[1]]; m_d->currentCoordinates[ch[2]] = w2[ch[2]]; m_d->widgetlist.at(0)->setHSX(m_d->currentCoordinates, true); m_d->widgetlist.at(1)->setHSX(m_d->currentCoordinates, true); } /*------------Selector shape------------*/ struct KisVisualColorSelectorShape::Private { QImage gradient; QImage fullSelector; bool imagesNeedUpdate= true; QPointF currentCoordinates; Dimensions dimension; ColorModel model; const KoColorSpace *cs; KoColor currentColor; int channel1; int channel2; KisSignalCompressor *updateTimer; KisSignalCompressor *siblingTimer; bool mousePressActive = false; const KoColorDisplayRendererInterface *displayRenderer = 0; qreal hue = 0.0; qreal sat = 0.0; qreal tone = 0.0; }; KisVisualColorSelectorShape::KisVisualColorSelectorShape(QWidget *parent, KisVisualColorSelectorShape::Dimensions dimension, KisVisualColorSelectorShape::ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer): QWidget(parent), m_d(new Private) { m_d->dimension = dimension; m_d->model = model; m_d->cs = cs; m_d->currentColor = KoColor(); m_d->currentColor.setOpacity(1.0); m_d->currentColor.convertTo(cs); int maxchannel = m_d->cs->colorChannelCount()-1; m_d->channel1 = qBound(0, channel1, maxchannel); m_d->channel2 = qBound(0, channel2, maxchannel); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_d->updateTimer = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); m_d->siblingTimer = new KisSignalCompressor(30 /* ms */, KisSignalCompressor::POSTPONE, this); setDisplayRenderer(displayRenderer); show(); } KisVisualColorSelectorShape::~KisVisualColorSelectorShape() { } void KisVisualColorSelectorShape::updateCursor() { QPointF point1 = convertKoColorToShapeCoordinate(m_d->currentColor); if (point1 != m_d->currentCoordinates) { m_d->currentCoordinates = point1; } } QPointF KisVisualColorSelectorShape::getCursorPosition() { return m_d->currentCoordinates; } void KisVisualColorSelectorShape::setColor(KoColor c) { if (c.colorSpace() != m_d->cs) { c.convertTo(m_d->cs); } m_d->currentColor = c; updateCursor(); m_d->imagesNeedUpdate = true; update(); } void KisVisualColorSelectorShape::setColorFromSibling(KoColor c) { if (c.colorSpace() != m_d->cs) { c.convertTo(m_d->cs); } m_d->currentColor = c; Q_EMIT sigNewColor(c); m_d->imagesNeedUpdate = true; update(); } void KisVisualColorSelectorShape::setDisplayRenderer (const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { if (m_d->displayRenderer) { m_d->displayRenderer->disconnect(this); } m_d->displayRenderer = displayRenderer; } else { m_d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } connect(m_d->displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(updateFromChangedDisplayRenderer()), Qt::UniqueConnection); } void KisVisualColorSelectorShape::updateFromChangedDisplayRenderer() { m_d->imagesNeedUpdate = true; updateCursor(); //m_d->currentColor = convertShapeCoordinateToKoColor(getCursorPosition()); update(); } void KisVisualColorSelectorShape::forceImageUpdate() { m_d->imagesNeedUpdate = true; } QColor KisVisualColorSelectorShape::getColorFromConverter(KoColor c){ QColor col; KoColor color = c; if (m_d->displayRenderer) { color.convertTo(m_d->displayRenderer->getPaintingColorSpace()); col = m_d->displayRenderer->toQColor(c); } else { col = c.toQColor(); } return col; } void KisVisualColorSelectorShape::slotSetActiveChannels(int channel1, int channel2) { int maxchannel = m_d->cs->colorChannelCount()-1; m_d->channel1 = qBound(0, channel1, maxchannel); m_d->channel2 = qBound(0, channel2, maxchannel); m_d->imagesNeedUpdate = true; update(); } QImage KisVisualColorSelectorShape::getImageMap() { if (m_d->imagesNeedUpdate == true) { m_d->imagesNeedUpdate = false; m_d->gradient = QImage(width(), height(), QImage::Format_ARGB32); m_d->gradient.fill(Qt::transparent); QImage img(width(), height(), QImage::Format_ARGB32); img.fill(Qt::transparent); for (int y = 0; y(img.scanLine(y)); for (int x=0; xgradient = img; } return m_d->gradient; } KoColor KisVisualColorSelectorShape::convertShapeCoordinateToKoColor(QPointF coordinates, bool cursor) { KoColor c = m_d->currentColor; QVector channelValues (c.colorSpace()->channelCount()); channelValues.fill(1.0); c.colorSpace()->normalisedChannelsValue(c.data(), channelValues); QVector channelValuesDisplay = channelValues; QVector maxvalue(c.colorSpace()->channelCount()); maxvalue.fill(1.0); if (m_d->displayRenderer && (m_d->cs->colorDepthId() == Float16BitsColorDepthID || m_d->cs->colorDepthId() == Float32BitsColorDepthID || m_d->cs->colorDepthId() == Float64BitsColorDepthID) && m_d->cs->colorModelId() != LABAColorModelID && m_d->cs->colorModelId() != CMYKAColorModelID) { for (int ch = 0; chcs->channels()[ch]; maxvalue[ch] = m_d->displayRenderer->maxVisibleFloatValue(channel); channelValues[ch] = channelValues[ch]/(maxvalue[ch]); channelValuesDisplay[KoChannelInfo::displayPositionToChannelIndex(ch, m_d->cs->channels())] = channelValues[ch]; } } else { for (int i =0; ics->channels())] = qBound((float)0.0,channelValues[i], (float)1.0); } } qreal huedivider = 1.0; qreal huedivider2 = 1.0; if (m_d->channel1==0) { huedivider = 360.0; } if (m_d->channel2==0) { huedivider2 = 360.0; } if (m_d->model != ColorModel::Channel && c.colorSpace()->colorModelId().id() == "RGBA") { if (c.colorSpace()->colorModelId().id() == "RGBA") { if (m_d->model == ColorModel::HSV){ /* * RGBToHSV has a undefined hue possibility. This means that hue will be -1. * This can be annoying for dealing with a selector, but I understand it is being * used for the KoColorSelector... For now implement a qMax here. */ QVector inbetween(3); RGBToHSV(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); inbetween[m_d->channel1] = coordinates.x()*huedivider; if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y()*huedivider2; } if (cursor==true){setHSX(convertvectorfloatToqreal(inbetween));Q_EMIT sigHSXchange();} HSVToRGB(qMax(inbetween[0],(float)0.0), inbetween[1], inbetween[2], &channelValuesDisplay[0], &channelValuesDisplay[1], &channelValuesDisplay[2]); } else if (m_d->model == ColorModel::HSL) { /* * HSLToRGB can give negative values on the grey. I fixed the fromNormalisedChannel function to clamp, * but you might want to manually clamp for floating point values. */ QVector inbetween(3); RGBToHSL(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); inbetween[m_d->channel1] = fmod(coordinates.x()*huedivider, 360.0); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y()*huedivider2; } if (cursor==true){setHSX(convertvectorfloatToqreal(inbetween));Q_EMIT sigHSXchange();} HSLToRGB(qMax(inbetween[0],(float)0.0), inbetween[1], inbetween[2],&channelValuesDisplay[0],&channelValuesDisplay[1], &channelValuesDisplay[2]); } else if (m_d->model == ColorModel::HSI) { /* * HSI is a modified HSY function. */ QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSI(chan2[0],chan2[1], chan2[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = getHSX(inbetween); inbetween[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y(); } if (cursor==true){setHSX(inbetween);Q_EMIT sigHSXchange();} HSIToRGB(inbetween[0], inbetween[1], inbetween[2],&chan2[0],&chan2[1], &chan2[2]); channelValuesDisplay = convertvectorqrealTofloat(chan2); } else /*if (m_d->model == ColorModel::HSY)*/ { /* * HSY is pretty slow to render due being a pretty over-the-top function. * Might be worth investigating whether HCY can be used instead, but I have had * some weird results with that. */ QVector luma= m_d->cs->lumaCoefficients(); QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSY(chan2[0],chan2[1], chan2[2], &inbetween[0], &inbetween[1], &inbetween[2], luma[0], luma[1], luma[2]); inbetween = getHSX(inbetween); inbetween[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { inbetween[m_d->channel2] = coordinates.y(); } if (cursor==true){setHSX(inbetween);Q_EMIT sigHSXchange();} HSYToRGB(inbetween[0], inbetween[1], inbetween[2],&chan2[0],&chan2[1], &chan2[2], luma[0], luma[1], luma[2]); channelValuesDisplay = convertvectorqrealTofloat(chan2); } } } else { channelValuesDisplay[m_d->channel1] = coordinates.x(); if (m_d->dimension == Dimensions::twodimensional) { channelValuesDisplay[m_d->channel2] = coordinates.y(); } } for (int i=0; ics->channels())]*(maxvalue[i]); } c.colorSpace()->fromNormalisedChannelsValue(c.data(), channelValues); return c; } QPointF KisVisualColorSelectorShape::convertKoColorToShapeCoordinate(KoColor c) { if (c.colorSpace() != m_d->cs) { c.convertTo(m_d->cs); } QVector channelValues (m_d->currentColor.colorSpace()->channelCount()); channelValues.fill(1.0); m_d->cs->normalisedChannelsValue(c.data(), channelValues); QVector channelValuesDisplay = channelValues; QVector maxvalue(c.colorSpace()->channelCount()); maxvalue.fill(1.0); if (m_d->displayRenderer && (m_d->cs->colorDepthId() == Float16BitsColorDepthID || m_d->cs->colorDepthId() == Float32BitsColorDepthID || m_d->cs->colorDepthId() == Float64BitsColorDepthID) && m_d->cs->colorModelId() != LABAColorModelID && m_d->cs->colorModelId() != CMYKAColorModelID) { for (int ch = 0; chcs->channels()[ch]; maxvalue[ch] = m_d->displayRenderer->maxVisibleFloatValue(channel); channelValues[ch] = channelValues[ch]/(maxvalue[ch]); channelValuesDisplay[KoChannelInfo::displayPositionToChannelIndex(ch, m_d->cs->channels())] = channelValues[ch]; } } else { for (int i =0; ics->channels())] = qBound((float)0.0,channelValues[i], (float)1.0); } } QPointF coordinates(0.0,0.0); qreal huedivider = 1.0; qreal huedivider2 = 1.0; if (m_d->channel1==0) { huedivider = 360.0; } if (m_d->channel2==0) { huedivider2 = 360.0; } if (m_d->model != ColorModel::Channel && c.colorSpace()->colorModelId().id() == "RGBA") { if (c.colorSpace()->colorModelId().id() == "RGBA") { if (m_d->model == ColorModel::HSV){ QVector inbetween(3); RGBToHSV(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); coordinates.setX(inbetween[m_d->channel1]/huedivider); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]/huedivider2); } } else if (m_d->model == ColorModel::HSL) { QVector inbetween(3); RGBToHSL(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = convertvectorqrealTofloat(getHSX(convertvectorfloatToqreal(inbetween))); coordinates.setX(inbetween[m_d->channel1]/huedivider); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]/huedivider2); } } else if (m_d->model == ColorModel::HSI) { QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSI(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2]); inbetween = getHSX(inbetween); coordinates.setX(inbetween[m_d->channel1]); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]); } } else if (m_d->model == ColorModel::HSY) { QVector luma = m_d->cs->lumaCoefficients(); QVector chan2 = convertvectorfloatToqreal(channelValuesDisplay); QVector inbetween(3); RGBToHSY(channelValuesDisplay[0],channelValuesDisplay[1], channelValuesDisplay[2], &inbetween[0], &inbetween[1], &inbetween[2], luma[0], luma[1], luma[2]); inbetween = getHSX(inbetween); coordinates.setX(inbetween[m_d->channel1]); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(inbetween[m_d->channel2]); } } } } else { coordinates.setX(qBound((float)0.0, channelValuesDisplay[m_d->channel1], (float)1.0)); if (m_d->dimension == Dimensions::twodimensional) { coordinates.setY(qBound((float)0.0, channelValuesDisplay[m_d->channel2], (float)1.0)); } } return coordinates; } QVector KisVisualColorSelectorShape::convertvectorqrealTofloat(QVector real) { QVector vloat(real.size()); for (int i=0; i KisVisualColorSelectorShape::convertvectorfloatToqreal(QVector vloat) { QVector real(vloat.size()); for (int i=0; ibutton()==Qt::LeftButton) { m_d->mousePressActive = true; QPointF coordinates = convertWidgetCoordinateToShapeCoordinate(e->pos()); KoColor col = convertShapeCoordinateToKoColor(coordinates, true); setColor(col); Q_EMIT sigNewColor(col); m_d->updateTimer->start(); } } void KisVisualColorSelectorShape::mouseMoveEvent(QMouseEvent *e) { if (m_d->mousePressActive==true && this->mask().contains(e->pos())) { QPointF coordinates = convertWidgetCoordinateToShapeCoordinate(e->pos()); KoColor col = convertShapeCoordinateToKoColor(coordinates, true); setColor(col); if (!m_d->updateTimer->isActive()) { Q_EMIT sigNewColor(col); m_d->updateTimer->start(); } } else { e->ignore(); } } void KisVisualColorSelectorShape::mouseReleaseEvent(QMouseEvent *) { m_d->mousePressActive = false; } void KisVisualColorSelectorShape::paintEvent(QPaintEvent*) { QPainter painter(this); //check if old and new colors differ. if (m_d->imagesNeedUpdate) { setMask(getMaskMap()); } drawCursor(); painter.drawImage(0,0,m_d->fullSelector); } KisVisualColorSelectorShape::Dimensions KisVisualColorSelectorShape::getDimensions() { return m_d->dimension; } KisVisualColorSelectorShape::ColorModel KisVisualColorSelectorShape::getColorModel() { return m_d->model; } void KisVisualColorSelectorShape::setFullImage(QImage full) { m_d->fullSelector = full; } KoColor KisVisualColorSelectorShape::getCurrentColor() { return m_d->currentColor; } QVector KisVisualColorSelectorShape::getHSX(QVector hsx, bool wrangler) { QVector ihsx = hsx; if (!wrangler){ //Ok, so this docker will not update luminosity if there's not at the least 3% more variation. //This is necessary for 8bit. if (m_d->cs->colorDepthId()==Integer8BitsColorDepthID){ if (hsx[2]>m_d->tone-0.03 && hsx[2]tone+0.03) { ihsx[2] = m_d->tone; } } else { if (hsx[2]>m_d->tone-0.005 && hsx[2]tone+0.005) { ihsx[2] = m_d->tone; } } if (m_d->model==HSV){ if (hsx[2]<=0.0) { ihsx[1] = m_d->sat; } } else { if ((hsx[2]<=0.0 || hsx[2]>=1.0)) { ihsx[1] = m_d->sat; } } if ((hsx[1]<=0.0 || hsx[0]<0.0)){ ihsx[0]=m_d->hue; } } else { ihsx[0]=m_d->hue; ihsx[1]=m_d->sat; ihsx[2]=m_d->tone; } return ihsx; } void KisVisualColorSelectorShape::setHSX(QVector hsx, bool wrangler) { if (wrangler){ m_d->tone = hsx[2]; m_d->sat = hsx[1]; m_d->hue = hsx[0]; } else { if (m_d->channel1==2 || m_d->channel2==2){ m_d->tone=hsx[2]; } if (m_d->model==HSV){ if (hsx[2]>0.0) { m_d->sat = hsx[1]; } } else { if ((hsx[2]>0.0 || hsx[2]<1.0)) { m_d->sat = hsx[1]; } } if ((hsx[1]>0.0 && hsx[0]>=0.0)){ m_d->hue = hsx[0]; } } } QVector KisVisualColorSelectorShape::getChannels() { QVector channels(2); channels[0] = m_d->channel1; channels[1] = m_d->channel2; return channels; } /*-----------Rectangle Shape------------*/ KisVisualRectangleSelectorShape::KisVisualRectangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int width, singelDTypes d) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { m_type = d; m_barWidth = width; } KisVisualRectangleSelectorShape::~KisVisualRectangleSelectorShape() { } void KisVisualRectangleSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualRectangleSelectorShape::getSpaceForSquare(QRect geom) { QPointF tl; QPointF br; if (m_type==KisVisualRectangleSelectorShape::vertical) { br = geom.bottomRight(); tl = QPoint(geom.topLeft().x()+m_barWidth, geom.topLeft().y()); } else if (m_type==KisVisualRectangleSelectorShape::horizontal) { br = geom.bottomRight(); tl = QPoint(geom.topLeft().x(), geom.topLeft().y()+m_barWidth); } else { tl = QPointF (geom.topLeft().x()+m_barWidth, geom.topLeft().y()+m_barWidth); br = QPointF (geom.bottomRight().x()-m_barWidth, geom.bottomRight().y()-m_barWidth); } QRect a(tl.toPoint(), br.toPoint()); QRect r(a.left(), a.top(), qMin(a.height(), a.width()), qMin(a.height(), a.width())); return r; } QRect KisVisualRectangleSelectorShape::getSpaceForCircle(QRect geom) { return getSpaceForSquare(geom); } QRect KisVisualRectangleSelectorShape::getSpaceForTriangle(QRect geom) { return getSpaceForSquare(geom); } QPointF KisVisualRectangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) { qreal x = m_barWidth/2; qreal y = m_barWidth/2; qreal offset = 5.0; KisVisualColorSelectorShape::Dimensions dimension = getDimensions(); if (dimension == KisVisualColorSelectorShape::onedimensional) { if ( m_type == KisVisualRectangleSelectorShape::vertical) { y = qMin(coordinate.x()*(height()-offset*2)+offset, (qreal)height()); } else if (m_type == KisVisualRectangleSelectorShape::horizontal) { x = qMin(coordinate.x()*(width()-offset*2)+offset, (qreal)width()); } else if (m_type == KisVisualRectangleSelectorShape::border) { QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth); QPointF left (innerRect.left(),innerRect.center().y()); QList polygonLines; polygonLines.append(QLineF(left, innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), left)); qreal totalLength =0.0; Q_FOREACH(QLineF line, polygonLines) { totalLength += line.length(); } qreal length = coordinate.x()*totalLength; QPointF intersect(x,y); Q_FOREACH(QLineF line, polygonLines) { if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } x = qRound(intersect.x()); y = qRound(intersect.y()); } else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ { QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth); QPointF bottom (innerRect.center().x(), innerRect.bottom()); QList polygonLines; polygonLines.append(QLineF(bottom, innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), bottom)); qreal totalLength =0.0; Q_FOREACH(QLineF line, polygonLines) { totalLength += line.length(); } qreal length = coordinate.x()*(totalLength/2); QPointF intersect(x,y); if (coordinate.y()==1) { for (int i = polygonLines.size()-1; i==0; i--) { QLineF line = polygonLines.at(i); if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } } else { Q_FOREACH(QLineF line, polygonLines) { if (line.length()>length && length>0){ intersect = line.pointAt(length/line.length()); } length-=line.length(); } } x = qRound(intersect.x()); y = qRound(intersect.y()); } } else { x = qMin(coordinate.x()*(height()-offset*2)+offset, (qreal)height()); y = qMin(coordinate.y()*(width()-offset*2)+offset, (qreal)width()); } return QPointF(x,y); } QPointF KisVisualRectangleSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) { //default implementation: qreal x = 0.5; qreal y = 0.5; qreal offset = 5.0; KisVisualColorSelectorShape::Dimensions dimension = getDimensions(); if (getMaskMap().contains(coordinate)) { if (dimension == KisVisualColorSelectorShape::onedimensional ) { if (m_type == KisVisualRectangleSelectorShape::vertical) { x = qMax(((qreal)coordinate.y()-offset)/((qreal)height()-offset*2), 0.0); } else if (m_type == KisVisualRectangleSelectorShape::horizontal) { x = qMax(((qreal)coordinate.x()-offset)/((qreal)width()-offset*2),0.0); } else if (m_type == KisVisualRectangleSelectorShape::border) { //border QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); QPointF left (innerRect.left(),innerRect.center().y()); QList polygonLines; polygonLines.append(QLineF(left, innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), left)); QLineF radius(coordinate, this->geometry().center()); QPointF intersect(0.5,0.5); qreal length = 0.0; qreal totalLength = 0.0; bool foundIntersect = false; Q_FOREACH(QLineF line, polygonLines) { if (line.intersect(radius,&intersect)==QLineF::BoundedIntersection && foundIntersect==false) { foundIntersect = true; length+=QLineF(line.p1(), intersect).length(); } if (foundIntersect==false) { length+=line.length(); } totalLength+=line.length(); } x = length/totalLength; } else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ { //border QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); QPointF bottom (innerRect.center().x(), innerRect.bottom()); QList polygonLines; polygonLines.append(QLineF(bottom, innerRect.bottomLeft())); polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft())); polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight())); polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight())); polygonLines.append(QLineF(innerRect.bottomRight(), bottom)); QLineF radius(coordinate, this->geometry().center()); QPointF intersect(0.5,0.5); qreal length = 0.0; qreal totalLength = 0.0; bool foundIntersect = false; Q_FOREACH(QLineF line, polygonLines) { if (line.intersect(radius,&intersect)==QLineF::BoundedIntersection && foundIntersect==false) { foundIntersect = true; length+=QLineF(line.p1(), intersect).length(); } if (foundIntersect==false) { length+=line.length(); } totalLength+=line.length(); } int halflength = totalLength/2; if (length>halflength) { x = (halflength - (length-halflength))/halflength; y = 1.0; } else { x = length/halflength; y = 0.0; } } } else { x = qMax(((qreal)coordinate.x()-offset)/((qreal)width()-offset*2), 0.0); y = qMax(((qreal)coordinate.y()-offset)/((qreal)height()-offset*2), 0.0);; } } return QPointF(x, y); } QRegion KisVisualRectangleSelectorShape::getMaskMap() { QRegion mask = QRegion(0,0,width(),height()); if (m_type==KisVisualRectangleSelectorShape::border || m_type==KisVisualRectangleSelectorShape::borderMirrored) { mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2))); } return mask; } void KisVisualRectangleSelectorShape::resizeEvent(QResizeEvent *) { forceImageUpdate(); } void KisVisualRectangleSelectorShape::drawCursor() { QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); QImage fullSelector = getImageMap(); QColor col = getColorFromConverter(getCurrentColor()); QPainter painter; painter.begin(&fullSelector); painter.setRenderHint(QPainter::Antialiasing); //QPainterPath path; QBrush fill; fill.setStyle(Qt::SolidPattern); int cursorwidth = 5; QRect rect(cursorPoint.toPoint().x()-cursorwidth,cursorPoint.toPoint().y()-cursorwidth, cursorwidth*2,cursorwidth*2); if (m_type==KisVisualRectangleSelectorShape::vertical){ int x = ( cursorPoint.x()-(width()/2)+1 ); int y = ( cursorPoint.y()-cursorwidth ); rect.setCoords(x, y, x+width()-2, y+(cursorwidth*2)); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawLine(QLine(QPoint(0.0,0.0), QPoint(0.0,height()))); painter.drawLine(QLine(QPoint(width(),0.0), QPoint(width(),height()))); painter.restore(); } else { int x = cursorPoint.x()-cursorwidth; int y = cursorPoint.y()-(height()/2)+1; rect.setCoords(x, y, x+(cursorwidth*2), y+cursorwidth-2); } QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); if (getDimensions() == KisVisualColorSelectorShape::onedimensional && m_type!=KisVisualRectangleSelectorShape::border && m_type!=KisVisualRectangleSelectorShape::borderMirrored) { painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawRect(rect); //set filter conversion! fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); rect.setCoords(rect.topLeft().x()+1, rect.topLeft().y()+1, rect.topLeft().x()+rect.width()-2, rect.topLeft().y()+rect.height()-2); painter.drawRect(rect); }else if(m_type==KisVisualRectangleSelectorShape::borderMirrored){ painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y()); painter.drawEllipse(mirror, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); } else { painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawRect(QRect(0,0,width(),height())); painter.restore(); painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); } painter.end(); setFullImage(fullSelector); } //----------------Elliptical--------------------------// KisVisualEllipticalSelectorShape::KisVisualEllipticalSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int borwidth, singelDTypes d) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { m_type = d; m_barWidth = borwidth; } KisVisualEllipticalSelectorShape::~KisVisualEllipticalSelectorShape() { } QSize KisVisualEllipticalSelectorShape::sizeHint() const { return QSize(180,180); } void KisVisualEllipticalSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualEllipticalSelectorShape::getSpaceForSquare(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QLineF radius(b.center(), QPointF(b.left()+m_barWidth, b.center().y()) ); radius.setAngle(135); QPointF tl = radius.p2(); radius.setAngle(315); QPointF br = radius.p2(); QRect r(tl.toPoint(), br.toPoint()); return r; } QRect KisVisualEllipticalSelectorShape::getSpaceForCircle(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QPointF tl = QPointF (b.topLeft().x()+m_barWidth, b.topLeft().y()+m_barWidth); QPointF br = QPointF (b.bottomRight().x()-m_barWidth, b.bottomRight().y()-m_barWidth); QRect r(tl.toPoint(), br.toPoint()); return r; } QRect KisVisualEllipticalSelectorShape::getSpaceForTriangle(QRect geom) { int sizeValue = qMin(width(),height()); QRect b(geom.left(), geom.top(), sizeValue, sizeValue); QLineF radius(b.center(), QPointF(b.left()+m_barWidth, b.center().y()) ); radius.setAngle(90);//point at yellowgreen :) QPointF t = radius.p2(); radius.setAngle(330);//point to purple :) QPointF br = radius.p2(); radius.setAngle(210);//point to cerulean :) QPointF bl = radius.p2(); QPointF tl = QPoint(bl.x(),t.y()); QRect r(tl.toPoint(), br.toPoint()); return r; } QPointF KisVisualEllipticalSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) { qreal x; qreal y; qreal offset=7.0; qreal a = (qreal)width()*0.5; QPointF center(a, a); QLineF line(center, QPoint((m_barWidth*0.5),a)); qreal angle = coordinate.x()*360.0; angle = fmod(angle+180.0,360.0); angle = 180.0-angle; angle = angle+180.0; if (m_type==KisVisualEllipticalSelectorShape::borderMirrored) { angle = (coordinate.x()/2)*360.0; angle = fmod((angle+90.0), 360.0); } line.setAngle(angle); if (getDimensions()!=KisVisualColorSelectorShape::onedimensional) { line.setLength(qMin(coordinate.y()*(a-offset), a-offset)); } x = qRound(line.p2().x()); y = qRound(line.p2().y()); return QPointF(x,y); } QPointF KisVisualEllipticalSelectorShape::convertWidgetCoordinateToShapeCoordinate(QPoint coordinate) { //default implementation: qreal x = 0.5; qreal y = 1.0; qreal offset = 7.0; QRect total(0, 0, width(), height()); QLineF line(total.center(), coordinate); qreal a = (total.width()/2); qreal angle; if (m_type!=KisVisualEllipticalSelectorShape::borderMirrored){ angle = fmod((line.angle()+180.0), 360.0); angle = 180.0-angle; angle = angle+180.0; x = angle/360.0; if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { y = qBound(0.0,line.length()/(a-offset), 1.0); } } else { angle = fmod((line.angle()+270.0), 360.0); if (angle>180.0) { angle = 180.0-angle; angle = angle+180; } x = (angle/360.0)*2; if (getDimensions()==KisVisualColorSelectorShape::twodimensional) { y = qBound(0.0,(line.length()+offset)/a, 1.0); } } return QPointF(x, y); } QRegion KisVisualEllipticalSelectorShape::getMaskMap() { QRegion mask = QRegion(0,0,width(),height(), QRegion::Ellipse); if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2), QRegion::Ellipse)); } return mask; } void KisVisualEllipticalSelectorShape::resizeEvent(QResizeEvent *) { forceImageUpdate(); } void KisVisualEllipticalSelectorShape::drawCursor() { QPointF cursorPoint = convertShapeCoordinateToWidgetCoordinate(getCursorPosition()); QImage fullSelector = getImageMap(); QColor col = getColorFromConverter(getCurrentColor()); QPainter painter; painter.begin(&fullSelector); painter.setRenderHint(QPainter::Antialiasing); QRect innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)); painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Clear); QPen pen; pen.setWidth(5); painter.setPen(pen); painter.drawEllipse(QRect(0,0,width(),height())); if (getDimensions()==KisVisualColorSelectorShape::onedimensional) { painter.setBrush(Qt::SolidPattern); painter.drawEllipse(innerRect); } painter.restore(); QBrush fill; fill.setStyle(Qt::SolidPattern); int cursorwidth = 5; if(m_type==KisVisualEllipticalSelectorShape::borderMirrored){ painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y()); painter.drawEllipse(mirror, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1); painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1); } else { painter.setPen(Qt::white); fill.setColor(Qt::white); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth); fill.setColor(col); painter.setPen(Qt::black); painter.setBrush(fill); painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0); } painter.end(); setFullImage(fullSelector); } //----------------Triangle--------------------------// KisVisualTriangleSelectorShape::KisVisualTriangleSelectorShape(QWidget *parent, Dimensions dimension, ColorModel model, const KoColorSpace *cs, int channel1, int channel2, const KoColorDisplayRendererInterface *displayRenderer, int borwidth) : KisVisualColorSelectorShape(parent, dimension, model, cs, channel1, channel2, displayRenderer) { m_barWidth = borwidth; QRect total(0,0,width()*0.9,width()*0.9); setTriangle(); } KisVisualTriangleSelectorShape::~KisVisualTriangleSelectorShape() { } void KisVisualTriangleSelectorShape::setBorderWidth(int width) { m_barWidth = width; } QRect KisVisualTriangleSelectorShape::getSpaceForSquare(QRect geom) { return geom; } QRect KisVisualTriangleSelectorShape::getSpaceForCircle(QRect geom) { return geom; } QRect KisVisualTriangleSelectorShape::getSpaceForTriangle(QRect geom) { return geom; } void KisVisualTriangleSelectorShape::setTriangle() { QPoint apex = QPoint (width()*0.5,0); QPolygon triangle; triangle<< QPoint(0,height()) << apex << QPoint(width(),height()) << QPoint(0,height()); m_triangle = triangle; QLineF a(triangle.at(0),triangle.at(1)); QLineF b(triangle.at(0),triangle.at(2)); QLineF ap(triangle.at(2), a.pointAt(0.5)); QLineF bp(triangle.at(1), b.pointAt(0.5)); QPointF intersect; ap.intersect(bp,&intersect); m_center = intersect; QLineF r(triangle.at(0), intersect); m_radius = r.length(); } QPointF KisVisualTriangleSelectorShape::convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) { qreal offset=7.0;//the offset is so we get a nice little border that allows selecting extreme colors better. qreal y = qMin(coordinate.y()*(height()-offset*2)+offset+5.0, (qreal)height()-offset); qreal triWidth = width(); qreal horizontalLineLength = y*(2./sqrt(3.)); qreal horizontalLineStart = triWidth/2.-horizontalLineLength/2.; qreal relativeX = coordinate.x()*(horizontalLineLength-offset*2); qreal x = qMin(relativeX + horizontalLineStart + offset, (qreal)width()-offset*2); if (y, (C) 2008 * * 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_wdg_generator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_wdggenerators.h" class KisGeneratorItem : public QListWidgetItem { public: KisGeneratorItem(const QString & text, QListWidget * parent = 0, int type = Type) : QListWidgetItem(text, parent, type) { } KisGeneratorSP generator; }; struct KisWdgGenerator::Private { public: Private() : centralWidget(0), view(0) { } QWidget * centralWidget; // Active generator settings widget KisGeneratorSP currentGenerator; Ui_WdgGenerators uiWdgGenerators; KisPaintDeviceSP dev; QGridLayout *widgetLayout; KisViewManager *view; }; KisWdgGenerator::KisWdgGenerator(QWidget * parent) : QWidget(parent) , d(new Private()) { KisPaintDeviceSP dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8(0)); } KisWdgGenerator::~KisWdgGenerator() { delete d; } void KisWdgGenerator::initialize(KisViewManager *view) { d->view = view; d->uiWdgGenerators.setupUi(this); d->widgetLayout = new QGridLayout(d->uiWdgGenerators.centralWidgetHolder); QList generators = KisGeneratorRegistry::instance()->values(); Q_FOREACH (const KisGeneratorSP generator, generators) { Q_ASSERT(generator); KisGeneratorItem * item = new KisGeneratorItem(generator->name(), d->uiWdgGenerators.lstGenerators, QListWidgetItem::UserType + 1); item->generator = generator; } connect(d->uiWdgGenerators.lstGenerators, SIGNAL(currentRowChanged(int)), this, SLOT(slotGeneratorActivated(int))); if (d->uiWdgGenerators.lstGenerators->count() > 0) { d->uiWdgGenerators.lstGenerators->setCurrentRow(0); } } -void KisWdgGenerator::setConfiguration(const KisFilterConfiguration * config) +void KisWdgGenerator::setConfiguration(const KisFilterConfigurationSP config) { for (int i = 0; i < d->uiWdgGenerators.lstGenerators->count(); ++i) { KisGeneratorItem * item = static_cast(d->uiWdgGenerators.lstGenerators->item(i)); if (item->generator->id() == config->name()) { // match! slotGeneratorActivated(i); d->uiWdgGenerators.lstGenerators->setCurrentRow(i); KisConfigWidget * wdg = dynamic_cast(d->centralWidget); if (wdg) { wdg->setConfiguration(config); } return; } } } -KisFilterConfiguration * KisWdgGenerator::configuration() +KisFilterConfigurationSP KisWdgGenerator::configuration() { KisConfigWidget * wdg = dynamic_cast(d->centralWidget); if (wdg) { - KisFilterConfiguration * config - = dynamic_cast(wdg->configuration()); + KisFilterConfigurationSP config = dynamic_cast(wdg->configuration().data()); if (config) { return config; } } else { return d->currentGenerator->defaultConfiguration(0); } return 0; } void KisWdgGenerator::slotGeneratorActivated(int row) { - KisGeneratorItem * item = dynamic_cast(d->uiWdgGenerators.lstGenerators->item(row)); + KisGeneratorItem *item = dynamic_cast(d->uiWdgGenerators.lstGenerators->item(row)); if (!item) { - d->centralWidget = new QLabel(i18n("No configuration options."), - d->uiWdgGenerators.centralWidgetHolder); - } else { - + d->centralWidget = new QLabel(i18n("No configuration options."), d->uiWdgGenerators.centralWidgetHolder); + } + else { d->currentGenerator = item->generator; delete d->centralWidget; KisConfigWidget* widget = d->currentGenerator->createConfigurationWidget(d->uiWdgGenerators.centralWidgetHolder, d->dev); if (!widget) { // No widget, so display a label instead d->centralWidget = new QLabel(i18n("No configuration options."), d->uiWdgGenerators.centralWidgetHolder); } else { d->centralWidget = widget; widget->setView(d->view); widget->setConfiguration(d->currentGenerator->defaultConfiguration(d->dev)); } } d->widgetLayout->addWidget(d->centralWidget, 0 , 0); d->uiWdgGenerators.centralWidgetHolder->setMinimumSize(d->centralWidget->minimumSize()); } diff --git a/libs/ui/widgets/kis_wdg_generator.h b/libs/ui/widgets/kis_wdg_generator.h index f8e246e46d..a81afd2c68 100644 --- a/libs/ui/widgets/kis_wdg_generator.h +++ b/libs/ui/widgets/kis_wdg_generator.h @@ -1,65 +1,65 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_WDG_GENERATOR_H #define KIS_WDG_GENERATOR_H #include #include class KisFilterConfiguration; class KisViewManager; /** * A widget that allows users to select a generator and * create a config object for it. * * XXX: make use of bookmarked configuration things, like * in the filter widget. */ class KisWdgGenerator : public QWidget { Q_OBJECT public: KisWdgGenerator(QWidget * parent); KisWdgGenerator(QWidget * parent, KisPaintDeviceSP dev); ~KisWdgGenerator(); void initialize(KisViewManager *view); - void setConfiguration(const KisFilterConfiguration * config); + void setConfiguration(const KisFilterConfigurationSP config); - KisFilterConfiguration * configuration(); + KisFilterConfigurationSP configuration(); private Q_SLOTS: void slotGeneratorActivated(int); private: struct Private; Private * const d; }; #endif diff --git a/libs/widgets/KoResourcePopupAction.cpp b/libs/widgets/KoResourcePopupAction.cpp index 95f0192818..1c27b0c4cf 100644 --- a/libs/widgets/KoResourcePopupAction.cpp +++ b/libs/widgets/KoResourcePopupAction.cpp @@ -1,201 +1,202 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * 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 "KoResourcePopupAction.h" #include "KoResourceServerAdapter.h" #include "KoResourceItemView.h" #include "KoResourceModel.h" #include "KoResourceItemDelegate.h" #include #include "KoCheckerBoardPainter.h" #include "KoShapeBackground.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class KoResourcePopupAction::Private { public: Private() : resourceList(0), background(0), checkerPainter(4) {} QMenu *menu; KoResourceItemView *resourceList; QSharedPointer background; + KoImageCollection *imageCollection; KoCheckerBoardPainter checkerPainter; }; KoResourcePopupAction::KoResourcePopupAction(QSharedPointerresourceAdapter, QObject *parent) : QAction(parent) , d(new Private()) { Q_ASSERT(resourceAdapter); d->menu = new QMenu(); QWidget *widget = new QWidget(); QWidgetAction *wdgAction = new QWidgetAction(this); d->resourceList = new KoResourceItemView(widget); d->resourceList->setModel(new KoResourceModel(resourceAdapter, widget)); d->resourceList->setItemDelegate(new KoResourceItemDelegate(widget)); KoResourceModel * resourceModel = qobject_cast(d->resourceList->model()); if (resourceModel) { resourceModel->setColumnCount(1); } KoResource *resource = 0; if (resourceAdapter->resources().count() > 0) { resource = resourceAdapter->resources().at(0); } KoAbstractGradient *gradient = dynamic_cast(resource); KoPattern *pattern = dynamic_cast(resource); if (gradient) { QGradient *qg = gradient->toQGradient(); qg->setCoordinateMode(QGradient::ObjectBoundingMode); d->background = QSharedPointer(new KoGradientBackground(qg)); } else if (pattern) { - KoImageCollection *collection = new KoImageCollection(); - d->background = QSharedPointer(new KoPatternBackground(collection)); + d->imageCollection = new KoImageCollection(); + d->background = QSharedPointer(new KoPatternBackground(d->imageCollection)); static_cast(d->background.data())->setPattern(pattern->pattern()); } QHBoxLayout *layout = new QHBoxLayout(widget); layout->addWidget(d->resourceList); widget->setLayout(layout); wdgAction->setDefaultWidget(widget); d->menu->addAction(wdgAction); setMenu(d->menu); new QHBoxLayout(d->menu); d->menu->layout()->addWidget(widget); d->menu->layout()->setMargin(0); connect(d->resourceList, SIGNAL(clicked(QModelIndex)), this, SLOT(indexChanged(QModelIndex))); updateIcon(); } KoResourcePopupAction::~KoResourcePopupAction() { /* Removing the actions here make them be deleted together with their default widget. * This happens only if the actions are QWidgetAction, and we know they are since * the only ones added are in KoResourcePopupAction constructor. */ int i = 0; while(d->menu->actions().size() > 0) { d->menu->removeAction(d->menu->actions()[i]); ++i; } delete d->menu; - + delete d->imageCollection; delete d; } QSharedPointer KoResourcePopupAction::currentBackground() const { return d->background; } void KoResourcePopupAction::setCurrentBackground(QSharedPointer background) { d->background = background; updateIcon(); } void KoResourcePopupAction::indexChanged(const QModelIndex &modelIndex) { if (! modelIndex.isValid()) { return; } d->menu->hide(); KoResource *resource = static_cast(modelIndex.internalPointer()); if(resource) { KoAbstractGradient *gradient = dynamic_cast(resource); KoPattern *pattern = dynamic_cast(resource); if (gradient) { QGradient *qg = gradient->toQGradient(); qg->setCoordinateMode(QGradient::ObjectBoundingMode); d->background = QSharedPointer(new KoGradientBackground(qg)); } else if (pattern) { KoImageCollection *collection = new KoImageCollection(); d->background = QSharedPointer(new KoPatternBackground(collection)); qSharedPointerDynamicCast(d->background)->setPattern(pattern->pattern()); } emit resourceSelected(d->background); updateIcon(); } } void KoResourcePopupAction::updateIcon() { QSize iconSize; QToolButton *toolButton = dynamic_cast(parentWidget()); if (toolButton) { iconSize = QSize(toolButton->iconSize()); } else { iconSize = QSize(16, 16); } // This must be a QImage, as drawing to a QPixmap outside the // UI thread will cause sporadic crashes. QImage pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied); pm.fill(Qt::transparent); QPainter p(&pm); QSharedPointer gradientBackground = qSharedPointerDynamicCast(d->background); QSharedPointer patternBackground = qSharedPointerDynamicCast(d->background); if (gradientBackground) { QRect innerRect(0, 0, iconSize.width(), iconSize.height()); QLinearGradient paintGradient; paintGradient.setStops(gradientBackground->gradient()->stops()); paintGradient.setStart(innerRect.topLeft()); paintGradient.setFinalStop(innerRect.topRight()); d->checkerPainter.paint(p, innerRect); p.fillRect(innerRect, QBrush(paintGradient)); } else if (patternBackground) { d->checkerPainter.paint(p, QRect(QPoint(),iconSize)); p.fillRect(0, 0, iconSize.width(), iconSize.height(), patternBackground->pattern()); } p.end(); setIcon(QIcon(QPixmap::fromImage(pm))); } diff --git a/libs/widgets/kis_file_name_requester.cpp b/libs/widgets/kis_file_name_requester.cpp index 66eb12283d..10996e845e 100644 --- a/libs/widgets/kis_file_name_requester.cpp +++ b/libs/widgets/kis_file_name_requester.cpp @@ -1,101 +1,100 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_file_name_requester.h" #include "ui_wdg_file_name_requester.h" #include #include "KoIcon.h" KisFileNameRequester::KisFileNameRequester(QWidget *parent) : QWidget(parent) , m_ui(new Ui::WdgFileNameRequester) , m_mode(KoFileDialog::OpenFile) { m_ui->setupUi(this); m_ui->btnSelectFile->setIcon(kisIcon("folder")); connect(m_ui->btnSelectFile, SIGNAL(clicked()), SLOT(slotSelectFile())); connect(m_ui->txtFileName, SIGNAL(textChanged(const QString&)), SIGNAL(textChanged(const QString&))); } KisFileNameRequester::~KisFileNameRequester() { } void KisFileNameRequester::setStartDir(const QString &path) { m_basePath = path; } void KisFileNameRequester::setFileName(const QString &path) { QString realPath = path; if (!m_basePath.isEmpty()) { QDir d(m_basePath); realPath = d.relativeFilePath(path); } m_ui->txtFileName->setText(realPath); emit fileSelected(realPath); } QString KisFileNameRequester::fileName() const { return m_ui->txtFileName->text(); } void KisFileNameRequester::setMode(KoFileDialog::DialogType mode) { m_mode = mode; } KoFileDialog::DialogType KisFileNameRequester::mode() const { return m_mode; } void KisFileNameRequester::setMimeTypeFilters(const QStringList &filterList, - QString defaultFilter) + QString defaultFilter) { m_mime_filter_list = filterList; m_mime_default_filter = defaultFilter; } void KisFileNameRequester::slotSelectFile() { KoFileDialog dialog(this, m_mode, "OpenDocument"); if (m_mode == KoFileDialog::OpenFile) { dialog.setCaption(i18n("Select a file to load...")); } else if (m_mode == KoFileDialog::OpenDirectory) { dialog.setCaption(i18n("Select a directory to load...")); } - dialog.setDefaultDir(m_basePath.isEmpty() ? QDesktopServices::storageLocation(QDesktopServices::PicturesLocation) : m_basePath); Q_ASSERT(!m_mime_filter_list.isEmpty()); dialog.setMimeTypeFilters(m_mime_filter_list, m_mime_default_filter); setFileName(dialog.filename()); } diff --git a/libs/widgets/kis_file_name_requester.h b/libs/widgets/kis_file_name_requester.h index 29bb673a05..748a4908d7 100644 --- a/libs/widgets/kis_file_name_requester.h +++ b/libs/widgets/kis_file_name_requester.h @@ -1,81 +1,80 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_FILE_NAME_REQUESTER_H #define KIS_FILE_NAME_REQUESTER_H #include "kritawidgets_export.h" #include #include #include #include namespace Ui { class WdgFileNameRequester; } /** * This represents an editable file name. * Visual it presents a QLineEdit + a buton that pops up * a file chooser. * * Signals are fired when the user changes the text * or selects a new file via the button/file chooser. */ class KRITAWIDGETS_EXPORT KisFileNameRequester : public QWidget { Q_OBJECT public: explicit KisFileNameRequester(QWidget *parent = 0); ~KisFileNameRequester(); void setStartDir(const QString &path); QString fileName() const; void setFileName(const QString &path); void setMode(KoFileDialog::DialogType mode); KoFileDialog::DialogType mode() const; /** * Sets the mime type filters to use, same format as KoFileDialog::setMimeTypeFilters. * If this is not called, the default list is used, which simply selects all the image * file formats Krita can load. */ - void setMimeTypeFilters(const QStringList &filterList, - QString defaultFilter = QString()); + void setMimeTypeFilters(const QStringList &filterList, QString defaultFilter = QString()); public Q_SLOTS: void slotSelectFile(); Q_SIGNALS: void textChanged(const QString &fileName); void fileSelected(const QString &fileName); private: QScopedPointer m_ui; QString m_basePath; KoFileDialog::DialogType m_mode; QStringList m_mime_filter_list; QString m_mime_default_filter; }; #endif // KIS_FILE_NAME_REQUESTER_H diff --git a/packaging/linux/appimage/build-deps.sh b/packaging/linux/appimage/build-deps.sh index c263cc4e1d..8b3e9c4c3c 100644 --- a/packaging/linux/appimage/build-deps.sh +++ b/packaging/linux/appimage/build-deps.sh @@ -1,122 +1,122 @@ #!/bin/bash # Enter a CentOS 6 chroot (you could use other methods) # git clone https://github.com/probonopd/AppImageKit.git # ./AppImageKit/build.sh # sudo ./AppImageKit/AppImageAssistant.AppDir/testappimage /isodevice/boot/iso/CentOS-6.5-x86_64-LiveCD.iso bash # Halt on errors set -e # Be verbose set -x # Now we are inside CentOS 6 grep -r "CentOS release 6" /etc/redhat-release || exit 1 # qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. That's # not always set correctly in CentOS 6.7 export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # Determine which architecture should be built if [[ "$(arch)" = "i686" || "$(arch)" = "x86_64" ]] ; then ARCH=$(arch) else echo "Architecture could not be determined" exit 1 fi # if the library path doesn't point to our usr/lib, linking will be broken and we won't find all deps either export LD_LIBRARY_PATH=/usr/lib64/:/usr/lib:/krita.appdir/usr/lib git_pull_rebase_helper() { git reset --hard HEAD git pull } yum -y install epel-release # we need to be up to date in order to install the xcb-keysyms dependency yum -y update # base dependencies and Qt5. -yum -y install wget tar bzip2 git libtool which fuse fuse-devel libpng-devel automake libtool mesa-libEGL cppunit-devel cmake3 glibc-headers libstdc++-devel gcc-c++ freetype-devel fontconfig-devel libxml2-devel libstdc++-devel libXrender-devel patch xcb-util-keysyms-devel libXi-devel mesa-libGL-devel libxcb libxcb-devel xcb-util xcb-util-devel +yum -y install wget tar bzip2 git libtool which fuse fuse-devel libpng-devel automake libtool mesa-libEGL cppunit-devel cmake3 glibc-headers libstdc++-devel gcc-c++ freetype-devel fontconfig-devel libxml2-devel libstdc++-devel libXrender-devel patch xcb-util-keysyms-devel libXi-devel mesa-libGL-devel mesa-libGLU-devel libxcb libxcb-devel xcb-util xcb-util-devel # Newer compiler than what comes with CentOS 6 yum -y install centos-release-scl-rh yum -y install devtoolset-3-gcc devtoolset-3-gcc-c++ . /opt/rh/devtoolset-3/enable # Make sure we build from the /, parts of this script depends on that. We also need to run as root... cd / # Build AppImageKit if [ ! -d AppImageKit ] ; then git clone --depth 1 https://github.com/probonopd/AppImageKit.git /AppImageKit fi cd /AppImageKit/ git_pull_rebase_helper ./build.sh cd / # Workaround for: On CentOS 6, .pc files in /usr/lib/pkgconfig are not recognized # However, this is where .pc files get installed when bulding libraries... (FIXME) # I found this by comparing the output of librevenge's "make install" command # between Ubuntu and CentOS 6 ln -sf /usr/share/pkgconfig /usr/lib/pkgconfig # A krita build layout looks like this: # krita/ -- the source directory # krita/3rdparty -- the cmake3 definitions for the dependencies # d -- downloads of the dependencies from files.kde.org # b -- build directory for the dependencies # krita_build -- build directory for krita itself # krita.appdir -- install directory for krita and the dependencies # Get Krita if [ ! -d /krita ] ; then git clone --depth 1 https://github.com/KDE/krita.git /krita fi cd /krita/ git_pull_rebase_helper # Create the build dir for the 3rdparty deps if [ ! -d /b ] ; then mkdir /b fi if [ ! -d /d ] ; then mkdir /d fi # start building the deps cd /b rm -rf /b/* || true cmake3 /krita/3rdparty \ -DCMAKE_INSTALL_PREFIX:PATH=/usr \ -DINSTALL_ROOT=/usr \ -DEXTERNALS_DOWNLOAD_DIR=/d cmake3 --build . --config RelWithDebInfo --target ext_qt cmake3 --build . --config RelWithDebInfo --target ext_boost cmake3 --build . --config RelWithDebInfo --target ext_eigen3 cmake3 --build . --config RelWithDebInfo --target ext_exiv2 cmake3 --build . --config RelWithDebInfo --target ext_fftw3 cmake3 --build . --config RelWithDebInfo --target ext_lcms2 cmake3 --build . --config RelWithDebInfo --target ext_ocio cmake3 --build . --config RelWithDebInfo --target ext_openexr cmake3 --build . --config RelWithDebInfo --target ext_vc #cmake3 --build . --config RelWithDebInfo --target ext_png cmake3 --build . --config RelWithDebInfo --target ext_tiff cmake3 --build . --config RelWithDebInfo --target ext_jpeg cmake3 --build . --config RelWithDebInfo --target ext_libraw cmake3 --build . --config RelWithDebInfo --target ext_kcrash cmake3 --build . --config RelWithDebInfo --target ext_poppler cmake3 --build . --config RelWithDebInfo --target ext_gsl diff --git a/packaging/linux/appimage/build-image.sh b/packaging/linux/appimage/build-image.sh index fd53c7d0e7..1940f18e69 100644 --- a/packaging/linux/appimage/build-image.sh +++ b/packaging/linux/appimage/build-image.sh @@ -1,255 +1,255 @@ #!/bin/bash # Enter a CentOS 6 chroot (you could use other methods) # git clone https://github.com/probonopd/AppImageKit.git # ./AppImageKit/build.sh # sudo ./AppImageKit/AppImageAssistant.AppDir/testappimage /isodevice/boot/iso/CentOS-6.5-x86_64-LiveCD.iso bash # Halt on errors set -e # Be verbose set -x # Now we are inside CentOS 6 grep -r "CentOS release 6" /etc/redhat-release || exit 1 # If we are running inside Travis CI, then we want to build Krita # and we remove the $DO_NOT_BUILD_KRITA environment variable # that was used in the process of generating the Docker image. # Also we do not want to download and build the dependencies every # time we build Krita on travis in the docker image. In order to # use newer dependencies, we re-build the docker image instead. #unset DO_NOT_BUILD_KRITA #NO_DOWNLOAD=1 # clean up rm -f krita-3.0-l10n-win-current.tar.gz rm -rf /out/* rm -rf /krita.appdir # qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. That's # not always set correctly in CentOS 6.7 export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # Determine which architecture should be built if [[ "$(arch)" = "i686" || "$(arch)" = "x86_64" ]] ; then ARCH=$(arch) else echo "Architecture could not be determined" exit 1 fi # if the library path doesn't point to our usr/lib, linking will be broken and we won't find all deps either export LD_LIBRARY_PATH=/usr/lib64/:/usr/lib:/krita.appdir/usr/lib cd / # Prepare the install location rm -rf /krita.appdir/ || true mkdir -p /krita.appdir/usr/bin # make sure lib and lib64 are the same thing mkdir -p /krita.appdir/usr/lib cd /krita.appdir/usr ln -s lib lib64 cd /krita_build make -j4 install cd /krita.appdir # FIXME: How to find out which subset of plugins is really needed? I used strace when running the binary cp -r /usr/plugins ./usr/bin/ # copy the Qt translation cp -r /usr/translations ./usr cp $(ldconfig -p | grep libsasl2.so.2 | cut -d ">" -f 2 | xargs) ./usr/lib/ cp $(ldconfig -p | grep libGL.so.1 | cut -d ">" -f 2 | xargs) ./usr/lib/ # otherwise segfaults!? cp $(ldconfig -p | grep libGLU.so.1 | cut -d ">" -f 2 | xargs) ./usr/lib/ # otherwise segfaults!? # Fedora 23 seemed to be missing SOMETHING from the Centos 6.7. The only message was: # This application failed to start because it could not find or load the Qt platform plugin "xcb". # Setting export QT_DEBUG_PLUGINS=1 revealed the cause. # QLibraryPrivate::loadPlugin failed on "/usr/lib64/qt5/plugins/platforms/libqxcb.so" : # "Cannot load library /usr/lib64/qt5/plugins/platforms/libqxcb.so: (/lib64/libEGL.so.1: undefined symbol: drmGetNodeTypeFromFd)" # Which means that we have to copy libEGL.so.1 in too cp $(ldconfig -p | grep libEGL.so.1 | cut -d ">" -f 2 | xargs) ./usr/lib/ # Otherwise F23 cannot load the Qt platform plugin "xcb" # let's not copy xcb itself, that breaks on dri3 systems https://bugs.kde.org/show_bug.cgi?id=360552 #cp $(ldconfig -p | grep libxcb.so.1 | cut -d ">" -f 2 | xargs) ./usr/lib/ cp $(ldconfig -p | grep libfreetype.so.6 | cut -d ">" -f 2 | xargs) ./usr/lib/ # For Fedora 20 ldd usr/bin/krita | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./usr/lib || true #ldd usr/lib64/krita/*.so | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./usr/lib || true #ldd usr/lib64/plugins/imageformats/*.so | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./usr/lib || true ldd usr/bin/plugins/platforms/libqxcb.so | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ./usr/lib || true # Copy in the indirect dependencies FILES=$(find . -type f -executable) for FILE in $FILES ; do ldd "${FILE}" | grep "=>" | awk '{print $3}' | xargs -I '{}' cp -v '{}' usr/lib || true done #DEPS="" #for FILE in $FILES ; do # ldd "${FILE}" | grep "=>" | awk '{print $3}' | xargs -I '{}' echo '{}' > DEPSFILE #done #DEPS=$(cat DEPSFILE |sort | uniq) #for FILE in $DEPS ; do # if [ -f $FILE ] ; then # echo $FILE # cp --parents -rfL $FILE ./ # fi #done #rm -f DEPSFILE # The following are assumed to be part of the base system rm -f usr/lib/libcom_err.so.2 || true rm -f usr/lib/libcrypt.so.1 || true rm -f usr/lib/libdl.so.2 || true rm -f usr/lib/libexpat.so.1 || true #rm -f usr/lib/libfontconfig.so.1 || true rm -f usr/lib/libgcc_s.so.1 || true rm -f usr/lib/libglib-2.0.so.0 || true rm -f usr/lib/libgpg-error.so.0 || true rm -f usr/lib/libgssapi_krb5.so.2 || true rm -f usr/lib/libgssapi.so.3 || true rm -f usr/lib/libhcrypto.so.4 || true rm -f usr/lib/libheimbase.so.1 || true rm -f usr/lib/libheimntlm.so.0 || true rm -f usr/lib/libhx509.so.5 || true rm -f usr/lib/libICE.so.6 || true rm -f usr/lib/libidn.so.11 || true rm -f usr/lib/libk5crypto.so.3 || true rm -f usr/lib/libkeyutils.so.1 || true rm -f usr/lib/libkrb5.so.26 || true rm -f usr/lib/libkrb5.so.3 || true rm -f usr/lib/libkrb5support.so.0 || true # rm -f usr/lib/liblber-2.4.so.2 || true # needed for debian wheezy # rm -f usr/lib/libldap_r-2.4.so.2 || true # needed for debian wheezy rm -f usr/lib/libm.so.6 || true rm -f usr/lib/libp11-kit.so.0 || true rm -f usr/lib/libpcre.so.3 || true rm -f usr/lib/libpthread.so.0 || true rm -f usr/lib/libresolv.so.2 || true rm -f usr/lib/libroken.so.18 || true rm -f usr/lib/librt.so.1 || true rm -f usr/lib/libsasl2.so.2 || true rm -f usr/lib/libSM.so.6 || true rm -f usr/lib/libusb-1.0.so.0 || true rm -f usr/lib/libuuid.so.1 || true rm -f usr/lib/libwind.so.0 || true rm -f usr/lib/libfontconfig.so.* || true # Remove these libraries, we need to use the system versions; this means 11.04 is not supported (12.04 is our baseline) rm -f usr/lib/libGL.so.* || true rm -f usr/lib/libdrm.so.* || true rm -f usr/lib/libX11.so.* || true #rm -f usr/lib/libz.so.1 || true # These seem to be available on most systems but not Ubuntu 11.04 # rm -f usr/lib/libffi.so.6 usr/lib/libGL.so.1 usr/lib/libglapi.so.0 usr/lib/libxcb.so.1 usr/lib/libxcb-glx.so.0 || true # Delete potentially dangerous libraries rm -f usr/lib/libstdc* usr/lib/libgobject* usr/lib/libc.so.* || true rm -f usr/lib/libxcb.so.1 # Do NOT delete libX* because otherwise on Ubuntu 11.04: # loaded library "Xcursor" malloc.c:3096: sYSMALLOc: Assertion (...) Aborted # We don't bundle the developer stuff rm -rf usr/include || true rm -rf usr/lib/cmake3 || true rm -rf usr/lib/pkgconfig || true rm -rf usr/share/ECM/ || true rm -rf usr/share/gettext || true rm -rf usr/share/pkgconfig || true strip usr/lib/kritaplugins/* usr/bin/* usr/lib/* || true # Since we set /krita.appdir as the prefix, we need to patch it away too (FIXME) # Probably it would be better to use /app as a prefix because it has the same length for all apps cd usr/ ; find . -type f -exec sed -i -e 's|/krita.appdir/usr/|./././././././././|g' {} \; ; cd .. # On openSUSE Qt is picking up the wrong libqxcb.so # (the one from the system when in fact it should use the bundled one) - is this a Qt bug? # Also, Krita has a hardcoded /usr which we patch away cd usr/ ; find . -type f -exec sed -i -e 's|/usr|././|g' {} \; ; cd .. # We do not bundle this, so let's not search that inside the AppImage. # Fixes "Qt: Failed to create XKB context!" and lets us enter text sed -i -e 's|././/share/X11/|/usr/share/X11/|g' ./usr/bin/plugins/platforminputcontexts/libcomposeplatforminputcontextplugin.so sed -i -e 's|././/share/X11/|/usr/share/X11/|g' ./usr/lib/libQt5XcbQpa.so.5 # Workaround for: # D-Bus library appears to be incorrectly set up; # failed to read machine uuid: Failed to open # The file is more commonly in /etc/machine-id # sed -i -e 's|/var/lib/dbus/machine-id|//././././etc/machine-id|g' ./usr/lib/libdbus-1.so.3 # or rm -f ./usr/lib/libdbus-1.so.3 || true cp ../AppImageKit/AppRun . cp ./usr/share/applications/org.kde.krita.desktop krita.desktop cp /krita/krita/pics/app/64-apps-calligrakrita.png calligrakrita.png # # Fetch and install the translations # cd / rm -f krita-3.0-l10-win-current.tar.gz || true wget http://files.kde.org/krita/build/krita-3.0-l10n-win-current.tar.gz tar -xf krita-3.0-l10n-win-current.tar.gz cd /krita.appdir/usr/share tar -xf /krita-3.0-l10n-win-current.tar.gz # replace krita with the lib-checking startup script. #cd /krita.appdir/usr/bin #mv krita krita.real #wget https://raw.githubusercontent.com/boudewijnrempt/AppImages/master/recipes/krita/krita #chmod a+rx krita cd / APP=krita # Source functions wget -q https://github.com/probonopd/AppImages/raw/master/functions.sh -O ./functions.sh . ./functions.sh # Install desktopintegration in usr/bin/krita.wrapper -- feel free to edit it cd /krita.appdir get_desktopintegration krita cd / VER=$(grep "#define KRITA_VERSION_STRING" krita_build/libs/version/kritaversion.h | cut -d '"' -f 2) cd /krita REVISION=$(git rev-parse --short HEAD) cd .. VERSION=$VER-$REVISION VERSION="$(sed s/\ /-/g <<<$VERSION)" echo $VERSION if [[ "$ARCH" = "x86_64" ]] ; then APPIMAGE=$APP"-"$VERSION"-x86_64.appimage" fi if [[ "$ARCH" = "i686" ]] ; then APPIMAGE=$APP"-"$VERSION"-i386.appimage" fi echo $APPIMAGE mkdir -p /out rm -f /out/*.AppImage || true AppImageKit/AppImageAssistant.AppDir/package /krita.appdir/ /out/$APPIMAGE chmod a+rwx /out/$APPIMAGE # So that we can edit the AppImage outside of the Docker container cd /krita.appdir mv AppRun krita cd / -mv krita.appdir $APP"-"$VERSION"-x86_64 -tar -czf $APP"-"$VERSION"-x86_64.tgz $APP"-"$VERSION"-x86_64 +mv krita.appdir "$APP"-"$VERSION"-x86_64 +tar -czf "$APP"-"$VERSION"-x86_64.tgz "$APP"-"$VERSION"-x86_64 diff --git a/plugins/dockers/lut/lutdocker_dock.cpp b/plugins/dockers/lut/lutdocker_dock.cpp index 6ca0ae40d2..51e7362b2a 100644 --- a/plugins/dockers/lut/lutdocker_dock.cpp +++ b/plugins/dockers/lut/lutdocker_dock.cpp @@ -1,593 +1,596 @@ /* * Copyright (c) 2004 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 "lutdocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_icon_utils.h" #include #include #include #include #include #include #include #include #include "widgets/squeezedcombobox.h" #include "kis_signals_blocker.h" #include "krita_utils.h" #include "ocio_display_filter.h" #include "black_white_point_chooser.h" OCIO::ConstConfigRcPtr defaultRawProfile() { /** * Copied from OCIO, just a noop profile */ const char * INTERNAL_RAW_PROFILE = "ocio_profile_version: 1\n" "strictparsing: false\n" "roles:\n" " default: raw\n" "displays:\n" " sRGB:\n" " - ! {name: Raw, colorspace: raw}\n" "colorspaces:\n" " - !\n" " name: raw\n" " family: raw\n" " equalitygroup:\n" " bitdepth: 32f\n" " isdata: true\n" " allocation: uniform\n" " description: 'A raw color space. Conversions to and from this space are no-ops.'\n"; std::istringstream istream; istream.str(INTERNAL_RAW_PROFILE); return OCIO::Config::CreateFromStream(istream); } LutDockerDock::LutDockerDock() : QDockWidget(i18n("LUT Management")) , m_canvas(0) , m_draggingSlider(false) , m_ownDisplayFilter(false) { using namespace std::placeholders; // For _1 m_exposureCompressor.reset( new KisSignalCompressorWithParam(40, std::bind(&LutDockerDock::setCurrentExposureImpl, this, _1))); m_gammaCompressor.reset( new KisSignalCompressorWithParam(40, std::bind(&LutDockerDock::setCurrentGammaImpl, this, _1))); m_page = new QWidget(this); setupUi(m_page); setWidget(m_page); KisConfig cfg; m_chkUseOcio->setChecked(cfg.useOcio()); connect(m_chkUseOcio, SIGNAL(toggled(bool)), SLOT(updateDisplaySettings())); connect(m_colorManagement, SIGNAL(currentIndexChanged(int)), SLOT(slotColorManagementModeChanged())); m_txtConfigurationPath->setText(cfg.ocioConfigurationPath()); m_bnSelectConfigurationFile->setToolTip(i18n("Select custom configuration file.")); connect(m_bnSelectConfigurationFile,SIGNAL(clicked()), SLOT(selectOcioConfiguration())); m_txtLut->setText(cfg.ocioLutPath()); m_bnSelectLut->setToolTip(i18n("Select LUT file")); connect(m_bnSelectLut, SIGNAL(clicked()), SLOT(selectLut())); connect(m_bnClearLut, SIGNAL(clicked()), SLOT(clearLut())); // See http://groups.google.com/group/ocio-dev/browse_thread/thread/ec95c5f54a74af65 -- maybe need to be reinstated // when people ask for it. m_lblLut->hide(); m_txtLut->hide(); m_bnSelectLut->hide(); m_bnClearLut->hide(); connect(m_cmbDisplayDevice, SIGNAL(currentIndexChanged(int)), SLOT(refillViewCombobox())); m_exposureDoubleWidget->setToolTip(i18n("Select the exposure (stops) for HDR images.")); m_exposureDoubleWidget->setRange(-10, 10); m_exposureDoubleWidget->setPrecision(1); m_exposureDoubleWidget->setValue(0.0); m_exposureDoubleWidget->setSingleStep(0.25); m_exposureDoubleWidget->setPageStep(1); connect(m_exposureDoubleWidget, SIGNAL(valueChanged(double)), SLOT(exposureValueChanged(double))); connect(m_exposureDoubleWidget, SIGNAL(sliderPressed()), SLOT(exposureSliderPressed())); connect(m_exposureDoubleWidget, SIGNAL(sliderReleased()), SLOT(exposureSliderReleased())); // Gamma needs to be exponential (gamma *= 1.1f, gamma /= 1.1f as steps) m_gammaDoubleWidget->setToolTip(i18n("Select the amount of gamma modification for display. This does not affect the pixels of your image.")); m_gammaDoubleWidget->setRange(0.1, 5); m_gammaDoubleWidget->setPrecision(2); m_gammaDoubleWidget->setValue(1.0); m_gammaDoubleWidget->setSingleStep(0.1); m_gammaDoubleWidget->setPageStep(1); connect(m_gammaDoubleWidget, SIGNAL(valueChanged(double)), SLOT(gammaValueChanged(double))); connect(m_gammaDoubleWidget, SIGNAL(sliderPressed()), SLOT(gammaSliderPressed())); connect(m_gammaDoubleWidget, SIGNAL(sliderReleased()), SLOT(gammaSliderReleased())); m_bwPointChooser = new BlackWhitePointChooser(this); connect(m_bwPointChooser, SIGNAL(sigBlackPointChanged(qreal)), SLOT(updateDisplaySettings())); connect(m_bwPointChooser, SIGNAL(sigWhitePointChanged(qreal)), SLOT(updateDisplaySettings())); connect(m_btnConvertCurrentColor, SIGNAL(toggled(bool)), SLOT(updateDisplaySettings())); connect(m_btmShowBWConfiguration, SIGNAL(clicked()), SLOT(slotShowBWConfiguration())); slotUpdateIcons(); connect(m_cmbInputColorSpace, SIGNAL(currentIndexChanged(int)), SLOT(updateDisplaySettings())); connect(m_cmbDisplayDevice, SIGNAL(currentIndexChanged(int)), SLOT(updateDisplaySettings())); connect(m_cmbView, SIGNAL(currentIndexChanged(int)), SLOT(updateDisplaySettings())); connect(m_cmbLook, SIGNAL(currentIndexChanged(int)), SLOT(updateDisplaySettings())); connect(m_cmbComponents, SIGNAL(currentIndexChanged(int)), SLOT(updateDisplaySettings())); m_draggingSlider = false; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetOcioConfiguration())); m_displayFilter = 0; resetOcioConfiguration(); } LutDockerDock::~LutDockerDock() { if(m_ownDisplayFilter) delete m_displayFilter; } void LutDockerDock::setCanvas(KoCanvasBase* _canvas) { if (m_canvas) { m_canvas->disconnect(this); + if (m_ownDisplayFilter) { + delete m_displayFilter; + } m_displayFilter = 0; } setEnabled(_canvas != 0); if (KisCanvas2* canvas = dynamic_cast(_canvas)) { m_canvas = canvas; if (m_canvas) { if (!m_canvas->displayFilter()) { m_displayFilter = new OcioDisplayFilter(this); m_ownDisplayFilter = true; resetOcioConfiguration(); updateDisplaySettings(); } else { m_displayFilter = dynamic_cast(m_canvas->displayFilter()); Q_ASSERT(m_displayFilter); m_ocioConfig = m_displayFilter->config; KisSignalsBlocker exposureBlocker(m_exposureDoubleWidget); m_exposureDoubleWidget->setValue(m_displayFilter->exposure); KisSignalsBlocker gammaBlocker(m_gammaDoubleWidget); m_gammaDoubleWidget->setValue(m_displayFilter->gamma); KisSignalsBlocker componentsBlocker(m_cmbComponents); m_cmbComponents->setCurrentIndex((int)m_displayFilter->swizzle); KisSignalsBlocker bwBlocker(m_bwPointChooser); m_bwPointChooser->setBlackPoint(m_displayFilter->blackPoint); m_bwPointChooser->setWhitePoint(m_displayFilter->whitePoint); } connect(m_canvas->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), SLOT(slotImageColorSpaceChanged()), Qt::UniqueConnection); connect(m_canvas->viewManager()->mainWindow(), SIGNAL(themeChanged()), SLOT(slotUpdateIcons()), Qt::UniqueConnection); } } } void LutDockerDock::slotUpdateIcons() { m_btnConvertCurrentColor->setIcon(KisIconUtils::loadIcon("krita_tool_freehand")); m_btmShowBWConfiguration->setIcon(KisIconUtils::loadIcon("properties")); } void LutDockerDock::slotShowBWConfiguration() { m_bwPointChooser->showPopup(m_btmShowBWConfiguration->mapToGlobal(QPoint())); } bool LutDockerDock::canChangeExposureAndGamma() const { return m_chkUseOcio->isChecked() && m_ocioConfig; } qreal LutDockerDock::currentExposure() const { if (!m_displayFilter) return 0.0; return canChangeExposureAndGamma() ? m_displayFilter->exposure : 0.0; } void LutDockerDock::setCurrentExposure(qreal value) { if (!canChangeExposureAndGamma()) return; m_exposureCompressor->start(value); } qreal LutDockerDock::currentGamma() const { if (!m_displayFilter) return 1.0; return canChangeExposureAndGamma() ? m_displayFilter->gamma : 1.0; } void LutDockerDock::setCurrentGamma(qreal value) { if (!canChangeExposureAndGamma()) return; m_gammaCompressor->start(value); } void LutDockerDock::setCurrentExposureImpl(qreal value) { m_exposureDoubleWidget->setValue(value); if (!m_canvas) return; m_canvas->viewManager()->showFloatingMessage( i18nc("floating message about exposure", "Exposure: %1", KritaUtils::prettyFormatReal(m_exposureDoubleWidget->value())), QIcon(), 500, KisFloatingMessage::Low); } void LutDockerDock::setCurrentGammaImpl(qreal value) { m_gammaDoubleWidget->setValue(value); if (!m_canvas) return; m_canvas->viewManager()->showFloatingMessage( i18nc("floating message about gamma", "Gamma: %1", KritaUtils::prettyFormatReal(m_gammaDoubleWidget->value())), QIcon(), 500, KisFloatingMessage::Low); } void LutDockerDock::slotImageColorSpaceChanged() { enableControls(); writeControls(); resetOcioConfiguration(); } void LutDockerDock::exposureValueChanged(double exposure) { if (m_canvas && !m_draggingSlider) { m_canvas->viewManager()->resourceProvider()->setHDRExposure(exposure); updateDisplaySettings(); } } void LutDockerDock::exposureSliderPressed() { m_draggingSlider = true; } void LutDockerDock::exposureSliderReleased() { m_draggingSlider = false; exposureValueChanged(m_exposureDoubleWidget->value()); } void LutDockerDock::gammaValueChanged(double gamma) { if (m_canvas && !m_draggingSlider) { m_canvas->viewManager()->resourceProvider()->setHDRGamma(gamma); updateDisplaySettings(); } } void LutDockerDock::gammaSliderPressed() { m_draggingSlider = true; } void LutDockerDock::gammaSliderReleased() { m_draggingSlider = false; gammaValueChanged(m_gammaDoubleWidget->value()); } void LutDockerDock::enableControls() { bool canDoExternalColorCorrection = false; if (m_canvas) { KisImageSP image = m_canvas->viewManager()->image(); canDoExternalColorCorrection = image->colorSpace()->colorModelId() == RGBAColorModelID; } if (!canDoExternalColorCorrection) { KisSignalsBlocker colorManagementBlocker(m_colorManagement); Q_UNUSED(colorManagementBlocker); m_colorManagement->setCurrentIndex((int) KisConfig::INTERNAL); } bool ocioEnabled = m_chkUseOcio->isChecked(); m_colorManagement->setEnabled(ocioEnabled && canDoExternalColorCorrection); bool externalColorManagementEnabled = m_colorManagement->currentIndex() != (int)KisConfig::INTERNAL; m_lblInputColorSpace->setEnabled(ocioEnabled && externalColorManagementEnabled); m_cmbInputColorSpace->setEnabled(ocioEnabled && externalColorManagementEnabled); m_lblDisplayDevice->setEnabled(ocioEnabled && externalColorManagementEnabled); m_cmbDisplayDevice->setEnabled(ocioEnabled && externalColorManagementEnabled); m_lblView->setEnabled(ocioEnabled && externalColorManagementEnabled); m_cmbView->setEnabled(ocioEnabled && externalColorManagementEnabled); m_lblLook->setEnabled(ocioEnabled && externalColorManagementEnabled); m_cmbLook->setEnabled(ocioEnabled && externalColorManagementEnabled); bool enableConfigPath = m_colorManagement->currentIndex() == (int) KisConfig::OCIO_CONFIG; lblConfig->setEnabled(ocioEnabled && enableConfigPath); m_txtConfigurationPath->setEnabled(ocioEnabled && enableConfigPath); m_bnSelectConfigurationFile->setEnabled(ocioEnabled && enableConfigPath); } void LutDockerDock::updateDisplaySettings() { if (!m_canvas || !m_canvas->viewManager() || !m_canvas->viewManager()->image()) { return; } enableControls(); writeControls(); if (m_chkUseOcio->isChecked() && m_ocioConfig) { m_displayFilter->config = m_ocioConfig; m_displayFilter->inputColorSpaceName = m_ocioConfig->getColorSpaceNameByIndex(m_cmbInputColorSpace->currentIndex()); m_displayFilter->displayDevice = m_ocioConfig->getDisplay(m_cmbDisplayDevice->currentIndex()); m_displayFilter->view = m_ocioConfig->getView(m_displayFilter->displayDevice, m_cmbView->currentIndex()); m_displayFilter->look = m_ocioConfig->getLookNameByIndex(m_cmbLook->currentIndex()); m_displayFilter->gamma = m_gammaDoubleWidget->value(); m_displayFilter->exposure = m_exposureDoubleWidget->value(); m_displayFilter->swizzle = (OCIO_CHANNEL_SWIZZLE)m_cmbComponents->currentIndex(); m_displayFilter->blackPoint = m_bwPointChooser->blackPoint(); m_displayFilter->whitePoint = m_bwPointChooser->whitePoint(); m_displayFilter->forceInternalColorManagement = m_colorManagement->currentIndex() == (int)KisConfig::INTERNAL; m_displayFilter->setLockCurrentColorVisualRepresentation(m_btnConvertCurrentColor->isChecked()); m_displayFilter->updateProcessor(); m_canvas->setDisplayFilter(m_displayFilter); } else { m_canvas->setDisplayFilter(0); } m_canvas->updateCanvas(); } void LutDockerDock::writeControls() { KisConfig cfg; cfg.setUseOcio(m_chkUseOcio->isChecked()); cfg.setOcioColorManagementMode((KisConfig::OcioColorManagementMode) m_colorManagement->currentIndex()); cfg.setOcioLockColorVisualRepresentation(m_btnConvertCurrentColor->isChecked()); } void LutDockerDock::slotColorManagementModeChanged() { enableControls(); writeControls(); resetOcioConfiguration(); } void LutDockerDock::selectOcioConfiguration() { QString filename = m_txtConfigurationPath->text(); KoFileDialog dialog(this, KoFileDialog::OpenFile, "lutdocker"); dialog.setCaption(i18n("Select OpenColorIO Configuration")); dialog.setDefaultDir(QDir::cleanPath(filename)); dialog.setMimeTypeFilters(QStringList() << "application/x-opencolorio-configuration"); filename = dialog.filename(); QFile f(filename); if (f.exists()) { m_txtConfigurationPath->setText(filename); KisConfig cfg; cfg.setOcioConfigurationPath(filename); writeControls(); resetOcioConfiguration(); } } void LutDockerDock::resetOcioConfiguration() { m_ocioConfig.reset(); KisConfig cfg; try { if (cfg.ocioColorManagementMode() == KisConfig::INTERNAL) { m_ocioConfig = defaultRawProfile(); } else if (cfg.ocioColorManagementMode() == KisConfig::OCIO_ENVIRONMENT) { m_ocioConfig = OCIO::Config::CreateFromEnv(); } else if (cfg.ocioColorManagementMode() == KisConfig::OCIO_CONFIG) { QString configFile = cfg.ocioConfigurationPath(); if (QFile::exists(configFile)) { m_ocioConfig = OCIO::Config::CreateFromFile(configFile.toUtf8()); } else { m_ocioConfig = defaultRawProfile(); } } if (m_ocioConfig) { OCIO::SetCurrentConfig(m_ocioConfig); } } catch (OCIO::Exception &exception) { dbgKrita << "OpenColorIO Error:" << exception.what() << "Cannot create the LUT docker"; } if (m_ocioConfig) { refillControls(); } } void LutDockerDock::refillControls() { if (!m_canvas) return; if (!m_canvas->viewManager()) return; if (!m_canvas->viewManager()->resourceProvider()) return; if (!m_canvas->viewManager()->image()) return; KIS_ASSERT_RECOVER_RETURN(m_ocioConfig); { // Color Management Mode KisConfig cfg; KisSignalsBlocker modeBlocker(m_colorManagement); m_colorManagement->setCurrentIndex((int) cfg.ocioColorManagementMode()); } { // Exposure KisSignalsBlocker exposureBlocker(m_exposureDoubleWidget); m_exposureDoubleWidget->setValue(m_canvas->viewManager()->resourceProvider()->HDRExposure()); } { // Gamma KisSignalsBlocker gammaBlocker(m_gammaDoubleWidget); m_gammaDoubleWidget->setValue(m_canvas->viewManager()->resourceProvider()->HDRGamma()); } { // Components const KoColorSpace *cs = m_canvas->viewManager()->image()->colorSpace(); KisSignalsBlocker componentsBlocker(m_cmbComponents); m_cmbComponents->clear(); m_cmbComponents->addSqueezedItem(i18n("Luminance")); m_cmbComponents->addSqueezedItem(i18n("All Channels")); Q_FOREACH (KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(cs->channels())) { m_cmbComponents->addSqueezedItem(channel->name()); } m_cmbComponents->setCurrentIndex(1); // All Channels... } { // Input Color Space KisSignalsBlocker inputCSBlocker(m_cmbInputColorSpace); m_cmbInputColorSpace->clear(); int numOcioColorSpaces = m_ocioConfig->getNumColorSpaces(); for(int i = 0; i < numOcioColorSpaces; ++i) { const char *cs = m_ocioConfig->getColorSpaceNameByIndex(i); OCIO::ConstColorSpaceRcPtr colorSpace = m_ocioConfig->getColorSpace(cs); m_cmbInputColorSpace->addSqueezedItem(QString::fromUtf8(colorSpace->getName())); } } { // Display Device KisSignalsBlocker displayDeviceLocker(m_cmbDisplayDevice); m_cmbDisplayDevice->clear(); int numDisplays = m_ocioConfig->getNumDisplays(); for (int i = 0; i < numDisplays; ++i) { m_cmbDisplayDevice->addSqueezedItem(QString::fromUtf8(m_ocioConfig->getDisplay(i))); } } { // Lock Current Color KisSignalsBlocker locker(m_btnConvertCurrentColor); KisConfig cfg; m_btnConvertCurrentColor->setChecked(cfg.ocioLockColorVisualRepresentation()); } refillViewCombobox(); { KisSignalsBlocker LookComboLocker(m_cmbLook); m_cmbLook->clear(); int numLooks = m_ocioConfig->getNumLooks(); for (int k = 0; k < numLooks; k++) { m_cmbLook->addSqueezedItem(QString::fromUtf8(m_ocioConfig->getLookNameByIndex(k))); } m_cmbLook->addSqueezedItem(i18nc("Item to indicate no look transform being selected","None")); } updateDisplaySettings(); } void LutDockerDock::refillViewCombobox() { KisSignalsBlocker viewComboLocker(m_cmbView); m_cmbView->clear(); if (!m_canvas || !m_ocioConfig) return; const char *display = m_ocioConfig->getDisplay(m_cmbDisplayDevice->currentIndex()); int numViews = m_ocioConfig->getNumViews(display); for (int j = 0; j < numViews; ++j) { m_cmbView->addSqueezedItem(QString::fromUtf8(m_ocioConfig->getView(display, j))); } } void LutDockerDock::selectLut() { QString filename = m_txtLut->text(); KoFileDialog dialog(this, KoFileDialog::OpenFile, "lutdocker"); dialog.setCaption(i18n("Select LUT file")); dialog.setDefaultDir(QDir::cleanPath(filename)); dialog.setMimeTypeFilters(QStringList() << "application/octet-stream", "application/octet-stream"); filename = dialog.filename(); QFile f(filename); if (f.exists() && filename != m_txtLut->text()) { m_txtLut->setText(filename); KisConfig cfg; cfg.setOcioLutPath(filename); updateDisplaySettings(); } } void LutDockerDock::clearLut() { m_txtLut->clear(); updateDisplaySettings(); } diff --git a/plugins/extensions/CMakeLists.txt b/plugins/extensions/CMakeLists.txt index e09bd6e52f..a54f7a5405 100644 --- a/plugins/extensions/CMakeLists.txt +++ b/plugins/extensions/CMakeLists.txt @@ -1,25 +1,26 @@ add_subdirectory( bigbrother ) add_subdirectory( imagesplit ) add_subdirectory( clonesarray ) add_subdirectory( colorrange ) add_subdirectory( colorspaceconversion ) add_subdirectory( histogram ) add_subdirectory( imagesize ) add_subdirectory( metadataeditor ) add_subdirectory( modify_selection ) add_subdirectory( offsetimage ) add_subdirectory( rotateimage ) add_subdirectory( separate_channels ) add_subdirectory( shearimage ) add_subdirectory( layergroupswitcher ) add_subdirectory( resourcemanager ) add_subdirectory( layersplit ) +add_subdirectory( animationrenderer ) add_subdirectory( waveletdecompose ) # Allow to skip building GMIC plugin option(WITH_GMIC "Build the G'Mic plugin" ON) if(WITH_GMIC) if (CMAKE_COMPILER_IS_GNUCC) add_subdirectory( gmic ) endif() endif() diff --git a/plugins/extensions/animationrenderer/AnimationRenderer.cpp b/plugins/extensions/animationrenderer/AnimationRenderer.cpp new file mode 100644 index 0000000000..ec3eb696f9 --- /dev/null +++ b/plugins/extensions/animationrenderer/AnimationRenderer.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "AnimationRenderer.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DlgAnimationRenderer.h" + + +K_PLUGIN_FACTORY_WITH_JSON(AnimaterionRendererFactory, "kritaanimationrenderer.json", registerPlugin();) + +AnimaterionRenderer::AnimaterionRenderer(QObject *parent, const QVariantList &) + : KisViewPlugin(parent) +{ + // Shows the big dialog + KisAction *action = createAction("render_animation"); + action->setActivationFlags(KisAction::IMAGE_HAS_ANIMATION); + connect(action, SIGNAL(triggered()), this, SLOT(slotRenderAnimation())); + + // Re-renders the image sequence as defined in the last render + action = createAction("render_image_sequence_again"); + action->setActivationFlags(KisAction::IMAGE_HAS_ANIMATION); + connect(action, SIGNAL(triggered()), this, SLOT(slotRenderSequenceAgain())); +} + +AnimaterionRenderer::~AnimaterionRenderer() +{ +} + +void AnimaterionRenderer::slotRenderAnimation() +{ + KisImageWSP image = m_view->image(); + + if (!image) return; + if (!image->animationInterface()->hasAnimation()) return; + + KisDocument *doc = m_view->document(); + doc->setFileProgressProxy(); + doc->setFileProgressUpdater(i18n("Export frames")); + + DlgAnimationRenderer dlgAnimationRenderer(doc, m_view->mainWindow()); + + dlgAnimationRenderer.setCaption(i18n("Render Animation")); + + KisConfig kisConfig; + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->fromXML(kisConfig.exportConfiguration("IMAGESEQUENCE")); + // Override the saved start/end with the ones from the image in case of using gui. + cfg->setProperty("first_frame", image->animationInterface()->playbackRange().start()); + cfg->setProperty("last_frame", image->animationInterface()->playbackRange().end()); + dlgAnimationRenderer.setSequenceConfiguration(cfg); + + cfg->clearProperties(); + cfg->fromXML(kisConfig.exportConfiguration("ANIMATION_RENDERER")); + dlgAnimationRenderer.setVideoConfiguration(cfg); + + cfg->clearProperties(); + cfg->fromXML(kisConfig.exportConfiguration("FFMPEG_CONFIG")); + dlgAnimationRenderer.setEncoderConfiguration(cfg); + + + if (dlgAnimationRenderer.exec() == QDialog::Accepted) { + KisPropertiesConfigurationSP sequenceConfig = dlgAnimationRenderer.getSequenceConfiguration(); + kisConfig.setExportConfiguration("IMAGESEQUENCE", *sequenceConfig.data()); + QString mimetype = sequenceConfig->getString("mimetype"); + QString extension = KisMimeDatabase::suffixesForMimeType(mimetype).first(); + QString baseFileName = QString("%1/%2.%3").arg(sequenceConfig->getString("directory")) + .arg(sequenceConfig->getString("basename")) + .arg(extension); + + KisAnimationExportSaver exporter(doc, baseFileName, sequenceConfig->getInt("first_frame"), sequenceConfig->getInt("last_frame"), sequenceConfig->getInt("sequence_start")); + bool success = exporter.exportAnimation(dlgAnimationRenderer.getFrameExportConfiguration()); + Q_ASSERT(success); + QString savedFilesMask = exporter.savedFilesMask(); + + KisPropertiesConfigurationSP videoConfig = dlgAnimationRenderer.getVideoConfiguration(); + if (videoConfig) { + kisConfig.setExportConfiguration("ANIMATION_RENDERER", *videoConfig.data()); + + KisPropertiesConfigurationSP encoderConfig = dlgAnimationRenderer.getEncoderConfiguration(); + if (encoderConfig) { + kisConfig.setExportConfiguration("FFMPEG_CONFIG", *encoderConfig.data()); + encoderConfig->setProperty("savedFilesMask", savedFilesMask); + } + + QSharedPointer encoder = dlgAnimationRenderer.encoderFilter(); + KisFilterChainSP chain(new KisFilterChain(doc->importExportManager())); + chain->setOutputFile(videoConfig->getString("filename")); + encoder->setChain(chain); + KisImportExportFilter::ConversionStatus res = encoder->convert(KisDocument::nativeFormatMimeType(), encoderConfig->getString("mimetype").toLatin1(), encoderConfig); + if (res != KisImportExportFilter::OK) { + QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage())); + } + + if (videoConfig->getBool("delete_sequence", false)) { + QDir d(sequenceConfig->getString("directory")); + QStringList sequenceFiles = d.entryList(QStringList() << sequenceConfig->getString("basename") + "*." + extension, QDir::Files); + Q_FOREACH(const QString &f, sequenceFiles) { + d.remove(f); + } + } + } + } + + doc->clearFileProgressUpdater(); + doc->clearFileProgressProxy(); + +} + +void AnimaterionRenderer::slotRenderSequenceAgain() +{ + KisImageWSP image = m_view->image(); + + if (!image) return; + if (!image->animationInterface()->hasAnimation()) return; + + KisDocument *doc = m_view->document(); + doc->setFileProgressProxy(); + doc->setFileProgressUpdater(i18n("Export frames")); + + KisConfig kisConfig; + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->fromXML(kisConfig.exportConfiguration("IMAGESEQUENCE")); + QString mimetype = cfg->getString("mimetype"); + QString extension = KisMimeDatabase::suffixesForMimeType(mimetype).first(); + QString baseFileName = QString("%1/%2.%3").arg(cfg->getString("directory")) + .arg(cfg->getString("basename")) + .arg(extension); + KisAnimationExportSaver exporter(doc, baseFileName, cfg->getInt("first_frame"), cfg->getInt("last_frame"), cfg->getInt("sequence_start")); + bool success = exporter.exportAnimation(); + Q_ASSERT(success); + + doc->clearFileProgressUpdater(); + doc->clearFileProgressProxy(); + +} + +#include "AnimationRenderer.moc" diff --git a/plugins/impex/video/tests/kis_video_plugin_test.h b/plugins/extensions/animationrenderer/AnimationRenderer.h similarity index 62% rename from plugins/impex/video/tests/kis_video_plugin_test.h rename to plugins/extensions/animationrenderer/AnimationRenderer.h index 8f08f43cbd..7ad80f5b54 100644 --- a/plugins/impex/video/tests/kis_video_plugin_test.h +++ b/plugins/extensions/animationrenderer/AnimationRenderer.h @@ -1,31 +1,39 @@ /* - * Copyright (c) 2016 Dmitry Kazakov + * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _KIS_VIDEO_PLUGIN_TEST_H_ -#define _KIS_VIDEO_PLUGIN_TEST_H_ +#ifndef ANIMATIONRENDERERIMAGE_H +#define ANIMATIONRENDERERIMAGE_H -#include +#include -class KisVideoPluginTest : public QObject +#include + +class AnimaterionRenderer : public KisViewPlugin { Q_OBJECT +public: + AnimaterionRenderer(QObject *parent, const QVariantList &); + virtual ~AnimaterionRenderer(); + private Q_SLOTS: - void testFiles(); + + void slotRenderAnimation(); + void slotRenderSequenceAgain(); + }; -#endif +#endif // ANIMATIONRENDERERIMAGE_H diff --git a/plugins/extensions/animationrenderer/CMakeLists.txt b/plugins/extensions/animationrenderer/CMakeLists.txt new file mode 100644 index 0000000000..3127391d9e --- /dev/null +++ b/plugins/extensions/animationrenderer/CMakeLists.txt @@ -0,0 +1,5 @@ +set(kritaanimationrenderer_SOURCES AnimationRenderer.cpp DlgAnimationRenderer.cpp ) +ki18n_wrap_ui(kritaanimationrenderer_SOURCES wdg_animationrenderer.ui ) +add_library(kritaanimationrenderer MODULE ${kritaanimationrenderer_SOURCES}) +target_link_libraries(kritaanimationrenderer kritaui) +install(TARGETS kritaanimationrenderer DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) diff --git a/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp b/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp new file mode 100644 index 0000000000..2932af4526 --- /dev/null +++ b/plugins/extensions/animationrenderer/DlgAnimationRenderer.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2016 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DlgAnimationRenderer.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent) + : KoDialog(parent) + , m_image(doc->image()) + , m_defaultFileName(QFileInfo(doc->url().toLocalFile()).completeBaseName()) +{ + KisConfig cfg; + + setCaption(i18n("Render Animation")); + setButtons(Ok | Cancel); + setDefaultButton(Ok); + + m_page = new WdgAnimaterionRenderer(this); + m_page->layout()->setMargin(0); + m_page->dirRequester->setMode(KoFileDialog::OpenDirectory); + QString lastLocation = cfg.readEntry("AnimationRenderer/last_sequence_export_location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); + m_page->dirRequester->setFileName(lastLocation); + + m_page->intStart->setMinimum(doc->image()->animationInterface()->fullClipRange().start()); + m_page->intStart->setMaximum(doc->image()->animationInterface()->fullClipRange().end()); + m_page->intStart->setValue(doc->image()->animationInterface()->playbackRange().start()); + + m_page->intEnd->setMinimum(doc->image()->animationInterface()->fullClipRange().start()); + m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end()); + m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end()); + + QStringList mimes = KisImportExportManager::mimeFilter(KisImportExportManager::Export); + mimes.sort(); + Q_FOREACH(const QString &mime, mimes) { + QString description = KisMimeDatabase::descriptionForMimeType(mime); + if (description.isEmpty()) { + description = mime; + } + m_page->cmbMimetype->addItem(description, mime); + if (mime == "image/png") { + m_page->cmbMimetype->setCurrentIndex(m_page->cmbMimetype->count() - 1); + } + + } + + setMainWidget(m_page); + resize(m_page->sizeHint()); + + KoJsonTrader trader; + QListlist = trader.query("Krita/AnimationExporter", ""); + Q_FOREACH(QPluginLoader *loader, list) { + QJsonObject json = loader->metaData().value("MetaData").toObject(); + QStringList mimetypes = json.value("X-KDE-Export").toString().split(","); + Q_FOREACH(const QString &mime, mimetypes) { + + KLibFactory *factory = qobject_cast(loader->instance()); + if (!factory) { + warnUI << loader->errorString(); + continue; + } + + QObject* obj = factory->create(0); + if (!obj || !obj->inherits("KisImportExportFilter")) { + delete obj; + continue; + } + + QSharedPointerfilter(static_cast(obj)); + if (!filter) { + delete obj; + continue; + } + + m_renderFilters.append(filter); + + QString description = KisMimeDatabase::descriptionForMimeType(mime); + if (description.isEmpty()) { + description = mime; + } + m_page->cmbRenderType->addItem(description, mime); + + } + } + m_page->videoFilename->setMode(KoFileDialog::SaveFile); + m_page->videoFilename->setStartDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); + + qDeleteAll(list); + + connect(m_page->grpRender, SIGNAL(toggled(bool)), this, SLOT(toggleSequenceType(bool))); + connect(m_page->bnExportOptions, SIGNAL(clicked()), this, SLOT(sequenceMimeTypeSelected())); + connect(m_page->bnRenderOptions, SIGNAL(clicked()), this, SLOT(selectRenderType())); + + QString ffmpeg = cfg.customFFMpegPath(); + m_page->ffmpegLocation->setFileName(ffmpeg); + m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile); + connect(m_page->ffmpegLocation, SIGNAL(fileSelected(QString)), this, SLOT(ffmpegLocationChanged(QString))); + + m_page->grpRender->setChecked(cfg.readEntry("AnimationRenderer/render_animation", false)); + m_page->chkDeleteSequence->setChecked(cfg.readEntry("AnimationRenderer/delete_sequence", false)); + m_page->cmbRenderType->setCurrentIndex(cfg.readEntry("AnimationRenderer/render_type", 0)); + + +} + +DlgAnimationRenderer::~DlgAnimationRenderer() +{ + KisConfig cfg; + cfg.writeEntry("AnimationRenderer/render_animation", m_page->grpRender->isChecked()); + cfg.writeEntry("AnimationRenderer/last_sequence_export_location", m_page->dirRequester->fileName()); + cfg.writeEntry("AnimationRenderer/render_type", m_page->cmbRenderType->currentIndex()); + cfg.writeEntry("AnimationRenderer/delete_sequence", m_page->chkDeleteSequence->isChecked()); + cfg.setCustomFFMpegPath(m_page->ffmpegLocation->fileName()); + + if (m_encoderConfigWidget) { + m_encoderConfigWidget->setParent(0); + m_encoderConfigWidget->deleteLater(); + } + if (m_frameExportConfigWidget) { + m_frameExportConfigWidget->setParent(0); + m_frameExportConfigWidget->deleteLater(); + } + + delete m_page; + +} + +KisPropertiesConfigurationSP DlgAnimationRenderer::getSequenceConfiguration() const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("basename", m_page->txtBasename->text()); + cfg->setProperty("directory", m_page->dirRequester->fileName()); + cfg->setProperty("first_frame", m_page->intStart->value()); + cfg->setProperty("last_frame", m_page->intEnd->value()); + cfg->setProperty("sequence_start", m_page->sequenceStart->value()); + cfg->setProperty("mimetype", m_page->cmbMimetype->currentData().toString()); + return cfg; +} + +void DlgAnimationRenderer::setSequenceConfiguration(KisPropertiesConfigurationSP cfg) +{ + m_page->txtBasename->setText(cfg->getString("basename", "frame")); + m_page->dirRequester->setFileName(cfg->getString("directory", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation))); + m_page->intStart->setValue(cfg->getInt("first_frame", m_image->animationInterface()->playbackRange().start())); + m_page->intEnd->setValue(cfg->getInt("last_frame", m_image->animationInterface()->playbackRange().end())); + m_page->sequenceStart->setValue(cfg->getInt("sequence_start", m_image->animationInterface()->playbackRange().start())); + QString mimetype = cfg->getString("mimetype"); + for (int i = 0; i < m_page->cmbMimetype->count(); ++i) { + if (m_page->cmbMimetype->itemData(i).toString() == mimetype) { + m_page->cmbMimetype->setCurrentIndex(i); + break; + } + } +} + +KisPropertiesConfigurationSP DlgAnimationRenderer::getFrameExportConfiguration() const +{ + if (m_frameExportConfigWidget) { + KisPropertiesConfigurationSP cfg = m_frameExportConfigWidget->configuration(); + cfg->setProperty("basename", m_page->txtBasename->text()); + cfg->setProperty("directory", m_page->dirRequester->fileName()); + cfg->setProperty("first_frame", m_page->intStart->value()); + cfg->setProperty("last_frame", m_page->intEnd->value()); + cfg->setProperty("sequence_start", m_page->sequenceStart->value()); + + return m_frameExportConfigWidget->configuration(); + } + return 0; +} + +bool DlgAnimationRenderer::renderToVideo() const +{ + return m_page->grpRender->isChecked(); +} + +KisPropertiesConfigurationSP DlgAnimationRenderer::getVideoConfiguration() const +{ + if (!m_page->grpRender->isChecked()) { + return 0; + } + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("filename", m_page->videoFilename->fileName()); + cfg->setProperty("delete_sequence", m_page->chkDeleteSequence->isChecked()); + return cfg; +} + +void DlgAnimationRenderer::setVideoConfiguration(KisPropertiesConfigurationSP /*cfg*/) +{ +} + +KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() const +{ + if (!m_page->grpRender->isChecked()) { + return 0; + } + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + if (m_encoderConfigWidget) { + cfg = m_encoderConfigWidget->configuration(); + } + cfg->setProperty("mimetype", m_page->cmbRenderType->currentData().toString()); + cfg->setProperty("directory", m_page->dirRequester->fileName()); + cfg->setProperty("first_frame", m_page->intStart->value()); + cfg->setProperty("last_frame", m_page->intEnd->value()); + cfg->setProperty("sequence_start", m_page->sequenceStart->value()); + + return cfg; +} + +void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP /*cfg*/) +{ + +} + +QSharedPointer DlgAnimationRenderer::encoderFilter() const +{ + if (m_page->cmbRenderType->currentIndex() < m_renderFilters.size()) { + return m_renderFilters[m_page->cmbRenderType->currentIndex()]; + } + return QSharedPointer(0); +} + +void DlgAnimationRenderer::selectRenderType() +{ + int index = m_page->cmbRenderType->currentIndex(); + + if (m_encoderConfigWidget) { + m_encoderConfigWidget->deleteLater(); + m_encoderConfigWidget = 0; + } + + if (index >= m_renderFilters.size()) return; + + QSharedPointer filter = m_renderFilters[index]; + QString mimetype = m_page->cmbRenderType->itemData(index).toString(); + + if (!m_page->videoFilename->fileName().isEmpty() && QFileInfo(m_page->videoFilename->fileName()).completeBaseName() != m_defaultFileName) { + m_defaultFileName = QFileInfo(m_page->videoFilename->fileName()).completeBaseName(); + } + m_page->videoFilename->setMimeTypeFilters(QStringList() << mimetype, mimetype); + m_page->videoFilename->setFileName(m_defaultFileName + "." + KisMimeDatabase::suffixesForMimeType(mimetype).first()); + + if (filter) { + m_encoderConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1()); + if (m_encoderConfigWidget) { + m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1())); + KoDialog dlg(this); + dlg.setMainWidget(m_encoderConfigWidget); + dlg.setButtons(KoDialog::Ok | KoDialog::Cancel); + if (!dlg.exec()) { + m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration()); + } + dlg.setMainWidget(0); + m_encoderConfigWidget->hide(); + m_encoderConfigWidget->setParent(0); + } + } + else { + m_encoderConfigWidget = 0; + } +} + +void DlgAnimationRenderer::toggleSequenceType(bool toggle) +{ + m_page->cmbMimetype->setEnabled(!toggle); + for (int i = 0; i < m_page->cmbMimetype->count(); ++i) { + if (m_page->cmbMimetype->itemData(i).toString() == "image/png") { + m_page->cmbMimetype->setCurrentIndex(i); + break; + } + } +} + +void DlgAnimationRenderer::sequenceMimeTypeSelected() +{ + int index = m_page->cmbMimetype->currentIndex(); + + if (m_frameExportConfigWidget) { + m_frameExportConfigWidget->deleteLater(); + m_frameExportConfigWidget = 0; + } + + QString mimetype = m_page->cmbMimetype->itemData(index).toString(); + KisImportExportFilter *filter = KisImportExportManager::filterForMimeType(mimetype, KisImportExportManager::Export); + if (filter) { + m_frameExportConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1()); + if (m_frameExportConfigWidget) { + m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1())); + KoDialog dlg(this); + dlg.setMainWidget(m_frameExportConfigWidget); + dlg.setButtons(KoDialog::Ok | KoDialog::Cancel); + if (!dlg.exec()) { + m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration()); + } + m_frameExportConfigWidget->hide(); + m_frameExportConfigWidget->setParent(0); + dlg.setMainWidget(0); + } + delete filter; + } +} + +void DlgAnimationRenderer::ffmpegLocationChanged(const QString &s) +{ + KisConfig cfg; + cfg.setCustomFFMpegPath(s); +} + +void DlgAnimationRenderer::slotButtonClicked(int button) +{ + if (button == KoDialog::Ok && m_page->grpRender->isChecked()) { + QString ffmpeg = m_page->ffmpegLocation->fileName(); + if (m_page->videoFilename->fileName().isEmpty()) { + QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Please enter a file name to render to.")); + return; + } + else if (ffmpeg.isEmpty()) { + QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is unknown. Please install FFmpeg first: Krita cannot render animations without FFmpeg. (www.ffmpeg.org)")); + return; + } + else { + QFileInfo fi(ffmpeg); + if (!fi.exists()) { + QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is invalid. Please select the correct location of the FFmpeg executable on your system.")); + return; + } + } + } + KoDialog::slotButtonClicked(button); +} + diff --git a/plugins/extensions/animationrenderer/DlgAnimationRenderer.h b/plugins/extensions/animationrenderer/DlgAnimationRenderer.h new file mode 100644 index 0000000000..e63a0654ef --- /dev/null +++ b/plugins/extensions/animationrenderer/DlgAnimationRenderer.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_ANIMATIONRENDERERIMAGE +#define DLG_ANIMATIONRENDERERIMAGE + +#include +#include + +#include "ui_wdg_animationrenderer.h" + +#include +#include + +class KisDocument; +class KisImportExportFilter; +class KisConfigWidget; +class QHBoxLayout; + +class WdgAnimaterionRenderer : public QWidget, public Ui::WdgAnimaterionRenderer +{ + Q_OBJECT + +public: + WdgAnimaterionRenderer(QWidget *parent) + : QWidget(parent) + { + setupUi(this); + } +}; + +class DlgAnimationRenderer: public KoDialog +{ + + Q_OBJECT + +public: + + DlgAnimationRenderer(KisDocument *doc, QWidget *parent = 0); + ~DlgAnimationRenderer(); + + KisPropertiesConfigurationSP getSequenceConfiguration() const; + void setSequenceConfiguration(KisPropertiesConfigurationSP cfg); + + KisPropertiesConfigurationSP getFrameExportConfiguration() const; + + bool renderToVideo() const; + + KisPropertiesConfigurationSP getVideoConfiguration() const; + void setVideoConfiguration(KisPropertiesConfigurationSP cfg); + + KisPropertiesConfigurationSP getEncoderConfiguration() const; + void setEncoderConfiguration(KisPropertiesConfigurationSP cfg); + + QSharedPointer encoderFilter() const; + +private Q_SLOTS: + + void selectRenderType(); + void toggleSequenceType(bool toggle); + void sequenceMimeTypeSelected(); + void ffmpegLocationChanged(const QString&); + +protected Q_SLOTS: + + void slotButtonClicked(int button); + +private: + + KisImageWSP m_image; + WdgAnimaterionRenderer *m_page {0}; + QList> m_renderFilters; + KisConfigWidget *m_encoderConfigWidget {0}; + KisConfigWidget *m_frameExportConfigWidget {0}; + QString m_defaultFileName; +}; + +#endif // DLG_ANIMATIONRENDERERIMAGE diff --git a/plugins/extensions/animationrenderer/kritaanimationrenderer.json b/plugins/extensions/animationrenderer/kritaanimationrenderer.json new file mode 100644 index 0000000000..10a5d70135 --- /dev/null +++ b/plugins/extensions/animationrenderer/kritaanimationrenderer.json @@ -0,0 +1,9 @@ +{ + "Id": "AnimationRenderer Plugin", + "Type": "Service", + "X-KDE-Library": "kritaanimationrenderer", + "X-KDE-ServiceTypes": [ + "Krita/ViewPlugin" + ], + "X-Krita-Version": "28" +} diff --git a/plugins/extensions/animationrenderer/wdg_animationrenderer.ui b/plugins/extensions/animationrenderer/wdg_animationrenderer.ui new file mode 100644 index 0000000000..f60044edc7 --- /dev/null +++ b/plugins/extensions/animationrenderer/wdg_animationrenderer.ui @@ -0,0 +1,282 @@ + + + WdgAnimaterionRenderer + + + + 0 + 0 + 444 + 443 + + + + AnimationRenderer Image + + + + + + Image Sequence + + + + + + Base name: + + + + + + + frame + + + + + + + Fi&le format: + + + label_8 + + + + + + + + + + 2 + 0 + + + + Select the file format for the image sequence. If you want to render to video or animated gif, you can only select PNG + + + + + + + Select the frame export options + + + ... + + + + + + + + + Render location: + + + + + + + + 1 + 0 + + + + + + + + First frame: + + + + + + + + 1 + 0 + + + + + + + + Last frame: + + + + + + + + 1 + 0 + + + + + + + + + + Naming sequence starts with: + + + + + + + + 1 + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 1 + + + + Render + + + true + + + false + + + + + + Render as: + + + + + + + + + + + + Select the ffmpeg render options. + + + ... + + + + + + + + + File: + + + + + + + + 1 + 0 + + + + + + + + FF&Mpeg: + + + ffmpegLocation + + + + + + + + + + Delete Sequence After Rendering + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + KisFileNameRequester + QWidget +
kis_file_name_requester.h
+ 1 +
+
+ + txtBasename + cmbMimetype + intStart + intEnd + sequenceStart + grpRender + cmbRenderType + chkDeleteSequence + + + +
diff --git a/plugins/extensions/gmic/CMakeLists.txt b/plugins/extensions/gmic/CMakeLists.txt index b69cd646db..862222afca 100644 --- a/plugins/extensions/gmic/CMakeLists.txt +++ b/plugins/extensions/gmic/CMakeLists.txt @@ -1,202 +1,202 @@ ## # CMake for gmic ## set(GMIC_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/gmic") include_directories( ${GMIC_SOURCE_DIR}) if(NOT MSVC) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC") endif() # turn off O2 and Ob1 or Ob2 for g'mic if (MSVC) # RelWithDebInfo set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /Oy /Gs /GF /Gy") string(REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) string(REPLACE "/Ob1" "/Ob0" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) #Release set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /Ot /Oy /Gs /GF /Gy") string(REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) string(REPLACE "/Ob2" "/Ob0" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) endif() set(gmic_sources_SRCS ${GMIC_SOURCE_DIR}/gmic.cpp ) set(gmic_headers_SRCS ${GMIC_SOURCE_DIR}/CImg.h ${GMIC_SOURCE_DIR}/gmic_def.h ${GMIC_SOURCE_DIR}/gmic.h ) # Mandatory flags add_definitions(-Dgmic_gimp) add_definitions(-Dgmic_build) add_definitions(-Dgmic_float_only) add_definitions(-Dcimg_use_vt100 ) # PARALLEL if (Threads_FOUND) message("G'Mic: using pthreads") add_definitions(-Dgmic_is_parallel) add_definitions(-Dcimg_use_rng) endif() #OpenMP if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8.3 AND OPENMP_FOUND) message("G'Mic: using OpenMP") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") add_definitions(-Dcimg_use_openmp) add_definitions(-fopenmp) endif() #FFTW if(FFTW3_FOUND) message("G'Mic: using FFTW3") add_definitions(-Dcimg_use_fftw3 ) add_definitions(-Dcimg_use_fftw3_singlethread ) include_directories(${FFTW3_INCLUDE_DIR}) endif() # PNG if (PNG_FOUND) add_definitions(${PNG_DEFINITIONS}) add_definitions(-Dcimg_use_png) include_directories(SYSTEM ${PNG_INCLUDE_DIR}) endif() # ZLIB if (ZLIB_FOUND) add_definitions(-Dcimg_use_zlib) include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS} ) endif() # CURL if (CURL_FOUND) message("G'Mic: using Curl") add_definitions(-Dcimg_use_curl) include_directories(SYSTEM ${CURL_INCLUDE_DIRS} ) endif() # X11 if(X11_FOUND) add_definitions(-Dcimg_display=1) add_definitions(-Dcimg_appname="gmic") elseif (WIN32 AND MSVC) # CMake for MSVC automatically links and finds headers for gdi32 add_definitions(-Dcimg_display=2) add_definitions(-Dcimg_appname="gmic") else() add_definitions(-Dcimg_display=0) endif() # Extra for Krita if(APPLE) add_definitions(-D_APPLE) endif() -if (MSYS) +if (WIN32) add_definitions(-Dcimg_OS=2) add_definitions(-Dcimg_display=2) endif() add_library(gmic STATIC ${gmic_sources_SRCS} ${gmic_headers_SRCS}) if(FFTW3_FOUND) target_link_libraries(gmic ${FFTW3_LIBRARIES}) endif() if (X11_FOUND) target_link_libraries(gmic ${X11_LIBRARIES} KF5::WindowSystem Qt5::Core) endif() if(CURL_FOUND) target_link_libraries(gmic ${CURL_LIBRARIES}) endif() # Only build gmic with gcc; msvc is broken, and now dtschump tells is that on OSX # gcc should be used as well because clang is broken. if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8.3 AND OPENMP_FOUND) target_link_libraries(gmic ${OPENMP_LIBRARIES}) endif() target_link_libraries(gmic ${ZLIB_LIBRARIES}) target_link_libraries(gmic ${PNG_LIBRARIES}) if(Threads_FOUND) target_link_libraries(gmic ${CMAKE_THREAD_LIBS_INIT}) endif() ## # compile Krita plug-in and link static library in ## set(kritagmic_shared_SOURCES kis_gmic_parser.cpp kis_gmic_blacklister.cpp kis_gmic_filter_model.cpp kis_gmic_filter_settings.cpp Component.cpp Category.cpp Command.cpp Parameter.cpp kis_input_output_mapper.cpp kis_html_delegate.cpp kis_gmic_settings_widget.cpp kis_gmic_input_output_widget.cpp kis_gmic_filter_proxy_model.cpp kis_gmic_widget.cpp kis_gmic_updater.cpp kis_filter_preview_widget.cpp ) ki18n_wrap_ui(kritagmic_shared_SOURCES wdg_gmic.ui wdg_gmic_input_output.ui) set(kritagmic_SOURCES kis_gmic_simple_convertor.cpp kis_export_gmic_processing_visitor.cpp kis_gmic_applicator.cpp kis_gmic_command.cpp kis_gmic_data.cpp kis_gmic_synchronize_layers_command.cpp kis_gmic_synchronize_image_size_command.cpp kis_import_gmic_processing_visitor.cpp kis_gmic_progress_manager.cpp kis_gmic_small_applicator.cpp kis_gmic_plugin.cpp ${kritagmic_shared_SOURCES} ) add_library(kritagmic MODULE ${kritagmic_SOURCES}) target_link_libraries(kritagmic kritaui gmic Qt5::Xml Qt5::Network ${ZLIB_LIBRARIES}) # gmicparser for debugging purposes set(gmicparser_SOURCES gmicparser.cpp ${kritagmic_shared_SOURCES}) add_executable(gmicparser ${gmicparser_SOURCES}) target_link_libraries(gmicparser Qt5::Core Qt5::Gui Qt5::Network kritaui gmic ${ZLIB_LIBRARIES}) ########### install files ############### set(GMIC_INSTALL_DIR ${DATA_INSTALL_DIR}/krita/gmic) install(TARGETS kritagmic DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) install(TARGETS gmicparser ${INSTALL_TARGETS_DEFAULT_ARGS}) install( FILES gmic.xmlgui DESTINATION ${DATA_INSTALL_DIR}/kritaplugins) install( FILES #${GMIC_SOURCE_DIR}/gmic_def.gmic #${GMIC_SOURCE_DIR}/update1610.gmic ${GMIC_SOURCE_DIR}/gimp_update169.gmic gmic_def.gmic.blacklist DESTINATION ${GMIC_INSTALL_DIR} ) # tests, currently broken on OSX due to fftw linking problem if(NOT APPLE) #add_subdirectory(tests) endif() diff --git a/plugins/extensions/gmic/kis_gmic_settings_widget.h b/plugins/extensions/gmic/kis_gmic_settings_widget.h index 7f25ebc99c..86e925556e 100644 --- a/plugins/extensions/gmic/kis_gmic_settings_widget.h +++ b/plugins/extensions/gmic/kis_gmic_settings_widget.h @@ -1,83 +1,83 @@ /* * Copyright (c) 2013-2015 Lukáš Tvrdý * * 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_GMIC_SETTINGS_WIDGET #define KIS_GMIC_SETTINGS_WIDGET #include #include #include #include #include /** * creates GUI for GMIC filter definition (Command) */ enum ROLE { CreateRole = 0, LoadRole = 1 }; class KisGmicSettingsWidget : public KisConfigWidget { Q_OBJECT public: KisGmicSettingsWidget(Command * command = 0); ~KisGmicSettingsWidget(); - virtual KisPropertiesConfiguration* configuration() const { return 0; } - virtual void setConfiguration(const KisPropertiesConfiguration* config) { Q_UNUSED(config) } + virtual KisPropertiesConfigurationSP configuration() const { return 0; } + virtual void setConfiguration(const KisPropertiesConfigurationSP config) { Q_UNUSED(config) } Command * currentCommandSettings(); void reload(); private: void createSettingsWidget(ROLE role); private: Command * m_commandDefinition; QHash m_widgetToParameterIndexMapper; QHash m_parameterToWidgetMapper; Parameter * parameter(QObject * widget); QWidget * widget(Parameter * parameter); // maps the parameter to widget in both directions, two hash tables are used for it void mapParameterWidget(Parameter * parameter, QWidget * widget); private Q_SLOTS: void setIntValue(int value); void setFloatValue(qreal value); void setBoolValue(bool value); void setChoiceIndex(int index); void setColorValue(const QColor &color); void setTextValue(); void setFolderPathValue(const QString &path); void setFilePathValue(const QString &path); }; Q_DECLARE_METATYPE(KisGmicSettingsWidget*) #endif diff --git a/plugins/extensions/modify_selection/dlg_border_selection.cc b/plugins/extensions/modify_selection/dlg_border_selection.cc index 47e06bf0ef..50640acc55 100644 --- a/plugins/extensions/modify_selection/dlg_border_selection.cc +++ b/plugins/extensions/modify_selection/dlg_border_selection.cc @@ -1,105 +1,105 @@ /* * dlg_border_selection.cc - part of Krita * * Copyright (c) 2006 Michael Thaler * 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 "dlg_border_selection.h" #include #include #include #include #include WdgBorderSelection::WdgBorderSelection(QWidget* parent, KisViewManager *view) : KisOperationUIWidget(i18n("Border Selection"), parent) , m_width(1) { Q_ASSERT(view); KisImageWSP image = view->image(); Q_ASSERT(image); m_resolution = image->yRes(); setupUi(this); spbWidth->setValue(m_width); spbWidth->setFocus(); spbWidth->setVisible(true); spbWidthDouble->setVisible(false); cmbUnit->addItems(KoUnit::listOfUnitNameForUi()); cmbUnit->setCurrentIndex(KoUnit(KoUnit::Pixel).indexInListForUi()); // ensure that both spinboxes request the same horizontal size KisSizeGroup *spbGroup = new KisSizeGroup(this); spbGroup->addWidget(spbWidth); spbGroup->addWidget(spbWidthDouble); connect(spbWidth, SIGNAL(valueChanged(int)), this, SLOT(slotWidthChanged(int))); connect(spbWidthDouble, SIGNAL(valueChanged(double)), this, SLOT(slotWidthChanged(double))); connect(cmbUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUnitChanged(int))); } void WdgBorderSelection::slotWidthChanged(int width) { slotWidthChanged((double) width); } void WdgBorderSelection::slotWidthChanged(double width) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); const double resWidth = (selectedUnit == KoUnit(KoUnit::Pixel)) ? width : (width * m_resolution); m_width = qRound(selectedUnit.fromUserValue(resWidth)); } void WdgBorderSelection::slotUnitChanged(int index) { updateWidthUIValue(m_width); const KoUnit selectedUnit = KoUnit::fromListForUi(index); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbWidth->setVisible(false); spbWidthDouble->setVisible(true); } else { spbWidth->setVisible(true); spbWidthDouble->setVisible(false); } } void WdgBorderSelection::updateWidthUIValue(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbWidthDouble->blockSignals(true); spbWidthDouble->setValue(selectedUnit.toUserValue(value / m_resolution)); spbWidthDouble->blockSignals(false); } else { const int finalValue = (selectedUnit == KoUnit(KoUnit::Point)) ? qRound(value / m_resolution) : value; spbWidth->blockSignals(true); spbWidth->setValue(selectedUnit.toUserValue(finalValue)); spbWidth->blockSignals(false); } } -void WdgBorderSelection::getConfiguration(KisOperationConfiguration* config) +void WdgBorderSelection::getConfiguration(KisOperationConfigurationSP config) { config->setProperty("x-radius", m_width); config->setProperty("y-radius", m_width); } diff --git a/plugins/extensions/modify_selection/dlg_border_selection.h b/plugins/extensions/modify_selection/dlg_border_selection.h index b1f272854b..a6e900fdc0 100644 --- a/plugins/extensions/modify_selection/dlg_border_selection.h +++ b/plugins/extensions/modify_selection/dlg_border_selection.h @@ -1,49 +1,49 @@ /* * dlg_border_selection.h -- part of Krita * * Copyright (c) 2006 Michael Thaler * 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. */ #ifndef DLG_BORDER_SELECTION_H #define DLG_BORDER_SELECTION_H #include "ui_wdg_border_selection.h" #include class KisViewManager; class WdgBorderSelection : public KisOperationUIWidget, public Ui::WdgBorderSelection { Q_OBJECT public: WdgBorderSelection(QWidget *parent, KisViewManager* view); - virtual void getConfiguration(KisOperationConfiguration* config); + virtual void getConfiguration(KisOperationConfigurationSP config); private Q_SLOTS: void slotWidthChanged(int width); void slotWidthChanged(double width); void slotUnitChanged(int index); private: void updateWidthUIValue(double value); double m_resolution; int m_width; }; #endif // DLG_BORDER_SELECTION_H diff --git a/plugins/extensions/modify_selection/dlg_feather_selection.cc b/plugins/extensions/modify_selection/dlg_feather_selection.cc index 5d209113b5..e79ff4f893 100644 --- a/plugins/extensions/modify_selection/dlg_feather_selection.cc +++ b/plugins/extensions/modify_selection/dlg_feather_selection.cc @@ -1,104 +1,104 @@ /* * dlg_feather_selection.cc - part of Krita * * Copyright (c) 2009 Edward Apap * 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 "dlg_feather_selection.h" #include #include #include #include #include WdgFeatherSelection::WdgFeatherSelection(QWidget* parent, KisViewManager* view) : KisOperationUIWidget(i18n("Feather Selection"), parent) , m_radius(5) { Q_ASSERT(view); KisImageWSP image = view->image(); Q_ASSERT(image); m_resolution = image->yRes(); setupUi(this); spbRadius->setValue(m_radius); spbRadius->setFocus(); spbRadius->setVisible(true); spbRadiusDouble->setVisible(false); cmbUnit->addItems(KoUnit::listOfUnitNameForUi()); cmbUnit->setCurrentIndex(KoUnit(KoUnit::Pixel).indexInListForUi()); // ensure that both spinboxes request the same horizontal size KisSizeGroup *spbGroup = new KisSizeGroup(this); spbGroup->addWidget(spbRadius); spbGroup->addWidget(spbRadiusDouble); connect(spbRadius, SIGNAL(valueChanged(int)), this, SLOT(slotRadiusChanged(int))); connect(spbRadiusDouble, SIGNAL(valueChanged(double)), this, SLOT(slotRadiusChanged(double))); connect(cmbUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUnitChanged(int))); } void WdgFeatherSelection::slotRadiusChanged(int radius) { slotRadiusChanged((double) radius); } void WdgFeatherSelection::slotRadiusChanged(double radius) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); const double resRadius = (selectedUnit == KoUnit(KoUnit::Pixel)) ? radius : (radius * m_resolution); m_radius = qRound(selectedUnit.fromUserValue(resRadius)); } void WdgFeatherSelection::slotUnitChanged(int index) { updateRadiusUIValue(m_radius); const KoUnit selectedUnit = KoUnit::fromListForUi(index); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbRadius->setVisible(false); spbRadiusDouble->setVisible(true); } else { spbRadius->setVisible(true); spbRadiusDouble->setVisible(false); } } void WdgFeatherSelection::updateRadiusUIValue(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbRadiusDouble->blockSignals(true); spbRadiusDouble->setValue(selectedUnit.toUserValue(value / m_resolution)); spbRadiusDouble->blockSignals(false); } else { const int finalValue = (selectedUnit == KoUnit(KoUnit::Point)) ? qRound(value / m_resolution) : value; spbRadius->blockSignals(true); spbRadius->setValue(selectedUnit.toUserValue(finalValue)); spbRadius->blockSignals(false); } } -void WdgFeatherSelection::getConfiguration(KisOperationConfiguration* config) +void WdgFeatherSelection::getConfiguration(KisOperationConfigurationSP config) { config->setProperty("radius", m_radius); } diff --git a/plugins/extensions/modify_selection/dlg_feather_selection.h b/plugins/extensions/modify_selection/dlg_feather_selection.h index dae209f09a..b7ee16c2be 100644 --- a/plugins/extensions/modify_selection/dlg_feather_selection.h +++ b/plugins/extensions/modify_selection/dlg_feather_selection.h @@ -1,49 +1,49 @@ /* * dlg_feather_selection.h -- part of Krita * * Copyright (c) 2009 Edward Apap * 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. */ #ifndef DLG_FEATHER_SELECTION_H #define DLG_FEATHER_SELECTION_H #include "ui_wdg_feather_selection.h" #include class KisViewManager; class WdgFeatherSelection : public KisOperationUIWidget, public Ui::WdgFeatherSelection { Q_OBJECT public: WdgFeatherSelection(QWidget *parent, KisViewManager *view); - virtual void getConfiguration(KisOperationConfiguration* config); + virtual void getConfiguration(KisOperationConfigurationSP config); private Q_SLOTS: void slotRadiusChanged(int radius); void slotRadiusChanged(double radius); void slotUnitChanged(int index); private: void updateRadiusUIValue(double value); double m_resolution; int m_radius; }; #endif // DLG_GROW_SELECTION_H diff --git a/plugins/extensions/modify_selection/dlg_grow_selection.cc b/plugins/extensions/modify_selection/dlg_grow_selection.cc index 70c02198cd..fc457e4e67 100644 --- a/plugins/extensions/modify_selection/dlg_grow_selection.cc +++ b/plugins/extensions/modify_selection/dlg_grow_selection.cc @@ -1,105 +1,105 @@ /* * dlg_grow_selection.cc - part of Krita * * Copyright (c) 2006 Michael Thaler * 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 "dlg_grow_selection.h" #include #include #include #include #include WdgGrowSelection::WdgGrowSelection(QWidget* parent, KisViewManager* view) : KisOperationUIWidget(i18n("Grow Selection"), parent) , m_growValue(1) { Q_ASSERT(view); KisImageWSP image = view->image(); Q_ASSERT(image); m_resolution = image->yRes(); setupUi(this); spbGrowValue->setValue(m_growValue); spbGrowValue->setFocus(); spbGrowValue->setVisible(true); spbGrowValueDouble->setVisible(false); cmbUnit->addItems(KoUnit::listOfUnitNameForUi()); cmbUnit->setCurrentIndex(KoUnit(KoUnit::Pixel).indexInListForUi()); // ensure that both spinboxes request the same horizontal size KisSizeGroup *spbGroup = new KisSizeGroup(this); spbGroup->addWidget(spbGrowValue); spbGroup->addWidget(spbGrowValueDouble); connect(spbGrowValue, SIGNAL(valueChanged(int)), this, SLOT(slotGrowValueChanged(int))); connect(spbGrowValueDouble, SIGNAL(valueChanged(double)), this, SLOT(slotGrowValueChanged(double))); connect(cmbUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUnitChanged(int))); } void WdgGrowSelection::slotGrowValueChanged(int value) { slotGrowValueChanged((double) value); } void WdgGrowSelection::slotGrowValueChanged(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); const double resValue = (selectedUnit == KoUnit(KoUnit::Pixel)) ? value : (value * m_resolution); m_growValue = qRound(selectedUnit.fromUserValue(resValue)); } void WdgGrowSelection::slotUnitChanged(int index) { updateGrowUIValue(m_growValue); const KoUnit selectedUnit = KoUnit::fromListForUi(index); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbGrowValue->setVisible(false); spbGrowValueDouble->setVisible(true); } else { spbGrowValue->setVisible(true); spbGrowValueDouble->setVisible(false); } } void WdgGrowSelection::updateGrowUIValue(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbGrowValueDouble->blockSignals(true); spbGrowValueDouble->setValue(selectedUnit.toUserValue(value / m_resolution)); spbGrowValueDouble->blockSignals(false); } else { const int finalValue = (selectedUnit == KoUnit(KoUnit::Point)) ? qRound(value / m_resolution) : value; spbGrowValue->blockSignals(true); spbGrowValue->setValue(selectedUnit.toUserValue(finalValue)); spbGrowValue->blockSignals(false); } } -void WdgGrowSelection::getConfiguration(KisOperationConfiguration* config) +void WdgGrowSelection::getConfiguration(KisOperationConfigurationSP config) { config->setProperty("x-radius", m_growValue); config->setProperty("y-radius", m_growValue); } diff --git a/plugins/extensions/modify_selection/dlg_grow_selection.h b/plugins/extensions/modify_selection/dlg_grow_selection.h index d6d430bb22..882498cded 100644 --- a/plugins/extensions/modify_selection/dlg_grow_selection.h +++ b/plugins/extensions/modify_selection/dlg_grow_selection.h @@ -1,49 +1,49 @@ /* * dlg_grow_selection.h -- part of Krita * * Copyright (c) 2006 Michael Thaler * 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. */ #ifndef DLG_GROW_SELECTION_H #define DLG_GROW_SELECTION_H #include "ui_wdg_grow_selection.h" #include class KisViewManager; class WdgGrowSelection : public KisOperationUIWidget, public Ui::WdgGrowSelection { Q_OBJECT public: WdgGrowSelection(QWidget *parent, KisViewManager* view); - virtual void getConfiguration(KisOperationConfiguration* config); + virtual void getConfiguration(KisOperationConfigurationSP config); private Q_SLOTS: void slotGrowValueChanged(int value); void slotGrowValueChanged(double value); void slotUnitChanged(int index); private: void updateGrowUIValue(double value); double m_resolution; int m_growValue; }; #endif // DLG_GROW_SELECTION_H diff --git a/plugins/extensions/modify_selection/dlg_shrink_selection.cc b/plugins/extensions/modify_selection/dlg_shrink_selection.cc index c251b627d0..8222d8c786 100644 --- a/plugins/extensions/modify_selection/dlg_shrink_selection.cc +++ b/plugins/extensions/modify_selection/dlg_shrink_selection.cc @@ -1,106 +1,106 @@ /* * dlg_shrink_selection.cc - part of Krita * * Copyright (c) 2006 Michael Thaler * 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 "dlg_shrink_selection.h" #include #include #include #include #include WdgShrinkSelection::WdgShrinkSelection(QWidget* parent, KisViewManager *view) : KisOperationUIWidget(i18n("Shrink Selection"), parent) , m_shrinkValue(1) { Q_ASSERT(view); KisImageWSP image = view->image(); Q_ASSERT(image); m_resolution = image->yRes(); setupUi(this); spbShrinkValue->setValue(m_shrinkValue); spbShrinkValue->setFocus(); spbShrinkValue->setVisible(true); spbShrinkValueDouble->setVisible(false); cmbUnit->addItems(KoUnit::listOfUnitNameForUi()); cmbUnit->setCurrentIndex(KoUnit(KoUnit::Pixel).indexInListForUi()); // ensure that both spinboxes request the same horizontal size KisSizeGroup *spbGroup = new KisSizeGroup(this); spbGroup->addWidget(spbShrinkValue); spbGroup->addWidget(spbShrinkValueDouble); connect(spbShrinkValue, SIGNAL(valueChanged(int)), this, SLOT(slotShrinkValueChanged(int))); connect(spbShrinkValueDouble, SIGNAL(valueChanged(double)), this, SLOT(slotShrinkValueChanged(double))); connect(cmbUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUnitChanged(int))); } void WdgShrinkSelection::slotShrinkValueChanged(int value) { slotShrinkValueChanged((double) value); } void WdgShrinkSelection::slotShrinkValueChanged(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); const double resValue = (selectedUnit == KoUnit(KoUnit::Pixel)) ? value : (value * m_resolution); m_shrinkValue = qRound(selectedUnit.fromUserValue(resValue)); } void WdgShrinkSelection::slotUnitChanged(int index) { updateShrinkUIValue(m_shrinkValue); const KoUnit selectedUnit = KoUnit::fromListForUi(index); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbShrinkValue->setVisible(false); spbShrinkValueDouble->setVisible(true); } else { spbShrinkValue->setVisible(true); spbShrinkValueDouble->setVisible(false); } } void WdgShrinkSelection::updateShrinkUIValue(double value) { const KoUnit selectedUnit = KoUnit::fromListForUi(cmbUnit->currentIndex()); if (selectedUnit != KoUnit(KoUnit::Pixel)) { spbShrinkValueDouble->blockSignals(true); spbShrinkValueDouble->setValue(selectedUnit.toUserValue(value / m_resolution)); spbShrinkValueDouble->blockSignals(false); } else { const int finalValue = (selectedUnit == KoUnit(KoUnit::Point)) ? qRound(value / m_resolution) : value; spbShrinkValue->blockSignals(true); spbShrinkValue->setValue(selectedUnit.toUserValue(finalValue)); spbShrinkValue->blockSignals(false); } } -void WdgShrinkSelection::getConfiguration(KisOperationConfiguration* config) +void WdgShrinkSelection::getConfiguration(KisOperationConfigurationSP config) { config->setProperty("x-radius", m_shrinkValue); config->setProperty("y-radius", m_shrinkValue); config->setProperty("edgeLock", !ckbShrinkFromImageBorder->isChecked()); } diff --git a/plugins/extensions/modify_selection/dlg_shrink_selection.h b/plugins/extensions/modify_selection/dlg_shrink_selection.h index 53dc301403..c02af70254 100644 --- a/plugins/extensions/modify_selection/dlg_shrink_selection.h +++ b/plugins/extensions/modify_selection/dlg_shrink_selection.h @@ -1,49 +1,49 @@ /* * dlg_shrink_selection.h -- part of Krita * * Copyright (c) 2006 Michael Thaler * 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. */ #ifndef DLG_SHRINK_SELECTION_H #define DLG_SHRINK_SELECTION_H #include "ui_wdg_shrink_selection.h" #include class KisViewManager; class WdgShrinkSelection : public KisOperationUIWidget, public Ui::WdgShrinkSelection { Q_OBJECT public: WdgShrinkSelection(QWidget *parent, KisViewManager* view); - virtual void getConfiguration(KisOperationConfiguration* config); + virtual void getConfiguration(KisOperationConfigurationSP config); private Q_SLOTS: void slotShrinkValueChanged(int value); void slotShrinkValueChanged(double value); void slotUnitChanged(int index); private: void updateShrinkUIValue(double value); double m_resolution; int m_shrinkValue; }; #endif // DLG_SHRINK_SELECTION_H diff --git a/plugins/filters/blur/kis_blur_filter.cpp b/plugins/filters/blur/kis_blur_filter.cpp index d1060611ef..7511a22ce2 100644 --- a/plugins/filters/blur/kis_blur_filter.cpp +++ b/plugins/filters/blur/kis_blur_filter.cpp @@ -1,138 +1,138 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include //MSVC requires that Vc come first #include "kis_blur_filter.h" #include #include #include #include "kis_wdg_blur.h" #include "ui_wdgblur.h" #include #include #include #include #include "kis_mask_generator.h" #include "kis_lod_transform.h" KisBlurFilter::KisBlurFilter() : KisFilter(id(), categoryBlur(), i18n("&Blur...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisBlurFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgBlur(parent); } -KisFilterConfiguration* KisBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("halfWidth", 5); config->setProperty("halfHeight", 5); config->setProperty("rotate", 0); config->setProperty("strength", 0); config->setProperty("shape", 0); return config; } void KisBlurFilter::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = rect.topLeft(); Q_ASSERT(device != 0); - if (!config) config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration(id().id(), 1); KisLodTransformScalar t(device); QVariant value; const uint halfWidth = t.scale((config->getProperty("halfWidth", value)) ? value.toUInt() : 5); const uint halfHeight = t.scale((config->getProperty("halfHeight", value)) ? value.toUInt() : 5); int shape = (config->getProperty("shape", value)) ? value.toInt() : 0; uint width = 2 * halfWidth + 1; uint height = 2 * halfHeight + 1; float aspectRatio = (float) width / height; int rotate = (config->getProperty("rotate", value)) ? value.toInt() : 0; int strength = 100 - (config->getProperty("strength", value) ? value.toUInt() : 0); int hFade = (halfWidth * strength) / 100; int vFade = (halfHeight * strength) / 100; KisMaskGenerator* kas; dbgKrita << width << "" << height << "" << hFade << "" << vFade; switch (shape) { case 1: kas = new KisRectangleMaskGenerator(width, aspectRatio, hFade, vFade, 2, true); break; case 0: default: kas = new KisCircleMaskGenerator(width, aspectRatio, hFade, vFade, 2, true); break; } QBitArray channelFlags; if (config) { channelFlags = config->channelFlags(); - } + } if (channelFlags.isEmpty() || !config) { channelFlags = QBitArray(device->colorSpace()->channelCount(), true); } KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMaskGenerator(kas, rotate * M_PI / 180.0); delete kas; KisConvolutionPainter painter(device); painter.setChannelFlags(channelFlags); painter.setProgress(progressUpdater); painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT); } -QRect KisBlurFilter::neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisBlurFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const int halfWidth = t.scale(_config->getProperty("halfWidth", value) ? value.toUInt() : 5); const int halfHeight = t.scale(_config->getProperty("halfHeight", value) ? value.toUInt() : 5); return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } -QRect KisBlurFilter::changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisBlurFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const int halfWidth = t.scale(_config->getProperty("halfWidth", value) ? value.toUInt() : 5); const int halfHeight = t.scale(_config->getProperty("halfHeight", value) ? value.toUInt() : 5); return rect.adjusted(-halfWidth, -halfHeight, halfWidth, halfHeight); } diff --git a/plugins/filters/blur/kis_blur_filter.h b/plugins/filters/blur/kis_blur_filter.h index 20ff4c5360..8fcdf9823e 100644 --- a/plugins/filters/blur/kis_blur_filter.h +++ b/plugins/filters/blur/kis_blur_filter.h @@ -1,48 +1,48 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_BLUR_FILTER_H #define KIS_BLUR_FILTER_H #include "filter/kis_filter.h" class KisBlurFilter : public KisFilter { public: KisBlurFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("blur", i18n("Blur")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - QRect neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; - QRect changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; + QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; + QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; }; #endif diff --git a/plugins/filters/blur/kis_gaussian_blur_filter.cpp b/plugins/filters/blur/kis_gaussian_blur_filter.cpp index 325bf7089a..47a59b4caf 100644 --- a/plugins/filters/blur/kis_gaussian_blur_filter.cpp +++ b/plugins/filters/blur/kis_gaussian_blur_filter.cpp @@ -1,122 +1,122 @@ /* * This file is part of Krita * * Copyright (c) 2009 Edward Apap * * 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_gaussian_blur_filter.h" #include "kis_wdg_gaussian_blur.h" #include #include #include #include #include "ui_wdg_gaussian_blur.h" #include #include #include #include #include "kis_lod_transform.h" #include KisGaussianBlurFilter::KisGaussianBlurFilter() : KisFilter(id(), categoryBlur(), i18n("&Gaussian Blur...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisGaussianBlurFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgGaussianBlur(parent); } -KisFilterConfiguration* KisGaussianBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisGaussianBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("horizRadius", 5); config->setProperty("vertRadius", 5); config->setProperty("lockAspect", true); return config; } void KisGaussianBlurFilter::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { Q_ASSERT(device != 0); - if (!config) config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration(id().id(), 1); KisLodTransformScalar t(device); QVariant value; config->getProperty("horizRadius", value); float horizontalRadius = t.scale(value.toFloat()); config->getProperty("vertRadius", value); float verticalRadius = t.scale(value.toFloat()); QBitArray channelFlags; if (config) { channelFlags = config->channelFlags(); - } + } if (channelFlags.isEmpty() || !config) { channelFlags = QBitArray(device->colorSpace()->channelCount(), true); } KisGaussianKernel::applyGaussian(device, rect, horizontalRadius, verticalRadius, channelFlags, progressUpdater); } -QRect KisGaussianBlurFilter::neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisGaussianBlurFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; /** * NOTE: integer devision by two is done on purpose, * because the kernel size is always odd */ const int halfWidth = _config->getProperty("horizRadius", value) ? KisGaussianKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; const int halfHeight = _config->getProperty("vertRadius", value) ? KisGaussianKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } -QRect KisGaussianBlurFilter::changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisGaussianBlurFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const int halfWidth = _config->getProperty("horizRadius", value) ? KisGaussianKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; const int halfHeight = _config->getProperty("vertRadius", value) ? KisGaussianKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5; return rect.adjusted( -halfWidth, -halfHeight, halfWidth, halfHeight); } diff --git a/plugins/filters/blur/kis_gaussian_blur_filter.h b/plugins/filters/blur/kis_gaussian_blur_filter.h index 7fd7b11cf1..cb8349860f 100644 --- a/plugins/filters/blur/kis_gaussian_blur_filter.h +++ b/plugins/filters/blur/kis_gaussian_blur_filter.h @@ -1,50 +1,50 @@ /* This file is part of Krita * * Copyright (c) 2009 Edward Apap * * 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_GAUSSIAN_BLUR_FILTER_H #define KIS_GAUSSIAN_BLUR_FILTER_H #include "filter/kis_filter.h" #include "ui_wdg_gaussian_blur.h" #include class KisGaussianBlurFilter : public KisFilter { public: KisGaussianBlurFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("gaussian blur", i18n("Gaussian Blur")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - QRect neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; - QRect changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; + QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; + QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; }; #endif diff --git a/plugins/filters/blur/kis_lens_blur_filter.cpp b/plugins/filters/blur/kis_lens_blur_filter.cpp index 92a2ffbd48..a1bc478869 100644 --- a/plugins/filters/blur/kis_lens_blur_filter.cpp +++ b/plugins/filters/blur/kis_lens_blur_filter.cpp @@ -1,204 +1,204 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_lens_blur_filter.h" #include "kis_wdg_lens_blur.h" #include #include #include #include "ui_wdg_lens_blur.h" #include #include #include #include #include "kis_lod_transform.h" #include #include KisLensBlurFilter::KisLensBlurFilter() : KisFilter(id(), categoryBlur(), i18n("&Lens Blur...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisLensBlurFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgLensBlur(parent); } -QSize KisLensBlurFilter::getKernelHalfSize(const KisFilterConfiguration* config, int lod) +QSize KisLensBlurFilter::getKernelHalfSize(const KisFilterConfigurationSP config, int lod) { QPolygonF iris = getIrisPolygon(config, lod); QRect rect = iris.boundingRect().toAlignedRect(); int w = std::ceil(qreal(rect.width()) / 2.0); int h = std::ceil(qreal(rect.height()) / 2.0); return QSize(w, h); } -KisFilterConfiguration* KisLensBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisLensBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("irisShape", "Pentagon (5)"); config->setProperty("irisRadius", 5); config->setProperty("irisRotation", 0); QSize halfSize = getKernelHalfSize(config, 0); config->setProperty("halfWidth", halfSize.width()); config->setProperty("halfHeight", halfSize.height()); return config; } -QPolygonF KisLensBlurFilter::getIrisPolygon(const KisFilterConfiguration* config, int lod) +QPolygonF KisLensBlurFilter::getIrisPolygon(const KisFilterConfigurationSP config, int lod) { KIS_ASSERT_RECOVER(config) { return QPolygonF(); } KisLodTransformScalar t(lod); QVariant value; config->getProperty("irisShape", value); QString irisShape = value.toString(); config->getProperty("irisRadius", value); uint irisRadius = t.scale(value.toUInt()); config->getProperty("irisRotation", value); uint irisRotation = value.toUInt(); if (irisRadius < 1) return QPolygon(); QPolygonF irisShapePoly; int sides = 1; qreal angle = 0; if (irisShape == "Triangle") sides = 3; else if (irisShape == "Quadrilateral (4)") sides = 4; else if (irisShape == "Pentagon (5)") sides = 5; else if (irisShape == "Hexagon (6)") sides = 6; else if (irisShape == "Heptagon (7)") sides = 7; else if (irisShape == "Octagon (8)") sides = 8; else return QPolygonF(); for (int i = 0; i < sides; ++i) { irisShapePoly << QPointF(0.5 * cos(angle), 0.5 * sin(angle)); angle += 2 * M_PI / sides; } QTransform transform; transform.rotate(irisRotation); transform.scale(irisRadius * 2, irisRadius * 2); QPolygonF transformedIris = transform.map(irisShapePoly); return transformedIris; } void KisLensBlurFilter::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = rect.topLeft(); Q_ASSERT(device != 0); - if (!config) config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration(id().id(), 1); QBitArray channelFlags; if (config) { channelFlags = config->channelFlags(); - } + } if (channelFlags.isEmpty() || !config) { channelFlags = QBitArray(device->colorSpace()->channelCount(), true); } const int lod = device->defaultBounds()->currentLevelOfDetail(); QPolygonF transformedIris = getIrisPolygon(config, lod); if (transformedIris.isEmpty()) return; QRectF boundingRect = transformedIris.boundingRect(); int kernelWidth = boundingRect.toAlignedRect().width(); int kernelHeight = boundingRect.toAlignedRect().height(); QImage kernelRepresentation(kernelWidth, kernelHeight, QImage::Format_RGB32); kernelRepresentation.fill(0); QPainter imagePainter(&kernelRepresentation); imagePainter.setRenderHint(QPainter::Antialiasing); imagePainter.setBrush(QColor::fromRgb(255, 255, 255)); QTransform offsetTransform; offsetTransform.translate(-boundingRect.x(), -boundingRect.y()); imagePainter.setTransform(offsetTransform); imagePainter.drawPolygon(transformedIris, Qt::WindingFill); // construct kernel from image Eigen::Matrix irisKernel(kernelHeight, kernelWidth); for (int j = 0; j < kernelHeight; ++j) { for (int i = 0; i < kernelWidth; ++i) { irisKernel(j, i) = qRed(kernelRepresentation.pixel(i, j)); } } // apply convolution KisConvolutionPainter painter(device); painter.setChannelFlags(channelFlags); painter.setProgress(progressUpdater); KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMatrix(irisKernel, 0, irisKernel.sum()); painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT); } -QRect KisLensBlurFilter::neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisLensBlurFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const int halfWidth = t.scale(_config->getProperty("halfWidth", value) ? value.toUInt() : 5); const int halfHeight = t.scale(_config->getProperty("halfHeight", value) ? value.toUInt() : 5); return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } -QRect KisLensBlurFilter::changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisLensBlurFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const int halfWidth = t.scale(_config->getProperty("halfWidth", value) ? value.toUInt() : 5); const int halfHeight = t.scale(_config->getProperty("halfHeight", value) ? value.toUInt() : 5); return rect.adjusted(-halfWidth, -halfHeight, halfWidth, halfHeight); } diff --git a/plugins/filters/blur/kis_lens_blur_filter.h b/plugins/filters/blur/kis_lens_blur_filter.h index 8f19045366..1f66559fa0 100644 --- a/plugins/filters/blur/kis_lens_blur_filter.h +++ b/plugins/filters/blur/kis_lens_blur_filter.h @@ -1,59 +1,59 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_LENS_BLUR_FILTER_H #define KIS_LENS_BLUR_FILTER_H #include "filter/kis_filter.h" #include "ui_wdg_lens_blur.h" #include class KisLensBlurFilter : public KisFilter { public: KisLensBlurFilter(); public: void processImpl(KisPaintDeviceSP src, const QRect& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("lens blur", i18n("Lens Blur")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; - static QSize getKernelHalfSize(const KisFilterConfiguration* config, int lod); + static QSize getKernelHalfSize(const KisFilterConfigurationSP config, int lod); - QRect neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; - QRect changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; + QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; + QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: - static QPolygonF getIrisPolygon(const KisFilterConfiguration* config, int lod); + static QPolygonF getIrisPolygon(const KisFilterConfigurationSP config, int lod); }; #endif diff --git a/plugins/filters/blur/kis_motion_blur_filter.cpp b/plugins/filters/blur/kis_motion_blur_filter.cpp index 2924f76717..b691615361 100644 --- a/plugins/filters/blur/kis_motion_blur_filter.cpp +++ b/plugins/filters/blur/kis_motion_blur_filter.cpp @@ -1,166 +1,166 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_motion_blur_filter.h" #include "kis_wdg_motion_blur.h" #include #include #include #include "ui_wdg_motion_blur.h" #include #include #include #include #include "kis_lod_transform.h" #include #include KisMotionBlurFilter::KisMotionBlurFilter() : KisFilter(id(), categoryBlur(), i18n("&Motion Blur...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisMotionBlurFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgMotionBlur(parent); } -KisFilterConfiguration* KisMotionBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisMotionBlurFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("blurAngle", 0); config->setProperty("blurLength", 5); return config; } void KisMotionBlurFilter::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = rect.topLeft(); Q_ASSERT(device != 0); - if (!config) config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration(id().id(), 1); QVariant value; config->getProperty("blurAngle", value); uint blurAngle = value.toUInt(); KisLodTransformScalar t(device); config->getProperty("blurLength", value); uint blurLength = t.scale(value.toUInt()); if (blurLength == 0) return; QBitArray channelFlags; if (config) { channelFlags = config->channelFlags(); } if (channelFlags.isEmpty() || !config) { channelFlags = QBitArray(device->colorSpace()->channelCount(), true); } // convert angle to radians qreal angleRadians = blurAngle / 360.0 * 2 * M_PI; // construct image qreal halfWidth = blurLength / 2.0 * cos(angleRadians); qreal halfHeight = blurLength / 2.0 * sin(angleRadians); int kernelWidth = ceil(fabs(halfWidth)) * 2; int kernelHeight = ceil(fabs(halfHeight)) * 2; // check for zero dimensions (vertical/horizontal motion vectors) kernelWidth = (kernelWidth == 0) ? 1 : kernelWidth; kernelHeight = (kernelHeight == 0) ? 1 : kernelHeight; QImage kernelRepresentation(kernelWidth, kernelHeight, QImage::Format_RGB32); kernelRepresentation.fill(0); QPainter imagePainter(&kernelRepresentation); imagePainter.setRenderHint(QPainter::Antialiasing); imagePainter.setPen(QPen(QColor::fromRgb(255, 255, 255), 1.0)); - imagePainter.drawLine(QPointF(kernelWidth / 2 - halfWidth, kernelHeight / 2 + halfHeight), + imagePainter.drawLine(QPointF(kernelWidth / 2 - halfWidth, kernelHeight / 2 + halfHeight), QPointF(kernelWidth / 2 + halfWidth, kernelHeight / 2 - halfHeight)); // construct kernel from image Eigen::Matrix motionBlurKernel(kernelHeight, kernelWidth); for (int j = 0; j < kernelHeight; ++j) { for (int i = 0; i < kernelWidth; ++i) { motionBlurKernel(j, i) = qRed(kernelRepresentation.pixel(i, j)); } } // apply convolution KisConvolutionPainter painter(device); painter.setChannelFlags(channelFlags); painter.setProgress(progressUpdater); KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMatrix(motionBlurKernel, 0, motionBlurKernel.sum()); painter.applyMatrix(kernel, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT); } -QRect KisMotionBlurFilter::neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisMotionBlurFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; uint blurAngle = _config->getProperty("blurAngle", value) ? value.toUInt() : 0; uint blurLength = t.scale(_config->getProperty("blurLength", value) ? value.toUInt() : 5); qreal angleRadians = blurAngle / 360.0 * 2 * M_PI; const int halfWidth = ceil(fabs(blurLength / 2.0 * cos(angleRadians))); const int halfHeight = ceil(fabs(blurLength / 2.0 * cos(angleRadians))); return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } -QRect KisMotionBlurFilter::changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const +QRect KisMotionBlurFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const { KisLodTransformScalar t(lod); QVariant value; uint blurAngle = _config->getProperty("blurAngle", value) ? value.toUInt() : 0; uint blurLength = t.scale(_config->getProperty("blurLength", value) ? value.toUInt() : 5); qreal angleRadians = blurAngle / 360.0 * 2 * M_PI; const int halfWidth = ceil(fabs(blurLength * cos(angleRadians))); const int halfHeight = ceil(fabs(blurLength * cos(angleRadians))); return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2); } diff --git a/plugins/filters/blur/kis_motion_blur_filter.h b/plugins/filters/blur/kis_motion_blur_filter.h index 9eb31f0546..5a1c4e238b 100644 --- a/plugins/filters/blur/kis_motion_blur_filter.h +++ b/plugins/filters/blur/kis_motion_blur_filter.h @@ -1,52 +1,52 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_MOTION_BLUR_FILTER_H #define KIS_MOTION_BLUR_FILTER_H #include "filter/kis_filter.h" #include "ui_wdg_motion_blur.h" #include class KisMotionBlurFilter : public KisFilter { public: KisMotionBlurFilter(); public: void processImpl(KisPaintDeviceSP src, const QRect& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("motion blur", i18n("Motion Blur")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - QRect neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; - QRect changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; + QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; + QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; }; #endif diff --git a/plugins/filters/blur/kis_wdg_blur.cpp b/plugins/filters/blur/kis_wdg_blur.cpp index beb51140b8..968dcd6cf1 100644 --- a/plugins/filters/blur/kis_wdg_blur.cpp +++ b/plugins/filters/blur/kis_wdg_blur.cpp @@ -1,118 +1,118 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_blur.h" #include #include #include #include #include #include #include #include #include "ui_wdgblur.h" KisWdgBlur::KisWdgBlur(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgBlur(); m_widget->setupUi(this); linkSpacingToggled(true); connect(widget()->aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(linkSpacingToggled(bool))); connect(widget()->intHalfWidth, SIGNAL(valueChanged(int)), this, SLOT(spinBoxHalfWidthChanged(int))); connect(widget()->intHalfHeight, SIGNAL(valueChanged(int)), this, SLOT(spinBoxHalfHeightChanged(int))); connect(widget()->intStrength, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intAngle, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->cbShape, SIGNAL(activated(int)), SIGNAL(sigConfigurationItemChanged())); } KisWdgBlur::~KisWdgBlur() { delete m_widget; } -KisPropertiesConfiguration* KisWdgBlur::configuration() const +KisPropertiesConfigurationSP KisWdgBlur::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("blur", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("blur", 1); config->setProperty("lockAspect", widget()->aspectButton->keepAspectRatio()); config->setProperty("halfWidth", widget()->intHalfWidth->value()); config->setProperty("halfHeight", widget()->intHalfHeight->value()); config->setProperty("rotate", widget()->intAngle->value()); config->setProperty("strength", widget()->intStrength->value()); config->setProperty("shape", widget()->cbShape->currentIndex()); return config; } -void KisWdgBlur::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgBlur::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("lockAspect", value)) { m_widget->aspectButton->setKeepAspectRatio(value.toBool()); } if (config->getProperty("shape", value)) { widget()->cbShape->setCurrentIndex(value.toUInt()); } if (config->getProperty("halfWidth", value)) { widget()->intHalfWidth->setValue(value.toUInt()); } if (config->getProperty("halfHeight", value)) { widget()->intHalfHeight->setValue(value.toUInt()); } if (config->getProperty("rotate", value)) { widget()->intAngle->setValue(value.toUInt()); } if (config->getProperty("strength", value)) { widget()->intStrength->setValue(value.toUInt()); } } void KisWdgBlur::linkSpacingToggled(bool b) { m_halfSizeLink = b; widget()->intHalfHeight->setValue(widget()->intHalfWidth->value()); } void KisWdgBlur::spinBoxHalfWidthChanged(int v) { if (m_halfSizeLink) { widget()->intHalfHeight->setValue(v); } /* if( widget()->intHalfHeight->value() == v && widget()->cbShape->currentItem() != 1) widget()->intAngle->setEnabled(false); else widget()->intAngle->setEnabled(true);*/ emit sigConfigurationItemChanged(); } void KisWdgBlur::spinBoxHalfHeightChanged(int v) { if (m_halfSizeLink) { widget()->intHalfWidth->setValue(v); } /* if( widget()->intHalfWidth->value() == v && widget()->cbShape->currentItem() != 1) widget()->intAngle->setEnabled(false); else widget()->intAngle->setEnabled(true);*/ emit sigConfigurationItemChanged(); } diff --git a/plugins/filters/blur/kis_wdg_blur.h b/plugins/filters/blur/kis_wdg_blur.h index a0e343210a..de60032597 100644 --- a/plugins/filters/blur/kis_wdg_blur.h +++ b/plugins/filters/blur/kis_wdg_blur.h @@ -1,52 +1,52 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_BLUR_H_ #define _KIS_WDG_BLUR_H_ #include class Ui_WdgBlur; class KisWdgBlur : public KisConfigWidget { Q_OBJECT public: KisWdgBlur(QWidget * parent); virtual ~KisWdgBlur(); inline const Ui_WdgBlur* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private Q_SLOTS: void linkSpacingToggled(bool); void spinBoxHalfWidthChanged(int); void spinBoxHalfHeightChanged(int); private: bool m_halfSizeLink; Ui_WdgBlur* m_widget; }; #endif diff --git a/plugins/filters/blur/kis_wdg_gaussian_blur.cpp b/plugins/filters/blur/kis_wdg_gaussian_blur.cpp index 48a9701c26..7e347681a6 100644 --- a/plugins/filters/blur/kis_wdg_gaussian_blur.cpp +++ b/plugins/filters/blur/kis_wdg_gaussian_blur.cpp @@ -1,119 +1,119 @@ /* * This file is part of Krita * * Copyright (c) 2009 Edward Apap * * 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_wdg_gaussian_blur.h" #include #include #include #include #include #include #include #include #include "ui_wdg_gaussian_blur.h" KisWdgGaussianBlur::KisWdgGaussianBlur(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgGaussianBlur(); m_widget->setupUi(this); m_widget->aspectButton->setKeepAspectRatio(false); m_widget->horizontalRadius->setRange(0.0, 100.0, 2); m_widget->horizontalRadius->setSingleStep(0.2); m_widget->horizontalRadius->setValue(0.5); m_widget->horizontalRadius->setSuffix(i18n(" px")); connect(m_widget->horizontalRadius, SIGNAL(valueChanged(qreal)), this, SLOT(horizontalRadiusChanged(qreal))); m_widget->verticalRadius->setRange(0.0, 100.0, 2); m_widget->verticalRadius->setSingleStep(0.2); m_widget->verticalRadius->setValue(0.5); m_widget->verticalRadius->setSuffix(i18n(" px")); connect(m_widget->verticalRadius, SIGNAL(valueChanged(qreal)), this, SLOT(verticalRadiusChanged(qreal))); connect(m_widget->aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(aspectLockChanged(bool))); connect(m_widget->horizontalRadius, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_widget->verticalRadius, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); } KisWdgGaussianBlur::~KisWdgGaussianBlur() { delete m_widget; } -KisPropertiesConfiguration* KisWdgGaussianBlur::configuration() const +KisPropertiesConfigurationSP KisWdgGaussianBlur::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("gaussian blur", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("gaussian blur", 1); config->setProperty("horizRadius", m_widget->horizontalRadius->value()); config->setProperty("vertRadius", m_widget->verticalRadius->value()); config->setProperty("lockAspect", m_widget->aspectButton->keepAspectRatio()); return config; } -void KisWdgGaussianBlur::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgGaussianBlur::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("horizRadius", value)) { m_widget->horizontalRadius->setValue(value.toFloat()); } if (config->getProperty("vertRadius", value)) { m_widget->verticalRadius->setValue(value.toFloat()); } if (config->getProperty("lockAspect", value)) { m_widget->aspectButton->setKeepAspectRatio(value.toBool()); } } void KisWdgGaussianBlur::horizontalRadiusChanged(qreal v) { m_widget->horizontalRadius->blockSignals(true); m_widget->horizontalRadius->setValue(v); m_widget->horizontalRadius->blockSignals(false); if (m_widget->aspectButton->keepAspectRatio()) { m_widget->verticalRadius->blockSignals(true); m_widget->verticalRadius->setValue(v); m_widget->verticalRadius->blockSignals(false); } } void KisWdgGaussianBlur::verticalRadiusChanged(qreal v) { m_widget->verticalRadius->blockSignals(true); m_widget->verticalRadius->setValue(v); m_widget->verticalRadius->blockSignals(false); if (m_widget->aspectButton->keepAspectRatio()) { m_widget->horizontalRadius->blockSignals(true); m_widget->horizontalRadius->setValue(v); m_widget->horizontalRadius->blockSignals(false); } } void KisWdgGaussianBlur::aspectLockChanged(bool v) { if (v) { m_widget->verticalRadius->setValue( m_widget->horizontalRadius->value() ); } } diff --git a/plugins/filters/blur/kis_wdg_gaussian_blur.h b/plugins/filters/blur/kis_wdg_gaussian_blur.h index fd4a98c55d..35bb17bad7 100644 --- a/plugins/filters/blur/kis_wdg_gaussian_blur.h +++ b/plugins/filters/blur/kis_wdg_gaussian_blur.h @@ -1,49 +1,49 @@ /* * This file is part of Krita * * Copyright (c) 2009 Edward Apap * * 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_WDG_GAUSSIAN_BLUR_H_ #define _KIS_WDG_GAUSSIAN_BLUR_H_ #include class Ui_WdgGaussianBlur; class KisWdgGaussianBlur : public KisConfigWidget { Q_OBJECT public: KisWdgGaussianBlur(QWidget * parent); virtual ~KisWdgGaussianBlur(); inline const Ui_WdgGaussianBlur* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private Q_SLOTS: void horizontalRadiusChanged(qreal); void verticalRadiusChanged(qreal); void aspectLockChanged(bool); private: Ui_WdgGaussianBlur* m_widget; }; #endif diff --git a/plugins/filters/blur/kis_wdg_lens_blur.cpp b/plugins/filters/blur/kis_wdg_lens_blur.cpp index eeb82a414f..74bb07a196 100644 --- a/plugins/filters/blur/kis_wdg_lens_blur.cpp +++ b/plugins/filters/blur/kis_wdg_lens_blur.cpp @@ -1,82 +1,82 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_wdg_lens_blur.h" #include #include #include #include #include #include #include #include #include "kis_lens_blur_filter.h" #include "ui_wdg_lens_blur.h" KisWdgLensBlur::KisWdgLensBlur(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgLensBlur(); m_widget->setupUi(this); connect(m_widget->irisShapeCombo, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_widget->irisRadiusSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_widget->irisRotationSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); } KisWdgLensBlur::~KisWdgLensBlur() { delete m_widget; } -KisPropertiesConfiguration* KisWdgLensBlur::configuration() const +KisPropertiesConfigurationSP KisWdgLensBlur::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("lens blur", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("lens blur", 1); config->setProperty("irisShape", m_widget->irisShapeCombo->currentText()); config->setProperty("irisRadius", m_widget->irisRadiusSlider->value()); config->setProperty("irisRotation", m_widget->irisRotationSlider->value()); QSize halfSize = KisLensBlurFilter::getKernelHalfSize(config, 0); config->setProperty("halfWidth", halfSize.width()); config->setProperty("halfHeight", halfSize.height()); return config; } -void KisWdgLensBlur::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgLensBlur::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("irisShape", value)) { for (int i = 0; i < m_widget->irisShapeCombo->count(); ++i) { if (value.toString() == m_widget->irisShapeCombo->itemText(i)) { m_widget->irisShapeCombo->setCurrentIndex(i); } } } if (config->getProperty("irisRadius", value)) { m_widget->irisRadiusSlider->setValue(value.toInt()); } if (config->getProperty("irisRotation", value)) { m_widget->irisRotationSlider->setValue(value.toInt()); } } diff --git a/plugins/filters/blur/kis_wdg_lens_blur.h b/plugins/filters/blur/kis_wdg_lens_blur.h index d347a6971e..0f573573d8 100644 --- a/plugins/filters/blur/kis_wdg_lens_blur.h +++ b/plugins/filters/blur/kis_wdg_lens_blur.h @@ -1,43 +1,43 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_WDG_LENS_BLUR_H_ #define _KIS_WDG_LENS_BLUR_H_ #include class Ui_WdgLensBlur; class KisWdgLensBlur : public KisConfigWidget { Q_OBJECT public: KisWdgLensBlur(QWidget * parent); virtual ~KisWdgLensBlur(); inline const Ui_WdgLensBlur* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgLensBlur* m_widget; }; #endif diff --git a/plugins/filters/blur/kis_wdg_motion_blur.cpp b/plugins/filters/blur/kis_wdg_motion_blur.cpp index 93aefb6461..b3c325bd75 100644 --- a/plugins/filters/blur/kis_wdg_motion_blur.cpp +++ b/plugins/filters/blur/kis_wdg_motion_blur.cpp @@ -1,96 +1,96 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_wdg_motion_blur.h" #include #include #include #include #include #include #include #include #include "ui_wdg_motion_blur.h" KisWdgMotionBlur::KisWdgMotionBlur(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgMotionBlur(); m_widget->setupUi(this); connect(m_widget->blurAngleSlider, SIGNAL(valueChanged(int)), SLOT(angleSliderChanged(int))); connect(m_widget->blurAngleDial, SIGNAL(valueChanged(int)), SLOT(angleDialChanged(int))); connect(m_widget->blurAngleSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_widget->blurLength, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); } KisWdgMotionBlur::~KisWdgMotionBlur() { delete m_widget; } -KisPropertiesConfiguration* KisWdgMotionBlur::configuration() const +KisPropertiesConfigurationSP KisWdgMotionBlur::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("motion blur", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("motion blur", 1); config->setProperty("blurAngle", m_widget->blurAngleSlider->value()); config->setProperty("blurLength", m_widget->blurLength->value()); return config; } -void KisWdgMotionBlur::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgMotionBlur::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("blurAngle", value)) { m_widget->blurAngleSlider->setValue(value.toInt()); } if (config->getProperty("blurLength", value)) { m_widget->blurLength->setValue(value.toInt()); } } void KisWdgMotionBlur::angleSliderChanged(int v) { int absoluteValue = -v + 270; if (absoluteValue < 0) { absoluteValue += 360; } else if (absoluteValue > 360) { absoluteValue = absoluteValue - 360; } m_widget->blurAngleDial->setValue(absoluteValue); } void KisWdgMotionBlur::angleDialChanged(int v) { int absoluteValue = v - 270; if (absoluteValue < 0) { absoluteValue = 360 + absoluteValue; } absoluteValue = -absoluteValue; if (absoluteValue < 0) { absoluteValue += 360; } m_widget->blurAngleSlider->setValue(absoluteValue); } diff --git a/plugins/filters/blur/kis_wdg_motion_blur.h b/plugins/filters/blur/kis_wdg_motion_blur.h index 7b897642ce..29749d3432 100644 --- a/plugins/filters/blur/kis_wdg_motion_blur.h +++ b/plugins/filters/blur/kis_wdg_motion_blur.h @@ -1,46 +1,46 @@ /* * This file is part of Krita * * Copyright (c) 2010 Edward Apap * * 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_WDG_MOTION_BLUR_H_ #define _KIS_WDG_MOTION_BLUR_H_ #include class Ui_WdgMotionBlur; class KisWdgMotionBlur : public KisConfigWidget { Q_OBJECT public: KisWdgMotionBlur(QWidget * parent); virtual ~KisWdgMotionBlur(); inline const Ui_WdgMotionBlur* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; public Q_SLOTS: void angleSliderChanged(int); void angleDialChanged(int); private: Ui_WdgMotionBlur* m_widget; }; #endif diff --git a/plugins/filters/colors/kis_color_to_alpha.cpp b/plugins/filters/colors/kis_color_to_alpha.cpp index 82d626008d..dd2ffba258 100644 --- a/plugins/filters/colors/kis_color_to_alpha.cpp +++ b/plugins/filters/colors/kis_color_to_alpha.cpp @@ -1,191 +1,191 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_color_to_alpha.h" #include #include #include #include #include "kis_progress_update_helper.h" #include #include #include #include #include "ui_wdgcolortoalphabase.h" #include "kis_wdg_color_to_alpha.h" #include KisFilterColorToAlpha::KisFilterColorToAlpha() : KisFilter(id(), categoryColors(), i18n("&Color to Alpha...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisFilterColorToAlpha::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgColorToAlpha(parent); } -KisFilterConfiguration* KisFilterColorToAlpha::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterColorToAlpha::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("colortoalpha", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("colortoalpha", 1); config->setProperty("targetcolor", QColor(255, 255, 255)); config->setProperty("threshold", 100); return config; } template inline void inverseOver(const int numChannels, const int *channelIndex, channel_type *dst, const channel_type *baseColor, qreal dstOpacity) { for (int i = 0; i < numChannels; i++) { const int idx = channelIndex[i]; dst[idx] = KoColorSpaceMaths::clamp( (static_cast(dst[idx]) - baseColor[idx]) / dstOpacity + baseColor[idx]); } } template void applyToIterator(const int numChannels, const int *channelIndex, KisSequentialIterator &it, KoColor baseColor, int threshold, const KoColorSpace *cs, KisProgressUpdateHelper &progressHelper) { qreal thresholdF = threshold; quint8 *baseColorData_uint8 = baseColor.data(); channel_type *baseColorData = reinterpret_cast(baseColorData_uint8); do { channel_type *dst = reinterpret_cast(it.rawData()); quint8 *dst_uint8 = it.rawData(); quint8 diff = cs->difference(baseColorData_uint8, dst_uint8); qreal newOpacity = diff >= threshold ? 1.0 : diff / thresholdF; if(newOpacity < cs->opacityF(dst_uint8)) { cs->setOpacity(dst_uint8, newOpacity, 1); } inverseOver(numChannels, channelIndex, dst, baseColorData, newOpacity); progressHelper.step(); } while(it.nextPixel()); } void KisFilterColorToAlpha::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { Q_ASSERT(device != 0); - if (config == 0) config = new KisFilterConfiguration("colortoalpha", 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration("colortoalpha", 1); QVariant value; QColor cTA = (config->getProperty("targetcolor", value)) ? value.value() : QColor(255, 255, 255); int threshold = (config->getProperty("threshold", value)) ? value.toInt() : 1; const KoColorSpace * cs = device->colorSpace(); KisProgressUpdateHelper progressHelper(progressUpdater, 100, rect.width() * rect.height()); KisSequentialIterator it(device, rect); KoColor baseColor(cTA, cs); QVector channelIndex; KoChannelInfo::enumChannelValueType valueType = KoChannelInfo::OTHER; QList channels = cs->channels(); for (int i = 0; i < channels.size(); i++) { const KoChannelInfo *info = channels[i]; if (info->channelType() != KoChannelInfo::COLOR) continue; KoChannelInfo::enumChannelValueType currentValueType = info->channelValueType(); if (valueType != KoChannelInfo::OTHER && valueType != currentValueType) { warnKrita << "Cannot apply a Color-to-Alpha filter to a heterogeneous colorspace"; return; } else { valueType = currentValueType; } channelIndex.append(i); } switch (valueType) { case KoChannelInfo::UINT8: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; case KoChannelInfo::UINT16: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; case KoChannelInfo::UINT32: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; case KoChannelInfo::FLOAT32: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; case KoChannelInfo::FLOAT64: applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; case KoChannelInfo::FLOAT16: #include #ifdef HAVE_OPENEXR #include applyToIterator(channelIndex.size(), channelIndex.data(), it, baseColor, threshold, cs, progressHelper); break; #endif case KoChannelInfo::INT8: /* !UNSUPPORTED! */ case KoChannelInfo::INT16: /* !UNSUPPORTED! */ case KoChannelInfo::OTHER: warnKrita << "Color To Alpha: Unsupported channel type:" << valueType; } } diff --git a/plugins/filters/colors/kis_color_to_alpha.h b/plugins/filters/colors/kis_color_to_alpha.h index cbeec8d809..0fffc0d18c 100644 --- a/plugins/filters/colors/kis_color_to_alpha.h +++ b/plugins/filters/colors/kis_color_to_alpha.h @@ -1,49 +1,49 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_COLOR_TO_ALPHA_H_ #define KIS_COLOR_TO_ALPHA_H_ #include "filter/kis_filter.h" class KisFilterColorToAlpha : public KisFilter { public: KisFilterColorToAlpha(); void processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("colortoalpha", i18n("Color to Alpha")); } public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP dev) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/filters/colors/kis_minmax_filters.cpp b/plugins/filters/colors/kis_minmax_filters.cpp index e1ec2e3761..8f1380a0ad 100644 --- a/plugins/filters/colors/kis_minmax_filters.cpp +++ b/plugins/filters/colors/kis_minmax_filters.cpp @@ -1,152 +1,152 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_minmax_filters.h" #include #include #include #include #include #include #include typedef void (*funcMaxMin)(const quint8* , quint8* , uint); template void maximize(const quint8* s, quint8* d, uint nbpixels) { const _TYPE* sT = (_TYPE*)(s); _TYPE* dT = (_TYPE*)(d); _TYPE vmax = *sT; for (uint i = 1; i < nbpixels; i ++) { if (sT[i] > vmax) { vmax = sT[i]; } } for (uint i = 0; i < nbpixels; i ++) { if (dT[i] != vmax) { dT[i] = 0; } } } template void minimize(const quint8* s, quint8* d, uint nbpixels) { const _TYPE* sT = (_TYPE*)(s); _TYPE* dT = (_TYPE*)(d); _TYPE vmin = *sT; for (uint i = 1; i < nbpixels; i ++) { if (sT[i] < vmin) { vmin = sT[i]; } } for (uint i = 0; i < nbpixels; i ++) { if (dT[i] != vmin) { dT[i] = 0; } } } KisFilterMax::KisFilterMax() : KisFilter(id(), categoryColors(), i18n("M&aximize Channel")) { setSupportsPainting(true); setSupportsLevelOfDetail(true); setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(false); } void KisFilterMax::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_UNUSED(config); Q_ASSERT(device != 0); int pixelsProcessed = 0; int totalCost = rect.width() * rect.height() / 100; const KoColorSpace * cs = device->colorSpace(); qint32 nC = cs->colorChannelCount(); funcMaxMin F; KoChannelInfo::enumChannelValueType cT = cs->channels()[0]->channelValueType(); if (cT == KoChannelInfo::UINT8 || cT == KoChannelInfo::INT8) { F = & maximize; } else if (cT == KoChannelInfo::UINT16 || cT == KoChannelInfo::INT16) { F = & maximize; } else if (cT == KoChannelInfo::FLOAT32) { F = & maximize; } else { return; } KisSequentialIterator it(device, rect); do { F(it.oldRawData(), it.rawData(), nC); if (progressUpdater) progressUpdater->setProgress((++pixelsProcessed) / totalCost); } while(it.nextPixel()); } KisFilterMin::KisFilterMin() : KisFilter(id(), categoryColors(), i18n("M&inimize Channel")) { setSupportsPainting(true); setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(false); } void KisFilterMin::processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_UNUSED(config); Q_ASSERT(device != 0); int pixelsProcessed = 0; int totalCost = rect.width() * rect.height() / 100; if (totalCost == 0) totalCost = 1; const KoColorSpace * cs = device->colorSpace(); qint32 nC = cs->colorChannelCount(); funcMaxMin F; KoChannelInfo::enumChannelValueType cT = cs->channels()[0]->channelValueType(); if (cT == KoChannelInfo::UINT8 || cT == KoChannelInfo::INT8) { F = & minimize; } else if (cT == KoChannelInfo::UINT16 || cT == KoChannelInfo::INT16) { F = & minimize; } else if (cT == KoChannelInfo::FLOAT32) { F = & minimize; } else { return; } KisSequentialIterator it(device, rect); do { F(it.oldRawData(), it.rawData(), nC); if (progressUpdater) progressUpdater->setProgress((++pixelsProcessed) / totalCost); } while(it.nextPixel()); } diff --git a/plugins/filters/colors/kis_minmax_filters.h b/plugins/filters/colors/kis_minmax_filters.h index e5cbca48d8..fca02f4f6a 100644 --- a/plugins/filters/colors/kis_minmax_filters.h +++ b/plugins/filters/colors/kis_minmax_filters.h @@ -1,60 +1,60 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_MINMAX_FILTERS_H #define KIS_MINMAX_FILTERS_H #include "filter/kis_filter.h" class KisFilterMax : public KisFilter { public: KisFilterMax(); void processImpl(KisPaintDeviceSP src, const QRect& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("maximize", i18n("Maximize Channel")); } }; class KisFilterMin : public KisFilter { public: KisFilterMin(); public: void processImpl(KisPaintDeviceSP device, const QRect& rect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("minimize", i18n("Minimize Channel")); } }; #endif diff --git a/plugins/filters/colors/kis_wdg_color_to_alpha.cpp b/plugins/filters/colors/kis_wdg_color_to_alpha.cpp index 1d13900252..c92c841b36 100644 --- a/plugins/filters/colors/kis_wdg_color_to_alpha.cpp +++ b/plugins/filters/colors/kis_wdg_color_to_alpha.cpp @@ -1,127 +1,127 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_color_to_alpha.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_wdgcolortoalphabase.h" KisWdgColorToAlpha::KisWdgColorToAlpha(QWidget * parent) : KisConfigWidget(parent), m_view(0) { m_widget = new Ui_WdgColorToAlphaBase(); m_widget->setupUi(this); m_widget->textLabel1->hide(); m_widget->intThreshold->setRange(1, 255, 0); connect(m_widget->colorSelector, SIGNAL(sigNewColor(KoColor)), SLOT(slotColorSelectorChanged(const KoColor&))); connect(m_widget->intThreshold, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_widget->btnCustomColor, SIGNAL(changed(const KoColor)), SLOT(slotCustomColorSelected(const KoColor&))); KoColor c(Qt::white, KoColorSpaceRegistry::instance()->rgb8()); m_widget->btnCustomColor->setColor(c); } KisWdgColorToAlpha::~KisWdgColorToAlpha() { delete m_widget; } void KisWdgColorToAlpha::setView(KisViewManager *view) { m_view = view; } void KisWdgColorToAlpha::slotFgColorChanged(const KoColor &color) { m_widget->btnCustomColor->setColor(color); } void KisWdgColorToAlpha::slotColorSelectorChanged(const KoColor &color) { m_widget->btnCustomColor->setColor(color); } void KisWdgColorToAlpha::slotCustomColorSelected(const KoColor &color) { m_widget->colorSelector->slotSetColor(color); emit sigConfigurationItemChanged(); } -void KisWdgColorToAlpha::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgColorToAlpha::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("targetcolor", value)) { KoColor c; if (value.value().isValid()) { c.fromQColor(value.value()); } else { c = value.value(); } m_widget->colorSelector->slotSetColor(c); } if (config->getProperty("threshold", value)) { m_widget->intThreshold->setValue(value.toInt()); } } -KisPropertiesConfiguration* KisWdgColorToAlpha::configuration() const +KisPropertiesConfigurationSP KisWdgColorToAlpha::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("colortoalpha", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("colortoalpha", 1); config->setProperty("targetcolor", widget()->colorSelector->getCurrentColor().toQColor()); config->setProperty("threshold", widget()->intThreshold->value()); return config; } void KisWdgColorToAlpha::hideEvent(QHideEvent *) { if (m_view) { disconnect(m_view->resourceProvider(), SIGNAL(sigFGColorChanged(const KoColor&)), this, SLOT(slotFgColorChanged(const KoColor&))); KoToolManager::instance()->switchBackRequested(); } } void KisWdgColorToAlpha::showEvent(QShowEvent *) { if (m_view) { connect(m_view->resourceProvider(), SIGNAL(sigFGColorChanged(const KoColor&)), this, SLOT(slotFgColorChanged(const KoColor&))); KoToolManager::instance()->switchToolTemporaryRequested("KritaSelected/KisToolColorPicker"); } } diff --git a/plugins/filters/colors/kis_wdg_color_to_alpha.h b/plugins/filters/colors/kis_wdg_color_to_alpha.h index 2a2937d253..44e83ef423 100644 --- a/plugins/filters/colors/kis_wdg_color_to_alpha.h +++ b/plugins/filters/colors/kis_wdg_color_to_alpha.h @@ -1,60 +1,60 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_COLOR_TO_ALPHA_H_ #define _KIS_WDG_COLOR_TO_ALPHA_H_ #include class KoColor; class Ui_WdgColorToAlphaBase; class KisWdgColorToAlpha : public KisConfigWidget { Q_OBJECT public: KisWdgColorToAlpha(QWidget * parent); virtual ~KisWdgColorToAlpha(); inline const Ui_WdgColorToAlphaBase* widget() const { return m_widget; } void setView(KisViewManager *view); - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; protected: void hideEvent(QHideEvent *); void showEvent(QShowEvent *); private Q_SLOTS: void slotFgColorChanged(const KoColor &color); void slotColorSelectorChanged(const KoColor &color); void slotCustomColorSelected(const KoColor &color); private: Ui_WdgColorToAlphaBase* m_widget; KisViewManager *m_view; }; #endif diff --git a/plugins/filters/colorsfilters/colorsfilters.cpp b/plugins/filters/colorsfilters/colorsfilters.cpp index 71215ad975..51d50e5140 100644 --- a/plugins/filters/colorsfilters/colorsfilters.cpp +++ b/plugins/filters/colorsfilters/colorsfilters.cpp @@ -1,181 +1,181 @@ /* * This file is part of Krita * * Copyright (c) 2004 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. */ #include "colorsfilters.h" #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_hsv_adjustment_filter.h" #include "kis_brightness_contrast_filter.h" #include "kis_perchannel_filter.h" #include "kis_color_balance_filter.h" #include "kis_desaturate_filter.h" K_PLUGIN_FACTORY_WITH_JSON(ColorsFiltersFactory, "kritacolorsfilter.json", registerPlugin();) ColorsFilters::ColorsFilters(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry * manager = KisFilterRegistry::instance(); manager->add(new KisBrightnessContrastFilter()); manager->add(new KisAutoContrast()); manager->add(new KisPerChannelFilter()); manager->add(new KisDesaturateFilter()); manager->add(new KisHSVAdjustmentFilter()); manager->add(new KisColorBalanceFilter()); } ColorsFilters::~ColorsFilters() { } //================================================================== KisAutoContrast::KisAutoContrast() : KisFilter(id(), categoryAdjust(), i18n("&Auto Contrast")) { setSupportsPainting(false); setSupportsThreading(false); setSupportsAdjustmentLayers(false); setColorSpaceIndependence(TO_LAB16); setShowConfigurationWidget(false); } void KisAutoContrast::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { Q_ASSERT(device != 0); Q_UNUSED(config); // initialize KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); KisHistogram histogram(device, applyRect, producer, LINEAR); int minvalue = int(255 * histogram.calculations().getMin() + 0.5); int maxvalue = int(255 * histogram.calculations().getMax() + 0.5); if (maxvalue > 255) maxvalue = 255; histogram.setChannel(0); int twoPercent = int(0.005 * histogram.calculations().getCount()); int pixCount = 0; int binnum = 0; while (binnum < histogram.producer()->numberOfBins()) { pixCount += histogram.getValue(binnum); if (pixCount > twoPercent) { minvalue = binnum; break; } binnum++; } pixCount = 0; binnum = histogram.producer()->numberOfBins() - 1; while (binnum > 0) { pixCount += histogram.getValue(binnum); if (pixCount > twoPercent) { maxvalue = binnum; break; } binnum--; } // build the transferfunction int diff = maxvalue - minvalue; quint16* transfer = new quint16[256]; for (int i = 0; i < 255; i++) transfer[i] = 0xFFFF; if (diff != 0) { for (int i = 0; i < minvalue; i++) transfer[i] = 0x0; for (int i = minvalue; i < maxvalue; i++) { qint32 val = (i - minvalue) / diff; val = int((0xFFFF * (i - minvalue)) / diff); if (val > 0xFFFF) val = 0xFFFF; if (val < 0) val = 0; transfer[i] = val; } for (int i = maxvalue; i < 256; i++) transfer[i] = 0xFFFF; } // apply KoColorTransformation *adj = device->colorSpace()->createBrightnessContrastAdjustment(transfer); KisSequentialIterator it(device, applyRect); qint32 totalCost = (applyRect.width() * applyRect.height()) / 100; if (totalCost == 0) totalCost = 1; qint32 pixelsProcessed = 0; quint32 npix; do { npix = it.nConseqPixels(); // adjust adj->transform(it.oldRawData(), it.rawData(), npix); pixelsProcessed += npix; if (progressUpdater) progressUpdater->setProgress(pixelsProcessed / totalCost); } while(it.nextPixels(npix) && !(progressUpdater && progressUpdater->interrupted())); delete[] transfer; delete adj; } #include "colorsfilters.moc" diff --git a/plugins/filters/colorsfilters/colorsfilters.h b/plugins/filters/colorsfilters/colorsfilters.h index b7cf0c16a8..40e84aba19 100644 --- a/plugins/filters/colorsfilters/colorsfilters.h +++ b/plugins/filters/colorsfilters/colorsfilters.h @@ -1,55 +1,55 @@ /* * This file is part of Krita * * Copyright (c) 2004 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 COLORSFILTERS_H #define COLORSFILTERS_H #include #include #include "kis_perchannel_filter.h" #include "filter/kis_color_transformation_filter.h" class ColorsFilters : public QObject { Q_OBJECT public: ColorsFilters(QObject *parent, const QVariantList &); virtual ~ColorsFilters(); }; class KisAutoContrast : public KisFilter { public: KisAutoContrast(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("autocontrast", i18n("Auto Contrast")); } }; #endif diff --git a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp index e203744fc9..2401b0dce6 100644 --- a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp +++ b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cpp @@ -1,302 +1,302 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2005 C. Boemann * * 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_brightness_contrast_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include "KoColorSpace.h" #include "KoColorTransformation.h" #include "KoCompositeOp.h" #include #include "kis_config_widget.h" #include "kis_bookmarked_configuration_manager.h" #include "kis_paint_device.h" #include "widgets/kis_curve_widget.h" #include "kis_histogram.h" #include "kis_painter.h" #include #include #include KisBrightnessContrastFilterConfiguration::KisBrightnessContrastFilterConfiguration() : KisColorTransformationConfiguration("brightnesscontrast", 1) { } KisBrightnessContrastFilterConfiguration::~KisBrightnessContrastFilterConfiguration() { } void KisBrightnessContrastFilterConfiguration::fromLegacyXML(const QDomElement& root) { fromXML(root); } void KisBrightnessContrastFilterConfiguration::updateTransfer() { m_transfer = m_curve.uint16Transfer(); } void KisBrightnessContrastFilterConfiguration::setCurve(const KisCubicCurve &curve) { m_curve = curve; updateTransfer(); } const QVector& KisBrightnessContrastFilterConfiguration::transfer() const { return m_transfer; } const KisCubicCurve& KisBrightnessContrastFilterConfiguration::curve() const { return m_curve; } void KisBrightnessContrastFilterConfiguration::fromXML(const QDomElement& root) { KisCubicCurve curve; int version; version = root.attribute("version").toInt(); QDomElement e = root.firstChild().toElement(); QString attributeName; while (!e.isNull()) { if ((attributeName = e.attribute("name")) != "nTransfers") { QRegExp rx("curve(\\d+)"); if (rx.indexIn(attributeName, 0) != -1) { quint16 index = rx.cap(1).toUShort(); if (index == 0 && !e.text().isEmpty()) { /** * We are going to use first curve only */ curve.fromString(e.text()); } } } e = e.nextSiblingElement(); } setVersion(version); setCurve(curve); } /** * Inherited from KisPropertiesConfiguration */ //void KisPerChannelFilterConfiguration::fromXML(const QString& s) void KisBrightnessContrastFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { /** * * 1 * 0,0;0.5,0.5;1,1; * */ /* This is a constant for Brightness/Contranst filter */ const qint32 numTransfers = 1; root.setAttribute("version", version()); QDomElement t = doc.createElement("param"); QDomText text = doc.createTextNode(QString::number(numTransfers)); t.setAttribute("name", "nTransfers"); t.appendChild(text); root.appendChild(t); t = doc.createElement("param"); t.setAttribute("name", "curve0"); text = doc.createTextNode(m_curve.toString()); t.appendChild(text); root.appendChild(t); } /** * Inherited from KisPropertiesConfiguration */ //QString KisPerChannelFilterConfiguration::toXML() KisBrightnessContrastFilter::KisBrightnessContrastFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Brightness/Contrast curve...")) { setSupportsPainting(false); setColorSpaceIndependence(TO_LAB16); } KisConfigWidget * KisBrightnessContrastFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisBrightnessContrastConfigWidget(parent, dev); } -KisFilterConfiguration* KisBrightnessContrastFilter::factoryConfiguration(const KisPaintDeviceSP) +KisFilterConfigurationSP KisBrightnessContrastFilter::factoryConfiguration(const KisPaintDeviceSP) const { return new KisBrightnessContrastFilterConfiguration(); } -KoColorTransformation* KisBrightnessContrastFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisBrightnessContrastFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { - const KisBrightnessContrastFilterConfiguration* configBC = dynamic_cast(config); + const KisBrightnessContrastFilterConfiguration* configBC = dynamic_cast(config.data()); if (!configBC) return 0; KoColorTransformation * adjustment = cs->createBrightnessContrastAdjustment(configBC->transfer().constData()); return adjustment; } KisBrightnessContrastConfigWidget::KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f) : KisConfigWidget(parent, f) { int i; int height; m_page = new WdgBrightnessContrast(this); QHBoxLayout * l = new QHBoxLayout(this); Q_CHECK_PTR(l); //Hide these buttons and labels as they are not implemented in 1.5 m_page->pb_more_contrast->hide(); m_page->pb_less_contrast->hide(); m_page->pb_more_brightness->hide(); m_page->pb_less_brightness->hide(); m_page->textLabelBrightness->hide(); m_page->textLabelContrast->hide(); l->addWidget(m_page, 1, Qt::AlignTop); l->setContentsMargins(0,0,0,0); - + height = 256; connect(m_page->curveWidget, SIGNAL(modified()), SIGNAL(sigConfigurationItemChanged())); // Create the horizontal gradient label QPixmap hgradientpix(256, 1); QPainter hgp(&hgradientpix); hgp.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (i = 0; i < 256; ++i) { hgp.setPen(QColor(i, i, i)); hgp.drawPoint(i, 0); } m_page->hgradient->setPixmap(hgradientpix); // Create the vertical gradient label QPixmap vgradientpix(1, 256); QPainter vgp(&vgradientpix); vgp.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (i = 0; i < 256; ++i) { vgp.setPen(QColor(i, i, i)); vgp.drawPoint(0, 255 - i); } m_page->vgradient->setPixmap(vgradientpix); KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); KisHistogram histogram(dev, dev->exactBounds(), producer, LINEAR); QPalette appPalette = QApplication::palette(); QPixmap pix(256, height); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); double highest = (double)histogram.calculations().getHighest(); qint32 bins = histogram.producer()->numberOfBins(); if (histogram.getHistogramType() == LINEAR) { double factor = (double)height / highest; for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(histogram.getValue(i) * factor)); } } else { double factor = (double)height / (double)log(highest); for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(log((double)histogram.getValue(i)) * factor)); } } m_page->curveWidget->setPixmap(pix); m_page->curveWidget->setBasePixmap(pix); } KisBrightnessContrastConfigWidget::~KisBrightnessContrastConfigWidget() { KoToolManager::instance()->switchBackRequested(); delete m_page; } -KisBrightnessContrastFilterConfiguration * KisBrightnessContrastConfigWidget::configuration() const +KisPropertiesConfigurationSP KisBrightnessContrastConfigWidget::configuration() const { KisBrightnessContrastFilterConfiguration * cfg = new KisBrightnessContrastFilterConfiguration(); cfg->setCurve(m_page->curveWidget->curve()); return cfg; } void KisBrightnessContrastConfigWidget::slotDrawLine(const KoColor &color) { QColor colorNew = color.toQColor(); int i = (colorNew.red() + colorNew.green() + colorNew.blue())/3 ; QPixmap pix = m_page->curveWidget->getBasePixmap(); QPainter p(&pix); p.setPen(QPen(Qt::black, 1, Qt::SolidLine)); p.drawLine(i,0,i,255); QString label = "x:"; label.insert(2,QString(QString::number(i))); p.drawText(i,250,label); m_page->curveWidget->setPixmap(pix); } void KisBrightnessContrastConfigWidget::setView(KisViewManager *view) { connect(view->resourceProvider(), SIGNAL(sigFGColorChanged(const KoColor&)), this, SLOT(slotDrawLine(const KoColor&))); KoToolManager::instance()->switchToolTemporaryRequested("KritaSelected/KisToolColorPicker"); } -void KisBrightnessContrastConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisBrightnessContrastConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { - const KisBrightnessContrastFilterConfiguration * cfg = dynamic_cast(config); + const KisBrightnessContrastFilterConfiguration * cfg = dynamic_cast(config.data()); Q_ASSERT(cfg); m_page->curveWidget->setCurve(cfg->curve()); } diff --git a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h index 46e9f93eaa..6a0f8a9739 100644 --- a/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h +++ b/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h @@ -1,116 +1,116 @@ /* * This file is part of Krita * * Copyright (c) 2004 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_BRIGHTNESS_CONTRAST_FILTER_H_ #define _KIS_BRIGHTNESS_CONTRAST_FILTER_H_ #include #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" #include "ui_wdg_brightness_contrast.h" #include #include #include #include #include class QWidget; class KoColorTransformation; class WdgBrightnessContrast : public QWidget, public Ui::WdgBrightnessContrast { Q_OBJECT public: WdgBrightnessContrast(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KisBrightnessContrastFilterConfiguration : public KisColorTransformationConfiguration { - + public: using KisFilterConfiguration::fromXML; using KisFilterConfiguration::toXML; using KisFilterConfiguration::fromLegacyXML; virtual void fromLegacyXML(const QDomElement& root); virtual void fromXML(const QDomElement& e); virtual void toXML(QDomDocument& doc, QDomElement& root) const; KisBrightnessContrastFilterConfiguration(); virtual ~KisBrightnessContrastFilterConfiguration(); virtual void setCurve(const KisCubicCurve &curve); const QVector& transfer() const; virtual const KisCubicCurve& curve() const; private: void updateTransfer(); private: KisCubicCurve m_curve; QVector m_transfer; }; /** * This class affect Intensity Y of the image */ class KisBrightnessContrastFilter : public KisColorTransformationFilter { public: KisBrightnessContrastFilter(); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("brightnesscontrast", i18n("Brightness / Contrast")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; class KisBrightnessContrastConfigWidget : public KisConfigWidget { Q_OBJECT public: KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); virtual ~KisBrightnessContrastConfigWidget(); - virtual KisBrightnessContrastFilterConfiguration * configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); WdgBrightnessContrast * m_page; void setView(KisViewManager *view); public Q_SLOTS: void slotDrawLine(const KoColor &color); }; #endif diff --git a/plugins/filters/colorsfilters/kis_color_balance_filter.cpp b/plugins/filters/colorsfilters/kis_color_balance_filter.cpp index 1ee4c85d6c..58e21f2430 100644 --- a/plugins/filters/colorsfilters/kis_color_balance_filter.cpp +++ b/plugins/filters/colorsfilters/kis_color_balance_filter.cpp @@ -1,205 +1,205 @@ /* * Copyright (c) 2013 Sahil Nagpal * * 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_balance_filter.h" #include "filter/kis_color_transformation_configuration.h" #include "kis_selection.h" #include "kis_paint_device.h" #include "kis_processing_information.h" KisColorBalanceFilter::KisColorBalanceFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Color Balance...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); setSupportsPainting(true); } KisConfigWidget * KisColorBalanceFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisColorBalanceConfigWidget(parent); } -KoColorTransformation * KisColorBalanceFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation * KisColorBalanceFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; if (config) { params["cyan_red_midtones"] = config->getInt("cyan_red_midtones", 0) * 0.01; params["magenta_green_midtones"] = config->getInt("magenta_green_midtones", 0) * 0.01; params["yellow_blue_midtones"] = config->getInt("yellow_blue_midtones", 0) * 0.01; params["cyan_red_shadows"] = config->getInt("cyan_red_shadows", 0) * 0.01; params["magenta_green_shadows"] = config->getInt("magenta_green_shadows", 0) * 0.01; params["yellow_blue_shadows"] = config->getInt("yellow_blue_shadows", 0) * 0.01; params["cyan_red_highlights"] = config->getInt("cyan_red_highlights", 0) * 0.01; params["magenta_green_highlights"] = config->getInt("magenta_green_highlights", 0) * 0.01; params["yellow_blue_highlights"] = config->getInt("yellow_blue_highlights", 0) * 0.01; params["preserve_luminosity"] = config->getBool("preserve_luminosity", true); } return cs->createColorTransformation("ColorBalance" , params); } -KisFilterConfiguration* KisColorBalanceFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisColorBalanceFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration(id().id(), 0); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 0); config->setProperty("cyan_red_midtones", 0); config->setProperty("yellow_green_midtones", 0); config->setProperty("magenta_blue_midtones", 0); config->setProperty("cyan_red_shadows", 0); config->setProperty("yellow_green_shadows", 0); config->setProperty("magenta_blue_shadows", 0); config->setProperty("cyan_red_highlights", 0); config->setProperty("yellow_green_highlights", 0); config->setProperty("magenta_blue_highlights", 0); config->setProperty("preserve_luminosity", true); return config; } KisColorBalanceConfigWidget::KisColorBalanceConfigWidget(QWidget* parent) : KisConfigWidget(parent) { m_page = new Ui_Form(); m_page->setupUi(this); m_page->cyanRedShadowsSlider->setMaximum(100); m_page->cyanRedShadowsSlider->setMinimum(-100); m_page->yellowBlueShadowsSlider->setMaximum(100); m_page->yellowBlueShadowsSlider->setMinimum(-100); m_page->magentaGreenShadowsSlider->setMaximum(100); m_page->magentaGreenShadowsSlider->setMinimum(-100); m_page->cyanRedMidtonesSlider->setMaximum(100); m_page->cyanRedMidtonesSlider->setMinimum(-100); m_page->yellowBlueMidtonesSlider->setMaximum(100); m_page->yellowBlueMidtonesSlider->setMinimum(-100); m_page->magentaGreenMidtonesSlider->setMaximum(100); m_page->magentaGreenMidtonesSlider->setMinimum(-100); m_page->cyanRedHighlightsSlider->setMaximum(100); m_page->cyanRedHighlightsSlider->setMinimum(-100); m_page->yellowBlueHighlightsSlider->setMaximum(100); m_page->yellowBlueHighlightsSlider->setMinimum(-100); m_page->magentaGreenHighlightsSlider->setMaximum(100); m_page->magentaGreenHighlightsSlider->setMinimum(-100); connect(m_page->cyanRedShadowsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->magentaGreenShadowsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->yellowBlueShadowsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->cyanRedMidtonesSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->magentaGreenMidtonesSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->yellowBlueMidtonesSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->cyanRedHighlightsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->magentaGreenHighlightsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->yellowBlueHighlightsSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->chkPreserveLuminosity, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->pushResetShadows, SIGNAL(clicked()), SLOT(slotShadowsClear())); connect(m_page->pushResetMidtones, SIGNAL(clicked()), SLOT(slotMidtonesClear())); connect(m_page->pushResetHighlights, SIGNAL(clicked()), SLOT(slotHighlightsClear())); m_page->cyanRedShadowsSpinbox->setMaximum(100); m_page->cyanRedShadowsSpinbox->setMinimum(-100); m_page->yellowBlueShadowsSpinbox->setMaximum(100); m_page->yellowBlueShadowsSpinbox->setMinimum(-100); m_page->magentaGreenShadowsSpinbox->setMaximum(100); m_page->magentaGreenShadowsSpinbox->setMinimum(-100); m_page->cyanRedMidtonesSpinbox->setMaximum(100); m_page->cyanRedMidtonesSpinbox->setMinimum(-100); m_page->yellowBlueMidtonesSpinbox->setMaximum(100); m_page->yellowBlueMidtonesSpinbox->setMinimum(-100); m_page->magentaGreenMidtonesSpinbox->setMaximum(100); m_page->magentaGreenMidtonesSpinbox->setMinimum(-100); m_page->cyanRedHighlightsSpinbox->setMaximum(100); m_page->cyanRedHighlightsSpinbox->setMinimum(-100); m_page->yellowBlueHighlightsSpinbox->setMaximum(100); m_page->yellowBlueHighlightsSpinbox->setMinimum(-100); m_page->magentaGreenHighlightsSpinbox->setMaximum(100); m_page->magentaGreenHighlightsSpinbox->setMinimum(-100); } KisColorBalanceConfigWidget::~KisColorBalanceConfigWidget() { delete m_page; } -KisPropertiesConfiguration * KisColorBalanceConfigWidget::configuration() const +KisPropertiesConfigurationSP KisColorBalanceConfigWidget::configuration() const { - KisColorTransformationConfiguration* c = new KisColorTransformationConfiguration(KisColorBalanceFilter::id().id(), 0); + KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(KisColorBalanceFilter::id().id(), 0); c->setProperty("cyan_red_shadows", m_page->cyanRedShadowsSlider->value()); c->setProperty("magenta_green_shadows", m_page->magentaGreenShadowsSlider->value()); c->setProperty("yellow_blue_shadows", m_page->yellowBlueShadowsSlider->value()); c->setProperty("cyan_red_midtones", m_page->cyanRedMidtonesSlider->value()); c->setProperty("magenta_green_midtones", m_page->magentaGreenMidtonesSlider->value()); c->setProperty("yellow_blue_midtones", m_page->yellowBlueMidtonesSlider->value()); c->setProperty("cyan_red_highlights", m_page->cyanRedHighlightsSlider->value()); c->setProperty("magenta_green_highlights", m_page->magentaGreenHighlightsSlider->value()); c->setProperty("yellow_blue_highlights", m_page->yellowBlueHighlightsSlider->value()); c->setProperty("preserve_luminosity", m_page->chkPreserveLuminosity->isChecked()); return c; } -void KisColorBalanceConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisColorBalanceConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_page->cyanRedMidtonesSlider->setValue( config->getDouble("cyan_red_midtones", 0)); m_page->magentaGreenMidtonesSlider->setValue( config->getDouble("magenta_green_midtones", 0)); m_page->yellowBlueMidtonesSlider->setValue( config->getDouble("yellow_blue_midtones", 0)); m_page->cyanRedShadowsSlider->setValue( config->getDouble("cyan_red_shadows", 0)); m_page->magentaGreenShadowsSlider->setValue( config->getDouble("magenta_green_shadows", 0)); m_page->yellowBlueShadowsSlider->setValue( config->getDouble("yellow_blue_shadows", 0)); m_page->cyanRedHighlightsSlider->setValue( config->getDouble("cyan_red_highlights", 0)); m_page->magentaGreenHighlightsSlider->setValue( config->getDouble("magenta_green_highlights", 0)); m_page->yellowBlueHighlightsSlider->setValue( config->getDouble("yellow_blue_highlights", 0)); m_page->chkPreserveLuminosity->setChecked(config->getBool("preserve_luminosity", true)); } void KisColorBalanceConfigWidget::slotMidtonesClear() { m_page->cyanRedMidtonesSlider->setValue(0); m_page->magentaGreenMidtonesSlider->setValue(0); m_page->yellowBlueMidtonesSlider->setValue(0); } void KisColorBalanceConfigWidget::slotHighlightsClear() { m_page->cyanRedHighlightsSlider->setValue(0); m_page->magentaGreenHighlightsSlider->setValue(0); m_page->yellowBlueHighlightsSlider->setValue(0); } void KisColorBalanceConfigWidget::slotShadowsClear() { m_page->cyanRedShadowsSlider->setValue(0); m_page->magentaGreenShadowsSlider->setValue(0); m_page->yellowBlueShadowsSlider->setValue(0); } diff --git a/plugins/filters/colorsfilters/kis_color_balance_filter.h b/plugins/filters/colorsfilters/kis_color_balance_filter.h index f6e7b572ec..d02d3dbb69 100644 --- a/plugins/filters/colorsfilters/kis_color_balance_filter.h +++ b/plugins/filters/colorsfilters/kis_color_balance_filter.h @@ -1,80 +1,80 @@ /* * Copyright (c) 2013 Sahil Nagpal * * 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_COLOR_BALANCE_FILTER_H_ #define _KIS_COLOR_BALANCE_FILTER_H_ #include #include "filter/kis_filter.h" #include "kis_config_widget.h" #include "ui_wdg_color_balance.h" #include "filter/kis_color_transformation_filter.h" class QWidget; class KoColorTransformation; class KisColorBalanceFilter : public KisColorTransformationFilter { public: KisColorBalanceFilter(); public: enum Type { SHADOWS, MIDTONES, HIGHLIGHTS }; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("colorbalance", i18n("Color Balance")); } - virtual KisFilterConfiguration * factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; class KisColorBalanceConfigWidget : public KisConfigWidget { Q_OBJECT public: KisColorBalanceConfigWidget(QWidget * parent); virtual ~KisColorBalanceConfigWidget(); - virtual KisPropertiesConfiguration * configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); Ui_Form * m_page; QString m_id; public Q_SLOTS: void slotShadowsClear(); void slotMidtonesClear(); void slotHighlightsClear(); }; #endif diff --git a/plugins/filters/colorsfilters/kis_desaturate_filter.cpp b/plugins/filters/colorsfilters/kis_desaturate_filter.cpp index 359c0f9037..bf4e7b9d5f 100644 --- a/plugins/filters/colorsfilters/kis_desaturate_filter.cpp +++ b/plugins/filters/colorsfilters/kis_desaturate_filter.cpp @@ -1,121 +1,121 @@ /* * This file is part of Krita * * Copyright (c) 2004 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. */ #include "kis_desaturate_filter.h" #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include #include #include #include #include #include #include #include #include #include #include #include "filter/kis_filter_registry.h" #include #include #include #include KisDesaturateFilter::KisDesaturateFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Desaturate...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U)); setSupportsPainting(true); } KisDesaturateFilter::~KisDesaturateFilter() { } KisConfigWidget *KisDesaturateFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisDesaturateConfigWidget(parent); } -KoColorTransformation* KisDesaturateFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisDesaturateFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; if (config) { params["type"] = config->getInt("type", 0); } return cs->createColorTransformation("desaturate_adjustment", params); } -KisFilterConfiguration *KisDesaturateFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisDesaturateFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration(id().id(), 1); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 1); config->setProperty("type", 0); return config; } KisDesaturateConfigWidget::KisDesaturateConfigWidget(QWidget * parent, Qt::WFlags f) : KisConfigWidget(parent, f) { m_page = new Ui_WdgDesaturate(); m_page->setupUi(this); m_group = new QButtonGroup(this); m_group->addButton(m_page->radioLightness, 0); m_group->addButton(m_page->radioLuminosityBT709, 1); m_group->addButton(m_page->radioLuminosityBT601, 2); m_group->addButton(m_page->radioAverage, 3); m_group->addButton(m_page->radioMin, 4); m_group->addButton(m_page->radioMax, 5); m_group->setExclusive(true); connect(m_group, SIGNAL(buttonClicked(int)), SIGNAL(sigConfigurationItemChanged())); } KisDesaturateConfigWidget::~KisDesaturateConfigWidget() { delete m_page; } -KisPropertiesConfiguration * KisDesaturateConfigWidget::configuration() const +KisPropertiesConfigurationSP KisDesaturateConfigWidget::configuration() const { - KisColorTransformationConfiguration* c = new KisColorTransformationConfiguration(KisDesaturateFilter::id().id(), 0); + KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(KisDesaturateFilter::id().id(), 0); c->setProperty("type", m_group->checkedId()); return c; } -void KisDesaturateConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisDesaturateConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_group->button(config->getInt("type", 0))->setChecked(true); emit sigConfigurationItemChanged(); } diff --git a/plugins/filters/colorsfilters/kis_desaturate_filter.h b/plugins/filters/colorsfilters/kis_desaturate_filter.h index 0208c27466..9095dacf52 100644 --- a/plugins/filters/colorsfilters/kis_desaturate_filter.h +++ b/plugins/filters/colorsfilters/kis_desaturate_filter.h @@ -1,70 +1,70 @@ /* * This file is part of Krita * * Copyright (c) 2004 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_DESATURATE_FILTER_H #define KIS_DESATURATE_FILTER_H #include #include #include #include #include "ui_wdg_desaturate.h" class KoColorSpace; class KoColorTransformation; class KisDesaturateFilter : public KisColorTransformationFilter { public: KisDesaturateFilter(); ~KisDesaturateFilter(); public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("desaturate", i18n("Desaturate")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; class KisDesaturateConfigWidget : public KisConfigWidget { Q_OBJECT public: KisDesaturateConfigWidget(QWidget * parent, Qt::WFlags f = 0); virtual ~KisDesaturateConfigWidget(); - virtual KisPropertiesConfiguration * configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); Ui_WdgDesaturate *m_page; QButtonGroup *m_group; }; #endif diff --git a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp index 83d1c5b383..4854ec254c 100644 --- a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp +++ b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.cpp @@ -1,190 +1,190 @@ /* * Copyright (c) 2007 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 * 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 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_hsv_adjustment_filter.h" #include #include #include #include #include namespace { struct SliderConfig { QString m_text; int m_minimum; int m_maximum; inline void apply(QSpinBox* spinBox, QSlider* slider, QLabel* label) const { label->setText(m_text); slider->setMinimum(m_minimum); slider->setMaximum(m_maximum); spinBox->setMinimum(m_minimum); spinBox->setMaximum(m_maximum); int sliderValue = slider->value(); if (sliderValue < m_minimum || sliderValue > m_maximum) { slider->setValue((m_minimum + m_maximum) / 2); } } inline double normalize(int value) const { return (double)value / (double)m_maximum; } }; struct WidgetSlidersConfig { SliderConfig m_sliders[3]; }; #define PERCENT_FIELD_REL(x) {x, -100, 100} #define PERCENT_FIELD_ABS(x) {x, 0, 100} #define DEGREES_FIELD_REL(x) {x, -180, 180} #define DEGREES_FIELD_ABS(x) {x, 0, 360} #define HSX_CONFIGS(x) { \ { {DEGREES_FIELD_REL(i18n("Hue:")), PERCENT_FIELD_REL(i18n("Saturation:")), PERCENT_FIELD_REL(x)} }, \ { {DEGREES_FIELD_ABS(i18n("Hue:")), PERCENT_FIELD_ABS(i18n("Saturation:")), PERCENT_FIELD_REL(x)} } \ } const WidgetSlidersConfig WIDGET_CONFIGS[][2] = { // Hue/Saturation/Value HSX_CONFIGS(i18n("Value:")), // Hue/Saturation/Lightness HSX_CONFIGS(i18n("Lightness:")), // Hue/Saturation/Intensity HSX_CONFIGS(i18n("Intensity:")), // Hue/Saturation/Luminosity HSX_CONFIGS(i18n("Luma:")), // Blue Chroma/Red Chroma/Luma {{ {PERCENT_FIELD_REL(i18n("Yellow-Blue:")), PERCENT_FIELD_REL(i18n("Green-Red:")), PERCENT_FIELD_REL(i18n("Luma:"))} }, { {PERCENT_FIELD_ABS(i18n("Yellow-Blue:")), PERCENT_FIELD_ABS(i18n("Green-Red:")), PERCENT_FIELD_REL(i18n("Luma:"))} }} }; inline const WidgetSlidersConfig& getCurrentWidgetConfig(int type, bool colorize) { return WIDGET_CONFIGS[type][colorize ? 1 : 0]; } } KisHSVAdjustmentFilter::KisHSVAdjustmentFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&HSV Adjustment...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U)); setSupportsPainting(true); } KisConfigWidget * KisHSVAdjustmentFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisHSVConfigWidget(parent); } -KoColorTransformation* KisHSVAdjustmentFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisHSVAdjustmentFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; if (config) { int type = config->getInt("type", 1); bool colorize = config->getBool("colorize", false); const WidgetSlidersConfig& widgetConfig = getCurrentWidgetConfig(type, colorize); params["h"] = widgetConfig.m_sliders[0].normalize(config->getInt("h", 0)); params["s"] = widgetConfig.m_sliders[1].normalize(config->getInt("s", 0)); params["v"] = widgetConfig.m_sliders[2].normalize(config->getInt("v", 0)); params["type"] = type; params["colorize"] = colorize; params["lumaRed"] = cs->lumaCoefficients()[0]; params["lumaGreen"] = cs->lumaCoefficients()[1]; params["lumaBlue"] = cs->lumaCoefficients()[2]; } return cs->createColorTransformation("hsv_adjustment", params); } -KisFilterConfiguration* KisHSVAdjustmentFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisHSVAdjustmentFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration(id().id(), 1); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 1); config->setProperty("h", 0); config->setProperty("s", 0); config->setProperty("v", 0); config->setProperty("type", 1); config->setProperty("colorize", false); return config; } KisHSVConfigWidget::KisHSVConfigWidget(QWidget * parent, Qt::WFlags f) : KisConfigWidget(parent, f) { m_page = new Ui_WdgHSVAdjustment(); m_page->setupUi(this); connect(m_page->cmbType, SIGNAL(activated(int)), this, SLOT(configureSliderLimitsAndLabels())); connect(m_page->chkColorize, SIGNAL(toggled(bool)), this, SLOT(configureSliderLimitsAndLabels())); // connect horizontal sliders connect(m_page->hueSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->saturationSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->valueSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->hueSpinBox, SIGNAL(valueChanged(int)), m_page->hueSlider, SLOT(setValue(int))); connect(m_page->saturationSpinBox, SIGNAL(valueChanged(int)), m_page->saturationSlider, SLOT(setValue(int))); connect(m_page->valueSpinBox, SIGNAL(valueChanged(int)), m_page->valueSlider, SLOT(setValue(int))); connect(m_page->hueSlider, SIGNAL(valueChanged(int)), m_page->hueSpinBox, SLOT(setValue(int))); connect(m_page->saturationSlider, SIGNAL(valueChanged(int)), m_page->saturationSpinBox, SLOT(setValue(int))); connect(m_page->valueSlider, SIGNAL(valueChanged(int)), m_page->valueSpinBox, SLOT(setValue(int))); } KisHSVConfigWidget::~KisHSVConfigWidget() { delete m_page; } -KisPropertiesConfiguration * KisHSVConfigWidget::configuration() const +KisPropertiesConfigurationSP KisHSVConfigWidget::configuration() const { - KisColorTransformationConfiguration* c = new KisColorTransformationConfiguration(KisHSVAdjustmentFilter::id().id(), 0); + KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(KisHSVAdjustmentFilter::id().id(), 0); c->setProperty("h", m_page->hueSlider->value()); c->setProperty("s", m_page->saturationSlider->value()); c->setProperty("v", m_page->valueSlider->value()); c->setProperty("type", m_page->cmbType->currentIndex()); c->setProperty("colorize", m_page->chkColorize->isChecked()); return c; } -void KisHSVConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisHSVConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_page->cmbType->setCurrentIndex(config->getInt("type", 1)); m_page->chkColorize->setChecked(config->getBool("colorize", false)); m_page->hueSlider->setValue(config->getInt("h", 0)); m_page->saturationSlider->setValue(config->getInt("s", 0)); m_page->valueSlider->setValue(config->getInt("v", 0)); configureSliderLimitsAndLabels(); } void KisHSVConfigWidget::configureSliderLimitsAndLabels() { const WidgetSlidersConfig& widget = getCurrentWidgetConfig(m_page->cmbType->currentIndex(), m_page->chkColorize->isChecked()); widget.m_sliders[0].apply(m_page->hueSpinBox, m_page->hueSlider, m_page->label); widget.m_sliders[1].apply(m_page->saturationSpinBox, m_page->saturationSlider, m_page->label_2); widget.m_sliders[2].apply(m_page->valueSpinBox, m_page->valueSlider, m_page->label_3); emit sigConfigurationItemChanged(); } diff --git a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h index 7c38c3d65a..678779c5c8 100644 --- a/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h +++ b/plugins/filters/colorsfilters/kis_hsv_adjustment_filter.h @@ -1,77 +1,77 @@ /* * Copyright (c) 2007 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 * 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 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_HSV_ADJUSTMENT_FILTER_H_ #define _KIS_HSV_ADJUSTMENT_FILTER_H_ #include #include "filter/kis_filter.h" #include "kis_config_widget.h" #include "ui_wdg_hsv_adjustment.h" #include "filter/kis_color_transformation_filter.h" class QWidget; class KoColorTransformation; /** * This class affect Intensity Y of the image */ class KisHSVAdjustmentFilter : public KisColorTransformationFilter { public: KisHSVAdjustmentFilter(); public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("hsvadjustment", i18n("HSV/HSL Adjustment")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; class KisHSVConfigWidget : public KisConfigWidget { Q_OBJECT public: KisHSVConfigWidget(QWidget * parent, Qt::WFlags f = 0); virtual ~KisHSVConfigWidget(); - virtual KisPropertiesConfiguration * configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); Ui_WdgHSVAdjustment * m_page; private Q_SLOTS: void configureSliderLimitsAndLabels(); }; #endif diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp index 5ce0125907..6714c30a57 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp @@ -1,598 +1,598 @@ /* * This file is part of Krita * * Copyright (c) 2005 C. Boemann * * 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_perchannel_filter.h" #include #include #include #include #include #include #include #include #include "KoChannelInfo.h" #include "KoBasicHistogramProducers.h" #include "KoColorModelStandardIds.h" #include "KoColorSpace.h" #include "KoColorTransformation.h" #include "KoCompositeColorTransformation.h" #include "KoCompositeOp.h" #include "KoID.h" #include "kis_signals_blocker.h" #include "kis_bookmarked_configuration_manager.h" #include "kis_config_widget.h" #include #include #include #include #include "kis_histogram.h" #include "kis_painter.h" #include "widgets/kis_curve_widget.h" QVector getVirtualChannels(const KoColorSpace *cs) { const bool supportsLightness = cs->colorModelId() != LABAColorModelID && cs->colorModelId() != GrayAColorModelID && cs->colorModelId() != GrayColorModelID && cs->colorModelId() != AlphaColorModelID; QVector vchannels; QList sortedChannels = KoChannelInfo::displayOrderSorted(cs->channels()); if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs); } Q_FOREACH (KoChannelInfo *channel, sortedChannels) { int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels); vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs); } if (supportsLightness) { vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs); } return vchannels; } KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f) : KisConfigWidget(parent, f), m_histogram(0) { Q_ASSERT(dev); m_page = new WdgPerChannel(this); QHBoxLayout * layout = new QHBoxLayout(this); Q_CHECK_PTR(layout); layout->setContentsMargins(0,0,0,0); layout->addWidget(m_page); m_dev = dev; m_activeVChannel = 0; const KoColorSpace *targetColorSpace = dev->compositionSourceColorSpace(); // fill in the channel chooser, in the display order, but store the pixel index as well. m_virtualChannels = getVirtualChannels(targetColorSpace); const int virtualChannelCount = m_virtualChannels.size(); KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, virtualChannelCount); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_page->cmbChannel->addItem(info.name(), info.pixelIndex()); m_curves[i].setName(info.name()); } connect(m_page->cmbChannel, SIGNAL(activated(int)), this, SLOT(setActiveChannel(int))); // create the horizontal and vertical gradient labels m_page->hgradient->setPixmap(createGradient(Qt::Horizontal)); m_page->vgradient->setPixmap(createGradient(Qt::Vertical)); // init histogram calculator QList keys = KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(targetColorSpace); if(keys.size() > 0) { KoHistogramProducerFactory *hpf; hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0)); - m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); + m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); } connect(m_page->curveWidget, SIGNAL(modified()), this, SIGNAL(sigConfigurationItemChanged())); m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, 0, 100); { KisSignalsBlocker b(m_page->curveWidget); m_page->curveWidget->setCurve(m_curves[0]); setActiveChannel(0); } } KisPerChannelConfigWidget::~KisPerChannelConfigWidget() { delete m_histogram; } inline QPixmap KisPerChannelConfigWidget::createGradient(Qt::Orientation orient /*, int invert (not used yet) */) { int width; int height; int *i, inc, col; int x = 0, y = 0; if (orient == Qt::Horizontal) { i = &x; inc = 1; col = 0; width = 256; height = 1; } else { i = &y; inc = -1; col = 255; width = 1; height = 256; } QPixmap gradientpix(width, height); QPainter p(&gradientpix); p.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); for (; *i < 256; (*i)++, col += inc) { p.setPen(QColor(col, col, col)); p.drawPoint(x, y); } return gradientpix; } inline QPixmap KisPerChannelConfigWidget::getHistogram() { int i; int height = 256; QPixmap pix(256, height); QPalette appPalette = QApplication::palette(); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QColor(appPalette.color(QPalette::Text))); p.save(); p.setOpacity(0.2); const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel]; if (m_histogram && info.type() == VirtualChannelInfo::REAL) { m_histogram->setChannel(info.pixelIndex()); double highest = (double)m_histogram->calculations().getHighest(); qint32 bins = m_histogram->producer()->numberOfBins(); if (m_histogram->getHistogramType() == LINEAR) { double factor = (double)height / highest; for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); } } else { double factor = (double)height / (double)log(highest); for (i = 0; i < bins; ++i) { p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); } } } p.restore(); return pix; } #define BITS_PER_BYTE 8 #define pwr2(p) (1<curveWidget->curve(); m_activeVChannel = ch; m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); m_page->curveWidget->setPixmap(getHistogram()); m_page->cmbChannel->setCurrentIndex(m_activeVChannel); // Getting range accepted by channel VirtualChannelInfo ¤tVChannel = m_virtualChannels[m_activeVChannel]; KoChannelInfo::enumChannelValueType valueType = currentVChannel.valueType(); int order = BITS_PER_BYTE * currentVChannel.channelSize(); int maxValue = pwr2(order); int min; int max; m_page->curveWidget->dropInOutControls(); switch (valueType) { case KoChannelInfo::UINT8: case KoChannelInfo::UINT16: case KoChannelInfo::UINT32: m_shift = 0; m_scale = double(maxValue); min = 0; max = maxValue - 1; break; case KoChannelInfo::INT8: case KoChannelInfo::INT16: m_shift = 0.5; m_scale = double(maxValue); min = -maxValue / 2; max = maxValue / 2 - 1; break; case KoChannelInfo::FLOAT16: case KoChannelInfo::FLOAT32: case KoChannelInfo::FLOAT64: default: m_shift = 0; m_scale = 100.0; //Hack Alert: should be changed to float min = 0; max = 100; break; } m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, min, max); } -KisPropertiesConfiguration * KisPerChannelConfigWidget::configuration() const +KisPropertiesConfigurationSP KisPerChannelConfigWidget::configuration() const { int numChannels = m_virtualChannels.size(); KisPerChannelFilterConfiguration * cfg = new KisPerChannelFilterConfiguration(numChannels); KIS_ASSERT_RECOVER(m_activeVChannel < m_curves.size()) { return cfg; } m_curves[m_activeVChannel] = m_page->curveWidget->curve(); cfg->setCurves(m_curves); return cfg; } -void KisPerChannelConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisPerChannelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { - const KisPerChannelFilterConfiguration * cfg = dynamic_cast(config); + const KisPerChannelFilterConfiguration * cfg = dynamic_cast(config.data()); if (!cfg) return; if (cfg->curves().size() == 0) { /** * HACK ALERT: our configuration factory generates * default configuration with nTransfers==0. * Catching it here. Just reset all the transfers. */ const int virtualChannelCount = m_virtualChannels.size(); KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, virtualChannelCount); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_curves[i].setName(info.name()); } } else if (cfg->curves().size() != int(m_virtualChannels.size())) { warnKrita << "WARNING: trying to load a curve with incorrect number of channels!"; warnKrita << "WARNING: expected:" << m_virtualChannels.size(); warnKrita << "WARNING: got:" << cfg->curves().size(); return; } else { for (int ch = 0; ch < cfg->curves().size(); ch++) m_curves[ch] = cfg->curves()[ch]; } // HACK: we save the previous curve in setActiveChannel, so just copy it m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); setActiveChannel(0); } KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int nCh) : KisColorTransformationConfiguration("perchannel", 1) { initDefaultCurves(m_curves, nCh); updateTransfers(); } KisPerChannelFilterConfiguration::~KisPerChannelFilterConfiguration() { } bool KisPerChannelFilterConfiguration::isCompatible(const KisPaintDeviceSP dev) const { return (int)dev->compositionSourceColorSpace()->channelCount() == m_curves.size(); } void KisPerChannelFilterConfiguration::setCurves(QList &curves) { m_curves.clear(); m_curves = curves; updateTransfers(); } void KisPerChannelFilterConfiguration::initDefaultCurves(QList &curves, int nCh) { curves.clear(); for (int i = 0; i < nCh; i++) { curves.append(KisCubicCurve()); } } void KisPerChannelFilterConfiguration::updateTransfers() { m_transfers.resize(m_curves.size()); for (int i = 0; i < m_curves.size(); i++) { m_transfers[i] = m_curves[i].uint16Transfer(); } } const QVector >& KisPerChannelFilterConfiguration::transfers() const { return m_transfers; } const QList& KisPerChannelFilterConfiguration::curves() const { return m_curves; } void KisPerChannelFilterConfiguration::fromLegacyXML(const QDomElement& root) { fromXML(root); } void KisPerChannelFilterConfiguration::fromXML(const QDomElement& root) { QList curves; quint16 numTransfers = 0; int version; version = root.attribute("version").toInt(); QDomElement e = root.firstChild().toElement(); QString attributeName; KisCubicCurve curve; quint16 index; while (!e.isNull()) { if ((attributeName = e.attribute("name")) == "nTransfers") { numTransfers = e.text().toUShort(); } else { QRegExp rx("curve(\\d+)"); if (rx.indexIn(attributeName, 0) != -1) { index = rx.cap(1).toUShort(); index = qMin(index, quint16(curves.count())); if (!e.text().isEmpty()) { curve.fromString(e.text()); } curves.insert(index, curve); } } e = e.nextSiblingElement(); } if (!numTransfers) return; setVersion(version); setCurves(curves); } /** * Inherited from KisPropertiesConfiguration */ //void KisPerChannelFilterConfiguration::fromXML(const QString& s) void addParamNode(QDomDocument& doc, QDomElement& root, const QString &name, const QString &value) { QDomText text = doc.createTextNode(value); QDomElement t = doc.createElement("param"); t.setAttribute("name", name); t.appendChild(text); root.appendChild(t); } void KisPerChannelFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { /** * * 3 * 0,0;0.5,0.5;1,1; * 0,0;1,1; * 0,0;1,1; * */ root.setAttribute("version", version()); QDomText text; QDomElement t; addParamNode(doc, root, "nTransfers", QString::number(m_curves.size())); KisCubicCurve curve; QString paramName; for (int i = 0; i < m_curves.size(); ++i) { QString name = QLatin1String("curve") + QString::number(i); QString value = m_curves[i].toString(); addParamNode(doc, root, name, value); } } /** * Inherited from KisPropertiesConfiguration */ //QString KisPerChannelFilterConfiguration::toXML() KisPerChannelFilter::KisPerChannelFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Color Adjustment curves...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M)); setSupportsPainting(true); setColorSpaceIndependence(TO_LAB16); } KisConfigWidget * KisPerChannelFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisPerChannelConfigWidget(parent, dev); } -KisFilterConfiguration * KisPerChannelFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisPerChannelFilter::factoryConfiguration(const KisPaintDeviceSP) const { return new KisPerChannelFilterConfiguration(0); } -KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { const KisPerChannelFilterConfiguration* configBC = - dynamic_cast(config); // Somehow, this shouldn't happen + dynamic_cast(config.data()); // Somehow, this shouldn't happen Q_ASSERT(configBC); const QVector > &originalTransfers = configBC->transfers(); const QList &originalCurves = configBC->curves(); /** * TODO: What about the order of channels? (DK) * * Virtual channels are sorted in display order, does Lcms accepts * transforms in display order? Why on Earth it works?! Is it * documented anywhere? */ const QVector virtualChannels = getVirtualChannels(cs); if (originalTransfers.size() != int(virtualChannels.size())) { // We got an illegal number of colorchannels :( return 0; } bool colorsNull = true; bool lightnessNull = true; bool allColorsNull = true; int alphaIndexInReal = -1; QVector > realTransfers; QVector lightnessTransfer; QVector allColorsTransfer; for (int i = 0; i < virtualChannels.size(); i++) { if (virtualChannels[i].type() == VirtualChannelInfo::REAL) { realTransfers << originalTransfers[i]; if (virtualChannels[i].isAlpha()) { alphaIndexInReal = realTransfers.size() - 1; } if (colorsNull && !originalCurves[i].isNull()) { colorsNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) { KIS_ASSERT_RECOVER_NOOP(lightnessTransfer.isEmpty()); lightnessTransfer = originalTransfers[i]; if (lightnessNull && !originalCurves[i].isNull()) { lightnessNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::ALL_COLORS) { KIS_ASSERT_RECOVER_NOOP(allColorsTransfer.isEmpty()); allColorsTransfer = originalTransfers[i]; if (allColorsNull && !originalCurves[i].isNull()) { allColorsNull = false; } } } KoColorTransformation *lightnessTransform = 0; KoColorTransformation *allColorsTransform = 0; KoColorTransformation *colorTransform = 0; if (!colorsNull) { const quint16** transfers = new const quint16*[realTransfers.size()]; for(int i = 0; i < realTransfers.size(); ++i) { transfers[i] = realTransfers[i].constData(); /** * createPerChannelAdjustment() expects alpha channel to * be the last channel in the list, so just it here */ KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal || alphaIndexInReal == (realTransfers.size() - 1)); } colorTransform = cs->createPerChannelAdjustment(transfers); delete [] transfers; } if (!lightnessNull) { lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTransfer.constData()); } if (!allColorsNull) { const quint16** allColorsTransfers = new const quint16*[realTransfers.size()]; for(int i = 0; i < realTransfers.size(); ++i) { allColorsTransfers[i] = (i != alphaIndexInReal) ? allColorsTransfer.constData() : 0; /** * createPerChannelAdjustment() expects alpha channel to * be the last channel in the list, so just it here */ KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal || alphaIndexInReal == (realTransfers.size() - 1)); } allColorsTransform = cs->createPerChannelAdjustment(allColorsTransfers); delete[] allColorsTransfers; } QVector allTransforms; allTransforms << colorTransform; allTransforms << allColorsTransform; allTransforms << lightnessTransform; return KoCompositeColorTransformation::createOptimizedCompositeTransform(allTransforms); } -bool KisPerChannelFilter::needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const +bool KisPerChannelFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); return cs->colorModelId() == AlphaColorModelID; } diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.h b/plugins/filters/colorsfilters/kis_perchannel_filter.h index 9cd7703ad7..ce272ead29 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.h +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.h @@ -1,135 +1,135 @@ /* * This file is part of Krita * * Copyright (c) 2004 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_PERCHANNEL_FILTER_H_ #define _KIS_PERCHANNEL_FILTER_H_ #include #include #include #include #include #include #include "ui_wdg_perchannel.h" #include "virtual_channel_info.h" class WdgPerChannel : public QWidget, public Ui::WdgPerChannel { Q_OBJECT public: WdgPerChannel(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KisPerChannelFilterConfiguration : public KisColorTransformationConfiguration { public: KisPerChannelFilterConfiguration(int n); ~KisPerChannelFilterConfiguration(); using KisFilterConfiguration::fromXML; using KisFilterConfiguration::toXML; using KisFilterConfiguration::fromLegacyXML; virtual void fromLegacyXML(const QDomElement& root); virtual void fromXML(const QDomElement& e); virtual void toXML(QDomDocument& doc, QDomElement& root) const; virtual void setCurves(QList &curves); static inline void initDefaultCurves(QList &curves, int nCh); bool isCompatible(const KisPaintDeviceSP) const; const QVector >& transfers() const; virtual const QList& curves() const; private: QList m_curves; private: void updateTransfers(); private: QVector > m_transfers; }; /** * This class is generic for filters that affect channel separately */ class KisPerChannelFilter : public KisColorTransformationFilter { public: KisPerChannelFilter(); public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration * factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; - virtual bool needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const; + virtual bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const; static inline KoID id() { return KoID("perchannel", i18n("Color Adjustment")); } private: }; class KisPerChannelConfigWidget : public KisConfigWidget { Q_OBJECT public: KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); virtual ~KisPerChannelConfigWidget(); - virtual void setConfiguration(const KisPropertiesConfiguration* config); - virtual KisPropertiesConfiguration * configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); + virtual KisPropertiesConfigurationSP configuration() const; private Q_SLOTS: virtual void setActiveChannel(int ch); private: QVector m_virtualChannels; int m_activeVChannel; // private routines inline QPixmap getHistogram(); inline QPixmap createGradient(Qt::Orientation orient /*, int invert (not used now) */); // members WdgPerChannel * m_page; KisPaintDeviceSP m_dev; KisHistogram *m_histogram; mutable QList m_curves; // scales for displaying color numbers double m_scale; double m_shift; }; #endif diff --git a/plugins/filters/convolutionfilters/kis_convolution_filter.cpp b/plugins/filters/convolutionfilters/kis_convolution_filter.cpp index e451ad63d1..23080fe6ea 100644 --- a/plugins/filters/convolutionfilters/kis_convolution_filter.cpp +++ b/plugins/filters/convolutionfilters/kis_convolution_filter.cpp @@ -1,71 +1,71 @@ /* * This file is part of the KDE project * * Copyright (c) 2004 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. */ #include "kis_convolution_filter.h" #include #include #include #include "kis_painter.h" #include "kis_convolution_painter.h" #include "kis_convolution_kernel.h" #include #include #include #include KisConvolutionFilter::KisConvolutionFilter(const KoID& id, const KoID & category, const QString & entry) : KisFilter(id, category, entry) { setColorSpaceIndependence(FULLY_INDEPENDENT); } void KisConvolutionFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { Q_UNUSED(config); QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device != 0); KisConvolutionPainter painter(device); QBitArray channelFlags; if (config) { channelFlags = config->channelFlags(); } if (channelFlags.isEmpty() || !config) { channelFlags = QBitArray(device->colorSpace()->channelCount(), true); } painter.setChannelFlags(channelFlags); painter.setProgress(progressUpdater); painter.applyMatrix(m_matrix, device, srcTopLeft, srcTopLeft, applyRect.size(), BORDER_REPEAT); } void KisConvolutionFilter::setIgnoreAlpha(bool v) { m_ignoreAlpha = v; } diff --git a/plugins/filters/convolutionfilters/kis_convolution_filter.h b/plugins/filters/convolutionfilters/kis_convolution_filter.h index 31cdda3ccb..e05c5d983d 100644 --- a/plugins/filters/convolutionfilters/kis_convolution_filter.h +++ b/plugins/filters/convolutionfilters/kis_convolution_filter.h @@ -1,47 +1,47 @@ /* * This file is part of Krita * * Copyright (c) 2004 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_CONVOLUTION_FILTER_H_ #define _KIS_CONVOLUTION_FILTER_H_ #include "filter/kis_filter.h" #include "filter/kis_filter_registry.h" #include "filter/kis_filter_configuration.h" #include "kis_convolution_painter.h" class KisConvolutionFilter : public KisFilter { public: KisConvolutionFilter(const KoID& id, const KoID & category, const QString & entry); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const; protected: void setIgnoreAlpha(bool v); protected: KisConvolutionKernelSP m_matrix; bool m_ignoreAlpha; }; #endif diff --git a/plugins/filters/dodgeburn/DodgeBurn.cpp b/plugins/filters/dodgeburn/DodgeBurn.cpp index 94f5d61d55..bea5f60275 100644 --- a/plugins/filters/dodgeburn/DodgeBurn.cpp +++ b/plugins/filters/dodgeburn/DodgeBurn.cpp @@ -1,111 +1,111 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "DodgeBurn.h" #include #include #include "ui_DodgeBurnConfigurationBaseWidget.h" KisFilterDodgeBurn::KisFilterDodgeBurn(const QString& id, const QString& prefix, const QString& name ) : KisColorTransformationFilter(KoID(id, name), categoryAdjust(), name), m_prefix(prefix) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } KisConfigWidget * KisFilterDodgeBurn::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisDodgeBurnConfigWidget(parent, id()); } -KoColorTransformation* KisFilterDodgeBurn::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisFilterDodgeBurn::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { QHash params; QString suffix = "Midtones"; if (config) { params["exposure"] = config->getDouble("exposure", 0.5); int type = config->getInt("type", KisFilterDodgeBurn::MIDTONES); switch(type) { case KisFilterDodgeBurn::HIGHLIGHTS: suffix = "Highlights"; break; case KisFilterDodgeBurn::SHADOWS: suffix = "Shadows"; break; default: break; } } return cs->createColorTransformation(m_prefix + suffix, params); } KisDodgeBurnConfigWidget::KisDodgeBurnConfigWidget(QWidget * parent, const QString& id) : KisConfigWidget(parent), m_id(id) { m_page = new Ui_DodgeBurnConfigurationBaseWidget(); m_page->setupUi(this); connect(m_page->radioButtonHighlights, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->radioButtonMidtones, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->radioButtonShadows, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->sliderExposure, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); } KisDodgeBurnConfigWidget::~KisDodgeBurnConfigWidget() { delete m_page; } -KisPropertiesConfiguration * KisDodgeBurnConfigWidget::configuration() const +KisPropertiesConfigurationSP KisDodgeBurnConfigWidget::configuration() const { - KisColorTransformationConfiguration* c = new KisColorTransformationConfiguration(m_id, 0); + KisColorTransformationConfigurationSP c = new KisColorTransformationConfiguration(m_id, 0); int type = 0; if(m_page->radioButtonHighlights->isChecked()) { type = KisFilterDodgeBurn::HIGHLIGHTS; } else if(m_page->radioButtonShadows->isChecked()) { type = KisFilterDodgeBurn::SHADOWS; } else { type = KisFilterDodgeBurn::MIDTONES; } c->setProperty("type", type); c->setProperty("exposure", m_page->sliderExposure->value() / 100.0); return c; } -void KisDodgeBurnConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisDodgeBurnConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { int type = config->getInt("type", KisFilterDodgeBurn::MIDTONES); switch(type) { case KisFilterDodgeBurn::HIGHLIGHTS: m_page->radioButtonHighlights->setChecked(true); break; case KisFilterDodgeBurn::SHADOWS: m_page->radioButtonShadows->setChecked(true); break; default: case KisFilterDodgeBurn::MIDTONES: m_page->radioButtonMidtones->setChecked(true); break; } m_page->sliderExposure->setValue(config->getDouble("exposure", 0.5) * 100); } diff --git a/plugins/filters/dodgeburn/DodgeBurn.h b/plugins/filters/dodgeburn/DodgeBurn.h index 9bb11740a5..9d8d08cc46 100644 --- a/plugins/filters/dodgeburn/DodgeBurn.h +++ b/plugins/filters/dodgeburn/DodgeBurn.h @@ -1,58 +1,58 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DODGE_BURN_H #define DODGE_BURN_H #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" class KisFilterDodgeBurn : public KisColorTransformationFilter { public: enum Type { SHADOWS, MIDTONES, HIGHLIGHTS }; public: KisFilterDodgeBurn(const QString& id, const QString& prefix, const QString& name ); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: QString m_prefix; }; class Ui_DodgeBurnConfigurationBaseWidget; class KisDodgeBurnConfigWidget : public KisConfigWidget { public: KisDodgeBurnConfigWidget(QWidget * parent, const QString& id); virtual ~KisDodgeBurnConfigWidget(); - virtual KisPropertiesConfiguration * configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); QString m_id; Ui_DodgeBurnConfigurationBaseWidget * m_page; }; #endif diff --git a/plugins/filters/embossfilter/kis_emboss_filter.cpp b/plugins/filters/embossfilter/kis_emboss_filter.cpp index fdc2ba238d..64981dae47 100644 --- a/plugins/filters/embossfilter/kis_emboss_filter.cpp +++ b/plugins/filters/embossfilter/kis_emboss_filter.cpp @@ -1,163 +1,163 @@ /* * This file is part of Krita * * Copyright (c) 2004 Michael Thaler * * ported from digikam, Copyrighted 2004 Gilles Caulier, * Original Emboss algorithm copyrighted 2004 by * Pieter Z. Voloshyn . * * 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_emboss_filter.h" #include #include #include #include #include #include #include #include "KoIntegerMaths.h" #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_integer_filter_widget.h" #include KisEmbossFilter::KisEmbossFilter() : KisFilter(id(), categoryEmboss(), i18n("&Emboss with Variable Depth...")) { setSupportsPainting(false); setColorSpaceIndependence(TO_RGBA8); setSupportsThreading(false); setSupportsAdjustmentLayers(false); } -KisFilterConfiguration* KisEmbossFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisEmbossFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 0); config->setProperty("depth", 30); return config; } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to apply the Emboss effect * * data => The image data in RGBA mode. * Width => Width of image. * Height => Height of image. * d => Emboss value * * Theory => This is an amazing effect. And the theory is very simple to * understand. You get the diference between the colors and * increase it. After this, get the gray tone */ void KisEmbossFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); //read the filter configuration values from the KisFilterConfiguration object quint32 embossdepth = config ? config->getInt("depth", 30) : 30; //the actual filter function from digikam. It needs a pointer to a quint8 array //with the actual pixel data. float Depth = embossdepth / 10.0; int R = 0, G = 0, B = 0; uchar Gray = 0; int Width = applyRect.width(); int Height = applyRect.height(); if (progressUpdater) { progressUpdater->setRange(0, Height); } KisSequentialIterator it(device, applyRect); QColor color1; QColor color2; KisRandomConstAccessorSP acc = device->createRandomAccessorNG(srcTopLeft.x(), srcTopLeft.y()); do { // XXX: COLORSPACE_INDEPENDENCE or at least work IN RGB16A device->colorSpace()->toQColor(it.oldRawData(), &color1); acc->moveTo(srcTopLeft.x() + it.x() + Lim_Max(it.x(), 1, Width), srcTopLeft.y() + it.y() + Lim_Max(it.y(), 1, Height)); device->colorSpace()->toQColor(acc->oldRawData(), &color2); R = abs((int)((color1.red() - color2.red()) * Depth + (quint8_MAX / 2))); G = abs((int)((color1.green() - color2.green()) * Depth + (quint8_MAX / 2))); B = abs((int)((color1.blue() - color2.blue()) * Depth + (quint8_MAX / 2))); Gray = CLAMP((R + G + B) / 3, 0, quint8_MAX); device->colorSpace()->fromQColor(QColor(Gray, Gray, Gray, color1.alpha()), it.rawData()); if (progressUpdater) { progressUpdater->setValue(it.y()); if(progressUpdater->interrupted()) return; } } while(it.nextPixel()); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* This function limits the max and min values * defined by the developer * * Now => Original value * Up => Increments * Max => Maximum value * * Theory => This function is used in some functions to limit the * "for step". E.g. I have a picture with 309 pixels (width), and * my "for step" is 5. All the code go alright until reachs the * w = 305, because in the next step w will go to 310, but we want * to analize all the pixels. So, this function will reduce the * "for step", when necessary, until reach the last possible value */ int KisEmbossFilter::Lim_Max(int Now, int Up, int Max) const { --Max; while (Now > Max - Up) --Up; return (Up); } KisConfigWidget * KisEmbossFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(10, 300, 30, i18n("Depth"), "depth")); KisConfigWidget * w = new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); Q_CHECK_PTR(w); return w; } diff --git a/plugins/filters/embossfilter/kis_emboss_filter.h b/plugins/filters/embossfilter/kis_emboss_filter.h index 09cc7bc614..2744d2812f 100644 --- a/plugins/filters/embossfilter/kis_emboss_filter.h +++ b/plugins/filters/embossfilter/kis_emboss_filter.h @@ -1,51 +1,51 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_EMBOSS_FILTER_H_ #define _KIS_EMBOSS_FILTER_H_ #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisEmbossFilter : public KisFilter { public: KisEmbossFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("emboss", i18n("Emboss with Variable Depth")); } public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; protected: - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; private: inline int Lim_Max(int Now, int Up, int Max) const; }; #endif diff --git a/plugins/filters/example/example.cpp b/plugins/filters/example/example.cpp index 53dbe948eb..d4017c388a 100644 --- a/plugins/filters/example/example.cpp +++ b/plugins/filters/example/example.cpp @@ -1,73 +1,73 @@ /* * This file is part of the KDE project * * Copyright (c) 2004 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. */ #include "example.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoColorModelStandardIds.h" K_PLUGIN_FACTORY_WITH_JSON(KritaExampleFactory, "kritaexample.json", registerPlugin();) KritaExample::KritaExample(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KisFilterInvert())); } KritaExample::~KritaExample() { } KisFilterInvert::KisFilterInvert() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Invert")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I)); setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); setShowConfigurationWidget(false); setSupportsLevelOfDetail(true); } -KoColorTransformation* KisFilterInvert::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisFilterInvert::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { Q_UNUSED(config); return cs->createInvertTransformation(); } -bool KisFilterInvert::needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const +bool KisFilterInvert::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); return cs->colorModelId() == AlphaColorModelID; } #include "example.moc" diff --git a/plugins/filters/example/example.h b/plugins/filters/example/example.h index 6632b89baf..d9473105db 100644 --- a/plugins/filters/example/example.h +++ b/plugins/filters/example/example.h @@ -1,51 +1,51 @@ /* * This file is part of Krita * * Copyright (c) 2004 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 EXAMPLE_H #define EXAMPLE_H #include #include #include "filter/kis_color_transformation_filter.h" class KritaExample : public QObject { Q_OBJECT public: KritaExample(QObject *parent, const QVariantList &); virtual ~KritaExample(); }; class KisFilterInvert : public KisColorTransformationFilter { public: KisFilterInvert(); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("invert", i18n("Invert")); } - bool needsTransparentPixels(const KisFilterConfiguration *config, const KoColorSpace *cs) const; + bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const; }; #endif diff --git a/plugins/filters/fastcolortransfer/fastcolortransfer.cpp b/plugins/filters/fastcolortransfer/fastcolortransfer.cpp index e3e42e8e6d..558bb8522f 100644 --- a/plugins/filters/fastcolortransfer/fastcolortransfer.cpp +++ b/plugins/filters/fastcolortransfer/fastcolortransfer.cpp @@ -1,175 +1,175 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "fastcolortransfer.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_fastcolortransfer.h" #include "ui_wdgfastcolortransfer.h" #include K_PLUGIN_FACTORY_WITH_JSON(KritaFastColorTransferFactory, "kritafastcolortransfer.json", registerPlugin();) FastColorTransferPlugin::FastColorTransferPlugin(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(new KisFilterFastColorTransfer()); } FastColorTransferPlugin::~FastColorTransferPlugin() { } KisFilterFastColorTransfer::KisFilterFastColorTransfer() : KisFilter(id(), categoryColors(), i18n("&Color Transfer...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsThreading(false); setSupportsPainting(false); setSupportsAdjustmentLayers(false); } KisConfigWidget * KisFilterFastColorTransfer::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgFastColorTransfer(parent); } -KisFilterConfiguration* KisFilterFastColorTransfer::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterFastColorTransfer::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("filename", ""); // TODO: put an exemple image in share/krita, like a sunset that what's give the best results return config; } #define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) void KisFilterFastColorTransfer::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { Q_ASSERT(device != 0); dbgPlugins << "Start transferring color"; // Convert ref and src to LAB const KoColorSpace* labCS = KoColorSpaceRegistry::instance()->lab16(); if (!labCS) { dbgPlugins << "The LAB colorspace is not available."; return; } dbgPlugins << "convert a copy of src to lab"; const KoColorSpace* oldCS = device->colorSpace(); KisPaintDeviceSP srcLAB = new KisPaintDevice(*device.data()); dbgPlugins << "srcLab : " << srcLAB->extent(); KUndo2Command* cmd = srcLAB->convertTo(labCS, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); delete cmd; if (progressUpdater) { progressUpdater->setRange(0, 2 * applyRect.width() * applyRect.height()); } int count = 0; // Compute the means and sigmas of src dbgPlugins << "Compute the means and sigmas of src"; double meanL_src = 0., meanA_src = 0., meanB_src = 0.; double sigmaL_src = 0., sigmaA_src = 0., sigmaB_src = 0.; KisSequentialConstIterator srcIt(srcLAB, applyRect); do { const quint16* data = reinterpret_cast(srcIt.oldRawData()); quint32 L = data[0]; quint32 A = data[1]; quint32 B = data[2]; meanL_src += L; meanA_src += A; meanB_src += B; sigmaL_src += L * L; sigmaA_src += A * A; sigmaB_src += B * B; if (progressUpdater) progressUpdater->setValue(++count); } while (srcIt.nextPixel() && !(progressUpdater && progressUpdater->interrupted())); double totalSize = 1. / (applyRect.width() * applyRect.height()); meanL_src *= totalSize; meanA_src *= totalSize; meanB_src *= totalSize; sigmaL_src *= totalSize; sigmaA_src *= totalSize; sigmaB_src *= totalSize; dbgPlugins << totalSize << "" << meanL_src << "" << meanA_src << "" << meanB_src << "" << sigmaL_src << "" << sigmaA_src << "" << sigmaB_src; double meanL_ref = config->getDouble("meanL"); double meanA_ref = config->getDouble("meanA"); double meanB_ref = config->getDouble("meanB"); double sigmaL_ref = config->getDouble("sigmaL"); double sigmaA_ref = config->getDouble("sigmaA"); double sigmaB_ref = config->getDouble("sigmaB"); // Transfer colors dbgPlugins << "Transfer colors"; { double coefL = sqrt((sigmaL_ref - meanL_ref * meanL_ref) / (sigmaL_src - meanL_src * meanL_src)); double coefA = sqrt((sigmaA_ref - meanA_ref * meanA_ref) / (sigmaA_src - meanA_src * meanA_src)); double coefB = sqrt((sigmaB_ref - meanB_ref * meanB_ref) / (sigmaB_src - meanB_src * meanB_src)); KisHLineConstIteratorSP srcLABIt = srcLAB->createHLineConstIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); KisHLineIteratorSP dstIt = device->createHLineIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); quint16 labPixel[4]; for (int y = 0; y < applyRect.height() && !(progressUpdater && progressUpdater->interrupted()); ++y) { do { const quint16* data = reinterpret_cast(srcLABIt->oldRawData()); labPixel[0] = (quint16)CLAMP(((double)data[0] - meanL_src) * coefL + meanL_ref, 0., 65535.); labPixel[1] = (quint16)CLAMP(((double)data[1] - meanA_src) * coefA + meanA_ref, 0., 65535.); labPixel[2] = (quint16)CLAMP(((double)data[2] - meanB_src) * coefB + meanB_ref, 0., 65535.); labPixel[3] = data[3]; oldCS->fromLabA16(reinterpret_cast(labPixel), dstIt->rawData(), 1); if (progressUpdater) progressUpdater->setValue(++count); srcLABIt->nextPixel(); } while(dstIt->nextPixel()); dstIt->nextRow(); srcLABIt->nextRow(); } } } #include "fastcolortransfer.moc" diff --git a/plugins/filters/fastcolortransfer/fastcolortransfer.h b/plugins/filters/fastcolortransfer/fastcolortransfer.h index 07ed2789b6..f906fe66be 100644 --- a/plugins/filters/fastcolortransfer/fastcolortransfer.h +++ b/plugins/filters/fastcolortransfer/fastcolortransfer.h @@ -1,55 +1,55 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 COLORTRANSFER_H #define COLORTRANSFER_H #include #include #include class FastColorTransferPlugin : public QObject { Q_OBJECT public: FastColorTransferPlugin(QObject *parent, const QVariantList &); virtual ~FastColorTransferPlugin(); }; class KisFilterFastColorTransfer : public KisFilter { public: KisFilterFastColorTransfer(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const; static inline KoID id() { return KoID("colortransfer", i18n("Color Transfer")); } public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; #endif diff --git a/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp b/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp index 2fd275c09e..e0fa53f8cf 100644 --- a/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp +++ b/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp @@ -1,147 +1,147 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_fastcolortransfer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_wdgfastcolortransfer.h" KisWdgFastColorTransfer::KisWdgFastColorTransfer(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgFastColorTransfer(); m_widget->setupUi(this); m_widget->fileNameURLRequester->setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); connect(m_widget->fileNameURLRequester, SIGNAL(textChanged(const QString&)), this, SIGNAL(sigConfigurationItemChanged())); } KisWdgFastColorTransfer::~KisWdgFastColorTransfer() { delete m_widget; } -void KisWdgFastColorTransfer::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgFastColorTransfer::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("filename", value)) { widget()->fileNameURLRequester->setFileName(value.toString()); } } -KisPropertiesConfiguration* KisWdgFastColorTransfer::configuration() const +KisPropertiesConfigurationSP KisWdgFastColorTransfer::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("colortransfer", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("colortransfer", 1); QString fileName = this->widget()->fileNameURLRequester->fileName(); if (fileName.isEmpty()) return config; KisPaintDeviceSP ref; dbgPlugins << "Use as reference file : " << fileName; KisDocument *d = KisPart::instance()->createDocument(); KisImportExportManager manager(d); KisImportExportFilter::ConversionStatus status; QString s = manager.importDocument(fileName, QString(), status); dbgPlugins << "import returned" << s << "and status" << status; KisImageWSP importedImage = d->image(); if (importedImage) { ref = importedImage->projection(); } if (!ref) { dbgPlugins << "No reference image was specified."; delete d; return config; } // Convert ref to LAB const KoColorSpace* labCS = KoColorSpaceRegistry::instance()->lab16(); if (!labCS) { dbgPlugins << "The LAB colorspace is not available."; delete d; return config; } dbgPlugins << "convert ref to lab"; KUndo2Command* cmd = ref->convertTo(labCS, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); delete cmd; // Compute the means and sigmas of ref double meanL_ref = 0., meanA_ref = 0., meanB_ref = 0.; double sigmaL_ref = 0., sigmaA_ref = 0., sigmaB_ref = 0.; KisSequentialConstIterator refIt(ref, importedImage->bounds()); do { const quint16* data = reinterpret_cast(refIt.oldRawData()); quint32 L = data[0]; quint32 A = data[1]; quint32 B = data[2]; meanL_ref += L; meanA_ref += A; meanB_ref += B; sigmaL_ref += L * L; sigmaA_ref += A * A; sigmaB_ref += B * B; } while (refIt.nextPixel()); double totalSize = 1. / (importedImage->width() * importedImage->height()); meanL_ref *= totalSize; meanA_ref *= totalSize; meanB_ref *= totalSize; sigmaL_ref *= totalSize; sigmaA_ref *= totalSize; sigmaB_ref *= totalSize; dbgPlugins << totalSize << "" << meanL_ref << "" << meanA_ref << "" << meanB_ref << "" << sigmaL_ref << "" << sigmaA_ref << "" << sigmaB_ref; config->setProperty("filename", fileName); config->setProperty("meanL", meanL_ref); config->setProperty("meanA", meanA_ref); config->setProperty("meanB", meanB_ref); config->setProperty("sigmaL", sigmaL_ref); config->setProperty("sigmaA", sigmaA_ref); config->setProperty("sigmaB", sigmaB_ref); delete d; return config; } diff --git a/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h b/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h index a15a3dcc88..8825130d91 100644 --- a/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h +++ b/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h @@ -1,45 +1,45 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_FASTCOLORTRANSFER_H #define KIS_WDG_FASTCOLORTRANSFER_H #include class Ui_WdgFastColorTransfer; /** @author Cyrille Berger */ class KisWdgFastColorTransfer : public KisConfigWidget { public: KisWdgFastColorTransfer(QWidget * parent); ~KisWdgFastColorTransfer(); - virtual void setConfiguration(const KisPropertiesConfiguration*); + virtual void setConfiguration(const KisPropertiesConfigurationSP); inline const Ui_WdgFastColorTransfer* widget() const { return m_widget; } - virtual KisPropertiesConfiguration* configuration() const; + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgFastColorTransfer* m_widget; }; #endif diff --git a/plugins/filters/gradientmap/gradientmap.cpp b/plugins/filters/gradientmap/gradientmap.cpp index c8a6eefa47..b818dc44a4 100644 --- a/plugins/filters/gradientmap/gradientmap.cpp +++ b/plugins/filters/gradientmap/gradientmap.cpp @@ -1,92 +1,92 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Spencer Brown * 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 "QObject" #include "gradientmap.h" #include #include #include "krita_filter_gradient_map.h" #include "KoResourceServerProvider.h" #include "kis_config_widget.h" K_PLUGIN_FACTORY_WITH_JSON(KritaGradientMapFactory, "kritagradientmap.json", registerPlugin();) KritaGradientMapConfigWidget::KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WFlags f) - : KisConfigWidget(parent, f) + : KisConfigWidget(parent, f) { Q_UNUSED(dev) - m_page = new WdgGradientMap(this); - QHBoxLayout *l = new QHBoxLayout(this); - Q_CHECK_PTR(l); - l->addWidget(m_page); - l->setContentsMargins(0, 0, 0, 0); + m_page = new WdgGradientMap(this); + QHBoxLayout *l = new QHBoxLayout(this); + Q_CHECK_PTR(l); + l->addWidget(m_page); + l->setContentsMargins(0, 0, 0, 0); connect(m_page->gradientchooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(sigConfigurationItemChanged())); } KritaGradientMapConfigWidget::~KritaGradientMapConfigWidget() { - delete m_page; + delete m_page; } void KritaGradientMapConfigWidget::gradientResourceChanged(KoResource* gradient) { Q_UNUSED(gradient) } -KisFilterConfiguration* KritaGradientMapConfigWidget::configuration() const +KisPropertiesConfigurationSP KritaGradientMapConfigWidget::configuration() const { - KisFilterConfiguration* cfg = new KisFilterConfiguration("gradientmap", 1); + KisFilterConfigurationSP cfg = new KisFilterConfiguration("gradientmap", 1); QString gradientName; gradientName = m_page->gradientchooser->currentResource()->name(); cfg->setProperty("gradientName", gradientName); return cfg; } //----------------------------- -void KritaGradientMapConfigWidget::setConfiguration(const KisPropertiesConfiguration* config) +void KritaGradientMapConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { m_page->gradientchooser->setCurrentResource(KoResourceServerProvider::instance()->gradientServer(false)->resourceByName(config->getString("gradientName"))); Q_ASSERT(config); Q_UNUSED(config); } void KritaGradientMapConfigWidget::setView(KisViewManager *view) { Q_UNUSED(view) } //------------------------------ KritaGradientMap::KritaGradientMap(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KritaFilterGradientMap())); } KritaGradientMap::~KritaGradientMap() { } //----------------------------- #include "gradientmap.moc" diff --git a/plugins/filters/gradientmap/gradientmap.h b/plugins/filters/gradientmap/gradientmap.h index 78c6f7aa62..c719e5a249 100644 --- a/plugins/filters/gradientmap/gradientmap.h +++ b/plugins/filters/gradientmap/gradientmap.h @@ -1,60 +1,76 @@ /* * This file is part of Krita * * Copyright (c) 2016 Spencer Brown * * 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. */ #pragma once #include "QObject" #include "ui_wdg_gradientmap.h" #include "kis_properties_configuration.h" #include "filter/kis_color_transformation_configuration.h" #include "kis_config_widget.h" class WdgGradientMap : public QWidget, public Ui::WdgGradientMap { Q_OBJECT public: WdgGradientMap(QWidget *parent) : QWidget(parent) { setupUi(this); } }; + +class KritaGradientMapFilterConfiguration : public KisColorTransformationConfiguration +{ +public: + KritaGradientMapFilterConfiguration(); + virtual ~KritaGradientMapFilterConfiguration(); + + virtual void setGradient(const KoResource* gradient); + + virtual const KoResource* gradient() const; + +private: + KoResource const* m_gradient; +}; + class KritaGradientMapConfigWidget : public KisConfigWidget { Q_OBJECT public: KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WFlags f = 0); virtual ~KritaGradientMapConfigWidget(); - virtual KisFilterConfiguration *configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); + WdgGradientMap * m_page; void setView(KisViewManager *view); - void gradientResourceChanged(KoResource *gradient); + void gradientResourceChanged(KoResource *gradient); }; class KritaGradientMap : public QObject { Q_OBJECT public: KritaGradientMap(QObject *parent, const QVariantList &); virtual ~KritaGradientMap(); }; diff --git a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp index 44b7b081ff..917b0f468e 100644 --- a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp @@ -1,99 +1,98 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Spencer Brown * 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 "krita_filter_gradient_map.h" #include #include #include #include #include #include "kis_config_widget.h" #include #include #include #include #include "gradientmap.h" #include KritaFilterGradientMap::KritaFilterGradientMap() : KisFilter(id(), categoryMap(), i18n("&Gradient Map")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(true); - // don't support anything just yet because of thread safety problems setSupportsLevelOfDetail(true); setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsThreading(true); } void KritaFilterGradientMap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration *config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const { Q_ASSERT(!device.isNull()); if (progressUpdater) { progressUpdater->setRange(0, applyRect.height() * applyRect.width()); } KoAbstractGradient *gradient = KoResourceServerProvider::instance()->gradientServer(false)->resourceByName(config->getString("gradientName")); KoColorSet *gradientCache = new KoColorSet(); for (int i=0; i<256; i++) { KoColor gc; gradient->colorAt(gc, ((qreal)i/255.0)); KoColorSetEntry col; col.color = gc; gradientCache->add(col); } KoColor outColor(Qt::white, device->colorSpace()); KisSequentialIterator it(device, applyRect); int p = 0; quint8 grey; const int pixelSize = device->colorSpace()->pixelSize(); do { grey = device->colorSpace()->intensity8(it.oldRawData()); outColor = gradientCache->getColor((quint32)grey).color; outColor.convertTo(device->colorSpace()); memcpy(it.rawData(), outColor.data(), pixelSize); if (progressUpdater) progressUpdater->setValue(p++); } while (it.nextPixel()); } -KisFilterConfiguration *KritaFilterGradientMap::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KritaFilterGradientMap::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration *config = new KisFilterConfiguration("gradientmap", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("gradientmap", 1); KoAbstractGradient *gradient = KoResourceServerProvider::instance()->gradientServer(false)->resources().first(); config->setProperty("gradientName", gradient->name()); return config; } KisConfigWidget * KritaFilterGradientMap::createConfigurationWidget(QWidget * parent, const KisPaintDeviceSP dev) const { - return new KritaGradientMapConfigWidget(parent, dev); + return new KritaGradientMapConfigWidget(parent, dev); } diff --git a/plugins/filters/gradientmap/krita_filter_gradient_map.h b/plugins/filters/gradientmap/krita_filter_gradient_map.h index a4e87b8ced..6d805da010 100644 --- a/plugins/filters/gradientmap/krita_filter_gradient_map.h +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.h @@ -1,53 +1,52 @@ /* * This file is part of Krita * * Copyright (c) 2016 Spencer Brown * * 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_GRADIENT_MAP_H #define KIS_GRADIENT_MAP_H #include #include #include #include #include #include #include class KritaFilterGradientMap : public KisFilter { public: KritaFilterGradientMap(); public: - static inline KoID id() { return KoID("gradientmap", i18n("Gradient Map")); } virtual void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const; - virtual KisFilterConfiguration *factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; - virtual KisConfigWidget* createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; + virtual KisConfigWidget* createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp b/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp index c9e437a9b5..0d6dde31d6 100644 --- a/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp +++ b/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp @@ -1,129 +1,129 @@ /* * Copyright (c) 2005 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. */ #include //MSVC requires that Vc come first #include "kis_simple_noise_reducer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include KisSimpleNoiseReducer::KisSimpleNoiseReducer() : KisFilter(id(), categoryEnhance(), i18n("&Gaussian Noise Reduction...")) { setSupportsPainting(false); } KisSimpleNoiseReducer::~KisSimpleNoiseReducer() { } KisConfigWidget * KisSimpleNoiseReducer::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(0, 255, 15, i18n("Threshold"), "threshold")); param.push_back(KisIntegerWidgetParam(0, 10, 1, i18n("Window size"), "windowsize")); return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration * KisSimpleNoiseReducer::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisSimpleNoiseReducer::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 0); config->setProperty("threshold", 15); config->setProperty("windowsize", 1); return config; } inline int ABS(int v) { if (v < 0) return -v; return v; } void KisSimpleNoiseReducer::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); int threshold, windowsize; - if (config == 0) { - config = defaultConfiguration(device); - } + + KisFilterConfigurationSP config = _config ? _config : defaultConfiguration(device); + if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } int count = 0; threshold = config->getInt("threshold", 15); windowsize = config->getInt("windowsize", 1); const KoColorSpace* cs = device->colorSpace(); // Compute the blur mask KisCircleMaskGenerator* kas = new KisCircleMaskGenerator(2*windowsize + 1, 1, windowsize, windowsize, 2, true); KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMaskGenerator(kas); delete kas; KisPaintDeviceSP interm = new KisPaintDevice(*device); // TODO no need for a full copy and then a transaction KisConvolutionPainter painter(interm); painter.beginTransaction(); painter.applyMatrix(kernel, interm, srcTopLeft, srcTopLeft, applyRect.size(), BORDER_REPEAT); painter.deleteTransaction(); if (progressUpdater && progressUpdater->interrupted()) { return; } KisHLineIteratorSP dstIt = device->createHLineIteratorNG(srcTopLeft.x(), srcTopLeft.y(), applyRect.width()); KisHLineConstIteratorSP intermIt = interm->createHLineConstIteratorNG(srcTopLeft.x(), srcTopLeft.y(), applyRect.width()); for (int j = 0; j < applyRect.height() && !(progressUpdater && progressUpdater->interrupted()); j++) { do { quint8 diff = cs->difference(dstIt->oldRawData(), intermIt->oldRawData()); if (diff > threshold) { memcpy(dstIt->rawData(), intermIt->oldRawData(), cs->pixelSize()); } if (progressUpdater) progressUpdater->setValue(++count); intermIt->nextPixel(); } while (dstIt->nextPixel() && !(progressUpdater && progressUpdater->interrupted())); dstIt->nextRow(); intermIt->nextRow(); } } diff --git a/plugins/filters/imageenhancement/kis_simple_noise_reducer.h b/plugins/filters/imageenhancement/kis_simple_noise_reducer.h index 7ba5da1f32..94899b488c 100644 --- a/plugins/filters/imageenhancement/kis_simple_noise_reducer.h +++ b/plugins/filters/imageenhancement/kis_simple_noise_reducer.h @@ -1,48 +1,48 @@ /* a * Copyright (c) 2005 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 KISSIMPLENOISEREDUCER_H #define KISSIMPLENOISEREDUCER_H #include #include "kis_config_widget.h" /** @author Cyrille Berger */ class KisSimpleNoiseReducer : public KisFilter { public: KisSimpleNoiseReducer(); ~KisSimpleNoiseReducer(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; static inline KoID id() { return KoID("gaussiannoisereducer", i18n("Gaussian Noise Reducer")); } protected: - virtual KisFilterConfiguration * factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; #endif diff --git a/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp b/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp index 86aa5208dc..d09b3b7f8e 100644 --- a/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp +++ b/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp @@ -1,129 +1,127 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 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. */ #include "kis_wavelet_noise_reduction.h" #include #include #include #include #include #include #include #include #include KisWaveletNoiseReduction::KisWaveletNoiseReduction() - : KisFilter(id(), categoryEnhance(), i18n("&Wavelet Noise Reducer...")) + : KisFilter(id(), categoryEnhance(), i18n("&Wavelet Noise Reducer...")) { setSupportsPainting(false); setSupportsThreading(false); } KisWaveletNoiseReduction::~KisWaveletNoiseReduction() { } KisConfigWidget * KisWaveletNoiseReduction::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisDoubleWidgetParam param; param.push_back(KisDoubleWidgetParam(0.0, 256.0, BEST_WAVELET_THRESHOLD_VALUE, i18n("Threshold"), "threshold")); return new KisMultiDoubleFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration* KisWaveletNoiseReduction::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisWaveletNoiseReduction::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 0); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 0); config->setProperty("threshold", BEST_WAVELET_THRESHOLD_VALUE); return config; } void KisWaveletNoiseReduction::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { Q_ASSERT(device); // TODO take selections into account float threshold; - if (!config) { - config = defaultConfiguration(device); - } + KisFilterConfigurationSP config = _config ? _config : defaultConfiguration(device); threshold = config->getDouble("threshold", BEST_WAVELET_THRESHOLD_VALUE); qint32 depth = device->colorSpace()->colorChannelCount(); int size; int maxrectsize = qMax(applyRect.width(), applyRect.height()); for (size = 2; size < maxrectsize; size *= 2) ; KisMathToolbox mathToolbox; if (progressUpdater) { progressUpdater->setRange(0, mathToolbox.fastWaveletTotalSteps(applyRect) * 2 + size*size*depth); } int count = 0; -// dbgFilters << size <<"" << maxrectsize <<"" << srcTopLeft.x() <<"" << srcTopLeft.y(); + // dbgFilters << size <<"" << maxrectsize <<"" << srcTopLeft.x() <<"" << srcTopLeft.y(); -// dbgFilters <<"Transforming..."; + // dbgFilters <<"Transforming..."; KisMathToolbox::KisWavelet* buff = 0; KisMathToolbox::KisWavelet* wav = 0; try { buff = mathToolbox.initWavelet(device, applyRect); } catch (std::bad_alloc) { if (buff) delete buff; return; } try { wav = mathToolbox.fastWaveletTransformation(device, applyRect, buff); } catch (std::bad_alloc) { if (wav) delete wav; return; } -// dbgFilters <<"Thresholding..."; + // dbgFilters <<"Thresholding..."; float* fin = wav->coeffs + wav->depth * wav->size * wav->size; for (float* it = wav->coeffs + wav->depth; it < fin; it++) { if (*it > threshold) { *it -= threshold; } else if (*it < -threshold) { *it += threshold; } else { *it = 0.; } if (progressUpdater) progressUpdater->setValue(++count); } -// dbgFilters <<"Untransforming..."; + // dbgFilters <<"Untransforming..."; mathToolbox.fastWaveletUntransformation(device, applyRect, wav, buff); delete wav; delete buff; } diff --git a/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h b/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h index ba365895ca..99858e2dfd 100644 --- a/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h +++ b/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h @@ -1,57 +1,57 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 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_WAVELET_NOISE_REDUCTION_H #define KIS_WAVELET_NOISE_REDUCTION_H #include #include #define BEST_WAVELET_THRESHOLD_VALUE 7.0 /** @author Cyrille Berger */ class KisWaveletNoiseReduction : public KisFilter { public: KisWaveletNoiseReduction(); ~KisWaveletNoiseReduction(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; static inline KoID id() { return KoID("waveletnoisereducer", i18n("Wavelet Noise Reducer")); } private: - virtual KisFilterConfiguration * factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; #endif diff --git a/plugins/filters/indexcolors/indexcolors.cpp b/plugins/filters/indexcolors/indexcolors.cpp index b1d814d1c7..3e4aca223e 100644 --- a/plugins/filters/indexcolors/indexcolors.cpp +++ b/plugins/filters/indexcolors/indexcolors.cpp @@ -1,144 +1,144 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #include "indexcolors.h" #include #include #include #include #include #include #include #include "kiswdgindexcolors.h" #include "palettegeneratorconfig.h" K_PLUGIN_FACTORY_WITH_JSON(IndexColorsFactory, "kritaindexcolors.json", registerPlugin();) IndexColors::IndexColors(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KisFilterIndexColors())); } IndexColors::~IndexColors() { } KisFilterIndexColors::KisFilterIndexColors() : KisColorTransformationFilter(id(), categoryArtistic(), i18n("&Index Colors...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); // Technically it is TO_LAB16 but that would only display a warning we don't want // This filter will always degrade the color space, that is it's purpose setSupportsPainting(true); setShowConfigurationWidget(true); } -KoColorTransformation* KisFilterIndexColors::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisFilterIndexColors::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { IndexColorPalette pal; PaletteGeneratorConfig palCfg; palCfg.fromByteArray(config->getProperty("paletteGen").toByteArray()); pal = palCfg.generate(); if(config->getBool("reduceColorsEnabled")) { int maxClrs = config->getInt("colorLimit"); while(pal.numColors() > maxClrs) pal.mergeMostReduantColors(); } pal.similarityFactors.L = config->getFloat("LFactor"); pal.similarityFactors.a = config->getFloat("aFactor"); pal.similarityFactors.b = config->getFloat("bFactor"); return new KisIndexColorTransformation(pal, cs, config->getInt("alphaSteps")); } KisConfigWidget* KisFilterIndexColors::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); KisWdgIndexColors* w = new KisWdgIndexColors(parent); w->setup( QStringList() << i18nc("Color palette shade", "Bright") << i18nc("Color palette shade", "Light") << i18nc("Color palette shade", "Base") << i18nc("Color palette shade", "Shadow") , 4 ); return w; } -KisFilterConfiguration* KisFilterIndexColors::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterIndexColors::factoryConfiguration(const KisPaintDeviceSP) const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration(id().id(), 0); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 0); PaletteGeneratorConfig palCfg; // Default constructor is factory config config->setProperty("paletteGen", palCfg.toByteArray()); config->setProperty("LFactor", 1.f); config->setProperty("aFactor", 1.f); config->setProperty("bFactor", 1.f); config->setProperty("reduceColorsEnabled", false); config->setProperty("colorLimit", 32); config->setProperty("alphaSteps", 1); return config; } KisIndexColorTransformation::KisIndexColorTransformation(IndexColorPalette palette, const KoColorSpace* cs, int alphaSteps) : m_colorSpace(cs), m_psize(cs->pixelSize()) { m_palette = palette; static const qreal max = KoColorSpaceMathsTraits::max; if(alphaSteps > 0) { m_alphaStep = max / alphaSteps; m_alphaHalfStep = m_alphaStep / 2; } else { m_alphaStep = 0; m_alphaHalfStep = 0; } } void KisIndexColorTransformation::transform(const quint8* src, quint8* dst, qint32 nPixels) const { union { quint16 laba[4]; LabColor lab; } clr; while (nPixels--) { m_colorSpace->toLabA16(src, reinterpret_cast(clr.laba), 1); clr.lab = m_palette.getNearestIndex(clr.lab); if(m_alphaStep) { quint16 amod = clr.laba[3] % m_alphaStep; clr.laba[3] = clr.laba[3] + (amod > m_alphaHalfStep ? m_alphaStep - amod : -amod); } m_colorSpace->fromLabA16(reinterpret_cast(clr.laba), dst, 1); src += m_psize; dst += m_psize; } } #include "indexcolors.moc" \ No newline at end of file diff --git a/plugins/filters/indexcolors/indexcolors.h b/plugins/filters/indexcolors/indexcolors.h index 0642116916..7bbe1bfb75 100644 --- a/plugins/filters/indexcolors/indexcolors.h +++ b/plugins/filters/indexcolors/indexcolors.h @@ -1,69 +1,69 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #ifndef INDEXCOLORS_H #define INDEXCOLORS_H #include #include #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" #include #include "indexcolorpalette.h" class IndexColors : public QObject { Q_OBJECT public: IndexColors(QObject *parent, const QVariantList &); virtual ~IndexColors(); }; class KisFilterIndexColors : public KisColorTransformationFilter { public: KisFilterIndexColors(); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; virtual KisConfigWidget* createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; static inline KoID id() { return KoID("indexcolors", i18n("Index Colors")); } protected: - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; class KisIndexColorTransformation : public KoColorTransformation { public: KisIndexColorTransformation(IndexColorPalette palette, const KoColorSpace* cs, int alphaSteps); virtual void transform(const quint8* src, quint8* dst, qint32 nPixels) const; private: const KoColorSpace* m_colorSpace; quint32 m_psize; IndexColorPalette m_palette; quint16 m_alphaStep; quint16 m_alphaHalfStep; }; #endif diff --git a/plugins/filters/indexcolors/kiswdgindexcolors.cpp b/plugins/filters/indexcolors/kiswdgindexcolors.cpp index c375e6ee8b..fd2659e8aa 100644 --- a/plugins/filters/indexcolors/kiswdgindexcolors.cpp +++ b/plugins/filters/indexcolors/kiswdgindexcolors.cpp @@ -1,192 +1,192 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #include "filter/kis_color_transformation_configuration.h" #include "kiswdgindexcolors.h" #include "palettegeneratorconfig.h" #include "ui_kiswdgindexcolors.h" #include "kis_int_parse_spin_box.h" #include KisWdgIndexColors::KisWdgIndexColors(QWidget* parent, Qt::WFlags f, int delay): KisConfigWidget(parent, f, delay) { ui = new Ui::KisWdgIndexColors; ui->setupUi(this); connect(ui->diagCheck, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(ui->inbetweenSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->alphaStepsSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->colorLimit, SIGNAL(valueChanged(int)), SLOT(slotColorLimitChanged(int))); connect(ui->colorLimit, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->colorLimitCheck, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(ui->luminanceSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->aSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(ui->bSlider, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); } void KisWdgIndexColors::slotColorLimitChanged(int value) { ui->colorLimit->setSuffix(i18ncp("suffix for a spinbox", " color", " colors", value)); } void KisWdgIndexColors::setup(QStringList shadesLabels, int ramps) { int rows = shadesLabels.length(); int collumns = ramps; m_colorSelectors.resize(rows); m_stepSpinners.resize(rows-1); // Labels for the shades for(int row = 0; row < rows; ++row) { QLabel* l = new QLabel(shadesLabels[row], ui->colorsBox); ui->layoutColors->addWidget(l, row+1, 0); m_colorSelectors[row].resize(collumns); } // Labels for the ramps /*for(int col = 0; col < collumns; ++col) { QLabel* l = new QLabel(rampsLabels[col], ui->colorsBox); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ui->layoutColors->addWidget(l, 0, col+1); }*/ // Step selectors for the shade gradients for(int row = 0; row < (rows-1); ++row) { QLabel* l0 = new QLabel(shadesLabels[row+1]); QLabel* l1 = new QLabel(QString::fromUtf8("↔")); QLabel* l2 = new QLabel(shadesLabels[row]); QSpinBox* s = new KisIntParseSpinBox(); s->setMinimum(0); s->setMaximum(32); s->setValue(2); connect(s, SIGNAL(valueChanged(int)), this, SIGNAL(sigConfigurationItemChanged())); m_stepSpinners[row] = s; ui->layoutRowSteps->addWidget(l0, row, 0); ui->layoutRowSteps->addWidget(l1, row, 1); ui->layoutRowSteps->addWidget(l2, row, 2); ui->layoutRowSteps->addWidget(s, row, 3); } // Color selectors for(int y = 0; y < rows; ++y) for(int x = 0; x < collumns; ++x) { KisColorButton* b = new KisColorButton; QCheckBox* c = new QCheckBox; c->setChecked(false); b->setEnabled(false); b->setMaximumWidth(50); c->setMaximumWidth(21); // Ugh. I hope this won't be causing any issues. Trying to get rid of the unnecessary spacing after it. connect(c, SIGNAL(toggled(bool)), b, SLOT(setEnabled(bool))); connect(c, SIGNAL(toggled(bool)), this, SIGNAL(sigConfigurationItemChanged())); connect(b, SIGNAL(changed(KoColor)), this, SIGNAL(sigConfigurationItemChanged())); QHBoxLayout* cell = new QHBoxLayout(); cell->setSpacing(0); cell->setContentsMargins(0, 0, 0, 0); cell->addWidget(c); cell->addWidget(b); ui->layoutColors->addLayout(cell, 1+y, 1+x); m_colorSelectors[y][x].button = b; m_colorSelectors[y][x].checkbox = c; } } -KisPropertiesConfiguration* KisWdgIndexColors::configuration() const +KisPropertiesConfigurationSP KisWdgIndexColors::configuration() const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration("indexcolors", 1); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration("indexcolors", 1); PaletteGeneratorConfig palCfg; for(int y = 0; y < 4; ++y) for(int x = 0; x < 4; ++x) { palCfg.colors[y][x] = m_colorSelectors[y][x].button->color().toQColor(); palCfg.colorsEnabled[y][x] = m_colorSelectors[y][x].button->isEnabled(); } for(int y = 0; y < 3; ++y) palCfg.gradientSteps[y] = m_stepSpinners[y]->value(); palCfg.diagonalGradients = ui->diagCheck->isChecked(); palCfg.inbetweenRampSteps = ui->inbetweenSpinBox->value(); IndexColorPalette pal = palCfg.generate(); ui->colorCount->setText(QString::number(pal.numColors())); config->setProperty("paletteGen", palCfg.toByteArray()); config->setProperty("LFactor", ui->luminanceSlider->value() / 100.f); config->setProperty("aFactor", ui->aSlider->value() / 100.f); config->setProperty("bFactor", ui->bSlider->value() / 100.f); config->setProperty("reduceColorsEnabled", ui->colorLimitCheck->isChecked()); config->setProperty("colorLimit", ui->colorLimit->value()); config->setProperty("alphaSteps", ui->alphaStepsSpinBox->value()); return config; } -void KisWdgIndexColors::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgIndexColors::setConfiguration(const KisPropertiesConfigurationSP config) { PaletteGeneratorConfig palCfg; palCfg.fromByteArray(config->getProperty("paletteGen").toByteArray()); ui->luminanceSlider->setValue(config->getFloat("LFactor")*100); ui->aSlider->setValue(config->getFloat("aFactor")*100); ui->bSlider->setValue(config->getFloat("bFactor")*100); ui->alphaStepsSpinBox->setValue(config->getInt("alphaSteps")); ui->colorLimitCheck->setChecked(config->getBool("reduceColorsEnabled")); ui->colorLimit->setEnabled(config->getBool("reduceColorsEnabled")); ui->colorLimit->setValue(config->getInt("colorLimit")); ui->diagCheck->setChecked(palCfg.diagonalGradients); ui->inbetweenSpinBox->setValue(palCfg.inbetweenRampSteps); for(int y = 0; y < 4; ++y) for(int x = 0; x < 4; ++x) { m_colorSelectors[y][x].checkbox->setChecked(palCfg.colorsEnabled[y][x]); m_colorSelectors[y][x].button->setEnabled(palCfg.colorsEnabled[y][x]); KoColor c; c.fromQColor(palCfg.colors[y][x]); m_colorSelectors[y][x].button->setColor(c); } for(int y = 0; y < 3; ++y) m_stepSpinners[y]->setValue(palCfg.gradientSteps[y]); IndexColorPalette pal = palCfg.generate(); ui->colorCount->setText(QString::number(pal.numColors())); } diff --git a/plugins/filters/indexcolors/kiswdgindexcolors.h b/plugins/filters/indexcolors/kiswdgindexcolors.h index f1d4605f3a..ee576f8d6f 100644 --- a/plugins/filters/indexcolors/kiswdgindexcolors.h +++ b/plugins/filters/indexcolors/kiswdgindexcolors.h @@ -1,59 +1,59 @@ /* * Copyright 2014 Manuel Riecke * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaim all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. */ #ifndef KISWDGINDEXCOLORS_H #define KISWDGINDEXCOLORS_H #include #include class QCheckBox; class KisColorButton; namespace Ui { class KisWdgIndexColors; } class KisWdgIndexColors : public KisConfigWidget { Q_OBJECT public: KisWdgIndexColors(QWidget* parent = 0, Qt::WFlags f = 0, int delay = 500); - virtual KisPropertiesConfiguration* configuration() const; - virtual void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP config); void setup(QStringList shadesLabels, int ramps); private Q_SLOTS: void slotColorLimitChanged(int value); private: struct ColorWidgets { KisColorButton* button; QCheckBox* checkbox; }; QVector< QVector > m_colorSelectors; QVector< QSpinBox* > m_stepSpinners; Ui::KisWdgIndexColors* ui; }; #endif // KISWDGINDEXCOLORS_H diff --git a/plugins/filters/levelfilter/kis_level_filter.cpp b/plugins/filters/levelfilter/kis_level_filter.cpp index 8f84d984aa..1d479e2a2e 100644 --- a/plugins/filters/levelfilter/kis_level_filter.cpp +++ b/plugins/filters/levelfilter/kis_level_filter.cpp @@ -1,312 +1,312 @@ /* * This file is part of Krita * * Copyright (c) 2006 Frederic Coiffier * * 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_level_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_paint_device.h" #include "kis_histogram.h" #include "kis_painter.h" #include "kis_gradient_slider.h" #include "kis_processing_information.h" #include "kis_selection.h" #include "kis_types.h" #include "filter/kis_color_transformation_configuration.h" KisLevelFilter::KisLevelFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Levels...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L)); setSupportsPainting(false); setColorSpaceIndependence(TO_LAB16); } KisLevelFilter::~KisLevelFilter() { } KisConfigWidget * KisLevelFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { return new KisLevelConfigWidget(parent, dev); } -KoColorTransformation* KisLevelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisLevelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { if (!config) { warnKrita << "No configuration object for level filter\n"; return 0; } Q_ASSERT(config); int blackvalue = config->getInt("blackvalue"); int whitevalue = config->getInt("whitevalue", 255); double gammavalue = config->getDouble("gammavalue", 1.0); int outblackvalue = config->getInt("outblackvalue"); int outwhitevalue = config->getInt("outwhitevalue", 255); quint16 transfer[256]; for (int i = 0; i < 256; i++) { if (i <= blackvalue) transfer[i] = outblackvalue; else if (i < whitevalue) { double a = (double)(i - blackvalue) / (double)(whitevalue - blackvalue); a = (double)(outwhitevalue - outblackvalue) * pow(a, (1.0 / gammavalue)); transfer[i] = int(outblackvalue + a); } else transfer[i] = outwhitevalue; // TODO use floats instead of integer in the configuration transfer[i] = ((int)transfer[i] * 0xFFFF) / 0xFF ; } return cs->createBrightnessContrastAdjustment(transfer); } KisLevelConfigWidget::KisLevelConfigWidget(QWidget * parent, KisPaintDeviceSP dev) : KisConfigWidget(parent) { Q_ASSERT(dev); m_page.setupUi(this); m_page.ingradient->enableGamma(true); m_page.blackspin->setValue(0); m_page.whitespin->setValue(255); m_page.gammaspin->setValue(1.0); m_page.ingradient->slotModifyGamma(1.0); m_page.outblackspin->setValue(0); m_page.outwhitespin->setValue(255); connect(m_page.blackspin, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.whitespin, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.ingradient, SIGNAL(sigModifiedGamma(double)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.blackspin, SIGNAL(valueChanged(int)), m_page.ingradient, SLOT(slotModifyBlack(int))); connect(m_page.whitespin, SIGNAL(valueChanged(int)), m_page.ingradient, SLOT(slotModifyWhite(int))); connect(m_page.gammaspin, SIGNAL(valueChanged(double)), m_page.ingradient, SLOT(slotModifyGamma(double))); connect(m_page.blackspin, SIGNAL(valueChanged(int)), this, SLOT(slotModifyInWhiteLimit(int))); connect(m_page.whitespin, SIGNAL(valueChanged(int)), this, SLOT(slotModifyInBlackLimit(int))); connect(m_page.ingradient, SIGNAL(sigModifiedBlack(int)), m_page.blackspin, SLOT(setValue(int))); connect(m_page.ingradient, SIGNAL(sigModifiedWhite(int)), m_page.whitespin, SLOT(setValue(int))); connect(m_page.ingradient, SIGNAL(sigModifiedGamma(double)), m_page.gammaspin, SLOT(setValue(double))); connect(m_page.outblackspin, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.outwhitespin, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.outblackspin, SIGNAL(valueChanged(int)), m_page.outgradient, SLOT(slotModifyBlack(int))); connect(m_page.outwhitespin, SIGNAL(valueChanged(int)), m_page.outgradient, SLOT(slotModifyWhite(int))); connect(m_page.outblackspin, SIGNAL(valueChanged(int)), this, SLOT(slotModifyOutWhiteLimit(int))); connect(m_page.outwhitespin, SIGNAL(valueChanged(int)), this, SLOT(slotModifyOutBlackLimit(int))); connect(m_page.outgradient, SIGNAL(sigModifiedBlack(int)), m_page.outblackspin, SLOT(setValue(int))); connect(m_page.outgradient, SIGNAL(sigModifiedWhite(int)), m_page.outwhitespin, SLOT(setValue(int))); connect(m_page.butauto, SIGNAL(clicked(bool)), this, SLOT(slotAutoLevel(void))); connect((QObject*)(m_page.chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(slotDrawHistogram(bool))); KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); m_histogram.reset( new KisHistogram(dev, dev->exactBounds(), producer, LINEAR) ); m_histlog = false; m_page.histview->resize(288,100); slotDrawHistogram(); } KisLevelConfigWidget::~KisLevelConfigWidget() { } void KisLevelConfigWidget::slotDrawHistogram(bool logarithmic) { int wHeight = m_page.histview->height(); int wHeightMinusOne = wHeight - 1; int wWidth = m_page.histview->width(); if (m_histlog != logarithmic) { // Update the m_histogram if (logarithmic) m_histogram->setHistogramType(LOGARITHMIC); else m_histogram->setHistogramType(LINEAR); m_histlog = logarithmic; } QPalette appPalette = QApplication::palette(); QPixmap pix(wWidth-100, wHeight); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); double highest = (double)m_histogram->calculations().getHighest(); qint32 bins = m_histogram->producer()->numberOfBins(); // use nearest neighbour interpolation if (m_histogram->getHistogramType() == LINEAR) { double factor = (double)(wHeight - wHeight / 5.0) / highest; for (int i = 0; i < wWidth; i++) { int binNo = qRound((double)i / wWidth * (bins - 1)); if ((int)m_histogram->getValue(binNo) != 0) p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - (int)m_histogram->getValue(binNo) * factor); } } else { double factor = (double)(wHeight - wHeight / 5.0) / (double)log(highest); for (int i = 0; i < wWidth; i++) { int binNo = qRound((double)i / wWidth * (bins - 1)) ; if ((int)m_histogram->getValue(binNo) != 0) p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - log((double)m_histogram->getValue(binNo)) * factor); } } m_page.histview->setPixmap(pix); } void KisLevelConfigWidget::slotModifyInBlackLimit(int limit) { m_page.blackspin->setMaximum(limit - 1); } void KisLevelConfigWidget::slotModifyInWhiteLimit(int limit) { m_page.whitespin->setMinimum(limit + 1); } void KisLevelConfigWidget::slotModifyOutBlackLimit(int limit) { m_page.outblackspin->setMaximum(limit - 1); } void KisLevelConfigWidget::slotModifyOutWhiteLimit(int limit) { m_page.outwhitespin->setMinimum(limit + 1); } void KisLevelConfigWidget::slotAutoLevel(void) { Q_ASSERT(m_histogram); qint32 num_bins = m_histogram->producer()->numberOfBins(); Q_ASSERT(num_bins > 1); int chosen_low_bin = 0, chosen_high_bin = num_bins-1; int count_thus_far = m_histogram->getValue(0); const int total_count = m_histogram->producer()->count(); const double threshold = 0.006; // find the low and hi point/bins based on summing count percentages // // this implementation is a port of GIMP's auto level implementation // (use a GPLv2 version as reference, specifically commit 51bfd07f18ef045a3e43632218fd92cae9ff1e48) for (int bin=0; bin<(num_bins-1); ++bin) { int next_count_thus_far = count_thus_far + m_histogram->getValue(bin+1); double this_percentage = static_cast(count_thus_far) / total_count; double next_percentage = static_cast(next_count_thus_far) / total_count; //dbgKrita << "bin" << bin << "this_percentage" << this_percentage << "next_percentage" << next_percentage; if (fabs(this_percentage - threshold) < fabs(next_percentage - threshold)) { chosen_low_bin = bin; break; } count_thus_far = next_count_thus_far; } count_thus_far = m_histogram->getValue(num_bins-1); for (int bin=(num_bins-1); bin>0; --bin) { int next_count_thus_far = count_thus_far + m_histogram->getValue(bin-1); double this_percentage = static_cast(count_thus_far) / total_count; double next_percentage = static_cast(next_count_thus_far) / total_count; //dbgKrita << "hi-bin" << bin << "this_percentage" << this_percentage << "next_percentage" << next_percentage; if (fabs(this_percentage - threshold) < fabs(next_percentage - threshold)) { chosen_high_bin = bin; break; } count_thus_far = next_count_thus_far; } if (chosen_low_bin < chosen_high_bin) { m_page.blackspin->setValue(chosen_low_bin); m_page.ingradient->slotModifyBlack(chosen_low_bin); m_page.whitespin->setValue(chosen_high_bin); m_page.ingradient->slotModifyWhite(chosen_high_bin); } } -KisPropertiesConfiguration * KisLevelConfigWidget::configuration() const +KisPropertiesConfigurationSP KisLevelConfigWidget::configuration() const { KisColorTransformationConfiguration * config = new KisColorTransformationConfiguration(KisLevelFilter::id().id(), 1); config->setProperty("blackvalue", m_page.blackspin->value()); config->setProperty("whitevalue", m_page.whitespin->value()); config->setProperty("gammavalue", m_page.ingradient->getGamma()); config->setProperty("outblackvalue", m_page.outblackspin->value()); config->setProperty("outwhitevalue", m_page.outwhitespin->value()); return config; } -void KisLevelConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisLevelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("blackvalue", value)) { m_page.blackspin->setValue(value.toUInt()); m_page.ingradient->slotModifyBlack(value.toUInt()); } if (config->getProperty("whitevalue", value)) { m_page.whitespin->setValue(value.toUInt()); m_page.ingradient->slotModifyWhite(value.toUInt()); } if (config->getProperty("gammavalue", value)) { m_page.gammaspin->setValue(value.toUInt()); m_page.ingradient->slotModifyGamma(value.toDouble()); } if (config->getProperty("outblackvalue", value)) { m_page.outblackspin->setValue(value.toUInt()); m_page.outgradient->slotModifyBlack(value.toUInt()); } if (config->getProperty("outwhitevalue", value)) { m_page.outwhitespin->setValue(value.toUInt()); m_page.outgradient->slotModifyWhite(value.toUInt()); } } diff --git a/plugins/filters/levelfilter/kis_level_filter.h b/plugins/filters/levelfilter/kis_level_filter.h index d2945b7b8d..114c074033 100644 --- a/plugins/filters/levelfilter/kis_level_filter.h +++ b/plugins/filters/levelfilter/kis_level_filter.h @@ -1,84 +1,84 @@ /* * This file is part of Krita * * Copyright (c) 2006 Frederic Coiffier * * 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_LEVEL_FILTER_H_ #define _KIS_LEVEL_FILTER_H_ #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" #include "ui_wdg_level.h" class WdgLevel; class QWidget; class KisHistogram; /** * This class affect Intensity Y of the image */ class KisLevelFilter : public KisColorTransformationFilter { public: KisLevelFilter(); ~KisLevelFilter(); public: -// virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; +// virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; static inline KoID id() { return KoID("levels", i18n("Levels")); } }; class KisLevelConfigWidget : public KisConfigWidget { Q_OBJECT public: KisLevelConfigWidget(QWidget * parent, KisPaintDeviceSP dev); virtual ~KisLevelConfigWidget(); - virtual KisPropertiesConfiguration* configuration() const; - void setConfiguration(const KisPropertiesConfiguration* config); + virtual KisPropertiesConfigurationSP configuration() const; + void setConfiguration(const KisPropertiesConfigurationSP config); Ui::WdgLevel m_page; protected Q_SLOTS: void slotDrawHistogram(bool logarithmic = false); void slotModifyInBlackLimit(int); void slotModifyInWhiteLimit(int); void slotModifyOutBlackLimit(int); void slotModifyOutWhiteLimit(int); void slotAutoLevel(void); protected: QScopedPointer m_histogram; bool m_histlog; }; #endif diff --git a/plugins/filters/noisefilter/kis_wdg_noise.cpp b/plugins/filters/noisefilter/kis_wdg_noise.cpp index f3ca6bee7a..f7020848a9 100644 --- a/plugins/filters/noisefilter/kis_wdg_noise.cpp +++ b/plugins/filters/noisefilter/kis_wdg_noise.cpp @@ -1,72 +1,72 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_noise.h" #include #include #include "ui_wdgnoiseoptions.h" KisWdgNoise::KisWdgNoise(KisFilter* /*nfilter*/, QWidget* parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgNoiseOptions(); m_widget->setupUi(this); connect(widget()->intLevel, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intOpacity, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); m_seedThreshold = rand(); m_seedRed = rand(); m_seedGreen = rand(); m_seedBlue = rand(); } KisWdgNoise::~KisWdgNoise() { delete m_widget; } -void KisWdgNoise::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgNoise::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("level", value)) { widget()->intLevel->setValue(value.toUInt()); } if (config->getProperty("opacity", value)) { widget()->intOpacity->setValue(value.toUInt()); } } -KisPropertiesConfiguration* KisWdgNoise::configuration() const +KisPropertiesConfigurationSP KisWdgNoise::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("noise", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("noise", 1); config->setProperty("level", this->widget()->intLevel->value()); config->setProperty("opacity", this->widget()->intOpacity->value()); config->setProperty("seedThreshold", m_seedThreshold); config->setProperty("seedRed", m_seedRed); config->setProperty("seedGreen", m_seedGreen); config->setProperty("seedBlue", m_seedBlue); return config; } diff --git a/plugins/filters/noisefilter/kis_wdg_noise.h b/plugins/filters/noisefilter/kis_wdg_noise.h index 20b477fc01..59f1f04fe7 100644 --- a/plugins/filters/noisefilter/kis_wdg_noise.h +++ b/plugins/filters/noisefilter/kis_wdg_noise.h @@ -1,47 +1,47 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_NOISE_H #define KIS_WDG_NOISE_H #include class Ui_WdgNoiseOptions; class KisFilter; class KisWdgNoise : public KisConfigWidget { Q_OBJECT public: KisWdgNoise(KisFilter* nfilter, QWidget* parent = 0); ~KisWdgNoise(); public: inline const Ui_WdgNoiseOptions* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgNoiseOptions* m_widget; int m_seedThreshold, m_seedRed, m_seedGreen, m_seedBlue; }; #endif diff --git a/plugins/filters/noisefilter/noisefilter.cpp b/plugins/filters/noisefilter/noisefilter.cpp index 41d7da55d6..008db81482 100644 --- a/plugins/filters/noisefilter/noisefilter.cpp +++ b/plugins/filters/noisefilter/noisefilter.cpp @@ -1,154 +1,154 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 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. */ #include "noisefilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_noise.h" #include "ui_wdgnoiseoptions.h" #include K_PLUGIN_FACTORY_WITH_JSON(KritaNoiseFilterFactory, "kritanoisefilter.json", registerPlugin();) KritaNoiseFilter::KritaNoiseFilter(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(new KisFilterNoise()); } KritaNoiseFilter::~KritaNoiseFilter() { } KisFilterNoise::KisFilterNoise() : KisFilter(id(), categoryOther(), i18n("&Random Noise...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } -KisFilterConfiguration* KisFilterNoise::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterNoise::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("noise", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("noise", 1); config->setProperty("level", 50); config->setProperty("opacity", 100); config->setProperty("seedThreshold", rand()); config->setProperty("seedRed", rand()); config->setProperty("seedGreen", rand()); config->setProperty("seedBlue", rand()); return config; } KisConfigWidget * KisFilterNoise::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgNoise((KisFilter*)this, (QWidget*)parent); } void KisFilterNoise::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_ASSERT(!device.isNull()); if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } int count = 0; const KoColorSpace * cs = device->colorSpace(); QVariant value; int level = (config && config->getProperty("level", value)) ? value.toInt() : 50; int opacity = (config && config->getProperty("opacity", value)) ? value.toInt() : 100; KisSequentialIterator it(device, applyRect); quint8* interm = new quint8[cs->pixelSize()]; double threshold = (100.0 - level) * 0.01; qint16 weights[2]; weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; const quint8* pixels[2]; pixels[0] = interm; KoMixColorsOp * mixOp = cs->mixColorsOp(); int seedThreshold = rand(); int seedRed = rand(); int seedGreen = rand(); int seedBlue = rand(); if (config) { seedThreshold = config->getInt("seedThreshold", seedThreshold); seedRed = config->getInt("seedRed", seedRed); seedGreen = config->getInt("seedGreen", seedGreen); seedBlue = config->getInt("seedBlue", seedBlue); } KisRandomGenerator randt(seedThreshold); KisRandomGenerator randr(seedRed); KisRandomGenerator randg(seedGreen); KisRandomGenerator randb(seedBlue); do { if (randt.doubleRandomAt(it.x(), it.y()) > threshold) { // XXX: Added static_cast to get rid of warnings QColor c = qRgb(static_cast((double)randr.doubleRandomAt(it.x(), it.y()) * 255), static_cast((double)randg.doubleRandomAt(it.x(), it.y()) * 255), static_cast((double)randb.doubleRandomAt(it.x(), it.y()) * 255)); cs->fromQColor(c, interm, 0); pixels[1] = it.oldRawData(); mixOp->mixColors(pixels, weights, 2, it.rawData()); } if (progressUpdater) progressUpdater->setValue(++count); } while (it.nextPixel() && !(progressUpdater && progressUpdater->interrupted())); delete [] interm; } #include "noisefilter.moc" diff --git a/plugins/filters/noisefilter/noisefilter.h b/plugins/filters/noisefilter/noisefilter.h index 8203bd7736..dfd0570b9a 100644 --- a/plugins/filters/noisefilter/noisefilter.h +++ b/plugins/filters/noisefilter/noisefilter.h @@ -1,56 +1,56 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 NOISEFILTER_H #define NOISEFILTER_H #include #include #include "filter/kis_filter.h" class KisConfigWidget; class KritaNoiseFilter : public QObject { Q_OBJECT public: KritaNoiseFilter(QObject *parent, const QVariantList &); virtual ~KritaNoiseFilter(); }; class KisFilterNoise : public KisFilter { public: KisFilterNoise(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("noise", i18n("Noise")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/filters/normalize/kis_normalize.cpp b/plugins/filters/normalize/kis_normalize.cpp index ae4dc170ce..3eb77992e4 100644 --- a/plugins/filters/normalize/kis_normalize.cpp +++ b/plugins/filters/normalize/kis_normalize.cpp @@ -1,129 +1,129 @@ /* * * Copyright (c) 2015 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. */ #include "kis_normalize.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KritaNormalizeFilterFactory, "kritanormalize.json", registerPlugin();) KritaNormalizeFilter::KritaNormalizeFilter(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KisFilterNormalize())); } KritaNormalizeFilter::~KritaNormalizeFilter() { } KisFilterNormalize::KisFilterNormalize() : KisColorTransformationFilter(KoID("normalize" , i18n("Normalize")) , KisFilter::categoryMap(), i18n("&Normalize...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); setShowConfigurationWidget(false); } -KoColorTransformation* KisFilterNormalize::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisFilterNormalize::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { Q_UNUSED(config); return new KisNormalizeTransformation(cs); } KisNormalizeTransformation::KisNormalizeTransformation(const KoColorSpace* cs) : m_colorSpace(cs), m_psize(cs->pixelSize()) { } void KisNormalizeTransformation::transform(const quint8* src, quint8* dst, qint32 nPixels) const { QVector3D normal_vector; QVector channelValues(4); //if (m_colorSpace->colorDepthId().id()!="F16" && m_colorSpace->colorDepthId().id()!="F32" && m_colorSpace->colorDepthId().id()!="F64") { /* I don't know why, but the results of this are unexpected with a floating point space. * And manipulating the pixels gives strange results. */ while (nPixels--) { m_colorSpace->normalisedChannelsValue(src, channelValues); normal_vector.setX(channelValues[2]*2-1.0); normal_vector.setY(channelValues[1]*2-1.0); normal_vector.setZ(channelValues[0]*2-1.0); normal_vector.normalize(); channelValues[0]=normal_vector.z()*0.5+0.5; channelValues[1]=normal_vector.y()*0.5+0.5; channelValues[2]=normal_vector.x()*0.5+0.5; //channelValues[3]=1.0; m_colorSpace->fromNormalisedChannelsValue(dst, channelValues); dst[3]=src[3]; src += m_psize; dst += m_psize; } /* } else { while (nPixels--) { m_colorSpace->normalisedChannelsValue(src, channelValues); qreal max = qMax(channelValues[2], qMax(channelValues[1], channelValues[0])); qreal min = qMin(channelValues[2], qMin(channelValues[1], channelValues[0])); qreal range = max-min; normal_vector.setX( ((channelValues[2]-min)/range) *2.0-1.0); normal_vector.setY( ((channelValues[1]-min)/range) *2.0-1.0); normal_vector.setZ( ((channelValues[0]-min)/range) *2.0-1.0); normal_vector.normalize(); channelValues[2]=normal_vector.x()*0.5+0.5; channelValues[1]=normal_vector.y()*0.5+0.5; channelValues[0]=normal_vector.z()*0.5+0.5; //channelValues[3]=1.0; m_colorSpace->fromNormalisedChannelsValue(dst, channelValues); dst[3]=src[3]; //hack to trunucate values. m_colorSpace->toRgbA16(dst, reinterpret_cast(m_rgba), 1); m_colorSpace->fromRgbA16(reinterpret_cast(m_rgba), dst, 1); src += m_psize; dst += m_psize; } }*/ } #include "kis_normalize.moc" diff --git a/plugins/filters/normalize/kis_normalize.h b/plugins/filters/normalize/kis_normalize.h index 6930e19d6d..1b07e70dec 100644 --- a/plugins/filters/normalize/kis_normalize.h +++ b/plugins/filters/normalize/kis_normalize.h @@ -1,52 +1,52 @@ /* * Copyright (c) 2015 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 NORMALIZE_H #define NORMALIZE_H #include #include #include "filter/kis_color_transformation_filter.h" class KritaNormalizeFilter : public QObject { Q_OBJECT public: KritaNormalizeFilter(QObject *parent, const QVariantList &); virtual ~KritaNormalizeFilter(); }; class KisFilterNormalize : public KisColorTransformationFilter { public: KisFilterNormalize(); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; }; class KisNormalizeTransformation : public KoColorTransformation { public: KisNormalizeTransformation(const KoColorSpace* cs); virtual void transform(const quint8* src, quint8* dst, qint32 nPixels) const; private: const KoColorSpace* m_colorSpace; quint32 m_psize; }; #endif diff --git a/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp b/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp index d6bcadee45..9b3b165b92 100644 --- a/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp +++ b/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cpp @@ -1,220 +1,220 @@ /* * This file is part of Krita * * Copyright (c) 2004 Michael Thaler * Copyright (c) 2008 Cyrille Berger * * ported from digikam, Copyrighted by Gilles Caulier, * Original Oilpaint algorithm copyrighted 2004 by * Pieter Z. Voloshyn . * * 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_oilpaint_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_integer_filter_widget.h" KisOilPaintFilter::KisOilPaintFilter() : KisFilter(id(), KisFilter::categoryArtistic(), i18n("&Oilpaint...")) { setSupportsPainting(true); setSupportsThreading(false); setSupportsAdjustmentLayers(true); } void KisOilPaintFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(!device.isNull()); qint32 width = applyRect.width(); qint32 height = applyRect.height(); //read the filter configuration values from the KisFilterConfiguration object quint32 brushSize = config ? config->getInt("brushSize", 1) : 1; quint32 smooth = config ? config->getInt("smooth", 30) : 30; OilPaint(device, device, srcTopLeft, applyRect.topLeft(), width, height, brushSize, smooth, progressUpdater); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to apply the OilPaint effect. * * data => The image data in RGBA mode. * w => Width of image. * h => Height of image. * BrushSize => Brush size. * Smoothness => Smooth value. * * Theory => Using MostFrequentColor function we take the main color in * a matrix and simply write at the original position. */ void KisOilPaintFilter::OilPaint(const KisPaintDeviceSP src, KisPaintDeviceSP dst, const QPoint& srcTopLeft, const QPoint& dstTopLeft, int w, int h, int BrushSize, int Smoothness, KoUpdater* progressUpdater) const { if (progressUpdater) { progressUpdater->setRange(0, w * h); } QRect bounds(srcTopLeft.x(), srcTopLeft.y(), w, h); KisHLineConstIteratorSP it = src->createHLineConstIteratorNG(srcTopLeft.x(), srcTopLeft.y(), w); KisHLineIteratorSP dstIt = dst->createHLineIteratorNG(dstTopLeft.x(), dstTopLeft.y(), w); int progress = 0; for (qint32 yOffset = 0; yOffset < h; yOffset++) { do { //&& !cancelRequested()) { MostFrequentColor(src, dstIt->rawData(), bounds, it->x(), it->y(), BrushSize, Smoothness); } while (it->nextPixel() && dstIt->nextPixel()); it->nextRow(); dstIt->nextRow(); if (progressUpdater) progressUpdater->setValue(progress += w); } } // This method has been ported from Pieter Z. Voloshyn's algorithm code in Digikam. /* Function to determine the most frequent color in a matrix * * Bits => Bits array * Width => Image width * Height => Image height * X => Position horizontal * Y => Position vertical * Radius => Is the radius of the matrix to be analyzed * Intensity => Intensity to calculate * * Theory => This function creates a matrix with the analyzed pixel in * the center of this matrix and find the most frequenty color */ void KisOilPaintFilter::MostFrequentColor(KisPaintDeviceSP src, quint8* dst, const QRect& bounds, int X, int Y, int Radius, int Intensity) const { uint I; double Scale = Intensity / 255.0; // Alloc some arrays to be used uchar *IntensityCount = new uchar[(Intensity + 1) * sizeof(uchar)]; const KoColorSpace* cs = src->colorSpace(); QVector channel(cs->channelCount()); QVector* AverageChannels = new QVector[(Intensity + 1)]; // Erase the array memset(IntensityCount, 0, (Intensity + 1) * sizeof(uchar)); int startx = qMax(X - Radius, bounds.left()); int starty = qMax(Y - Radius, bounds.top()); int width = (2 * Radius) + 1; if ((startx + width - 1) > bounds.right()) width = bounds.right() - startx + 1; Q_ASSERT((startx + width - 1) <= bounds.right()); int height = (2 * Radius) + 1; if ((starty + height) > bounds.bottom()) height = bounds.bottom() - starty + 1; Q_ASSERT((starty + height - 1) <= bounds.bottom()); KisSequentialConstIterator srcIt(src, QRect(startx, starty, width, height)); do { cs->normalisedChannelsValue(srcIt.rawDataConst(), channel); I = (uint)(cs->intensity8(srcIt.rawDataConst()) * Scale); IntensityCount[I]++; if (IntensityCount[I] == 1) { AverageChannels[I] = channel; } else { for (int i = 0; i < channel.size(); i++) { AverageChannels[I][i] += channel[i]; } } } while (srcIt.nextPixel()); I = 0; int MaxInstance = 0; for (int i = 0 ; i <= Intensity ; ++i) { if (IntensityCount[i] > MaxInstance) { I = i; MaxInstance = IntensityCount[i]; } } if (MaxInstance != 0) { channel = AverageChannels[I]; for (int i = 0; i < channel.size(); i++) { channel[i] /= MaxInstance; } cs->fromNormalisedChannelsValue(dst, channel); } else { memset(dst, 0, cs->pixelSize()); cs->setOpacity(dst, OPACITY_OPAQUE_U8, 1); } delete [] IntensityCount; // free all the arrays delete [] AverageChannels; } KisConfigWidget * KisOilPaintFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(1, 5, 1, i18n("Brush size"), "brushSize")); param.push_back(KisIntegerWidgetParam(10, 255, 30, i18nc("smooth out the painting strokes the filter creates", "Smooth"), "smooth")); KisMultiIntegerFilterWidget * w = new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); w->setConfiguration(factoryConfiguration(0)); return w; } -KisFilterConfiguration* KisOilPaintFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisOilPaintFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("oilpaint", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("oilpaint", 1); config->setProperty("brushSize", 1); config->setProperty("smooth", 30); return config; } diff --git a/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h b/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h index 92a6885afe..570a7730fd 100644 --- a/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h +++ b/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h @@ -1,51 +1,51 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_OILPAINT_FILTER_H_ #define _KIS_OILPAINT_FILTER_H_ #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisOilPaintFilter : public KisFilter { public: KisOilPaintFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("oilpaint", i18n("Oilpaint")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: void OilPaint(const KisPaintDeviceSP src, KisPaintDeviceSP dst, const QPoint& srcTopLeft, const QPoint& dstTopLeft, int w, int h, int BrushSize, int Smoothness, KoUpdater* progressUpdater) const; void MostFrequentColor(KisPaintDeviceSP src, quint8* dst, const QRect& bounds, int X, int Y, int Radius, int Intensity) const; }; #endif diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp index f989076b18..de3399d0cd 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.cpp @@ -1,186 +1,186 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * 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_phong_bumpmap_config_widget.h" #include #include #include "phong_bumpmap_constants.h" #include "KoChannelInfo.h" #include "KoColorSpace.h" KisPhongBumpmapConfigWidget::KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WFlags f) : KisConfigWidget(parent, f) , m_device(dev) { Q_ASSERT(m_device); m_page = new KisPhongBumpmapWidget(this); KisSizeGroup *matPropLabelsGroup = new KisSizeGroup(this); matPropLabelsGroup->addWidget(m_page->lblAmbientReflectivity); matPropLabelsGroup->addWidget(m_page->lblDiffuseReflectivity); matPropLabelsGroup->addWidget(m_page->lblSpecularReflectivity); matPropLabelsGroup->addWidget(m_page->lblSpecularShinyExp); // Connect widgets to each other connect(m_page->azimuthDial1, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox1, SLOT(setValue(int))); connect(m_page->azimuthDial2, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox2, SLOT(setValue(int))); connect(m_page->azimuthDial3, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox3, SLOT(setValue(int))); connect(m_page->azimuthDial4, SIGNAL(valueChanged(int)), m_page->azimuthSpinBox4, SLOT(setValue(int))); connect(m_page->azimuthSpinBox1, SIGNAL(valueChanged(int)), m_page->azimuthDial1, SLOT(setValue(int))); connect(m_page->azimuthSpinBox2, SIGNAL(valueChanged(int)), m_page->azimuthDial2, SLOT(setValue(int))); connect(m_page->azimuthSpinBox3, SIGNAL(valueChanged(int)), m_page->azimuthDial3, SLOT(setValue(int))); connect(m_page->azimuthSpinBox4, SIGNAL(valueChanged(int)), m_page->azimuthDial4, SLOT(setValue(int))); //Let widgets warn the preview of when they are updated connect(m_page->azimuthDial1, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial2, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial3, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->azimuthDial4, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo1, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo2, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo3, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightKColorCombo4, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox1, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox2, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox3, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->inclinationSpinBox4, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->useNormalMap, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->diffuseReflectivityGroup, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->specularReflectivityGroup, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->ambientReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->diffuseReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->specularReflectivityKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->shinynessExponentKisSliderSpinBox, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->heightChannelComboBox, SIGNAL(currentIndexChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox1, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox2, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox3, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); connect(m_page->lightSourceGroupBox4, SIGNAL(toggled(bool)), SIGNAL(sigConfigurationItemChanged())); QVBoxLayout *l = new QVBoxLayout(this); Q_CHECK_PTR(l); l->addWidget(m_page); /* fill in the channel chooser */ QList channels = m_device->colorSpace()->channels(); for (quint8 ch = 0; ch < m_device->colorSpace()->colorChannelCount(); ch++) m_page->heightChannelComboBox->addItem(channels.at(ch)->name()); connect(m_page->useNormalMap, SIGNAL(toggled(bool)), this, SLOT(slotDisableHeightChannelCombobox(bool) ) ); } -void KisPhongBumpmapConfigWidget::setConfiguration(const KisPropertiesConfiguration *config) +void KisPhongBumpmapConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { if (!config) return; QVariant tempcolor; if (config->getBool(USE_NORMALMAP_IS_ENABLED)) { m_page->heightChannelComboBox->setEnabled(false); } else { m_page->heightChannelComboBox->setEnabled(true); } m_page->ambientReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_AMBIENT_REFLECTIVITY) ); m_page->diffuseReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_DIFFUSE_REFLECTIVITY) ); m_page->specularReflectivityKisDoubleSliderSpinBox->setValue( config->getDouble(PHONG_SPECULAR_REFLECTIVITY) ); m_page->shinynessExponentKisSliderSpinBox->setValue( config->getInt(PHONG_SHINYNESS_EXPONENT) ); m_page->useNormalMap->setChecked( config->getBool(USE_NORMALMAP_IS_ENABLED) ); m_page->diffuseReflectivityGroup->setChecked( config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED) ); m_page->specularReflectivityGroup->setChecked( config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED) ); // NOTE: Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 m_page->lightSourceGroupBox1->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[0]) ); m_page->lightSourceGroupBox2->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[1]) ); m_page->lightSourceGroupBox3->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[2]) ); m_page->lightSourceGroupBox4->setChecked( config->getBool(PHONG_ILLUMINANT_IS_ENABLED[3]) ); config->getProperty(PHONG_ILLUMINANT_COLOR[0], tempcolor); m_page->lightKColorCombo1->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[1], tempcolor); m_page->lightKColorCombo2->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[2], tempcolor); m_page->lightKColorCombo3->setColor(tempcolor.value()); config->getProperty(PHONG_ILLUMINANT_COLOR[3], tempcolor); m_page->lightKColorCombo4->setColor(tempcolor.value()); m_page->azimuthSpinBox1->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[0]) ); m_page->azimuthSpinBox2->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[1]) ); m_page->azimuthSpinBox3->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[2]) ); m_page->azimuthSpinBox4->setValue( config->getDouble(PHONG_ILLUMINANT_AZIMUTH[3]) ); m_page->inclinationSpinBox1->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[0]) ); m_page->inclinationSpinBox2->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[1]) ); m_page->inclinationSpinBox3->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[2]) ); m_page->inclinationSpinBox4->setValue( config->getDouble(PHONG_ILLUMINANT_INCLINATION[3]) ); } -KisPropertiesConfiguration *KisPhongBumpmapConfigWidget::configuration() const +KisPropertiesConfigurationSP KisPhongBumpmapConfigWidget::configuration() const { - KisFilterConfiguration *config = new KisFilterConfiguration("phongbumpmap", 2); + KisFilterConfigurationSP config = new KisFilterConfiguration("phongbumpmap", 2); config->setProperty(PHONG_HEIGHT_CHANNEL, m_page->heightChannelComboBox->currentText()); config->setProperty(USE_NORMALMAP_IS_ENABLED, m_page->useNormalMap->isChecked()); config->setProperty(PHONG_AMBIENT_REFLECTIVITY, m_page->ambientReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY, m_page->diffuseReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_SPECULAR_REFLECTIVITY, m_page->specularReflectivityKisDoubleSliderSpinBox->value()); config->setProperty(PHONG_SHINYNESS_EXPONENT, m_page->shinynessExponentKisSliderSpinBox->value()); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED, m_page->diffuseReflectivityGroup->isChecked()); config->setProperty(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED, m_page->specularReflectivityGroup->isChecked()); //config->setProperty(PHONG_SHINYNESS_EXPONENT_IS_ENABLED, m_page->specularReflectivityCheckBox->isChecked()); // Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[0], m_page->lightSourceGroupBox1->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[1], m_page->lightSourceGroupBox2->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[2], m_page->lightSourceGroupBox3->isChecked()); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[3], m_page->lightSourceGroupBox4->isChecked()); config->setProperty(PHONG_ILLUMINANT_COLOR[0], m_page->lightKColorCombo1->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[1], m_page->lightKColorCombo2->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[2], m_page->lightKColorCombo3->color()); config->setProperty(PHONG_ILLUMINANT_COLOR[3], m_page->lightKColorCombo4->color()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[0], m_page->azimuthSpinBox1->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[1], m_page->azimuthSpinBox2->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[2], m_page->azimuthSpinBox3->value()); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[3], m_page->azimuthSpinBox4->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[0], m_page->inclinationSpinBox1->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[1], m_page->inclinationSpinBox2->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[2], m_page->inclinationSpinBox3->value()); config->setProperty(PHONG_ILLUMINANT_INCLINATION[3], m_page->inclinationSpinBox4->value()); // Read configuration /* QMap rofl = QMap(config->getProperties()); QMap::const_iterator i; for (i = rofl.constBegin(); i != rofl.constEnd(); ++i) dbgKrita << i.key() << ":" << i.value(); */ return config; } void KisPhongBumpmapConfigWidget::slotDisableHeightChannelCombobox(bool normalmapchecked) { if (normalmapchecked) { m_page->heightChannelComboBox->setEnabled(false); } else { m_page->heightChannelComboBox->setEnabled(true); } } diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h index aba727091c..a61c8d0dbc 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_config_widget.h @@ -1,66 +1,66 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * 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_PHONG_BUMPMAP_CONFIG_WIDGET_H #define KIS_PHONG_BUMPMAP_CONFIG_WIDGET_H #include "ui_wdgphongbumpmap.h" #include "kis_paint_device.h" #include "kis_config_widget.h" #include "kis_image.h" class KisPhongBumpmapWidget : public QWidget, public Ui::WdgPhongBumpmap { Q_OBJECT public: KisPhongBumpmapWidget(QWidget *parent) : QWidget(parent) { setupUi(this); ambientReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); diffuseReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); specularReflectivityKisDoubleSliderSpinBox -> setRange(0, 1, 2); shinynessExponentKisSliderSpinBox -> setRange(1, 200); ambientReflectivityKisDoubleSliderSpinBox -> setValue(0.1); diffuseReflectivityKisDoubleSliderSpinBox -> setValue(0.5); specularReflectivityKisDoubleSliderSpinBox -> setValue(0.5); shinynessExponentKisSliderSpinBox -> setValue(40); } }; class KisPhongBumpmapConfigWidget : public KisConfigWidget { Q_OBJECT public: KisPhongBumpmapConfigWidget(const KisPaintDeviceSP dev, QWidget *parent, Qt::WFlags f = 0); virtual ~KisPhongBumpmapConfigWidget() {} - void setConfiguration(const KisPropertiesConfiguration *config); - KisPropertiesConfiguration *configuration() const; + void setConfiguration(const KisPropertiesConfigurationSP config); + KisPropertiesConfigurationSP configuration() const; KisPhongBumpmapWidget *m_page; private: KisPaintDeviceSP m_device; private Q_SLOTS: void slotDisableHeightChannelCombobox(bool normalmapchecked); }; #endif //KIS_PHONG_BUMPMAP_CONFIG_WIDGET_H diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp index 5d5c28fb22..a34b1b7e8e 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp @@ -1,238 +1,238 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * 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_phong_bumpmap_filter.h" #include "kis_phong_bumpmap_config_widget.h" #include "phong_pixel_processor.h" #include "kis_debug.h" #include "kis_paint_device.h" #include "kis_config_widget.h" #include "KoUpdater.h" #include "kis_math_toolbox.h" #include "KoColorSpaceRegistry.h" #include #include #include "kis_iterator_ng.h" #include "kundo2command.h" #include "kis_painter.h" KisFilterPhongBumpmap::KisFilterPhongBumpmap() : KisFilter(KoID("phongbumpmap" , i18n("PhongBumpmap")), KisFilter::categoryMap(), i18n("&PhongBumpmap...")) { setColorSpaceIndependence(TO_LAB16); setSupportsPainting(true); setSupportsLevelOfDetail(true); } void KisFilterPhongBumpmap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration *config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater ) const { if (!config) return; if (progressUpdater) progressUpdater->setProgress(0); QString userChosenHeightChannel = config->getString(PHONG_HEIGHT_CHANNEL, "FAIL"); bool m_usenormalmap = config->getBool(USE_NORMALMAP_IS_ENABLED); if (userChosenHeightChannel == "FAIL") { qDebug("FIX YOUR FILTER"); return; } KoChannelInfo *m_heightChannel = 0; Q_FOREACH (KoChannelInfo* channel, device->colorSpace()->channels()) { if (userChosenHeightChannel == channel->name()) { m_heightChannel = channel; } } if (!m_heightChannel) { m_heightChannel = device->colorSpace()->channels().first(); } KIS_ASSERT_RECOVER_RETURN(m_heightChannel); QRect inputArea = applyRect; QRect outputArea = applyRect; if (m_usenormalmap==false) { inputArea.adjust(-1, -1, 1, 1); } quint32 posup; quint32 posdown; quint32 posleft; quint32 posright; QColor I; //Reflected light if (progressUpdater) progressUpdater->setProgress(1); //======Preparation paraphlenalia======= //Hardcoded facts about Phong Bumpmap: it _will_ generate an RGBA16 bumpmap const quint8 BYTE_DEPTH_OF_BUMPMAP = 2; // 16 bits per channel const quint8 CHANNEL_COUNT_OF_BUMPMAP = 4; // RGBA const quint32 pixelsOfInputArea = abs(inputArea.width() * inputArea.height()); const quint32 pixelsOfOutputArea = abs(outputArea.width() * outputArea.height()); const quint8 pixelSize = BYTE_DEPTH_OF_BUMPMAP * CHANNEL_COUNT_OF_BUMPMAP; const quint32 bytesToFillBumpmapArea = pixelsOfOutputArea * pixelSize; QVector bumpmap(bytesToFillBumpmapArea); quint8 *bumpmapDataPointer = bumpmap.data(); quint32 ki = KoChannelInfo::displayPositionToChannelIndex(m_heightChannel->displayPosition(), device->colorSpace()->channels()); PhongPixelProcessor tileRenderer(pixelsOfInputArea, config); if (progressUpdater) progressUpdater->setProgress(2); //===============RENDER================= QVector toDoubleFuncPtr(device->colorSpace()->channels().count()); KisMathToolbox mathToolbox; if (!mathToolbox.getToDoubleChannelPtr(device->colorSpace()->channels(), toDoubleFuncPtr)) { return; } KisHLineConstIteratorSP iterator; quint32 curPixel = 0; iterator = device->createHLineConstIteratorNG(inputArea.x(), inputArea.y(), inputArea.width() ); if (m_usenormalmap==false) { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); curPixel++; } while (iterator->nextPixel()); iterator->nextRow(); } if (progressUpdater) progressUpdater->setProgress(50); const int tileHeightMinus1 = inputArea.height() - 1; const int tileWidthMinus1 = inputArea.width() - 1; // Foreach INNER pixel in tile for (int y = 1; y < tileHeightMinus1; ++y) { for (int x = 1; x < tileWidthMinus1; ++x) { posup = (y + 1) * inputArea.width() + x; posdown = (y - 1) * inputArea.width() + x; posleft = y * inputArea.width() + x - 1; posright = y * inputArea.width() + x + 1; memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromHeightmap(posup, posdown, posleft, posright).data(), pixelSize); bumpmapDataPointer += pixelSize; } } } else { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); QVector current_pixel_values(4); device->colorSpace()->normalisedChannelsValue(data, current_pixel_values ); //dbgKrita<< "Vector:" << current_pixel_values[2] << "," << current_pixel_values[1] << "," << current_pixel_values[0]; memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromNormalmap(current_pixel_values[2], current_pixel_values[1], current_pixel_values[0]).data(), pixelSize); curPixel++; //pointer that crashes here, but not in the other if statement. bumpmapDataPointer += pixelSize; } while (iterator->nextPixel()); iterator->nextRow(); } } if (progressUpdater) progressUpdater->setProgress(90); KisPaintDeviceSP bumpmapPaintDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb16()); bumpmapPaintDevice->writeBytes(bumpmap.data(), outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); KUndo2Command *leaker = bumpmapPaintDevice->convertTo(device->colorSpace(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); KisPainter copier(device); copier.bitBlt(outputArea.x(), outputArea.y(), bumpmapPaintDevice, outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); //device->prepareClone(bumpmapPaintDevice); //device->makeCloneFrom(bumpmapPaintDevice, bumpmapPaintDevice->extent()); // THIS COULD BE BUG GY delete leaker; if (progressUpdater) progressUpdater->setProgress(100); } -KisFilterConfiguration *KisFilterPhongBumpmap::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterPhongBumpmap::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration *config = new KisFilterConfiguration(id(), 2); + KisFilterConfigurationSP config = new KisFilterConfiguration(id(), 2); config->setProperty(PHONG_AMBIENT_REFLECTIVITY, 0.2); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY, 0.5); config->setProperty(PHONG_SPECULAR_REFLECTIVITY, 0.3); config->setProperty(PHONG_SHINYNESS_EXPONENT, 2); config->setProperty(USE_NORMALMAP_IS_ENABLED, false); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED, true); config->setProperty(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED, true); // Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[0], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[1], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[2], false); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[3], false); config->setProperty(PHONG_ILLUMINANT_COLOR[0], QColor(255, 255, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[1], QColor(255, 0, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[2], QColor(0, 0, 255)); config->setProperty(PHONG_ILLUMINANT_COLOR[3], QColor(0, 255, 0)); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[0], 50); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[1], 100); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[2], 150); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[3], 200); config->setProperty(PHONG_ILLUMINANT_INCLINATION[0], 25); config->setProperty(PHONG_ILLUMINANT_INCLINATION[1], 20); config->setProperty(PHONG_ILLUMINANT_INCLINATION[2], 30); config->setProperty(PHONG_ILLUMINANT_INCLINATION[3], 40); return config; } -QRect KisFilterPhongBumpmap::neededRect(const QRect &rect, const KisFilterConfiguration* /*config*/, int /*lod*/) const +QRect KisFilterPhongBumpmap::neededRect(const QRect &rect, const KisFilterConfigurationSP /*config*/, int /*lod*/) const { return rect.adjusted(-1, -1, 1, 1); } -QRect KisFilterPhongBumpmap::changedRect(const QRect &rect, const KisFilterConfiguration* /*config*/, int /*lod*/) const +QRect KisFilterPhongBumpmap::changedRect(const QRect &rect, const KisFilterConfigurationSP /*config*/, int /*lod*/) const { return rect; } KisConfigWidget *KisFilterPhongBumpmap::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { KisPhongBumpmapConfigWidget *w = new KisPhongBumpmapConfigWidget(dev, parent); return w; } diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.h b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.h index 579b6cda66..2c8abbc945 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.h +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.h @@ -1,54 +1,54 @@ /* * Copyright (c) 2010 Dmitry Kazakov * Copyright (c) 2010-2011 José Luis Vergara * * 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_PHONG_BUMPMAP_FILTER_H #define KIS_PHONG_BUMPMAP_FILTER_H #include #include /** * This class is an implementation of the phong illumination model. * It uses a heightmap as an input mesh (normally taken from 1 * channel of a colorspace) to achieve a bumpmapping effect with * multiple illumination sources. */ class KisFilterPhongBumpmap : public KisFilter { public: KisFilterPhongBumpmap(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration *config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater ) const; - QRect neededRect(const QRect &rect, const KisFilterConfiguration *config, int lod) const; - QRect changedRect(const QRect &rect, const KisFilterConfiguration *config, int lod) const; + QRect neededRect(const QRect &rect, const KisFilterConfigurationSP config, int lod) const; + QRect changedRect(const QRect &rect, const KisFilterConfigurationSP config, int lod) const; virtual KisConfigWidget *createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; private: //bool m_usenormalmap; }; #endif //KIS_PHONG_BUMPMAP_FILTER_H diff --git a/plugins/filters/phongbumpmap/phong_pixel_processor.cpp b/plugins/filters/phongbumpmap/phong_pixel_processor.cpp index b2e4d0d50b..a906860bc7 100644 --- a/plugins/filters/phongbumpmap/phong_pixel_processor.cpp +++ b/plugins/filters/phongbumpmap/phong_pixel_processor.cpp @@ -1,202 +1,202 @@ /* * Copyright (c) 2010-2012 José Luis Vergara * * 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 "phong_pixel_processor.h" #include #include #include -PhongPixelProcessor::PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfiguration* config) +PhongPixelProcessor::PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfigurationSP config) { m_pixelArea = pixelArea; initialize(config); } -void PhongPixelProcessor::initialize(const KisPropertiesConfiguration* config) +void PhongPixelProcessor::initialize(const KisPropertiesConfigurationSP config) { // Basic, fundamental normal_vector = QVector3D(0, 0, 1); vision_vector = QVector3D(0, 0, 1); x_vector = QVector3D(1, 0, 0); y_vector = QVector3D(0, 1, 0); // Mutable light_vector = QVector3D(0, 0, 0); reflection_vector = QVector3D(0, 0, 0); //setLightVector(QVector3D(-8, 8, 2)); Illuminant light[PHONG_TOTAL_ILLUMINANTS]; QVariant guiLight[PHONG_TOTAL_ILLUMINANTS]; qint32 azimuth; qint32 inclination; for (int i = 0; i < PHONG_TOTAL_ILLUMINANTS; i++) { if (config->getBool(PHONG_ILLUMINANT_IS_ENABLED[i])) { config->getProperty(PHONG_ILLUMINANT_COLOR[i], guiLight[i]); light[i].RGBvalue << guiLight[i].value().redF(); light[i].RGBvalue << guiLight[i].value().greenF(); light[i].RGBvalue << guiLight[i].value().blueF(); azimuth = config->getInt(PHONG_ILLUMINANT_AZIMUTH[i]) - 90; inclination = config->getInt(PHONG_ILLUMINANT_INCLINATION[i]); qreal m; //2D vector magnitude light[i].lightVector.setZ( sin( inclination * M_PI / 180 ) ); m = cos( inclination * M_PI / 180); light[i].lightVector.setX( cos( azimuth * M_PI / 180 ) * m ); light[i].lightVector.setY( sin( azimuth * M_PI / 180 ) * m ); //Pay close attention to this, indexes will move in this line lightSources.append(light[i]); } } size = lightSources.size(); //Code that exists only to swiftly switch to the other algorithm (reallyFastIlluminatePixel) to test if (size > 0) { fastLight = light[0]; fastLight2 = light[0]; } //Ka, Kd and Ks must be between 0 and 1 or grave errors will happen Ka = config->getDouble(PHONG_AMBIENT_REFLECTIVITY); Kd = config->getDouble(PHONG_DIFFUSE_REFLECTIVITY); Ks = config->getDouble(PHONG_SPECULAR_REFLECTIVITY); shiny_exp = config->getInt(PHONG_SHINYNESS_EXPONENT); Ia = Id = Is = 0; diffuseLightIsEnabled = config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED); specularLightIsEnabled = config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED); realheightmap = QVector(m_pixelArea, 0); } PhongPixelProcessor::~PhongPixelProcessor() { } void PhongPixelProcessor::setLightVector(QVector3D lightVector) { lightVector.normalize(); light_vector = lightVector; } QVector PhongPixelProcessor::IlluminatePixelFromHeightmap(quint32 posup, quint32 posdown, quint32 posleft, quint32 posright) { QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // Algorithm begins, Phong Illumination Model normal_vector.setX(- realheightmap[posright] + realheightmap[posleft]); normal_vector.setY(- realheightmap[posup] + realheightmap[posdown]); normal_vector.setZ(8); normal_vector.normalize(); // PREPARE ALGORITHM HERE finalPixel = IlluminatePixel(); return finalPixel; } QVector PhongPixelProcessor::IlluminatePixel() { qreal temp; quint8 channel = 0; const quint8 totalChannels = 3; // The 4th is alpha and we'll fill it with a nice 0xFFFF qreal computation[] = {0, 0, 0}; QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // PREPARE ALGORITHM HERE for (int i = 0; i < size; i++) { light_vector = lightSources.at(i).lightVector; for (channel = 0; channel < totalChannels; channel++) { Ia = lightSources.at(i).RGBvalue.at(channel) * Ka; computation[channel] += Ia; } if (diffuseLightIsEnabled) { temp = Kd * QVector3D::dotProduct(normal_vector, light_vector); for (channel = 0; channel < totalChannels; channel++) { Id = lightSources.at(i).RGBvalue.at(channel) * temp; if (Id < 0) Id = 0; if (Id > 1) Id = 1; computation[channel] += Id; } } if (specularLightIsEnabled) { reflection_vector = (2 * pow(QVector3D::dotProduct(normal_vector, light_vector), shiny_exp)) * normal_vector - light_vector; temp = Ks * QVector3D::dotProduct(vision_vector, reflection_vector); for (channel = 0; channel < totalChannels; channel++) { Is = lightSources.at(i).RGBvalue.at(channel) * temp; if (Is < 0) Is = 0; if (Is > 1) Is = 1; computation[channel] += Is; } } } for (channel = 0; channel < totalChannels; channel++) { if (computation[channel] > 1) computation[channel] = 1; if (computation[channel] < 0) computation[channel] = 0; } //RGBA actually uses the BGRA order of channels, hence the disorder finalPixel[2] = quint16(computation[0] * 0xFFFF); finalPixel[1] = quint16(computation[1] * 0xFFFF); finalPixel[0] = quint16(computation[2] * 0xFFFF); return finalPixel; } QVector PhongPixelProcessor::IlluminatePixelFromNormalmap(qreal r, qreal g, qreal b) { QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // if () // Algorithm begins, Phong Illumination Model normal_vector.setX(r*2-1.0); normal_vector.setY(-(g*2-1.0)); normal_vector.setZ(b*2-1.0); //normal_vector.normalize(); // PREPARE ALGORITHM HERE finalPixel = IlluminatePixel(); return finalPixel; } diff --git a/plugins/filters/phongbumpmap/phong_pixel_processor.h b/plugins/filters/phongbumpmap/phong_pixel_processor.h index 0066a56813..e1f51cbc63 100644 --- a/plugins/filters/phongbumpmap/phong_pixel_processor.h +++ b/plugins/filters/phongbumpmap/phong_pixel_processor.h @@ -1,101 +1,101 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * 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 PHONG_PIXEL_PROCESSOR_H #define PHONG_PIXEL_PROCESSOR_H #include #include #include #include #include #include #include #include "phong_bumpmap_constants.h" #include "kis_properties_configuration.h" struct Illuminant { QList RGBvalue; QVector3D lightVector; }; class PhongPixelProcessor { public: - PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfiguration* config); + PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfigurationSP config); ~PhongPixelProcessor(); - void initialize(const KisPropertiesConfiguration* config); + void initialize(const KisPropertiesConfigurationSP config); void normalizeHeightmap(); QVector3D reflection_vector; QVector3D normal_vector; QVector3D x_vector; QVector3D y_vector; QVector3D light_vector; QVector3D vision_vector; QVector realheightmap; ///Ambient light coefficient qreal Ka; ///Diffuse light coefficient qreal Kd; ///Specular light coefficient qreal Ks; ///Shinyness exponent qreal shiny_exp; ///Total ambient light qreal Ia; ///Total diffuse light qreal Id; ///Total specular light qreal Is; QVector IlluminatePixelFromHeightmap(quint32 posup, quint32 posdown, quint32 posleft, quint32 posright); QVector IlluminatePixel(); QVector IlluminatePixelFromNormalmap(qreal r, qreal g, qreal b); void setLightVector(QVector3D light_vector); ///Light sources to use (those disabled in the GUI are not present here) QList lightSources; ///Size of this stuff quint8 size; Illuminant fastLight; Illuminant fastLight2; bool diffuseLightIsEnabled; bool specularLightIsEnabled; private: quint32 m_pixelArea; }; #endif diff --git a/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp b/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp index 13d38df324..e6dff618e8 100644 --- a/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp +++ b/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp @@ -1,142 +1,142 @@ /* * This file is part of Krita * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * 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_pixelize_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_integer_filter_widget.h" #include KisPixelizeFilter::KisPixelizeFilter() : KisFilter(id(), KisFilter::categoryArtistic(), i18n("&Pixelize...")) { setSupportsPainting(true); setSupportsThreading(false); setSupportsAdjustmentLayers(false); } void KisPixelizeFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); qint32 width = applyRect.width(); qint32 height = applyRect.height(); //read the filter configuration values from the KisFilterConfiguration object quint32 pixelWidth = config ? config->getInt("pixelWidth", 10) : 10; quint32 pixelHeight = config ? config->getInt("pixelHeight", 10) : 10; if (pixelWidth == 0) pixelWidth = 1; if (pixelHeight == 0) pixelHeight = 1; qint32 pixelSize = device->pixelSize(); QVector average(pixelSize); qint32 count; if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } qint32 numberOfPixelsProcessed = 0; for (qint32 y = 0; y < height; y += pixelHeight - (y % pixelHeight)) { qint32 h = pixelHeight; h = qMin(h, height - y); for (qint32 x = 0; x < width; x += pixelWidth - (x % pixelWidth)) { qint32 w = pixelWidth; w = qMin(w, width - x); average.fill(0, pixelSize); count = 0; //read KisSequentialConstIterator srcIt(device, QRect(srcTopLeft.x() + x, srcTopLeft.y() + y, w, h)); do { for (qint32 i = 0; i < pixelSize; i++) { average[i] += srcIt.oldRawData()[i]; } count++; } while (srcIt.nextPixel()); //average if (count > 0) { for (qint32 i = 0; i < pixelSize; i++) average[i] /= count; } //write KisSequentialIterator dstIt(device, QRect(srcTopLeft.x() + x, srcTopLeft.y() + y, w, h)); do { for (int i = 0; i < pixelSize; i++) { dstIt.rawData()[i] = average[i]; } } while (dstIt.nextPixel()); if (progressUpdater) progressUpdater->setValue(++numberOfPixelsProcessed); } } } KisConfigWidget * KisPixelizeFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(2, 512, 10, i18n("Pixel width"), "pixelWidth")); param.push_back(KisIntegerWidgetParam(2, 512, 10, i18n("Pixel height"), "pixelHeight")); return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration* KisPixelizeFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisPixelizeFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("pixelize", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("pixelize", 1); config->setProperty("pixelWidth", 10); config->setProperty("pixelHeight", 10); return config; } diff --git a/plugins/filters/pixelizefilter/kis_pixelize_filter.h b/plugins/filters/pixelizefilter/kis_pixelize_filter.h index b7b4a50548..19b1dfb705 100644 --- a/plugins/filters/pixelizefilter/kis_pixelize_filter.h +++ b/plugins/filters/pixelizefilter/kis_pixelize_filter.h @@ -1,47 +1,47 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_PIXELIZE_FILTER_H_ #define _KIS_PIXELIZE_FILTER_H_ #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisPixelizeFilter : public KisFilter { public: KisPixelizeFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const; static inline KoID id() { return KoID("pixelize", i18n("Pixelize")); } public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; #endif diff --git a/plugins/filters/posterize/posterize.cpp b/plugins/filters/posterize/posterize.cpp index eedd5df766..b9e82783bf 100644 --- a/plugins/filters/posterize/posterize.cpp +++ b/plugins/filters/posterize/posterize.cpp @@ -1,110 +1,110 @@ /* * Copyright (c) 2014 Manuel Riecke * * 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 "posterize.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(PosterizeFactory, "kritaposterize.json", registerPlugin();) Posterize::Posterize(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KisFilterPosterize())); } Posterize::~Posterize() { } KisFilterPosterize::KisFilterPosterize() : KisColorTransformationFilter(id(), categoryArtistic(), i18n("&Posterize...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); setShowConfigurationWidget(true); } -KoColorTransformation* KisFilterPosterize::createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const +KoColorTransformation* KisFilterPosterize::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { return new KisPosterizeColorTransformation(config->getInt("steps", 16), cs); } KisPosterizeColorTransformation::KisPosterizeColorTransformation(int steps, const KoColorSpace* cs) : m_colorSpace(cs), m_psize(cs->pixelSize()) { m_step = KoColorSpaceMathsTraits::max / steps; m_halfStep = m_step / 2; } KisConfigWidget* KisFilterPosterize::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(2, 128, 16, i18n("Steps"), "steps")); return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration* KisFilterPosterize::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterPosterize::factoryConfiguration(const KisPaintDeviceSP) const { - KisColorTransformationConfiguration* config = new KisColorTransformationConfiguration(id().id(), 0); + KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 0); config->setProperty("steps", 16); return config; } void KisPosterizeColorTransformation::transform(const quint8* src, quint8* dst, qint32 nPixels) const { quint16 m_rgba[4]; quint16 m_mod[4]; while (nPixels--) { m_colorSpace->toRgbA16(src, reinterpret_cast(m_rgba), 1); m_mod[0] = m_rgba[0] % m_step; m_mod[1] = m_rgba[1] % m_step; m_mod[2] = m_rgba[2] % m_step; m_mod[3] = m_rgba[3] % m_step; m_rgba[0] = m_rgba[0] + (m_mod[0] > m_halfStep ? m_step - m_mod[0] : -m_mod[0]); m_rgba[1] = m_rgba[1] + (m_mod[1] > m_halfStep ? m_step - m_mod[1] : -m_mod[1]); m_rgba[2] = m_rgba[2] + (m_mod[2] > m_halfStep ? m_step - m_mod[2] : -m_mod[2]); m_rgba[3] = m_rgba[3] + (m_mod[3] > m_halfStep ? m_step - m_mod[3] : -m_mod[3]); m_colorSpace->fromRgbA16(reinterpret_cast(m_rgba), dst, 1); src += m_psize; dst += m_psize; } } #include "posterize.moc" diff --git a/plugins/filters/posterize/posterize.h b/plugins/filters/posterize/posterize.h index 7a655e11cc..e66016bb05 100644 --- a/plugins/filters/posterize/posterize.h +++ b/plugins/filters/posterize/posterize.h @@ -1,61 +1,61 @@ /* * Copyright (c) 2014 Manuel Riecke * * 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 POSTERIZE_H #define POSTERIZE_H #include #include #include "filter/kis_color_transformation_filter.h" #include "kis_config_widget.h" class Posterize : public QObject { Q_OBJECT public: Posterize(QObject *parent, const QVariantList &); virtual ~Posterize(); }; class KisFilterPosterize : public KisColorTransformationFilter { public: KisFilterPosterize(); public: - virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfiguration* config) const; + virtual KoColorTransformation* createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const; virtual KisConfigWidget* createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; static inline KoID id() { return KoID("posterize", i18n("Posterize")); } protected: - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; }; class KisPosterizeColorTransformation : public KoColorTransformation { public: KisPosterizeColorTransformation(int steps, const KoColorSpace* cs); virtual void transform(const quint8* src, quint8* dst, qint32 nPixels) const; private: const KoColorSpace* m_colorSpace; quint32 m_psize; quint16 m_step; quint16 m_halfStep; }; #endif diff --git a/plugins/filters/raindropsfilter/kis_raindrops_filter.cpp b/plugins/filters/raindropsfilter/kis_raindrops_filter.cpp index 31dbda1f00..1c061b2d3f 100644 --- a/plugins/filters/raindropsfilter/kis_raindrops_filter.cpp +++ b/plugins/filters/raindropsfilter/kis_raindrops_filter.cpp @@ -1,402 +1,402 @@ /* * This file is part of the KDE project * * Copyright (c) 2004 Michael Thaler * * ported from digikam, copyrighted 2004 by Gilles Caulier, * Original RainDrops algorithm copyrighted 2004 by * Pieter Z. Voloshyn . * * 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_raindrops_filter.h" #include #include #include #include #include #include #include #include #include #include "KoIntegerMaths.h" #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_integer_filter_widget.h" KisRainDropsFilter::KisRainDropsFilter() : KisFilter(id(), KisFilter::categoryArtistic(), i18n("&Raindrops...")) { setSupportsPainting(false); setSupportsThreading(false); setSupportsAdjustmentLayers(true); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to apply the RainDrops effect (inspired from Jason Waltman code) * * data => The image data in RGBA mode. * Width => Width of image. * Height => Height of image. * DropSize => Raindrop size * number => Maximum number of raindrops * fishEyes => FishEye coefficient * * Theory => This functions does several math's functions and the engine * is simple to undestand, but a little hard to implement. A * control will indicate if there is or not a raindrop in that * area, if not, a fisheye effect with a random size (max=DropSize) * will be applied, after this, a shadow will be applied too. * and after this, a blur function will finish the effect. */ void KisRainDropsFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); //read the filter configuration values from the KisFilterConfiguration object quint32 DropSize = config->getInt("dropSize", 80); quint32 number = config->getInt("number", 80); quint32 fishEyes = config->getInt("fishEyes", 30); qsrand(config->getInt("seed")); if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } int count = 0; if (fishEyes <= 0) fishEyes = 1; if (fishEyes > 100) fishEyes = 100; int Width = applyRect.width(); int Height = applyRect.height(); bool** BoolMatrix = CreateBoolArray(Width, Height); int i, j, k, l, m, n; // loop variables int Bright; // Bright value for shadows and highlights int x, y; // center coordinates int Counter = 0; // Counter (duh !) int NewSize; // Size of current raindrop int halfSize; // Half of the current raindrop int Radius; // Maximum radius for raindrop int BlurRadius; // Blur Radius int BlurPixels; double r, a; // polar coordinates double OldRadius; // Radius before processing double NewfishEyes = (double)fishEyes * 0.01; // FishEye fishEyesicients double s; double R, G, B; bool FindAnother = false; // To search for good coordinates const KoColorSpace * cs = device->colorSpace(); // Init booleen Matrix. for (i = 0 ; (i < Width) && !(progressUpdater && progressUpdater->interrupted()) ; ++i) { for (j = 0 ; (j < Height) && !(progressUpdater && progressUpdater->interrupted()); ++j) { BoolMatrix[i][j] = false; } } KisRandomAccessorSP dstAccessor = device->createRandomAccessorNG(srcTopLeft.x(), srcTopLeft.y()); for (uint NumBlurs = 0; (NumBlurs <= number) && !(progressUpdater && progressUpdater->interrupted()); ++NumBlurs) { NewSize = (int)(qrand() * ((double)(DropSize - 5) / RAND_MAX) + 5); halfSize = NewSize / 2; Radius = halfSize; s = Radius / log(NewfishEyes * Radius + 1); Counter = 0; do { FindAnother = false; y = (int)(qrand() * ((double)(Width - 1) / RAND_MAX)); x = (int)(qrand() * ((double)(Height - 1) / RAND_MAX)); if (BoolMatrix[y][x]) FindAnother = true; else for (i = x - halfSize ; (i <= x + halfSize) && !(progressUpdater && progressUpdater->interrupted()); i++) for (j = y - halfSize ; (j <= y + halfSize) && !(progressUpdater && progressUpdater->interrupted()); j++) if ((i >= 0) && (i < Height) && (j >= 0) && (j < Width)) if (BoolMatrix[j][i]) FindAnother = true; Counter++; } while ((FindAnother && (Counter < 10000) && !(progressUpdater && progressUpdater->interrupted()))); if (Counter >= 10000) { NumBlurs = number; break; } for (i = -1 * halfSize ; (i < NewSize - halfSize) && !(progressUpdater && progressUpdater->interrupted()); i++) { for (j = -1 * halfSize ; (j < NewSize - halfSize) && !(progressUpdater && progressUpdater->interrupted()); j++) { r = sqrt((double)i * i + j * j); a = atan2(static_cast(i), static_cast(j)); if (r <= Radius) { OldRadius = r; r = (exp(r / s) - 1) / NewfishEyes; k = x + (int)(r * sin(a)); l = y + (int)(r * cos(a)); m = x + i; n = y + j; if ((k >= 0) && (k < Height) && (l >= 0) && (l < Width)) { if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) { Bright = 0; if (OldRadius >= 0.9 * Radius) { if ((a <= 0) && (a > -2.25)) Bright = -80; else if ((a <= -2.25) && (a > -2.5)) Bright = -40; else if ((a <= 0.25) && (a > 0)) Bright = -40; } else if (OldRadius >= 0.8 * Radius) { if ((a <= -0.75) && (a > -1.50)) Bright = -40; else if ((a <= 0.10) && (a > -0.75)) Bright = -30; else if ((a <= -1.50) && (a > -2.35)) Bright = -30; } else if (OldRadius >= 0.7 * Radius) { if ((a <= -0.10) && (a > -2.0)) Bright = -20; else if ((a <= 2.50) && (a > 1.90)) Bright = 60; } else if (OldRadius >= 0.6 * Radius) { if ((a <= -0.50) && (a > -1.75)) Bright = -20; else if ((a <= 0) && (a > -0.25)) Bright = 20; else if ((a <= -2.0) && (a > -2.25)) Bright = 20; } else if (OldRadius >= 0.5 * Radius) { if ((a <= -0.25) && (a > -0.50)) Bright = 30; else if ((a <= -1.75) && (a > -2.0)) Bright = 30; } else if (OldRadius >= 0.4 * Radius) { if ((a <= -0.5) && (a > -1.75)) Bright = 40; } else if (OldRadius >= 0.3 * Radius) { if ((a <= 0) && (a > -2.25)) Bright = 30; } else if (OldRadius >= 0.2 * Radius) { if ((a <= -0.5) && (a > -1.75)) Bright = 20; } BoolMatrix[n][m] = true; QColor originalColor; dstAccessor->moveTo(srcTopLeft.x() + l, srcTopLeft.y() + k); cs->toQColor(dstAccessor->oldRawData(), &originalColor); int newRed = CLAMP(originalColor.red() + Bright, 0, quint8_MAX); int newGreen = CLAMP(originalColor.green() + Bright, 0, quint8_MAX); int newBlue = CLAMP(originalColor.blue() + Bright, 0, quint8_MAX); QColor newColor; newColor.setRgb(newRed, newGreen, newBlue); dstAccessor->moveTo(srcTopLeft.x() + n, srcTopLeft.y() + m); cs->fromQColor(newColor, dstAccessor->rawData()); } } } } } BlurRadius = NewSize / 25 + 1; for (i = -1 * halfSize - BlurRadius ; (i < NewSize - halfSize + BlurRadius) && !(progressUpdater && progressUpdater->interrupted()) ; i++) { for (j = -1 * halfSize - BlurRadius; ((j < NewSize - halfSize + BlurRadius) && !(progressUpdater && progressUpdater->interrupted())); ++j) { r = sqrt((double)i * i + j * j); if (r <= Radius * 1.1) { R = G = B = 0; BlurPixels = 0; for (k = -1 * BlurRadius; k < BlurRadius + 1; k++) for (l = -1 * BlurRadius; l < BlurRadius + 1; l++) { m = x + i + k; n = y + j + l; if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) { QColor color; dstAccessor->moveTo(srcTopLeft.x() + n, srcTopLeft.y() + m); cs->toQColor(dstAccessor->rawData(), &color); R += color.red(); G += color.green(); B += color.blue(); BlurPixels++; } } m = x + i; n = y + j; if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) { QColor color; color.setRgb((int)(R / BlurPixels), (int)(G / BlurPixels), (int)(B / BlurPixels)); dstAccessor->moveTo(srcTopLeft.x() + n, srcTopLeft.y() + m); cs->fromQColor(color, dstAccessor->rawData()); } } } } if (progressUpdater) progressUpdater->setValue(++count); } FreeBoolArray(BoolMatrix, Width); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* Function to free a dinamic boolean array * * lpbArray => Dynamic boolean array * Columns => The array bidimension value * * Theory => An easy to undestand 'for' statement */ void KisRainDropsFilter::FreeBoolArray(bool** lpbArray, uint Columns) const { for (uint i = 0; i < Columns; ++i) free(lpbArray[i]); free(lpbArray); } /* Function to create a bidimentional dinamic boolean array * * Columns => Number of columns * Rows => Number of rows * * Theory => Using 'for' statement, we can alloc multiple dinamic arrays * To create more dimentions, just add some 'for's, ok? */ bool** KisRainDropsFilter::CreateBoolArray(uint Columns, uint Rows) const { bool** lpbArray = 0; lpbArray = (bool**) malloc(Columns * sizeof(bool*)); if (lpbArray == 0) return (0); for (uint i = 0; i < Columns; ++i) { lpbArray[i] = (bool*) malloc(Rows * sizeof(bool)); if (lpbArray[i] == 0) { FreeBoolArray(lpbArray, Columns); return (0); } } return (lpbArray); } // This method have been ported from Pieter Z. Voloshyn algorithm code. /* This function limits the RGB values * * ColorValue => Here, is an RGB value to be analized * * Theory => A color is represented in RGB value (e.g. 0xFFFFFF is * white color). But R, G and B values has 256 values to be used * so, this function analize the value and limits to this range */ uchar KisRainDropsFilter::LimitValues(int ColorValue) const { if (ColorValue > 255) // MAX = 255 ColorValue = 255; if (ColorValue < 0) // MIN = 0 ColorValue = 0; return ((uchar) ColorValue); } KisConfigWidget * KisRainDropsFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(1, 200, 80, i18n("Drop size"), "dropsize")); param.push_back(KisIntegerWidgetParam(1, 500, 80, i18n("Number"), "number")); param.push_back(KisIntegerWidgetParam(1, 100, 30, i18n("Fish eyes"), "fishEyes")); KisMultiIntegerFilterWidget * w = new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); w->setConfiguration(factoryConfiguration(0)); return w; } -KisFilterConfiguration* KisRainDropsFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisRainDropsFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("raindrops", 2); + KisFilterConfigurationSP config = new KisFilterConfiguration("raindrops", 2); config->setProperty("dropsize", 80); config->setProperty("number", 80); config->setProperty("fishEyes", 30); config->setProperty("seed", QTime::currentTime().msec()); return config; } diff --git a/plugins/filters/raindropsfilter/kis_raindrops_filter.h b/plugins/filters/raindropsfilter/kis_raindrops_filter.h index 78622ff201..61712794b5 100644 --- a/plugins/filters/raindropsfilter/kis_raindrops_filter.h +++ b/plugins/filters/raindropsfilter/kis_raindrops_filter.h @@ -1,51 +1,51 @@ /* * This file is part of Krita * * Copyright (c) Michael Thaler * * 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_RAINDROPS_FILTER_H_ #define _KIS_RAINDROPS_FILTER_H_ #include "filter/kis_filter.h" #include "kis_config_widget.h" #include "kis_paint_device.h" class KisRainDropsFilter : public KisFilter { public: KisRainDropsFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const; static inline KoID id() { return KoID("raindrops", i18n("Raindrops")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: bool** CreateBoolArray(uint Columns, uint Rows) const; void FreeBoolArray(bool** lpbArray, uint Columns) const; uchar LimitValues(int ColorValue) const; }; #endif diff --git a/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp b/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp index effd17704f..a78bc24463 100644 --- a/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp +++ b/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp @@ -1,76 +1,76 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_random_pick.h" #include #include #include "ui_wdgrandompickoptions.h" KisWdgRandomPick::KisWdgRandomPick(KisFilter* /*nfilter*/, QWidget* parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgRandomPickOptions(); m_widget->setupUi(this); connect(widget()->intLevel, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intWindowSize, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intOpacity, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); m_seedH = rand(); m_seedV = rand(); m_seedThreshold = rand(); } KisWdgRandomPick::~KisWdgRandomPick() { delete m_widget; } -void KisWdgRandomPick::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgRandomPick::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("level", value)) { widget()->intLevel->setValue(value.toUInt()); } if (config->getProperty("windowsize", value)) { widget()->intWindowSize->setValue(value.toUInt()); } if (config->getProperty("opacity", value)) { widget()->intOpacity->setValue(value.toUInt()); } } -KisPropertiesConfiguration* KisWdgRandomPick::configuration() const +KisPropertiesConfigurationSP KisWdgRandomPick::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("randompick", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("randompick", 1); config->setProperty("level", this->widget()->intLevel->value()); config->setProperty("windowsize", this->widget()->intWindowSize->value()); config->setProperty("opacity", this->widget()->intOpacity->value()); config->setProperty("seedH", m_seedH); config->setProperty("seedV", m_seedV); config->setProperty("seedThreshold", m_seedThreshold); return config; } diff --git a/plugins/filters/randompickfilter/kis_wdg_random_pick.h b/plugins/filters/randompickfilter/kis_wdg_random_pick.h index 592881c683..92c1aa653f 100644 --- a/plugins/filters/randompickfilter/kis_wdg_random_pick.h +++ b/plugins/filters/randompickfilter/kis_wdg_random_pick.h @@ -1,47 +1,47 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_RANDOMPICK_H #define KIS_WDG_RANDOMPICK_H #include class Ui_WdgRandomPickOptions; class KisFilter; class KisWdgRandomPick : public KisConfigWidget { Q_OBJECT public: KisWdgRandomPick(KisFilter* nfilter, QWidget* parent = 0); ~KisWdgRandomPick(); public: inline const Ui_WdgRandomPickOptions* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgRandomPickOptions* m_widget; int m_seedH, m_seedV, m_seedThreshold; }; #endif diff --git a/plugins/filters/randompickfilter/randompickfilter.cpp b/plugins/filters/randompickfilter/randompickfilter.cpp index 048c2e2a9e..f871e9ddb1 100644 --- a/plugins/filters/randompickfilter/randompickfilter.cpp +++ b/plugins/filters/randompickfilter/randompickfilter.cpp @@ -1,156 +1,156 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 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. */ #include "randompickfilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_random_pick.h" #include "ui_wdgrandompickoptions.h" #include K_PLUGIN_FACTORY_WITH_JSON(KritaRandomPickFilterFactory, "kritarandompickfilter.json", registerPlugin();) KritaRandomPickFilter::KritaRandomPickFilter(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(new KisFilterRandomPick()); } KritaRandomPickFilter::~KritaRandomPickFilter() { } KisFilterRandomPick::KisFilterRandomPick() : KisFilter(id(), categoryOther(), i18n("&Random Pick...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } void KisFilterRandomPick::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_UNUSED(config); Q_ASSERT(!device.isNull()); if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } int count = 0; const KoColorSpace * cs = device->colorSpace(); QVariant value; int level = (config && config->getProperty("level", value)) ? value.toInt() : 50; int opacity = (config && config->getProperty("opacity", value)) ? value.toInt() : 100; double windowsize = (config && config->getProperty("windowsize", value)) ? value.toDouble() : 2.5; int seedThreshold = rand(); int seedH = rand(); int seedV = rand(); if (config) { seedThreshold = config->getInt("seedThreshold", seedThreshold); seedH = config->getInt("seedH", seedH); seedV = config->getInt("seedV", seedV); } KisRandomGenerator randT(seedThreshold); KisRandomGenerator randH(seedH); KisRandomGenerator randV(seedV); KisSequentialIterator dstIt(device, applyRect); KisRandomConstAccessorSP srcRA = device->createRandomConstAccessorNG(0, 0); double threshold = (100 - level) / 100.0; qint16 weights[2]; weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; const quint8* pixels[2]; KoMixColorsOp * mixOp = cs->mixColorsOp(); do{ if (randT.doubleRandomAt(dstIt.x(), dstIt.y()) > threshold) { int x = static_cast(dstIt.x() + windowsize * (randH.doubleRandomAt(dstIt.x(), dstIt.y()) - 0.5)); int y = static_cast(dstIt.y() + windowsize * (randV.doubleRandomAt(dstIt.x(), dstIt.y()) -0.5)); srcRA->moveTo(x, y); pixels[0] = srcRA->oldRawData(); pixels[1] = dstIt.oldRawData(); mixOp->mixColors(pixels, weights, 2, dstIt.rawData()); } if (progressUpdater) progressUpdater->setValue(++count); } while(dstIt.nextPixel()); } KisConfigWidget * KisFilterRandomPick::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgRandomPick((KisFilter*)this, (QWidget*)parent); } -KisFilterConfiguration* KisFilterRandomPick::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterRandomPick::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("randompick", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("randompick", 1); config->setProperty("level", 50); config->setProperty("windowsize", 2.5); config->setProperty("opacity", 100); config->setProperty("seedThreshold", rand()); config->setProperty("seedH", rand()); config->setProperty("seedV", rand()); return config; } -QRect KisFilterRandomPick::neededRect(const QRect& rect, const KisFilterConfiguration* config, int lod) const +QRect KisFilterRandomPick::neededRect(const QRect& rect, const KisFilterConfigurationSP config, int lod) const { Q_UNUSED(lod); QVariant value; int windowsize = ceil((config && config->getProperty("windowsize", value)) ? value.toDouble() : 2.5); return rect.adjusted(-windowsize, -windowsize, windowsize, windowsize); } #include "randompickfilter.moc" diff --git a/plugins/filters/randompickfilter/randompickfilter.h b/plugins/filters/randompickfilter/randompickfilter.h index 71ddc20dc8..0937c67a0e 100644 --- a/plugins/filters/randompickfilter/randompickfilter.h +++ b/plugins/filters/randompickfilter/randompickfilter.h @@ -1,59 +1,59 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 RANDOMPICKFILTER_H #define RANDOMPICKFILTER_H #include #include #include "filter/kis_filter.h" class KisConfigWidget; class KritaRandomPickFilter : public QObject { Q_OBJECT public: KritaRandomPickFilter(QObject *parent, const QVariantList &); virtual ~KritaRandomPickFilter(); }; class KisFilterRandomPick : public KisFilter { public: KisFilterRandomPick(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("randompick", i18n("Random Pick")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual QRect neededRect(const QRect& rect, const KisFilterConfiguration* config, int lod = 0) const; + virtual QRect neededRect(const QRect& rect, const KisFilterConfigurationSP config, int lod = 0) const; }; #endif diff --git a/plugins/filters/roundcorners/kis_round_corners_filter.cpp b/plugins/filters/roundcorners/kis_round_corners_filter.cpp index 2c3f36e82b..3f12d65cc4 100644 --- a/plugins/filters/roundcorners/kis_round_corners_filter.cpp +++ b/plugins/filters/roundcorners/kis_round_corners_filter.cpp @@ -1,138 +1,138 @@ /* * This file is part of Krita * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * 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_round_corners_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KisRoundCornersFilter::KisRoundCornersFilter() : KisFilter(id(), KisFilter::categoryMap(), i18n("&Round Corners...")) { setSupportsPainting(false); } void KisRoundCornersFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_UNUSED(config); Q_ASSERT(!device.isNull()); if (!device || !config) { warnKrita << "Invalid parameters for round corner filter"; dbgPlugins << device << " " << config; return; } //read the filter configuration values from the KisFilterConfiguration object qint32 radius = qMax(1, config->getInt("radius" , 30)); if (progressUpdater) { progressUpdater->setRange(0, applyRect.height()); } qint32 width = applyRect.width(); KisHLineIteratorSP dstIt = device->createHLineIteratorNG(applyRect.x(), applyRect.y(), width); const KoColorSpace* cs = device->colorSpace(); QRect bounds = device->defaultBounds()->bounds(); for (qint32 y = applyRect.y(); y < applyRect.y() + applyRect.height(); y++) { qint32 x = applyRect.x(); do { if (x <= radius && y <= radius) { double dx = radius - x; double dy = radius - y; double dradius = static_cast(radius); if (dx >= sqrt(dradius*dradius - dy*dy)) { cs->setOpacity(dstIt->rawData(), OPACITY_TRANSPARENT_U8, 1); } } else if (x >= bounds.width() - radius && y <= radius) { double dx = x + radius - bounds.width(); double dy = radius - y; double dradius = static_cast(radius); if (dx >= sqrt(dradius*dradius - dy*dy)) { cs->setOpacity(dstIt->rawData(), OPACITY_TRANSPARENT_U8, 1); } } else if (x <= radius && y >= bounds.height() - radius) { double dx = radius - x; double dy = y + radius - bounds.height(); double dradius = static_cast(radius); if (dx >= sqrt(dradius*dradius - dy*dy)) { cs->setOpacity(dstIt->rawData(), OPACITY_TRANSPARENT_U8, 1); } } else if (x >= bounds.width() - radius && y >= bounds.height() - radius) { double dx = x + radius - bounds.width() ; double dy = y + radius - bounds.height(); double dradius = static_cast(radius); if (dx >= sqrt(dradius*dradius - dy*dy)) { cs->setOpacity(dstIt->rawData(), OPACITY_TRANSPARENT_U8, 1); } } ++x; } while(dstIt->nextPixel()); dstIt->nextRow(); if (progressUpdater) progressUpdater->setValue(y); } } KisConfigWidget * KisRoundCornersFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(2, 100, 30, i18n("Radius"), "radius")); return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration* KisRoundCornersFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisRoundCornersFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("roundcorners", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("roundcorners", 1); config->setProperty("radius", 30); return config; } diff --git a/plugins/filters/roundcorners/kis_round_corners_filter.h b/plugins/filters/roundcorners/kis_round_corners_filter.h index d12cdd11a4..6afb1688de 100644 --- a/plugins/filters/roundcorners/kis_round_corners_filter.h +++ b/plugins/filters/roundcorners/kis_round_corners_filter.h @@ -1,47 +1,47 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_ROUND_CORNERS_FILTER_H_ #define _KIS_ROUND_CORNERS_FILTER_H_ #include "kis_paint_device.h" #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisRoundCornersFilter : public KisFilter { public: KisRoundCornersFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("roundcorners", i18n("Round Corners")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: }; #endif diff --git a/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cpp b/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cpp index dc9acd8119..5cd51d0df9 100644 --- a/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cpp +++ b/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cpp @@ -1,112 +1,112 @@ /* * This file is part of Krita * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * 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_small_tiles_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_integer_filter_widget.h" KisSmallTilesFilter::KisSmallTilesFilter() : KisFilter(id(), KisFilter::categoryMap(), i18n("&Small Tiles...")) { setSupportsPainting(true); setSupportsThreading(false); setSupportsAdjustmentLayers(false); } void KisSmallTilesFilter::processImpl(KisPaintDeviceSP device, const QRect& /*applyRect*/, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_ASSERT(!device.isNull()); //read the filter configuration values from the KisFilterConfiguration object quint32 numberOfTiles = config->getInt("numberOfTiles", 2); QRect srcRect = device->exactBounds(); int w = static_cast(srcRect.width() / numberOfTiles); int h = static_cast(srcRect.height() / numberOfTiles); KisPaintDeviceSP tile = device->createThumbnailDevice(srcRect.width() / numberOfTiles, srcRect.height() / numberOfTiles); if (tile.isNull()) return; KisPainter gc(device); gc.setCompositeOp(COMPOSITE_COPY); if (progressUpdater) { progressUpdater->setRange(0, numberOfTiles); } for (uint y = 0; y < numberOfTiles; ++y) { for (uint x = 0; x < numberOfTiles; ++x) { gc.bitBlt(w * x, h * y, tile, 0, 0, w, h); } if (progressUpdater) progressUpdater->setValue(y); } gc.end(); } KisConfigWidget * KisSmallTilesFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisIntegerWidgetParam param; param.push_back(KisIntegerWidgetParam(2, 5, 1, i18n("Number of tiles"), "numberOfTiles")); return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param); } -KisFilterConfiguration* KisSmallTilesFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisSmallTilesFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("smalltiles", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("smalltiles", 1); config->setProperty("numberOfTiles", 2); return config; } diff --git a/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h b/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h index 2a1d73ab27..c14495306e 100644 --- a/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h +++ b/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h @@ -1,51 +1,51 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_SMALL_TILES_FILTER_H_ #define _KIS_SMALL_TILES_FILTER_H_ #include "kis_paint_device.h" #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisSmallTilesFilter : public KisFilter { public: KisSmallTilesFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("smalltiles", i18n("Small Tiles")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/filters/sobelfilter/kis_sobel_filter.cpp b/plugins/filters/sobelfilter/kis_sobel_filter.cpp index 34fc7191d8..73eeca20f0 100644 --- a/plugins/filters/sobelfilter/kis_sobel_filter.cpp +++ b/plugins/filters/sobelfilter/kis_sobel_filter.cpp @@ -1,204 +1,204 @@ /* * This file is part of Krita * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * 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_sobel_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_multi_bool_filter_widget.h" #define MIN(a,b) (((a)<(b))?(a):(b)) // void KisSobelFilterConfiguration::fromXML(const QString & s) // { // KisFilterConfiguration::fromXML(s); // m_doHorizontally = getBool( "doHorizontally" ); // m_doVertically = getBool( "doVertically" ); // m_keepSign = getBool( "makeOpaque" ); // } // // QString KisSobelFilterConfiguration::toString() // { // m_properties.clear(); // setProperty("doHorizontally", m_doHorizontally); // setProperty("doVertically", m_doVertically); // setProperty("keepSign", m_keepSign); // setProperty("makeOpaque", m_makeOpaque); // // return KisFilterConfiguration::toString(); // } #include KisSobelFilter::KisSobelFilter() : KisFilter(id(), categoryEdgeDetection(), i18n("&Sobel...")) { setSupportsPainting(false); setSupportsThreading(false); // TODO Sobel doesn't support threading on image with height > 512 setSupportsAdjustmentLayers(false); } void KisSobelFilter::prepareRow(KisPaintDeviceSP src, quint8* data, quint32 x, quint32 y, quint32 w, quint32 h) const { if (y > h - 1) y = h - 1; quint32 pixelSize = src->pixelSize(); src->readBytes(data, x, y, w, 1); for (quint32 b = 0; b < pixelSize; b++) { int offset = pixelSize - b; data[-offset] = data[b]; data[w * pixelSize + b] = data[(w - 1) * pixelSize + b]; } } #define RMS(a, b) (sqrt ((qreal)(a) * (a) + (b) * (b))) #define ROUND(x) ((int) ((x) + 0.5)) void KisSobelFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* configuration, + const KisFilterConfigurationSP configuration, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(!device.isNull()); //read the filter configuration values from the KisFilterConfiguration object bool doHorizontal = configuration->getBool("doHorizontally", true); bool doVertical = configuration->getBool("doVertically", true); bool keepSign = configuration->getBool("keepSign", true); bool makeOpaque = configuration->getBool("makeOpaque", true); quint32 width = applyRect.width(); quint32 height = applyRect.height(); quint32 pixelSize = device->pixelSize(); int cost = applyRect.height(); /* allocate row buffers */ quint8* prevRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(prevRow); quint8* curRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(curRow); quint8* nextRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(nextRow); quint8* dest = new quint8[width * pixelSize]; Q_CHECK_PTR(dest); quint8* pr = prevRow + pixelSize; quint8* cr = curRow + pixelSize; quint8* nr = nextRow + pixelSize; prepareRow(device, pr, srcTopLeft.x(), srcTopLeft.y() - 1, width, height); prepareRow(device, cr, srcTopLeft.x(), srcTopLeft.y(), width, height); quint32 counter = 0; quint8* d; quint8* tmp; qint32 gradient, horGradient, verGradient; // loop through the rows, applying the sobel convolution KisHLineIteratorSP dstIt = device->createHLineIteratorNG(srcTopLeft.x(), srcTopLeft.y(), width); for (quint32 row = 0; row < height; row++) { // prepare the next row prepareRow(device, nr, srcTopLeft.x(), srcTopLeft.y() + row + 1, width, height); d = dest; for (quint32 col = 0; col < width * pixelSize; col++) { int positive = col + pixelSize; int negative = col - pixelSize; horGradient = (doHorizontal ? ((pr[negative] + 2 * pr[col] + pr[positive]) - (nr[negative] + 2 * nr[col] + nr[positive])) : 0); verGradient = (doVertical ? ((pr[negative] + 2 * cr[negative] + nr[negative]) - (pr[positive] + 2 * cr[positive] + nr[positive])) : 0); gradient = (qint32)((doVertical && doHorizontal) ? (ROUND(RMS(horGradient, verGradient)) / 5.66) // always >0 : (keepSign ? (127 + (ROUND((horGradient + verGradient) / 8.0))) : (ROUND(qAbs(horGradient + verGradient) / 4.0)))); *d++ = gradient; if (gradient > 10) counter ++; } // shuffle the row pointers tmp = pr; pr = cr; cr = nr; nr = tmp; //store the dest device->writeBytes(dest, srcTopLeft.x(), row, width, 1); if (makeOpaque) { do { device->colorSpace()->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } while(dstIt->nextPixel()); dstIt->nextRow(); } if (progressUpdater) progressUpdater->setProgress(row / cost); } delete[] prevRow; delete[] curRow; delete[] nextRow; delete[] dest; } KisConfigWidget * KisSobelFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisBoolWidgetParam param; param.push_back(KisBoolWidgetParam(true, i18n("Sobel horizontally"), "doHorizontally")); param.push_back(KisBoolWidgetParam(true, i18n("Sobel vertically"), "doVertically")); param.push_back(KisBoolWidgetParam(true, i18n("Keep sign of result"), "keepSign")); param.push_back(KisBoolWidgetParam(true, i18n("Make image opaque"), "makeOpaque")); return new KisMultiBoolFilterWidget(id().id(), parent, id().id(), param); } diff --git a/plugins/filters/sobelfilter/kis_sobel_filter.h b/plugins/filters/sobelfilter/kis_sobel_filter.h index 47bb524b54..b1da9b0bcf 100644 --- a/plugins/filters/sobelfilter/kis_sobel_filter.h +++ b/plugins/filters/sobelfilter/kis_sobel_filter.h @@ -1,48 +1,48 @@ /* * This file is part of the KDE project * * Copyright (c) Michael Thaler * * 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_SOBEL_FILTER_H_ #define _KIS_SOBEL_FILTER_H_ #include "filter/kis_filter.h" #include "kis_config_widget.h" class KisSobelFilter : public KisFilter { public: KisSobelFilter(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("sobel", i18n("Sobel")); } public: virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; private: void prepareRow(const KisPaintDeviceSP src, quint8* data, quint32 x, quint32 y, quint32 w, quint32 h) const; }; #endif diff --git a/plugins/filters/tests/kis_all_filter_test.cpp b/plugins/filters/tests/kis_all_filter_test.cpp index 99e9e0d946..acb4a12262 100644 --- a/plugins/filters/tests/kis_all_filter_test.cpp +++ b/plugins/filters/tests/kis_all_filter_test.cpp @@ -1,316 +1,316 @@ /* * 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 "kis_all_filter_test.h" #include #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_processing_information.h" #include "filter/kis_filter.h" #include "kis_pixel_selection.h" #include "kis_transaction.h" #include bool compareQImages(QPoint & pt, const QImage & image1, const QImage & image2) { // QTime t; // t.start(); int w1 = image1.width(); int h1 = image1.height(); int w2 = image2.width(); int h2 = image2.height(); if (w1 != w2 || h1 != h2) { dbgKrita << w1 << " " << w2 << " " << h1 << " " << h2; pt.setX(-1); pt.setY(-1); return false; } for (int x = 0; x < w1; ++x) { for (int y = 0; y < h1; ++y) { if (image1.pixel(x, y) != image2.pixel(x, y)) { pt.setX(x); pt.setY(y); return false; } } } // dbgKrita << "compareQImages time elapsed:" << t.elapsed(); return true; } bool testFilterSrcNotIsDev(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "carrot_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); KisPaintDeviceSP dstdev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file - KisFilterConfiguration * kfc = f->defaultConfiguration(dev); + KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, dstdev, 0, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dstdev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("src_not_is_dst_carrot_%1.png").arg(f->id())); return false; } return true; } bool testFilterNoTransaction(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "carrot_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file - KisFilterConfiguration * kfc = f->defaultConfiguration(dev); + KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("no_transactio_carrot_%1.png").arg(f->id())); return false; } return true; } bool testFilter(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); QString resultFileName = QString(FILES_DATA_DIR) + QDir::separator() + "carrot_" + f->id() + ".png"; QImage result(resultFileName); if (!QFileInfo(resultFileName).exists()) { dbgKrita << resultFileName << " not found"; return false; } KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); KisTransaction * cmd = new KisTransaction(kundo2_noi18n(f->name()), dev); // Get the predefined configuration from a file - KisFilterConfiguration * kfc = f->defaultConfiguration(dev); + KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; delete cmd; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dbgKrita << errpoint; dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("carrot_%1.png").arg(f->id())); return false; } return true; } bool testFilterWithSelections(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "carrot_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file - KisFilterConfiguration * kfc = f->defaultConfiguration(dev); + KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n"; << kfc->toXML() << "\n"; KisSelectionSP sel1 = new KisSelection(new KisSelectionDefaultBounds(dev)); sel1->pixelSelection()->select(qimage.rect()); f->process(dev, dev, sel1, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("sel_carrot_%1.png").arg(f->id())); return false; } return true; } void KisAllFilterTest::testAllFilters() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilter(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersNoTransaction() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterNoTransaction(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success (no transaction): " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters (no transaction):\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersSrcNotIsDev() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterSrcNotIsDev(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Src!=Dev Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Src!=Dev Failed filters:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersWithSelections() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterWithSelections(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters with selections:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } QTEST_MAIN(KisAllFilterTest) diff --git a/plugins/filters/tests/kis_crash_filter_test.cpp b/plugins/filters/tests/kis_crash_filter_test.cpp index f885e1d3c5..dd770f2106 100644 --- a/plugins/filters/tests/kis_crash_filter_test.cpp +++ b/plugins/filters/tests/kis_crash_filter_test.cpp @@ -1,99 +1,99 @@ /* * 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 "kis_crash_filter_test.h" #include #include #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_processing_information.h" #include "filter/kis_filter.h" #include "kis_pixel_selection.h" #include bool KisCrashFilterTest::applyFilter(const KoColorSpace * cs, KisFilterSP f) { QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); // dev->fill(0, 0, 100, 100, dev->defaultPixel()); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file - KisFilterConfiguration * kfc = f->defaultConfiguration(dev); + KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } dbgKrita << f->id() << ", " << cs->id() << ", " << cs->profile()->name();// << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); return true; } bool KisCrashFilterTest::testFilter(KisFilterSP f) { QList colorSpaces = KoColorSpaceRegistry::instance()->allColorSpaces(KoColorSpaceRegistry::AllColorSpaces, KoColorSpaceRegistry::AllProfiles); bool ok = false; Q_FOREACH (const KoColorSpace* colorSpace, colorSpaces) { // XXX: Let's not check the painterly colorspaces right now if (colorSpace->id().startsWith("KS", Qt::CaseInsensitive)) { continue; } ok = applyFilter(colorSpace, f); } return ok; } void KisCrashFilterTest::testCrashFilters() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilter(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } QTEST_MAIN(KisCrashFilterTest) diff --git a/plugins/filters/threshold/threshold.cpp b/plugins/filters/threshold/threshold.cpp index 6f588f8e38..fbd51dd2d0 100644 --- a/plugins/filters/threshold/threshold.cpp +++ b/plugins/filters/threshold/threshold.cpp @@ -1,220 +1,220 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "threshold.h" #include #include #include #include #include #include #include #include #include #include "kis_gradient_slider.h" #include "kis_histogram.h" #include #include "kis_paint_device.h" #include "kis_painter.h" #include #include #include #include #include #include "KoColorModelStandardIds.h" #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KritaThresholdFactory, "kritathreshold.json", registerPlugin();) KritaThreshold::KritaThreshold(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(new KisFilterThreshold()); } KritaThreshold::~KritaThreshold() { } KisFilterThreshold::KisFilterThreshold() : KisFilter(id(), categoryAdjust(), i18n("&Threshold...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(false); setShowConfigurationWidget(true); setSupportsLevelOfDetail(true); setSupportsAdjustmentLayers(true); setSupportsThreading(true); } void KisFilterThreshold::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration *config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const { Q_ASSERT(!device.isNull()); if (progressUpdater) { progressUpdater->setRange(0, applyRect.height() * applyRect.width()); } int threshold = config->getInt("threshold"); KoColor white(Qt::white, device->colorSpace()); KoColor black(Qt::black, device->colorSpace()); KisSequentialIterator it(device, applyRect); int p = 0; const int pixelSize = device->colorSpace()->pixelSize(); do { if (device->colorSpace()->intensity8(it.oldRawData()) > threshold) { memcpy(it.rawData(), white.data(), pixelSize); } else { memcpy(it.rawData(), black.data(), pixelSize); } if (progressUpdater) progressUpdater->setValue(p++); } while (it.nextPixel()); } -KisFilterConfiguration *KisFilterThreshold::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterThreshold::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration *config = new KisFilterConfiguration("threshold", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("threshold", 1); config->setProperty("threshold", 128); return config; } KisConfigWidget *KisFilterThreshold::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisThresholdConfigWidget(parent, dev); } KisThresholdConfigWidget::KisThresholdConfigWidget(QWidget * parent, KisPaintDeviceSP dev) : KisConfigWidget(parent) { Q_ASSERT(dev); m_page.setupUi(this); m_page.thresholdGradient->enableGamma(false); m_page.thresholdGradient->enableWhite(false); m_page.intThreshold->setValue(128); connect(m_page.intThreshold, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.thresholdGradient, SIGNAL(sigModifiedGamma(double)), SIGNAL(sigConfigurationItemChanged())); connect(m_page.intThreshold, SIGNAL(valueChanged(int)), m_page.thresholdGradient, SLOT(slotModifyBlack(int))); connect(m_page.thresholdGradient, SIGNAL(sigModifiedBlack(int)), m_page.intThreshold, SLOT(setValue(int))); connect((QObject*)(m_page.chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(slotDrawHistogram(bool))); KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); m_histogram.reset( new KisHistogram(dev, dev->exactBounds(), producer, LINEAR) ); m_histlog = false; m_page.histview->resize(288,100); slotDrawHistogram(); } KisThresholdConfigWidget::~KisThresholdConfigWidget() { } void KisThresholdConfigWidget::slotDrawHistogram(bool logarithmic) { int wHeight = m_page.histview->height(); int wHeightMinusOne = wHeight - 1; int wWidth = m_page.histview->width(); if (m_histlog != logarithmic) { // Update the m_histogram if (logarithmic) m_histogram->setHistogramType(LOGARITHMIC); else m_histogram->setHistogramType(LINEAR); m_histlog = logarithmic; } QPalette appPalette = QApplication::palette(); QPixmap pix(wWidth-100, wHeight); pix.fill(QColor(appPalette.color(QPalette::Base))); QPainter p(&pix); p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); double highest = (double)m_histogram->calculations().getHighest(); qint32 bins = m_histogram->producer()->numberOfBins(); // use nearest neighbour interpolation if (m_histogram->getHistogramType() == LINEAR) { double factor = (double)(wHeight - wHeight / 5.0) / highest; for (int i = 0; i < wWidth; i++) { int binNo = qRound((double)i / wWidth * (bins - 1)); if ((int)m_histogram->getValue(binNo) != 0) p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - (int)m_histogram->getValue(binNo) * factor); } } else { double factor = (double)(wHeight - wHeight / 5.0) / (double)log(highest); for (int i = 0; i < wWidth; i++) { int binNo = qRound((double)i / wWidth * (bins - 1)) ; if ((int)m_histogram->getValue(binNo) != 0) p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - log((double)m_histogram->getValue(binNo)) * factor); } } m_page.histview->setPixmap(pix); } void KisThresholdConfigWidget::slotSetThreshold(int limit) { m_page.intThreshold->setMaximum(limit - 1); } -KisPropertiesConfiguration *KisThresholdConfigWidget::configuration() const +KisPropertiesConfigurationSP KisThresholdConfigWidget::configuration() const { - KisFilterConfiguration *config = new KisFilterConfiguration("threshold", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("threshold", 1); config->setProperty("threshold", m_page.intThreshold->value()); return config; } -void KisThresholdConfigWidget::setConfiguration(const KisPropertiesConfiguration * config) +void KisThresholdConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("threshold", value)) { m_page.intThreshold->setValue(value.toUInt()); m_page.thresholdGradient->slotModifyBlack(value.toUInt()); } } #include "threshold.moc" diff --git a/plugins/filters/threshold/threshold.h b/plugins/filters/threshold/threshold.h index f050019bd8..29b04d1381 100644 --- a/plugins/filters/threshold/threshold.h +++ b/plugins/filters/threshold/threshold.h @@ -1,91 +1,91 @@ /* * This file is part of Krita * * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef THRESHOLD_H #define THRESHOLD_H #include #include #include #include #include #include "ui_wdg_threshold.h" class WdgThreshold; class QWidget; class KisHistogram; class KritaThreshold : public QObject { Q_OBJECT public: KritaThreshold(QObject *parent, const QVariantList &); virtual ~KritaThreshold(); }; class KisFilterThreshold : public KisFilter { public: KisFilterThreshold(); public: static inline KoID id() { return KoID("threshold", i18n("Threshold")); } virtual void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const; - virtual KisFilterConfiguration *factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget *createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const; }; class KisThresholdConfigWidget : public KisConfigWidget { Q_OBJECT public: KisThresholdConfigWidget(QWidget *parent, KisPaintDeviceSP dev); virtual ~KisThresholdConfigWidget(); - virtual KisPropertiesConfiguration *configuration() const; - void setConfiguration(const KisPropertiesConfiguration *config); + virtual KisPropertiesConfigurationSP configuration() const; + void setConfiguration(const KisPropertiesConfigurationSP config); Ui::WdgThreshold m_page; private Q_SLOTS: void slotDrawHistogram(bool logarithmic = false); void slotSetThreshold(int); protected: QScopedPointer m_histogram; bool m_histlog; }; #endif diff --git a/plugins/filters/unsharp/kis_unsharp_filter.cpp b/plugins/filters/unsharp/kis_unsharp_filter.cpp index fe9d4b4486..9674691489 100644 --- a/plugins/filters/unsharp/kis_unsharp_filter.cpp +++ b/plugins/filters/unsharp/kis_unsharp_filter.cpp @@ -1,229 +1,229 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include //MSVC requires that Vc come first #include "kis_unsharp_filter.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_lod_transform.h" #include "kis_wdg_unsharp.h" #include "ui_wdgunsharp.h" #include #include "KoColorSpaceTraits.h" KisUnsharpFilter::KisUnsharpFilter() : KisFilter(id(), categoryEnhance(), i18n("&Unsharp Mask...")) { setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsThreading(true); /** * Officially Unsharp Mask doesn't support LoD, because it * generates subtle artifacts when the unsharp radius is smaller * than current zoom level. But LoD devices can still appear when * the filter is used in Adjustment Layer. So the actual LoD is * still counted on. */ setSupportsLevelOfDetail(false); setColorSpaceIndependence(FULLY_INDEPENDENT); } KisConfigWidget * KisUnsharpFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgUnsharp(parent); } -KisFilterConfiguration* KisUnsharpFilter::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisUnsharpFilter::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = new KisFilterConfiguration(id().id(), 1); config->setProperty("halfSize", 1); config->setProperty("amount", 50); config->setProperty("threshold", 0); config->setProperty("lightnessOnly", true); return config; } void KisUnsharpFilter::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP _config, KoUpdater* progressUpdater ) const { QPointer filterUpdater = 0; QPointer convolutionUpdater = 0; KoProgressUpdater* updater = 0; if (progressUpdater) { updater = new KoProgressUpdater(progressUpdater); updater->start(100, i18n("Unsharp Mask")); // Two sub-sub tasks that each go from 0 to 100. convolutionUpdater = updater->startSubtask(); filterUpdater = updater->startSubtask(); } - if (!config) config = new KisFilterConfiguration(id().id(), 1); + KisFilterConfigurationSP config = _config ? _config : new KisFilterConfiguration(id().id(), 1); QVariant value; KisLodTransformScalar t(device); const qreal halfSize = t.scale(config->getProperty("halfSize", value) ? value.toDouble() : 1.0); const qreal amount = (config->getProperty("amount", value)) ? value.toDouble() : 25; const uint threshold = (config->getProperty("threshold", value)) ? value.toUInt() : 0; const uint lightnessOnly = (config->getProperty("lightnessOnly", value)) ? value.toBool() : true; QBitArray channelFlags = config->channelFlags(); KisGaussianKernel::applyGaussian(device, applyRect, halfSize, halfSize, channelFlags, progressUpdater); if (progressUpdater && progressUpdater->interrupted()) { return; } qreal weights[2]; qreal factor = 128; weights[0] = factor * (1. + amount); weights[1] = -factor * amount; if (lightnessOnly) { processLightnessOnly(device, applyRect, threshold, weights, factor, channelFlags); } else { processRaw(device, applyRect, threshold, weights, factor, channelFlags); } delete updater; if (progressUpdater) progressUpdater->setProgress(100); } void KisUnsharpFilter::processRaw(KisPaintDeviceSP device, const QRect &rect, quint8 threshold, qreal weights[2], qreal factor, const QBitArray &channelFlags) const { const KoColorSpace *cs = device->colorSpace(); const int pixelSize = cs->pixelSize(); KoConvolutionOp * convolutionOp = cs->convolutionOp(); KisHLineIteratorSP dstIt = device->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); quint8 *colors[2]; colors[0] = new quint8[pixelSize]; colors[1] = new quint8[pixelSize]; for (int j = 0; j < rect.height(); j++) { do { quint8 diff = cs->difference(dstIt->oldRawData(), dstIt->rawDataConst()); if (diff > threshold) { memcpy(colors[0], dstIt->oldRawData(), pixelSize); memcpy(colors[1], dstIt->rawDataConst(), pixelSize); convolutionOp->convolveColors(colors, weights, dstIt->rawData(), factor, 0, 2, channelFlags); } else { memcpy(dstIt->rawData(), dstIt->oldRawData(), pixelSize); } } while (dstIt->nextPixel()); dstIt->nextRow(); } delete[] colors[0]; delete[] colors[1]; } void KisUnsharpFilter::processLightnessOnly(KisPaintDeviceSP device, const QRect &rect, quint8 threshold, qreal weights[2], qreal factor, const QBitArray & /*channelFlags*/) const { const KoColorSpace *cs = device->colorSpace(); const int pixelSize = cs->pixelSize(); KisHLineIteratorSP dstIt = device->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); quint16 labColorSrc[4]; quint16 labColorDst[4]; const int posL = 0; const int posAplha = 3; const qreal factorInv = 1.0 / factor; for (int j = 0; j < rect.height(); j++) { do { quint8 diff = cs->differenceA(dstIt->oldRawData(), dstIt->rawDataConst()); if (diff > threshold) { cs->toLabA16(dstIt->oldRawData(), (quint8*)labColorSrc, 1); cs->toLabA16(dstIt->rawDataConst(), (quint8*)labColorDst, 1); qint32 valueL = (labColorSrc[posL] * weights[0] + labColorDst[posL] * weights[1]) * factorInv; labColorSrc[posL] = CLAMP(valueL, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); qint32 valueAlpha = (labColorSrc[posAplha] * weights[0] + labColorDst[posAplha] * weights[1]) * factorInv; labColorSrc[posAplha] = CLAMP(valueAlpha, KoColorSpaceMathsTraits::min, KoColorSpaceMathsTraits::max); cs->fromLabA16((quint8*)labColorSrc, dstIt->rawData(), 1); } else { memcpy(dstIt->rawData(), dstIt->oldRawData(), pixelSize); } } while (dstIt->nextPixel()); dstIt->nextRow(); } } -QRect KisUnsharpFilter::neededRect(const QRect & rect, const KisFilterConfiguration* config, int lod) const +QRect KisUnsharpFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const qreal halfSize = t.scale(config->getProperty("halfSize", value) ? value.toDouble() : 1.0); return rect.adjusted(-halfSize * 2, -halfSize * 2, halfSize * 2, halfSize * 2); } -QRect KisUnsharpFilter::changedRect(const QRect & rect, const KisFilterConfiguration* config, int lod) const +QRect KisUnsharpFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP config, int lod) const { KisLodTransformScalar t(lod); QVariant value; const qreal halfSize = t.scale(config->getProperty("halfSize", value) ? value.toDouble() : 1.0); return rect.adjusted( -halfSize, -halfSize, halfSize, halfSize); } diff --git a/plugins/filters/unsharp/kis_unsharp_filter.h b/plugins/filters/unsharp/kis_unsharp_filter.h index 1f5a158b1a..34bfb5d6d5 100644 --- a/plugins/filters/unsharp/kis_unsharp_filter.h +++ b/plugins/filters/unsharp/kis_unsharp_filter.h @@ -1,64 +1,64 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_UNSHARP_FILTER_H #define KIS_UNSHARP_FILTER_H #include "filter/kis_filter.h" class KisUnsharpFilter : public KisFilter { public: KisUnsharpFilter(); void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("unsharp", i18n("Unsharp Mask")); } virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; - QRect changedRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; - QRect neededRect(const QRect & rect, const KisFilterConfiguration* _config, int lod) const; + QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; + QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const; private: void processLightnessOnly(KisPaintDeviceSP device, const QRect &rect, quint8 threshold, qreal weights[2], qreal factor, const QBitArray &channelFlags) const; void processRaw(KisPaintDeviceSP device, const QRect &rect, quint8 threshold, qreal weights[2], qreal factor, const QBitArray &channelFlags) const; }; #endif diff --git a/plugins/filters/unsharp/kis_wdg_unsharp.cpp b/plugins/filters/unsharp/kis_wdg_unsharp.cpp index 73ece65b8e..e9ff2b7645 100644 --- a/plugins/filters/unsharp/kis_wdg_unsharp.cpp +++ b/plugins/filters/unsharp/kis_wdg_unsharp.cpp @@ -1,66 +1,66 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_unsharp.h" #include #include #include #include #include #include "ui_wdgunsharp.h" KisWdgUnsharp::KisWdgUnsharp(QWidget * parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgUnsharp(); m_widget->setupUi(this); connect(widget()->doubleHalfSize, SIGNAL(valueChanged(double)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->doubleAmount, SIGNAL(valueChanged(double)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intThreshold, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->chkLightnessOnly, SIGNAL(stateChanged(int)), SIGNAL(sigConfigurationItemChanged())); } KisWdgUnsharp::~KisWdgUnsharp() { delete m_widget; } -void KisWdgUnsharp::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgUnsharp::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; widget()->doubleHalfSize->setValue((config->getProperty("halfSize", value)) ? value.toDouble() : 1.0); widget()->doubleAmount->setValue((config->getProperty("amount", value)) ? value.toDouble() : 0.0); widget()->intThreshold->setValue((config->getProperty("threshold", value)) ? value.toUInt() : 25); widget()->chkLightnessOnly->setChecked((config->getProperty("lightnessOnly", value)) ? value.toBool() : true); } -KisPropertiesConfiguration* KisWdgUnsharp::configuration() const +KisPropertiesConfigurationSP KisWdgUnsharp::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("unsharp", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("unsharp", 1); config->setProperty("halfSize", widget()->doubleHalfSize->value()); config->setProperty("amount", widget()->doubleAmount->value()); config->setProperty("threshold", widget()->intThreshold->value()); config->setProperty("lightnessOnly", widget()->chkLightnessOnly->isChecked()); return config; } diff --git a/plugins/filters/unsharp/kis_wdg_unsharp.h b/plugins/filters/unsharp/kis_wdg_unsharp.h index 30c2b8da9c..ac82b6c126 100644 --- a/plugins/filters/unsharp/kis_wdg_unsharp.h +++ b/plugins/filters/unsharp/kis_wdg_unsharp.h @@ -1,43 +1,43 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_UNSHARP_H_ #define _KIS_WDG_UNSHARP_H_ #include class Ui_WdgUnsharp; class KisWdgUnsharp : public KisConfigWidget { Q_OBJECT public: KisWdgUnsharp(QWidget * parent); virtual ~KisWdgUnsharp(); inline const Ui_WdgUnsharp* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgUnsharp* m_widget; }; #endif diff --git a/plugins/filters/unsharp/tests/kis_unsharp_mask_test.cpp b/plugins/filters/unsharp/tests/kis_unsharp_mask_test.cpp index 85626efc4b..4ad7a55101 100644 --- a/plugins/filters/unsharp/tests/kis_unsharp_mask_test.cpp +++ b/plugins/filters/unsharp/tests/kis_unsharp_mask_test.cpp @@ -1,67 +1,67 @@ /* * 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_unsharp_mask_test.h" #include #include "kis_transaction.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "testutil.h" void KisUnsharpMaskTest::testUnsharpWithTransparency() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage srcImage(TestUtil::fetchDataFileLazy("source_with_transparency.png")); QVERIFY(!srcImage.isNull()); QRect imageRect = srcImage.rect(); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(srcImage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("unsharp"); Q_ASSERT(f); - KisFilterConfiguration * kfc = f->defaultConfiguration(0); + KisFilterConfigurationSP kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); kfc->setProperty("halfSize", 3); kfc->setProperty("amount", 2.5); kfc->setProperty("threshold", 0); KisTransaction t(dev); f->process(dev, QRect(imageRect.topLeft(), imageRect.size()), kfc); t.end(); QImage resultImage = dev->convertToQImage(0, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height()); TestUtil::checkQImage(resultImage, "unsharp_mask_test", "with_transparency", "unsharp_with_transparency"); } QTEST_MAIN(KisUnsharpMaskTest) diff --git a/plugins/filters/wavefilter/kis_wdg_wave.cpp b/plugins/filters/wavefilter/kis_wdg_wave.cpp index 023b5dc319..25a1a7e40f 100644 --- a/plugins/filters/wavefilter/kis_wdg_wave.cpp +++ b/plugins/filters/wavefilter/kis_wdg_wave.cpp @@ -1,93 +1,93 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_wave.h" #include #include #include #include "ui_wdgwaveoptions.h" KisWdgWave::KisWdgWave(KisFilter* /*nfilter*/, QWidget* parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgWaveOptions(); m_widget->setupUi(this); connect(widget()->intHWavelength, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intHShift, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intHAmplitude, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->cbHShape, SIGNAL(activated(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intVWavelength, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intVShift, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->intVAmplitude, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); connect(widget()->cbVShape, SIGNAL(activated(int)), SIGNAL(sigConfigurationItemChanged())); } KisWdgWave::~KisWdgWave() { delete m_widget; } -void KisWdgWave::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgWave::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; if (config->getProperty("horizontalwavelength", value)) { widget()->intHWavelength->setValue(value.toUInt()); } if (config->getProperty("horizontalshift", value)) { widget()->intHShift->setValue(value.toUInt()); } if (config->getProperty("horizontalamplitude", value)) { widget()->intHAmplitude->setValue(value.toUInt()); } if (config->getProperty("horizontalshape", value)) { widget()->cbHShape->setCurrentIndex(value.toUInt()); } if (config->getProperty("verticalwavelength", value)) { widget()->intVWavelength->setValue(value.toUInt()); } if (config->getProperty("verticalshift", value)) { widget()->intVShift->setValue(value.toUInt()); } if (config->getProperty("verticalamplitude", value)) { widget()->intVAmplitude->setValue(value.toUInt()); } if (config->getProperty("verticalshape", value)) { widget()->cbVShape->setCurrentIndex(value.toUInt()); } } -KisPropertiesConfiguration* KisWdgWave::configuration() const +KisPropertiesConfigurationSP KisWdgWave::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("wave", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("wave", 1); config->setProperty("horizontalwavelength", this->widget()->intHWavelength->value()); config->setProperty("horizontalshift", this->widget()->intHShift->value()); config->setProperty("horizontalamplitude", this->widget()->intHAmplitude->value()); config->setProperty("horizontalshape", this->widget()->cbHShape->currentIndex()); config->setProperty("verticalwavelength", this->widget()->intVWavelength->value()); config->setProperty("verticalshift", this->widget()->intVShift->value()); config->setProperty("verticalamplitude", this->widget()->intVAmplitude->value()); config->setProperty("verticalshape", this->widget()->cbVShape->currentIndex()); return config; } diff --git a/plugins/filters/wavefilter/kis_wdg_wave.h b/plugins/filters/wavefilter/kis_wdg_wave.h index 475de9f522..b2002c3200 100644 --- a/plugins/filters/wavefilter/kis_wdg_wave.h +++ b/plugins/filters/wavefilter/kis_wdg_wave.h @@ -1,46 +1,46 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_WAVE_H #define KIS_WDG_WAVE_H #include class Ui_WdgWaveOptions; class KisFilter; class KisWdgWave : public KisConfigWidget { Q_OBJECT public: KisWdgWave(KisFilter* nfilter, QWidget* parent = 0); ~KisWdgWave(); public: inline const Ui_WdgWaveOptions* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgWaveOptions* m_widget; }; #endif diff --git a/plugins/filters/wavefilter/wavefilter.cpp b/plugins/filters/wavefilter/wavefilter.cpp index d3ffe973b3..ed6e6fe31f 100644 --- a/plugins/filters/wavefilter/wavefilter.cpp +++ b/plugins/filters/wavefilter/wavefilter.cpp @@ -1,179 +1,179 @@ /* * This file is part of the KDE project * * Copyright (c) 2005 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. */ #include "wavefilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_wave.h" #include "ui_wdgwaveoptions.h" #include K_PLUGIN_FACTORY_WITH_JSON(KritaWaveFilterFactory, "kritawavefilter.json", registerPlugin();) class KisWaveCurve { public: virtual ~KisWaveCurve() {} virtual double valueAt(int x, int y) = 0; }; class KisSinusoidalWaveCurve : public KisWaveCurve { public: KisSinusoidalWaveCurve(int amplitude, int wavelength, int shift) : m_amplitude(amplitude), m_wavelength(wavelength), m_shift(shift) { } virtual ~KisSinusoidalWaveCurve() {} virtual double valueAt(int x, int y) { return y + m_amplitude * cos((double)(m_shift + x) / m_wavelength); } private: int m_amplitude, m_wavelength, m_shift; }; class KisTriangleWaveCurve : public KisWaveCurve { public: KisTriangleWaveCurve(int amplitude, int wavelength, int shift) : m_amplitude(amplitude), m_wavelength(wavelength), m_shift(shift) { } virtual ~KisTriangleWaveCurve() {} virtual double valueAt(int x, int y) { return y + m_amplitude * pow(-1.0, (m_shift + x) / m_wavelength) *(0.5 - (double)((m_shift + x) % m_wavelength) / m_wavelength); } private: int m_amplitude, m_wavelength, m_shift; }; KritaWaveFilter::KritaWaveFilter(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(new KisFilterWave()); } KritaWaveFilter::~KritaWaveFilter() { } KisFilterWave::KisFilterWave() : KisFilter(id(), categoryOther(), i18n("&Wave...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(false); setSupportsAdjustmentLayers(false); } -KisFilterConfiguration* KisFilterWave::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisFilterWave::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("wave", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("wave", 1); config->setProperty("horizontalwavelength", 50); config->setProperty("horizontalshift", 50); config->setProperty("horizontalamplitude", 4); config->setProperty("horizontalshape", 0); config->setProperty("verticalwavelength", 50); config->setProperty("verticalshift", 50); config->setProperty("verticalamplitude", 4); config->setProperty("verticalshape", 0); return config; } KisConfigWidget * KisFilterWave::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { return new KisWdgWave((KisFilter*)this, (QWidget*)parent); } void KisFilterWave::processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const { Q_ASSERT(device.data() != 0); int cost = (applyRect.width() * applyRect.height()) / 100; if (cost == 0) cost = 1; int count = 0; QVariant value; int horizontalwavelength = (config && config->getProperty("horizontalwavelength", value)) ? value.toInt() : 50; int horizontalshift = (config && config->getProperty("horizontalshift", value)) ? value.toInt() : 50; int horizontalamplitude = (config && config->getProperty("horizontalamplitude", value)) ? value.toInt() : 4; int horizontalshape = (config && config->getProperty("horizontalshape", value)) ? value.toInt() : 0; int verticalwavelength = (config && config->getProperty("verticalwavelength", value)) ? value.toInt() : 50; int verticalshift = (config && config->getProperty("verticalshift", value)) ? value.toInt() : 50; int verticalamplitude = (config && config->getProperty("verticalamplitude", value)) ? value.toInt() : 4; int verticalshape = (config && config->getProperty("verticalshape", value)) ? value.toInt() : 0; KisSequentialIterator dstIt(device, applyRect); KisWaveCurve* verticalcurve; if (verticalshape == 1) verticalcurve = new KisTriangleWaveCurve(verticalamplitude, verticalwavelength, verticalshift); else verticalcurve = new KisSinusoidalWaveCurve(verticalamplitude, verticalwavelength, verticalshift); KisWaveCurve* horizontalcurve; if (horizontalshape == 1) horizontalcurve = new KisTriangleWaveCurve(horizontalamplitude, horizontalwavelength, horizontalshift); else horizontalcurve = new KisSinusoidalWaveCurve(horizontalamplitude, horizontalwavelength, horizontalshift); KisRandomSubAccessorSP srcRSA = device->createRandomSubAccessor(); do { double xv = horizontalcurve->valueAt(dstIt.y(), dstIt.x()); double yv = verticalcurve->valueAt(dstIt.x(), dstIt.y()); srcRSA->moveTo(QPointF(xv, yv)); srcRSA->sampledOldRawData(dstIt.rawData()); if (progressUpdater) progressUpdater->setProgress((++count) / cost); } while (dstIt.nextPixel()); delete horizontalcurve; delete verticalcurve; } -QRect KisFilterWave::neededRect(const QRect& rect, const KisFilterConfiguration* config, int lod) const +QRect KisFilterWave::neededRect(const QRect& rect, const KisFilterConfigurationSP config, int lod) const { Q_UNUSED(lod); QVariant value; int horizontalamplitude = (config && config->getProperty("horizontalamplitude", value)) ? value.toInt() : 4; int verticalamplitude = (config && config->getProperty("verticalamplitude", value)) ? value.toInt() : 4; return rect.adjusted(-horizontalamplitude, -verticalamplitude, horizontalamplitude, verticalamplitude); } #include "wavefilter.moc" diff --git a/plugins/filters/wavefilter/wavefilter.h b/plugins/filters/wavefilter/wavefilter.h index c6d7ebd3e0..16f435ef97 100644 --- a/plugins/filters/wavefilter/wavefilter.h +++ b/plugins/filters/wavefilter/wavefilter.h @@ -1,61 +1,61 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 WAVEFILTER_H #define WAVEFILTER_H #include #include #include "filter/kis_filter.h" class KisConfigWidget; class KritaWaveFilter : public QObject { Q_OBJECT public: KritaWaveFilter(QObject *parent, const QVariantList &); virtual ~KritaWaveFilter(); }; class KisFilterWave : public KisFilter { public: KisFilterWave(); public: void processImpl(KisPaintDeviceSP device, const QRect& applyRect, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const; static inline KoID id() { return KoID("wave", i18n("Wave")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; public: - virtual QRect neededRect(const QRect& rect, const KisFilterConfiguration* config = 0, int lod = 0) const; + virtual QRect neededRect(const QRect& rect, const KisFilterConfigurationSP config = 0, int lod = 0) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/generators/pattern/kis_wdg_pattern.cpp b/plugins/generators/pattern/kis_wdg_pattern.cpp index ce380bda8a..2f16ae2548 100644 --- a/plugins/generators/pattern/kis_wdg_pattern.cpp +++ b/plugins/generators/pattern/kis_wdg_pattern.cpp @@ -1,70 +1,70 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_pattern.h" #include #include #include #include #include #include #include #include #include "ui_wdgpatternoptions.h" KisWdgPattern::KisWdgPattern(QWidget* parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgPatternOptions(); m_widget->setupUi(this); m_widget->lblPattern->setVisible(false); m_widget->lblColor->setVisible(false); m_widget->bnColor->setVisible(false); } KisWdgPattern::~KisWdgPattern() { delete m_widget; } -void KisWdgPattern::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgPattern::setConfiguration(const KisPropertiesConfigurationSP config) { KoResourceServer *rserver = KoResourceServerProvider::instance()->patternServer(); KoPattern *pattern = rserver->resourceByName(config->getString("pattern", "Grid01.pat")); if (pattern) { widget()->patternChooser->setCurrentPattern(pattern); } } -KisPropertiesConfiguration* KisWdgPattern::configuration() const +KisPropertiesConfigurationSP KisWdgPattern::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("pattern", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("pattern", 1); QVariant v; v.setValue(widget()->patternChooser->currentResource()->name()); config->setProperty("pattern", v); return config; } diff --git a/plugins/generators/pattern/kis_wdg_pattern.h b/plugins/generators/pattern/kis_wdg_pattern.h index f0ab00d9fe..62fc4a54c9 100644 --- a/plugins/generators/pattern/kis_wdg_pattern.h +++ b/plugins/generators/pattern/kis_wdg_pattern.h @@ -1,45 +1,45 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_PATTERN_H #define KIS_WDG_PATTERN_H #include class Ui_WdgPatternOptions; class KisWdgPattern : public KisConfigWidget { Q_OBJECT public: KisWdgPattern(QWidget* parent = 0); ~KisWdgPattern(); public: inline const Ui_WdgPatternOptions* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgPatternOptions* m_widget; }; #endif diff --git a/plugins/generators/pattern/patterngenerator.cpp b/plugins/generators/pattern/patterngenerator.cpp index 10e6666c77..1cb8889a88 100644 --- a/plugins/generators/pattern/patterngenerator.cpp +++ b/plugins/generators/pattern/patterngenerator.cpp @@ -1,121 +1,121 @@ /* * This file is part of the KDE project * * 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 "patterngenerator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_pattern.h" #include "ui_wdgpatternoptions.h" K_PLUGIN_FACTORY_WITH_JSON(KritaPatternGeneratorFactory, "kritapatterngenerator.json", registerPlugin();) KritaPatternGenerator::KritaPatternGenerator(QObject *parent, const QVariantList &) : QObject(parent) { KisGeneratorRegistry::instance()->add(new KoPatternGenerator()); } KritaPatternGenerator::~KritaPatternGenerator() { } KoPatternGenerator::KoPatternGenerator() : KisGenerator(id(), KoID("basic"), i18n("&Pattern...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } -KisFilterConfiguration* KoPatternGenerator::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KoPatternGenerator::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("pattern", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("pattern", 1); QVariant v; v.setValue(QString("Grid01.pat")); config->setProperty("pattern", v); // v.setValue(KoColor()); // config->setProperty("color", v); return config; } KisConfigWidget * KoPatternGenerator::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgPattern(parent); } void KoPatternGenerator::generate(KisProcessingInformation dstInfo, const QSize& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { KisPaintDeviceSP dst = dstInfo.paintDevice(); Q_ASSERT(!dst.isNull()); Q_ASSERT(config); if (!config) return; QString patternName = config->getString("pattern", "Grid01.pat"); KoResourceServer *rserver = KoResourceServerProvider::instance()->patternServer(); KoPattern *pattern = rserver->resourceByName(patternName); // KoColor c = config->getColor("color"); KisFillPainter gc(dst); gc.setPattern(pattern); // gc.setPaintColor(c); gc.setProgress(progressUpdater); gc.setChannelFlags(config->channelFlags()); gc.setOpacity(OPACITY_OPAQUE_U8); gc.setSelection(dstInfo.selection()); gc.setWidth(size.width()); gc.setHeight(size.height()); gc.setFillStyle(KisFillPainter::FillStylePattern); gc.fillRect(QRect(dstInfo.topLeft(), size), pattern); gc.end(); } #include "patterngenerator.moc" \ No newline at end of file diff --git a/plugins/generators/pattern/patterngenerator.h b/plugins/generators/pattern/patterngenerator.h index c399805eb8..36b7af3acb 100644 --- a/plugins/generators/pattern/patterngenerator.h +++ b/plugins/generators/pattern/patterngenerator.h @@ -1,59 +1,59 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 PATTERN_GENERATOR_H #define PATTERN_GENERATOR_H #include #include #include "generator/kis_generator.h" class KisConfigWidget; class KritaPatternGenerator : public QObject { Q_OBJECT public: KritaPatternGenerator(QObject *parent, const QVariantList &); virtual ~KritaPatternGenerator(); }; class KoPatternGenerator : public KisGenerator { public: KoPatternGenerator(); using KisGenerator::generate; void generate(KisProcessingInformation dst, const QSize& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("pattern", i18n("Pattern")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/generators/solid/colorgenerator.cpp b/plugins/generators/solid/colorgenerator.cpp index 67268884fc..dd74c90121 100644 --- a/plugins/generators/solid/colorgenerator.cpp +++ b/plugins/generators/solid/colorgenerator.cpp @@ -1,103 +1,103 @@ /* * This file is part of the KDE project * * 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 "colorgenerator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_color.h" #include "ui_wdgcoloroptions.h" K_PLUGIN_FACTORY_WITH_JSON(KritaColorGeneratorFactory, "kritacolorgenerator.json", registerPlugin();) KritaColorGenerator::KritaColorGenerator(QObject *parent, const QVariantList &) : QObject(parent) { KisGeneratorRegistry::instance()->add(new KisColorGenerator()); } KritaColorGenerator::~KritaColorGenerator() { } KisColorGenerator::KisColorGenerator() : KisGenerator(id(), KoID("basic"), i18n("&Solid Color...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } -KisFilterConfiguration* KisColorGenerator::factoryConfiguration(const KisPaintDeviceSP) const +KisFilterConfigurationSP KisColorGenerator::factoryConfiguration(const KisPaintDeviceSP) const { - KisFilterConfiguration* config = new KisFilterConfiguration("color", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("color", 1); QVariant v; v.setValue(KoColor()); config->setProperty("color", v); return config; } KisConfigWidget * KisColorGenerator::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgColor(parent); } void KisColorGenerator::generate(KisProcessingInformation dstInfo, const QSize& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { KisPaintDeviceSP dst = dstInfo.paintDevice(); Q_ASSERT(!dst.isNull()); Q_ASSERT(config); KoColor c; if (config) { c = config->getColor("color"); KisFillPainter gc(dst); gc.setProgress(progressUpdater); gc.setChannelFlags(config->channelFlags()); gc.setOpacity(100); gc.setSelection(dstInfo.selection()); gc.fillRect(QRect(dstInfo.topLeft(), size), c); gc.end(); } } #include "colorgenerator.moc" diff --git a/plugins/generators/solid/colorgenerator.h b/plugins/generators/solid/colorgenerator.h index af1c1d972d..a141e7b1e4 100644 --- a/plugins/generators/solid/colorgenerator.h +++ b/plugins/generators/solid/colorgenerator.h @@ -1,59 +1,59 @@ /* * This file is part of Krita * * Copyright (c) 2006 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 COLOR_GENERATOR_H #define COLOR_GENERATOR_H #include #include #include "generator/kis_generator.h" class KisConfigWidget; class KritaColorGenerator : public QObject { Q_OBJECT public: KritaColorGenerator(QObject *parent, const QVariantList &); virtual ~KritaColorGenerator(); }; class KisColorGenerator : public KisGenerator { public: KisColorGenerator(); using KisGenerator::generate; void generate(KisProcessingInformation dst, const QSize& size, - const KisFilterConfiguration* config, + const KisFilterConfigurationSP config, KoUpdater* progressUpdater ) const; static inline KoID id() { return KoID("color", i18n("Color")); } - virtual KisFilterConfiguration* factoryConfiguration(const KisPaintDeviceSP) const; + virtual KisFilterConfigurationSP factoryConfiguration(const KisPaintDeviceSP) const; virtual KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const; }; #endif diff --git a/plugins/generators/solid/kis_wdg_color.cpp b/plugins/generators/solid/kis_wdg_color.cpp index 83624ece1b..b2bd6e9a88 100644 --- a/plugins/generators/solid/kis_wdg_color.cpp +++ b/plugins/generators/solid/kis_wdg_color.cpp @@ -1,63 +1,63 @@ /* * This file is part of Krita * * Copyright (c) 2006 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. */ #include "kis_wdg_color.h" #include #include #include #include "ui_wdgcoloroptions.h" KisWdgColor::KisWdgColor(QWidget* parent, const KoColorSpace *cs) : KisConfigWidget(parent) { m_widget = new Ui_WdgColorOptions(); m_widget->setupUi(this); m_cs = cs; } KisWdgColor::~KisWdgColor() { delete m_widget; } -void KisWdgColor::setConfiguration(const KisPropertiesConfiguration* config) +void KisWdgColor::setConfiguration(const KisPropertiesConfigurationSP config) { QVariant value; KoColor c =config->getColor("color"); c.convertTo(m_cs); widget()->bnColor->setColor(c); } -KisPropertiesConfiguration* KisWdgColor::configuration() const +KisPropertiesConfigurationSP KisWdgColor::configuration() const { - KisFilterConfiguration* config = new KisFilterConfiguration("color", 1); + KisFilterConfigurationSP config = new KisFilterConfiguration("color", 1); KoColor c; c.fromKoColor(this->widget()->bnColor->color()); QVariant v; v.setValue(c); config->setProperty("color", v); return config; } diff --git a/plugins/generators/solid/kis_wdg_color.h b/plugins/generators/solid/kis_wdg_color.h index 55ce1e54f1..cb36459337 100644 --- a/plugins/generators/solid/kis_wdg_color.h +++ b/plugins/generators/solid/kis_wdg_color.h @@ -1,48 +1,48 @@ /* * This file is part of Krita * * Copyright (c) 2006 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_WDG_COLOR_H #define KIS_WDG_COLOR_H #include #include #include class Ui_WdgColorOptions; class KisWdgColor : public KisConfigWidget { Q_OBJECT public: KisWdgColor(QWidget* parent = 0, const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8()); ~KisWdgColor(); public: inline const Ui_WdgColorOptions* widget() const { return m_widget; } - virtual void setConfiguration(const KisPropertiesConfiguration*); - virtual KisPropertiesConfiguration* configuration() const; + virtual void setConfiguration(const KisPropertiesConfigurationSP); + virtual KisPropertiesConfigurationSP configuration() const; private: Ui_WdgColorOptions* m_widget; const KoColorSpace *m_cs; }; #endif diff --git a/plugins/impex/CMakeLists.txt b/plugins/impex/CMakeLists.txt index 4b3db50779..7571851366 100644 --- a/plugins/impex/CMakeLists.txt +++ b/plugins/impex/CMakeLists.txt @@ -1,43 +1,43 @@ project(kritafilters) if(CMAKE_SIZEOF_VOID_P EQUAL 4) add_definitions( -DCPU_32_BITS ) endif() if(JPEG_FOUND AND HAVE_LCMS2) add_subdirectory(jpeg) endif() if(TIFF_FOUND) add_subdirectory(tiff) endif() if(PNG_FOUND) add_subdirectory(png) add_subdirectory(csv) endif() if(OPENEXR_FOUND) add_subdirectory(exr) endif() if(POPPLER_FOUND) add_subdirectory(pdf) endif() if(LIBRAW_FOUND) add_subdirectory(raw) endif() add_subdirectory(bmp) add_subdirectory(ora) add_subdirectory(ppm) add_subdirectory(xcf) add_subdirectory(psd) add_subdirectory(odg) add_subdirectory(qml) add_subdirectory(tga) add_subdirectory(heightmap) add_subdirectory(brush) add_subdirectory(spriter) -#add_subdirectory(video) +add_subdirectory(video) diff --git a/plugins/impex/bmp/kis_bmp_export.cpp b/plugins/impex/bmp/kis_bmp_export.cpp index 6202f399fb..e5b110d731 100644 --- a/plugins/impex/bmp/kis_bmp_export.cpp +++ b/plugins/impex/bmp/kis_bmp_export.cpp @@ -1,70 +1,70 @@ /* * Copyright (c) 2007 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_bmp_export.h" #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisBMPExportFactory, "krita_bmp_export.json", registerPlugin();) KisBMPExport::KisBMPExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBMPExport::~KisBMPExport() { } -KisImportExportFilter::ConversionStatus KisBMPExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisBMPExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "BMP export! From:" << from << ", To:" << to << ""; KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; QRect rc = input->image()->bounds(); // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); image.save(filename); return KisImportExportFilter::OK; } #include "kis_bmp_export.moc" diff --git a/plugins/impex/bmp/kis_bmp_export.h b/plugins/impex/bmp/kis_bmp_export.h index 0d38bc7098..9cc799fae1 100644 --- a/plugins/impex/bmp/kis_bmp_export.h +++ b/plugins/impex/bmp/kis_bmp_export.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_BMP_EXPORT_H_ #define _KIS_BMP_EXPORT_H_ #include #include class KisBMPExport : public KisImportExportFilter { Q_OBJECT public: KisBMPExport(QObject *parent, const QVariantList &); virtual ~KisBMPExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/bmp/kis_bmp_import.cpp b/plugins/impex/bmp/kis_bmp_import.cpp index 633b9aecc5..4cc1512f12 100644 --- a/plugins/impex/bmp/kis_bmp_import.cpp +++ b/plugins/impex/bmp/kis_bmp_import.cpp @@ -1,93 +1,93 @@ /* * Copyright (c) 2007 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_bmp_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisBMPImportFactory, "krita_bmp_import.json", registerPlugin();) KisBMPImport::KisBMPImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBMPImport::~KisBMPImport() { } -KisImportExportFilter::ConversionStatus KisBMPImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisBMPImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "BMP import! From:" << from << ", To:" << to << 0; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { - + QFileInfo fi(filename); if (!fi.exists()) { return KisImportExportFilter::FileNotFound; } QImage img(filename); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(doc->createUndoStore(), img.width(), img.height(), colorSpace, "imported from bmp"); KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255); layer->paintDevice()->convertFromQImage(img, 0, 0, 0); image->addNode(layer.data(), image->rootLayer().data()); doc->setCurrentImage(image); return KisImportExportFilter::OK; } return KisImportExportFilter::StorageCreationError; } #include "kis_bmp_import.moc" diff --git a/plugins/impex/bmp/kis_bmp_import.h b/plugins/impex/bmp/kis_bmp_import.h index 95399c8d6c..6fa514f3f8 100644 --- a/plugins/impex/bmp/kis_bmp_import.h +++ b/plugins/impex/bmp/kis_bmp_import.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_BMP_IMPORT_H_ #define _KIS_BMP_IMPORT_H_ #include #include class KisBMPImport : public KisImportExportFilter { Q_OBJECT public: KisBMPImport(QObject *parent, const QVariantList &); virtual ~KisBMPImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/brush/kis_brush_export.cpp b/plugins/impex/brush/kis_brush_export.cpp index af895c4fae..a60bfe73a2 100644 --- a/plugins/impex/brush/kis_brush_export.cpp +++ b/plugins/impex/brush/kis_brush_export.cpp @@ -1,211 +1,211 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_brush_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct KisBrushExportOptions { qreal spacing; bool mask; int brushStyle; int selectionMode; QString name; }; K_PLUGIN_FACTORY_WITH_JSON(KisBrushExportFactory, "krita_brush_export.json", registerPlugin();) KisBrushExport::KisBrushExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBrushExport::~KisBrushExport() { } -KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisAnnotationSP annotation = input->image()->annotation("ImagePipe Parasite"); KisPipeBrushParasite parasite; if (annotation) { QBuffer buf(const_cast(&annotation->annotation())); buf.open(QBuffer::ReadOnly); //parasite.loadFromDevice(&buf); buf.close(); } KisBrushExportOptions exportOptions; exportOptions.spacing = 1.0; exportOptions.name = input->image()->objectName(); exportOptions.mask = true; exportOptions.selectionMode = 0; exportOptions.brushStyle = 0; if (input->image()->dynamicPropertyNames().contains("brushspacing")) { exportOptions.spacing = input->image()->property("brushspacing").toFloat(); } KisGbrBrush *brush = 0; if (!getBatchMode()) { KoDialog* dlgBrushExportOptions = new KoDialog(0); dlgBrushExportOptions->setWindowTitle(i18n("Brush Tip Export Options")); dlgBrushExportOptions->setButtons(KoDialog::Ok | KoDialog::Cancel); Ui::WdgExportGih wdgUi; QWidget* wdg = new QWidget(dlgBrushExportOptions); wdgUi.setupUi(wdg); wdgUi.spacingWidget->setSpacing(false, exportOptions.spacing); wdgUi.nameLineEdit->setText(exportOptions.name); dlgBrushExportOptions->setMainWidget(wdg); if (to == "image/x-gimp-brush") { brush = new KisGbrBrush(filename); wdgUi.groupBox->setVisible(false); } else if (to == "image/x-gimp-brush-animated") { brush = new KisImagePipeBrush(filename); wdgUi.groupBox->setVisible(true); } else { delete dlgBrushExportOptions; return KisImportExportFilter::BadMimeType; } if (dlgBrushExportOptions->exec() == QDialog::Rejected) { delete dlgBrushExportOptions; return KisImportExportFilter::UserCancelled; } else { exportOptions.spacing = wdgUi.spacingWidget->spacing(); exportOptions.name = wdgUi.brushNameLbl->text(); exportOptions.mask = wdgUi.colorAsMask->isChecked(); exportOptions.brushStyle = wdgUi.brushStyle->currentIndex(); exportOptions.selectionMode = wdgUi.cmbSelectionMode->currentIndex(); delete dlgBrushExportOptions; } } else { qApp->processEvents(); // For vector layers to be updated } // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); QRect rc = input->image()->bounds(); brush->setName(exportOptions.name); brush->setSpacing(exportOptions.spacing); brush->setUseColorAsMask(exportOptions.mask); int w = input->image()->width(); int h = input->image()->height(); KisImagePipeBrush *pipeBrush = dynamic_cast(brush); if (pipeBrush) { // Create parasite. XXX: share with KisCustomBrushWidget QVector< QVector > devices; devices.push_back(QVector()); KoProperties properties; properties.setProperty("visible", true); QList layers = input->image()->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (exportOptions.selectionMode) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } KisPipeBrushParasite parasite; // XXX: share code with KisImagePipeBrush, when we figure out how to support more gih features parasite.dim = devices.count(); // XXX Change for multidim! : parasite.ncells = devices.at(0).count(); parasite.rank[0] = parasite.ncells; // ### This can mask some bugs, be careful here in the future parasite.selection[0] = modes.at(0); // XXX needsmovement! parasite.setBrushesCount(); pipeBrush->setParasite(parasite); pipeBrush->setDevices(devices, w, h); } else { QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); brush->setImage(image); } brush->setWidth(w); brush->setHeight(h); QFile f(filename); f.open(QIODevice::WriteOnly); brush->saveToDevice(&f); f.close(); return KisImportExportFilter::OK; } #include "kis_brush_export.moc" diff --git a/plugins/impex/brush/kis_brush_export.h b/plugins/impex/brush/kis_brush_export.h index 26933875fa..47b3bb27a3 100644 --- a/plugins/impex/brush/kis_brush_export.h +++ b/plugins/impex/brush/kis_brush_export.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_Brush_EXPORT_H_ #define _KIS_Brush_EXPORT_H_ #include #include class KisBrushExport : public KisImportExportFilter { Q_OBJECT public: KisBrushExport(QObject *parent, const QVariantList &); virtual ~KisBrushExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/brush/kis_brush_import.cpp b/plugins/impex/brush/kis_brush_import.cpp index 41a5646ac9..967accf9b6 100644 --- a/plugins/impex/brush/kis_brush_import.cpp +++ b/plugins/impex/brush/kis_brush_import.cpp @@ -1,149 +1,149 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_brush_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisBrushImportFactory, "krita_brush_import.json", registerPlugin();) KisBrushImport::KisBrushImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBrushImport::~KisBrushImport() { } -KisImportExportFilter::ConversionStatus KisBrushImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisBrushImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; QString filename = inputFile(); if (!filename.isEmpty()) { if (!QFile(filename).exists()) { return KisImportExportFilter::FileNotFound; } KisBrush *brush; if (from == "image/x-gimp-brush") { brush = new KisGbrBrush(filename); } else if (from == "image/x-gimp-brush-animated") { brush = new KisImagePipeBrush(filename); } else { return KisImportExportFilter::BadMimeType; } if (!brush->load()) { delete brush; return KisImportExportFilter::InvalidFormat; } if (!brush->valid()) { delete brush; return KisImportExportFilter::InvalidFormat; } KisDocument * doc = outputDocument(); if (!doc) { delete brush; return KisImportExportFilter::NoDocumentCreated; } doc->prepareForImport(); const KoColorSpace *colorSpace = 0; if (brush->hasColor()) { colorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisImageWSP image = new KisImage(doc->createUndoStore(), brush->width(), brush->height(), colorSpace, brush->name()); image->setProperty("brushspacing", brush->spacing()); KisImagePipeBrush *pipeBrush = dynamic_cast(brush); if (pipeBrush) { QVector brushes = pipeBrush->brushes(); for(int i = brushes.size(); i > 0; i--) { KisGbrBrush *subbrush = brushes.at(i - 1); const KoColorSpace *subColorSpace = 0; if (brush->hasColor()) { subColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { subColorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, subColorSpace); layer->paintDevice()->convertFromQImage(subbrush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer()); } KisAnnotationSP ann = new KisAnimatedBrushAnnotation(pipeBrush->parasite()); image->addAnnotation(ann); } else { KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, colorSpace); layer->paintDevice()->convertFromQImage(brush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer(), 0); } doc->setCurrentImage(image); delete brush; return KisImportExportFilter::OK; } return KisImportExportFilter::StorageCreationError; } #include "kis_brush_import.moc" diff --git a/plugins/impex/brush/kis_brush_import.h b/plugins/impex/brush/kis_brush_import.h index d6b85ecab6..290fee192e 100644 --- a/plugins/impex/brush/kis_brush_import.h +++ b/plugins/impex/brush/kis_brush_import.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_Brush_IMPORT_H_ #define _KIS_Brush_IMPORT_H_ #include #include class KisBrushImport : public KisImportExportFilter { Q_OBJECT public: KisBrushImport(QObject *parent, const QVariantList &); virtual ~KisBrushImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/csv/kis_csv_export.cpp b/plugins/impex/csv/kis_csv_export.cpp index d5369537ce..49615d9234 100644 --- a/plugins/impex/csv/kis_csv_export.cpp +++ b/plugins/impex/csv/kis_csv_export.cpp @@ -1,107 +1,107 @@ /* * Copyright (c) 2016 Laszlo Fazekas * * 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_csv_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "csv_saver.h" K_PLUGIN_FACTORY_WITH_JSON(KisCSVExportFactory, "krita_csv_export.json", registerPlugin();) bool checkHomogenity(KisNodeSP root) { bool res = true; KisNodeSP child = root->firstChild(); while (child) { if (child->childCount() > 0) { res= false; break; } child = child->nextSibling(); } return res; } KisCSVExport::KisCSVExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisCSVExport::~KisCSVExport() { } -KisImportExportFilter::ConversionStatus KisCSVExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisCSVExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "CSV export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument* input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (!checkHomogenity(input->image()->rootLayer())) { if (!getBatchMode()) { QMessageBox::critical(0, i18nc("@title:window", "CSV Export Error"), i18n("Unable to save to the CSV format.\n" "The CSV format not supports layer groups or masked layers.")); } return KisImportExportFilter::InvalidFormat; } if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; CSVSaver kpc(input, getBatchMode()); KisImageBuilder_Result res; if ((res = kpc.buildAnimation(filename)) == KisImageBuilder_RESULT_OK) { dbgFile <<"success !"; return KisImportExportFilter::OK; } dbgFile <<" Result =" << res; if (res == KisImageBuilder_RESULT_CANCEL) return KisImportExportFilter::ProgressCancelled; return KisImportExportFilter::InternalError; } #include "kis_csv_export.moc" diff --git a/plugins/impex/csv/kis_csv_export.h b/plugins/impex/csv/kis_csv_export.h index ce7a3fa9a8..71ffff081c 100644 --- a/plugins/impex/csv/kis_csv_export.h +++ b/plugins/impex/csv/kis_csv_export.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2016 Laszlo Fazekas * * 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_CSV_EXPORT_H_ #define _KIS_CSV_EXPORT_H_ #include #include class KisCSVExport : public KisImportExportFilter { Q_OBJECT public: KisCSVExport(QObject *parent, const QVariantList &); virtual ~KisCSVExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/csv/kis_csv_import.cpp b/plugins/impex/csv/kis_csv_import.cpp index e46dd08270..657b65aaa1 100644 --- a/plugins/impex/csv/kis_csv_import.cpp +++ b/plugins/impex/csv/kis_csv_import.cpp @@ -1,95 +1,95 @@ /* * Copyright (c) 2016 Laszlo Fazekas * * 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_csv_import.h" #include #include #include #include #include #include #include #include "csv_loader.h" K_PLUGIN_FACTORY_WITH_JSON(CSVImportFactory, "krita_csv_import.json", registerPlugin();) KisCSVImport::KisCSVImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisCSVImport::~KisCSVImport() { } -KisImportExportFilter::ConversionStatus KisCSVImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisCSVImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Importing using CSVImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc -> prepareForImport(); if (!filename.isEmpty() && QFileInfo(filename).exists()) { CSVLoader ib(doc, getBatchMode()); KisImageBuilder_Result result = ib.buildAnimation(filename); switch (result) { case KisImageBuilder_RESULT_UNSUPPORTED: return KisImportExportFilter::NotImplemented; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_EXIST: case KisImageBuilder_RESULT_NOT_LOCAL: qDebug() << "ib returned KisImageBuilder_RESULT_NOT_LOCAL"; return KisImportExportFilter::FileNotFound; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; case KisImageBuilder_RESULT_CANCEL: return KisImportExportFilter::ProgressCancelled; case KisImageBuilder_RESULT_OK: doc -> setCurrentImage( ib.image()); return KisImportExportFilter::OK; default: return KisImportExportFilter::StorageCreationError; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/csv/kis_csv_import.h b/plugins/impex/csv/kis_csv_import.h index cb915de1b9..c80e93bb88 100644 --- a/plugins/impex/csv/kis_csv_import.h +++ b/plugins/impex/csv/kis_csv_import.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2016 Laszlo Fazekas * * 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_CSV_IMPORT_H_ #define _KIS_CSV_IMPORT_H_ #include #include class KisCSVImport : public KisImportExportFilter { Q_OBJECT public: KisCSVImport(QObject *parent, const QVariantList &); virtual ~KisCSVImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/exr/exr_export.cc b/plugins/impex/exr/exr_export.cc index 1b196f54a0..237ea7117d 100644 --- a/plugins/impex/exr/exr_export.cc +++ b/plugins/impex/exr/exr_export.cc @@ -1,153 +1,186 @@ /* * Copyright (c) 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. */ #include "exr_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "exr_converter.h" -#include "ui_exr_export_widget.h" class KisExternalLayer; K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_exr_export.json", registerPlugin();) exrExport::exrExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } exrExport::~exrExport() { } -KisImportExportFilter::ConversionStatus exrExport::convert(const QByteArray& from, const QByteArray& to) +KisPropertiesConfigurationSP exrExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("flatten", false); + return cfg; +} + +KisPropertiesConfigurationSP exrExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + QString filterConfig = KisConfig().exportConfiguration("EXR"); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *exrExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + return new KisWdgOptionsExr(parent); +} + +KisImportExportFilter::ConversionStatus exrExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "EXR export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); if (!input) return KisImportExportFilter::NoDocumentCreated; KisImageWSP image = input->image(); Q_CHECK_PTR(image); - KoDialog dialog; - dialog.setWindowTitle(i18n("OpenEXR Export Options")); - dialog.setButtons(KoDialog::Ok | KoDialog::Cancel); - Ui::ExrExportWidget widget; - QWidget *page = new QWidget(&dialog); - widget.setupUi(page); - dialog.setMainWidget(page); - dialog.resize(dialog.minimumSize()); - - QString filterConfig = KisConfig().exportConfiguration("EXR"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - widget.flatten->setChecked(cfg.getBool("flatten", false)); + KoDialog kdb; + kdb.setWindowTitle(i18n("OpenEXR Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisConfigWidget *wdg = createConfigurationWidget(&kdb, from, to); + kdb.setMainWidget(wdg); + kdb.resize(kdb.minimumSize()); + + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + if (configuration) { + cfg->fromXML(configuration->toXML()); + } + else { + cfg = lastSavedConfiguration(from, to); + } + wdg->setConfiguration(cfg); if (!getBatchMode() ) { QApplication::restoreOverrideCursor(); - if (dialog.exec() == QDialog::Rejected) { + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("EXR", *cfg.data()); } - cfg.setProperty("flatten", widget.flatten->isChecked()); - KisConfig().setExportConfiguration("EXR", cfg); - QString filename = outputFile(); if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; exrConverter kpc(input, !getBatchMode()); KisImageBuilder_Result res; - if (widget.flatten->isChecked()) { + if (cfg->getBool("flatten")) { // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); KisPaintDeviceSP pd = new KisPaintDevice(*image->projection()); KisPaintLayerSP l = new KisPaintLayer(image, "projection", OPACITY_OPAQUE_U8, pd); res = kpc.buildFile(filename, l); } else { // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); - res = kpc.buildFile(filename, image->rootLayer()); } dbgFile << " Result =" << res; switch (res) { case KisImageBuilder_RESULT_INVALID_ARG: input->setErrorMessage(i18n("This layer cannot be saved to EXR.")); return KisImportExportFilter::WrongFormat; case KisImageBuilder_RESULT_EMPTY: input->setErrorMessage(i18n("The layer does not have an image associated with it.")); return KisImportExportFilter::WrongFormat; case KisImageBuilder_RESULT_NO_URI: input->setErrorMessage(i18n("The filename is empty.")); return KisImportExportFilter::CreationError; case KisImageBuilder_RESULT_NOT_LOCAL: input->setErrorMessage(i18n("EXR images cannot be saved remotely.")); return KisImportExportFilter::InternalError; case KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE: input->setErrorMessage(i18n("Colorspace not supported: EXR images must be 16 or 32 bits floating point RGB.")); return KisImportExportFilter::WrongFormat; case KisImageBuilder_RESULT_OK: return KisImportExportFilter::OK; default: break; } input->setErrorMessage(i18n("Internal Error")); return KisImportExportFilter::InternalError; } + +void KisWdgOptionsExr::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + chkFlatten->setChecked(cfg->getBool("flatten", false)); +} + +KisPropertiesConfigurationSP KisWdgOptionsExr::configuration() const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("flatten", chkFlatten->isChecked()); + return cfg; +} + + #include diff --git a/plugins/impex/exr/exr_export.h b/plugins/impex/exr/exr_export.h index ab24938422..96e8fbc9e8 100644 --- a/plugins/impex/exr/exr_export.h +++ b/plugins/impex/exr/exr_export.h @@ -1,37 +1,58 @@ /* * Copyright (c) 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 _EXR_EXPORT_H_ #define _EXR_EXPORT_H_ #include #include +#include +#include "ui_exr_export_widget.h" + +class KisWdgOptionsExr : public KisConfigWidget, public Ui::ExrExportWidget +{ + Q_OBJECT + +public: + KisWdgOptionsExr(QWidget *parent) + : KisConfigWidget(parent) + { + setupUi(this); + } + + void setConfiguration(const KisPropertiesConfigurationSP cfg); + KisPropertiesConfigurationSP configuration() const; +}; + class exrExport : public KisImportExportFilter { Q_OBJECT public: exrExport(QObject *parent, const QVariantList &); virtual ~exrExport(); + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/exr/exr_export_widget.ui b/plugins/impex/exr/exr_export_widget.ui index 9b0b44678a..d535bac2df 100644 --- a/plugins/impex/exr/exr_export_widget.ui +++ b/plugins/impex/exr/exr_export_widget.ui @@ -1,50 +1,50 @@ ExrExportWidget 0 0 400 243 - + 0 0 This option will merge all layers. It is advisable to check this option, otherwise other applications might not be able to read your file correctly. Flatten the &image false Qt::Vertical 20 200 diff --git a/plugins/impex/exr/exr_import.cc b/plugins/impex/exr/exr_import.cc index 665fcadd5f..0aa583c6f8 100644 --- a/plugins/impex/exr/exr_import.cc +++ b/plugins/impex/exr/exr_import.cc @@ -1,106 +1,106 @@ /* * Copyright (c) 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. */ #include "exr_import.h" #include #include #include #include #include #include #include "exr_converter.h" K_PLUGIN_FACTORY_WITH_JSON(ImportFactory, "krita_exr_import.json", registerPlugin();) exrImport::exrImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } exrImport::~exrImport() { } -KisImportExportFilter::ConversionStatus exrImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus exrImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Importing using EXRImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } exrConverter ib(doc, !getBatchMode()); switch (ib.buildImage(filename)) { case KisImageBuilder_RESULT_UNSUPPORTED: case KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE: doc->setErrorMessage(i18n("Krita does support this type of EXR file.")); return KisImportExportFilter::NotImplemented; case KisImageBuilder_RESULT_INVALID_ARG: doc->setErrorMessage(i18n("This is not an EXR file.")); return KisImportExportFilter::BadMimeType; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_LOCAL: doc->setErrorMessage(i18n("The EXR file does not exist.")); return KisImportExportFilter::FileNotFound; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: doc->setErrorMessage(i18n("The EXR is corrupted.")); return KisImportExportFilter::ParsingError; case KisImageBuilder_RESULT_FAILURE: doc->setErrorMessage(i18n("Krita could not create a new image.")); return KisImportExportFilter::InternalError; case KisImageBuilder_RESULT_OK: Q_ASSERT(ib.image()); doc -> setCurrentImage(ib.image()); return KisImportExportFilter::OK; default: break; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/exr/exr_import.h b/plugins/impex/exr/exr_import.h index 33edcdc606..646804c10b 100644 --- a/plugins/impex/exr/exr_import.h +++ b/plugins/impex/exr/exr_import.h @@ -1,37 +1,37 @@ /* * Copyright (c) 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 EXR_IMPORT_H_ #define EXR_IMPORT_H_ #include #include class exrImport : public KisImportExportFilter { Q_OBJECT public: exrImport(QObject *parent, const QVariantList &); virtual ~exrImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/heightmap/kis_heightmap_export.cpp b/plugins/impex/heightmap/kis_heightmap_export.cpp index eeeb4baf60..f55e15ec7f 100644 --- a/plugins/impex/heightmap/kis_heightmap_export.cpp +++ b/plugins/impex/heightmap/kis_heightmap_export.cpp @@ -1,168 +1,193 @@ /* * Copyright (c) 2014 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; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_heightmap_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include - -#include "ui_kis_wdg_options_heightmap.h" +#include K_PLUGIN_FACTORY_WITH_JSON(KisHeightMapExportFactory, "krita_heightmap_export.json", registerPlugin();) KisHeightMapExport::KisHeightMapExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisHeightMapExport::~KisHeightMapExport() { } -KisImportExportFilter::ConversionStatus KisHeightMapExport::convert(const QByteArray& from, const QByteArray& to) +KisPropertiesConfigurationSP KisHeightMapExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("endianness", 0); + return cfg; +} + +KisPropertiesConfigurationSP KisHeightMapExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + QString filterConfig = KisConfig().exportConfiguration("HeightMap"); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisHeightMapExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + return new KisWdgOptionsHeightmap(parent); +} + +KisImportExportFilter::ConversionStatus KisHeightMapExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "HeightMap export! From:" << from << ", To:" << to; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *inputDoc = inputDocument(); QString filename = outputFile(); if (!inputDoc) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; KisImageWSP image = inputDoc->image(); Q_CHECK_PTR(image); if (inputDoc->image()->width() != inputDoc->image()->height()) { inputDoc->setErrorMessage(i18n("Cannot export this image to a heightmap: it is not square")); return KisImportExportFilter::WrongFormat; } if (inputDoc->image()->colorSpace()->colorModelId() != GrayAColorModelID) { inputDoc->setErrorMessage(i18n("Cannot export this image to a heightmap: it is not grayscale")); return KisImportExportFilter::WrongFormat; } - KoDialog* kdb = new KoDialog(0); - kdb->setWindowTitle(i18n("HeightMap Export Options")); - kdb->setButtons(KoDialog::Ok | KoDialog::Cancel); - - Ui::WdgOptionsHeightMap optionsHeightMap; + KoDialog kdb; + kdb.setWindowTitle(i18n("HeightMap Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisConfigWidget *wdg = createConfigurationWidget(&kdb, from, to); + kdb.setMainWidget(wdg); - QWidget* wdg = new QWidget(kdb); - optionsHeightMap.setupUi(wdg); - - kdb->setMainWidget(wdg); QApplication::restoreOverrideCursor(); - QString filterConfig = KisConfig().exportConfiguration("HeightMap"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - optionsHeightMap.intSize->setValue(image->width()); - - int endianness = cfg.getInt("endianness", 0); - QDataStream::ByteOrder bo = QDataStream::LittleEndian; - optionsHeightMap.radioPC->setChecked(true); - - if (endianness == 0) { - bo = QDataStream::BigEndian; - optionsHeightMap.radioMac->setChecked(true); + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + if (configuration) { + cfg->fromXML(configuration->toXML()); + } + else { + cfg = lastSavedConfiguration(from, to); } + cfg->setProperty("width", image->width()); + wdg->setConfiguration(cfg); if (!getBatchMode()) { - if (kdb->exec() == QDialog::Rejected) { + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("HeightMap", *cfg.data()); } - if (optionsHeightMap.radioMac->isChecked()) { - cfg.setProperty("endianness", 0); - bo = QDataStream::BigEndian; - } - else { - cfg.setProperty("endianness", 1); - bo = QDataStream::LittleEndian; - } - KisConfig().setExportConfiguration("HeightMap", cfg); + QDataStream::ByteOrder bo = cfg->getInt("endianness", 0) ? QDataStream::BigEndian : QDataStream::LittleEndian; bool downscale = false; if (to == "image/x-r8" && image->colorSpace()->colorDepthId() == Integer16BitsColorDepthID) { downscale = (QMessageBox::question(0, i18nc("@title:window", "Downscale Image"), i18n("You specified the .r8 extension for a 16 bit/channel image. Do you want to save as 8 bit? Your image data will not be changed."), QMessageBox::Yes | QMessageBox::No) - == QMessageBox::Yes); + == QMessageBox::Yes); } // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(image->locked()); KisPaintDeviceSP pd = new KisPaintDevice(*image->projection()); QFile f(filename); f.open(QIODevice::WriteOnly); QDataStream s(&f); s.setByteOrder(bo); KisRandomConstAccessorSP it = pd->createRandomConstAccessorNG(0, 0); bool r16 = ((image->colorSpace()->colorDepthId() == Integer16BitsColorDepthID) && !downscale); for (int i = 0; i < image->height(); ++i) { for (int j = 0; j < image->width(); ++j) { it->moveTo(i, j); if (r16) { s << KoGrayU16Traits::gray(const_cast(it->rawDataConst())); } else { s << KoGrayU8Traits::gray(const_cast(it->rawDataConst())); } } } f.close(); return KisImportExportFilter::OK; } + +void KisWdgOptionsHeightmap::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + intSize->setValue(cfg->getInt("width")); + int endianness = cfg->getInt("endianness", 0); + radioMac->setChecked(endianness == 0); +} + +KisPropertiesConfigurationSP KisWdgOptionsHeightmap::configuration() const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + if (radioMac->isChecked()) { + cfg->setProperty("endianness", 0); + } + else { + cfg->setProperty("endianness", 1); + } + return cfg; +} + #include "kis_heightmap_export.moc" diff --git a/plugins/impex/heightmap/kis_heightmap_export.h b/plugins/impex/heightmap/kis_heightmap_export.h index de2e5a03c9..97bd128722 100644 --- a/plugins/impex/heightmap/kis_heightmap_export.h +++ b/plugins/impex/heightmap/kis_heightmap_export.h @@ -1,36 +1,57 @@ /* * Copyright (c) 2014 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; 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_HeightMap_EXPORT_H_ #define _KIS_HeightMap_EXPORT_H_ #include #include +#include +#include "ui_kis_wdg_options_heightmap.h" + +class KisWdgOptionsHeightmap : public KisConfigWidget, public Ui::WdgOptionsHeightMap +{ + Q_OBJECT + +public: + KisWdgOptionsHeightmap(QWidget *parent) + : KisConfigWidget(parent) + { + setupUi(this); + } + + void setConfiguration(const KisPropertiesConfigurationSP cfg); + KisPropertiesConfigurationSP configuration() const; +}; + class KisHeightMapExport : public KisImportExportFilter { Q_OBJECT public: KisHeightMapExport(QObject *parent, const QVariantList &); virtual ~KisHeightMapExport(); + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/heightmap/kis_heightmap_import.cpp b/plugins/impex/heightmap/kis_heightmap_import.cpp index b4b30020ca..a1ba03f4c1 100644 --- a/plugins/impex/heightmap/kis_heightmap_import.cpp +++ b/plugins/impex/heightmap/kis_heightmap_import.cpp @@ -1,198 +1,198 @@ /* * Copyright (c) 2014 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_heightmap_import.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 "ui_kis_wdg_options_heightmap.h" K_PLUGIN_FACTORY_WITH_JSON(HeightMapImportFactory, "krita_heightmap_import.json", registerPlugin();) KisHeightMapImport::KisHeightMapImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisHeightMapImport::~KisHeightMapImport() { } -KisImportExportFilter::ConversionStatus KisHeightMapImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisHeightMapImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { KisDocument * doc = outputDocument(); if (!doc) { return KisImportExportFilter::NoDocumentCreated; } KoID depthId; if (from == "image/x-r8") { depthId = Integer8BitsColorDepthID; } else if (from == "image/x-r16") { depthId = Integer16BitsColorDepthID; } else { doc->setErrorMessage(i18n("The file is not 8 or 16 bits raw")); return KisImportExportFilter::WrongFormat; } dbgFile << "Importing using HeightMapImport!"; if (to != "application/x-krita") { return KisImportExportFilter::BadMimeType; } QString filename = inputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } QFileInfo fi(filename); if (!fi.exists()) { return KisImportExportFilter::FileNotFound; } QApplication::restoreOverrideCursor(); KoDialog* kdb = new KoDialog(0); kdb->setWindowTitle(i18n("R16 HeightMap Import Options")); kdb->setButtons(KoDialog::Ok | KoDialog::Cancel); Ui::WdgOptionsHeightMap optionsHeightMap; QWidget* wdg = new QWidget(kdb); optionsHeightMap.setupUi(wdg); kdb->setMainWidget(wdg); QString filterConfig = KisConfig().exportConfiguration("HeightMap"); KisPropertiesConfiguration cfg; cfg.fromXML(filterConfig); QFile f(filename); int w = 0; int h = 0; if (!f.exists()) { doc->setErrorMessage(i18n("File does not exist.")); return KisImportExportFilter::CreationError; } if (!f.isOpen()) { f.open(QFile::ReadOnly); } optionsHeightMap.intSize->setValue(0); int endianness = cfg.getInt("endianness", 0); if (endianness == 0) { optionsHeightMap.radioMac->setChecked(true); } else { optionsHeightMap.radioPC->setChecked(true); } if (!getBatchMode()) { if (kdb->exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } } w = h = optionsHeightMap.intSize->value(); if ((w * h * (from == "image/x-r16" ? 2 : 1)) != f.size()) { doc->setErrorMessage(i18n("Source file is not the right size for the specified width and height.")); return KisImportExportFilter::WrongFormat; } QDataStream::ByteOrder bo = QDataStream::LittleEndian; cfg.setProperty("endianness", 1); if (optionsHeightMap.radioMac->isChecked()) { bo = QDataStream::BigEndian; cfg.setProperty("endianness", 0); } KisConfig().setExportConfiguration("HeightMap", cfg); doc->prepareForImport(); QDataStream s(&f); s.setByteOrder(bo); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), depthId.id(), 0); KisImageSP image = new KisImage(doc->createUndoStore(), w, h, colorSpace, "imported heightmap"); KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255); KisRandomAccessorSP it = layer->paintDevice()->createRandomAccessorNG(0, 0); bool r16 = (depthId == Integer16BitsColorDepthID); for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { it->moveTo(i, j); if (r16) { quint16 pixel; s >> pixel; KoGrayU16Traits::setGray(it->rawData(), pixel); KoGrayU16Traits::setOpacity(it->rawData(), OPACITY_OPAQUE_F, 1); } else { quint8 pixel; s >> pixel; KoGrayU8Traits::setGray(it->rawData(), pixel); KoGrayU8Traits::setOpacity(it->rawData(), OPACITY_OPAQUE_F, 1); } } } image->addNode(layer.data(), image->rootLayer().data()); doc->setCurrentImage(image); return KisImportExportFilter::OK; } #include "kis_heightmap_import.moc" diff --git a/plugins/impex/heightmap/kis_heightmap_import.h b/plugins/impex/heightmap/kis_heightmap_import.h index 0a6e9f5704..9770f6b1d2 100644 --- a/plugins/impex/heightmap/kis_heightmap_import.h +++ b/plugins/impex/heightmap/kis_heightmap_import.h @@ -1,38 +1,38 @@ /* * Copyright (c) 2014 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 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_HeightMap_IMPORT_H_ #define _KIS_HeightMap_IMPORT_H_ #include #include class KisHeightMapImport : public KisImportExportFilter { Q_OBJECT public: KisHeightMapImport(QObject *parent, const QVariantList &); virtual ~KisHeightMapImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/jpeg/kis_jpeg_export.cc b/plugins/impex/jpeg/kis_jpeg_export.cc index c252383de6..c34b14dd46 100644 --- a/plugins/impex/jpeg/kis_jpeg_export.cc +++ b/plugins/impex/jpeg/kis_jpeg_export.cc @@ -1,230 +1,264 @@ /* * Copyright (c) 2005 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. */ #include "kis_jpeg_export.h" #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include -#include "kis_slider_spin_box.h" +#include +#include #include #include #include #include #include #include #include #include #include #include #include #include "kis_jpeg_converter.h" #include -#include "ui_kis_wdg_options_jpeg.h" class KisExternalLayer; K_PLUGIN_FACTORY_WITH_JSON(KisJPEGExportFactory, "krita_jpeg_export.json", registerPlugin();) KisJPEGExport::KisJPEGExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisJPEGExport::~KisJPEGExport() { } -KisImportExportFilter::ConversionStatus KisJPEGExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisJPEGExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "JPEG export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); if (!input) return KisImportExportFilter::NoDocumentCreated; KisImageWSP image = input->image(); Q_CHECK_PTR(image); - KoDialog* kdb = new KoDialog(0); - kdb->setWindowTitle(i18n("JPEG Export Options")); - kdb->setButtons(KoDialog::Ok | KoDialog::Cancel); - - Ui::WdgOptionsJPEG wdgUi; - QWidget* wdg = new QWidget(kdb); - wdgUi.setupUi(wdg); - KisMetaData::FilterRegistryModel frm; - wdgUi.metaDataFilters->setModel(&frm); - - QString filterConfig = KisConfig().exportConfiguration("JPEG"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - wdgUi.progressive->setChecked(cfg.getBool("progressive", false)); - - wdgUi.qualityLevel->setValue(cfg.getInt("quality", 80)); - wdgUi.qualityLevel->setRange(0, 100, 0); - wdgUi.qualityLevel->setSuffix("%"); - - wdgUi.optimize->setChecked(cfg.getBool("optimize", true)); - - wdgUi.smoothLevel->setValue(cfg.getInt("smoothing", 0)); - wdgUi.smoothLevel->setRange(0, 100, 0); - wdgUi.smoothLevel->setSuffix("%"); - - - wdgUi.baseLineJPEG->setChecked(cfg.getBool("baseline", true)); - wdgUi.subsampling->setCurrentIndex(cfg.getInt("subsampling", 0)); - wdgUi.exif->setChecked(cfg.getBool("exif", true)); - wdgUi.iptc->setChecked(cfg.getBool("iptc", true)); - wdgUi.xmp->setChecked(cfg.getBool("xmp", true)); + KoDialog kdb; + kdb.setWindowTitle(i18n("JPEG Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisConfigWidget *wdg = createConfigurationWidget(&kdb, from, to); + kdb.setMainWidget(wdg); + kdb.resize(kdb.minimumSize()); + + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + if (configuration) { + cfg->fromXML(configuration->toXML()); + } + else { + cfg = lastSavedConfiguration(from, to); + } + // An extra option to pass to the config widget to set the state correctly, this isn't saved const KoColorSpace* cs = image->projection()->colorSpace(); bool sRGB = cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive); - wdgUi.chkForceSRGB->setVisible(!sRGB); - wdgUi.chkForceSRGB->setChecked(cfg.getBool("forceSRGB", false)); + cfg->setProperty("is_sRGB", sRGB); - wdgUi.chkSaveProfile->setChecked(cfg.getBool("saveProfile", true)); - - QStringList rgb = cfg.getString("transparencyFillcolor", "255,255,255").split(','); - KoColor background(KoColorSpaceRegistry::instance()->rgb8()); - background.fromQColor(Qt::white); - wdgUi.bnTransparencyFillColor->setDefaultColor(background); - background.fromQColor(QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt())); - wdgUi.bnTransparencyFillColor->setColor(background); + wdg->setConfiguration(cfg); - frm.setEnabledFilters(cfg.getString("filters").split(',')); - kdb->setMainWidget(wdg); QApplication::restoreOverrideCursor(); if (!getBatchMode()) { - if (kdb->exec() == QDialog::Rejected) { - delete kdb; + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } - } - - KisJPEGOptions options; - options.progressive = wdgUi.progressive->isChecked(); - cfg.setProperty("progressive", options.progressive); - - options.quality = (int)wdgUi.qualityLevel->value(); - cfg.setProperty("quality", options.quality); - - options.forceSRGB = wdgUi.chkForceSRGB->isChecked(); - cfg.setProperty("forceSRGB", options.forceSRGB); - - options.saveProfile = wdgUi.chkSaveProfile->isChecked(); - cfg.setProperty("saveProfile", options.saveProfile); - - // Advanced - options.optimize = wdgUi.optimize->isChecked(); - cfg.setProperty("optimize", options.optimize); - - options.smooth = (int)wdgUi.smoothLevel->value(); - cfg.setProperty("smoothing", options.smooth); + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("JPEG", *cfg.data()); - options.baseLineJPEG = wdgUi.baseLineJPEG->isChecked(); - cfg.setProperty("baseline", options.baseLineJPEG); - - options.subsampling = wdgUi.subsampling->currentIndex(); - cfg.setProperty("subsampling", options.subsampling); - // Jpeg - options.exif = wdgUi.exif->isChecked(); - cfg.setProperty("exif", options.exif); - - options.iptc = wdgUi.iptc->isChecked(); - cfg.setProperty("iptc", options.iptc); - - options.xmp = wdgUi.xmp->isChecked(); - cfg.setProperty("xmp", options.xmp); - - QColor c = wdgUi.bnTransparencyFillColor->color().toQColor(); - options.transparencyFillColor = c; - cfg.setProperty("transparencyFillcolor", QString("%1,%2,%3").arg(c.red()).arg(c.green()).arg(c.blue())); - - options.filters = frm.enabledFilters(); - QString enabledFilters; - Q_FOREACH (const KisMetaData::Filter* filter, options.filters) { - enabledFilters = enabledFilters + filter->id() + ','; } - cfg.setProperty("filters", enabledFilters); - - KisConfig().setExportConfiguration("JPEG", cfg); - - delete kdb; - // XXX: Add dialog about flattening layers here + KisJPEGOptions options; + options.progressive = cfg->getBool("progressive", false); + options.quality = cfg->getInt("quality", 80); + options.forceSRGB = cfg->getBool("forceSRGB", false); + options.saveProfile = cfg->getBool("saveProfile", true); + options.optimize = cfg->getBool("optimize", true); + options.smooth = cfg->getInt("smoothing", 0); + options.baseLineJPEG = cfg->getBool("baseline", true); + options.subsampling = cfg->getInt("subsampling", 0); + options.exif = cfg->getBool("exif", true); + options.iptc = cfg->getBool("iptc", true); + options.xmp = cfg->getBool("xmp", true); + options.transparencyFillColor = cfg->getColor("transparencyFillcolor").toQColor(); + KisMetaData::FilterRegistryModel m; + m.setEnabledFilters(cfg->getString("filters").split(",")); + options.filters = m.enabledFilters(); QString filename = outputFile(); if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); KisPaintDeviceSP pd = new KisPaintDevice(*image->projection()); KisJPEGConverter kpc(input, getBatchMode()); KisPaintLayerSP l = new KisPaintLayer(image, "projection", OPACITY_OPAQUE_U8, pd); vKisAnnotationSP_it beginIt = image->beginAnnotations(); vKisAnnotationSP_it endIt = image->endAnnotations(); KisImageBuilder_Result res; KisExifInfoVisitor eIV; eIV.visit(image->rootLayer().data()); KisMetaData::Store* eI = 0; if (eIV.countPaintLayer() == 1) eI = eIV.exifInfo(); if (eI) { KisMetaData::Store* copy = new KisMetaData::Store(*eI); eI = copy; } if ((res = kpc.buildFile(filename, l, beginIt, endIt, options, eI)) == KisImageBuilder_RESULT_OK) { dbgFile << "success !"; delete eI; return KisImportExportFilter::OK; } delete eI; dbgFile << " Result =" << res; return KisImportExportFilter::InternalError; } -#include +KisPropertiesConfigurationSP KisJPEGExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("progressive", false); + cfg->setProperty("quality", 80); + cfg->setProperty("forceSRGB", false); + cfg->setProperty("saveProfile", true); + cfg->setProperty("optimize", true); + cfg->setProperty("smoothing", 0); + cfg->setProperty("baseline", true); + cfg->setProperty("subsampling", 0); + cfg->setProperty("exif", true); + cfg->setProperty("iptc", true); + cfg->setProperty("xmp", true); + cfg->setProperty("transparencyFillcolor", QString("255,255,255")); + cfg->setProperty("filters", ""); + + return cfg; +} + +KisPropertiesConfigurationSP KisJPEGExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + QString filterConfig = KisConfig().exportConfiguration("JPEG"); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisJPEGExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + return new KisWdgOptionsJPEG(parent); +} + +KisWdgOptionsJPEG::KisWdgOptionsJPEG(QWidget *parent) + : KisConfigWidget(parent) +{ + setupUi(this); + + metaDataFilters->setModel(&m_filterRegistryModel); + qualityLevel->setRange(0, 100, 0); + qualityLevel->setSuffix("%"); + smoothLevel->setRange(0, 100, 0); + smoothLevel->setSuffix("%"); +} + +void KisWdgOptionsJPEG::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + progressive->setChecked(cfg->getBool("progressive", false)); + qualityLevel->setValue(cfg->getInt("quality", 80)); + optimize->setChecked(cfg->getBool("optimize", true)); + smoothLevel->setValue(cfg->getInt("smoothing", 0)); + baseLineJPEG->setChecked(cfg->getBool("baseline", true)); + subsampling->setCurrentIndex(cfg->getInt("subsampling", 0)); + exif->setChecked(cfg->getBool("exif", true)); + iptc->setChecked(cfg->getBool("iptc", true)); + xmp->setChecked(cfg->getBool("xmp", true)); + chkForceSRGB->setVisible(cfg->getBool("is_sRGB")); + chkForceSRGB->setChecked(cfg->getBool("forceSRGB", false)); + chkSaveProfile->setChecked(cfg->getBool("saveProfile", true)); + QStringList rgb = cfg->getString("transparencyFillcolor", "255,255,255").split(','); + KoColor background(KoColorSpaceRegistry::instance()->rgb8()); + background.fromQColor(Qt::white); + bnTransparencyFillColor->setDefaultColor(background); + background.fromQColor(QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt())); + bnTransparencyFillColor->setColor(background); + + m_filterRegistryModel.setEnabledFilters(cfg->getString("filters").split(',')); + +} + +KisPropertiesConfigurationSP KisWdgOptionsJPEG::configuration() const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("progressive", progressive->isChecked()); + cfg->setProperty("quality", (int)qualityLevel->value()); + cfg->setProperty("forceSRGB", chkForceSRGB->isChecked()); + cfg->setProperty("saveProfile", chkSaveProfile->isChecked()); + cfg->setProperty("optimize", optimize->isChecked()); + cfg->setProperty("smoothing", (int)smoothLevel->value()); + cfg->setProperty("baseline", baseLineJPEG->isChecked()); + cfg->setProperty("subsampling", subsampling->currentIndex()); + cfg->setProperty("exif", exif->isChecked()); + cfg->setProperty("iptc", iptc->isChecked()); + cfg->setProperty("xmp", xmp->isChecked()); + QColor c = bnTransparencyFillColor->color().toQColor(); + cfg->setProperty("transparencyFillcolor", QString("%1,%2,%3").arg(c.red()).arg(c.green()).arg(c.blue())); + QString enabledFilters; + Q_FOREACH (const KisMetaData::Filter* filter, m_filterRegistryModel.enabledFilters()) { + enabledFilters = enabledFilters + filter->id() + ','; + } + cfg->setProperty("filters", enabledFilters); + + return cfg; +} +#include diff --git a/plugins/impex/jpeg/kis_jpeg_export.h b/plugins/impex/jpeg/kis_jpeg_export.h index a38830cc83..89148feed3 100644 --- a/plugins/impex/jpeg/kis_jpeg_export.h +++ b/plugins/impex/jpeg/kis_jpeg_export.h @@ -1,37 +1,58 @@ /* * Copyright (c) 2005 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_JPEG_EXPORT_H_ #define _KIS_JPEG_EXPORT_H_ #include #include +#include +#include "ui_kis_wdg_options_jpeg.h" +#include +#include + + +class KisWdgOptionsJPEG : public KisConfigWidget, public Ui::WdgOptionsJPEG +{ + Q_OBJECT + +public: + KisWdgOptionsJPEG(QWidget *parent); + void setConfiguration(const KisPropertiesConfigurationSP cfg); + KisPropertiesConfigurationSP configuration() const; +private: + KisMetaData::FilterRegistryModel m_filterRegistryModel; +}; + class KisJPEGExport : public KisImportExportFilter { Q_OBJECT public: KisJPEGExport(QObject *parent, const QVariantList &); virtual ~KisJPEGExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; }; #endif diff --git a/plugins/impex/jpeg/kis_jpeg_import.cc b/plugins/impex/jpeg/kis_jpeg_import.cc index 457b663f81..bada591e38 100644 --- a/plugins/impex/jpeg/kis_jpeg_import.cc +++ b/plugins/impex/jpeg/kis_jpeg_import.cc @@ -1,103 +1,103 @@ /* * Copyright (c) 2005 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. */ #include "kis_jpeg_import.h" #include #include #include #include #include #include #include #include "kis_jpeg_converter.h" K_PLUGIN_FACTORY_WITH_JSON(JPEGImportFactory, "krita_jpeg_import.json", registerPlugin();) KisJPEGImport::KisJPEGImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisJPEGImport::~KisJPEGImport() { } -KisImportExportFilter::ConversionStatus KisJPEGImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisJPEGImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP /*configuration*/) { dbgFile << "Importing using JPEGImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } KisJPEGConverter ib(doc, getBatchMode()); // if (view != 0) // view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); switch (ib.buildImage(filename)) { case KisImageBuilder_RESULT_UNSUPPORTED: case KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE: return KisImportExportFilter::NotImplemented; break; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; break; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_LOCAL: return KisImportExportFilter::FileNotFound; break; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; break; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; break; case KisImageBuilder_RESULT_OK: doc->setCurrentImage(ib.image()); return KisImportExportFilter::OK; default: break; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/jpeg/kis_jpeg_import.h b/plugins/impex/jpeg/kis_jpeg_import.h index 6ada5b6f9c..72a800e329 100644 --- a/plugins/impex/jpeg/kis_jpeg_import.h +++ b/plugins/impex/jpeg/kis_jpeg_import.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2005 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_JPEG_IMPORT_H_ #define _KIS_JPEG_IMPORT_H_ #include #include class KisJPEGImport : public KisImportExportFilter { Q_OBJECT public: KisJPEGImport(QObject *parent, const QVariantList &); virtual ~KisJPEGImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/odg/kis_odg_import.cc b/plugins/impex/odg/kis_odg_import.cc index 8bf405c739..218ef05ae5 100644 --- a/plugins/impex/odg/kis_odg_import.cc +++ b/plugins/impex/odg/kis_odg_import.cc @@ -1,160 +1,160 @@ /* * Copyright (c) 2006-2008 Boudewijn Rempt * Copyright (c) 2007 Thomas Zander * Copyright (c) 2009 Cyrille Berger * Copyright (c) 2010 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_odg_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(ODGImportFactory, "krita_odg_import.json", registerPlugin();) KisODGImport::KisODGImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisODGImport::~KisODGImport() { } -KisImportExportFilter::ConversionStatus KisODGImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisODGImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Import odg"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); KoStore* store = KoStore::createStore(filename, KoStore::Read, from, KoStore::Zip); if (!store || store->bad()) { delete store; return KisImportExportFilter::BadConversionGraph; } - + doc -> prepareForImport(); KoOdfReadStore odfStore(store); QString errorMessage; odfStore.loadAndParse(errorMessage); if (!errorMessage.isEmpty()) { warnKrita << errorMessage; return KisImportExportFilter::CreationError; } KoXmlElement contents = odfStore.contentDoc().documentElement(); KoXmlElement body(KoXml::namedItemNS(contents, KoXmlNS::office, "body")); if (body.isNull()) { //setErrorMessage( i18n( "Invalid OASIS document. No office:body tag found." ) ); return KisImportExportFilter::CreationError; } body = KoXml::namedItemNS(body, KoXmlNS::office, "drawing"); if (body.isNull()) { //setErrorMessage( i18n( "Invalid OASIS document. No office:drawing tag found." ) ); return KisImportExportFilter::CreationError; } KoXmlElement page(KoXml::namedItemNS(body, KoXmlNS::draw, "page")); if (page.isNull()) { //setErrorMessage( i18n( "Invalid OASIS document. No draw:page tag found." ) ); return KisImportExportFilter::CreationError; } KoXmlElement * master = 0; if (odfStore.styles().masterPages().contains("Standard")) master = odfStore.styles().masterPages().value("Standard"); else if (odfStore.styles().masterPages().contains("Default")) master = odfStore.styles().masterPages().value("Default"); else if (! odfStore.styles().masterPages().empty()) master = odfStore.styles().masterPages().begin().value(); qint32 width = 1000; qint32 height = 1000; if (master) { const KoXmlElement *style = odfStore.styles().findStyle( master->attributeNS(KoXmlNS::style, "page-layout-name", QString())); if (style) { KoPageLayout pageLayout; pageLayout.loadOdf(*style); width = pageLayout.width; height = pageLayout.height; } } // We work fine without a master page KoOdfLoadingContext context(odfStore.styles(), odfStore.store()); context.setManifestFile(QString("tar:/") + odfStore.store()->currentPath() + "META-INF/manifest.xml"); KoShapeLoadingContext shapeContext(context, doc->shapeController()->resourceManager()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageWSP image = new KisImage(doc->createUndoStore(), width, height, cs, "built image"); doc->setCurrentImage(image); KoXmlElement layerElement; forEachElement(layerElement, KoXml::namedItemNS(page, KoXmlNS::draw, "layer-set")) { KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image, i18n("Vector Layer"), OPACITY_OPAQUE_U8); if (!shapeLayer->loadOdf(layerElement, shapeContext)) { dbgKrita << "Could not load vector layer!"; return KisImportExportFilter::CreationError; } image->addNode(shapeLayer, image->rootLayer(), 0); } KoXmlElement child; forEachElement(child, page) { /*KoShape * shape = */KoShapeRegistry::instance()->createShapeFromOdf(child, shapeContext); } return KisImportExportFilter::OK; } #include "kis_odg_import.moc" diff --git a/plugins/impex/odg/kis_odg_import.h b/plugins/impex/odg/kis_odg_import.h index 42dc98ae92..6d7a523a33 100644 --- a/plugins/impex/odg/kis_odg_import.h +++ b/plugins/impex/odg/kis_odg_import.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2010 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_ODG_IMPORT_H_ #define _KIS_ODG_IMPORT_H_ #include #include class KisODGImport : public KisImportExportFilter { Q_OBJECT public: KisODGImport(QObject *parent, const QVariantList &); virtual ~KisODGImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/ora/ora_export.cc b/plugins/impex/ora/ora_export.cc index 458a98d96f..4a0d955b8f 100644 --- a/plugins/impex/ora/ora_export.cc +++ b/plugins/impex/ora/ora_export.cc @@ -1,127 +1,127 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ora_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ora_converter.h" class KisExternalLayer; K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_ora_export.json", registerPlugin();) OraExport::OraExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } OraExport::~OraExport() { } bool hasShapeLayerChild(KisNodeSP node) { if (!node) return false; Q_FOREACH (KisNodeSP child, node->childNodes(QStringList(), KoProperties())) { if (child->inherits("KisShapeLayer") || child->inherits("KisGeneratorLayer") || child->inherits("KisCloneLayer")) { return true; } else { if (hasShapeLayerChild(child)) { return true; } } } return false; } -KisImportExportFilter::ConversionStatus OraExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus OraExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "ORA export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) { return KisImportExportFilter::NoDocumentCreated; } if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; KisImageWSP image = input->image(); Q_CHECK_PTR(image); KisPaintDeviceSP pd = image->projection(); QStringList supportedColorModelIds; supportedColorModelIds << RGBAColorModelID.id() << GrayAColorModelID.id() << GrayColorModelID.id(); QStringList supportedColorDepthIds; supportedColorDepthIds << Integer8BitsColorDepthID.id() << Integer16BitsColorDepthID.id(); if (!supportedColorModelIds.contains(pd->colorSpace()->colorModelId().id()) || !supportedColorDepthIds.contains(pd->colorSpace()->colorDepthId().id())) { if (!getBatchMode()) { QMessageBox::critical(0, i18nc("@title:window", "Krita OpenRaster Export"), i18n("Cannot export images in this colorspace or channel depth to OpenRaster")); } return KisImportExportFilter::UsageError; } if (hasShapeLayerChild(image->root()) && !getBatchMode()) { QMessageBox::information(0, i18nc("@title:window", "Krita:Warning"), i18n("This image contains vector, clone or fill layers.\nThese layers will be saved as raster layers.")); } OraConverter kpc(input); KisImageBuilder_Result res; if ((res = kpc.buildFile(filename, image, input->activeNodes())) == KisImageBuilder_RESULT_OK) { dbgFile << "success !"; return KisImportExportFilter::OK; } dbgFile << " Result =" << res; return KisImportExportFilter::InternalError; } #include diff --git a/plugins/impex/ora/ora_export.h b/plugins/impex/ora/ora_export.h index d2218ab57a..e34b28409a 100644 --- a/plugins/impex/ora/ora_export.h +++ b/plugins/impex/ora/ora_export.h @@ -1,35 +1,35 @@ /* * Copyright (c) 2007 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 _ORA_EXPORT_H_ #define _ORA_EXPORT_H_ #include #include class OraExport : public KisImportExportFilter { Q_OBJECT public: OraExport(QObject *parent, const QVariantList &); virtual ~OraExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/ora/ora_import.cc b/plugins/impex/ora/ora_import.cc index 18bfc5b4e1..15c2261dac 100644 --- a/plugins/impex/ora/ora_import.cc +++ b/plugins/impex/ora/ora_import.cc @@ -1,98 +1,98 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ora_import.h" #include #include #include #include #include #include "ora_converter.h" K_PLUGIN_FACTORY_WITH_JSON(ImportFactory, "krita_ora_import.json", registerPlugin();) OraImport::OraImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } OraImport::~OraImport() { } -KisImportExportFilter::ConversionStatus OraImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus OraImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Importing using ORAImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } OraConverter ib(doc); switch (ib.buildImage(filename)) { case KisImageBuilder_RESULT_UNSUPPORTED: return KisImportExportFilter::NotImplemented; break; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; break; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_LOCAL: return KisImportExportFilter::FileNotFound; break; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; break; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; break; case KisImageBuilder_RESULT_OK: doc->setCurrentImage(ib.image()); if (ib.activeNodes().size() > 0) { doc->setPreActivatedNode(ib.activeNodes()[0]); } return KisImportExportFilter::OK; default: break; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/ora/ora_import.h b/plugins/impex/ora/ora_import.h index 8a468410cc..59593126f3 100644 --- a/plugins/impex/ora/ora_import.h +++ b/plugins/impex/ora/ora_import.h @@ -1,35 +1,35 @@ /* * Copyright (c) 2007 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 ORA_IMPORT_H_ #define ORA_IMPORT_H_ #include #include class OraImport : public KisImportExportFilter { Q_OBJECT public: OraImport(QObject *parent, const QVariantList &); virtual ~OraImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/pdf/kis_pdf_import.cpp b/plugins/impex/pdf/kis_pdf_import.cpp index 63234dedce..38cceb835a 100644 --- a/plugins/impex/pdf/kis_pdf_import.cpp +++ b/plugins/impex/pdf/kis_pdf_import.cpp @@ -1,162 +1,163 @@ /* * Copyright (c) 2006 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. */ #include "kis_pdf_import.h" // poppler's headers #include // Qt's headers #include #include #include #include #include // KDE's headers #include #include #include #include #include #include // calligra's headers #include #include #include #include #include // krita's headers #include #include #include #include #include // plugins's headers #include "kis_pdf_import_widget.h" K_PLUGIN_FACTORY_WITH_JSON(PDFImportFactory, "krita_pdf_import.json", registerPlugin();) -KisPDFImport::KisPDFImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) +KisPDFImport::KisPDFImport(QObject *parent, const QVariantList &) + : KisImportExportFilter(parent) { } KisPDFImport::~KisPDFImport() { } -KisPDFImport::ConversionStatus KisPDFImport::convert(const QByteArray& , const QByteArray&) +KisPDFImport::ConversionStatus KisPDFImport::convert(const QByteArray& , const QByteArray&, KisPropertiesConfigurationSP configuration) { QString filename = inputFile(); dbgFile << "Importing using PDFImport!" << filename; if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } QFileInfo fi(filename); if (!fi.exists()) { return KisImportExportFilter::FileNotFound; } Poppler::Document* pdoc = Poppler::Document::load(filename); if (!pdoc) { return KisPDFImport::InvalidFormat; } pdoc->setRenderHint(Poppler::Document::Antialiasing, true); pdoc->setRenderHint(Poppler::Document::TextAntialiasing, true); if (!pdoc) { dbgFile << "Error when reading the PDF"; return KisImportExportFilter::StorageCreationError; } while (pdoc->isLocked()) { KPasswordDialog dlg(0); dlg.setPrompt(i18n("A password is required to read that pdf")); dlg.setWindowTitle(i18n("A password is required to read that pdf")); if (dlg.exec() != QDialog::Accepted) { dbgFile << "Password canceled"; return KisImportExportFilter::StorageCreationError; } else pdoc->unlock(dlg.password().toLocal8Bit(), dlg.password().toLocal8Bit()); } KoDialog* kdb = new KoDialog(0); kdb->setCaption(i18n("PDF Import Options")); kdb->setModal(false); KisPDFImportWidget* wdg = new KisPDFImportWidget(pdoc, kdb); kdb->setMainWidget(wdg); QApplication::restoreOverrideCursor(); if (kdb->exec() == QDialog::Rejected) { delete pdoc; delete kdb; return KisImportExportFilter::StorageCreationError; // FIXME Cancel doesn't exist :( } // Init kis's doc KisDocument * doc = outputDocument(); if (!doc) { delete pdoc; delete kdb; return KisImportExportFilter::NoDocumentCreated; } doc -> prepareForImport(); // Create the krita image const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); int width = wdg->intWidth->value(); int height = wdg->intHeight->value(); KisImageWSP image = new KisImage(doc->createUndoStore(), width, height, cs, "built image"); image->setResolution(wdg->intResolution->value() / 72.0, wdg->intResolution->value() / 72.0); // create a layer QList pages = wdg->pages(); QPointer loadUpdater = outputDocument()->progressUpdater()->startSubtask(1, "load"); loadUpdater->setRange(0, pages.count()); for (QList::const_iterator it = pages.constBegin(); it != pages.constEnd(); ++it) { KisPaintLayer* layer = new KisPaintLayer(image.data(), i18n("Page %1", *it + 1), quint8_MAX); Poppler::Page* page = pdoc->page(*it); QImage img = page->renderToImage(wdg->intResolution->value(), wdg->intResolution->value(), 0, 0, width, height); layer->paintDevice()->convertFromQImage(img, 0, 0, 0); delete page; image->addNode(layer, image->rootLayer(), 0); loadUpdater->setProgress(*it + 1); } doc->setCurrentImage(image); delete pdoc; delete kdb; return KisImportExportFilter::OK; } #include "kis_pdf_import.moc" diff --git a/plugins/impex/pdf/kis_pdf_import.h b/plugins/impex/pdf/kis_pdf_import.h index 660b431479..e1b86f2cb9 100644 --- a/plugins/impex/pdf/kis_pdf_import.h +++ b/plugins/impex/pdf/kis_pdf_import.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2006 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_PDF_IMPORT_H #define KIS_PDF_IMPORT_H #include #include class KisPDFImport : public KisImportExportFilter { Q_OBJECT public: KisPDFImport(QObject *parent, const QVariantList &); virtual ~KisPDFImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/png/kis_png_export.cc b/plugins/impex/png/kis_png_export.cc index 0f3aaf0ef2..1f02ad2fab 100644 --- a/plugins/impex/png/kis_png_export.cc +++ b/plugins/impex/png/kis_png_export.cc @@ -1,256 +1,293 @@ /* * Copyright (c) 2005 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. */ #include "kis_png_export.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_png_converter.h" #include K_PLUGIN_FACTORY_WITH_JSON(KisPNGExportFactory, "krita_png_export.json", registerPlugin();) KisPNGExport::KisPNGExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisPNGExport::~KisPNGExport() { } bool hasVisibleWidgets() { QWidgetList wl = QApplication::allWidgets(); Q_FOREACH (QWidget* w, wl) { if (w->isVisible() && strcmp(w->metaObject()->className(), "QDesktopWidget")) { dbgFile << "Widget " << w << " " << w->objectName() << " " << w->metaObject()->className() << " is visible"; return true; } } return false; } -KisImportExportFilter::ConversionStatus KisPNGExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisPNGExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Png export! From:" << from << ", To:" << to << ""; - KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; - KoDialog* kdb = new KoDialog(0); - kdb->setCaption(i18n("PNG Export Options")); - kdb->setModal(false); - kdb->setButtons(KoDialog::Ok | KoDialog::Cancel); KisImageWSP image = input->image(); // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(image->locked()); KisPaintDeviceSP pd; pd = new KisPaintDevice(*image->projection()); KisPaintLayerSP l = new KisPaintLayer(image, "projection", OPACITY_OPAQUE_U8, pd); if (!KisPNGConverter::isColorSpaceSupported(pd->colorSpace())) { if (!getBatchMode()) { QMessageBox::critical(0, i18nc("@title:window", "Krita PNG Export"), i18n("You can only save grayscale and RGB images to PNG. Convert your image before exporting to PNG.")); } return KisImportExportFilter::UsageError; } KisSequentialConstIterator it(l->paintDevice(), image->bounds()); const KoColorSpace* cs = l->paintDevice()->colorSpace(); KisPNGOptions options; bool isThereAlpha = false; + KisPropertiesConfigurationSP cfg = defaultConfiguration(); do { if (cs->opacityU8(it.oldRawData()) != OPACITY_OPAQUE_U8) { isThereAlpha = true; break; } } while (it.nextPixel()); if (!qApp->applicationName().toLower().contains("test")) { - bool sRGB = (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) - && !cs->profile()->name().contains(QLatin1String("g10"))); - - KisWdgOptionsPNG* wdg = new KisWdgOptionsPNG(kdb); + KoDialog kdb; + kdb.setCaption(i18n("PNG Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisConfigWidget *wdg = createConfigurationWidget(&kdb, from, to); + kdb.setMainWidget(wdg); - QString filterConfig = KisConfig().exportConfiguration("PNG"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - wdg->alpha->setChecked(cfg.getBool("alpha", isThereAlpha)); - - if (cs->colorModelId() == RGBAColorModelID) { - wdg->tryToSaveAsIndexed->setVisible(true); - if (wdg->alpha->isChecked()) { - wdg->tryToSaveAsIndexed->setChecked(false); - } - else { - wdg->tryToSaveAsIndexed->setChecked(cfg.getBool("indexed", false)); - } + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + if (configuration) { + cfg->fromXML(configuration->toXML()); } else { - wdg->tryToSaveAsIndexed->setVisible(false); + cfg = lastSavedConfiguration(from, to); } - wdg->interlacing->setChecked(cfg.getBool("interlaced", false)); - wdg->compressionLevel->setValue(cfg.getInt("compression", 9)); - wdg->compressionLevel->setRange(1, 9 , 0); - - wdg->alpha->setEnabled(isThereAlpha); - wdg->tryToSaveAsIndexed->setVisible(!isThereAlpha); - - wdg->bnTransparencyFillColor->setEnabled(!wdg->alpha->isChecked()); - - //This used to be 'cfg.getBool("saveSRGBProfile", true)' but firefox and ColorD are incredibly awkward about sRGB management - //on Linux devices, as indicated by the same distorted colours with using the sRGB chunk, meaning it's unrelated to the profile. - //We can somewhat assume sRGB is the default color space for the web, but it's still a darn pity we cannot rely on firefox and colord - //to manage sRGB-marked images properly. - wdg->chkSRGB->setEnabled(sRGB); - wdg->chkSRGB->setChecked(cfg.getBool("saveSRGBProfile", false)); - wdg->chkForceSRGB->setEnabled(!sRGB); - wdg->chkForceSRGB->setChecked(cfg.getBool("forceSRGB", false)); + cfg->setProperty("ColorModelID", cs->colorModelId().id()); - QStringList rgb = cfg.getString("transparencyFillcolor", "0,0,0").split(','); - KoColor background(KoColorSpaceRegistry::instance()->rgb8()); - background.fromQColor(Qt::white); - wdg->bnTransparencyFillColor->setDefaultColor(background); - background.fromQColor(QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt())); - wdg->bnTransparencyFillColor->setColor(background); + bool sRGB = (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) + && !cs->profile()->name().contains(QLatin1String("g10"))); + cfg->setProperty("sRGB", sRGB); + cfg->setProperty("isThereAlpha", isThereAlpha); + wdg->setConfiguration(cfg); - kdb->setMainWidget(wdg); QApplication::restoreOverrideCursor(); if (hasVisibleWidgets()) { if (!getBatchMode()) { - if (kdb->exec() == QDialog::Rejected) { + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("PNG", *cfg.data()); + } } - - bool alpha = wdg->alpha->isChecked(); - bool interlace = wdg->interlacing->isChecked(); - int compression = (int)wdg->compressionLevel->value(); - bool tryToSaveAsIndexed = wdg->tryToSaveAsIndexed->isChecked(); - QColor c = wdg->bnTransparencyFillColor->color().toQColor(); - bool saveSRGB = wdg->chkSRGB->isChecked(); - bool forceSRGB = wdg->chkForceSRGB->isChecked(); - - cfg.setProperty("alpha", alpha); - cfg.setProperty("indexed", tryToSaveAsIndexed); - cfg.setProperty("compression", compression); - cfg.setProperty("interlaced", interlace); - cfg.setProperty("transparencyFillcolor", QString("%1,%2,%3").arg(c.red()).arg(c.green()).arg(c.blue())); - cfg.setProperty("saveSRGBProfile", saveSRGB); - cfg.setProperty("forceSRGB", forceSRGB); - KisConfig().setExportConfiguration("PNG", cfg); - - options.alpha = alpha; - options.interlace = interlace; - options.compression = compression; - options.tryToSaveAsIndexed = tryToSaveAsIndexed; - options.transparencyFillColor = c; - options.saveSRGBProfile = saveSRGB; - options.forceSRGB = forceSRGB; - - } - else { - options.alpha = true; - options.interlace = false; - options.compression = 9; - options.tryToSaveAsIndexed = false; - options.transparencyFillColor = QColor(0,0,0); - options.saveSRGBProfile = false; - options.forceSRGB = false; - } - delete kdb; + options.alpha = cfg->getBool("alpha", true); + options.interlace = cfg->getBool("interlaced", false); + options.compression = cfg->getInt("compression", 0); + options.tryToSaveAsIndexed = cfg->getBool("indexed", false); + options.transparencyFillColor = cfg->getColor("transparencyFillColor").toQColor(); + options.saveSRGBProfile = cfg->getBool("saveSRGBProfile", false); + options.forceSRGB = cfg->getBool("forceSRGB", true); KisPNGConverter kpc(input); vKisAnnotationSP_it beginIt = image->beginAnnotations(); vKisAnnotationSP_it endIt = image->endAnnotations(); KisImageBuilder_Result res; KisExifInfoVisitor eIV; eIV.visit(image->rootLayer().data()); KisMetaData::Store* eI = 0; if (eIV.countPaintLayer() == 1) eI = eIV.exifInfo(); if (eI) { KisMetaData::Store* copy = new KisMetaData::Store(*eI); eI = copy; } if ((res = kpc.buildFile(filename, image->bounds(), image->xRes(), image->yRes(), l->paintDevice(), beginIt, endIt, options, eI)) == KisImageBuilder_RESULT_OK) { dbgFile << "success !"; delete eI; return KisImportExportFilter::OK; } delete eI; dbgFile << " Result =" << res; return KisImportExportFilter::InternalError; } -#include "kis_png_export.moc" +KisPropertiesConfigurationSP KisPNGExport::defaultConfiguration(const QByteArray &, const QByteArray &) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("alpha", true); + cfg->setProperty("indexed", false); + cfg->setProperty("compression", 9); + cfg->setProperty("interlaced", false); + cfg->setProperty("transparencyFillcolor", QString("255,255,255")); + cfg->setProperty("saveSRGBProfile", false); + cfg->setProperty("forceSRGB", true); + + return cfg; +} +KisPropertiesConfigurationSP KisPNGExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + QString filterConfig = KisConfig().exportConfiguration("PNG"); + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisPNGExport::createConfigurationWidget(QWidget *parent, const QByteArray &, const QByteArray &) const +{ + return new KisWdgOptionsPNG(parent); +} + +void KisWdgOptionsPNG::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + bool isThereAlpha = cfg->getBool("isThereAlpha"); + + alpha->setChecked(cfg->getBool("alpha", isThereAlpha)); + + if (cfg->getString("ColorModelID") == RGBAColorModelID.id()) { + tryToSaveAsIndexed->setVisible(true); + if (alpha->isChecked()) { + tryToSaveAsIndexed->setChecked(false); + } + else { + tryToSaveAsIndexed->setChecked(cfg->getBool("indexed", false)); + } + } + else { + tryToSaveAsIndexed->setVisible(false); + } + interlacing->setChecked(cfg->getBool("interlaced", false)); + compressionLevel->setValue(cfg->getInt("compression", 9)); + compressionLevel->setRange(1, 9 , 0); + + alpha->setEnabled(isThereAlpha); + tryToSaveAsIndexed->setVisible(!isThereAlpha); + + bnTransparencyFillColor->setEnabled(!alpha->isChecked()); + + bool sRGB = cfg->getBool("sRGB", false); + + chkSRGB->setEnabled(sRGB); + chkSRGB->setChecked(cfg->getBool("saveSRGBProfile", true)); + + chkForceSRGB->setEnabled(!sRGB); + chkForceSRGB->setChecked(cfg->getBool("forceSRGB", false)); + + QStringList rgb = cfg->getString("transparencyFillcolor", "0,0,0").split(','); + KoColor c(KoColorSpaceRegistry::instance()->rgb8()); + c.fromQColor(Qt::white); + bnTransparencyFillColor->setDefaultColor(c); + c.fromQColor(QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt())); + bnTransparencyFillColor->setColor(c); + +} + +KisPropertiesConfigurationSP KisWdgOptionsPNG::configuration() const +{ + + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + + bool alpha = this->alpha->isChecked(); + bool interlace = interlacing->isChecked(); + int compression = (int)compressionLevel->value(); + bool tryToSaveAsIndexed = this->tryToSaveAsIndexed->isChecked(); + QColor c = bnTransparencyFillColor->color().toQColor(); + bool saveSRGB = chkSRGB->isChecked(); + bool forceSRGB = chkForceSRGB->isChecked(); + + cfg->setProperty("alpha", alpha); + cfg->setProperty("indexed", tryToSaveAsIndexed); + cfg->setProperty("compression", compression); + cfg->setProperty("interlaced", interlace); + cfg->setProperty("transparencyFillcolor", QString("%1,%2,%3").arg(c.red()).arg(c.green()).arg(c.blue())); + cfg->setProperty("saveSRGBProfile", saveSRGB); + cfg->setProperty("forceSRGB", forceSRGB); + + return cfg; +} void KisWdgOptionsPNG::on_alpha_toggled(bool checked) { bnTransparencyFillColor->setEnabled(!checked); } + +#include "kis_png_export.moc" + diff --git a/plugins/impex/png/kis_png_export.h b/plugins/impex/png/kis_png_export.h index fde0675044..e4e15e4eaf 100644 --- a/plugins/impex/png/kis_png_export.h +++ b/plugins/impex/png/kis_png_export.h @@ -1,49 +1,62 @@ /* * Copyright (c) 2005 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_PNG_EXPORT_H_ #define _KIS_PNG_EXPORT_H_ #include "ui_kis_wdg_options_png.h" #include +#include -class KisWdgOptionsPNG : public QWidget, public Ui::KisWdgOptionsPNG +class KisWdgOptionsPNG : public KisConfigWidget, public Ui::KisWdgOptionsPNG { Q_OBJECT public: - KisWdgOptionsPNG(QWidget *parent) : QWidget(parent) { + KisWdgOptionsPNG(QWidget *parent) + : KisConfigWidget(parent) + { setupUi(this); } + + void setConfiguration(const KisPropertiesConfigurationSP config); + KisPropertiesConfigurationSP configuration() const; + private Q_SLOTS: void on_alpha_toggled(bool checked); }; class KisPNGExport : public KisImportExportFilter { Q_OBJECT + public: + KisPNGExport(QObject *parent, const QVariantList &); virtual ~KisPNGExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); + + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; }; #endif diff --git a/plugins/impex/png/kis_png_import.cc b/plugins/impex/png/kis_png_import.cc index 155e3e13af..7abef7213e 100644 --- a/plugins/impex/png/kis_png_import.cc +++ b/plugins/impex/png/kis_png_import.cc @@ -1,104 +1,104 @@ /* * Copyright (c) 2005 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. */ #include "kis_png_import.h" #include #include #include #include #include #include #include #include "kis_png_converter.h" K_PLUGIN_FACTORY_WITH_JSON(PNGImportFactory, "krita_png_import.json", registerPlugin();) KisPNGImport::KisPNGImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisPNGImport::~KisPNGImport() { } -KisImportExportFilter::ConversionStatus KisPNGImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisPNGImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Importing using PNGImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc -> prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } KisPNGConverter ib(doc, getBatchMode()); // if (view != 0) // view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); switch (ib.buildImage(filename)) { case KisImageBuilder_RESULT_UNSUPPORTED: return KisImportExportFilter::NotImplemented; break; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; break; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_EXIST: case KisImageBuilder_RESULT_NOT_LOCAL: return KisImportExportFilter::FileNotFound; break; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; break; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; break; case KisImageBuilder_RESULT_OK: doc -> setCurrentImage(ib.image()); return KisImportExportFilter::OK; break; default: break; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/png/kis_png_import.h b/plugins/impex/png/kis_png_import.h index 434fc594d6..a256ab910c 100644 --- a/plugins/impex/png/kis_png_import.h +++ b/plugins/impex/png/kis_png_import.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2005 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_PNG_IMPORT_H_ #define _KIS_PNG_IMPORT_H_ #include #include class KisPNGImport : public KisImportExportFilter { Q_OBJECT public: KisPNGImport(QObject *parent, const QVariantList &); virtual ~KisPNGImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/ppm/kis_ppm_export.cpp b/plugins/impex/ppm/kis_ppm_export.cpp index 1859cf3533..76ed7e31d1 100644 --- a/plugins/impex/ppm/kis_ppm_export.cpp +++ b/plugins/impex/ppm/kis_ppm_export.cpp @@ -1,286 +1,318 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_ppm_export.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include "ui_kis_wdg_options_ppm.h" #include #include #include #include #include "kis_iterator_ng.h" #include K_PLUGIN_FACTORY_WITH_JSON(KisPPMExportFactory, "krita_ppm_export.json", registerPlugin();) KisPPMExport::KisPPMExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisPPMExport::~KisPPMExport() { } class KisPPMFlow { public: KisPPMFlow() { } virtual ~KisPPMFlow() { } virtual void writeBool(quint8 v) = 0; virtual void writeBool(quint16 v) = 0; virtual void writeNumber(quint8 v) = 0; virtual void writeNumber(quint16 v) = 0; virtual void flush() = 0; private: }; class KisPPMAsciiFlow : public KisPPMFlow { public: KisPPMAsciiFlow(QIODevice* device) : m_device(device) { } ~KisPPMAsciiFlow() { } virtual void writeBool(quint8 v) { if (v > 127) { m_device->write("1 "); } else { m_device->write("0 "); } } virtual void writeBool(quint16 v) { writeBool(quint8(v >> 8)); } virtual void writeNumber(quint8 v) { m_device->write(QByteArray::number(v)); m_device->write(" "); } virtual void writeNumber(quint16 v) { m_device->write(QByteArray::number(v)); m_device->write(" "); } virtual void flush() { } private: QIODevice* m_device; }; class KisPPMBinaryFlow : public KisPPMFlow { public: KisPPMBinaryFlow(QIODevice* device) : m_device(device), m_pos(0), m_current(0) { } virtual ~KisPPMBinaryFlow() { } virtual void writeBool(quint8 v) { m_current = m_current << 1; m_current |= (v > 127); ++m_pos; if (m_pos >= 8) { m_current = 0; m_pos = 0; flush(); } } virtual void writeBool(quint16 v) { writeBool(quint8(v >> 8)); } virtual void writeNumber(quint8 v) { m_device->write((char*)&v, 1); } virtual void writeNumber(quint16 v) { quint16 vo = qToBigEndian(v); m_device->write((char*)&vo, 2); } virtual void flush() { m_device->write((char*)&m_current, 1); } private: QIODevice* m_device; int m_pos; quint8 m_current; }; -KisImportExportFilter::ConversionStatus KisPPMExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisPPMExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "PPM export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; - KoDialog* kdb = new KoDialog(0); - kdb->setWindowTitle(i18n("PPM Export Options")); - kdb->setButtons(KoDialog::Ok | KoDialog::Cancel); - - Ui::WdgOptionsPPM optionsPPM; - - QWidget* wdg = new QWidget(kdb); - optionsPPM.setupUi(wdg); - - kdb->setMainWidget(wdg); + KoDialog kdb; + kdb.setWindowTitle(i18n("PPM Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisConfigWidget *wdg = createConfigurationWidget(&kdb, from, to); + kdb.setMainWidget(wdg); QApplication::restoreOverrideCursor(); - QString filterConfig = KisConfig().exportConfiguration("PPM"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - optionsPPM.type->setCurrentIndex(cfg.getInt("type", 0)); + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + if (configuration) { + cfg->fromXML(configuration->toXML()); + } + else { + cfg = lastSavedConfiguration(from, to); + } + wdg->setConfiguration(cfg); if (!getBatchMode()) { - if (kdb->exec() == QDialog::Rejected) { + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("PPM", *cfg.data()); } bool rgb = (to == "image/x-portable-pixmap"); - bool binary = optionsPPM.type->currentIndex() == 0; - cfg.setProperty("type", optionsPPM.type->currentIndex()); - KisConfig().setExportConfiguration("PPM", cfg); + bool binary = (cfg->getInt("type") == 0); bool bitmap = (to == "image/x-portable-bitmap"); KisImageWSP image = input->image(); Q_CHECK_PTR(image); // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); KisPaintDeviceSP pd = new KisPaintDevice(*image->projection()); // Test color space if (((rgb && (pd->colorSpace()->id() != "RGBA" && pd->colorSpace()->id() != "RGBA16")) || (!rgb && (pd->colorSpace()->id() != "GRAYA" && pd->colorSpace()->id() != "GRAYA16" && pd->colorSpace()->id() != "GRAYAU16")))) { if (rgb) { pd->convertTo(KoColorSpaceRegistry::instance()->rgb8(0), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } else { pd->convertTo(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), 0), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } } bool is16bit = pd->colorSpace()->id() == "RGBA16" || pd->colorSpace()->id() == "GRAYAU16"; // Open the file for writing QFile fp(filename); fp.open(QIODevice::WriteOnly); // Write the magic if (rgb) { if (binary) fp.write("P6"); else fp.write("P3"); } else if (bitmap) { if (binary) fp.write("P4"); else fp.write("P1"); } else { if (binary) fp.write("P5"); else fp.write("P2"); } fp.write("\n"); // Write the header fp.write(QByteArray::number(image->width())); fp.write(" "); fp.write(QByteArray::number(image->height())); if (!bitmap) { if (is16bit) fp.write(" 65535\n"); else fp.write(" 255\n"); } else { fp.write("\n"); } // Write the data KisPPMFlow* flow = 0; if (binary) flow = new KisPPMBinaryFlow(&fp); else flow = new KisPPMAsciiFlow(&fp); for (int y = 0; y < image->height(); ++y) { KisHLineIteratorSP it = pd->createHLineIteratorNG(0, y, image->width()); if (is16bit) { if (rgb) { do { flow->writeNumber(KoBgrU16Traits::red(it->rawData())); flow->writeNumber(KoBgrU16Traits::green(it->rawData())); flow->writeNumber(KoBgrU16Traits::blue(it->rawData())); } while (it->nextPixel()); } else if (bitmap) { do { flow->writeBool(*reinterpret_cast(it->rawData())); } while (it->nextPixel()); } else { do { flow->writeNumber(*reinterpret_cast(it->rawData())); } while (it->nextPixel()); } } else { if (rgb) { do { flow->writeNumber(KoBgrTraits::red(it->rawData())); flow->writeNumber(KoBgrTraits::green(it->rawData())); flow->writeNumber(KoBgrTraits::blue(it->rawData())); } while (it->nextPixel()); } else if (bitmap) { do { flow->writeBool(*reinterpret_cast(it->rawData())); } while (it->nextPixel()); } else { do { flow->writeNumber(*reinterpret_cast(it->rawData())); } while (it->nextPixel()); } } } if (bitmap) { flow->flush(); } delete flow; fp.close(); return KisImportExportFilter::OK; } +KisPropertiesConfigurationSP KisPPMExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("type", 0); + return cfg; +} + +KisPropertiesConfigurationSP KisPPMExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + QString filterConfig = KisConfig().exportConfiguration("PPM"); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisPPMExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + return new KisWdgOptionsPPM(parent); +} + + +void KisWdgOptionsPPM::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + cmbType->setCurrentIndex(cfg->getInt("type", 0)); +} + +KisPropertiesConfigurationSP KisWdgOptionsPPM::configuration() const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("type", cmbType->currentIndex()); + return cfg; + +} #include "kis_ppm_export.moc" + diff --git a/plugins/impex/ppm/kis_ppm_export.h b/plugins/impex/ppm/kis_ppm_export.h index 21ddf0f292..b7983dc017 100644 --- a/plugins/impex/ppm/kis_ppm_export.h +++ b/plugins/impex/ppm/kis_ppm_export.h @@ -1,36 +1,58 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_PPM_EXPORT_H_ #define _KIS_PPM_EXPORT_H_ #include #include +#include +#include "ui_kis_wdg_options_ppm.h" + +class KisWdgOptionsPPM : public KisConfigWidget, public Ui::WdgOptionsPPM +{ + Q_OBJECT + +public: + KisWdgOptionsPPM(QWidget *parent) + : KisConfigWidget(parent) + { + setupUi(this); + } + + void setConfiguration(const KisPropertiesConfigurationSP cfg); + KisPropertiesConfigurationSP configuration() const; +}; + + class KisPPMExport : public KisImportExportFilter { Q_OBJECT public: KisPPMExport(QObject *parent, const QVariantList &); virtual ~KisPPMExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; }; #endif diff --git a/plugins/impex/ppm/kis_ppm_import.cpp b/plugins/impex/ppm/kis_ppm_import.cpp index 7d5d6c343c..376ecdb65c 100644 --- a/plugins/impex/ppm/kis_ppm_import.cpp +++ b/plugins/impex/ppm/kis_ppm_import.cpp @@ -1,326 +1,326 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_ppm_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_iterator_ng.h" K_PLUGIN_FACTORY_WITH_JSON(PPMImportFactory, "krita_ppm_import.json", registerPlugin();) KisPPMImport::KisPPMImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisPPMImport::~KisPPMImport() { } -KisImportExportFilter::ConversionStatus KisPPMImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisPPMImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(from); dbgFile << "Importing using PPMImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } QFile fp(filename); doc->prepareForImport(); return loadFromDevice(&fp, doc); } int readNumber(QIODevice* device) { char c; int val = 0; while (true) { if (!device->getChar(&c)) break; // End of the file if (isdigit(c)) { val = 10 * val + c - '0'; } else if (c == '#') { device->readLine(); break; } else if (isspace((uchar) c)) { break; } } return val; } class KisPpmFlow { public: KisPpmFlow() { } virtual ~KisPpmFlow() { } virtual void nextRow() = 0; virtual bool valid() = 0; virtual bool nextUint1() = 0; virtual quint8 nextUint8() = 0; virtual quint16 nextUint16() = 0; }; class KisAsciiPpmFlow : public KisPpmFlow { public: KisAsciiPpmFlow(QIODevice* device) : m_device(device) { } virtual ~KisAsciiPpmFlow() { } virtual void nextRow() { } virtual bool valid() { return !m_device->atEnd(); } virtual bool nextUint1() { return readNumber(m_device) == 1; } virtual quint8 nextUint8() { return readNumber(m_device); } virtual quint16 nextUint16() { return readNumber(m_device); } private: QIODevice* m_device; }; class KisBinaryPpmFlow : public KisPpmFlow { public: KisBinaryPpmFlow(QIODevice* device, int lineWidth) : m_pos(0), m_device(device), m_lineWidth(lineWidth) { } virtual ~KisBinaryPpmFlow() { } virtual void nextRow() { m_array = m_device->read(m_lineWidth); m_ptr = m_array.data(); } virtual bool valid() { return m_array.size() == m_lineWidth; } virtual bool nextUint1() { if (m_pos == 0) { m_current = nextUint8(); m_pos = 8; } bool v = (m_current & 1) == 1; --m_pos; m_current = m_current >> 1; return v; } virtual quint8 nextUint8() { quint8 v = *reinterpret_cast(m_ptr); m_ptr += 1; return v; } virtual quint16 nextUint16() { quint16 v = *reinterpret_cast(m_ptr); m_ptr += 2; return qFromBigEndian(v); } private: int m_pos; quint8 m_current; char* m_ptr; QIODevice* m_device; QByteArray m_array; int m_lineWidth; }; KisImportExportFilter::ConversionStatus KisPPMImport::loadFromDevice(QIODevice* device, KisDocument* doc) { dbgFile << "Start decoding file"; device->open(QIODevice::ReadOnly); if (!device->isOpen()) { return KisImportExportFilter::CreationError; } QByteArray array = device->read(2); if (array.size() < 2) return KisImportExportFilter::CreationError; // Read the type of the ppm file enum { Puk, P1, P2, P3, P4, P5, P6 } fileType = Puk; // Puk => unknown int channels = -1; bool isAscii = false; if (array == "P1") { fileType = P1; isAscii = true; channels = 0; } else if (array == "P2") { fileType = P2; channels = 1; isAscii = true; } else if (array == "P3") { fileType = P3; channels = 3; isAscii = true; } else if (array == "P4") { fileType = P4; channels = 0; } else if (array == "P5") { // PGM fileType = P5; channels = 1; } else if (array == "P6") { // PPM fileType = P6; channels = 3; } Q_ASSERT(channels != -1); char c; device->getChar(&c); if (!isspace(c)) return KisImportExportFilter::CreationError; // Invalid file, it should have a separator now // Read width int width = readNumber(device); int height = readNumber(device); int maxval = 1; if (fileType != P1 && fileType != P4) { maxval = readNumber(device); } dbgFile << "Width = " << width << " height = " << height << "maxval = " << maxval; // Select the colorspace depending on the maximum value int pixelsize = -1; const KoColorSpace* colorSpace = 0; if (maxval <= 255) { if (channels == 1 || channels == 0) { pixelsize = 1; colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), 0); } else { pixelsize = 3; colorSpace = KoColorSpaceRegistry::instance()->rgb8(); } } else if (maxval <= 65535) { if (channels == 1 || channels == 0) { pixelsize = 2; colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), 0); } else { pixelsize = 6; colorSpace = KoColorSpaceRegistry::instance()->rgb16(); } } else { dbgFile << "Unknown colorspace"; return KisImportExportFilter::CreationError; } KisImageSP image = new KisImage(doc->createUndoStore(), width, height, colorSpace, "built image"); KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255); KisPpmFlow* ppmFlow = 0; if (isAscii) { ppmFlow = new KisAsciiPpmFlow(device); } else { ppmFlow = new KisBinaryPpmFlow(device, pixelsize * width); } for (int v = 0; v < height; ++v) { KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, v, width); ppmFlow->nextRow(); if (!ppmFlow->valid()) return KisImportExportFilter::CreationError; if (maxval <= 255) { if (channels == 3) { do { KoBgrTraits::setRed(it->rawData(), ppmFlow->nextUint8()); KoBgrTraits::setGreen(it->rawData(), ppmFlow->nextUint8()); KoBgrTraits::setBlue(it->rawData(), ppmFlow->nextUint8()); colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } while (it->nextPixel()); } else if (channels == 1) { do { *reinterpret_cast(it->rawData()) = ppmFlow->nextUint8(); colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } while (it->nextPixel()); } else if (channels == 0) { do { if (ppmFlow->nextUint1()) { *reinterpret_cast(it->rawData()) = 255; } else { *reinterpret_cast(it->rawData()) = 0; } colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } while (it->nextPixel()); } } else { if (channels == 3) { do { KoBgrU16Traits::setRed(it->rawData(), ppmFlow->nextUint16()); KoBgrU16Traits::setGreen(it->rawData(), ppmFlow->nextUint16()); KoBgrU16Traits::setBlue(it->rawData(), ppmFlow->nextUint16()); colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } while (it->nextPixel()); } else if (channels == 1) { do { *reinterpret_cast(it->rawData()) = ppmFlow->nextUint16(); colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } while (it->nextPixel()); } } } image->addNode(layer.data(), image->rootLayer().data()); doc->setCurrentImage(image); return KisImportExportFilter::OK; } #include "kis_ppm_import.moc" diff --git a/plugins/impex/ppm/kis_ppm_import.h b/plugins/impex/ppm/kis_ppm_import.h index f908b49386..5c882db742 100644 --- a/plugins/impex/ppm/kis_ppm_import.h +++ b/plugins/impex/ppm/kis_ppm_import.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_PPM_IMPORT_H_ #define _KIS_PPM_IMPORT_H_ #include #include #include class KisDocument; class KisPPMImport : public KisImportExportFilter { Q_OBJECT public: KisPPMImport(QObject *parent, const QVariantList &); virtual ~KisPPMImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); private: KisImportExportFilter::ConversionStatus loadFromDevice(QIODevice* device, KisDocument* doc); }; #endif diff --git a/plugins/impex/ppm/kis_wdg_options_ppm.ui b/plugins/impex/ppm/kis_wdg_options_ppm.ui index e063013a5e..f3e565d5eb 100644 --- a/plugins/impex/ppm/kis_wdg_options_ppm.ui +++ b/plugins/impex/ppm/kis_wdg_options_ppm.ui @@ -1,61 +1,61 @@ WdgOptionsPPM 0 0 243 94 Type: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + 0 0 Binary Ascii Qt::Vertical 20 46 diff --git a/plugins/impex/psd/psd_export.cc b/plugins/impex/psd/psd_export.cc index 06eeb847dc..2ebb77236d 100644 --- a/plugins/impex/psd/psd_export.cc +++ b/plugins/impex/psd/psd_export.cc @@ -1,124 +1,124 @@ /* * Copyright (c) 2009 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 "psd_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psd_saver.h" class KisExternalLayer; K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_psd_export.json", registerPlugin();) bool checkHomogenity(KisNodeSP root, const KoColorSpace* cs) { bool res = true; KisNodeSP child = root->firstChild(); while (child) { if (child->childCount() > 0) { res = checkHomogenity(child, cs); if (res == false) { break; } } KisLayer *layer = dynamic_cast(child.data()); if (layer) { if (layer->colorSpace() != cs) { res = false; break; } } child = child->nextSibling(); } return res; } psdExport::psdExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } psdExport::~psdExport() { } -KisImportExportFilter::ConversionStatus psdExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus psdExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile <<"PSD export! From:" << from <<", To:" << to <<""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (input->image()->width() > 30000 || input->image()->height() > 30000) { if (!getBatchMode()) { QMessageBox::critical(0, i18nc("@title:window", "Photoshop Export Error"), i18n("Unable to save to the Photoshop format.\n" "The Photoshop format only supports images that are smaller than 30000x3000 pixels.")); } return KisImportExportFilter::InvalidFormat; } if (!checkHomogenity(input->image()->rootLayer(), input->image()->colorSpace())) { if (!getBatchMode()) { QMessageBox::critical(0, i18nc("@title:window", "Photoshop Export Error"), i18n("Unable to save to the Photoshop format.\n" "The Photoshop format only supports images where all layers have the same colorspace as the image.")); } return KisImportExportFilter::InvalidFormat; } if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; PSDSaver kpc(input); KisImageBuilder_Result res; if ((res = kpc.buildFile(filename)) == KisImageBuilder_RESULT_OK) { dbgFile <<"success !"; return KisImportExportFilter::OK; } dbgFile <<" Result =" << res; return KisImportExportFilter::InternalError; } #include diff --git a/plugins/impex/psd/psd_export.h b/plugins/impex/psd/psd_export.h index 49d8d0a343..3495fc4f10 100644 --- a/plugins/impex/psd/psd_export.h +++ b/plugins/impex/psd/psd_export.h @@ -1,34 +1,34 @@ /* * Copyright (c) 2009 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PSD_EXPORT_H_ #define _PSD_EXPORT_H_ #include #include class psdExport : public KisImportExportFilter { Q_OBJECT public: psdExport(QObject *parent, const QVariantList &); virtual ~psdExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/psd/psd_import.cc b/plugins/impex/psd/psd_import.cc index bcd83f9926..0e111dffc6 100644 --- a/plugins/impex/psd/psd_import.cc +++ b/plugins/impex/psd/psd_import.cc @@ -1,93 +1,93 @@ /* * Copyright (c) 2009 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 "psd_import.h" #include #include #include #include #include #include "psd_loader.h" K_PLUGIN_FACTORY_WITH_JSON(ImportFactory, "krita_psd_import.json", registerPlugin();) psdImport::psdImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } psdImport::~psdImport() { } -KisImportExportFilter::ConversionStatus psdImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus psdImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile <<"Importing using PSDImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } PSDLoader ib(doc); KisImageBuilder_Result result = ib.buildImage(filename); switch (result) { case KisImageBuilder_RESULT_UNSUPPORTED: return KisImportExportFilter::NotImplemented; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_EXIST: case KisImageBuilder_RESULT_NOT_LOCAL: qDebug() << "ib returned KisImageBuilder_RESULT_NOT_LOCAL"; return KisImportExportFilter::FileNotFound; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; case KisImageBuilder_RESULT_OK: doc -> setCurrentImage( ib.image()); return KisImportExportFilter::OK; default: return KisImportExportFilter::StorageCreationError; //dbgFile << "Result was: " << result; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/psd/psd_import.h b/plugins/impex/psd/psd_import.h index fa03e40492..712be6ef7e 100644 --- a/plugins/impex/psd/psd_import.h +++ b/plugins/impex/psd/psd_import.h @@ -1,34 +1,34 @@ /* * Copyright (c) 2009 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PSD_IMPORT_H_ #define PSD_IMPORT_H_ #include #include class psdImport : public KisImportExportFilter { Q_OBJECT public: psdImport(QObject *parent, const QVariantList &); virtual ~psdImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/qml/qml_export.cc b/plugins/impex/qml/qml_export.cc index aacafe3f0c..1a3574a64f 100644 --- a/plugins/impex/qml/qml_export.cc +++ b/plugins/impex/qml/qml_export.cc @@ -1,79 +1,79 @@ /* * Copyright (c) 2013 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "qml_export.h" #include #include #include #include #include #include #include #include #include "qml_converter.h" K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_qml_export.json", registerPlugin();) QMLExport::QMLExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } QMLExport::~QMLExport() { } -KisImportExportFilter::ConversionStatus QMLExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus QMLExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(to); if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); QString filename = outputFile(); dbgKrita << "input " << input; if (!input) { return KisImportExportFilter::NoDocumentCreated; } dbgKrita << "filename " << input; if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } KisImageWSP image = input->image(); Q_CHECK_PTR(image); QMLConverter converter; KisImageBuilder_Result result = converter.buildFile(filename, image); if (result == KisImageBuilder_RESULT_OK) { dbgFile << "success !"; return KisImportExportFilter::OK; } dbgFile << " Result =" << result; return KisImportExportFilter::InternalError; } #include diff --git a/plugins/impex/qml/qml_export.h b/plugins/impex/qml/qml_export.h index fd19af8032..56292b5e4e 100644 --- a/plugins/impex/qml/qml_export.h +++ b/plugins/impex/qml/qml_export.h @@ -1,35 +1,35 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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 _QML_EXPORT_H_ #define _QML_EXPORT_H_ #include #include class QMLExport : public KisImportExportFilter { Q_OBJECT public: QMLExport(QObject *parent, const QVariantList &); virtual ~QMLExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/raw/kis_raw_import.cpp b/plugins/impex/raw/kis_raw_import.cpp index a114afba71..973667d3dc 100644 --- a/plugins/impex/raw/kis_raw_import.cpp +++ b/plugins/impex/raw/kis_raw_import.cpp @@ -1,214 +1,214 @@ /* * Copyright (c) 2008 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. */ #include "kis_raw_import.h" #include #include #include #include #include #include #include "kis_debug.h" #include "KisDocument.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_transaction.h" #include "kis_group_layer.h" #include "kis_paint_layer.h" #include "kis_iterator_ng.h" #include #include using namespace KDcrawIface; K_PLUGIN_FACTORY_WITH_JSON(KisRawImportFactory, "krita_raw_import.json", registerPlugin();) KisRawImport::KisRawImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { m_dialog = new KoDialog(); m_dialog->enableButtonApply(false); QWidget* widget = new QWidget; m_rawWidget.setupUi(widget); m_dialog->setMainWidget(widget); connect(m_rawWidget.pushButtonUpdate, SIGNAL(clicked()), this, SLOT(slotUpdatePreview())); } KisRawImport::~KisRawImport() { delete m_dialog; } inline quint16 correctIndian(quint16 v) { #if KDCRAW_VERSION < 0x000400 return ((v & 0x00FF) << 8) | ((v & 0xFF00 >> 8)); #else return v; #endif } -KisImportExportFilter::ConversionStatus KisRawImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisRawImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << from << " " << to << ""; if (/*from != "image/x-raw" || */to != "application/x-krita") { // too many from to check, and I don't think it can happen an unsupported from return KisImportExportFilter::NotImplemented; } dbgFile << "Krita importing from Raw"; KisDocument * doc = outputDocument(); if (!doc) { return KisImportExportFilter::NoDocumentCreated; } doc -> prepareForImport(); QString filename = inputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } // Show dialog m_dialog->setCursor(Qt::ArrowCursor); QApplication::setOverrideCursor(Qt::ArrowCursor); #if KDCRAW_VERSION < 0x010200 m_rawWidget.rawSettings->setDefaultSettings(); #else m_rawWidget.rawSettings->resetToDefault(); #endif slotUpdatePreview(); if (m_dialog->exec() == QDialog::Accepted) { QApplication::setOverrideCursor(Qt::WaitCursor); // Do the decoding // TODO: it would probably be better done in a thread, while an other thread simulate that the application is still living (or even better if libkdcraw was giving us some progress report QByteArray imageData; RawDecodingSettings settings = rawDecodingSettings(); settings.sixteenBitsImage = true; int width, height, rgbmax; KDcraw dcraw; if (!dcraw.decodeRAWImage(inputFile(), settings, imageData, width, height, rgbmax)) return KisImportExportFilter::CreationError; QApplication::restoreOverrideCursor(); // Init the image const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb16(); KisImageWSP image = new KisImage(doc->createUndoStore(), width, height, cs, filename); if (image.isNull()) return KisImportExportFilter::CreationError; KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), quint8_MAX); image->addNode(layer, image->rootLayer()); if (layer.isNull()) return KisImportExportFilter::CreationError; KisPaintDeviceSP device = layer->paintDevice(); if (device.isNull()) return KisImportExportFilter::CreationError; // Copy the data KisHLineIteratorSP it = device->createHLineIteratorNG(0, 0, width); for (int y = 0; y < height; ++y) { do { KoBgrU16Traits::Pixel* pixel = reinterpret_cast(it->rawData()); quint16* ptr = ((quint16*)imageData.data()) + (y * width + it->x()) * 3; #if KDCRAW_VERSION < 0x000400 pixel->red = correctIndian(ptr[2]); pixel->green = correctIndian(ptr[1]); pixel->blue = correctIndian(ptr[0]); #else pixel->red = correctIndian(ptr[0]); pixel->green = correctIndian(ptr[1]); pixel->blue = correctIndian(ptr[2]); #endif pixel->alpha = 0xFFFF; } while (it->nextPixel()); it->nextRow(); } QApplication::restoreOverrideCursor(); doc->setCurrentImage(image); return KisImportExportFilter::OK; } QApplication::restoreOverrideCursor(); return KisImportExportFilter::UserCancelled; } void KisRawImport::slotUpdatePreview() { QByteArray imageData; RawDecodingSettings settings = rawDecodingSettings(); settings.sixteenBitsImage = false; int width, height, rgbmax; KDcraw dcraw; if (dcraw.decodeHalfRAWImage(inputFile(), settings, imageData, width, height, rgbmax)) { QImage image(width, height, QImage::Format_RGB32); for (int y = 0; y < height; ++y) { QRgb *pixel= reinterpret_cast(image.scanLine(y)); for (int x = 0; x < width; ++x) { quint8* ptr = ((quint8*)imageData.data()) + (y * width + x) * 3; pixel[x] = qRgb(ptr[0], ptr[1], ptr[2]); } } m_rawWidget.preview->setPixmap(QPixmap::fromImage(image)); } } RawDecodingSettings KisRawImport::rawDecodingSettings() { #if KDCRAW_VERSION < 0x010200 RawDecodingSettings settings; settings.sixteenBitsImage = true; settings.brightness = m_rawWidget.rawSettings->brightness(); settings.RAWQuality = m_rawWidget.rawSettings->quality(); settings.outputColorSpace = m_rawWidget.rawSettings->outputColorSpace(); settings.RGBInterpolate4Colors = m_rawWidget.rawSettings->useFourColor(); settings.DontStretchPixels = m_rawWidget.rawSettings->useDontStretchPixels(); settings.unclipColors = m_rawWidget.rawSettings->unclipColor(); settings.whiteBalance = m_rawWidget.rawSettings->whiteBalance(); settings.customWhiteBalance = m_rawWidget.rawSettings->customWhiteBalance(); settings.customWhiteBalanceGreen = m_rawWidget.rawSettings->customWhiteBalanceGreen(); settings.enableBlackPoint = m_rawWidget.rawSettings->useBlackPoint(); settings.blackPoint = m_rawWidget.rawSettings->blackPoint(); settings.enableNoiseReduction = m_rawWidget.rawSettings->useNoiseReduction(); settings.NRThreshold = m_rawWidget.rawSettings->NRThreshold(); settings.enableCACorrection = m_rawWidget.rawSettings->useCACorrection(); settings.caMultiplier[0] = m_rawWidget.rawSettings->caRedMultiplier(); settings.caMultiplier[1] = m_rawWidget.rawSettings->caBlueMultiplier(); return settings; #else return m_rawWidget.rawSettings->settings(); #endif } #include "kis_raw_import.moc" diff --git a/plugins/impex/raw/kis_raw_import.h b/plugins/impex/raw/kis_raw_import.h index 6f80a45d77..ed56323937 100644 --- a/plugins/impex/raw/kis_raw_import.h +++ b/plugins/impex/raw/kis_raw_import.h @@ -1,58 +1,58 @@ /* * Copyright (c) 2005 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_RAW_IMPORT_H_ #define KIS_RAW_IMPORT_H_ #include #include "ui_wdgrawimport.h" class KoDialog; class WdgRawImport; namespace KDcrawIface { class RawDecodingSettings; } class KisRawImport : public KisImportExportFilter { Q_OBJECT public: KisRawImport(QObject *parent, const QVariantList &); virtual ~KisRawImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); private Q_SLOTS: void slotUpdatePreview(); private: KDcrawIface::RawDecodingSettings rawDecodingSettings(); private: Ui::WdgRawImport m_rawWidget; KoDialog* m_dialog; }; #endif // KIS_RAW_IMPORT_H_ diff --git a/plugins/impex/spriter/kis_spriter_export.cpp b/plugins/impex/spriter/kis_spriter_export.cpp index c03822a579..3b69fe4e1d 100644 --- a/plugins/impex/spriter/kis_spriter_export.cpp +++ b/plugins/impex/spriter/kis_spriter_export.cpp @@ -1,626 +1,626 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_spriter_export.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 // for KisDegreesToRadians #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisSpriterExportFactory, "krita_spriter_export.json", registerPlugin();) KisSpriterExport::KisSpriterExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisSpriterExport::~KisSpriterExport() { } bool KisSpriterExport::savePaintDevice(KisPaintDeviceSP dev, const QString &fileName) { QFileInfo fi(fileName); QDir d = fi.absoluteDir(); d.mkpath(d.path()); QRect rc = m_image->bounds().intersected(dev->exactBounds()); if (!KisPNGConverter::isColorSpaceSupported(dev->colorSpace())) { dev = new KisPaintDevice(*dev.data()); KUndo2Command *cmd = dev->convertTo(KoColorSpaceRegistry::instance()->rgb8()); delete cmd; } QFile fp(fileName); KisPNGOptions options; options.forceSRGB = true; vKisAnnotationSP_it beginIt = m_image->beginAnnotations(); vKisAnnotationSP_it endIt = m_image->endAnnotations(); KisPNGConverter converter(0); KisImageBuilder_Result res = converter.buildFile(&fp, rc, m_image->xRes(), m_image->yRes(), dev, beginIt, endIt, options, 0); return (res == KisImageBuilder_RESULT_OK); } void KisSpriterExport::parseFolder(KisGroupLayerSP parentGroup, const QString &folderName, const QString &basePath) { // qDebug() << "parseFolder: parent" << parentGroup->name() // << "folderName" << folderName // << "basepath" << basePath; static int folderId = 0; QString pathName; if (!folderName.isEmpty()) { pathName = folderName + "/"; } KisNodeSP child = parentGroup->lastChild(); while (child) { if (child->visible() && child->inherits("KisGroupLayer")) { parseFolder(qobject_cast(child.data()), child->name().split(" ").first(), basePath + "/" + pathName); } child = child->prevSibling(); } Folder folder; folder.id = folderId; folder.name = folderName; folder.groupName = parentGroup->name(); int fileId = 0; child = parentGroup->lastChild(); while (child) { if (child->visible() && !child->inherits("KisGroupLayer") && !child->inherits("KisMask")) { QRectF rc = m_image->bounds().intersected(child->exactBounds()); QString layerBaseName = child->name().split(" ").first(); SpriterFile file; file.id = fileId++; file.pathName = pathName; file.baseName = layerBaseName; file.layerName = child->name(); file.name = folderName + "/" + layerBaseName + ".png"; qreal xmin = rc.left(); qreal ymin = rc.top(); qreal xmax = rc.right(); qreal ymax = rc.bottom(); file.width = xmax - xmin; file.height = ymax - ymin; file.x = xmin; file.y = ymin; //qDebug() << "Created file" << file.id << file.name << file.pathName << file.baseName << file.width << file.height << file.layerName; savePaintDevice(child->projection(), basePath + file.name); folder.files.append(file); } child = child->prevSibling(); } if (folder.files.size() > 0) { //qDebug() << "Adding folder" << folder.id << folder.name << folder.groupName << folder.files.length(); m_folders.append(folder); folderId++; } } Bone *KisSpriterExport::parseBone(const Bone *parent, KisGroupLayerSP groupLayer) { static int boneId = 0; QString groupBaseName = groupLayer->name().split(" ").first(); Bone *bone = new Bone; bone->id = boneId++; bone->parentBone = parent; bone->name = groupBaseName; if (m_boneLayer) { QRectF rc = m_image->bounds().intersected(m_boneLayer->exactBounds()); qreal xmin = rc.left(); qreal ymin = rc.top(); qreal xmax = rc.right(); qreal ymax = rc.bottom(); bone->x = (xmin + xmax) / 2; bone->y = -(ymin + ymax) / 2; bone->width = xmax - xmin; bone->height = ymax - ymin; } else { bone->x = 0.0; bone->y = 0.0; bone->width = 0.0; bone->height = 0.0; } if (parent) { bone->localX = bone->x - parent->x; bone->localY = bone->y - parent->y; } else { bone->localX = bone->x; bone->localY = bone->y; } bone->localAngle = 0.0; bone->localScaleX = 1.0; bone->localScaleY = 1.0; KisNodeSP child = groupLayer->lastChild(); while (child) { if (child->visible() && child->inherits("KisGroupLayer")) { bone->bones.append(parseBone(bone, qobject_cast(child.data()))); } child = child->prevSibling(); } //qDebug() << "Created bone" << bone->id << "with" << bone->bones.size() << "bones"; return bone; } void copyBone(Bone *startBone) { startBone->fixLocalX = startBone->localX; startBone->fixLocalY = startBone->localY; startBone->fixLocalAngle = startBone->localAngle; startBone->fixLocalScaleX= startBone->localScaleX; startBone->fixLocalScaleY= startBone->localScaleY; Q_FOREACH(Bone *child, startBone->bones) { copyBone(child); } } void KisSpriterExport::fixBone(Bone *bone) { qreal boneLocalAngle = 0; qreal boneLocalScaleX = 1; if (bone->bones.length() >= 1) { // if a bone has one or more children, point at first child Bone *childBone = bone->bones[0]; qreal dx = childBone->x - bone->x; qreal dy = childBone->y - bone->y; if (qAbs(dx) > 0 || qAbs(dy) > 0) { boneLocalAngle = KisFastMath::atan2(dy, dx); boneLocalScaleX = sqrt(dx * dx + dy * dy) / 200; } } else if (bone->parentBone) { // else, if bone has parent, point away from parent qreal dx = bone->x - bone->parentBone->x; qreal dy = bone->y - bone->parentBone->y; if (qAbs(dx) > 0 || qAbs(dy) > 0) { boneLocalAngle = KisFastMath::atan2(dy, dx); boneLocalScaleX = sqrt(dx * dx + dy * dy) / 200; } } // adjust bone angle bone->fixLocalAngle += boneLocalAngle; bone->fixLocalScaleX *= boneLocalScaleX; // rotate all the child bones back to world position for (int i = 0; i < bone->bones.length(); ++i) { Bone *childBone = bone->bones[i]; qreal tx = childBone->fixLocalX; qreal ty = childBone->fixLocalY; childBone->fixLocalX = tx * cos(-boneLocalAngle) - ty * sin(-boneLocalAngle); childBone->fixLocalY = tx * sin(-boneLocalAngle) + ty * cos(-boneLocalAngle); childBone->fixLocalX /= boneLocalScaleX; childBone->fixLocalAngle -= boneLocalAngle; childBone->fixLocalScaleX /= boneLocalScaleX; } // rotate all the child objects back to world position for (int i = 0; i < m_objects.length(); ++i) { if (m_objects[i].bone == bone) { m_objects[i].fixLocalAngle -= boneLocalAngle; m_objects[i].fixLocalScaleX /= boneLocalScaleX; } } // process all child bones for (int i = 0; i < bone->bones.length(); ++i) { fixBone(bone->bones[i]); } } void KisSpriterExport::writeBoneRef(const Bone *bone, QDomElement &key, QDomDocument &scml) { if (!bone) return; QDomElement boneRef = scml.createElement("bone_ref"); key.appendChild(boneRef); boneRef.setAttribute("id", bone->id); if (bone->parentBone) { boneRef.setAttribute("parent", bone->parentBone->id); } boneRef.setAttribute("timeline", m_timelineid++); boneRef.setAttribute("key", "0"); Q_FOREACH(const Bone *childBone, bone->bones) { writeBoneRef(childBone, key, scml); } } void KisSpriterExport::writeBone(const Bone *bone, QDomElement &animation, QDomDocument &scml) { if (!bone) return; QDomElement timeline = scml.createElement("timeline"); animation.appendChild(timeline); timeline.setAttribute("id", m_timelineid); timeline.setAttribute("name", bone->name); timeline.setAttribute("object_type", "bone"); QDomElement key = scml.createElement("key"); timeline.appendChild(key); key.setAttribute("id", "0"); key.setAttribute("spin", 0); QDomElement boneEl = scml.createElement("bone"); key.appendChild(boneEl); boneEl.setAttribute("x", QString::number(bone->fixLocalX, 'f', 2)); boneEl.setAttribute("y", QString::number(bone->fixLocalY, 'f', 2)); boneEl.setAttribute("angle", QString::number(bone->fixLocalAngle, 'f', 2)); boneEl.setAttribute("scale_x", QString::number(bone->fixLocalScaleX, 'f', 2)); boneEl.setAttribute("scale_y", QString::number(bone->fixLocalScaleY, 'f', 2)); m_timelineid++; Q_FOREACH(const Bone *childBone, bone->bones) { writeBone(childBone, animation, scml); } } void KisSpriterExport::fillScml(QDomDocument &scml, const QString &entityName) { //qDebug() << "Creating scml" << entityName; QDomElement root = scml.createElement("spriter_data"); scml.appendChild(root); root.setAttribute("scml_version", 1); root.setAttribute("generator", "krita"); root.setAttribute("generator_version", qApp->applicationVersion()); Q_FOREACH(const Folder &folder, m_folders) { QDomElement fe = scml.createElement("folder"); root.appendChild(fe); fe.setAttribute("id", folder.id); fe.setAttribute("name", folder.name); Q_FOREACH(const SpriterFile &file, folder.files) { QDomElement fileElement = scml.createElement("file"); fe.appendChild(fileElement); fileElement.setAttribute("id", file.id); fileElement.setAttribute("name", file.name); fileElement.setAttribute("width", QString::number(file.width, 'f', 2)); fileElement.setAttribute("height", QString::number(file.height, 'f', 2)); } } // entity QDomElement entity = scml.createElement("entity"); root.appendChild(entity); entity.setAttribute("id", "0"); entity.setAttribute("name", entityName); // entity/animation QDomElement animation = scml.createElement("animation"); entity.appendChild(animation); animation.setAttribute("id", "0"); animation.setAttribute("name", "default"); animation.setAttribute("length", "1000"); animation.setAttribute("looping", "false"); // entity/animation/mainline QDomElement mainline = scml.createElement("mainline"); animation.appendChild(mainline); QDomElement key = scml.createElement("key"); mainline.appendChild(key); key.setAttribute("id", "0"); m_timelineid = 0; writeBoneRef(m_rootBone, key, scml); Q_FOREACH(const SpriterObject &object, m_objects) { QDomElement oe = scml.createElement("object_ref"); key.appendChild(oe); oe.setAttribute("id", object.id); if (object.bone) { oe.setAttribute("parent", object.bone->id); } oe.setAttribute("timeline", m_timelineid++); oe.setAttribute("key", "0"); oe.setAttribute("z_index", object.id); } // entity/animation/timeline m_timelineid = 0; if (m_rootBone) { writeBone(m_rootBone, animation, scml); } Q_FOREACH(const SpriterObject &object, m_objects) { Folder folder; Q_FOREACH(const Folder & f, m_folders) { if (f.id == object.folderId) { folder = f; break; } } SpriterFile file; file.id = -1; Q_FOREACH(const SpriterFile &f, folder.files) { if (f.id == object.fileId) { file = f; break; } } Q_ASSERT(file.id >= 0); QString objectName = "object-" + file.baseName; qreal pivotX = (0.0 -(object.fixLocalX / file.width)); qreal pivotY = (1.0 -(object.fixLocalY / file.height)); QDomElement timeline = scml.createElement("timeline"); animation.appendChild(timeline); timeline.setAttribute("id", m_timelineid++); timeline.setAttribute("name", objectName); QDomElement key = scml.createElement("key"); timeline.appendChild(key); key.setAttribute("id", "0"); key.setAttribute("spin", "0"); QDomElement objectEl = scml.createElement("object"); key.appendChild(objectEl); objectEl.setAttribute("folder", object.folderId); objectEl.setAttribute("file", object.fileId); objectEl.setAttribute("x", "0"); objectEl.setAttribute("y", "0"); objectEl.setAttribute("pivot_x", QString::number(pivotX, 'f', 2)); objectEl.setAttribute("pivot_y", QString::number(pivotY, 'f', 2)); objectEl.setAttribute("angle", QString::number(kisRadiansToDegrees(object.fixLocalAngle), 'f', 2)); objectEl.setAttribute("scale_x", QString::number(object.fixLocalScaleX, 'f', 2)); objectEl.setAttribute("scale_y", QString::number(object.fixLocalScaleY, 'f', 2)); } } Bone *findBoneByName(Bone *startBone, const QString &name) { if (!startBone) return 0; //qDebug() << "findBoneByName" << name << "starting with" << startBone->name; if (startBone->name == name) { return startBone; } Q_FOREACH(Bone *child, startBone->bones) { //qDebug() << "looking for" << name << "found" << child->name; if (child->name == name) { return child; } Bone *grandChild = findBoneByName(child, name); if (grandChild){ return grandChild; } } return 0; } -KisImportExportFilter::ConversionStatus KisSpriterExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisSpriterExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Spriter export! From:" << from << ", To:" << to << "" << outputFile(); if (from != "application/x-krita") { return KisImportExportFilter::NotImplemented; } KisDocument *input = inputDocument(); QString filename = outputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } if (!input) { return KisImportExportFilter::NoDocumentCreated; } QFileInfo fi(filename); //qDebug() << "filename" << filename << fi.absolutePath() << fi.baseName(); m_image = input->image(); if (m_image->rootLayer()->childCount() == 0) { return KisImportExportFilter::UsageError; } KisGroupLayerSP root = input->image()->rootLayer(); m_boneLayer = qobject_cast(root->findChildByName("bone").data()); //qDebug() << "Found boneLayer" << m_boneLayer; m_rootLayer= qobject_cast(root->findChildByName("root").data()); //qDebug() << "Fond rootLayer" << m_rootLayer; parseFolder(input->image()->rootLayer(), "", fi.absolutePath()); m_rootBone = 0; if (m_rootLayer) { m_rootBone = parseBone(0, m_rootLayer); } // Generate objects int objectId = 0; for (int folderIndex = 0, folderCount = m_folders.size(); folderIndex < folderCount; ++folderIndex) { Folder folder = m_folders[folderCount - 1 - folderIndex]; for (int fileIndex = 0, fileCount = folder.files.size(); fileIndex < fileCount; ++ fileIndex) { SpriterFile file = folder.files[fileCount - 1 - fileIndex]; SpriterObject spriterObject; spriterObject.id = objectId++; spriterObject.folderId = folder.id; spriterObject.fileId = file.id; spriterObject.x = file.x; spriterObject.y = -file.y; Bone *bone = 0; //qDebug() << "file layername" << file.layerName; // layer.name format: "base_name bone(bone_name) slot(slot_name)" if (file.layerName.contains("bone(")) { int start = file.layerName.indexOf("bone(") + 5; int end = file.layerName.indexOf(')', start); QString boneName = file.layerName.mid(start, end - start); bone = findBoneByName(m_rootBone, boneName); } // layer.name format: "base_name" if (!bone && m_rootBone) { bone = findBoneByName(m_rootBone, file.layerName); } // group.name format: "base_name bone(bone_name)" if (!bone && m_rootBone) { if (folder.groupName.contains("bone(")) { int start = folder.groupName.indexOf("bone(") + 5; int end = folder.groupName.indexOf(')', start); QString boneName = folder.groupName.mid(start, end - start); bone = findBoneByName(m_rootBone, boneName); } // group.name format: "base_name" if (!bone) { bone = findBoneByName(m_rootBone, folder.groupName); } } if (!bone) { bone = m_rootBone; } if (bone) { spriterObject.bone = bone; spriterObject.localX = spriterObject.x - bone->x; spriterObject.localY = spriterObject.y - bone->y; } else { spriterObject.bone = 0; spriterObject.localX = spriterObject.x; spriterObject.localY = spriterObject.y; } spriterObject.localAngle = 0; spriterObject.localScaleX = 1.0; spriterObject.localScaleY = 1.0; SpriterSlot *slot = 0; // layer.name format: "base_name bone(bone_name) slot(slot_name)" if (file.layerName.contains("slot(")) { int start = file.layerName.indexOf("slot(") + 5; int end = file.layerName.indexOf(')', start); slot->name = file.layerName.mid(start, end - start); slot->defaultAttachmentFlag = file.layerName.contains("*"); } spriterObject.slot = slot; // qDebug() << "Created object" << spriterObject.id << spriterObject.folderId // << spriterObject.fileId << spriterObject.x << spriterObject.y // << spriterObject.localX << spriterObject.localY; m_objects.append(spriterObject); } } // Copy object transforms for (int i = 0; i < m_objects.size(); ++i) { m_objects[i].fixLocalX = m_objects[i].localX; m_objects[i].fixLocalY = m_objects[i].localY; m_objects[i].fixLocalAngle = m_objects[i].localAngle; m_objects[i].fixLocalScaleX = m_objects[i].localScaleX; m_objects[i].fixLocalScaleY = m_objects[i].localScaleY; } // Calculate bone angles if (m_rootBone) { copyBone(m_rootBone); fixBone(m_rootBone); } // Generate scml QDomDocument scml; fillScml(scml, fi.baseName()); QFile f(filename); //qDebug() << "Writing xml to" << f.fileName(); bool r = f.open(QFile::WriteOnly); Q_ASSERT(r); f.write("\n"); f.write(scml.toString(4).toUtf8()); f.flush(); f.close(); delete m_rootBone; return KisImportExportFilter::OK; } #include "kis_spriter_export.moc" diff --git a/plugins/impex/spriter/kis_spriter_export.h b/plugins/impex/spriter/kis_spriter_export.h index 445902f545..42f279decb 100644 --- a/plugins/impex/spriter/kis_spriter_export.h +++ b/plugins/impex/spriter/kis_spriter_export.h @@ -1,134 +1,134 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_SPRITER_EXPORT_H_ #define _KIS_SPRITER_EXPORT_H_ #include #include #include #include #include struct SpriterFile { qreal id; QString name; QString pathName; QString baseName; QString layerName; qreal width; qreal height; qreal x; qreal y; }; struct Folder { qreal id; QString name; QString pathName; QString baseName; QString groupName; QList files; }; struct Bone { qreal id; const Bone *parentBone; QString name; qreal x; qreal y; qreal width; qreal height; qreal localX; qreal localY; qreal localAngle; qreal localScaleX; qreal localScaleY; qreal fixLocalX; qreal fixLocalY; qreal fixLocalAngle; qreal fixLocalScaleX; qreal fixLocalScaleY; QList bones; ~Bone() { qDeleteAll(bones); bones.clear();; } }; struct SpriterSlot { QString name; bool defaultAttachmentFlag; }; struct SpriterObject { qreal id; qreal folderId; qreal fileId; Bone *bone; SpriterSlot *slot; qreal x; qreal y; qreal localX; qreal localY; qreal localAngle; qreal localScaleX; qreal localScaleY; qreal fixLocalX; qreal fixLocalY; qreal fixLocalAngle; qreal fixLocalScaleX; qreal fixLocalScaleY; ~SpriterObject() { delete slot; } }; class KisSpriterExport : public KisImportExportFilter { Q_OBJECT public: KisSpriterExport(QObject *parent, const QVariantList &); virtual ~KisSpriterExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); private: bool savePaintDevice(KisPaintDeviceSP dev, const QString &fileName); void parseFolder(KisGroupLayerSP parentGroup, const QString &folderName, const QString &basePath); Bone *parseBone(const Bone *parent, KisGroupLayerSP groupLayer); void fixBone(Bone *bone); void fillScml(QDomDocument &scml, const QString &entityName); void writeBoneRef(const Bone *bone, QDomElement &mainline, QDomDocument &scml); void writeBone(const Bone *bone, QDomElement &timeline, QDomDocument &scml); KisImageWSP m_image; qreal m_timelineid; QList m_folders; Bone *m_rootBone; QList m_objects; KisGroupLayerSP m_rootLayer; // Not the image's root later, but the one that is named "root" KisLayerSP m_boneLayer; }; #endif diff --git a/plugins/impex/tga/kis_tga_export.cpp b/plugins/impex/tga/kis_tga_export.cpp index c895d95b9a..c17b524a1a 100644 --- a/plugins/impex/tga/kis_tga_export.cpp +++ b/plugins/impex/tga/kis_tga_export.cpp @@ -1,101 +1,101 @@ /* * Copyright (c) 2007 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_tga_export.h" #include #include #include #include #include #include #include #include #include #include #include #include "tga.h" K_PLUGIN_FACTORY_WITH_JSON(KisTGAExportFactory, "krita_tga_export.json", registerPlugin();) KisTGAExport::KisTGAExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisTGAExport::~KisTGAExport() { } -KisImportExportFilter::ConversionStatus KisTGAExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisTGAExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "TGA export! From:" << from << ", To:" << to << ""; KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); QRect rc = input->image()->bounds(); QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); QFile f(filename); f.open(QIODevice::WriteOnly); QDataStream s(&f); s.setByteOrder(QDataStream::LittleEndian); const QImage& img = image; const bool hasAlpha = (img.format() == QImage::Format_ARGB32); for (int i = 0; i < 12; i++) s << targaMagic[i]; // write header s << quint16(img.width()); // width s << quint16(img.height()); // height s << quint8(hasAlpha ? 32 : 24); // depth (24 bit RGB + 8 bit alpha) s << quint8(hasAlpha ? 0x24 : 0x20); // top left image (0x20) + 8 bit alpha (0x4) for (int y = 0; y < img.height(); y++) { for (int x = 0; x < img.width(); x++) { const QRgb color = img.pixel(x, y); s << quint8(qBlue(color)); s << quint8(qGreen(color)); s << quint8(qRed(color)); if (hasAlpha) s << quint8(qAlpha(color)); } } return KisImportExportFilter::OK; } #include "kis_tga_export.moc" diff --git a/plugins/impex/tga/kis_tga_export.h b/plugins/impex/tga/kis_tga_export.h index 414eb26bf0..126e1609f2 100644 --- a/plugins/impex/tga/kis_tga_export.h +++ b/plugins/impex/tga/kis_tga_export.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_TGA_EXPORT_H_ #define _KIS_TGA_EXPORT_H_ #include #include class KisTGAExport : public KisImportExportFilter { Q_OBJECT public: KisTGAExport(QObject *parent, const QVariantList &); virtual ~KisTGAExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/tga/kis_tga_import.cpp b/plugins/impex/tga/kis_tga_import.cpp index 3a02e6269d..b3ca7c3137 100644 --- a/plugins/impex/tga/kis_tga_import.cpp +++ b/plugins/impex/tga/kis_tga_import.cpp @@ -1,304 +1,305 @@ /* * Copyright (c) 2007 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_tga_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisTGAImportFactory, "krita_tga_import.json", registerPlugin();) -KisTGAImport::KisTGAImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) +KisTGAImport::KisTGAImport(QObject *parent, const QVariantList &) + : KisImportExportFilter(parent) { } KisTGAImport::~KisTGAImport() { } static QDataStream & operator>> (QDataStream & s, TgaHeader & head) { s >> head.id_length; s >> head.colormap_type; s >> head.image_type; s >> head.colormap_index; s >> head.colormap_length; s >> head.colormap_size; s >> head.x_origin; s >> head.y_origin; s >> head.width; s >> head.height; s >> head.pixel_size; s >> head.flags; /*dbgKrita << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type; dbgKrita << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size; dbgKrita << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize: " << head.pixel_size << " - flags: " << head.flags;*/ return s; } static bool isSupported(const TgaHeader & head) { if (head.image_type != TGA_TYPE_INDEXED && head.image_type != TGA_TYPE_RGB && head.image_type != TGA_TYPE_GREY && head.image_type != TGA_TYPE_RLE_INDEXED && head.image_type != TGA_TYPE_RLE_RGB && head.image_type != TGA_TYPE_RLE_GREY) { return false; } if (head.image_type == TGA_TYPE_INDEXED || head.image_type == TGA_TYPE_RLE_INDEXED) { if (head.colormap_length > 256 || head.colormap_size != 24 || head.colormap_type != 1) { return false; } } if (head.image_type == TGA_TYPE_RGB || head.image_type == TGA_TYPE_GREY || head.image_type == TGA_TYPE_RLE_RGB || head.image_type == TGA_TYPE_RLE_GREY) { if (head.colormap_type != 0) { return false; } } if (head.width == 0 || head.height == 0) { return false; } if (head.pixel_size != 8 && head.pixel_size != 16 && head.pixel_size != 24 && head.pixel_size != 32) { return false; } return true; } static bool loadTGA(QDataStream & s, const TgaHeader & tga, QImage &img) { // Create image. img = QImage(tga.width, tga.height, QImage::Format_RGB32); TgaHeaderInfo info(tga); // However alpha exists only in the 32 bit format. if ((tga.pixel_size == 32) && (tga.flags & 0xf)) { img = QImage(tga.width, tga.height, QImage::Format_ARGB32); } uint pixel_size = (tga.pixel_size / 8); uint size = tga.width * tga.height * pixel_size; if (size < 1) { dbgFile << "This TGA file is broken with size " << size; return false; } // Read palette. char palette[768]; if (info.pal) { // @todo Support palettes in other formats! s.readRawData(palette, 3 * tga.colormap_length); } // Allocate image. uchar * const image = new uchar[size]; if (info.rle) { // Decode image. char * dst = (char *)image; int num = size; while (num > 0) { // Get packet header. uchar c; s >> c; uint count = (c & 0x7f) + 1; num -= count * pixel_size; if (c & 0x80) { // RLE pixels. Q_ASSERT(pixel_size <= 8); char pixel[8]; s.readRawData(pixel, pixel_size); do { memcpy(dst, pixel, pixel_size); dst += pixel_size; } while (--count); } else { // Raw pixels. count *= pixel_size; s.readRawData(dst, count); dst += count; } } } else { // Read raw image. s.readRawData((char *)image, size); } // Convert image to internal format. int y_start, y_step, y_end; if (tga.flags & TGA_ORIGIN_UPPER) { y_start = 0; y_step = 1; y_end = tga.height; } else { y_start = tga.height - 1; y_step = -1; y_end = -1; } uchar* src = image; for (int y = y_start; y != y_end; y += y_step) { QRgb * scanline = (QRgb *) img.scanLine(y); if (info.pal) { // Paletted. for (int x = 0; x < tga.width; x++) { uchar idx = *src++; scanline[x] = qRgb(palette[3 * idx + 2], palette[3 * idx + 1], palette[3 * idx + 0]); } } else if (info.grey) { // Greyscale. for (int x = 0; x < tga.width; x++) { scanline[x] = qRgb(*src, *src, *src); src++; } } else { // True Color. if (tga.pixel_size == 16) { for (int x = 0; x < tga.width; x++) { Color555 c = *reinterpret_cast(src); scanline[x] = qRgb((c.r << 3) | (c.r >> 2), (c.g << 3) | (c.g >> 2), (c.b << 3) | (c.b >> 2)); src += 2; } } else if (tga.pixel_size == 24) { for (int x = 0; x < tga.width; x++) { scanline[x] = qRgb(src[2], src[1], src[0]); src += 3; } } else if (tga.pixel_size == 32) { for (int x = 0; x < tga.width; x++) { const uchar alpha = src[3]; scanline[x] = qRgba(src[2], src[1], src[0], alpha); src += 4; } } } } // Free image. delete []image; return true; } -KisImportExportFilter::ConversionStatus KisTGAImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisTGAImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "TGA import! From:" << from << ", To:" << to << 0; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc->prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } QFile f(filename); f.open(QIODevice::ReadOnly); QDataStream s(&f); s.setByteOrder(QDataStream::LittleEndian); TgaHeader tga; s >> tga; s.device()->seek(TgaHeader::SIZE + tga.id_length); // Check image file format. if (s.atEnd()) { return KisImportExportFilter::InvalidFormat; } // Check supported file types. if (!isSupported(tga)) { return KisImportExportFilter::InvalidFormat; } QImage img; bool result = loadTGA(s, tga, img); if (result == false) { return KisImportExportFilter::CreationError; } const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(doc->createUndoStore(), img.width(), img.height(), colorSpace, "imported from tga"); KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255); layer->paintDevice()->convertFromQImage(img, 0, 0, 0); image->addNode(layer.data(), image->rootLayer().data()); doc->setCurrentImage(image); return KisImportExportFilter::OK; } return KisImportExportFilter::StorageCreationError; } #include "kis_tga_import.moc" diff --git a/plugins/impex/tga/kis_tga_import.h b/plugins/impex/tga/kis_tga_import.h index 53fe89649d..f7828581af 100644 --- a/plugins/impex/tga/kis_tga_import.h +++ b/plugins/impex/tga/kis_tga_import.h @@ -1,37 +1,37 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_TGA_IMPORT_H_ #define _KIS_TGA_IMPORT_H_ #include #include class KisTGAImport : public KisImportExportFilter { Q_OBJECT public: KisTGAImport(QObject *parent, const QVariantList &); virtual ~KisTGAImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/tiff/kis_dlg_options_tiff.cpp b/plugins/impex/tiff/kis_dlg_options_tiff.cpp index 63fa0038bd..4dbe04e97a 100644 --- a/plugins/impex/tiff/kis_dlg_options_tiff.cpp +++ b/plugins/impex/tiff/kis_dlg_options_tiff.cpp @@ -1,160 +1,172 @@ /* * Copyright (c) 2005 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. */ #include "kis_dlg_options_tiff.h" #include #include #include #include #include #include #include +#include +#include +#include + #include #include - -#include "ui_kis_wdg_options_tiff.h" - -KisDlgOptionsTIFF::KisDlgOptionsTIFF(QWidget *parent) - : KoDialog(parent), wdg(new QWidget) +KisTIFFOptionsWidget::KisTIFFOptionsWidget(QWidget *parent) + : KisConfigWidget(parent) { - setWindowTitle(i18n("TIFF Export Options")); - setButtons(KoDialog::Ok | KoDialog::Cancel); - optionswdg = new Ui_KisWdgOptionsTIFF(); - optionswdg->setupUi(wdg); + setupUi(this); activated(0); - connect(optionswdg->kComboBoxCompressionType, SIGNAL(activated(int)), this, SLOT(activated(int))); - connect(optionswdg->flatten, SIGNAL(toggled(bool)), this, SLOT(flattenToggled(bool))); - setMainWidget(wdg); + connect(kComboBoxCompressionType, SIGNAL(activated(int)), this, SLOT(activated(int))); + connect(flatten, SIGNAL(toggled(bool)), this, SLOT(flattenToggled(bool))); QApplication::restoreOverrideCursor(); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); - - QString filterConfig = KisConfig().exportConfiguration("TIFF"); - KisPropertiesConfiguration cfg; - cfg.fromXML(filterConfig); - - optionswdg->kComboBoxCompressionType->setCurrentIndex(cfg.getInt("compressiontype", 0)); - activated(optionswdg->kComboBoxCompressionType->currentIndex()); - optionswdg->kComboBoxPredictor->setCurrentIndex(cfg.getInt("predictor", 0)); - optionswdg->alpha->setChecked(cfg.getBool("alpha", true)); - optionswdg->flatten->setChecked(cfg.getBool("flatten", true)); - flattenToggled(optionswdg->flatten->isChecked()); - optionswdg->qualityLevel->setValue(cfg.getInt("quality", 80)); - optionswdg->compressionLevelDeflate->setValue(cfg.getInt("deflate", 6)); - optionswdg->kComboBoxFaxMode->setCurrentIndex(cfg.getInt("faxmode", 0)); - optionswdg->compressionLevelPixarLog->setValue(cfg.getInt("pixarlog", 6)); - optionswdg->chkSaveProfile->setChecked(cfg.getBool("saveProfile", true)); } -KisDlgOptionsTIFF::~KisDlgOptionsTIFF() +KisTIFFOptionsWidget::~KisTIFFOptionsWidget() { delete optionswdg; } -void KisDlgOptionsTIFF::activated(int index) +void KisTIFFOptionsWidget::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + kComboBoxCompressionType->setCurrentIndex(cfg->getInt("compressiontype", 0)); + activated(kComboBoxCompressionType->currentIndex()); + kComboBoxPredictor->setCurrentIndex(cfg->getInt("predictor", 0)); + alpha->setChecked(cfg->getBool("alpha", true)); + flatten->setChecked(cfg->getBool("flatten", true)); + flattenToggled(flatten->isChecked()); + qualityLevel->setValue(cfg->getInt("quality", 80)); + compressionLevelDeflate->setValue(cfg->getInt("deflate", 6)); + kComboBoxFaxMode->setCurrentIndex(cfg->getInt("faxmode", 0)); + compressionLevelPixarLog->setValue(cfg->getInt("pixarlog", 6)); + chkSaveProfile->setChecked(cfg->getBool("saveProfile", true)); + + if (cfg->getInt("type", -1) == KoChannelInfo::FLOAT16 || cfg->getInt("type", -1) == KoChannelInfo::FLOAT32) { + kComboBoxPredictor->removeItem(1); + } else { + kComboBoxPredictor->removeItem(2); + } + + if (cfg->getBool("isCMYK")) { + alpha->setChecked(false); + alpha->setEnabled(false); + } + + +} + +KisPropertiesConfigurationSP KisTIFFOptionsWidget::configuration() const +{ + KisTIFFOptions opts = options(); + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + cfg->setProperty("compressiontype", kComboBoxCompressionType->currentIndex()); + cfg->setProperty("predictor", opts.predictor - 1); + cfg->setProperty("alpha", opts.alpha); + cfg->setProperty("flatten", opts.flatten); + cfg->setProperty("quality", opts.jpegQuality); + cfg->setProperty("deflate", opts.deflateCompress); + cfg->setProperty("faxmode", opts.faxMode - 1); + cfg->setProperty("pixarlog", opts.pixarLogCompress); + cfg->setProperty("saveProfile", opts.saveProfile); + + return cfg; +} + +void KisTIFFOptionsWidget::activated(int index) { switch (index) { case 1: - optionswdg->codecsOptionsStack->setCurrentIndex(1); + codecsOptionsStack->setCurrentIndex(1); break; case 2: - optionswdg->codecsOptionsStack->setCurrentIndex(2); + codecsOptionsStack->setCurrentIndex(2); break; case 6: - optionswdg->codecsOptionsStack->setCurrentIndex(3); + codecsOptionsStack->setCurrentIndex(3); break; case 8: - optionswdg->codecsOptionsStack->setCurrentIndex(4); + codecsOptionsStack->setCurrentIndex(4); break; default: - optionswdg->codecsOptionsStack->setCurrentIndex(0); + codecsOptionsStack->setCurrentIndex(0); } } -void KisDlgOptionsTIFF::flattenToggled(bool t) +void KisTIFFOptionsWidget::flattenToggled(bool t) { - optionswdg->alpha->setEnabled(t); + alpha->setEnabled(t); if (!t) { - optionswdg->alpha->setChecked(true); + alpha->setChecked(true); } } - -KisTIFFOptions KisDlgOptionsTIFF::options() +KisTIFFOptions KisTIFFOptionsWidget::options() const { KisTIFFOptions options; - switch (optionswdg->kComboBoxCompressionType->currentIndex()) { + switch (kComboBoxCompressionType->currentIndex()) { case 0: options.compressionType = COMPRESSION_NONE; break; case 1: options.compressionType = COMPRESSION_JPEG; break; case 2: options.compressionType = COMPRESSION_DEFLATE; break; case 3: options.compressionType = COMPRESSION_LZW; break; case 4: options.compressionType = COMPRESSION_JP2000; break; case 5: options.compressionType = COMPRESSION_CCITTRLE; break; case 6: options.compressionType = COMPRESSION_CCITTFAX3; break; case 7: options.compressionType = COMPRESSION_CCITTFAX4; break; case 8: options.compressionType = COMPRESSION_PIXARLOG; break; default: options.compressionType = COMPRESSION_NONE; } - options.predictor = optionswdg->kComboBoxPredictor->currentIndex() + 1; - options.alpha = optionswdg->alpha->isChecked(); - options.flatten = optionswdg->flatten->isChecked(); - options.jpegQuality = optionswdg->qualityLevel->value(); - options.deflateCompress = optionswdg->compressionLevelDeflate->value(); - options.faxMode = optionswdg->kComboBoxFaxMode->currentIndex() + 1; - options.pixarLogCompress = optionswdg->compressionLevelPixarLog->value(); - options.saveProfile = optionswdg->chkSaveProfile->isChecked(); - - KisPropertiesConfiguration cfg; - cfg.setProperty("compressiontype", optionswdg->kComboBoxCompressionType->currentIndex()); - cfg.setProperty("predictor", options.predictor - 1); - cfg.setProperty("alpha", options.alpha); - cfg.setProperty("flatten", options.flatten); - cfg.setProperty("quality", options.jpegQuality); - cfg.setProperty("deflate", options.deflateCompress); - cfg.setProperty("faxmode", options.faxMode - 1); - cfg.setProperty("pixarlog", options.pixarLogCompress); - cfg.setProperty("saveProfile", options.saveProfile); - - KisConfig().setExportConfiguration("TIFF", cfg); + options.predictor = kComboBoxPredictor->currentIndex() + 1; + options.alpha = alpha->isChecked(); + options.flatten = flatten->isChecked(); + options.jpegQuality = qualityLevel->value(); + options.deflateCompress = compressionLevelDeflate->value(); + options.faxMode = kComboBoxFaxMode->currentIndex() + 1; + options.pixarLogCompress = compressionLevelPixarLog->value(); + options.saveProfile = chkSaveProfile->isChecked(); return options; } diff --git a/plugins/impex/tiff/kis_dlg_options_tiff.h b/plugins/impex/tiff/kis_dlg_options_tiff.h index 74f20af10a..b7fb930b3a 100644 --- a/plugins/impex/tiff/kis_dlg_options_tiff.h +++ b/plugins/impex/tiff/kis_dlg_options_tiff.h @@ -1,45 +1,51 @@ /* * Copyright (c) 2005-2006 Cyrille Berger + * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_DLG_OPTIONS_TIFF_H #define KIS_DLG_OPTIONS_TIFF_H -#include #include +#include +#include "ui_kis_wdg_options_tiff.h" class Ui_KisWdgOptionsTIFF; /** @author Cyrille Berger */ -class KisDlgOptionsTIFF : public KoDialog +class KisTIFFOptionsWidget : public KisConfigWidget, public Ui::KisWdgOptionsTIFF { Q_OBJECT public: - KisDlgOptionsTIFF(QWidget *parent = 0); - ~KisDlgOptionsTIFF(); + KisTIFFOptionsWidget(QWidget *parent = 0); + ~KisTIFFOptionsWidget(); + + void setConfiguration(const KisPropertiesConfigurationSP cfg); + KisPropertiesConfigurationSP configuration() const; + public Q_SLOTS: void activated(int index); void flattenToggled(bool); - KisTIFFOptions options(); + KisTIFFOptions options() const; public: QWidget* wdg; Ui_KisWdgOptionsTIFF* optionswdg; }; #endif diff --git a/plugins/impex/tiff/kis_tiff_export.cc b/plugins/impex/tiff/kis_tiff_export.cc index f9c245381a..d1d9c0ca2c 100644 --- a/plugins/impex/tiff/kis_tiff_export.cc +++ b/plugins/impex/tiff/kis_tiff_export.cc @@ -1,127 +1,168 @@ /* * Copyright (c) 2005 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. */ #include "kis_tiff_export.h" #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include - +#include #include "kis_tiff_converter.h" #include "kis_dlg_options_tiff.h" #include "ui_kis_wdg_options_tiff.h" K_PLUGIN_FACTORY_WITH_JSON(KisTIFFExportFactory, "krita_tiff_export.json", registerPlugin();) KisTIFFExport::KisTIFFExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisTIFFExport::~KisTIFFExport() { } -KisImportExportFilter::ConversionStatus KisTIFFExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisTIFFExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Tiff export! From:" << from << ", To:" << to << ""; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisDocument *input = inputDocument(); if (!input) { return KisImportExportFilter::NoDocumentCreated; } - KisDlgOptionsTIFF dlg; - const KoColorSpace* cs = input->image()->colorSpace(); - KoChannelInfo::enumChannelValueType type = cs->channels()[0]->channelValueType(); - - if (type == KoChannelInfo::FLOAT16 || type == KoChannelInfo::FLOAT32) { - dlg.optionswdg->kComboBoxPredictor->removeItem(1); - } else { - dlg.optionswdg->kComboBoxPredictor->removeItem(2); + KoDialog kdb; + kdb.setWindowTitle(i18n("TIFF Export Options")); + kdb.setButtons(KoDialog::Ok | KoDialog::Cancel); + KisTIFFOptionsWidget *wdg = static_cast(createConfigurationWidget(&kdb, from, to)); + kdb.setMainWidget(wdg); + kdb.resize(kdb.minimumSize()); + + // If a configuration object was passed to the convert method, we use that, otherwise we load from the settings + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + if (configuration) { + cfg->fromXML(configuration->toXML()); } - - if (cs->colorModelId() == CMYKAColorModelID) { - dlg.optionswdg->alpha->setChecked(false); - dlg.optionswdg->alpha->setEnabled(false); + else { + cfg = lastSavedConfiguration(from, to); } + const KoColorSpace* cs = input->image()->colorSpace(); + cfg->setProperty("type", (int)cs->channels()[0]->channelValueType()); + cfg->setProperty("isCMYK", (cs->colorModelId() == CMYKAColorModelID)); + + wdg->setConfiguration(cfg); + if (!getBatchMode()) { - if (dlg.exec() == QDialog::Rejected) { + if (kdb.exec() == QDialog::Rejected) { return KisImportExportFilter::UserCancelled; } + cfg = wdg->configuration(); + KisConfig().setExportConfiguration("TIFF", *cfg.data()); } - KisTIFFOptions options = dlg.options(); + KisTIFFOptions options = wdg->options(); - if ((type == KoChannelInfo::FLOAT16 || type == KoChannelInfo::FLOAT32) && options.predictor == 2) { // FIXME THIS IS AN HACK FIX THAT IN 2.0 !! (62456a7b47636548c6507593df3e2bdf440f7544, BUG:135649) + if ((cs->channels()[0]->channelValueType() == KoChannelInfo::FLOAT16 + || cs->channels()[0]->channelValueType() == KoChannelInfo::FLOAT32) && options.predictor == 2) { + // FIXME THIS IS AN HACK FIX THAT IN 2.0 !! (62456a7b47636548c6507593df3e2bdf440f7544, BUG:135649) options.predictor = 3; } QString filename = outputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } KisImageSP image; if (options.flatten) { image = new KisImage(0, input->image()->width(), input->image()->height(), input->image()->colorSpace(), ""); image->setResolution(input->image()->xRes(), input->image()->yRes()); KisPaintDeviceSP pd = KisPaintDeviceSP(new KisPaintDevice(*input->image()->projection())); KisPaintLayerSP l = KisPaintLayerSP(new KisPaintLayer(image.data(), "projection", OPACITY_OPAQUE_U8, pd)); image->addNode(KisNodeSP(l.data()), image->rootLayer().data()); } else { image = input->image(); } // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); KisTIFFConverter ktc(input); KisImageBuilder_Result res; if ((res = ktc.buildFile(filename, image, options)) == KisImageBuilder_RESULT_OK) { dbgFile << "success !"; return KisImportExportFilter::OK; } dbgFile << " Result =" << res; return KisImportExportFilter::InternalError; } +KisPropertiesConfigurationSP KisTIFFExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); + cfg->setProperty("compressiontype", 0); + cfg->setProperty("predictor", 0); + cfg->setProperty("alpha", true); + cfg->setProperty("flatten", true); + cfg->setProperty("quality", 80); + cfg->setProperty("deflate", 6); + cfg->setProperty("faxmode", 0); + cfg->setProperty("pixarlog", 6); + cfg->setProperty("saveProfile", true); + + return cfg; +} + +KisPropertiesConfigurationSP KisTIFFExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + QString filterConfig = KisConfig().exportConfiguration("TIFF"); + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisTIFFExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const +{ + return new KisTIFFOptionsWidget(parent); +} + #include diff --git a/plugins/impex/tiff/kis_tiff_export.h b/plugins/impex/tiff/kis_tiff_export.h index 678b9df390..839f395af2 100644 --- a/plugins/impex/tiff/kis_tiff_export.h +++ b/plugins/impex/tiff/kis_tiff_export.h @@ -1,37 +1,41 @@ /* * Copyright (c) 2005 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_TIFF_EXPORT_H_ #define _KIS_TIFF_EXPORT_H_ #include #include +#include class KisTIFFExport : public KisImportExportFilter { Q_OBJECT public: KisTIFFExport(QObject *parent, const QVariantList &); virtual ~KisTIFFExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; }; #endif diff --git a/plugins/impex/tiff/kis_tiff_import.cc b/plugins/impex/tiff/kis_tiff_import.cc index e760ba0278..ffc179bfbd 100644 --- a/plugins/impex/tiff/kis_tiff_import.cc +++ b/plugins/impex/tiff/kis_tiff_import.cc @@ -1,99 +1,99 @@ /* * Copyright (c) 2005 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. */ #include "kis_tiff_import.h" #include #include #include #include #include #include #include "kis_tiff_converter.h" K_PLUGIN_FACTORY_WITH_JSON(TIFFImportFactory, "krita_tiff_import.json", registerPlugin();) KisTIFFImport::KisTIFFImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisTIFFImport::~KisTIFFImport() { } -KisImportExportFilter::ConversionStatus KisTIFFImport::convert(const QByteArray&, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisTIFFImport::convert(const QByteArray&, const QByteArray& to, KisPropertiesConfigurationSP configuration) { dbgFile << "Importing using TIFFImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); doc -> prepareForImport(); if (!filename.isEmpty()) { if (!QFileInfo(filename).exists()) { return KisImportExportFilter::FileNotFound; } KisTIFFConverter ib(doc); // if (view != 0) // view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); switch (ib.buildImage(filename)) { case KisImageBuilder_RESULT_UNSUPPORTED: return KisImportExportFilter::NotImplemented; case KisImageBuilder_RESULT_INVALID_ARG: return KisImportExportFilter::BadMimeType; case KisImageBuilder_RESULT_NO_URI: case KisImageBuilder_RESULT_NOT_LOCAL: return KisImportExportFilter::FileNotFound; case KisImageBuilder_RESULT_BAD_FETCH: case KisImageBuilder_RESULT_EMPTY: return KisImportExportFilter::ParsingError; case KisImageBuilder_RESULT_FAILURE: return KisImportExportFilter::InternalError; case KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE: return KisImportExportFilter::WrongFormat; case KisImageBuilder_RESULT_OK: doc -> setCurrentImage(ib.image()); return KisImportExportFilter::OK; default: break; } } return KisImportExportFilter::StorageCreationError; } #include diff --git a/plugins/impex/tiff/kis_tiff_import.h b/plugins/impex/tiff/kis_tiff_import.h index 02ab7d0f5c..54b4e2abed 100644 --- a/plugins/impex/tiff/kis_tiff_import.h +++ b/plugins/impex/tiff/kis_tiff_import.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2005 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_TIFF_IMPORT_H_ #define _KIS_TIFF_IMPORT_H_ #include #include class KisTIFFImport : public KisImportExportFilter { Q_OBJECT public: KisTIFFImport(QObject *parent, const QVariantList &); virtual ~KisTIFFImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); }; #endif diff --git a/plugins/impex/video/CMakeLists.txt b/plugins/impex/video/CMakeLists.txt index 9172d2f8d3..be546b37b1 100644 --- a/plugins/impex/video/CMakeLists.txt +++ b/plugins/impex/video/CMakeLists.txt @@ -1,21 +1,21 @@ include_directories(${Boost_INCLUDE_DIRS}) -add_subdirectory(tests) - # export +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + set(kritavideoexport_SOURCES kis_video_export.cpp video_saver.cpp video_export_options_dialog.cpp ) ki18n_wrap_ui(kritavideoexport_SOURCES video_export_options_dialog.ui ) add_library(kritavideoexport MODULE ${kritavideoexport_SOURCES}) generate_export_header(kritavideoexport BASE_NAME kritavideoexport) target_link_libraries(kritavideoexport kritaui) install(TARGETS kritavideoexport DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) diff --git a/plugins/impex/video/kis_video_export.cpp b/plugins/impex/video/kis_video_export.cpp index 4dcc782927..4ea8573ec4 100644 --- a/plugins/impex/video/kis_video_export.cpp +++ b/plugins/impex/video/kis_video_export.cpp @@ -1,135 +1,147 @@ /* * 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_video_export.h" #include #include #include #include #include #include +#include #include #include #include - +#include #include "KisPart.h" #include #include #include #include #include +#include +#include #include "video_saver.h" #include "video_export_options_dialog.h" -#include "kis_cursor_override_hijacker.h" + K_PLUGIN_FACTORY_WITH_JSON(KisVideoExportFactory, "krita_video_export.json", registerPlugin();) KisVideoExport::KisVideoExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisVideoExport::~KisVideoExport() { } -KisImportExportFilter::ConversionStatus KisVideoExport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisVideoExport::convert(const QByteArray &from, const QByteArray &to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(to); if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; - KisDocument* input = inputDocument(); + KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; - bool askForOptions = false; - - const QFileInfo fileInfo(filename); - const QString suffix = fileInfo.suffix().toLower(); - - VideoExportOptionsDialog::CodecIndex codecIndex = - VideoExportOptionsDialog::CODEC_H264; - - if (suffix == "mkv" || suffix == "mp4") { - codecIndex = VideoExportOptionsDialog::CODEC_H264; - askForOptions = true; - } else if (suffix == "ogv") { - codecIndex = VideoExportOptionsDialog::CODEC_THEORA; - askForOptions = true; - } - - QStringList additionalOptionsList; - - askForOptions &= - !qApp->applicationName().toLower().contains("test") & - !getBatchMode(); - - if (askForOptions) { - KisCursorOverrideHijacker badGuy; + VideoSaver videoSaver(input, getBatchMode()); - VideoExportOptionsDialog dlg; - dlg.setCodec(codecIndex); - - if (dlg.exec() == QDialog::Accepted) { - additionalOptionsList = dlg.customUserOptions(); - } else { - return KisImportExportFilter::UserCancelled; - } - } - - VideoSaver kpc(input, getBatchMode()); - - if (!kpc.hasFFMpeg()) { + if (!videoSaver.hasFFMpeg()) { const QString warningMessage = - i18n("Could not find \'ffmpeg\' binary. Saving to video formats is impossible."); + i18n("Couldn not find \'ffmpeg\' binary. Saving to video formats is impossible."); - if (askForOptions) { + if (!getBatchMode()) { QMessageBox::critical(KisPart::instance()->currentMainwindow(), i18n("Video Export Error"), warningMessage); - } else { - qWarning() << "WARNING:" << warningMessage; } - return KisImportExportFilter::UsageError; } - KisImageBuilder_Result res = kpc.encode(filename, additionalOptionsList); + KisImageBuilder_Result res = videoSaver.encode(filename, configuration); if (res == KisImageBuilder_RESULT_OK) { return KisImportExportFilter::OK; - } else if (res == KisImageBuilder_RESULT_CANCEL) { + } + else if (res == KisImageBuilder_RESULT_CANCEL) { return KisImportExportFilter::ProgressCancelled; } + else { + input->setErrorMessage(i18n("FFMpeg failed to convert the image sequence. Check the logfile in your output directory for more information.")); + } return KisImportExportFilter::InternalError; } +KisPropertiesConfigurationSP KisVideoExport::defaultConfiguration(const QByteArray &from, const QByteArray &to) const +{ + Q_UNUSED(from); + Q_ASSERT(!to.isEmpty()); + + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); + + cfg->setProperty("h264PresetIndex", 5); + cfg->setProperty("h264ConstantRateFactor", 23); + cfg->setProperty("h264ProfileIndex", 4); + cfg->setProperty("h264TuneIndex", 1); + cfg->setProperty("TheoraBitrate", 5000); + cfg->setProperty("CustomLineValue", ""); + + if (to == "video/ogg") { + cfg->setProperty("CodecIndex", VideoExportOptionsDialog::CODEC_THEORA); + } + else if (to == "video/x-matroska" || to == "video/mp4") { + cfg->setProperty("CodecIndex", VideoExportOptionsDialog::CODEC_H264); + } + cfg->setProperty("mimetype", to); + + return cfg; +} + +KisPropertiesConfigurationSP KisVideoExport::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const +{ + KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); + QString filterConfig = KisConfig().exportConfiguration("FFMPEG_CONFIG"); + cfg->fromXML(filterConfig, false); + return cfg; +} + +KisConfigWidget *KisVideoExport::createConfigurationWidget(QWidget *parent, const QByteArray &from, const QByteArray &to) const +{ + Q_UNUSED(from); + KisConfigWidget *w = 0; + if (to != "image/gif") { + w = new VideoExportOptionsDialog(parent); + } + return w; +} + #include "kis_video_export.moc" diff --git a/plugins/impex/video/kis_video_export.h b/plugins/impex/video/kis_video_export.h index db6cf2ee7e..9f6d28edc0 100644 --- a/plugins/impex/video/kis_video_export.h +++ b/plugins/impex/video/kis_video_export.h @@ -1,37 +1,41 @@ /* * 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_VIDEO_EXPORT_H_ #define _KIS_VIDEO_EXPORT_H_ #include #include class KisVideoExport : public KisImportExportFilter { Q_OBJECT public: KisVideoExport(QObject *parent, const QVariantList &); virtual ~KisVideoExport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); + + KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from, const QByteArray& to) const; + KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const; + KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const; }; #endif diff --git a/plugins/impex/video/krita_video_export.json b/plugins/impex/video/krita_video_export.json index dc949e0615..b6a2a16ede 100644 --- a/plugins/impex/video/krita_video_export.json +++ b/plugins/impex/video/krita_video_export.json @@ -1,13 +1,13 @@ { "Id": "Krita Video Export Filter", "NoDisplay": "true", "Type": "Service", "X-KDE-Export": "video/x-matroska,image/gif,video/ogg,video/mp4", "X-KDE-Import": "application/x-krita", "X-KDE-Library": "kritavideoexport", "X-KDE-ServiceTypes": [ - "Krita/FileFilter" + "Krita/AnimationExporter" ], "X-KDE-Weight": "1", "X-KDE-Extensions" : "mkv,gif,ogg,mp4" } diff --git a/plugins/impex/video/tests/CMakeLists.txt b/plugins/impex/video/tests/CMakeLists.txt deleted file mode 100644 index cb551bf389..0000000000 --- a/plugins/impex/video/tests/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) -include_directories( ${CMAKE_SOURCE_DIR}/sdk/tests ) - -macro_add_unittest_definitions() - -########### next target ############### -set(kis_video_plugin_test_SRCS kis_video_plugin_test.cpp ) - -kde4_add_unit_test(kis_video_plugin_test TESTNAME krita-plugins-formats-video_test ${kis_video_plugin_test_SRCS}) - -target_link_libraries(kis_video_plugin_test kritavideoexport kritaui Qt5::Test) diff --git a/plugins/impex/video/tests/data/test_animation_small.kra b/plugins/impex/video/tests/data/test_animation_small.kra deleted file mode 100644 index 1cd9b66f68..0000000000 Binary files a/plugins/impex/video/tests/data/test_animation_small.kra and /dev/null differ diff --git a/plugins/impex/video/tests/kis_video_plugin_test.cpp b/plugins/impex/video/tests/kis_video_plugin_test.cpp deleted file mode 100644 index 925355678d..0000000000 --- a/plugins/impex/video/tests/kis_video_plugin_test.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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_video_plugin_test.h" - - -#include -#include - -#include - -#include "filestest.h" - -#ifndef FILES_DATA_DIR -#error "FILES_DATA_DIR not set. A directory with the data used for testing the importing of files in krita" -#endif - -#include "../video_saver.h" - - -void KisVideoPluginTest::testFiles() -{ - QString fname = QString(FILES_DATA_DIR) + QDir::separator() + "test_animation_small.kra"; - - KisDocument *doc = KisPart::instance()->createDocument(); - doc->loadNativeFormat(fname); - - - VideoSaver saver(doc, false); - - KisImageBuilder_Result result = - //saver.encode("testfile.gif"); - saver.encode("testfile.ogg"); - - QCOMPARE(result, KisImageBuilder_RESULT_OK); -} -QTEST_MAIN(KisVideoPluginTest) - diff --git a/plugins/impex/video/video_export_options_dialog.cpp b/plugins/impex/video/video_export_options_dialog.cpp index 4f466ac189..05f367259f 100644 --- a/plugins/impex/video/video_export_options_dialog.cpp +++ b/plugins/impex/video/video_export_options_dialog.cpp @@ -1,230 +1,243 @@ /* * 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 "video_export_options_dialog.h" #include "ui_video_export_options_dialog.h" #include #include #include struct VideoExportOptionsDialog::Private { Private() { presets << KoID("ultrafast", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "ultrafast")); presets << KoID("superfast", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "superfast")); presets << KoID("veryfast", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "veryfast")); presets << KoID("faster", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "faster")); presets << KoID("fast", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "fast")); presets << KoID("medium", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "medium")); presets << KoID("slow", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "slow")); presets << KoID("slower", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "slower")); presets << KoID("veryslow", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "veryslow")); presets << KoID("placebo", i18nc("h264 preset name, check simplescreenrecorder for standard translations", "placebo")); profiles << KoID("baseline", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "baseline")); profiles << KoID("main", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "main")); profiles << KoID("high", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "high")); profiles << KoID("high10", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "high10")); profiles << KoID("high422", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "high422")); profiles << KoID("high444", i18nc("h264 profile name, check simplescreenrecorder for standard translations", "high444")); tunes << KoID("film", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "film")); tunes << KoID("animation", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "animation")); tunes << KoID("grain", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "grain")); tunes << KoID("stillimage", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "stillimage")); tunes << KoID("psnr", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "psnr")); tunes << KoID("ssim", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "ssim")); tunes << KoID("fastdecode", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "fastdecode")); tunes << KoID("zerolatency", i18nc("h264 tune option name, check simplescreenrecorder for standard translations", "zerolatency")); - - - KConfigGroup cfg = KSharedConfig::openConfig()->group("VideoExportPlugin"); - - defaultPreset = cfg.readEntry("h264PresetIndex", 5); - defaultConstantRateFactor = cfg.readEntry("h264ConstantRateFactor", 23); - defaultProfile = cfg.readEntry("h264ProfileIndex", 4); - defaultTune = cfg.readEntry("h264TuneIndex", 1); - defaultBitrate = cfg.readEntry("TheoraBitrate", 5000); - defaultCustomLine = cfg.readEntry("CustomLineValue", ""); - } - - void updateDefaultCustomLine() { - KConfigGroup cfg = KSharedConfig::openConfig()->group("VideoExportPlugin"); - defaultCustomLine = cfg.readEntry("CustomLineValue", ""); } QVector presets; int defaultPreset; int defaultBitrate; int defaultConstantRateFactor; QVector profiles; int defaultProfile; QVector tunes; int defaultTune; QString defaultCustomLine; + QString currentCustomLine; + + void updateDefaultCustomLine() + { + defaultCustomLine = currentCustomLine; + } + }; VideoExportOptionsDialog::VideoExportOptionsDialog(QWidget *parent) : - QDialog(parent), + KisConfigWidget(parent), ui(new Ui::VideoExportOptionsDialog), m_d(new Private) { ui->setupUi(this); ui->intConstantRateFactor->setRange(0, 51); ui->intConstantRateFactor->setValue(m_d->defaultConstantRateFactor); Q_FOREACH (const KoID &preset, m_d->presets) { ui->cmbPreset->insertItem(ui->cmbPreset->count(), preset.name()); } ui->cmbPreset->setCurrentIndex(m_d->defaultPreset); Q_FOREACH (const KoID &profile, m_d->profiles) { ui->cmbProfile->insertItem(ui->cmbProfile->count(), profile.name()); } ui->cmbProfile->setCurrentIndex(m_d->defaultProfile); Q_FOREACH (const KoID &tune, m_d->tunes) { ui->cmbTune->insertItem(ui->cmbTune->count(), tune.name()); } ui->cmbTune->setCurrentIndex(m_d->defaultTune); ui->intBitrate->setRange(10, 50000); ui->intBitrate->setValue(5000); ui->intBitrate->setSuffix(i18nc("kilo-bits-per-second, video bitrate suffix", "kbps")); - connect(ui->cmbCodec, SIGNAL(currentIndexChanged(int)), - ui->stackedWidget, SLOT(setCurrentIndex(int))); + connect(ui->cmbCodec, SIGNAL(currentIndexChanged(int)), ui->stackedWidget, SLOT(setCurrentIndex(int))); ui->cmbCodec->setCurrentIndex(0); ui->cmbCodec->setEnabled(false); // TODO: temporarily hidden! Some combinations of 'tune' and // 'profile' options make ffmpeg generate empty file. // We should not let the user shoot into his own foot! ui->cmbTune->setVisible(false); ui->lblTune->setVisible(false); - setModal(true); - connect(this, SIGNAL(accepted()), SLOT(slotAccepted())); - ui->chkCustomLine->setChecked(!m_d->defaultCustomLine.isEmpty()); slotCustomLineToggled(!m_d->defaultCustomLine.isEmpty()); connect(ui->chkCustomLine, SIGNAL(toggled(bool)), SLOT(slotCustomLineToggled(bool))); - connect(ui->txtCustomLine, SIGNAL(editingFinished()), SLOT(slotSaveCustomLine())); connect(ui->btnResetCustomLine, SIGNAL(clicked()), SLOT(slotResetCustomLine())); } VideoExportOptionsDialog::~VideoExportOptionsDialog() { delete ui; } -void VideoExportOptionsDialog::slotAccepted() +KisPropertiesConfigurationSP VideoExportOptionsDialog::configuration() const { - KConfigGroup cfg = KSharedConfig::openConfig()->group("VideoExportPlugin"); + KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration()); - cfg.writeEntry("h264PresetIndex", ui->cmbPreset->currentIndex()); - cfg.writeEntry("h264ConstantRateFactor", ui->intConstantRateFactor->value()); - cfg.writeEntry("h264ProfileIndex", ui->cmbProfile->currentIndex()); - cfg.writeEntry("h264TuneIndex", ui->cmbTune->currentIndex()); - cfg.writeEntry("TheoraBitrate", ui->intBitrate->value()); - slotSaveCustomLine(); + cfg->setProperty("h264PresetIndex", ui->cmbPreset->currentIndex()); + cfg->setProperty("h264ConstantRateFactor", ui->intConstantRateFactor->value()); + cfg->setProperty("h264ProfileIndex", ui->cmbProfile->currentIndex()); + cfg->setProperty("h264TuneIndex", ui->cmbTune->currentIndex()); + cfg->setProperty("TheoraBitrate", ui->intBitrate->value()); + cfg->setProperty("CustomLineValue", ui->txtCustomLine->text()); + cfg->setProperty("customUserOptions", customUserOptions().join(' ')); + + return cfg; } void VideoExportOptionsDialog::slotCustomLineToggled(bool value) { m_d->updateDefaultCustomLine(); QString customLine = m_d->defaultCustomLine; if (customLine.isEmpty() && value) { customLine = generateCustomLine().join(" "); } else if (!value) { customLine = ""; } ui->txtCustomLine->setText(customLine); ui->stackedWidget->setEnabled(!value); ui->txtCustomLine->setEnabled(value); ui->btnResetCustomLine->setEnabled(value); } -void VideoExportOptionsDialog::slotSaveCustomLine() -{ - KConfigGroup cfg = KSharedConfig::openConfig()->group("VideoExportPlugin"); - cfg.writeEntry("CustomLineValue", ui->txtCustomLine->text()); -} - void VideoExportOptionsDialog::slotResetCustomLine() { ui->txtCustomLine->setText(generateCustomLine().join(" ")); slotSaveCustomLine(); } +void VideoExportOptionsDialog::slotSaveCustomLine() +{ + m_d->currentCustomLine = ui->txtCustomLine->text(); +} + void VideoExportOptionsDialog::setCodec(CodecIndex index) { ui->cmbCodec->setCurrentIndex(int(index)); } QStringList VideoExportOptionsDialog::customUserOptions() const { return ui->chkCustomLine->isChecked() ? ui->txtCustomLine->text().split(" ", QString::SkipEmptyParts) : - generateCustomLine(); + generateCustomLine(); +} + +void VideoExportOptionsDialog::setConfiguration(const KisPropertiesConfigurationSP cfg) +{ + m_d->defaultPreset = cfg->getInt("h264PresetIndex", 5); + ui->cmbPreset->setCurrentIndex(m_d->defaultPreset); + m_d->defaultConstantRateFactor = cfg->getInt("h264ConstantRateFactor", 23); + ui->intConstantRateFactor->setValue(m_d->defaultConstantRateFactor); + m_d->defaultProfile = cfg->getInt("h264ProfileIndex", 4); + ui->cmbProfile->setCurrentIndex(m_d->defaultProfile); + m_d->defaultTune = cfg->getInt("h264TuneIndex", 1); + ui->cmbTune->setCurrentIndex(m_d->defaultTune); + m_d->defaultBitrate = cfg->getInt("TheoraBitrate", 5000); + ui->intBitrate->setValue(m_d->defaultBitrate); + m_d->defaultCustomLine = cfg->getString("CustomLineValue", ""); + ui->txtCustomLine->setText(m_d->defaultCustomLine); + + if (cfg->hasProperty("CodecIndex")) { + setCodec((VideoExportOptionsDialog::CodecIndex)cfg->getInt("CodecIndex")); + } + if (cfg->getString("mimetype") == "video/ogg") { + ui->cmbCodec->setEnabled(false); + } } QStringList VideoExportOptionsDialog::generateCustomLine() const { QStringList options; if (ui->cmbCodec->currentIndex() == int(CODEC_H264)) { options << "-crf" << QString::number(ui->intConstantRateFactor->value()); const int presetIndex = ui->cmbPreset->currentIndex(); + //qDebug() << "presetIndex" << presetIndex << m_d->presets; options << "-preset" << m_d->presets[presetIndex].id(); const int profileIndex = ui->cmbProfile->currentIndex(); options << "-profile" << m_d->profiles[profileIndex].id(); if (m_d->profiles[profileIndex].id() == "high422") { options << "-pix_fmt" << "yuv422p"; } else if (m_d->profiles[profileIndex].id() == "high444") { options << "-pix_fmt" << "yuv444p"; } else { options << "-pix_fmt" << "yuv420p"; } // Disabled! see the comment in c-tor! //const int tuneIndex = ui->cmbTune->currentIndex(); //options << "-tune" << m_d->tunes[tuneIndex].id(); } else if (ui->cmbCodec->currentIndex() == int(CODEC_THEORA)) { options << "-b" << QString::number(ui->intBitrate->value()) + "k"; } return options; } diff --git a/plugins/impex/video/video_export_options_dialog.h b/plugins/impex/video/video_export_options_dialog.h index 0c59b0f649..4bc0763567 100644 --- a/plugins/impex/video/video_export_options_dialog.h +++ b/plugins/impex/video/video_export_options_dialog.h @@ -1,66 +1,70 @@ /* * 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 VIDEO_EXPORT_OPTIONS_DIALOG_H #define VIDEO_EXPORT_OPTIONS_DIALOG_H -#include +#include +#include + #include "video_saver.h" #include namespace Ui { class VideoExportOptionsDialog; } -class VideoExportOptionsDialog : public QDialog +class VideoExportOptionsDialog : public KisConfigWidget { Q_OBJECT public: enum CodecIndex { CODEC_H264 = 0, CODEC_THEORA }; public: explicit VideoExportOptionsDialog(QWidget *parent = 0); ~VideoExportOptionsDialog(); void setCodec(CodecIndex index); QStringList customUserOptions() const; + void setConfiguration(const KisPropertiesConfigurationSP config); + KisPropertiesConfigurationSP configuration() const; + private Q_SLOTS: - void slotAccepted(); void slotCustomLineToggled(bool value); void slotSaveCustomLine(); void slotResetCustomLine(); private: Ui::VideoExportOptionsDialog *ui; private: QStringList generateCustomLine() const; private: struct Private; const QScopedPointer m_d; }; #endif // VIDEO_EXPORT_OPTIONS_DIALOG_H diff --git a/plugins/impex/video/video_export_options_dialog.ui b/plugins/impex/video/video_export_options_dialog.ui index 21a85e0c63..dfb0453c4a 100644 --- a/plugins/impex/video/video_export_options_dialog.ui +++ b/plugins/impex/video/video_export_options_dialog.ui @@ -1,209 +1,163 @@ VideoExportOptionsDialog - + 0 0 - 505 - 333 + 273 + 323 - - Dialog - - + H.264, MPEG-4 Part 10 Theora 0 Constant Rate Factor: 0 0 Preset: Profile: Tune: Bitrate: 0 0 Custom Options: Add any ffmpeg filtering options here. It will be put between source and destination streams of the ffmpeg Reset Qt::Vertical QSizePolicy::MinimumExpanding 20 44 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - KisSliderSpinBox QWidget
kis_slider_spin_box.h
- - - buttonBox - accepted() - VideoExportOptionsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - VideoExportOptionsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - +
diff --git a/plugins/impex/video/video_saver.cpp b/plugins/impex/video/video_saver.cpp index c491779210..91abee9326 100644 --- a/plugins/impex/video/video_saver.cpp +++ b/plugins/impex/video/video_saver.cpp @@ -1,337 +1,321 @@ /* * 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 "video_saver.h" #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "kis_animation_exporter.h" #include #include #include #include #include #include #include "KisPart.h" class KisFFMpegProgressWatcher : public QObject { Q_OBJECT public: KisFFMpegProgressWatcher(QFile &progressFile, int totalFrames) : m_progressFile(progressFile), m_totalFrames(totalFrames) { connect(&m_progressWatcher, SIGNAL(fileChanged(QString)), SLOT(slotFileChanged())); m_progressWatcher.addPath(m_progressFile.fileName()); } private Q_SLOTS: void slotFileChanged() { - //qDebug() << "=== progress changed ==="; - int currentFrame = -1; bool isEnded = false; while(!m_progressFile.atEnd()) { QString line = QString(m_progressFile.readLine()).remove(QChar('\n')); QStringList var = line.split("="); if (var[0] == "frame") { currentFrame = var[1].toInt(); } else if (var[0] == "progress") { isEnded = var[1] == "end"; } - //qDebug() << var; } if (isEnded) { emit sigProgressChanged(100); emit sigProcessingFinished(); } else { emit sigProgressChanged(100 * currentFrame / m_totalFrames); } } Q_SIGNALS: void sigProgressChanged(int percent); void sigProcessingFinished(); private: QFileSystemWatcher m_progressWatcher; QFile &m_progressFile; int m_totalFrames; }; class KisFFMpegRunner { public: KisFFMpegRunner(const QString &ffmpegPath) : m_cancelled(false), m_ffmpegPath(ffmpegPath) {} public: KisImageBuilder_Result runFFMpeg(const QStringList &specialArgs, const QString &actionName, const QString &logPath, - int totalFrames) { + int totalFrames) + { +// qDebug() << "runFFMpeg: specialArgs" << specialArgs +// << "actionName" << actionName +// << "logPath" << logPath +// << "totalFrames" << totalFrames; QTemporaryFile progressFile("KritaFFmpegProgress.XXXXXX"); progressFile.open(); m_process.setStandardOutputFile(logPath); m_process.setProcessChannelMode(QProcess::MergedChannels); QStringList args; args << "-v" << "debug" << "-nostdin" << "-progress" << progressFile.fileName() << specialArgs; m_cancelled = false; m_process.start(m_ffmpegPath, args); return waitForFFMpegProcess(actionName, progressFile, m_process, totalFrames); } void cancel() { m_cancelled = true; m_process.kill(); } private: KisImageBuilder_Result waitForFFMpegProcess(const QString &message, QFile &progressFile, QProcess &ffmpegProcess, - int totalFrames) { + int totalFrames) + { KisFFMpegProgressWatcher watcher(progressFile, totalFrames); QProgressDialog progress(message, "", 0, 0, KisPart::instance()->currentMainwindow()); progress.setWindowModality(Qt::ApplicationModal); progress.setCancelButton(0); progress.setMinimumDuration(0); progress.setValue(0); progress.setRange(0,100); QEventLoop loop; loop.connect(&watcher, SIGNAL(sigProcessingFinished()), SLOT(quit())); loop.connect(&ffmpegProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(quit())); loop.connect(&watcher, SIGNAL(sigProgressChanged(int)), &progress, SLOT(setValue(int))); loop.exec(); // wait for some errorneous case ffmpegProcess.waitForFinished(5000); KisImageBuilder_Result retval = KisImageBuilder_RESULT_OK; if (ffmpegProcess.state() != QProcess::NotRunning) { // sorry... ffmpegProcess.kill(); retval = KisImageBuilder_RESULT_FAILURE; } else if (m_cancelled) { retval = KisImageBuilder_RESULT_CANCEL; } else if (ffmpegProcess.exitCode()) { retval = KisImageBuilder_RESULT_FAILURE; } return retval; } private: QProcess m_process; bool m_cancelled; QString m_ffmpegPath; }; VideoSaver::VideoSaver(KisDocument *doc, bool batchMode) : m_image(doc->image()) , m_doc(doc) , m_batchMode(batchMode) , m_ffmpegPath(findFFMpeg()) , m_runner(new KisFFMpegRunner(m_ffmpegPath)) { - } VideoSaver::~VideoSaver() { } KisImageSP VideoSaver::image() { return m_image; } bool VideoSaver::hasFFMpeg() const { return !m_ffmpegPath.isEmpty(); } QString VideoSaver::findFFMpeg() { QString result; QStringList proposedPaths; QString customPath = KisConfig().customFFMpegPath(); proposedPaths << customPath; proposedPaths << customPath + QDir::separator() + "ffmpeg"; proposedPaths << "ffmpeg"; proposedPaths << KoResourcePaths::getApplicationRoot() + QDir::separator() + "bin" + QDir::separator() + "ffmpeg"; Q_FOREACH (const QString &path, proposedPaths) { if (path.isEmpty()) continue; QProcess testProcess; testProcess.start(path, QStringList() << "-version"); testProcess.waitForFinished(1000); const bool successfulStart = testProcess.state() == QProcess::NotRunning && testProcess.error() == QProcess::UnknownError; if (successfulStart) { result = path; break; } } return result; } -KisImageBuilder_Result VideoSaver::encode(const QString &filename, const QStringList &additionalOptionsList) +KisImageBuilder_Result VideoSaver::encode(const QString &filename, KisPropertiesConfigurationSP configuration) { + + //qDebug() << "ffmpeg" << m_ffmpegPath << "filename" << filename << "configuration" << configuration->toXML(); + if (m_ffmpegPath.isEmpty()) return KisImageBuilder_RESULT_FAILURE; - KisImageBuilder_Result retval= KisImageBuilder_RESULT_OK; + KisImageBuilder_Result result = KisImageBuilder_RESULT_OK; KisImageAnimationInterface *animation = m_image->animationInterface(); - const KisTimeRange clipRange = animation->fullClipRange(); + const KisTimeRange fullRange = animation->fullClipRange(); + const KisTimeRange clipRange(configuration->getInt("firstframe", fullRange.start()), configuration->getInt("lastFrame"), fullRange.end()); const int frameRate = animation->framerate(); - const QString resultFile = filename; - const bool removeGeneratedFiles = - !qEnvironmentVariableIsSet("KRITA_KEEP_FRAMES"); + const QDir framesDir(configuration->getString("directory")); + const QString resultFile = framesDir.absolutePath() + "/" + filename; const QFileInfo info(resultFile); const QString suffix = info.suffix().toLower(); - const QString baseDirectory = info.absolutePath(); - const QString frameDirectoryTemplate = baseDirectory + QDir::separator() + "frames.XXXXXX"; - - QTemporaryDir framesDirImpl(frameDirectoryTemplate); - framesDirImpl.setAutoRemove(removeGeneratedFiles); - - const QDir framesDir(framesDirImpl.path()); - const QString framesPath = framesDir.path(); - const QString framesBasePath = framesDir.filePath("frame.png"); const QString palettePath = framesDir.filePath("palette.png"); - KisAnimationExportSaver saver(m_doc, framesBasePath, clipRange.start(), clipRange.end()); + const QString savedFilesMask = configuration->getString("savedFilesMask"); - KisImportExportFilter::ConversionStatus status = - saver.exportAnimation(); - - if (status == KisImportExportFilter::UserCancelled) { - return KisImageBuilder_RESULT_CANCEL; - } else if (status != KisImportExportFilter::OK) { - return KisImageBuilder_RESULT_FAILURE; - } + const QStringList additionalOptionsList = configuration->getString("customUserOptions").split(' ', QString::SkipEmptyParts); if (suffix == "gif") { { QStringList args; args << "-r" << QString::number(frameRate) - << "-i" << saver.savedFilesMask() + << "-i" << savedFilesMask << "-vf" << "palettegen" << "-y" << palettePath; KisImageBuilder_Result result = m_runner->runFFMpeg(args, i18n("Fetching palette..."), framesDir.filePath("log_palettegen.log"), clipRange.duration()); if (result) { return result; } } { QStringList args; args << "-r" << QString::number(frameRate) - << "-i" << saver.savedFilesMask() + << "-i" << savedFilesMask << "-i" << palettePath << "-lavfi" << "[0:v][1:v] paletteuse" << additionalOptionsList << "-y" << resultFile; KisImageBuilder_Result result = m_runner->runFFMpeg(args, i18n("Encoding frames..."), framesDir.filePath("log_paletteuse.log"), clipRange.duration()); if (result) { return result; } } } else { QStringList args; args << "-r" << QString::number(frameRate) - << "-i" << saver.savedFilesMask() + << "-i" << savedFilesMask << additionalOptionsList << "-y" << resultFile; - KisImageBuilder_Result result = - m_runner->runFFMpeg(args, i18n("Encoding frames..."), - framesDir.filePath("log_encode.log"), - clipRange.duration()); - - if (result) { - return result; - } + result = m_runner->runFFMpeg(args, i18n("Encoding frames..."), + framesDir.filePath("log_encode.log"), + clipRange.duration()); } - return retval; + return result; } void VideoSaver::cancel() { m_runner->cancel(); } #include "video_saver.moc" diff --git a/plugins/impex/video/video_saver.h b/plugins/impex/video/video_saver.h index 70ae221335..37dde67613 100644 --- a/plugins/impex/video/video_saver.h +++ b/plugins/impex/video/video_saver.h @@ -1,62 +1,63 @@ /* * 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 VIDEO_SAVER_H_ #define VIDEO_SAVER_H_ #include #include "kis_types.h" +#include #include "KisImageBuilderResult.h" #include "kritavideoexport_export.h" class KisFFMpegRunner; /* The KisImageBuilder_Result definitions come from kis_png_converter.h here */ class KisDocument; class KRITAVIDEOEXPORT_EXPORT VideoSaver : public QObject { Q_OBJECT public: VideoSaver(KisDocument* doc, bool batchMode); virtual ~VideoSaver(); KisImageSP image(); - KisImageBuilder_Result encode(const QString &filename, const QStringList &additionalOptionsList = QStringList()); + KisImageBuilder_Result encode(const QString &filename, KisPropertiesConfigurationSP configuration); bool hasFFMpeg() const; private Q_SLOTS: void cancel(); private: static QString findFFMpeg(); private: KisImageSP m_image; KisDocument* m_doc; bool m_batchMode; QString m_ffmpegPath; QScopedPointer m_runner; }; #endif diff --git a/plugins/impex/xcf/kis_xcf_import.cpp b/plugins/impex/xcf/kis_xcf_import.cpp index 3eed72096b..d7c6547c23 100644 --- a/plugins/impex/xcf/kis_xcf_import.cpp +++ b/plugins/impex/xcf/kis_xcf_import.cpp @@ -1,343 +1,343 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_xcf_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_iterator_ng.h" #include "kis_types.h" #include extern "C" { #include "xcftools.h" #include "pixels.h" #define GET_RED(x) (x >> RED_SHIFT) #define GET_GREEN(x) (x >> GREEN_SHIFT) #define GET_BLUE(x) (x >> BLUE_SHIFT) #define GET_ALPHA(x) (x >> ALPHA_SHIFT) } struct Layer { KisLayerSP layer; int depth; KisMaskSP mask; }; KisGroupLayerSP findGroup(const QVector &layers, const Layer& layer, int i) { for (; i < layers.size(); ++i) { KisGroupLayerSP group = dynamic_cast(const_cast(layers[i].layer.data())); if (group && (layers[i].depth == layer.depth -1)) { return group; } } return 0; } void addLayers(const QVector &layers, KisImageSP image, int depth) { for(int i = 0; i < layers.size(); i++) { const Layer &layer = layers[i]; if (layer.depth == depth) { KisGroupLayerSP group = (depth == 0 ? image->rootLayer() : findGroup(layers, layer, i)); image->addNode(layer.layer, group); if (layer.mask) { image->addNode(layer.mask, layer.layer); } } } } K_PLUGIN_FACTORY_WITH_JSON(XCFImportFactory, "krita_xcf_import.json", registerPlugin();) KisXCFImport::KisXCFImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisXCFImport::~KisXCFImport() { } -KisImportExportFilter::ConversionStatus KisXCFImport::convert(const QByteArray& from, const QByteArray& to) +KisImportExportFilter::ConversionStatus KisXCFImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(from); dbgFile << "Importing using XCFImport!"; if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; KisDocument * doc = outputDocument(); if (!doc) return KisImportExportFilter::NoDocumentCreated; QString filename = inputFile(); if (filename.isEmpty()) { return KisImportExportFilter::FileNotFound; } QFile fp(filename); if (fp.exists()) { doc->prepareForImport(); return loadFromDevice(&fp, doc); } return KisImportExportFilter::CreationError; } QString layerModeG2K(GimpLayerModeEffects mode) { switch (mode) { case GIMP_NORMAL_MODE: return COMPOSITE_OVER; case GIMP_DISSOLVE_MODE: return COMPOSITE_DISSOLVE; case GIMP_MULTIPLY_MODE: return COMPOSITE_MULT; case GIMP_SCREEN_MODE: return COMPOSITE_SCREEN; case GIMP_OVERLAY_MODE: case GIMP_SOFTLIGHT_MODE: return COMPOSITE_OVERLAY; case GIMP_DIFFERENCE_MODE: return COMPOSITE_DIFF; case GIMP_ADDITION_MODE: return COMPOSITE_ADD; case GIMP_SUBTRACT_MODE: return COMPOSITE_SUBTRACT; case GIMP_DARKEN_ONLY_MODE: return COMPOSITE_DARKEN; case GIMP_LIGHTEN_ONLY_MODE: return COMPOSITE_LIGHTEN; case GIMP_HUE_MODE: return COMPOSITE_HUE_HSL; case GIMP_SATURATION_MODE: return COMPOSITE_SATURATION_HSV; case GIMP_COLOR_MODE: return COMPOSITE_COLOR_HSL; case GIMP_VALUE_MODE: return COMPOSITE_VALUE; case GIMP_DIVIDE_MODE: return COMPOSITE_DIVIDE; case GIMP_DODGE_MODE: return COMPOSITE_DODGE; case GIMP_BURN_MODE: return COMPOSITE_BURN; case GIMP_ERASE_MODE: return COMPOSITE_ERASE; case GIMP_REPLACE_MODE: return COMPOSITE_COPY; case GIMP_HARDLIGHT_MODE: return COMPOSITE_HARD_LIGHT; case GIMP_COLOR_ERASE_MODE: case GIMP_NORMAL_NOPARTIAL_MODE: case GIMP_ANTI_ERASE_MODE: case GIMP_GRAIN_EXTRACT_MODE: return COMPOSITE_GRAIN_EXTRACT; case GIMP_GRAIN_MERGE_MODE: return COMPOSITE_GRAIN_MERGE; case GIMP_BEHIND_MODE: break; } dbgFile << "Unknown mode: " << mode; return COMPOSITE_OVER; } KisImportExportFilter::ConversionStatus KisXCFImport::loadFromDevice(QIODevice* device, KisDocument* doc) { dbgFile << "Start decoding file"; // Read the file into memory device->open(QIODevice::ReadOnly); QByteArray data = device->readAll(); xcf_file = (uint8_t*)data.data(); xcf_length = data.size(); device->close(); // Decode the data getBasicXcfInfo() ; initColormap(); dbgFile << XCF.version << "width = " << XCF.width << "height = " << XCF.height << "layers = " << XCF.numLayers; // Create the image KisImageSP image = new KisImage(doc->createUndoStore(), XCF.width, XCF.height, KoColorSpaceRegistry::instance()->rgb8(), "built image"); QVector layers; uint maxDepth = 0; // Read layers for (int i = 0; i < XCF.numLayers; ++i) { Layer layer; xcfLayer& xcflayer = XCF.layers[i]; dbgFile << i << " name = " << xcflayer.name << " opacity = " << xcflayer.opacity << "group:" << xcflayer.isGroup << xcflayer.pathLength; dbgFile << ppVar(xcflayer.dim.width) << ppVar(xcflayer.dim.height) << ppVar(xcflayer.dim.tilesx) << ppVar(xcflayer.dim.tilesy) << ppVar(xcflayer.dim.ntiles) << ppVar(xcflayer.dim.c.t) << ppVar(xcflayer.dim.c.l) << ppVar(xcflayer.dim.c.r) << ppVar(xcflayer.dim.c.b); maxDepth = qMax(maxDepth, xcflayer.pathLength); bool isRgbA = false; // Select the color space const KoColorSpace* colorSpace = 0; switch (xcflayer.type) { case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: case GIMP_RGB_IMAGE: case GIMP_RGBA_IMAGE: colorSpace = KoColorSpaceRegistry::instance()->rgb8(); isRgbA = true; break; case GIMP_GRAY_IMAGE: case GIMP_GRAYA_IMAGE: colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); isRgbA = false; break; } // Create the layer KisLayerSP kisLayer; if (xcflayer.isGroup) { kisLayer = new KisGroupLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity); } else { kisLayer = new KisPaintLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity, colorSpace); } // Set some properties kisLayer->setCompositeOpId(layerModeG2K(xcflayer.mode)); kisLayer->setVisible(xcflayer.isVisible); kisLayer->disableAlphaChannel(xcflayer.mode != GIMP_NORMAL_MODE); layer.layer = kisLayer; layer.depth = xcflayer.pathLength; // Copy the data in the image initLayer(&xcflayer); int left = xcflayer.dim.c.l; int top = xcflayer.dim.c.t; if (!xcflayer.isGroup) { // Copy the data; for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) { for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) { rect want; want.l = x + left; want.t = y + top; want.b = want.t + TILE_HEIGHT; want.r = want.l + TILE_WIDTH; Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.pixels, want); KisHLineIteratorSP it = kisLayer->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH); rgba* data = tile->pixels; for (int v = 0; v < TILE_HEIGHT; ++v) { if (isRgbA) { // RGB image do { KoBgrTraits::setRed(it->rawData(), GET_RED(*data)); KoBgrTraits::setGreen(it->rawData(), GET_GREEN(*data)); KoBgrTraits::setBlue(it->rawData(), GET_BLUE(*data)); KoBgrTraits::setOpacity(it->rawData(), quint8(GET_ALPHA(*data)), 1); ++data; } while (it->nextPixel()); } else { // Grayscale image do { it->rawData()[0] = GET_RED(*data); it->rawData()[1] = GET_ALPHA(*data); ++data; } while (it->nextPixel()); } it->nextRow(); } } } // Move the layer to its position kisLayer->paintDevice()->setX(left); kisLayer->paintDevice()->setY(top); } // Create the mask if (xcflayer.hasMask) { KisTransparencyMaskSP mask = new KisTransparencyMask(); layer.mask = mask; mask->initSelection(kisLayer); for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) { for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) { rect want; want.l = x + left; want.t = y + top; want.b = want.t + TILE_HEIGHT; want.r = want.l + TILE_WIDTH; Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.mask, want); KisHLineIteratorSP it = mask->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH); rgba* data = tile->pixels; for (int v = 0; v < TILE_HEIGHT; ++v) { do { it->rawData()[0] = GET_ALPHA(*data); ++data; } while (it->nextPixel()); it->nextRow(); } } } mask->paintDevice()->setX(left); mask->paintDevice()->setY(top); image->addNode(mask, kisLayer); } dbgFile << xcflayer.pixels.tileptrs; layers.append(layer); } for (int i = 0; i <= maxDepth; ++i) { addLayers(layers, image, i); } doc->setCurrentImage(image); return KisImportExportFilter::OK; } #include "kis_xcf_import.moc" diff --git a/plugins/impex/xcf/kis_xcf_import.h b/plugins/impex/xcf/kis_xcf_import.h index ddf1b860a2..2c6ae03a50 100644 --- a/plugins/impex/xcf/kis_xcf_import.h +++ b/plugins/impex/xcf/kis_xcf_import.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KIS_XCF_IMPORT_H_ #define _KIS_XCF_IMPORT_H_ #include #include #include class KisDocument; class KisXCFImport : public KisImportExportFilter { Q_OBJECT public: KisXCFImport(QObject *parent, const QVariantList &); virtual ~KisXCFImport(); public: - virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); + virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0); private: KisImportExportFilter::ConversionStatus loadFromDevice(QIODevice* device, KisDocument* doc); }; #endif diff --git a/plugins/paintops/chalk/chalk_paintop_plugin.cpp b/plugins/paintops/chalk/chalk_paintop_plugin.cpp index 320a02bef9..f3948920d1 100644 --- a/plugins/paintops/chalk/chalk_paintop_plugin.cpp +++ b/plugins/paintops/chalk/chalk_paintop_plugin.cpp @@ -1,50 +1,49 @@ /* * Copyright (c) 2008 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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 "chalk_paintop_plugin.h" #include #include #include #include #include "kis_chalk_paintop.h" #include "kis_simple_paintop_factory.h" #include "kis_global.h" K_PLUGIN_FACTORY_WITH_JSON(ChalkPaintOpPluginFactory, "kritachalkpaintop.json", registerPlugin();) ChalkPaintOpPlugin::ChalkPaintOpPlugin(QObject *parent, const QVariantList &) : QObject(parent) { KisPaintOpRegistry *r = KisPaintOpRegistry::instance(); - r->add(new KisSimplePaintOpFactory("chalkbrush", i18n("Chalk"), - KisPaintOpFactory::categoryStable(), "krita-chalk.png")); + r->add(new KisSimplePaintOpFactory("chalkbrush", i18n("Chalk"), KisPaintOpFactory::categoryStable(), "krita-chalk.png")); } ChalkPaintOpPlugin::~ChalkPaintOpPlugin() { } #include "chalk_paintop_plugin.moc" diff --git a/plugins/paintops/chalk/kis_chalk_paintop.cpp b/plugins/paintops/chalk/kis_chalk_paintop.cpp index 054e86113e..504e6e48a3 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop.cpp +++ b/plugins/paintops/chalk/kis_chalk_paintop.cpp @@ -1,91 +1,91 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_chalk_paintop.h" #include "kis_chalk_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisChalkPaintOp::KisChalkPaintOp(const KisChalkPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisChalkPaintOp::KisChalkPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); m_opacityOption.readOptionSetting(settings); m_opacityOption.resetAllSensors(); m_properties.readOptionSetting(settings); KoColorTransformation* transfo = 0; if (m_properties.inkDepletion && m_properties.useSaturation) { transfo = painter->device()->compositionSourceColorSpace()->createColorTransformation("hsv_adjustment", QHash()); } m_chalkBrush = new ChalkBrush(&m_properties, transfo); } KisChalkPaintOp::~KisChalkPaintOp() { delete m_chalkBrush; } KisSpacingInformation KisChalkPaintOp::paintAt(const KisPaintInformation& info) { if (!painter()) return KisSpacingInformation(1.0); if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } qreal x1, y1; x1 = info.pos().x(); y1 = info.pos().y(); const qreal additionalScale = KisLodTransform::lodToScale(painter()->device()); quint8 origOpacity = m_opacityOption.apply(painter(), info); m_chalkBrush->paint(m_dab, x1, y1, painter()->paintColor(), additionalScale); QRect rc = m_dab->extent(); painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); return KisSpacingInformation(1.0); } diff --git a/plugins/paintops/chalk/kis_chalk_paintop.h b/plugins/paintops/chalk/kis_chalk_paintop.h index 4d90ec44b8..0597a9118f 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop.h +++ b/plugins/paintops/chalk/kis_chalk_paintop.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008, 2009 Lukáš Tvrdý * * 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_CHALK_PAINTOP_H_ #define KIS_CHALK_PAINTOP_H_ #include #include #include "chalk_brush.h" #include "kis_chalk_paintop_settings.h" class KisPainter; class KisChalkPaintOp : public KisPaintOp { public: - KisChalkPaintOp(const KisChalkPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisChalkPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); virtual ~KisChalkPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: KisPaintDeviceSP m_dab; ChalkBrush * m_chalkBrush; KisPressureOpacityOption m_opacityOption; ChalkProperties m_properties; }; #endif // KIS_CHALK_PAINTOP_H_ diff --git a/plugins/paintops/chalk/kis_chalk_paintop_settings.cpp b/plugins/paintops/chalk/kis_chalk_paintop_settings.cpp index 8f2f60d11b..72d341c9eb 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop_settings.cpp +++ b/plugins/paintops/chalk/kis_chalk_paintop_settings.cpp @@ -1,59 +1,59 @@ /* * Copyright (c) 2008 Lukáš Tvrdý * * 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_chalk_paintop_settings.h" #include #include #include KisChalkPaintOpSettings::KisChalkPaintOpSettings() { } bool KisChalkPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } bool KisChalkPaintOpSettings::isAirbrushing() const { return getBool(AIRBRUSH_ENABLED); } int KisChalkPaintOpSettings::rate() const { return getInt(AIRBRUSH_RATE); } -QPainterPath KisChalkPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisChalkPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { qreal size = getInt(CHALK_RADIUS) * 2 + 1; path = ellipseOutline(size, size, 1.0, 0.0); if (mode == CursorTiltOutline) { path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), size * 0.5, 3.0)); } path.translate(info.pos()); } return path; } diff --git a/plugins/paintops/chalk/kis_chalk_paintop_settings.h b/plugins/paintops/chalk/kis_chalk_paintop_settings.h index 682605753a..9be8192752 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop_settings.h +++ b/plugins/paintops/chalk/kis_chalk_paintop_settings.h @@ -1,45 +1,45 @@ /* * Copyright (c) 2008,2009 Lukáš Tvrdý * * 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_CHALK_PAINTOP_SETTINGS_H_ #define KIS_CHALK_PAINTOP_SETTINGS_H_ #include #include #include "kis_chalk_paintop_settings_widget.h" #include class KisChalkPaintOpSettings : public KisPaintOpSettings { public: KisChalkPaintOpSettings(); virtual ~KisChalkPaintOpSettings() {} - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); bool paintIncremental(); bool isAirbrushing() const; int rate() const; }; #endif diff --git a/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.cpp b/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.cpp index 5e6e16ea7f..b9ea756304 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.cpp +++ b/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.cpp @@ -1,66 +1,66 @@ /* * Copyright (c) 2008 Lukáš Tvrdý * * 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_chalk_paintop_settings_widget.h" #include "kis_chalkop_option.h" #include "kis_chalk_paintop_settings.h" #include #include #include #include #include KisChalkPaintOpSettingsWidget:: KisChalkPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { m_chalkOption = new KisChalkOpOption(); addPaintOpOption(m_chalkOption, i18n("Brush size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisAirbrushOption(false), i18n("Airbrush")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisChalkPaintOpSettingsWidget::~ KisChalkPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisChalkPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisChalkPaintOpSettingsWidget::configuration() const { KisChalkPaintOpSettings* config = new KisChalkPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "chalkbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } void KisChalkPaintOpSettingsWidget::changePaintOpSize(qreal x, qreal y) { // if the movement is more left<->right then up<->down if (qAbs(x) > qAbs(y)) { m_chalkOption->setRadius(m_chalkOption->radius() + qRound(x)); } } QSizeF KisChalkPaintOpSettingsWidget::paintOpSize() const { qreal width = m_chalkOption->radius() * 2.0 + 1.0; return QSizeF(width, width); } diff --git a/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.h b/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.h index 5e7f61883a..e637ddfbbc 100644 --- a/plugins/paintops/chalk/kis_chalk_paintop_settings_widget.h +++ b/plugins/paintops/chalk/kis_chalk_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_CHALKPAINTOP_SETTINGS_WIDGET_H_ #define KIS_CHALKPAINTOP_SETTINGS_WIDGET_H_ #include #include "ui_wdgchalkoptions.h" class KisChalkOpOption; class KisChalkPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisChalkPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisChalkPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; ///Reimplemented void changePaintOpSize(qreal x, qreal y); virtual QSizeF paintOpSize() const; public: KisChalkOpOption* m_chalkOption; }; #endif diff --git a/plugins/paintops/chalk/kis_chalkop_option.cpp b/plugins/paintops/chalk/kis_chalkop_option.cpp index 7fd5a2efa1..546c96f042 100644 --- a/plugins/paintops/chalk/kis_chalkop_option.cpp +++ b/plugins/paintops/chalk/kis_chalkop_option.cpp @@ -1,105 +1,105 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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_chalkop_option.h" #include "ui_wdgchalkoptions.h" class KisChalkOpOptionsWidget: public QWidget, public Ui::WdgChalkOptions { public: KisChalkOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisChalkOpOption::KisChalkOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { m_checkable = false; m_options = new KisChalkOpOptionsWidget(); m_options->hide(); setObjectName("KisChalkOpOption"); // initialize values m_options->radiusSpinBox->setRange(0, 400); m_options->radiusSpinBox->setValue(5); m_options->radiusSpinBox->setSuffix(i18n(" px")); connect(m_options->radiusSpinBox, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->inkDepletionCHBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->opacity, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->saturation, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisChalkOpOption::~KisChalkOpOption() { // delete m_options; } int KisChalkOpOption::radius() const { return m_options->radiusSpinBox->value(); } void KisChalkOpOption::setRadius(int radius) const { m_options->radiusSpinBox->setValue(radius); } bool KisChalkOpOption::inkDepletion() const { return m_options->inkDepletionCHBox->isChecked(); } bool KisChalkOpOption::opacity() const { return m_options->opacity->isChecked(); } bool KisChalkOpOption::saturation() const { return m_options->saturation->isChecked(); } -void KisChalkOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisChalkOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(CHALK_RADIUS, radius()); setting->setProperty(CHALK_INK_DEPLETION, inkDepletion()); setting->setProperty(CHALK_USE_OPACITY, opacity()); setting->setProperty(CHALK_USE_SATURATION, saturation()); } -void KisChalkOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisChalkOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_options->radiusSpinBox->setValue(setting->getInt(CHALK_RADIUS)); m_options->inkDepletionCHBox->setChecked(setting->getBool(CHALK_INK_DEPLETION)); m_options->opacity->setChecked(setting->getBool(CHALK_USE_OPACITY)); m_options->saturation->setChecked(setting->getBool(CHALK_USE_SATURATION)); } diff --git a/plugins/paintops/chalk/kis_chalkop_option.h b/plugins/paintops/chalk/kis_chalkop_option.h index d61a4d260a..22631b8b6f 100644 --- a/plugins/paintops/chalk/kis_chalkop_option.h +++ b/plugins/paintops/chalk/kis_chalkop_option.h @@ -1,69 +1,69 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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_CHALKOP_OPTION_H #define KIS_CHALKOP_OPTION_H #include const QString CHALK_RADIUS = "Chalk/radius"; const QString CHALK_INK_DEPLETION = "Chalk/inkDepletion"; const QString CHALK_USE_OPACITY = "Chalk/opacity"; const QString CHALK_USE_SATURATION = "Chalk/saturation"; class KisChalkOpOptionsWidget; class KisChalkOpOption : public KisPaintOpOption { public: KisChalkOpOption(); ~KisChalkOpOption(); void setRadius(int radius) const; int radius() const; bool inkDepletion() const; bool saturation() const; bool opacity() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisChalkOpOptionsWidget * m_options; }; class ChalkProperties { public: int radius; bool inkDepletion; bool useOpacity; bool useSaturation; - void readOptionSetting(const KisPropertiesConfiguration* settings) { + void readOptionSetting(const KisPropertiesConfigurationSP settings) { radius = settings->getInt(CHALK_RADIUS); inkDepletion = settings->getBool(CHALK_INK_DEPLETION); useOpacity = settings->getBool(CHALK_USE_OPACITY); useSaturation = settings->getBool(CHALK_USE_SATURATION); } }; #endif diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop.cpp b/plugins/paintops/colorsmudge/kis_colorsmudgeop.cpp index 74d0dd82ac..68b95701c3 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop.cpp +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop.cpp @@ -1,287 +1,287 @@ /* * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_colorsmudgeop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisColorSmudgeOp::KisColorSmudgeOp(const KisBrushBasedPaintOpSettings* settings, KisPainter* painter, KisNodeSP node, KisImageSP image) +KisColorSmudgeOp::KisColorSmudgeOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_firstRun(true) , m_image(image) , m_tempDev(painter->device()->createCompositionSourceDevice()) , m_backgroundPainter(new KisPainter(m_tempDev)) , m_smudgePainter(new KisPainter(m_tempDev)) , m_colorRatePainter(new KisPainter(m_tempDev)) , m_smudgeRateOption() , m_colorRateOption("ColorRate", KisPaintOpOption::GENERAL, false) , m_smudgeRadiusOption() { Q_UNUSED(node); Q_ASSERT(settings); Q_ASSERT(painter); m_sizeOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_smudgeRateOption.readOptionSetting(settings); m_colorRateOption.readOptionSetting(settings); m_smudgeRadiusOption.readOptionSetting(settings); m_overlayModeOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_gradientOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_spacingOption.resetAllSensors(); m_smudgeRateOption.resetAllSensors(); m_colorRateOption.resetAllSensors(); m_smudgeRadiusOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_gradientOption.resetAllSensors(); m_gradient = painter->gradient(); m_backgroundPainter->setCompositeOp(COMPOSITE_COPY); // Smudge Painter works in default COMPOSITE_OVER mode m_colorRatePainter->setCompositeOp(painter->compositeOp()->id()); m_rotationOption.applyFanCornersInfo(this); } KisColorSmudgeOp::~KisColorSmudgeOp() { delete m_backgroundPainter; delete m_colorRatePainter; delete m_smudgePainter; } void KisColorSmudgeOp::updateMask(const KisPaintInformation& info, double scale, double rotation, const QPointF &cursorPoint) { static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); static KoColor color(Qt::black, cs); m_maskDab = m_dabCache->fetchDab(cs, color, cursorPoint, KisDabShape(scale, 1.0, rotation), info, 1.0, &m_dstDabRect); // sanity check KIS_ASSERT_RECOVER_NOOP(m_dstDabRect.size() == m_maskDab->bounds().size()); } inline void KisColorSmudgeOp::getTopLeftAligned(const QPointF &pos, const QPointF &hotSpot, qint32 *x, qint32 *y) { QPointF topLeft = pos - hotSpot; qreal xFraction, yFraction; // will not be used splitCoordinate(topLeft.x(), x, &xFraction); splitCoordinate(topLeft.y(), y, &yFraction); } KisSpacingInformation KisColorSmudgeOp::paintAt(const KisPaintInformation& info) { KisBrushSP brush = m_brush; // Simple error catching if (!painter()->device() || !brush || !brush->canPaintFor(info)) { return KisSpacingInformation(1.0); } if (m_smudgeRateOption.getMode() == KisSmudgeOption::SMEARING_MODE) { /** * Disable handling of the subpixel precision. In the smudge op we * should read from the aligned areas of the image, so having * additional internal offsets, created by the subpixel precision, * will worsen the quality (at least because * QRectF(m_dstDabRect).center() will not point to the real center * of the brush anymore). * Of course, this only really matters with smearing_mode (bug:327235), * and you only notice the lack of subpixel precision in the dulling methods. */ m_dabCache->disableSubpixelPrecision(); } #if 0 //if precision KoColor colorSpaceChanger = painter()->paintColor(); const KoColorSpace* preciseColorSpace = colorSpaceChanger.colorSpace(); if (colorSpaceChanger.colorSpace()->colorDepthId().id() == "U8") { - preciseColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceChanger.colorSpace()->colorModelId().id(), "U16", colorSpaceChanger.profile() ); + preciseColorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceChanger.colorSpace()->colorModelId().id(), "U16", colorSpaceChanger.profile() ); colorSpaceChanger.convertTo(preciseColorSpace); } painter()->setPaintColor(colorSpaceChanger); #endif // get the scaling factor calculated by the size option qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); KisDabShape shape(scale, 1.0, rotation); QPointF scatteredPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); QPointF hotSpot = brush->hotSpot(shape, info); /** * Update the brush mask. * * Upon leaving the function: * o m_maskDab stores the new mask * o m_maskBounds stores the extents of the mask paint device * o m_dstDabRect stores the destination rect where the mask is going * to be written to */ updateMask(info, scale, rotation, scatteredPos); QPointF newCenterPos = QRectF(m_dstDabRect).center(); /** * Save the center of the current dab to know where to read the * data during the next pass. We do not save scatteredPos here, * because it may differ slightly from the real center of the * brush (due to rounding effects), which will result in a * really weird quality. */ QRect srcDabRect = m_dstDabRect.translated((m_lastPaintPos - newCenterPos).toPoint()); m_lastPaintPos = newCenterPos; KisSpacingInformation spacingInfo = effectiveSpacing(scale, rotation, m_spacingOption, info); if (m_firstRun) { m_firstRun = false; return spacingInfo; } // save the old opacity value and composite mode quint8 oldOpacity = painter()->opacity(); QString oldCompositeOpId = painter()->compositeOp()->id(); qreal fpOpacity = (qreal(oldOpacity) / 255.0) * m_opacityOption.getOpacityf(info); if (m_image && m_overlayModeOption.isChecked()) { m_image->blockUpdates(); m_backgroundPainter->bitBlt(QPoint(), m_image->projection(), srcDabRect); m_image->unblockUpdates(); } else { // IMPORTANT: clear the temporary painting device to color black with zero opacity: // it will only clear the extents of the brush. m_tempDev->clear(QRect(QPoint(), m_dstDabRect.size())); } if (m_smudgeRateOption.getMode() == KisSmudgeOption::SMEARING_MODE) { m_smudgePainter->bitBlt(QPoint(), painter()->device(), srcDabRect); } else { QPoint pt = (srcDabRect.topLeft() + hotSpot).toPoint(); if (m_smudgeRadiusOption.isChecked()) { qreal effectiveSize = 0.5 * (m_dstDabRect.width() + m_dstDabRect.height()); m_smudgeRadiusOption.apply(*m_smudgePainter, info, effectiveSize, pt.x(), pt.y(), painter()->device()); KoColor color2 = m_smudgePainter->paintColor(); m_smudgePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color2); } else { KoColor color = painter()->paintColor(); // get the pixel on the canvas that lies beneath the hot spot // of the dab and fill the temporary paint device with that color KisCrossDeviceColorPickerInt colorPicker(painter()->device(), color); colorPicker.pickColor(pt.x(), pt.y(), color.data()); m_smudgePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color); } } // if the user selected the color smudge option, // we will mix some color into the temporary painting device (m_tempDev) if (m_colorRateOption.isChecked()) { // this will apply the opacity (selected by the user) to copyPainter // (but fit the rate inbetween the range 0.0 to (1.0-SmudgeRate)) qreal maxColorRate = qMax(1.0 - m_smudgeRateOption.getRate(), 0.2); m_colorRateOption.apply(*m_colorRatePainter, info, 0.0, maxColorRate, fpOpacity); // paint a rectangle with the current color (foreground color) // or a gradient color (if enabled) // into the temporary painting device and use the user selected // composite mode KoColor color = painter()->paintColor(); m_gradientOption.apply(color, m_gradient, info); m_colorRatePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color); } // if color is disabled (only smudge) and "overlay mode" is enabled // then first blit the region under the brush from the image projection // to the painting device to prevent a rapid build up of alpha value // if the color to be smudged is semi transparent. if (m_image && m_overlayModeOption.isChecked() && !m_colorRateOption.isChecked()) { painter()->setCompositeOp(COMPOSITE_COPY); painter()->setOpacity(OPACITY_OPAQUE_U8); m_image->blockUpdates(); painter()->bitBlt(m_dstDabRect.topLeft(), m_image->projection(), m_dstDabRect); m_image->unblockUpdates(); } // set opacity calculated by the rate option m_smudgeRateOption.apply(*painter(), info, 0.0, 1.0, fpOpacity); // then blit the temporary painting device on the canvas at the current brush position // the alpha mask (maskDab) will be used here to only blit the pixels that are in the area (shape) of the brush - + painter()->setCompositeOp(COMPOSITE_COPY); painter()->bitBltWithFixedSelection(m_dstDabRect.x(), m_dstDabRect.y(), m_tempDev, m_maskDab, m_dstDabRect.width(), m_dstDabRect.height()); painter()->renderMirrorMaskSafe(m_dstDabRect, m_tempDev, 0, 0, m_maskDab, !m_dabCache->needSeparateOriginal()); // restore orginal opacy and composite mode values painter()->setOpacity(oldOpacity); painter()->setCompositeOp(oldCompositeOpId); return spacingInfo; } diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop.h b/plugins/paintops/colorsmudge/kis_colorsmudgeop.h index 8237335c36..b851426a00 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop.h +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop.h @@ -1,80 +1,80 @@ /* * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_COLORSMUDGEOP_H_ #define _KIS_COLORSMUDGEOP_H_ #include #include #include #include #include #include #include #include #include #include "kis_overlay_mode_option.h" #include "kis_rate_option.h" #include "kis_smudge_option.h" #include "kis_smudge_radius_option.h" class QPointF; class KoAbstractGradient; class KisBrushBasedPaintOpSettings; class KisPainter; class KisColorSmudgeOp: public KisBrushBasedPaintOp { public: - KisColorSmudgeOp(const KisBrushBasedPaintOpSettings* settings, KisPainter* painter, KisNodeSP node, KisImageSP image); + KisColorSmudgeOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image); virtual ~KisColorSmudgeOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: // Sets the m_maskDab _and m_maskDabRect void updateMask(const KisPaintInformation& info, double scale, double rotation, const QPointF &cursorPoint); inline void getTopLeftAligned(const QPointF &pos, const QPointF &hotSpot, qint32 *x, qint32 *y); private: bool m_firstRun; KisImageWSP m_image; KisPaintDeviceSP m_tempDev; KisPainter* m_backgroundPainter; KisPainter* m_smudgePainter; KisPainter* m_colorRatePainter; const KoAbstractGradient* m_gradient; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisPressureSpacingOption m_spacingOption; KisSmudgeOption m_smudgeRateOption; KisRateOption m_colorRateOption; KisSmudgeRadiusOption m_smudgeRadiusOption; KisOverlayModeOption m_overlayModeOption; KisPressureRotationOption m_rotationOption; KisPressureScatterOption m_scatterOption; KisPressureGradientOption m_gradientOption; QRect m_dstDabRect; KisFixedPaintDeviceSP m_maskDab; QPointF m_lastPaintPos; }; #endif // _KIS_COLORSMUDGEOP_H_ diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.h b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.h index eebe6d216d..45098f4ff3 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.h +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.h @@ -1,39 +1,41 @@ /* * 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_COLORSMUDGEOP_SETTINGS_H #define __KIS_COLORSMUDGEOP_SETTINGS_H #include #include class KisColorSmudgeOpSettings : public KisBrushBasedPaintOpSettings { public: KisColorSmudgeOpSettings(); ~KisColorSmudgeOpSettings(); QList uniformProperties(); private: struct Private; const QScopedPointer m_d; }; +typedef KisSharedPtr KisColorSmudgeOpSettingsSP; + #endif /* __KIS_COLORSMUDGEOP_SETTINGS_H */ diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.cpp b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.cpp index dc3e978714..5b414567a1 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.cpp +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.cpp @@ -1,89 +1,88 @@ /* * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_colorsmudgeop_settings_widget.h" #include "kis_brush_based_paintop_settings.h" #include "kis_overlay_mode_option.h" #include "kis_rate_option.h" #include "kis_smudge_option_widget.h" #include "kis_smudge_radius_option.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" #include "kis_colorsmudgeop_settings.h" KisColorSmudgeOpSettingsWidget::KisColorSmudgeOpSettingsWidget(QWidget* parent): KisBrushBasedPaintopOptionWidget(parent) { setObjectName("brush option widget"); setPrecisionEnabled(true); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisPressureSpacingOptionWidget(), i18n("Spacing")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); m_smudgeOptionWidget = new KisSmudgeOptionWidget(); addPaintOpOption(m_smudgeOptionWidget, i18n("Smudge Length")); addPaintOpOption(new KisCurveOptionWidget(new KisSmudgeRadiusOption(), i18n("0.0"), i18n("1.0")), i18n("Smudge Radius")); addPaintOpOption(new KisCurveOptionWidget(new KisRateOption("ColorRate", KisPaintOpOption::GENERAL, false), i18n("0.0"), i18n("1.0")), i18n("Color Rate")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisPressureScatterOptionWidget(), i18n("Scatter")); addPaintOpOption(new KisOverlayModeOptionWidget(), i18n("Overlay Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureGradientOption(), i18n("0%"), i18n("100%")), i18n("Gradient")); addPaintOpOption(new KisTextureOption(), i18n("Pattern")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength")); } KisColorSmudgeOpSettingsWidget::~KisColorSmudgeOpSettingsWidget() { } -KisPropertiesConfiguration* KisColorSmudgeOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisColorSmudgeOpSettingsWidget::configuration() const { - KisColorSmudgeOpSettings *config = new KisColorSmudgeOpSettings(); + KisColorSmudgeOpSettingsSP config = new KisColorSmudgeOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "colorsmudge"); writeConfiguration(config); return config; } void KisColorSmudgeOpSettingsWidget::notifyPageChanged() { KisBrushSP brush = this->brush(); bool pierced = brush ? brush->isPiercedApprox() : false; m_smudgeOptionWidget->updateBrushPierced(pierced); } - diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.h b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.h index 7a3bb3c3b9..43b361d452 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.h +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings_widget.h @@ -1,45 +1,45 @@ /* * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_COLORSMUDGEOP_SETTINGS_WIDGET_H_ #define KIS_COLORSMUDGEOP_SETTINGS_WIDGET_H_ #include class KisSmudgeOptionWidget; class KisColorSmudgeOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisColorSmudgeOpSettingsWidget(QWidget* parent = 0); ~KisColorSmudgeOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; protected: void notifyPageChanged(); private: KisSmudgeOptionWidget *m_smudgeOptionWidget; }; #endif // KIS_COLORSMUDGEOP_SETTINGS_WIDGET_H_ diff --git a/plugins/paintops/colorsmudge/kis_overlay_mode_option.h b/plugins/paintops/colorsmudge/kis_overlay_mode_option.h index 3f6d63e7f9..94342f15dd 100644 --- a/plugins/paintops/colorsmudge/kis_overlay_mode_option.h +++ b/plugins/paintops/colorsmudge/kis_overlay_mode_option.h @@ -1,71 +1,71 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_OVERLAYMODE_OPTION_H_ #define _KIS_OVERLAYMODE_OPTION_H_ #include #include #include class KisOverlayModeOption : public KisPaintOpOption { public: KisOverlayModeOption(): KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisOverlayModeOption"); } virtual bool isCheckable() const { return true; } - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const { + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty("MergedPaint", isChecked()); } - virtual void readOptionSetting(const KisPropertiesConfiguration* setting) { + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting) { bool enabled = setting->getBool("MergedPaint"); setChecked(enabled); } virtual void lodLimitations(KisPaintopLodLimitations *l) const { l->blockers << KoID("colorsmudge-overlay", i18nc("PaintOp instant preview limitation", "Overlay Option")); } }; class KisOverlayModeOptionWidget: public KisOverlayModeOption { public: KisOverlayModeOptionWidget() { QLabel* label = new QLabel( i18n("Paints on the current layer\n\ but uses all layers that are currently visible for smudge input\n\ NOTE: This mode is only able to work correctly with a fully opaque background") ); label->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); setConfigurationPage(label); } }; #endif // _KIS_OVERLAYMODE_OPTION_H_ diff --git a/plugins/paintops/colorsmudge/kis_smudge_option.cpp b/plugins/paintops/colorsmudge/kis_smudge_option.cpp index ebe142e2cd..fbca1c97f5 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_option.cpp +++ b/plugins/paintops/colorsmudge/kis_smudge_option.cpp @@ -1,63 +1,63 @@ /* This file is part of the KDE project * * 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 "kis_smudge_option.h" #include #include #include #include KisSmudgeOption::KisSmudgeOption(): KisRateOption("SmudgeRate", KisPaintOpOption::GENERAL, true), m_mode(SMEARING_MODE) { setValueRange(0.01, 1.0); } void KisSmudgeOption::apply(KisPainter& painter, const KisPaintInformation& info, qreal scaleMin, qreal scaleMax, qreal multiplicator) const { if (!isChecked()) { painter.setOpacity((quint8)(scaleMax * 255.0)); return; } qreal value = computeSizeLikeValue(info); qreal rate = scaleMin + (scaleMax - scaleMin) * multiplicator * value; // scale m_rate into the range scaleMin - scaleMax quint8 opacity = qBound(OPACITY_TRANSPARENT_U8, (quint8)(rate * 255.0), OPACITY_OPAQUE_U8); painter.setOpacity(opacity); } -void KisSmudgeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisSmudgeOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisRateOption::writeOptionSetting(setting); setting->setProperty(name() + "Mode", m_mode); } -void KisSmudgeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisSmudgeOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisRateOption::readOptionSetting(setting); m_mode = (Mode)setting->getInt(name() + "Mode", SMEARING_MODE); } diff --git a/plugins/paintops/colorsmudge/kis_smudge_option.h b/plugins/paintops/colorsmudge/kis_smudge_option.h index f77dce3ae4..b8c10f1b2a 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_option.h +++ b/plugins/paintops/colorsmudge/kis_smudge_option.h @@ -1,60 +1,60 @@ /* This file is part of the KDE project * * 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_SMUDGE_OPTION_H #define KIS_SMUDGE_OPTION_H #include "kis_rate_option.h" #include #include // static const QString SMUDGE_MODE = "SmudgeMode"; class KisPropertiesConfiguration; class KisPainter; class KisSmudgeOption: public KisRateOption { public: KisSmudgeOption(); enum Mode { SMEARING_MODE, DULLING_MODE }; /** * Set the opacity of the painter based on the rate * and the curve (if checked) */ void apply(KisPainter& painter, const KisPaintInformation& info, qreal scaleMin = 0.0, qreal scaleMax = 1.0, qreal multiplicator = 1.0) const; Mode getMode() { return m_mode; } void setMode(Mode mode) { m_mode = mode; } - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); private: Mode m_mode; }; #endif // KIS_SMUDGE_OPTION_H diff --git a/plugins/paintops/colorsmudge/kis_smudge_option_widget.cpp b/plugins/paintops/colorsmudge/kis_smudge_option_widget.cpp index 3458f1f392..77d3383277 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_option_widget.cpp +++ b/plugins/paintops/colorsmudge/kis_smudge_option_widget.cpp @@ -1,87 +1,87 @@ /* This file is part of the KDE project * * 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 #include #include #include #include #include #include "kis_smudge_option_widget.h" #include "kis_smudge_option.h" KisSmudgeOptionWidget::KisSmudgeOptionWidget() : KisCurveOptionWidget(new KisSmudgeOption(), i18n("0.0"), i18n("1.0")) { setObjectName("KisSmudgeOptionWidget"); mCbSmudgeMode = new QComboBox(); mCbSmudgeMode->addItem(i18n("Smearing"), KisSmudgeOption::SMEARING_MODE); mCbSmudgeMode->addItem("dulling-placeholder" , KisSmudgeOption::DULLING_MODE); // the text for the second item is initialized here updateBrushPierced(false); QHBoxLayout* h = new QHBoxLayout(); h->addWidget(new QLabel(i18n("Smudge mode:"))); h->addWidget(mCbSmudgeMode, 1); QVBoxLayout* v = new QVBoxLayout(); v->setMargin(0); QWidget* w = new QWidget(); v->addLayout(h); v->addWidget(curveWidget()); w->setLayout(v); KisCurveOptionWidget::setConfigurationPage(w); connect(mCbSmudgeMode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); } void KisSmudgeOptionWidget::slotCurrentIndexChanged(int index) { static_cast(curveOption())->setMode((KisSmudgeOption::Mode)index); emitSettingChanged(); } -void KisSmudgeOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisSmudgeOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOptionWidget::readOptionSetting(setting); KisSmudgeOption::Mode mode = static_cast(curveOption())->getMode(); mCbSmudgeMode->setCurrentIndex(mode == KisSmudgeOption::SMEARING_MODE ? 0 : 1); } void KisSmudgeOptionWidget::updateBrushPierced(bool pierced) { QString dullingText = i18n("Dulling"); QString toolTip; if (pierced) { dullingText += i18n(" (caution, pierced brush!)"); toolTip = i18nc("@info:tooltip", "This brush has transparent pixels in its center. \"Dulling\" mode may give unstable results. Consider using \"Smearing\" mode instead."); } mCbSmudgeMode->setItemText(1, dullingText); mCbSmudgeMode->setToolTip(toolTip); } diff --git a/plugins/paintops/colorsmudge/kis_smudge_option_widget.h b/plugins/paintops/colorsmudge/kis_smudge_option_widget.h index 9e95d083f3..4aa9030a9c 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_option_widget.h +++ b/plugins/paintops/colorsmudge/kis_smudge_option_widget.h @@ -1,44 +1,44 @@ /* Copyright 2012 Silvio Heinrich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef KIS_SMUDGE_OPTION_WIDGET_H #define KIS_SMUDGE_OPTION_WIDGET_H #include class QComboBox; class KisSmudgeOptionWidget: public KisCurveOptionWidget { Q_OBJECT public: KisSmudgeOptionWidget(); - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); void updateBrushPierced(bool pierced); private Q_SLOTS: void slotCurrentIndexChanged(int index); private: QComboBox* mCbSmudgeMode; }; #endif // KIS_SMUDGE_OPTION_WIDGET_H diff --git a/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp b/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp index deece0b5a4..e54355941d 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp +++ b/plugins/paintops/colorsmudge/kis_smudge_radius_option.cpp @@ -1,163 +1,163 @@ /* * 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_smudge_radius_option.h" #include #include #include #include "kis_paint_device.h" #include "KoPointerEvent.h" #include "KoCanvasBase.h" #include "kis_random_accessor_ng.h" #include "KoColor.h" #include #include #include #include #include class KisRandomConstAccessorNG; KisSmudgeRadiusOption::KisSmudgeRadiusOption(): KisRateOption("SmudgeRadius", KisPaintOpOption::GENERAL, true) { setValueRange(0.0,300.0); } void KisSmudgeRadiusOption::apply(KisPainter& painter, const KisPaintInformation& info, qreal diameter, qreal posx, qreal posy, KisPaintDeviceSP dev) const { if (!isChecked()) return; qreal sliderValue = computeSizeLikeValue(info); int smudgeRadius = ((sliderValue * diameter) * 0.5) / 100.0; KoColor color = painter.paintColor(); if (smudgeRadius == 1) { dev->pixel(posx, posy, &color); painter.setPaintColor(color); } else { const KoColorSpace* cs = dev->colorSpace(); int pixelSize = cs->pixelSize(); quint8* data = new quint8[pixelSize]; static quint8** pixels = new quint8*[2]; qint16* weights = new qint16[2]; pixels[1] = new quint8[pixelSize]; pixels[0] = new quint8[pixelSize]; int loop_increment = 1; if(smudgeRadius >= 8) { loop_increment = (2*smudgeRadius)/16; } int i = 0; int k = 0; int j = 0; KisRandomConstAccessorSP accessor = dev->createRandomConstAccessorNG(0, 0); KisCrossDeviceColorPickerInt colorPicker(painter.device(), color); colorPicker.pickColor(posx, posy, color.data()); for (int y = 0; y <= smudgeRadius; y = y + loop_increment) { for (int x = 0; x <= smudgeRadius; x = x + loop_increment) { for(j = 0;j < 2;j++) { if(j == 1) { y = y*(-1); } for(k = 0;k < 2;k++) { if(k == 1) { x = x*(-1); } accessor->moveTo(posx + x, posy + y); memcpy(pixels[1], accessor->rawDataConst(), pixelSize); if(i == 0) { memcpy(pixels[0],accessor->rawDataConst(),pixelSize); } if (x == 0 && y == 0) { // Because the sum of the weights must be 255, // we cheat a bit, and weigh the center pixel differently in order // to sum to 255 in total // It's -(counts -1), because we'll add the center one implicitly // through that calculation weights[1] = (255 - ((i + 1) * (255 /(i+2) )) ); } else { weights[1] = 255 /(i+2); } i++; if (i>smudgeRadius){i=0;} weights[0] = 255 - weights[1]; const quint8** cpixels = const_cast(pixels); cs->mixColorsOp()->mixColors(cpixels, weights,2, data); memcpy(pixels[0],data,pixelSize); } x = x*(-1); } y = y*(-1); } } KoColor color = KoColor(pixels[0],cs); painter.setPaintColor(color); for (int l = 0; l < 2; l++){ delete[] pixels[l]; } // delete[] pixels; delete[] data; } } -void KisSmudgeRadiusOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisSmudgeRadiusOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); } -void KisSmudgeRadiusOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisSmudgeRadiusOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); } diff --git a/plugins/paintops/colorsmudge/kis_smudge_radius_option.h b/plugins/paintops/colorsmudge/kis_smudge_radius_option.h index 12784784f0..a74e4ea0ea 100644 --- a/plugins/paintops/colorsmudge/kis_smudge_radius_option.h +++ b/plugins/paintops/colorsmudge/kis_smudge_radius_option.h @@ -1,49 +1,49 @@ /* * 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. */ #ifndef KIS_SMUDGE_RADIUS_OPTION_H #define KIS_SMUDGE_RADIUS_OPTION_H #include "kis_rate_option.h" #include #include class KisPropertiesConfiguration; class KisPainter; class KisSmudgeRadiusOption: public KisRateOption { public: KisSmudgeRadiusOption(); /** * Set the opacity of the painter based on the rate * and the curve (if checked) */ void apply(KisPainter& painter, const KisPaintInformation& info, qreal diameter, qreal posx, qreal posy, KisPaintDeviceSP dev) const; - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); }; #endif // KIS_SMUDGE_RADIUS_OPTION_H diff --git a/plugins/paintops/curvebrush/kis_curve_line_option.cpp b/plugins/paintops/curvebrush/kis_curve_line_option.cpp index c13924a81a..30da5ecd99 100644 --- a/plugins/paintops/curvebrush/kis_curve_line_option.cpp +++ b/plugins/paintops/curvebrush/kis_curve_line_option.cpp @@ -1,86 +1,86 @@ /* * Copyright (c) 2011 Lukáš Tvrdý * * 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_curve_line_option.h" #include "ui_wdgcurveoptions.h" class KisCurveOpOptionsWidget: public QWidget, public Ui::WdgCurveOptions { public: KisCurveOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); historySizeSlider->setRange(2, 300); historySizeSlider->setValue(30); lineWidthSlider->setRange(1, 100); lineWidthSlider->setValue(1); lineWidthSlider->setSuffix(i18n(" px")); curvesOpacitySlider->setRange(0.0, 1.0, 2); curvesOpacitySlider->setValue(1.0); } }; KisCurveOpOption::KisCurveOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { m_checkable = false; m_options = new KisCurveOpOptionsWidget(); connect(m_options->connectionCHBox, SIGNAL(toggled(bool)), this, SLOT(emitSettingChanged())); connect(m_options->smoothingCHBox, SIGNAL(toggled(bool)), this, SLOT(emitSettingChanged())); connect(m_options->historySizeSlider, SIGNAL(valueChanged(qreal)), this, SLOT(emitSettingChanged())); connect(m_options->lineWidthSlider, SIGNAL(valueChanged(qreal)), this, SLOT(emitSettingChanged())); connect(m_options->curvesOpacitySlider, SIGNAL(valueChanged(qreal)), this, SLOT(emitSettingChanged())); setConfigurationPage(m_options); setObjectName("KisCurveOpOption"); } KisCurveOpOption::~KisCurveOpOption() { } -void KisCurveOpOption::writeOptionSetting(KisPropertiesConfiguration* config) const +void KisCurveOpOption::writeOptionSetting(KisPropertiesConfigurationSP config) const { CurveOption op; op.curve_paint_connection_line = m_options->connectionCHBox->isChecked(); op.curve_smoothing = m_options->smoothingCHBox->isChecked(); op.curve_stroke_history_size = m_options->historySizeSlider->value(); op.curve_line_width = m_options->lineWidthSlider->value(); op.curve_curves_opacity = m_options->curvesOpacitySlider->value(); op.writeOptionSetting(config); } -void KisCurveOpOption::readOptionSetting(const KisPropertiesConfiguration* config) +void KisCurveOpOption::readOptionSetting(const KisPropertiesConfigurationSP config) { CurveOption op; op.readOptionSetting(config); m_options->connectionCHBox->setChecked(op.curve_paint_connection_line); m_options->smoothingCHBox->setChecked(op.curve_smoothing); m_options->historySizeSlider->setValue(op.curve_stroke_history_size); m_options->lineWidthSlider->setValue(op.curve_line_width); m_options->curvesOpacitySlider->setValue(op.curve_curves_opacity); } diff --git a/plugins/paintops/curvebrush/kis_curve_line_option.h b/plugins/paintops/curvebrush/kis_curve_line_option.h index 504797a2bc..d3ae922bb6 100644 --- a/plugins/paintops/curvebrush/kis_curve_line_option.h +++ b/plugins/paintops/curvebrush/kis_curve_line_option.h @@ -1,72 +1,72 @@ /* * Copyright (c) 2011 Lukáš Tvrdý * * 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_CURVE_LINE_OPTION_H #define KIS_CURVE_LINE_OPTION_H #include class KisCurveOpOptionsWidget; // new rewrite const QString CURVE_LINE_WIDTH = "Curve/lineWidth"; // same as in sketch const QString CURVE_PAINT_CONNECTION_LINE = "Curve/makeConnection"; // same as in sketch const QString CURVE_STROKE_HISTORY_SIZE = "Curve/strokeHistorySize"; const QString CURVE_SMOOTHING = "Curve/smoothing"; const QString CURVE_CURVES_OPACITY = "Curve/curvesOpacity"; class KisCurveOpOption : public KisPaintOpOption { public: KisCurveOpOption(); ~KisCurveOpOption(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisCurveOpOptionsWidget * m_options; }; class CurveOption { public: bool curve_paint_connection_line; bool curve_smoothing; int curve_stroke_history_size; int curve_line_width; qreal curve_curves_opacity; - void readOptionSetting(const KisPropertiesConfiguration* config) { + void readOptionSetting(const KisPropertiesConfigurationSP config) { curve_paint_connection_line = config->getBool(CURVE_PAINT_CONNECTION_LINE); curve_smoothing = config->getBool(CURVE_SMOOTHING); curve_stroke_history_size = config->getInt(CURVE_STROKE_HISTORY_SIZE); curve_line_width = config->getInt(CURVE_LINE_WIDTH); curve_curves_opacity = config->getDouble(CURVE_CURVES_OPACITY); } - void writeOptionSetting(KisPropertiesConfiguration* config) const { + void writeOptionSetting(KisPropertiesConfigurationSP config) const { config->setProperty(CURVE_PAINT_CONNECTION_LINE, curve_paint_connection_line); config->setProperty(CURVE_SMOOTHING, curve_smoothing); config->setProperty(CURVE_STROKE_HISTORY_SIZE, curve_stroke_history_size); config->setProperty(CURVE_LINE_WIDTH, curve_line_width); config->setProperty(CURVE_CURVES_OPACITY, curve_curves_opacity); } }; #endif diff --git a/plugins/paintops/curvebrush/kis_curve_paintop.cpp b/plugins/paintops/curvebrush/kis_curve_paintop.cpp index a9f59a2026..15faff748f 100644 --- a/plugins/paintops/curvebrush/kis_curve_paintop.cpp +++ b/plugins/paintops/curvebrush/kis_curve_paintop.cpp @@ -1,127 +1,128 @@ /* * Copyright (c) 2008-2011 Lukáš Tvrdý * * 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_curve_paintop.h" #include #include #include #include #include "kis_global.h" #include "kis_paint_device.h" #include "kis_painter.h" #include "kis_types.h" #include -KisCurvePaintOp::KisCurvePaintOp(const KisCurvePaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) - : KisPaintOp(painter), m_painter(0) +KisCurvePaintOp::KisCurvePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) + : KisPaintOp(painter) + , m_painter(0) { Q_ASSERT(settings); Q_UNUSED(image); Q_UNUSED(node); m_curveProperties.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_lineWidthOption.readOptionSetting(settings); m_curvesOpacityOption.readOptionSetting(settings); } KisCurvePaintOp::~KisCurvePaintOp() { delete m_painter; } KisSpacingInformation KisCurvePaintOp::paintAt(const KisPaintInformation& info) { Q_UNUSED(info); return KisSpacingInformation(1.0); } void KisCurvePaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); if (!painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } paintLine(m_dab, pi1, pi2); QRect rc = m_dab->extent(); quint8 origOpacity = m_opacityOption.apply(painter(), pi2); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); } void KisCurvePaintOp::paintLine(KisPaintDeviceSP dab, const KisPaintInformation &pi1, const KisPaintInformation &pi2) { if (!m_painter) { m_painter = new KisPainter(dab); m_painter->setPaintColor(painter()->paintColor()); } int maxPoints = m_curveProperties.curve_stroke_history_size; m_points.append(pi2.pos()); while (m_points.length() > maxPoints) { m_points.removeFirst(); } const qreal additionalScale = KisLodTransform::lodToScale(painter()->device()); const qreal lineWidth = additionalScale * m_lineWidthOption.apply(pi2, m_curveProperties.curve_line_width); QPen pen(QBrush(Qt::white), lineWidth); QPainterPath path; if (m_curveProperties.curve_paint_connection_line) { path.moveTo(pi1.pos()); path.lineTo(pi2.pos()); m_painter->drawPainterPath(path, pen); path = QPainterPath(); } if (m_points.length() >= maxPoints) { // alpha * 0.2; path.moveTo(m_points.first()); if (m_curveProperties.curve_smoothing) { path.quadTo(m_points.at(maxPoints / 2), m_points.last()); } else { // control point is at 1/3 of the history, 2/3 of the history and endpoint at 3/3 int step = maxPoints / 3; path.cubicTo(m_points.at(step), m_points.at(step + step), m_points.last()); } qreal curveOpacity = m_curvesOpacityOption.apply(pi2, m_curveProperties.curve_curves_opacity); m_painter->setOpacity(qRound(255.0 * curveOpacity)); m_painter->drawPainterPath(path, pen); m_painter->setOpacity(255); // full } } diff --git a/plugins/paintops/curvebrush/kis_curve_paintop.h b/plugins/paintops/curvebrush/kis_curve_paintop.h index d9b471329c..baca8df083 100644 --- a/plugins/paintops/curvebrush/kis_curve_paintop.h +++ b/plugins/paintops/curvebrush/kis_curve_paintop.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2008-2011 Lukáš Tvrdý * * 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_CURVEPAINTOP_H_ #define KIS_CURVEPAINTOP_H_ #include #include #include "curve_brush.h" #include "kis_curve_line_option.h" #include "kis_curve_paintop_settings.h" #include #include "kis_linewidth_option.h" #include "kis_curves_opacity_option.h" class KisPainter; class KisCurvePaintOp : public KisPaintOp { public: - KisCurvePaintOp(const KisCurvePaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisCurvePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); virtual ~KisCurvePaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); private: void paintLine(KisPaintDeviceSP dab, const KisPaintInformation &pi1, const KisPaintInformation &pi2); private: KisPaintDeviceSP m_dab; KisPaintDeviceSP m_dev; CurveOption m_curveProperties; KisPressureOpacityOption m_opacityOption; KisLineWidthOption m_lineWidthOption; KisCurvesOpacityOption m_curvesOpacityOption; QList m_points; KisPainter * m_painter; }; #endif // KIS_CURVEPAINTOP_H_ diff --git a/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.cpp b/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.cpp index ce59e8a04d..fc1305009e 100644 --- a/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.cpp +++ b/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.cpp @@ -1,55 +1,55 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "kis_curve_line_option.h" #include #include #include #include #include #include "kis_curves_opacity_option.h" KisCurvePaintOpSettingsWidget:: KisCurvePaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { m_curveOption = new KisCurveOpOption(); addPaintOpOption(m_curveOption, i18n("Value")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisLineWidthOption(), i18n("0%"), i18n("100%")), i18n("Line width")); addPaintOpOption(new KisCurveOptionWidget(new KisCurvesOpacityOption(), i18n("0%"), i18n("100%")), i18n("Curves opacity")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisCurvePaintOpSettingsWidget::~ KisCurvePaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisCurvePaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisCurvePaintOpSettingsWidget::configuration() const { KisCurvePaintOpSettings* config = new KisCurvePaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "chalkbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.h b/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.h index a6954bdb77..a4244a6562 100644 --- a/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.h +++ b/plugins/paintops/curvebrush/kis_curve_paintop_settings_widget.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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_CURVE_PAINTOP_SETTINGS_WIDGET_H_ #define KIS_CURVE_PAINTOP_SETTINGS_WIDGET_H_ #include class KisCurveOpOption; class KisPropertiesConfiguration; class KisCurvePaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisCurvePaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisCurvePaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; private: KisCurveOpOption *m_curveOption; }; #endif diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp index 3ab6f688a7..e4b7380d1f 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp @@ -1,191 +1,193 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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_brushop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisBrushOp::KisBrushOp(const KisBrushBasedPaintOpSettings *settings, KisPainter *painter, KisNodeSP node, KisImageSP image) - : KisBrushBasedPaintOp(settings, painter), m_opacityOption(node), m_hsvTransformation(0) +KisBrushOp::KisBrushOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) + : KisBrushBasedPaintOp(settings, painter) + , m_opacityOption(node) + , m_hsvTransformation(0) { Q_UNUSED(image); Q_ASSERT(settings); KisColorSourceOption colorSourceOption; colorSourceOption.readOptionSetting(settings); m_colorSource = colorSourceOption.createColorSource(painter); m_hsvOptions.append(KisPressureHSVOption::createHueOption()); m_hsvOptions.append(KisPressureHSVOption::createSaturationOption()); m_hsvOptions.append(KisPressureHSVOption::createValueOption()); Q_FOREACH (KisPressureHSVOption * option, m_hsvOptions) { option->readOptionSetting(settings); option->resetAllSensors(); if (option->isChecked() && !m_hsvTransformation) { m_hsvTransformation = painter->backgroundColor().colorSpace()->createColorTransformation("hsv_adjustment", QHash()); } } m_opacityOption.readOptionSetting(settings); m_flowOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_ratioOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_softnessOption.readOptionSetting(settings); m_sharpnessOption.readOptionSetting(settings); m_darkenOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_mixOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_opacityOption.resetAllSensors(); m_flowOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_ratioOption.resetAllSensors(); m_softnessOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_darkenOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_dabCache->setSharpnessPostprocessing(&m_sharpnessOption); m_rotationOption.applyFanCornersInfo(this); } KisBrushOp::~KisBrushOp() { qDeleteAll(m_hsvOptions); delete m_colorSource; delete m_hsvTransformation; } KisSpacingInformation KisBrushOp::paintAt(const KisPaintInformation& info) { if (!painter()->device()) return KisSpacingInformation(1.0); KisBrushSP brush = m_brush; Q_ASSERT(brush); if (!brush) return KisSpacingInformation(1.0); if (!brush->canPaintFor(info)) return KisSpacingInformation(1.0); qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); qreal rotation = m_rotationOption.apply(info); qreal ratio = m_ratioOption.apply(info); KisPaintDeviceSP device = painter()->device(); KisDabShape shape(scale, ratio, rotation); QPointF cursorPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); quint8 origOpacity = painter()->opacity(); m_opacityOption.setFlow(m_flowOption.apply(info)); m_opacityOption.apply(painter(), info); m_colorSource->selectColor(m_mixOption.apply(info), info); m_darkenOption.apply(m_colorSource, info); if (m_hsvTransformation) { Q_FOREACH (KisPressureHSVOption * option, m_hsvOptions) { option->apply(m_hsvTransformation, info); } m_colorSource->applyColorTransformation(m_hsvTransformation); } QRect dabRect; KisFixedPaintDeviceSP dab = m_dabCache->fetchDab(device->compositionSourceColorSpace(), m_colorSource, cursorPos, shape, info, m_softnessOption.apply(info), &dabRect); // sanity check for the size calculation code if (dab->bounds().size() != dabRect.size()) { warnKrita << "KisBrushOp: dab bounds is not dab rect. See bug 327156" << dab->bounds().size() << dabRect.size(); } painter()->bltFixed(dabRect.topLeft(), dab, dab->bounds()); painter()->renderMirrorMaskSafe(dabRect, dab, !m_dabCache->needSeparateOriginal()); painter()->setOpacity(origOpacity); return effectiveSpacing(scale, rotation, m_spacingOption, info); } void KisBrushOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance) { if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) { if (!m_lineCacheDevice) { m_lineCacheDevice = source()->createCompositionSourceDevice(); } else { m_lineCacheDevice->clear(); } KisPainter p(m_lineCacheDevice); p.setPaintColor(painter()->paintColor()); p.drawDDALine(pi1.pos(), pi2.pos()); QRect rc = m_lineCacheDevice->extent(); painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height()); - //fixes Bug 338011 - painter()->renderMirrorMask(rc, m_lineCacheDevice); + //fixes Bug 338011 + painter()->renderMirrorMask(rc, m_lineCacheDevice); } else { KisPaintOp::paintLine(pi1, pi2, currentDistance); } } diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop.h b/plugins/paintops/defaultpaintops/brush/kis_brushop.h index 44b7340b16..ac0771f4bb 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop.h +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop.h @@ -1,78 +1,77 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_BRUSHOP_H_ #define KIS_BRUSHOP_H_ #include "kis_brush_based_paintop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include - -class KisBrushBasedPaintOpSettings; +#include class KisPainter; class KisColorSource; class KisBrushOp : public KisBrushBasedPaintOp { public: - KisBrushOp(const KisBrushBasedPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisBrushOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisBrushOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); private: KisColorSource *m_colorSource; KisPressureSizeOption m_sizeOption; KisPressureRatioOption m_ratioOption; KisPressureSpacingOption m_spacingOption; KisPressureFlowOption m_flowOption; KisFlowOpacityOption m_opacityOption; KisPressureSoftnessOption m_softnessOption; KisPressureSharpnessOption m_sharpnessOption; KisPressureDarkenOption m_darkenOption; KisPressureRotationOption m_rotationOption; KisPressureMixOption m_mixOption; KisPressureScatterOption m_scatterOption; QList m_hsvOptions; KoColorTransformation *m_hsvTransformation; KisPaintDeviceSP m_lineCacheDevice; KisPaintDeviceSP m_colorSourceDevice; }; #endif // KIS_BRUSHOP_H_ diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp index 0443d33a97..6d37dd26e9 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp @@ -1,97 +1,97 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_brushop_settings_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" KisBrushOpSettingsWidget::KisBrushOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { setObjectName("brush option widget"); setPrecisionEnabled(true); // Brush tip options addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisFlowOpacityOptionWidget(), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureFlowOption(), i18n("0%"), i18n("100%")), i18n("Flow")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRatioOption(), i18n("0%"), i18n("100%")), i18n("Ratio")); addPaintOpOption(new KisPressureSpacingOptionWidget(), i18n("Spacing")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSoftnessOption(), i18n("Soft"), i18n("Hard")), i18n("Softness")); addPaintOpOption(new KisPressureSharpnessOptionWidget(), i18n("Sharpness")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisPressureScatterOptionWidget(), i18n("Scatter")); // Colors options addPaintOpOption(new KisColorSourceOptionWidget(), i18n("Source")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureDarkenOption(), i18n("0.0"), i18n("1.0")), i18n("Darken")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureMixOption(), i18n("Foreground"), i18n("Background")), i18n("Mix")); addPaintOpOption(new KisCurveOptionWidget(KisPressureHSVOption::createHueOption(), KisPressureHSVOption::hueMinLabel(), KisPressureHSVOption::huemaxLabel()), i18n("Hue")); addPaintOpOption(new KisCurveOptionWidget(KisPressureHSVOption::createSaturationOption(), KisPressureHSVOption::saturationMinLabel(), KisPressureHSVOption::saturationmaxLabel()), i18n("Saturation")); addPaintOpOption(new KisCurveOptionWidget(KisPressureHSVOption::createValueOption(), KisPressureHSVOption::valueMinLabel(), KisPressureHSVOption::valuemaxLabel()), i18n("Value")); addPaintOpOption(new KisAirbrushOption(false), i18n("Airbrush")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); addPaintOpOption(new KisTextureOption(), i18n("Pattern")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength")); } KisBrushOpSettingsWidget::~KisBrushOpSettingsWidget() { } -KisPropertiesConfiguration* KisBrushOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisBrushOpSettingsWidget::configuration() const { - KisBrushBasedPaintOpSettings *config = new KisBrushBasedPaintOpSettings(); + KisBrushBasedPaintOpSettingsSP config = new KisBrushBasedPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "paintbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.h b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.h index 402804c635..eec4da46bd 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.h +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.h @@ -1,45 +1,45 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_BRUSHOP_SETTINGS_WIDGET_H_ #define KIS_BRUSHOP_SETTINGS_WIDGET_H_ #include class KisBrushOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisBrushOpSettingsWidget(QWidget* parent = 0); virtual ~KisBrushOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif // KIS_BRUSHOP_SETTINGS_WIDGET_H_ diff --git a/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc b/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc index 54bc6524a1..b50be936f0 100644 --- a/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc +++ b/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc @@ -1,60 +1,57 @@ /* * defaultpaintops_plugin.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "defaultpaintops_plugin.h" #include #include #include #include #include "kis_simple_paintop_factory.h" #include "kis_brushop.h" #include "kis_brushop_settings_widget.h" #include "kis_duplicateop.h" #include "kis_duplicateop_settings.h" #include "kis_global.h" #include #include "kis_brush_based_paintop_settings.h" #include "kis_brush_server.h" #include "kis_duplicateop_settings_widget.h" K_PLUGIN_FACTORY_WITH_JSON(DefaultPaintOpsPluginFactory, "kritadefaultpaintops.json", registerPlugin();) DefaultPaintOpsPlugin::DefaultPaintOpsPlugin(QObject *parent, const QVariantList &) : QObject(parent) { KisPaintOpRegistry *r = KisPaintOpRegistry::instance(); - r->add(new KisSimplePaintOpFactory( - "paintbrush", i18nc("Pixel paintbrush", "Pixel"), - KisPaintOpFactory::categoryStable(), "krita-paintbrush.png", QString(), QStringList(), 1)); + r->add(new KisSimplePaintOpFactory("paintbrush", i18nc("Pixel paintbrush", "Pixel"), KisPaintOpFactory::categoryStable(), "krita-paintbrush.png", QString(), QStringList(), 1)); r->add(new KisSimplePaintOpFactory("duplicate", i18nc("clone paintbrush (previously \"Duplicate\")", "Clone"), KisPaintOpFactory::categoryStable(), "krita-duplicate.png", QString(), QStringList(COMPOSITE_COPY), 15)); - QStringList whiteList; - whiteList << COMPOSITE_COPY; + KisBrushServer::instance(); } DefaultPaintOpsPlugin::~DefaultPaintOpsPlugin() { } #include "defaultpaintops_plugin.moc" diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.cpp b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.cpp index 3fc43ad72a..4b2b1a7d28 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.cpp +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.cpp @@ -1,283 +1,283 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004,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. */ #include "kis_duplicateop.h" #include "kis_duplicateop_p.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 #include #include "kis_duplicateop_settings.h" #include "kis_duplicateop_settings_widget.h" #include "kis_duplicateop_option.h" -KisDuplicateOp::KisDuplicateOp(const KisDuplicateOpSettings *settings, KisPainter *painter, KisNodeSP node, KisImageSP image) +KisDuplicateOp::KisDuplicateOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_image(image) , m_node(node) - , m_settings(settings) + , m_settings(static_cast(const_cast(settings.data()))) { Q_ASSERT(settings); Q_ASSERT(painter); m_sizeOption.readOptionSetting(settings); m_healing = settings->getBool(DUPLICATE_HEALING); m_perspectiveCorrection = settings->getBool(DUPLICATE_CORRECT_PERSPECTIVE); m_moveSourcePoint = settings->getBool(DUPLICATE_MOVE_SOURCE_POINT); m_cloneFromProjection = settings->getBool(DUPLICATE_CLONE_FROM_PROJECTION); m_srcdev = source()->createCompositionSourceDevice(); } KisDuplicateOp::~KisDuplicateOp() { } #define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) KisSpacingInformation KisDuplicateOp::paintAt(const KisPaintInformation& info) { if (!painter()->device()) return KisSpacingInformation(1.0); KisBrushSP brush = m_brush; if (!brush) return KisSpacingInformation(1.0); if (!brush->canPaintFor(info)) return KisSpacingInformation(1.0); if (!m_duplicateStartIsSet) { m_duplicateStartIsSet = true; m_duplicateStart = info.pos(); } KisPaintDeviceSP realSourceDevice; if (m_cloneFromProjection && m_image) { realSourceDevice = m_image->projection(); } else { KisNodeSP externalSourceNode = m_settings->sourceNode(); /** * The saved layer might have been deleted by then, so check if it * still belongs to a graph */ if (!externalSourceNode || !externalSourceNode->graphListener()) { externalSourceNode = m_node; } realSourceDevice = externalSourceNode->projection(); } qreal scale = m_sizeOption.apply(info); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); KisDabShape shape(scale, 1.0, 0.0); static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); static KoColor color(Qt::black, cs); QRect dstRect; KisFixedPaintDeviceSP dab = m_dabCache->fetchDab(cs, color, info.pos(), shape, info, 1.0, &dstRect); if (dstRect.isEmpty()) return KisSpacingInformation(1.0); QPoint srcPoint; if (m_moveSourcePoint) { srcPoint = (dstRect.topLeft() - m_settings->offset()).toPoint(); } else { QPointF hotSpot = brush->hotSpot(shape, info); srcPoint = (m_settings->position() - hotSpot).toPoint(); } qint32 sw = dstRect.width(); qint32 sh = dstRect.height(); // Perspective correction ? // if (m_perspectiveCorrection && m_image && m_image->perspectiveGrid()->countSubGrids() == 1) { // Matrix3qreal startM = Matrix3qreal::Identity(); // Matrix3qreal endM = Matrix3qreal::Identity(); // // First look for the grid corresponding to the start point // KisSubPerspectiveGrid* subGridStart = *m_image->perspectiveGrid()->begin(); // QRect r = QRect(0, 0, m_image->width(), m_image->height()); // if (subGridStart) { // startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); // } // // Second look for the grid corresponding to the end point // KisSubPerspectiveGrid* subGridEnd = *m_image->perspectiveGrid()->begin(); // if (subGridEnd) { // endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); // } // // Compute the translation in the perspective transformation space: // QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart)); // QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(m_settings->offset())); // QPointF translat = duplicateStartPositionT - positionStartPaintingT; // KisSequentialIterator dstIt(m_srcdev, QRect(0, 0, sw, sh)); // KisRandomSubAccessorSP srcAcc = realSourceDevice->createRandomSubAccessor(); // //Action // do { // QPointF p = KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt.x() + dstRect.x(), dstIt.y() + dstRect.y())) + translat); // srcAcc->moveTo(p); // srcAcc->sampledOldRawData(dstIt.rawData()); // } while (dstIt.nextPixel()); // } - // else + // else { KisPainter copyPainter(m_srcdev); copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.bitBltOldData(0, 0, realSourceDevice, srcPoint.x(), srcPoint.y(), sw, sh); copyPainter.end(); } // heal ? if (m_healing) { QRect healRect(dstRect); const bool smallWidth = healRect.width() < 3; const bool smallHeight = healRect.height() < 3; if (smallWidth || smallHeight) { healRect.adjust(-smallWidth, -smallHeight, smallWidth, smallHeight); } const int healSW = healRect.width(); const int healSH = healRect.height(); quint16 srcData[4]; quint16 tmpData[4]; QScopedArrayPointer matrix(new qreal[ 3 * healSW * healSH ]); // First divide const KoColorSpace* srcCs = realSourceDevice->colorSpace(); const KoColorSpace* tmpCs = m_srcdev->colorSpace(); KisHLineConstIteratorSP srcIt = realSourceDevice->createHLineConstIteratorNG(healRect.x(), healRect.y() , healSW); KisHLineIteratorSP tmpIt = m_srcdev->createHLineIteratorNG(0, 0, healSW); qreal* matrixIt = matrix.data(); for (int j = 0; j < healSH; j++) { for (int i = 0; i < healSW; i++) { srcCs->toLabA16(srcIt->oldRawData(), (quint8*)srcData, 1); tmpCs->toLabA16(tmpIt->rawData(), (quint8*)tmpData, 1); // Division for (int k = 0; k < 3; k++) { matrixIt[k] = srcData[k] / (qreal)qMax((int)tmpData [k], 1); } srcIt->nextPixel(); tmpIt->nextPixel(); matrixIt += 3; } srcIt->nextRow(); tmpIt->nextRow(); } // Minimize energy { int iter = 0; qreal err; QScopedArrayPointer solution(new qreal[ 3 * healSW * healSH ]); do { err = DuplicateOpUtils::minimizeEnergy(matrix.data(), solution.data(), healSW, healSH); solution.swap(matrix); iter++; } while (err > 0.00001 && iter < 100); } // Finally multiply KisHLineIteratorSP tmpIt2 = m_srcdev->createHLineIteratorNG(0, 0, healSW); matrixIt = &matrix[0]; for (int j = 0; j < healSH; j++) { for (int i = 0; i < healSW; i++) { tmpCs->toLabA16(tmpIt2->rawData(), (quint8*)tmpData, 1); // Multiplication for (int k = 0; k < 3; k++) { tmpData[k] = (int)CLAMP(matrixIt[k] * qMax((int) tmpData[k], 1), 0, 65535); } tmpCs->fromLabA16((quint8*)tmpData, tmpIt2->rawData(), 1); tmpIt2->nextPixel(); matrixIt += 3; } tmpIt2->nextRow(); } } painter()->bitBltWithFixedSelection(dstRect.x(), dstRect.y(), m_srcdev, dab, dstRect.width(), dstRect.height()); painter()->renderMirrorMaskSafe(dstRect, m_srcdev, 0, 0, dab, !m_dabCache->needSeparateOriginal()); return effectiveSpacing(scale, 0.0); } diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.h b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.h index dbab7c4807..1aa1206d11 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.h +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop.h @@ -1,73 +1,75 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_DUPLICATEOP_H_ #define KIS_DUPLICATEOP_H_ #include "kis_brush_based_paintop.h" #include #include #include #include #include +#include "kis_duplicateop_settings.h" + class KisPaintInformation; -class KisDuplicateOpSettings; + class QPointF; class KisPainter; class KisDuplicateOp : public KisBrushBasedPaintOp { public: - KisDuplicateOp(const KisDuplicateOpSettings *m_settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisDuplicateOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); ~KisDuplicateOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: qreal minimizeEnergy(const qreal* m, qreal* sol, int w, int h); private: KisImageSP m_image; KisNodeSP m_node; - const KisDuplicateOpSettings * m_settings; + KisDuplicateOpSettingsSP m_settings; KisPaintDeviceSP m_srcdev; KisPaintDeviceSP m_target; QPointF m_duplicateStart; bool m_duplicateStartIsSet; KisPressureSizeOption m_sizeOption; bool m_healing; bool m_perspectiveCorrection; bool m_moveSourcePoint; bool m_cloneFromProjection; }; #endif // KIS_DUPLICATEOP_H_ diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.cpp b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.cpp index 9bac6b0410..fb3470c910 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.cpp +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.cpp @@ -1,131 +1,131 @@ /* * 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 "kis_duplicateop_option.h" #include #include #include #include "ui_wdgduplicateop.h" #include class KisDuplicateOpOptionsWidget: public QWidget, public Ui::DuplicateOpOptionsWidget { public: KisDuplicateOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } KisImageWSP m_image; protected: void showEvent(QShowEvent* event) { QWidget::showEvent(event); //cbPerspective->setEnabled(m_image && m_image->perspectiveGrid() && m_image->perspectiveGrid()->countSubGrids() == 1); cbPerspective->setVisible(false); // XXX: Until perspective cloning works again! } }; KisDuplicateOpOption::KisDuplicateOpOption() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { setObjectName("KisDuplicateOpOption"); m_checkable = false; m_optionWidget = new KisDuplicateOpOptionsWidget(); connect(m_optionWidget->cbHealing, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->cbPerspective, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->cbSourcePoint, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->chkCloneProjection, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_optionWidget); } KisDuplicateOpOption::~KisDuplicateOpOption() { } bool KisDuplicateOpOption::healing() const { return m_optionWidget->cbHealing->isChecked(); } void KisDuplicateOpOption::setHealing(bool healing) { m_optionWidget->cbHealing->setChecked(healing); } bool KisDuplicateOpOption::correctPerspective() const { return m_optionWidget->cbPerspective->isChecked(); } void KisDuplicateOpOption::setPerspective(bool perspective) { m_optionWidget->cbPerspective->setChecked(perspective); } bool KisDuplicateOpOption::moveSourcePoint() const { return m_optionWidget->cbSourcePoint->isChecked(); } void KisDuplicateOpOption::setMoveSourcePoint(bool move) { m_optionWidget->cbSourcePoint->setChecked(move); } bool KisDuplicateOpOption::cloneFromProjection() const { return m_optionWidget->chkCloneProjection->isChecked(); } void KisDuplicateOpOption::setCloneFromProjection(bool cloneFromProjection) { m_optionWidget->chkCloneProjection->setChecked(cloneFromProjection); } -void KisDuplicateOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisDuplicateOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { DuplicateOption op; setting->setProperty(DUPLICATE_HEALING, healing()); setting->setProperty(DUPLICATE_CORRECT_PERSPECTIVE, correctPerspective()); setting->setProperty(DUPLICATE_MOVE_SOURCE_POINT, moveSourcePoint()); setting->setProperty(DUPLICATE_CLONE_FROM_PROJECTION, cloneFromProjection()); op.writeOptionSetting(setting); } -void KisDuplicateOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisDuplicateOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { DuplicateOption op; op.readOptionSetting(setting); m_optionWidget->cbHealing->setChecked(op.duplicate_healing); m_optionWidget->cbPerspective->setChecked(op.duplicate_correct_perspective); m_optionWidget->cbSourcePoint->setChecked(op.duplicate_move_source_point); m_optionWidget->chkCloneProjection->setChecked(op.duplicate_clone_from_projection); } void KisDuplicateOpOption::setImage(KisImageWSP image) { m_optionWidget->m_image = image; } diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.h b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.h index f31347ea37..bb2575c55a 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.h +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_option.h @@ -1,82 +1,82 @@ /* * 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. */ #ifndef KIS_DUPLICATEOP_OPTION_H #define KIS_DUPLICATEOP_OPTION_H #include const QString DUPLICATE_HEALING = "Duplicateop/Healing"; const QString DUPLICATE_CORRECT_PERSPECTIVE = "Duplicateop/CorrectPerspective"; const QString DUPLICATE_MOVE_SOURCE_POINT = "Duplicateop/MoveSourcePoint"; const QString DUPLICATE_CLONE_FROM_PROJECTION = "Duplicateop/CloneFromProjection"; class KisDuplicateOpOptionsWidget; class KisDuplicateOpOption : public KisPaintOpOption { public: KisDuplicateOpOption(); ~KisDuplicateOpOption(); private: bool healing() const; void setHealing(bool healing); bool correctPerspective() const; void setPerspective(bool perspective); bool moveSourcePoint() const; void setMoveSourcePoint(bool move); bool cloneFromProjection() const; void setCloneFromProjection(bool cloneFromProjection); public: - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); void setImage(KisImageWSP image); private: KisDuplicateOpOptionsWidget * m_optionWidget; }; struct DuplicateOption { bool duplicate_healing; bool duplicate_correct_perspective; bool duplicate_move_source_point; bool duplicate_clone_from_projection; void readOptionSetting(const KisPropertiesConfiguration* setting) { duplicate_healing = setting->getBool(DUPLICATE_HEALING, false); duplicate_correct_perspective = setting->getBool(DUPLICATE_CORRECT_PERSPECTIVE, false); duplicate_move_source_point = setting->getBool(DUPLICATE_MOVE_SOURCE_POINT, true); duplicate_clone_from_projection = setting->getBool(DUPLICATE_CLONE_FROM_PROJECTION, false); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(DUPLICATE_HEALING, duplicate_healing); setting->setProperty(DUPLICATE_CORRECT_PERSPECTIVE, duplicate_correct_perspective); setting->setProperty(DUPLICATE_MOVE_SOURCE_POINT, duplicate_move_source_point); setting->setProperty(DUPLICATE_CLONE_FROM_PROJECTION, duplicate_clone_from_projection); } }; #endif diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp index 85149b1a07..b831b02a0b 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp @@ -1,239 +1,239 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_duplicateop_settings.h" #include "kis_duplicateop_option.h" #include "kis_duplicateop_settings_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include KisDuplicateOpSettings::KisDuplicateOpSettings() : m_isOffsetNotUptodate(false) { } KisDuplicateOpSettings::~KisDuplicateOpSettings() { } bool KisDuplicateOpSettings::paintIncremental() { return false; } QString KisDuplicateOpSettings::indirectPaintingCompositeOp() const { return COMPOSITE_COPY; } QPointF KisDuplicateOpSettings::offset() const { return m_offset; } QPointF KisDuplicateOpSettings::position() const { return m_position; } bool KisDuplicateOpSettings::mousePressEvent(const KisPaintInformation &info, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode) { bool ignoreEvent = true; if (modifiers & Qt::ControlModifier) { if (!m_sourceNode || !(modifiers & Qt::AltModifier)) { m_sourceNode = currentNode; } m_position = info.pos(); m_isOffsetNotUptodate = true; ignoreEvent = false; } else { if (m_isOffsetNotUptodate) { m_offset = info.pos() - m_position; m_isOffsetNotUptodate = false; } ignoreEvent = true; } return ignoreEvent; } KisNodeWSP KisDuplicateOpSettings::sourceNode() const { return m_sourceNode; } void KisDuplicateOpSettings::activate() { } void KisDuplicateOpSettings::fromXML(const QDomElement& elt) { // First, call the parent class fromXML to make sure all the // properties are saved to the map KisPaintOpSettings::fromXML(elt); m_offset.setX(KisDomUtils::toDouble(elt.attribute("OffsetX", "0.0"))); m_offset.setY(KisDomUtils::toDouble(elt.attribute("OffsetY", "0.0"))); m_isOffsetNotUptodate = false; } void KisDuplicateOpSettings::toXML(QDomDocument& doc, QDomElement& rootElt) const { // Then call the parent class fromXML KisPropertiesConfiguration::toXML(doc, rootElt); rootElt.setAttribute("OffsetX", QString::number(m_offset.x())); rootElt.setAttribute("OffsetY", QString::number(m_offset.y())); } KisPaintOpSettingsSP KisDuplicateOpSettings::clone() const { KisPaintOpSettingsSP setting = KisBrushBasedPaintOpSettings::clone(); KisDuplicateOpSettings* s = dynamic_cast(setting.data()); s->m_offset = m_offset; s->m_isOffsetNotUptodate = m_isOffsetNotUptodate; s->m_position = m_position; return setting; } -QPainterPath KisDuplicateOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisDuplicateOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; // clone tool should always show an outline path = KisBrushBasedPaintOpSettings::brushOutlineImpl(info, mode, 1.0, true); QPainterPath copy(path); QRectF rect2 = copy.boundingRect(); if (m_isOffsetNotUptodate || !getBool(DUPLICATE_MOVE_SOURCE_POINT)) { copy.translate(m_position - info.pos()); } else { copy.translate(-m_offset); } path.addPath(copy); qreal dx = rect2.width() / 4.0; qreal dy = rect2.height() / 4.0; rect2.adjust(dx, dy, -dx, -dy); path.moveTo(rect2.topLeft()); path.lineTo(rect2.bottomRight()); path.moveTo(rect2.topRight()); path.lineTo(rect2.bottomLeft()); return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_duplicateop_option.h" #include "kis_standard_uniform_properties_factory.h" QList KisDuplicateOpSettings::uniformProperties() { QList props = listWeakToStrong(m_uniformProperties); if (props.isEmpty()) { { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "clone_healing", i18n("Healing"), this, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DuplicateOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.duplicate_healing); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DuplicateOption option; option.readOptionSetting(prop->settings().data()); option.duplicate_healing = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "clone_movesource", i18n("Move Source"), this, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DuplicateOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.duplicate_move_source_point); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DuplicateOption option; option.readOptionSetting(prop->settings().data()); option.duplicate_move_source_point = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties() + props; } diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.h b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.h index f4a15e2292..e7c6126af9 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.h +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.h @@ -1,69 +1,73 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_DUPLICATEOP_SETTINGS_H_ #define KIS_DUPLICATEOP_SETTINGS_H_ #include #include #include class QDomElement; class KisDuplicateOpSettings : public KisBrushBasedPaintOpSettings { public: using KisPaintOpSettings::fromXML; using KisPaintOpSettings::toXML; KisDuplicateOpSettings(); - virtual ~KisDuplicateOpSettings(); bool paintIncremental(); QString indirectPaintingCompositeOp() const; QPointF offset() const; QPointF position() const; virtual bool mousePressEvent(const KisPaintInformation& pos, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode); void activate(); void fromXML(const QDomElement& elt); void toXML(QDomDocument& doc, QDomElement& rootElt) const; KisPaintOpSettingsSP clone() const; - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + using KisBrushBasedPaintOpSettings::brushOutline; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); KisNodeWSP sourceNode() const; QList uniformProperties(); public: + Q_DISABLE_COPY(KisDuplicateOpSettings) + QPointF m_offset; bool m_isOffsetNotUptodate; QPointF m_position; // Give the position of the last alt-click KisNodeWSP m_sourceNode; QList m_uniformProperties; }; +typedef KisSharedPtr KisDuplicateOpSettingsSP; + #endif // KIS_DUPLICATEOP_SETTINGS_H_ diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.cpp b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.cpp index 474ddf9ac0..342be01e21 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.cpp +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.cpp @@ -1,75 +1,75 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_duplicateop_settings_widget.h" #include "kis_duplicateop_settings.h" #include "kis_duplicateop_option.h" #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" #include KisDuplicateOpSettingsWidget::KisDuplicateOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { setObjectName("brush option widget"); setPrecisionEnabled(true); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); addPaintOpOption(new KisDuplicateOpOption(), i18n("Painting Mode")); addPaintOpOption(new KisTextureOption(), i18n("Pattern")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength")); } KisDuplicateOpSettingsWidget::~KisDuplicateOpSettingsWidget() { } -KisPropertiesConfiguration* KisDuplicateOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisDuplicateOpSettingsWidget::configuration() const { KisDuplicateOpSettings *config = new KisDuplicateOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "duplicate"); // XXX: make this a const id string writeConfiguration(config); return config; } KisPaintopLodLimitations KisDuplicateOpSettingsWidget::lodLimitations() const { KisPaintopLodLimitations l = KisBrushBasedPaintopOptionWidget::lodLimitations(); l.blockers << KoID("clone-brush", i18nc("PaintOp instant preview limitation", "Clone Brush (temporarily disabled)")); return l; } diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.h b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.h index 3e0b06897d..3780816327 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.h +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings_widget.h @@ -1,57 +1,57 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_DUPLICATEOP_SETTINGS_WIDGET_H_ #define KIS_DUPLICATEOP_SETTINGS_WIDGET_H_ #include #include class KisDuplicateOpOption; class KisPaintopLodLimitations; class KisDuplicateOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisDuplicateOpSettingsWidget(QWidget* parent = 0); ~KisDuplicateOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; KisPaintopLodLimitations lodLimitations() const; virtual bool supportScratchBox() { return false; } public: KisDuplicateOpOption* m_duplicateOption; }; #endif // KIS_DUPLICATEOP_SETTINGS_WIDGET_H_ diff --git a/plugins/paintops/deform/kis_brush_size_option.cpp b/plugins/paintops/deform/kis_brush_size_option.cpp index 6a6c4afa99..b1e10c8411 100644 --- a/plugins/paintops/deform/kis_brush_size_option.cpp +++ b/plugins/paintops/deform/kis_brush_size_option.cpp @@ -1,154 +1,154 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_brush_size_option.h" #include #include #include #include "ui_wdgBrushSizeOptions.h" class KisBrushSizeOptionsWidget: public QWidget, public Ui::WdgBrushSizeOptions { public: KisBrushSizeOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisBrushSizeOption::KisBrushSizeOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisBrushSizeOption"); m_checkable = false; m_options = new KisBrushSizeOptionsWidget(); // init slider values m_options->diameter->setRange(1.0, 1000, 0); m_options->diameter->setValue(20); m_options->diameter->setExponentRatio(3.0); m_options->diameter->setSuffix(i18n(" px")); m_options->aspectBox->setRange(0.01, 2.0, 2); m_options->aspectBox->setValue(1.0); m_options->aspectBox->setExponentRatio(1.0); m_options->scale->setRange(0.01, 10.0, 2); m_options->scale->setValue(1.0); m_options->spacing->setRange(0.01, 5.0, 2); m_options->spacing->setValue(0.3); m_options->rotationBox->setRange(0.0, 360.0, 0); m_options->rotationBox->setValue(0.0); m_options->rotationBox->setSuffix(QChar(Qt::Key_degree)); m_options->densityBox->setRange(0.0, 100.0, 0); m_options->densityBox->setValue(100); m_options->densityBox->setSuffix("%"); m_options->jitterMove->setRange(0.0, 5.0, 2); m_options->jitterMove->setValue(0.0); connect(m_options->diameter, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->scale, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->aspectBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->spacing, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->rotationBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->densityBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->jitterMove, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->jitterMoveBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->jitterMoveBox, SIGNAL(toggled(bool)), m_options->jitterMove, SLOT(setEnabled(bool))); setConfigurationPage(m_options); } KisBrushSizeOption::~KisBrushSizeOption() { delete m_options; } int KisBrushSizeOption::diameter() const { return qRound(m_options->diameter->value()); } void KisBrushSizeOption::setDiameter(int diameter) { m_options->diameter->setValue(diameter); } qreal KisBrushSizeOption::brushAspect() const { return m_options->aspectBox->value(); } -void KisBrushSizeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisBrushSizeOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { BrushSizeOption op; op.brush_diameter = m_options->diameter->value(); op.brush_aspect = m_options->aspectBox->value(); op.brush_rotation = m_options->rotationBox->value(); op.brush_scale = m_options->scale->value(); op.brush_spacing = m_options->spacing->value(); op.brush_density = m_options->densityBox->value() / 100.0; op.brush_jitter_movement = m_options->jitterMove->value(); op.brush_jitter_movement_enabled = m_options->jitterMoveBox->isChecked(); op.writeOptionSetting(setting); } -void KisBrushSizeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisBrushSizeOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { BrushSizeOption op; op.readOptionSetting(setting); m_options->diameter->setValue(op.brush_diameter); m_options->aspectBox->setValue(op.brush_aspect); m_options->rotationBox->setValue(op.brush_rotation); m_options->scale->setValue(op.brush_scale); m_options->spacing->setValue(op.brush_spacing); m_options->densityBox->setValue(op.brush_density * 100.0); m_options->jitterMove->setValue(op.brush_jitter_movement); m_options->jitterMoveBox->setChecked(op.brush_jitter_movement_enabled); } void KisBrushSizeOption::setSpacing(qreal spacing) { m_options->spacing->setValue(spacing); } qreal KisBrushSizeOption::spacing() const { return m_options->spacing->value(); } diff --git a/plugins/paintops/deform/kis_brush_size_option.h b/plugins/paintops/deform/kis_brush_size_option.h index 62cd3f2855..f80f7c737d 100644 --- a/plugins/paintops/deform/kis_brush_size_option.h +++ b/plugins/paintops/deform/kis_brush_size_option.h @@ -1,97 +1,98 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_SIZE_OPTION_H_ #define KIS_SIZE_OPTION_H_ #include #include #include class KisBrushSizeOptionsWidget; const QString BRUSH_SHAPE = "Brush/shape"; const QString BRUSH_DIAMETER = "Brush/diameter"; const QString BRUSH_ASPECT = "Brush/aspect"; const QString BRUSH_SCALE = "Brush/scale"; const QString BRUSH_ROTATION = "Brush/rotation"; const QString BRUSH_SPACING = "Brush/spacing"; const QString BRUSH_DENSITY = "Brush/density"; const QString BRUSH_JITTER_MOVEMENT = "Brush/jitterMovement"; const QString BRUSH_JITTER_MOVEMENT_ENABLED = "Brush/jitterMovementEnabled"; class KisBrushSizeOption : public KisPaintOpOption { public: KisBrushSizeOption(); ~KisBrushSizeOption(); int diameter() const; void setDiameter(int diameter); void setSpacing(qreal spacing); qreal spacing() const; qreal brushAspect() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisBrushSizeOptionsWidget * m_options; }; class BrushSizeOption { public: qreal brush_diameter; qreal brush_aspect; qreal brush_rotation; qreal brush_scale; qreal brush_spacing; qreal brush_density; qreal brush_jitter_movement; bool brush_jitter_movement_enabled; public: - void readOptionSetting(const KisPropertiesConfiguration* setting) { + + void readOptionSetting(const KisPropertiesConfigurationSP setting) { brush_diameter = setting->getDouble(BRUSH_DIAMETER); brush_aspect = setting->getDouble(BRUSH_ASPECT); brush_rotation = setting->getDouble(BRUSH_ROTATION); brush_scale = setting->getDouble(BRUSH_SCALE); brush_spacing = setting->getDouble(BRUSH_SPACING); brush_density = setting->getDouble(BRUSH_DENSITY); brush_jitter_movement = setting->getDouble(BRUSH_JITTER_MOVEMENT); brush_jitter_movement_enabled = setting->getBool(BRUSH_JITTER_MOVEMENT_ENABLED); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(BRUSH_DIAMETER, brush_diameter); setting->setProperty(BRUSH_ASPECT, brush_aspect); setting->setProperty(BRUSH_ROTATION, brush_rotation); setting->setProperty(BRUSH_SCALE, brush_scale); setting->setProperty(BRUSH_SPACING, brush_spacing); setting->setProperty(BRUSH_DENSITY, brush_density); setting->setProperty(BRUSH_JITTER_MOVEMENT, brush_jitter_movement); setting->setProperty(BRUSH_JITTER_MOVEMENT_ENABLED, brush_jitter_movement_enabled); } }; #endif diff --git a/plugins/paintops/deform/kis_deform_option.cpp b/plugins/paintops/deform/kis_deform_option.cpp index dd17a0098f..43579d33fc 100644 --- a/plugins/paintops/deform/kis_deform_option.cpp +++ b/plugins/paintops/deform/kis_deform_option.cpp @@ -1,154 +1,154 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_deform_option.h" #include "ui_wdgdeformoptions.h" #include class KisDeformOptionsWidget: public QWidget, public Ui::WdgDeformOptions { public: KisDeformOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); deformAmount->setRange(0.0, 1.0, 2); deformAmount->setValue(0.20); } }; KisDeformOption::KisDeformOption() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { setObjectName("KisDeformOption"); m_checkable = false; m_options = new KisDeformOptionsWidget(); connect(m_options->deformAmount, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->interpolationChBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->useCounter, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->useOldData, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->growBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->shrinkBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->swirlCWBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->swirlCCWBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->moveBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->lensBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->lensOutBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->colorBtn, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisDeformOption::~KisDeformOption() { delete m_options; } -void KisDeformOption::readOptionSetting(const KisPropertiesConfiguration * setting) +void KisDeformOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { DeformOption op; op.readOptionSetting(setting); m_options->deformAmount->setValue(op.deform_amount); m_options->interpolationChBox->setChecked(op.deform_use_bilinear); m_options->useCounter->setChecked(op.deform_use_counter); m_options->useOldData->setChecked(op.deform_use_old_data); int deformAction = op.deform_action; if (deformAction == 1) { m_options->growBtn->setChecked(true); } else if (deformAction == 2) { m_options->shrinkBtn->setChecked(true); } else if (deformAction == 3) { m_options->swirlCWBtn->setChecked(true); } else if (deformAction == 4) { m_options->swirlCCWBtn->setChecked(true); } else if (deformAction == 5) { m_options->moveBtn->setChecked(true); } else if (deformAction == 6) { m_options->lensBtn->setChecked(true); } else if (deformAction == 7) { m_options->lensOutBtn->setChecked(true); } else if (deformAction == 8) { m_options->colorBtn->setChecked(true); } } -void KisDeformOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisDeformOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { DeformOption op; op.deform_amount = m_options->deformAmount->value(); op.deform_action = deformAction(); op.deform_use_bilinear = m_options->interpolationChBox->isChecked(); op.deform_use_counter = m_options->useCounter->isChecked(); op.deform_use_old_data = m_options->useOldData->isChecked(); op.writeOptionSetting(setting); } void KisDeformOption::lodLimitations(KisPaintopLodLimitations *l) const { l->blockers << KoID("deform-brush", i18nc("PaintOp instant preview limitation", "Deform Brush (unsupported)")); } int KisDeformOption::deformAction() const { //TODO: make it nicer using enums or something if (m_options->growBtn->isChecked()) { return 1; } else if (m_options->shrinkBtn->isChecked()) { return 2; } else if (m_options->swirlCWBtn->isChecked()) { return 3; } else if (m_options->swirlCCWBtn->isChecked()) { return 4; } else if (m_options->moveBtn->isChecked()) { return 5; } else if (m_options->lensBtn->isChecked()) { return 6; } else if (m_options->lensOutBtn->isChecked()) { return 7; } else if (m_options->colorBtn->isChecked()) { return 8; } else { return -1; } } diff --git a/plugins/paintops/deform/kis_deform_option.h b/plugins/paintops/deform/kis_deform_option.h index af901f36e9..c99f4b94c1 100644 --- a/plugins/paintops/deform/kis_deform_option.h +++ b/plugins/paintops/deform/kis_deform_option.h @@ -1,81 +1,81 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_DEFORM_OPTION_H #define KIS_DEFORM_OPTION_H #include class KisDeformOptionsWidget; class KisPaintopLodLimitations; const QString DEFORM_AMOUNT = "Deform/deformAmount"; const QString DEFORM_ACTION = "Deform/deformAction"; const QString DEFORM_USE_BILINEAR = "Deform/bilinear"; const QString DEFORM_USE_MOVEMENT_PAINT = "Deform/useMovementPaint"; const QString DEFORM_USE_COUNTER = "Deform/useCounter"; const QString DEFORM_USE_OLD_DATA = "Deform/useOldData"; class KisDeformOption : public KisPaintOpOption { public: KisDeformOption(); ~KisDeformOption(); double deformAmount() const; int deformAction() const; bool bilinear() const; bool useMovementPaint() const; bool useCounter() const; bool useOldData() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private: KisDeformOptionsWidget * m_options; }; struct DeformOption { qreal deform_amount; bool deform_use_bilinear; bool deform_use_counter; bool deform_use_old_data; int deform_action; - void readOptionSetting(const KisPropertiesConfiguration * config) { + void readOptionSetting(const KisPropertiesConfigurationSP config) { deform_amount = config->getDouble(DEFORM_AMOUNT); deform_use_bilinear = config->getBool(DEFORM_USE_BILINEAR); deform_use_counter = config->getBool(DEFORM_USE_COUNTER); deform_use_old_data = config->getBool(DEFORM_USE_OLD_DATA); deform_action = config->getInt(DEFORM_ACTION); } - void writeOptionSetting(KisPropertiesConfiguration* config) const { + void writeOptionSetting(KisPropertiesConfigurationSP config) const { config->setProperty(DEFORM_AMOUNT, deform_amount); config->setProperty(DEFORM_ACTION, deform_action); config->setProperty(DEFORM_USE_BILINEAR, deform_use_bilinear); config->setProperty(DEFORM_USE_COUNTER, deform_use_counter); config->setProperty(DEFORM_USE_OLD_DATA, deform_use_old_data); } }; #endif diff --git a/plugins/paintops/deform/kis_deform_paintop.cpp b/plugins/paintops/deform/kis_deform_paintop.cpp index 78e32b94b9..6cea8bbf43 100644 --- a/plugins/paintops/deform/kis_deform_paintop.cpp +++ b/plugins/paintops/deform/kis_deform_paintop.cpp @@ -1,145 +1,145 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_deform_paintop.h" #include "kis_deform_paintop_settings.h" #include #include #include #include #include #include "kis_global.h" #include "kis_paint_device.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_random_accessor_ng.h" #include #include "kis_deform_option.h" #include "kis_brush_size_option.h" #include #include #ifdef Q_OS_WIN // quoting DRAND48(3) man-page: // These functions are declared obsolete by SVID 3, // which states that rand(3) should be used instead. #define drand48() (static_cast(qrand()) / static_cast(RAND_MAX)) #endif -KisDeformPaintOp::KisDeformPaintOp(const KisDeformPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisDeformPaintOp::KisDeformPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); Q_ASSERT(settings); m_sizeProperties.readOptionSetting(settings); m_properties.readOptionSetting(settings); // sensors m_sizeOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_deformBrush.setProperties(&m_properties); m_deformBrush.setSizeProperties(&m_sizeProperties); m_deformBrush.initDeformAction(); m_dev = source(); if ((m_sizeProperties.brush_diameter * 0.5) > 1) { m_ySpacing = m_xSpacing = m_sizeProperties.brush_diameter * 0.5 * m_sizeProperties.brush_spacing; } else { m_ySpacing = m_xSpacing = 1.0; } m_spacing = m_xSpacing; } KisDeformPaintOp::~KisDeformPaintOp() { } KisSpacingInformation KisDeformPaintOp::paintAt(const KisPaintInformation& info) { if (!painter()) return KisSpacingInformation(m_spacing); if (!m_dev) return KisSpacingInformation(m_spacing); KisFixedPaintDeviceSP dab = cachedDab(source()->compositionSourceColorSpace()); qint32 x; qreal subPixelX; qint32 y; qreal subPixelY; QPointF pt = info.pos(); if (m_sizeProperties.brush_jitter_movement_enabled) { pt.setX(pt.x() + ((m_sizeProperties.brush_diameter * drand48()) - m_sizeProperties.brush_diameter * 0.5) * m_sizeProperties.brush_jitter_movement); pt.setY(pt.y() + ((m_sizeProperties.brush_diameter * drand48()) - m_sizeProperties.brush_diameter * 0.5) * m_sizeProperties.brush_jitter_movement); } qreal rotation = m_rotationOption.apply(info); // Deform Brush is capable of working with zero scale, // so no additional checks for 'zero'ness are needed qreal scale = m_sizeOption.apply(info); rotation += m_sizeProperties.brush_rotation; scale *= m_sizeProperties.brush_scale; QPointF pos = pt - m_deformBrush.hotSpot(scale, rotation); splitCoordinate(pos.x(), &x, &subPixelX); splitCoordinate(pos.y(), &y, &subPixelY); KisFixedPaintDeviceSP mask = m_deformBrush.paintMask(dab, m_dev, scale, rotation, info.pos(), subPixelX, subPixelY, x, y ); // this happens for the first dab of the move mode, we need more information for being able to move if (!mask) { return KisSpacingInformation(m_spacing); } quint8 origOpacity = m_opacityOption.apply(painter(), info); painter()->bltFixedWithFixedSelection(x, y, dab, mask, mask->bounds().width() , mask->bounds().height()); painter()->renderMirrorMask(QRect(QPoint(x, y), QSize(mask->bounds().width() , mask->bounds().height())), dab, mask); painter()->setOpacity(origOpacity); return KisSpacingInformation(m_spacing); } diff --git a/plugins/paintops/deform/kis_deform_paintop.h b/plugins/paintops/deform/kis_deform_paintop.h index 372d31d46c..7ab4fc2d28 100644 --- a/plugins/paintops/deform/kis_deform_paintop.h +++ b/plugins/paintops/deform/kis_deform_paintop.h @@ -1,63 +1,63 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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_DEFORMPAINTOP_H_ #define KIS_DEFORMPAINTOP_H_ #include #include #include #include #include #include "deform_brush.h" #include "kis_deform_paintop_settings.h" #include "kis_deform_option.h" class KisPainter; class KisDeformPaintOp : public KisPaintOp { public: - KisDeformPaintOp(const KisDeformPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisDeformPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); virtual ~KisDeformPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: KisPaintDeviceSP m_dab; KisPaintDeviceSP m_dev; DeformBrush m_deformBrush; DeformOption m_properties; BrushSizeOption m_sizeProperties; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisPressureRotationOption m_rotationOption; qreal m_xSpacing; qreal m_ySpacing; qreal m_spacing; }; #endif // KIS_DEFORMPAINTOP_H_ diff --git a/plugins/paintops/deform/kis_deform_paintop_settings.cpp b/plugins/paintops/deform/kis_deform_paintop_settings.cpp index 5ba280120e..1c3e2f8307 100644 --- a/plugins/paintops/deform/kis_deform_paintop_settings.cpp +++ b/plugins/paintops/deform/kis_deform_paintop_settings.cpp @@ -1,218 +1,230 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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 struct KisDeformPaintOpSettings::Private { QList uniformProperties; }; KisDeformPaintOpSettings::KisDeformPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION), m_d(new Private) { } KisDeformPaintOpSettings::~KisDeformPaintOpSettings() { } bool KisDeformPaintOpSettings::paintIncremental() { return true; } bool KisDeformPaintOpSettings::isAirbrushing() const { // version 2.3 if (hasProperty(AIRBRUSH_ENABLED)) { return getBool(AIRBRUSH_ENABLED); } else { return getBool(DEFORM_USE_MOVEMENT_PAINT); } } int KisDeformPaintOpSettings::rate() const { if (hasProperty(AIRBRUSH_RATE)) { return getInt(AIRBRUSH_RATE); } else { return KisPaintOpSettings::rate(); } } -QPainterPath KisDeformPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisDeformPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { qreal width = getInt(BRUSH_DIAMETER); qreal height = getInt(BRUSH_DIAMETER) * getDouble(BRUSH_ASPECT); path = ellipseOutline(width, height, getDouble(BRUSH_SCALE), getDouble(BRUSH_ROTATION)); + + QPainterPath tiltLine; + QLineF tiltAngle(QPointF(0.0,0.0), QPointF(0.0,width)); + tiltAngle.setLength(qMax(width*0.5, 50.0) * (1 - info.tiltElevation(info, 60.0, 60.0, true))); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))-3.0); + tiltLine.moveTo(tiltAngle.p1()); + tiltLine.lineTo(tiltAngle.p2()); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))+3.0); + tiltLine.lineTo(tiltAngle.p2()); + tiltLine.lineTo(tiltAngle.p1()); + + path = outlineFetcher()->fetchOutline(info, this, path); if (mode == CursorTiltOutline) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), width * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_brush_size_option.h" #include "kis_deform_option.h" #include "kis_standard_uniform_properties_factory.h" QList KisDeformPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "deform_amount", i18n("Amount"), this, 0); prop->setRange(0.01, 1.0); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.deform_amount); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); option.deform_amount = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisComboBasedPaintOpPropertyCallback *prop = new KisComboBasedPaintOpPropertyCallback( "deform_mode", i18n("Deform Mode"), this, 0); QList modes; modes << i18n("Grow"); modes << i18n("Shrink"); modes << i18n("Swirl CW"); modes << i18n("Swirl CCW"); modes << i18n("Move"); modes << i18n("Lens Zoom In"); modes << i18n("Lens Zoom Out"); modes << i18n("Color Deformation"); prop->setItems(modes); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.deform_action - 1)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); option.deform_action = prop->value().toInt() + 1; option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "deform_angle", i18n("Angle"), this, 0); const QString degree = QChar(Qt::Key_degree); prop->setRange(0, 360); prop->setSingleStep(1); prop->setSuffix(degree); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { BrushSizeOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.brush_rotation)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { BrushSizeOption option; option.readOptionSetting(prop->settings().data()); option.brush_rotation = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties()) { if (prop->id() == opacity.id() || prop->id() == size.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/deform/kis_deform_paintop_settings.h b/plugins/paintops/deform/kis_deform_paintop_settings.h index c4d885548c..a132962244 100644 --- a/plugins/paintops/deform/kis_deform_paintop_settings.h +++ b/plugins/paintops/deform/kis_deform_paintop_settings.h @@ -1,46 +1,46 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008,2009 Lukáš Tvrdý * * 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_DEFORM_PAINTOP_SETTINGS_H_ #define KIS_DEFORM_PAINTOP_SETTINGS_H_ #include #include #include #include class KisDeformPaintOpSettings : public KisOutlineGenerationPolicy { public: KisDeformPaintOpSettings(); ~KisDeformPaintOpSettings(); - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); bool paintIncremental(); bool isAirbrushing() const; int rate() const; QList uniformProperties(); private: struct Private; const QScopedPointer m_d; }; #endif diff --git a/plugins/paintops/deform/kis_deform_paintop_settings_widget.cpp b/plugins/paintops/deform/kis_deform_paintop_settings_widget.cpp index bb2f5199db..78f636e4e2 100644 --- a/plugins/paintops/deform/kis_deform_paintop_settings_widget.cpp +++ b/plugins/paintops/deform/kis_deform_paintop_settings_widget.cpp @@ -1,80 +1,80 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_deform_paintop_settings.h" #include "kis_deform_paintop_settings_widget.h" #include "kis_deform_option.h" #include #include #include #include #include #include #include #include KisDeformPaintOpSettingsWidget::KisDeformPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { m_deformOption = new KisDeformOption(); m_brushSizeOption = new KisBrushSizeOption(); m_brushSizeOption->setDiameter(200); addPaintOpOption(m_brushSizeOption, i18n("Brush size")); addPaintOpOption(m_deformOption, i18n("Deform Options")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisAirbrushOption(), i18n("Airbrush")); } KisDeformPaintOpSettingsWidget::~ KisDeformPaintOpSettingsWidget() { } void KisDeformPaintOpSettingsWidget::changePaintOpSize(qreal x, qreal y) { // if the movement is more left<->right then up<->down if (qAbs(x) > qAbs(y)) { m_brushSizeOption->setDiameter(m_brushSizeOption->diameter() + qRound(x)); } else { // vice-versa // we can do something different, e.g. change deform mode or ... } } QSizeF KisDeformPaintOpSettingsWidget::paintOpSize() const { qreal height = m_brushSizeOption->diameter() * m_brushSizeOption->brushAspect(); return QSizeF(m_brushSizeOption->diameter(), height); } -KisPropertiesConfiguration* KisDeformPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisDeformPaintOpSettingsWidget::configuration() const { KisDeformPaintOpSettings* config = new KisDeformPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "deformBrush"); writeConfiguration(config); return config; } diff --git a/plugins/paintops/deform/kis_deform_paintop_settings_widget.h b/plugins/paintops/deform/kis_deform_paintop_settings_widget.h index 1811409a97..56fcdddbb3 100644 --- a/plugins/paintops/deform/kis_deform_paintop_settings_widget.h +++ b/plugins/paintops/deform/kis_deform_paintop_settings_widget.h @@ -1,43 +1,43 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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_DEFORM_PAINTOP_SETTINGS_WIDGET_H_ #define KIS_DEFORM_PAINTOP_SETTINGS_WIDGET_H_ #include class KisDeformOption; class KisBrushSizeOption; class KisDeformPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisDeformPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisDeformPaintOpSettingsWidget(); - virtual KisPropertiesConfiguration* configuration() const; + virtual KisPropertiesConfigurationSP configuration() const; virtual void changePaintOpSize(qreal x, qreal y); virtual QSizeF paintOpSize() const; private: KisDeformOption * m_deformOption; KisBrushSizeOption * m_brushSizeOption; }; #endif diff --git a/plugins/paintops/dynadraw/kis_dyna_paintop.cpp b/plugins/paintops/dynadraw/kis_dyna_paintop.cpp index 2b349bdc4b..1a9a636537 100644 --- a/plugins/paintops/dynadraw/kis_dyna_paintop.cpp +++ b/plugins/paintops/dynadraw/kis_dyna_paintop.cpp @@ -1,112 +1,112 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_dyna_paintop.h" #include "kis_dyna_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_dynaop_option.h" #include "filter.h" -KisDynaPaintOp::KisDynaPaintOp(const KisDynaPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisDynaPaintOp::KisDynaPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(node); if (image) { m_dynaBrush.setCanvasSize(image->width(), image->height()); } else { // some dummy values for scratchpad m_dynaBrush.setCanvasSize(1000, 1000); } m_properties.initWidth = settings->getDouble(DYNA_WIDTH); m_properties.action = settings->getDouble(DYNA_ACTION); m_properties.mass = settings->getDouble(DYNA_MASS); m_properties.drag = settings->getDouble(DYNA_DRAG); double angle = settings->getDouble(DYNA_ANGLE); m_properties.xAngle = cos(angle * M_PI / 180.0); m_properties.yAngle = sin(angle * M_PI / 180.0); m_properties.widthRange = settings->getDouble(DYNA_WIDTH_RANGE); m_properties.diameter = settings->getInt(DYNA_DIAMETER); m_properties.lineCount = settings->getInt(DYNA_LINE_COUNT); m_properties.lineSpacing = settings->getDouble(DYNA_LINE_SPACING); m_properties.enableLine = settings->getBool(DYNA_ENABLE_LINE); m_properties.useTwoCircles = settings->getBool(DYNA_USE_TWO_CIRCLES); m_properties.useFixedAngle = settings->getBool(DYNA_USE_FIXED_ANGLE); m_dynaBrush.setProperties(&m_properties); } KisDynaPaintOp::~KisDynaPaintOp() { } void KisDynaPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); Q_UNUSED(pi2); if (!painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } qreal x1, y1; x1 = pi1.pos().x(); y1 = pi1.pos().y(); m_dynaBrush.updateCursorPosition(pi1.pos()); m_dynaBrush.paint(m_dab, x1, y1, painter()->paintColor()); QRect rc = m_dab->extent(); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); } KisSpacingInformation KisDynaPaintOp::paintAt(const KisPaintInformation& info) { KisDistanceInformation di; paintLine(info, info, &di); return di.currentSpacing(); } diff --git a/plugins/paintops/dynadraw/kis_dyna_paintop.h b/plugins/paintops/dynadraw/kis_dyna_paintop.h index 0853cb0a6e..21cd132bbd 100644 --- a/plugins/paintops/dynadraw/kis_dyna_paintop.h +++ b/plugins/paintops/dynadraw/kis_dyna_paintop.h @@ -1,53 +1,53 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_DYNA_PAINTOP_H_ #define KIS_DYNA_PAINTOP_H_ #include #include #include #include "dyna_brush.h" class KisPainter; class KisDynaPaintOpSettings; class KisDynaPaintOp : public KisPaintOp { public: - KisDynaPaintOp(const KisDynaPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisDynaPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisDynaPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); virtual bool incremental() const { return true; } private: KisDynaProperties m_properties; KisPaintDeviceSP m_dab; DynaBrush m_dynaBrush; }; #endif // KIS_DYNA_PAINTOP_H_ diff --git a/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.cpp b/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.cpp index bbb923a416..940551fd9a 100644 --- a/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.cpp +++ b/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.cpp @@ -1,49 +1,49 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_dyna_paintop_settings_widget.h" #include "kis_dynaop_option.h" #include "kis_dyna_paintop_settings.h" #include #include #include #include #include KisDynaPaintOpSettingsWidget:: KisDynaPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { addPaintOpOption(new KisDynaOpOption(), i18n("Brush size")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisAirbrushOption(), i18n("Airbrush")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisDynaPaintOpSettingsWidget::~ KisDynaPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisDynaPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisDynaPaintOpSettingsWidget::configuration() const { KisDynaPaintOpSettings* config = new KisDynaPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "dynabrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.h b/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.h index 67ee5bd114..4aab1dc441 100644 --- a/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.h +++ b/plugins/paintops/dynadraw/kis_dyna_paintop_settings_widget.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_DYNAPAINTOP_SETTINGS_WIDGET_H_ #define KIS_DYNAPAINTOP_SETTINGS_WIDGET_H_ #include class KisDynaPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisDynaPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisDynaPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif diff --git a/plugins/paintops/dynadraw/kis_dynaop_option.cpp b/plugins/paintops/dynadraw/kis_dynaop_option.cpp index 3f02765d89..9ca5d0cbe6 100644 --- a/plugins/paintops/dynadraw/kis_dynaop_option.cpp +++ b/plugins/paintops/dynadraw/kis_dynaop_option.cpp @@ -1,189 +1,189 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_dynaop_option.h" #include #include #include "ui_wdgdynaoptions.h" class KisDynaOpOptionsWidget: public QWidget, public Ui::WdgDynaOptions { public: KisDynaOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); angleSlider->setRange(0, 360, 0); angleSlider->setValue(0); angleSlider->setSingleStep(1); angleSlider->setSuffix(QChar(Qt::Key_degree)); diameterDSSB->setRange(0, 1000, 0); diameterDSSB->setValue(20); diameterDSSB->setExponentRatio(3.0); } }; KisDynaOpOption::KisDynaOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisDynaOpOption"); m_checkable = false; m_options = new KisDynaOpOptionsWidget(); //ui connect(m_options->fixedAngleChBox, SIGNAL(toggled(bool)), m_options->angleSlider, SLOT(setEnabled(bool))); // preset connect(m_options->circleRBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->polygonRBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->wireRBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->linesRBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->initWidthSPBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); connect(m_options->massSPBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); connect(m_options->dragSPBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); connect(m_options->angleSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->widthRangeSPBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); connect(m_options->diameterDSSB, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->lineCountSPBox, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->lineSpacingSPBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); connect(m_options->LineCBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->twoCBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->fixedAngleChBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisDynaOpOption::~KisDynaOpOption() { delete m_options; } qreal KisDynaOpOption::initWidth() const { return m_options->initWidthSPBox->value(); } qreal KisDynaOpOption::mass() const { return m_options->massSPBox->value(); } qreal KisDynaOpOption::drag() const { return m_options->dragSPBox->value(); } bool KisDynaOpOption::useFixedAngle() const { return m_options->fixedAngleChBox->isChecked(); } qreal KisDynaOpOption::widthRange() const { return m_options->widthRangeSPBox->value(); } int KisDynaOpOption::action() const { if (m_options->circleRBox->isChecked()) return 0; if (m_options->polygonRBox->isChecked()) return 1; if (m_options->wireRBox->isChecked()) return 2; if (m_options->linesRBox->isChecked()) return 3; return 0; } bool KisDynaOpOption::enableLine() const { return m_options->LineCBox->isChecked(); } bool KisDynaOpOption::useTwoCircles() const { return m_options->twoCBox->isChecked(); } int KisDynaOpOption::lineCount() const { return m_options->lineCountSPBox->value(); } qreal KisDynaOpOption::lineSpacing() const { return m_options->lineSpacingSPBox->value(); } -void KisDynaOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisDynaOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { DynaOption op; op.dyna_width = initWidth(); op.dyna_mass = mass(); op.dyna_drag = drag(); op.dyna_use_fixed_angle = useFixedAngle(); op.dyna_angle = m_options->angleSlider->value(); op.dyna_width_range = widthRange(); op.dyna_action = action(); op.dyna_diameter = m_options->diameterDSSB->value(); op.dyna_enable_line = enableLine(); op.dyna_use_two_circles = useTwoCircles(); op.dyna_line_count = lineCount(); op.dyna_line_spacing = lineSpacing(); op.writeOptionSetting(setting); } -void KisDynaOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisDynaOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { DynaOption op; op.readOptionSetting(setting); switch (op.dyna_action) { case 0: m_options->circleRBox->setChecked(true); break; case 1: m_options->polygonRBox->setChecked(true); break; case 2: m_options->wireRBox->setChecked(true); break; case 3: m_options->linesRBox->setChecked(true); break; default: break; } m_options->initWidthSPBox->setValue(op.dyna_width); m_options->massSPBox->setValue(op.dyna_mass); m_options->dragSPBox->setValue(op.dyna_drag); m_options->angleSlider->setValue(op.dyna_angle); m_options->widthRangeSPBox->setValue(op.dyna_width_range); m_options->diameterDSSB->setValue(op.dyna_diameter); m_options->lineCountSPBox->setValue(op.dyna_line_count); m_options->lineSpacingSPBox->setValue(op.dyna_line_spacing); m_options->LineCBox->setChecked(op.dyna_enable_line); m_options->twoCBox->setChecked(op.dyna_use_two_circles); m_options->fixedAngleChBox->setChecked(op.dyna_use_fixed_angle); } void KisDynaOpOption::lodLimitations(KisPaintopLodLimitations *l) const { l->blockers << KoID("dyna-brush", i18nc("PaintOp instant preview limitation", "Dyna Brush (not supported)")); } diff --git a/plugins/paintops/dynadraw/kis_dynaop_option.h b/plugins/paintops/dynadraw/kis_dynaop_option.h index f7f096ea2a..a8618b3166 100644 --- a/plugins/paintops/dynadraw/kis_dynaop_option.h +++ b/plugins/paintops/dynadraw/kis_dynaop_option.h @@ -1,117 +1,117 @@ /* * Copyright (c) 2009-2010 Lukáš Tvrdý * * 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_DYNAOP_OPTION_H #define KIS_DYNAOP_OPTION_H #include const QString DYNA_DIAMETER = "Dyna/diameter"; const QString DYNA_WIDTH = "Dyna/width"; const QString DYNA_MASS = "Dyna/mass"; const QString DYNA_DRAG = "Dyna/drag"; const QString DYNA_USE_FIXED_ANGLE = "Dyna/useFixedAngle"; const QString DYNA_ANGLE = "Dyna/angle"; const QString DYNA_WIDTH_RANGE = "Dyna/widthRange"; const QString DYNA_ACTION = "Dyna/action"; const QString DYNA_USE_TWO_CIRCLES = "Dyna/useTwoCirles"; const QString DYNA_ENABLE_LINE = "Dyna/enableLine"; const QString DYNA_LINE_COUNT = "Dyna/lineCount"; const QString DYNA_LINE_SPACING = "Dyna/lineSpacing"; class KisDynaOpOptionsWidget; class KisPaintopLodLimitations; class KisDynaOpOption : public KisPaintOpOption { Q_OBJECT public: KisDynaOpOption(); ~KisDynaOpOption(); qreal initWidth() const; qreal mass() const; qreal drag() const; bool useFixedAngle() const; qreal widthRange() const; int action() const; bool enableLine() const; bool useTwoCircles() const; int lineCount() const; qreal lineSpacing() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private: KisDynaOpOptionsWidget * m_options; }; struct DynaOption { int dyna_action; qreal dyna_width; qreal dyna_mass; qreal dyna_drag; qreal dyna_angle; qreal dyna_width_range; int dyna_diameter; int dyna_line_count; qreal dyna_line_spacing; bool dyna_enable_line; bool dyna_use_two_circles; bool dyna_use_fixed_angle; - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(DYNA_WIDTH, dyna_width); setting->setProperty(DYNA_MASS, dyna_mass); setting->setProperty(DYNA_DRAG, dyna_drag); setting->setProperty(DYNA_USE_FIXED_ANGLE, dyna_use_fixed_angle); setting->setProperty(DYNA_ANGLE, dyna_angle); setting->setProperty(DYNA_WIDTH_RANGE, dyna_width_range); setting->setProperty(DYNA_ACTION, dyna_action); setting->setProperty(DYNA_DIAMETER, dyna_diameter); setting->setProperty(DYNA_ENABLE_LINE, dyna_enable_line); setting->setProperty(DYNA_USE_TWO_CIRCLES, dyna_use_two_circles); setting->setProperty(DYNA_LINE_COUNT, dyna_line_count); setting->setProperty(DYNA_LINE_SPACING, dyna_line_spacing); } - void readOptionSetting(const KisPropertiesConfiguration* setting) { + void readOptionSetting(const KisPropertiesConfigurationSP setting) { dyna_action = setting->getInt(DYNA_ACTION); dyna_width = setting->getDouble(DYNA_WIDTH); dyna_mass = setting->getDouble(DYNA_MASS); dyna_drag = setting->getDouble(DYNA_DRAG); dyna_angle = setting->getDouble(DYNA_ANGLE); dyna_width_range = setting->getDouble(DYNA_WIDTH_RANGE); dyna_diameter = setting->getInt(DYNA_DIAMETER); dyna_line_count = setting->getInt(DYNA_LINE_COUNT); dyna_line_spacing = setting->getDouble(DYNA_LINE_SPACING); dyna_enable_line = setting->getBool(DYNA_ENABLE_LINE); dyna_use_two_circles = setting->getBool(DYNA_USE_TWO_CIRCLES); dyna_use_fixed_angle = setting->getBool(DYNA_USE_FIXED_ANGLE); } }; #endif diff --git a/plugins/paintops/experiment/kis_experiment_paintop.cpp b/plugins/paintops/experiment/kis_experiment_paintop.cpp index 92b806e183..d23c735498 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop.cpp +++ b/plugins/paintops/experiment/kis_experiment_paintop.cpp @@ -1,384 +1,384 @@ /* * Copyright (c) 2010-2011 Lukáš Tvrdý * Copyright (c) 2012 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_experiment_paintop.h" #include "kis_experiment_paintop_settings.h" #include #include #include #include #include #include #include -KisExperimentPaintOp::KisExperimentPaintOp(const KisExperimentPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisExperimentPaintOp::KisExperimentPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); m_firstRun = true; m_experimentOption.readOptionSetting(settings); m_displaceEnabled = m_experimentOption.isDisplacementEnabled; m_displaceCoeff = (m_experimentOption.displacement * 0.01 * 14) + 1; // 1..15 [7 default according alchemy] m_speedEnabled = m_experimentOption.isSpeedEnabled; m_speedMultiplier = (m_experimentOption.speed * 0.01 * 35); // 0..35 [15 default according alchemy] m_smoothingEnabled = m_experimentOption.isSmoothingEnabled; m_smoothingThreshold = m_experimentOption.smoothing; m_useMirroring = painter->hasMirroring(); m_windingFill = m_experimentOption.windingFill; m_hardEdge = m_experimentOption.hardEdge; if (m_useMirroring) { m_originalDevice = source()->createCompositionSourceDevice(); m_originalPainter = new KisPainter(m_originalDevice); m_originalPainter->setCompositeOp(COMPOSITE_COPY); m_originalPainter->setPaintColor(painter->paintColor()); m_originalPainter->setFillStyle(KisPainter::FillStyleForegroundColor); } else { m_originalPainter = 0; } } KisExperimentPaintOp::~KisExperimentPaintOp() { delete m_originalPainter; } void KisExperimentPaintOp::paintRegion(const QRegion &changedRegion) { if (m_windingFill) { m_path.setFillRule(Qt::WindingFill); } if (m_useMirroring) { m_originalPainter->setAntiAliasPolygonFill(!m_hardEdge); Q_FOREACH (const QRect & rect, changedRegion.rects()) { m_originalPainter->fillPainterPath(m_path, rect); painter()->renderDabWithMirroringNonIncremental(rect, m_originalDevice); } } else { painter()->setFillStyle(KisPainter::FillStyleForegroundColor); painter()->setCompositeOp(COMPOSITE_COPY); painter()->setAntiAliasPolygonFill(!m_hardEdge); Q_FOREACH (const QRect & rect, changedRegion.rects()) { painter()->fillPainterPath(m_path, rect); } } } QPointF KisExperimentPaintOp::speedCorrectedPosition(const KisPaintInformation& pi1, const KisPaintInformation& pi2) { const qreal fadeFactor = 0.6; QPointF diff = pi2.pos() - pi1.pos(); qreal realLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); if (realLength < 0.1) return pi2.pos(); qreal coeff = 0.5 * realLength * m_speedMultiplier; m_savedSpeedCoeff = fadeFactor * m_savedSpeedCoeff + (1 - fadeFactor) * coeff; QPointF newPoint = pi1.pos() + diff * m_savedSpeedCoeff / realLength; m_savedSpeedPoint = fadeFactor * m_savedSpeedPoint + (1 - fadeFactor) * newPoint; return m_savedSpeedPoint; } void KisExperimentPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); if (!painter()) return; if (m_firstRun) { m_firstRun = false; m_path.moveTo(pi1.pos()); m_path.lineTo(pi2.pos()); m_center = pi1.pos(); m_savedUpdateDistance = 0; m_lastPaintTime = 0; m_savedSpeedCoeff = 0; m_savedSpeedPoint = m_center; m_savedSmoothingDistance = 0; m_savedSmoothingPoint = m_center; } else { const QPointF pos1 = pi1.pos(); QPointF pos2 = pi2.pos(); if (m_speedEnabled) { pos2 = speedCorrectedPosition(pi1, pi2); } int length = (pos2 - pos1).manhattanLength(); m_savedUpdateDistance += length; if (m_smoothingEnabled) { m_savedSmoothingDistance += length; if (m_savedSmoothingDistance > m_smoothingThreshold) { QPointF pt = (m_savedSmoothingPoint + pos2) * 0.5; // for updates approximate curve with two lines m_savedPoints << m_path.currentPosition(); m_savedPoints << m_savedSmoothingPoint; m_savedPoints << m_savedSmoothingPoint; m_savedPoints << pt; m_path.quadTo(m_savedSmoothingPoint, pt); m_savedSmoothingPoint = pos2; m_savedSmoothingDistance = 0; } } else { m_path.lineTo(pos2); m_savedPoints << pos1; m_savedPoints << pos2; } if (m_displaceEnabled) { if (m_path.elementCount() % 16 == 0) { QRectF bounds = m_path.boundingRect(); m_path = applyDisplace(m_path, m_displaceCoeff - length); bounds |= m_path.boundingRect(); qreal threshold = simplifyThreshold(bounds); m_path = trySimplifyPath(m_path, threshold); } else { m_path = applyDisplace(m_path, m_displaceCoeff - length); } } /** * Refresh rate at least 25fps */ const int timeThreshold = 40; const int elapsedTime = pi2.currentTime() - m_lastPaintTime; QRect pathBounds = m_path.boundingRect().toRect(); int distanceMetric = qMax(pathBounds.width(), pathBounds.height()); if (elapsedTime > timeThreshold || (!m_displaceEnabled && m_savedUpdateDistance > distanceMetric / 8)) { if (m_displaceEnabled) { /** * Rendering the path with diff'ed rects is up to two * times more efficient for really huge shapes (tested * on 2000+ px shapes), however for smaller ones doing * paths arithmetics eats too much time. That's why we * choose the method on the base of the size of the * shape. */ const int pathSizeThreshold = 128; QRegion changedRegion; if (distanceMetric < pathSizeThreshold) { QRectF changedRect = m_path.boundingRect().toRect() | m_lastPaintedPath.boundingRect().toRect(); changedRect.adjust(-1, -1, 1, 1); changedRegion = changedRect.toRect(); } else { QPainterPath diff1 = m_path - m_lastPaintedPath; QPainterPath diff2 = m_lastPaintedPath - m_path; changedRegion = KritaUtils::splitPath(diff1 | diff2); } paintRegion(changedRegion); m_lastPaintedPath = m_path; } else if (!m_savedPoints.isEmpty()) { QRegion changedRegion = KritaUtils::splitTriangles(m_center, m_savedPoints); paintRegion(changedRegion); } m_savedPoints.clear(); m_savedUpdateDistance = 0; m_lastPaintTime = pi2.currentTime(); } } } KisSpacingInformation KisExperimentPaintOp::paintAt(const KisPaintInformation& info) { Q_UNUSED(info); return KisSpacingInformation(1.0); } bool tryMergePoints(QPainterPath &path, const QPointF &startPoint, const QPointF &endPoint, qreal &distance, qreal distanceThreshold, bool lastSegment) { qreal length = (endPoint - startPoint).manhattanLength(); if (lastSegment || length > distanceThreshold) { if (distance != 0) { path.lineTo(startPoint); } distance = 0; return false; } distance += length; if (distance > distanceThreshold) { path.lineTo(endPoint); distance = 0; } return true; } qreal KisExperimentPaintOp::simplifyThreshold(const QRectF &bounds) { qreal maxDimension = qMax(bounds.width(), bounds.height()); return qMax(0.01 * maxDimension, 1.0); } QPainterPath KisExperimentPaintOp::trySimplifyPath(const QPainterPath &path, qreal lengthThreshold) { QPainterPath newPath; QPointF startPoint; qreal distance = 0; int count = path.elementCount(); for (int i = 0; i < count; i++) { QPainterPath::Element e = path.elementAt(i); QPointF endPoint = QPointF(e.x, e.y); switch (e.type) { case QPainterPath::MoveToElement: newPath.moveTo(endPoint); break; case QPainterPath::LineToElement: if (!tryMergePoints(newPath, startPoint, endPoint, distance, lengthThreshold, i == count - 1)) { newPath.lineTo(endPoint); } break; case QPainterPath::CurveToElement: { Q_ASSERT(i + 2 < count); if (!tryMergePoints(newPath, startPoint, endPoint, distance, lengthThreshold, i == count - 1)) { e = path.elementAt(i + 1); Q_ASSERT(e.type == QPainterPath::CurveToDataElement); QPointF ctrl1 = QPointF(e.x, e.y); e = path.elementAt(i + 2); Q_ASSERT(e.type == QPainterPath::CurveToDataElement); QPointF ctrl2 = QPointF(e.x, e.y); newPath.cubicTo(ctrl1, ctrl2, endPoint); } i += 2; } default: ; } startPoint = endPoint; } return newPath; } QPointF KisExperimentPaintOp::getAngle(const QPointF& p1, const QPointF& p2, qreal distance) { QPointF diff = p1 - p2; qreal realLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); return realLength > 0.5 ? p1 + diff * distance / realLength : p1; } QPainterPath KisExperimentPaintOp::applyDisplace(const QPainterPath& path, int speed) { QPointF lastPoint = path.currentPosition(); QPainterPath newPath; int count = path.elementCount(); int curveElementCounter = 0; QPointF ctrl1; QPointF ctrl2; QPointF endPoint; for (int i = 0; i < count; i++) { QPainterPath::Element e = path.elementAt(i); switch (e.type) { case QPainterPath::MoveToElement: { newPath.moveTo(getAngle(QPointF(e.x, e.y), lastPoint, speed)); break; } case QPainterPath::LineToElement: { newPath.lineTo(getAngle(QPointF(e.x, e.y), lastPoint, speed)); break; } case QPainterPath::CurveToElement: { curveElementCounter = 0; endPoint = getAngle(QPointF(e.x, e.y), lastPoint, speed); break; } case QPainterPath::CurveToDataElement: { curveElementCounter++; if (curveElementCounter == 1) { ctrl1 = getAngle(QPointF(e.x, e.y), lastPoint, speed); } else if (curveElementCounter == 2) { ctrl2 = getAngle(QPointF(e.x, e.y), lastPoint, speed); newPath.cubicTo(ctrl1, ctrl2, endPoint); } break; } } }// for return newPath; } diff --git a/plugins/paintops/experiment/kis_experiment_paintop.h b/plugins/paintops/experiment/kis_experiment_paintop.h index 513172b5f8..5c98e70bc6 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop.h +++ b/plugins/paintops/experiment/kis_experiment_paintop.h @@ -1,87 +1,87 @@ /* * Copyright (c) 2010-2011 Lukáš Tvrdý * * 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_EXPERIMENT_PAINTOP_H_ #define KIS_EXPERIMENT_PAINTOP_H_ #include #include #include #include "kis_experiment_paintop_settings.h" #include "kis_experimentop_option.h" class QPointF; class KisPainter; class KisExperimentPaintOp : public KisPaintOp { public: - KisExperimentPaintOp(const KisExperimentPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisExperimentPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); ~KisExperimentPaintOp(); void paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance); KisSpacingInformation paintAt(const KisPaintInformation& info); private: void paintRegion(const QRegion &changedRegion); QPointF speedCorrectedPosition(const KisPaintInformation& pi1, const KisPaintInformation& pi2); static qreal simplifyThreshold(const QRectF &bounds); static QPainterPath trySimplifyPath(const QPainterPath &path, qreal lengthThreshold); static QPointF getAngle(const QPointF& p1, const QPointF& p2, qreal distance); static QPainterPath applyDisplace(const QPainterPath& path, int speed); bool m_displaceEnabled; int m_displaceCoeff; QPainterPath m_lastPaintedPath; bool m_windingFill; bool m_hardEdge; bool m_speedEnabled; int m_speedMultiplier; qreal m_savedSpeedCoeff; QPointF m_savedSpeedPoint; bool m_smoothingEnabled; int m_smoothingThreshold; QPointF m_savedSmoothingPoint; int m_savedSmoothingDistance; int m_savedUpdateDistance; QVector m_savedPoints; int m_lastPaintTime; bool m_firstRun; QPointF m_center; QPainterPath m_path; ExperimentOption m_experimentOption; bool m_useMirroring; KisPainter *m_originalPainter; KisPaintDeviceSP m_originalDevice; }; #endif // KIS_EXPERIMENT_PAINTOP_H_ diff --git a/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp b/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp index e28e478115..b4d98bbe76 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp +++ b/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp @@ -1,261 +1,261 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_experiment_paintop_settings.h" #include "kis_current_outline_fetcher.h" struct KisExperimentPaintOpSettings::Private { QList uniformProperties; }; KisExperimentPaintOpSettings::KisExperimentPaintOpSettings() : m_d(new Private) { } KisExperimentPaintOpSettings::~KisExperimentPaintOpSettings() { } bool KisExperimentPaintOpSettings::paintIncremental() { /** * The experiment brush supports working in the * WASH mode only! */ return false; } -QPainterPath KisExperimentPaintOpSettings::brushOutline(const KisPaintInformation &info, KisPaintOpSettings::OutlineMode mode) const +QPainterPath KisExperimentPaintOpSettings::brushOutline(const KisPaintInformation &info, KisPaintOpSettings::OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { QRectF ellipse(0, 0, 3, 3); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); ellipse.setRect(0,0, 12, 12); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); if (mode == CursorTiltOutline) { path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 3.0)); } path.translate(info.pos()); } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_experimentop_option.h" #include "kis_standard_uniform_properties_factory.h" QList KisExperimentPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_speed", i18n("Speed"), this, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.speed)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.speed = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) -> bool { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isSpeedEnabled; }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_smooth", i18n("Smooth"), this, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.smoothing)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.smoothing = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isSmoothingEnabled; }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_displace", i18n("Displace"), this, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.displacement)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.displacement = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isDisplacementEnabled; }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "shape_windingfill", i18n("Winding Fill"), this, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.windingFill); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.windingFill = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "shape_hardedge", i18n("Hard Edge"), this, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.hardEdge); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.hardEdge = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties()) { if (prop->id() == opacity.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/experiment/kis_experiment_paintop_settings.h b/plugins/paintops/experiment/kis_experiment_paintop_settings.h index 9701ec4b6c..e3cc39d619 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop_settings.h +++ b/plugins/paintops/experiment/kis_experiment_paintop_settings.h @@ -1,41 +1,42 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_EXPERIMENT_PAINTOP_SETTINGS_H_ #define KIS_EXPERIMENT_PAINTOP_SETTINGS_H_ #include #include class KisExperimentPaintOpSettings : public KisPaintOpSettings { public: KisExperimentPaintOpSettings(); - ~KisExperimentPaintOpSettings(); + virtual ~KisExperimentPaintOpSettings(); bool paintIncremental(); - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); QList uniformProperties(); private: + struct Private; const QScopedPointer m_d; }; #endif diff --git a/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.cpp b/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.cpp index 225d4f5528..229c55107a 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.cpp +++ b/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.cpp @@ -1,56 +1,56 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_experiment_paintop_settings_widget.h" #include "kis_experimentop_option.h" #include "kis_experiment_paintop_settings.h" #include #include #include #include #include #include #include KisExperimentPaintOpSettingsWidget:: KisExperimentPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { addPaintOpOption(new KisExperimentOpOption(), i18n("Experiment option")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); //addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); } KisExperimentPaintOpSettingsWidget::~ KisExperimentPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisExperimentPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisExperimentPaintOpSettingsWidget::configuration() const { KisExperimentPaintOpSettings* config = new KisExperimentPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "experimentbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } void KisExperimentPaintOpSettingsWidget::changePaintOpSize(qreal /*x*/, qreal /*y*/) { //m_experimentOption->setDiameter( m_experimentOption->startSize() + qRound(x) ); } diff --git a/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.h b/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.h index ec136ccc1a..b60868074d 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.h +++ b/plugins/paintops/experiment/kis_experiment_paintop_settings_widget.h @@ -1,36 +1,36 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_EXPERIMENTPAINTOP_SETTINGS_WIDGET_H_ #define KIS_EXPERIMENTPAINTOP_SETTINGS_WIDGET_H_ #include class KisExperimentPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisExperimentPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisExperimentPaintOpSettingsWidget(); virtual void changePaintOpSize(qreal x, qreal y); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif diff --git a/plugins/paintops/experiment/kis_experimentop_option.cpp b/plugins/paintops/experiment/kis_experimentop_option.cpp index 7ede67e258..ca0a41c397 100644 --- a/plugins/paintops/experiment/kis_experimentop_option.cpp +++ b/plugins/paintops/experiment/kis_experimentop_option.cpp @@ -1,135 +1,135 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_experimentop_option.h" #include #include #include "ui_wdgexperimentoptions.h" class KisExperimentOpOptionsWidget: public QWidget, public Ui::WdgExperimentOptions { public: KisExperimentOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); speed->setRange(0.0, 100.0, 0); speed->setSuffix(QChar(Qt::Key_Percent)); speed->setValue(42.0); speed->setSingleStep(1.0); smoothThreshold->setRange(0.0, 100.0, 0); smoothThreshold->setSuffix(i18n(" px")); smoothThreshold->setValue(20.0); smoothThreshold->setSingleStep(1.0); displaceStrength->setRange(0.0, 100.0, 0); displaceStrength->setSuffix(QChar(Qt::Key_Percent)); displaceStrength->setValue(42.0); displaceStrength->setSingleStep(1.0); } }; KisExperimentOpOption::KisExperimentOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisExperimentOpOption"); m_checkable = false; m_options = new KisExperimentOpOptionsWidget(); connect(m_options->displaceCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->displaceStrength, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->speedCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->speed, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->smoothCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->smoothThreshold, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->displaceStrength, SIGNAL(valueChanged(qreal)), SLOT(enableDisplacement(qreal))); connect(m_options->speed, SIGNAL(valueChanged(qreal)), SLOT(enableSpeed(qreal))); connect(m_options->smoothThreshold, SIGNAL(valueChanged(qreal)), SLOT(enableSmooth(qreal))); connect(m_options->windingFillCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->hardEdgeCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisExperimentOpOption::~KisExperimentOpOption() { delete m_options; } -void KisExperimentOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisExperimentOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { ExperimentOption op; op.isDisplacementEnabled = m_options->displaceCHBox->isChecked(); op.displacement = m_options->displaceStrength->value(); op.isSpeedEnabled = m_options->speedCHBox->isChecked(); op.speed = m_options->speed->value(); op.isSmoothingEnabled = m_options->smoothCHBox->isChecked(); op.smoothing = m_options->smoothThreshold->value(); op.windingFill = m_options->windingFillCHBox->isChecked(); op.hardEdge = m_options->hardEdgeCHBox->isChecked(); op.writeOptionSetting(setting); } -void KisExperimentOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisExperimentOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { ExperimentOption op; op.readOptionSetting(setting); m_options->displaceStrength->setValue(op.displacement); m_options->speed->setValue(op.speed); m_options->smoothThreshold->setValue(op.smoothing); m_options->windingFillCHBox->setChecked(op.windingFill); m_options->hardEdgeCHBox->setChecked(op.hardEdge); m_options->speedCHBox->setChecked(op.isSpeedEnabled); m_options->smoothCHBox->setChecked(op.isSmoothingEnabled); m_options->displaceCHBox->setChecked(op.isDisplacementEnabled); } inline void enableCheckBox(QCheckBox *checkBox, qreal sliderValue) { checkBox->setChecked(sliderValue > 0); } void KisExperimentOpOption::enableSpeed(qreal value) { enableCheckBox(m_options->speedCHBox, value); } void KisExperimentOpOption::enableSmooth(qreal value) { enableCheckBox(m_options->smoothCHBox, value); } void KisExperimentOpOption::enableDisplacement(qreal value) { enableCheckBox(m_options->displaceCHBox, value); } void KisExperimentOpOption::lodLimitations(KisPaintopLodLimitations *l) const { if (m_options->displaceCHBox->isChecked()) { l->blockers << KoID("experiment-displacement", i18nc("PaintOp instant preview limitation", "Displacement Option")); } } diff --git a/plugins/paintops/experiment/kis_experimentop_option.h b/plugins/paintops/experiment/kis_experimentop_option.h index 6f126b52ba..18dc154e26 100644 --- a/plugins/paintops/experiment/kis_experimentop_option.h +++ b/plugins/paintops/experiment/kis_experimentop_option.h @@ -1,98 +1,98 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_EXPERIMENTOP_OPTION_H #define KIS_EXPERIMENTOP_OPTION_H #include class KisPaintopLodLimitations; const QString EXPERIMENT_DISPLACEMENT_ENABLED = "Experiment/displacementEnabled"; const QString EXPERIMENT_DISPLACEMENT_VALUE = "Experiment/displacement"; const QString EXPERIMENT_SMOOTHING_ENABLED = "Experiment/smoothing"; const QString EXPERIMENT_SMOOTHING_VALUE = "Experiment/smoothingValue"; const QString EXPERIMENT_SPEED_ENABLED = "Experiment/speedEnabled"; const QString EXPERIMENT_SPEED_VALUE = "Experiment/speed"; const QString EXPERIMENT_WINDING_FILL = "Experiment/windingFill"; const QString EXPERIMENT_HARD_EDGE = "Experiment/hardEdge"; class KisExperimentOpOptionsWidget; class KisExperimentOpOption : public KisPaintOpOption { Q_OBJECT public: KisExperimentOpOption(); ~KisExperimentOpOption(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private Q_SLOTS: void enableSpeed(qreal value); void enableSmooth(qreal value); void enableDisplacement(qreal value); private: KisExperimentOpOptionsWidget * m_options; }; class ExperimentOption { public: bool isDisplacementEnabled; qreal displacement; bool isSpeedEnabled; qreal speed; bool isSmoothingEnabled; qreal smoothing; bool windingFill; bool hardEdge; - void readOptionSetting(const KisPropertiesConfiguration* setting) { + void readOptionSetting(const KisPropertiesConfigurationSP setting) { isDisplacementEnabled = setting->getBool(EXPERIMENT_DISPLACEMENT_ENABLED); displacement = setting->getDouble(EXPERIMENT_DISPLACEMENT_VALUE, 50.0); isSpeedEnabled = setting->getBool(EXPERIMENT_SPEED_ENABLED); speed = setting->getDouble(EXPERIMENT_SPEED_VALUE, 50.0); isSmoothingEnabled = setting->getBool(EXPERIMENT_SMOOTHING_ENABLED); smoothing = setting->getDouble(EXPERIMENT_SMOOTHING_VALUE, 20.0); windingFill = setting->getBool(EXPERIMENT_WINDING_FILL); hardEdge = setting->getBool(EXPERIMENT_HARD_EDGE); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(EXPERIMENT_DISPLACEMENT_ENABLED, isDisplacementEnabled); setting->setProperty(EXPERIMENT_DISPLACEMENT_VALUE, displacement); setting->setProperty(EXPERIMENT_SPEED_ENABLED, isSpeedEnabled); setting->setProperty(EXPERIMENT_SPEED_VALUE, speed); setting->setProperty(EXPERIMENT_SMOOTHING_ENABLED, isSmoothingEnabled); setting->setProperty(EXPERIMENT_SMOOTHING_VALUE, smoothing); setting->setProperty(EXPERIMENT_WINDING_FILL, windingFill); setting->setProperty(EXPERIMENT_HARD_EDGE, hardEdge); } }; #endif diff --git a/plugins/paintops/filterop/kis_filterop.cpp b/plugins/paintops/filterop/kis_filterop.cpp index 2b2746e944..74a022be53 100644 --- a/plugins/paintops/filterop/kis_filterop.cpp +++ b/plugins/paintops/filterop/kis_filterop.cpp @@ -1,145 +1,145 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_filterop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisFilterOp::KisFilterOp(const KisFilterOpSettings *settings, KisPainter *painter, KisNodeSP node, KisImageSP image) +KisFilterOp::KisFilterOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_filterConfiguration(0) { Q_UNUSED(node); Q_UNUSED(image); Q_ASSERT(settings); Q_ASSERT(painter); m_tmpDevice = source()->createCompositionSourceDevice(); m_sizeOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_filter = KisFilterRegistry::instance()->get(settings->getString(FILTER_ID)); - m_filterConfiguration = settings->filterConfig(); + m_filterConfiguration = static_cast(settings.data())->filterConfig(); m_smudgeMode = settings->getBool(FILTER_SMUDGE_MODE); m_rotationOption.applyFanCornersInfo(this); } KisFilterOp::~KisFilterOp() { } KisSpacingInformation KisFilterOp::paintAt(const KisPaintInformation& info) { if (!painter()) { return KisSpacingInformation(1.0); } if (!m_filter) { return KisSpacingInformation(1.0); } if (!source()) { return KisSpacingInformation(1.0); } KisBrushSP brush = m_brush; if (!brush) return KisSpacingInformation(1.0); if (! brush->canPaintFor(info)) return KisSpacingInformation(1.0); qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); qreal rotation = m_rotationOption.apply(info); KisDabShape shape(scale, 1.0, rotation); static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); static KoColor color(Qt::black, cs); QRect dstRect; KisFixedPaintDeviceSP dab = m_dabCache->fetchDab(cs, color, info.pos(), shape, info, 1.0, &dstRect); if (dstRect.isEmpty()) return KisSpacingInformation(1.0); QRect dabRect = dab->bounds(); // sanity check Q_ASSERT(dstRect.size() == dabRect.size()); // Filter the paint device QRect neededRect = m_filter->neededRect(dstRect, m_filterConfiguration, painter()->device()->defaultBounds()->currentLevelOfDetail()); KisPainter p(m_tmpDevice); if (!m_smudgeMode) { p.setCompositeOp(COMPOSITE_COPY); } p.bitBltOldData(neededRect.topLeft() - dstRect.topLeft(), source(), neededRect); KisTransaction transaction(m_tmpDevice); m_filter->process(m_tmpDevice, dabRect, m_filterConfiguration, 0); transaction.end(); painter()-> bitBltWithFixedSelection(dstRect.x(), dstRect.y(), m_tmpDevice, dab, 0, 0, dabRect.x(), dabRect.y(), dabRect.width(), dabRect.height()); painter()->renderMirrorMaskSafe(dstRect, m_tmpDevice, 0, 0, dab, !m_dabCache->needSeparateOriginal()); return effectiveSpacing(scale, rotation); } diff --git a/plugins/paintops/filterop/kis_filterop.h b/plugins/paintops/filterop/kis_filterop.h index e6a947117b..c152b39795 100644 --- a/plugins/paintops/filterop/kis_filterop.h +++ b/plugins/paintops/filterop/kis_filterop.h @@ -1,55 +1,55 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_FILTEROP_H_ #define KIS_FILTEROP_H_ #include "kis_brush_based_paintop.h" #include #include class KisFilterConfiguration; class KisFilterOpSettings; class KisPaintInformation; class KisPainter; class KisFilterOp : public KisBrushBasedPaintOp { public: - KisFilterOp(const KisFilterOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisFilterOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisFilterOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: KisPaintDeviceSP m_tmpDevice; KisPressureSizeOption m_sizeOption; KisPressureRotationOption m_rotationOption; KisFilterSP m_filter; - KisFilterConfiguration* m_filterConfiguration; + KisFilterConfigurationSP m_filterConfiguration; bool m_smudgeMode; }; #endif // KIS_FILTEROP_H_ diff --git a/plugins/paintops/filterop/kis_filterop_settings.cpp b/plugins/paintops/filterop/kis_filterop_settings.cpp index 4fa6b281f2..876aa8b498 100644 --- a/plugins/paintops/filterop/kis_filterop_settings.cpp +++ b/plugins/paintops/filterop/kis_filterop_settings.cpp @@ -1,90 +1,88 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_filterop_settings.h" #include #include #include #include #include #include #include #include #include KisFilterOpSettings::KisFilterOpSettings() { setPropertyNotSaved(FILTER_CONFIGURATION); } KisFilterOpSettings::~KisFilterOpSettings() { } bool KisFilterOpSettings::paintIncremental() { return true; // We always paint on the existing data } -KisFilterConfiguration* KisFilterOpSettings::filterConfig() const +KisFilterConfigurationSP KisFilterOpSettings::filterConfig() const { if (hasProperty(FILTER_ID)) { KisFilterSP filter = KisFilterRegistry::instance()->get(getString(FILTER_ID)); if (filter) { - KisFilterConfiguration* configuration = filter->factoryConfiguration(0); + KisFilterConfigurationSP configuration = filter->factoryConfiguration(0); configuration->fromXML(getString(FILTER_CONFIGURATION)); return configuration; } } return 0; } void KisFilterOpSettings::toXML(QDomDocument& doc, QDomElement& root) const { KisPaintOpSettings::toXML(doc, root); - KisFilterConfiguration* configuration = filterConfig(); + KisFilterConfigurationSP configuration = filterConfig(); if (configuration) { QDomElement e = doc.createElement("filterconfig"); configuration->toXML(doc, e); root.appendChild(e); } - delete configuration; } void KisFilterOpSettings::fromXML(const QDomElement& e) { KisPaintOpSettings::fromXML(e); QDomElement element = e.firstChildElement("filterconfig"); if (hasProperty(FILTER_ID)) { KisFilterSP filter = KisFilterRegistry::instance()->get(getString(FILTER_ID)); if (filter) { - KisFilterConfiguration* configuration = filter->factoryConfiguration(0); + KisFilterConfigurationSP configuration = filter->factoryConfiguration(0); configuration->fromXML(element); setProperty(FILTER_CONFIGURATION, configuration->toXML()); - delete configuration; } } } diff --git a/plugins/paintops/filterop/kis_filterop_settings.h b/plugins/paintops/filterop/kis_filterop_settings.h index 9c7d3483d8..8dcee32fc5 100644 --- a/plugins/paintops/filterop/kis_filterop_settings.h +++ b/plugins/paintops/filterop/kis_filterop_settings.h @@ -1,54 +1,54 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_FILTEROP_SETTINGS_H_ #define KIS_FILTEROP_SETTINGS_H_ #include #include #include "kis_filterop_settings_widget.h" class QDomElement; class KisFilterConfiguration; class KisFilterOpSettings : public KisBrushBasedPaintOpSettings { public: KisFilterOpSettings(); virtual ~KisFilterOpSettings(); bool paintIncremental(); - KisFilterConfiguration* filterConfig() const; + KisFilterConfigurationSP filterConfig() const; using KisPaintOpSettings::toXML; void toXML(QDomDocument& doc, QDomElement& root) const; using KisPaintOpSettings::fromXML; void fromXML(const QDomElement& e); }; #endif // KIS_FILTEROP_SETTINGS_H_ diff --git a/plugins/paintops/filterop/kis_filterop_settings_widget.cpp b/plugins/paintops/filterop/kis_filterop_settings_widget.cpp index 08f9d6658a..70e05467af 100644 --- a/plugins/paintops/filterop/kis_filterop_settings_widget.cpp +++ b/plugins/paintops/filterop/kis_filterop_settings_widget.cpp @@ -1,71 +1,71 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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. */ #include "kis_filterop_settings_widget.h" #include "kis_filterop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" KisFilterOpSettingsWidget::KisFilterOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { setObjectName("filter option widget"); setPrecisionEnabled(true); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); m_filterOption = new KisFilterOption(); addPaintOpOption(m_filterOption, i18nc("option name", "Filter")); } KisFilterOpSettingsWidget::~KisFilterOpSettingsWidget() { } -KisPropertiesConfiguration* KisFilterOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisFilterOpSettingsWidget::configuration() const { KisFilterOpSettings *config = new KisFilterOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "filter"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/filterop/kis_filterop_settings_widget.h b/plugins/paintops/filterop/kis_filterop_settings_widget.h index b2314b8f97..176fd000f8 100644 --- a/plugins/paintops/filterop/kis_filterop_settings_widget.h +++ b/plugins/paintops/filterop/kis_filterop_settings_widget.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 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_FILTEROP_SETTINGS_WIDGET_H_ #define KIS_FILTEROP_SETTINGS_WIDGET_H_ #include #include class KisFilterOption; class KisFilterOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisFilterOpSettingsWidget(QWidget* parent = 0); virtual ~KisFilterOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; public: KisFilterOption* m_filterOption; }; #endif // KIS_FILTEROP_SETTINGS_WIDGET_H_ diff --git a/plugins/paintops/gridbrush/kis_grid_paintop.cpp b/plugins/paintops/gridbrush/kis_grid_paintop.cpp index b2e09a8e47..dfd7dd5734 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop.cpp +++ b/plugins/paintops/gridbrush/kis_grid_paintop.cpp @@ -1,255 +1,255 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_grid_paintop.h" #include "kis_grid_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BENCHMARK #include #endif -KisGridPaintOp::KisGridPaintOp(const KisGridPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisGridPaintOp::KisGridPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) - , m_settings(settings) + , m_settings(static_cast(const_cast(settings.data()))) , m_image(image) , m_node(node) { m_properties.fillProperties(settings); m_colorProperties.fillProperties(settings); m_xSpacing = m_properties.gridWidth * m_properties.scale; m_ySpacing = m_properties.gridHeight * m_properties.scale; m_spacing = m_xSpacing; m_dab = source()->createCompositionSourceDevice(); m_painter = new KisPainter(m_dab); m_painter->setPaintColor(painter->paintColor()); m_painter->setFillStyle(KisPainter::FillStyleForegroundColor); #ifdef BENCHMARK m_count = m_total = 0; #endif } KisGridPaintOp::~KisGridPaintOp() { delete m_painter; } KisSpacingInformation KisGridPaintOp::paintAt(const KisPaintInformation& info) { #ifdef BENCHMARK QTime time; time.start(); #endif KisRandomSourceSP randomSource = info.randomSource(); const qreal additionalScale = KisLodTransform::lodToScale(painter()->device()); if (!painter()) return KisSpacingInformation(m_spacing * additionalScale); m_dab->clear(); qreal gridWidth = m_properties.gridWidth * m_properties.scale * additionalScale; qreal gridHeight = m_properties.gridHeight * m_properties.scale * additionalScale; int divide; if (m_properties.pressureDivision) { divide = m_properties.divisionLevel * info.pressure(); } else { divide = m_properties.divisionLevel; } divide = qRound(m_properties.scale * divide); qreal posX = info.pos().x(); qreal posY = info.pos().y(); posX = posX - std::fmod(posX, gridWidth); posY = posY - std::fmod(posY, gridHeight); const QRectF dabRect(posX, posY, gridWidth, gridHeight); const QRect dabRectAligned = dabRect.toAlignedRect(); divide = qMax(1, divide); const qreal yStep = gridHeight / (qreal)divide; const qreal xStep = gridWidth / (qreal)divide; QRectF tile; KoColor color(painter()->paintColor()); QScopedPointer colorPicker; if (m_node) { colorPicker.reset(new KisCrossDeviceColorPicker(m_node->paintDevice(), color)); } qreal vertBorder = m_properties.vertBorder * additionalScale; qreal horzBorder = m_properties.horizBorder * additionalScale; if (m_properties.randomBorder) { if (vertBorder == horzBorder) { vertBorder = horzBorder = vertBorder * randomSource->generateNormalized(); } else { vertBorder *= randomSource->generateNormalized(); horzBorder *= randomSource->generateNormalized(); } } bool shouldColor = true; // fill the tile if (m_colorProperties.fillBackground) { m_dab->fill(dabRectAligned, painter()->backgroundColor()); } for (int y = 0; y < divide; y++) { for (int x = 0; x < divide; x++) { // determine the tile size tile = QRectF(dabRect.x() + x * xStep, dabRect.y() + y * yStep, xStep, yStep); tile.adjust(vertBorder, horzBorder, -vertBorder, -horzBorder); tile = tile.normalized(); // do color transformation if (shouldColor) { if (colorPicker && m_colorProperties.sampleInputColor) { colorPicker->pickOldColor(tile.center().x(), tile.center().y(), color.data()); } // mix the color with background color if (m_colorProperties.mixBgColor) { KoMixColorsOp * mixOp = source()->colorSpace()->mixColorsOp(); const quint8 *colors[2]; colors[0] = color.data(); colors[1] = painter()->backgroundColor().data(); qint16 colorWeights[2]; int MAX_16BIT = 255; qreal blend = info.pressure(); colorWeights[0] = static_cast(blend * MAX_16BIT); colorWeights[1] = static_cast((1.0 - blend) * MAX_16BIT); mixOp->mixColors(colors, colorWeights, 2, color.data()); } if (m_colorProperties.useRandomHSV) { QHash params; params["h"] = (m_colorProperties.hue / 180.0) * randomSource->generateNormalized(); params["s"] = (m_colorProperties.saturation / 100.0) * randomSource->generateNormalized(); params["v"] = (m_colorProperties.value / 100.0) * randomSource->generateNormalized(); KoColorTransformation* transfo; transfo = m_dab->colorSpace()->createColorTransformation("hsv_adjustment", params); transfo->setParameter(3, 1);//sets the type to HSV. For some reason 0 is not an option. transfo->setParameter(4, false);//sets the colorize to false. transfo->transform(color.data(), color.data() , 1); } if (m_colorProperties.useRandomOpacity) { const qreal alpha = randomSource->generateNormalized(); color.setOpacity(alpha); m_painter->setOpacity(qRound(alpha * OPACITY_OPAQUE_U8)); } if (!m_colorProperties.colorPerParticle) { shouldColor = false; } m_painter->setPaintColor(color); } // paint some element switch (m_properties.shape) { case 0: { m_painter->paintEllipse(tile); break; } case 1: { // anti-aliased version //m_painter->paintRect(tile); m_dab->fill(tile.topLeft().x(), tile.topLeft().y(), tile.width(), tile.height(), color.data()); break; } case 2: { m_painter->drawDDALine(tile.topRight(), tile.bottomLeft()); break; } case 3: { m_painter->drawLine(tile.topRight(), tile.bottomLeft()); break; } case 4: { m_painter->drawThickLine(tile.topRight(), tile.bottomLeft() , 1, 10); break; } default: { break; } } if (m_colorProperties.colorPerParticle){ color=painter()->paintColor();//reset color// } } } QRect rc = m_dab->extent(); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); #ifdef BENCHMARK int msec = time.elapsed(); dbgKrita << msec << " ms/dab " << "[average: " << m_total / (qreal)m_count << "]"; m_total += msec; m_count++; #endif return KisSpacingInformation(m_spacing * additionalScale); } -void KisGridProperties::fillProperties(const KisPropertiesConfiguration* setting) +void KisGridProperties::fillProperties(const KisPropertiesConfigurationSP setting) { gridWidth = qMax(1, setting->getInt(GRID_WIDTH)); gridHeight = qMax(1, setting->getInt(GRID_HEIGHT)); divisionLevel = qMax(1, setting->getInt(GRID_DIVISION_LEVEL)); pressureDivision = setting->getBool(GRID_PRESSURE_DIVISION); randomBorder = setting->getBool(GRID_RANDOM_BORDER); scale = qMax(0.1, setting->getDouble(GRID_SCALE)); vertBorder = setting->getDouble(GRID_VERTICAL_BORDER); horizBorder = setting->getDouble(GRID_HORIZONTAL_BORDER); shape = setting->getInt(GRIDSHAPE_SHAPE); } diff --git a/plugins/paintops/gridbrush/kis_grid_paintop.h b/plugins/paintops/gridbrush/kis_grid_paintop.h index 54794dea78..849efdb61a 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop.h +++ b/plugins/paintops/gridbrush/kis_grid_paintop.h @@ -1,81 +1,81 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_GRID_PAINTOP_H_ #define KIS_GRID_PAINTOP_H_ //#define BENCHMARK #include #include #include #include #include "kis_grid_paintop_settings.h" class KisPainter; class KisGridProperties { public: quint16 gridWidth; quint16 gridHeight; quint16 divisionLevel; bool pressureDivision; bool randomBorder; qreal scale; qreal vertBorder; qreal horizBorder; quint8 shape; public: - void fillProperties(const KisPropertiesConfiguration* setting); + void fillProperties(const KisPropertiesConfigurationSP setting); }; class KisGridPaintOp : public KisPaintOp { public: - KisGridPaintOp(const KisGridPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisGridPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisGridPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: - const KisGridPaintOpSettings* m_settings; + KisGridPaintOpSettingsSP m_settings; KisImageWSP m_image; KisPaintDeviceSP m_dab; KisPainter* m_painter; qreal m_xSpacing; qreal m_ySpacing; qreal m_spacing; KisGridProperties m_properties; KisColorProperties m_colorProperties; KisNodeSP m_node; #ifdef BENCHMARK int m_total; int m_count; #endif }; #endif // KIS_GRID_PAINTOP_H_ diff --git a/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp b/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp index 6f4a57357d..bec9f645c6 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp +++ b/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp @@ -1,109 +1,124 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kis_grid_paintop_settings.h" #include "kis_grid_paintop_settings_widget.h" #include "kis_gridop_option.h" #include "kis_grid_shape_option.h" #include struct KisGridPaintOpSettings::Private { QList uniformProperties; }; KisGridPaintOpSettings::KisGridPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::NO_OPTION), m_d(new Private) { } +KisGridPaintOpSettings::~KisGridPaintOpSettings() +{ +} + bool KisGridPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } -QPainterPath KisGridPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisGridPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { qreal sizex = getInt(GRID_WIDTH) * getDouble(GRID_SCALE); qreal sizey = getInt(GRID_HEIGHT) * getDouble(GRID_SCALE); QRectF rc(0, 0, sizex, sizey); rc.translate(-rc.center()); path.addRect(rc); + + QPainterPath tiltLine; + QLineF tiltAngle(QPointF(0.0,0.0), QPointF(0.0,sizex)); + tiltAngle.setLength(qMax(sizex*0.5, 50.0) * (1 - info.tiltElevation(info, 60.0, 60.0, true))); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))-3.0); + tiltLine.moveTo(tiltAngle.p1()); + tiltLine.lineTo(tiltAngle.p2()); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))+3.0); + tiltLine.lineTo(tiltAngle.p2()); + tiltLine.lineTo(tiltAngle.p1()); + path = outlineFetcher()->fetchOutline(info, this, path); - + if (mode == CursorTiltOutline) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), sizex * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_gridop_option.h" QList KisGridPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "grid_divisionlevel", i18n("Division Level"), this, 0); prop->setRange(1, 25); prop->setSingleStep(1); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { GridOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.grid_division_level)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { GridOption option; option.readOptionSetting(prop->settings().data()); option.grid_division_level = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties() + props; } diff --git a/plugins/paintops/gridbrush/kis_grid_paintop_settings.h b/plugins/paintops/gridbrush/kis_grid_paintop_settings.h index c7827c0aec..232e71e5ad 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop_settings.h +++ b/plugins/paintops/gridbrush/kis_grid_paintop_settings.h @@ -1,47 +1,52 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_GRID_PAINTOP_SETTINGS_H_ #define KIS_GRID_PAINTOP_SETTINGS_H_ #include #include #include #include #include "kis_grid_paintop_settings_widget.h" class KisGridPaintOpSettings : public KisOutlineGenerationPolicy { public: KisGridPaintOpSettings(); + ~KisGridPaintOpSettings(); - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); bool paintIncremental(); QList uniformProperties(); private: + struct Private; const QScopedPointer m_d; + }; +typedef KisSharedPtr KisGridPaintOpSettingsSP; + #endif diff --git a/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.cpp b/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.cpp index bdac8f4135..09fa6deca6 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.cpp +++ b/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.cpp @@ -1,71 +1,71 @@ /* * Copyright (c) 2009 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_grid_paintop_settings_widget.h" #include "kis_gridop_option.h" #include "kis_grid_paintop_settings.h" #include "kis_grid_shape_option.h" #include #include #include #include #include KisGridPaintOpSettingsWidget:: KisGridPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { m_gridOption = new KisGridOpOption(); m_gridShapeOption = new KisGridShapeOption(); m_ColorOption = new KisColorOption(); addPaintOpOption(m_gridOption, i18n("Brush size")); addPaintOpOption(m_gridShapeOption, i18n("Particle type")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(m_ColorOption, i18n("Color options")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisGridPaintOpSettingsWidget::~ KisGridPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisGridPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisGridPaintOpSettingsWidget::configuration() const { KisGridPaintOpSettings* config = new KisGridPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "gridbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } void KisGridPaintOpSettingsWidget::changePaintOpSize(qreal x, qreal y) { if (qAbs(x) > qAbs(y)) { m_gridOption->setWidth(m_gridOption->gridWidth() + qRound(x)); m_gridOption->setHeight(m_gridOption->gridHeight() + qRound(x)); } else { //m_options->m_gridOption->setHeight( gridHeight() + qRound(y) ); } } QSizeF KisGridPaintOpSettingsWidget::paintOpSize() const { return QSizeF(m_gridOption->gridWidth(), m_gridOption->gridHeight()); } diff --git a/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.h b/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.h index 51c26988a5..cf6f88fcf7 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.h +++ b/plugins/paintops/gridbrush/kis_grid_paintop_settings_widget.h @@ -1,46 +1,46 @@ /* * Copyright (c) 2009 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_GRIDPAINTOP_SETTINGS_WIDGET_H_ #define KIS_GRIDPAINTOP_SETTINGS_WIDGET_H_ #include class KisGridOpOption; class KisGridShapeOption; class KisColorOption; class KisGridPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisGridPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisGridPaintOpSettingsWidget(); virtual void changePaintOpSize(qreal x, qreal y); virtual QSizeF paintOpSize() const; - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; public: KisGridOpOption *m_gridOption; KisGridShapeOption *m_gridShapeOption; KisColorOption *m_ColorOption; }; #endif diff --git a/plugins/paintops/gridbrush/kis_grid_shape_option.cpp b/plugins/paintops/gridbrush/kis_grid_shape_option.cpp index ebc121692b..6ddf20154f 100644 --- a/plugins/paintops/gridbrush/kis_grid_shape_option.cpp +++ b/plugins/paintops/gridbrush/kis_grid_shape_option.cpp @@ -1,63 +1,63 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_grid_shape_option.h" #include #include "ui_wdggridbrushshapeoptions.h" class KisShapeOptionsWidget: public QWidget, public Ui::WdgGridBrushShapeOptions { public: KisShapeOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisGridShapeOption::KisGridShapeOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisGridShapeOption"); m_checkable = false; m_options = new KisShapeOptionsWidget(); connect(m_options->shapeCBox, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisGridShapeOption::~KisGridShapeOption() { delete m_options; } int KisGridShapeOption::shape() const { return m_options->shapeCBox->currentIndex(); } -void KisGridShapeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisGridShapeOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(GRIDSHAPE_SHAPE, shape()); } -void KisGridShapeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisGridShapeOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_options->shapeCBox->setCurrentIndex(setting->getInt(GRIDSHAPE_SHAPE)); } diff --git a/plugins/paintops/gridbrush/kis_grid_shape_option.h b/plugins/paintops/gridbrush/kis_grid_shape_option.h index f89fe14486..4e178b5e35 100644 --- a/plugins/paintops/gridbrush/kis_grid_shape_option.h +++ b/plugins/paintops/gridbrush/kis_grid_shape_option.h @@ -1,44 +1,44 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_GRID_SHAPE_OPTION_H #define KIS_GRID_SHAPE_OPTION_H #include const QString GRIDSHAPE_SHAPE = "GridShape/shape"; class KisShapeOptionsWidget; class KisGridShapeOption : public KisPaintOpOption { public: KisGridShapeOption(); ~KisGridShapeOption(); /// Ellipse, rectangle, line, pixel, anti-aliased pixel int shape() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisShapeOptionsWidget * m_options; }; #endif // KIS_GRID_SHAPE_OPTION_H diff --git a/plugins/paintops/gridbrush/kis_gridop_option.cpp b/plugins/paintops/gridbrush/kis_gridop_option.cpp index b6bc61ccd0..b6bbd79261 100644 --- a/plugins/paintops/gridbrush/kis_gridop_option.cpp +++ b/plugins/paintops/gridbrush/kis_gridop_option.cpp @@ -1,175 +1,175 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_gridop_option.h" #include #include "ui_wdggridoptions.h" class KisGridOpOptionsWidget: public QWidget, public Ui::WdgGridOptions { public: KisGridOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisGridOpOption::KisGridOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisGridOpOption"); m_checkable = false; m_options = new KisGridOpOptionsWidget(); // initialize slider values m_options->gridWidthSPBox->setRange(1, 999, 0); m_options->gridWidthSPBox->setValue(25); m_options->gridWidthSPBox->setSuffix(i18n(" px")); m_options->gridWidthSPBox->setExponentRatio(3.0); m_options->gridHeightSPBox->setRange(1, 999, 0); m_options->gridHeightSPBox->setValue(25); m_options->gridHeightSPBox->setSuffix(i18n(" px")); m_options->gridHeightSPBox->setExponentRatio(3.0); m_options->divisionLevelSPBox->setRange(0, 25, 0); m_options->divisionLevelSPBox->setValue(2); m_options->scaleDSPBox->setRange(0.1, 10.0, 2); m_options->scaleDSPBox->setValue(1.0); m_options->scaleDSPBox->setExponentRatio(3.0); m_options->vertBorderDSPBox->setRange(0, 100, 2); m_options->vertBorderDSPBox->setValue(0.0); m_options->horizBorderDSPBox->setRange(0, 100, 2); m_options->vertBorderDSPBox->setValue(0.0); connect(m_options->gridWidthSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->gridHeightSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->divisionLevelSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->divisionPressureCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->scaleDSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->vertBorderDSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->horizBorderDSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->jitterBorderCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisGridOpOption::~KisGridOpOption() { delete m_options; } int KisGridOpOption::divisionLevel() const { return m_options->divisionLevelSPBox->value(); } int KisGridOpOption::gridWidth() const { return m_options->gridWidthSPBox->value(); } void KisGridOpOption::setWidth(int width) const { m_options->gridWidthSPBox->setValue(width); } int KisGridOpOption::gridHeight() const { return m_options->gridHeightSPBox->value(); } void KisGridOpOption::setHeight(int height) const { m_options->gridHeightSPBox->setValue(height); } bool KisGridOpOption::pressureDivision() const { return m_options->divisionPressureCHBox->isChecked(); } qreal KisGridOpOption::horizBorder() const { return m_options->vertBorderDSPBox->value(); } qreal KisGridOpOption::vertBorder() const { return m_options->horizBorderDSPBox->value(); } bool KisGridOpOption::randomBorder() const { return m_options->jitterBorderCHBox->isChecked(); } qreal KisGridOpOption::scale() const { return m_options->scaleDSPBox->value(); } -void KisGridOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisGridOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { GridOption op; op.grid_width = gridWidth(); op.grid_height = gridHeight(); op.grid_division_level = divisionLevel(); op.grid_pressure_division = pressureDivision(); op.grid_scale = scale(); op.grid_vertical_border = vertBorder(); op.grid_horizontal_border = horizBorder(); op.grid_random_border = randomBorder(); op.writeOptionSetting(setting); } -void KisGridOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisGridOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { GridOption op; op.readOptionSetting(setting); m_options->gridWidthSPBox->setValue(op.grid_width); m_options->gridHeightSPBox->setValue(op.grid_height); m_options->divisionLevelSPBox->setValue(op.grid_division_level); m_options->divisionPressureCHBox->setChecked(op.grid_pressure_division); m_options->scaleDSPBox->setValue(op.grid_scale); m_options->vertBorderDSPBox->setValue(op.grid_vertical_border); m_options->horizBorderDSPBox->setValue(op.grid_horizontal_border); m_options->jitterBorderCHBox->setChecked(op.grid_random_border); } diff --git a/plugins/paintops/gridbrush/kis_gridop_option.h b/plugins/paintops/gridbrush/kis_gridop_option.h index 3f67817b0d..98cbf5d295 100644 --- a/plugins/paintops/gridbrush/kis_gridop_option.h +++ b/plugins/paintops/gridbrush/kis_gridop_option.h @@ -1,100 +1,100 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_GRIDOP_OPTION_H #define KIS_GRIDOP_OPTION_H #include const QString GRID_WIDTH = "Grid/gridWidth"; const QString GRID_HEIGHT = "Grid/gridHeight"; const QString GRID_DIVISION_LEVEL = "Grid/divisionLevel"; const QString GRID_PRESSURE_DIVISION = "Grid/pressureDivision"; const QString GRID_SCALE = "Grid/scale"; const QString GRID_VERTICAL_BORDER = "Grid/verticalBorder"; const QString GRID_HORIZONTAL_BORDER = "Grid/horizontalBorder"; const QString GRID_RANDOM_BORDER = "Grid/randomBorder"; class KisGridOpOptionsWidget; class KisGridOpOption : public KisPaintOpOption { public: KisGridOpOption(); ~KisGridOpOption(); int gridWidth() const; void setWidth(int width) const; int gridHeight() const; void setHeight(int height) const; int divisionLevel() const; bool pressureDivision() const; qreal scale() const; qreal vertBorder() const; qreal horizBorder() const; bool randomBorder() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisGridOpOptionsWidget * m_options; }; struct GridOption { int grid_width; int grid_height; int grid_division_level; bool grid_pressure_division; qreal grid_scale; qreal grid_vertical_border; qreal grid_horizontal_border; bool grid_random_border; - void readOptionSetting(const KisPropertiesConfiguration* setting) { + void readOptionSetting(const KisPropertiesConfigurationSP setting) { grid_width = setting->getInt(GRID_WIDTH); grid_height = setting->getInt(GRID_HEIGHT); grid_division_level = setting->getInt(GRID_DIVISION_LEVEL); grid_pressure_division = setting->getBool(GRID_PRESSURE_DIVISION); grid_scale = setting->getDouble(GRID_SCALE); grid_vertical_border = setting->getDouble(GRID_VERTICAL_BORDER); grid_horizontal_border = setting->getDouble(GRID_HORIZONTAL_BORDER); grid_random_border = setting->getBool(GRID_RANDOM_BORDER); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(GRID_WIDTH, grid_width); setting->setProperty(GRID_HEIGHT, grid_height); setting->setProperty(GRID_DIVISION_LEVEL, grid_division_level); setting->setProperty(GRID_PRESSURE_DIVISION, grid_pressure_division); setting->setProperty(GRID_SCALE, grid_scale); setting->setProperty(GRID_VERTICAL_BORDER, grid_vertical_border); setting->setProperty(GRID_HORIZONTAL_BORDER, grid_horizontal_border); setting->setProperty(GRID_RANDOM_BORDER, grid_random_border); } }; #endif diff --git a/plugins/paintops/hairy/kis_hairy_bristle_option.cpp b/plugins/paintops/hairy/kis_hairy_bristle_option.cpp index 6b4f00a7a1..95aecc170d 100644 --- a/plugins/paintops/hairy/kis_hairy_bristle_option.cpp +++ b/plugins/paintops/hairy/kis_hairy_bristle_option.cpp @@ -1,104 +1,104 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_hairy_bristle_option.h" #include #include "ui_wdgbristleoptions.h" #include class KisBristleOptionsWidget: public QWidget, public Ui::WdgBristleOptions { public: KisBristleOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); rndBox->setRange(-10.0, 10.0, 2); rndBox->setValue(2.0); scaleBox->setRange(-10.0, 10.0, 2); scaleBox->setValue(2.0); shearBox->setRange(-2.0, 2.0, 2); shearBox->setValue(0.0); densityBox->setRange(0.0, 100.0, 0); densityBox->setValue(100.0); densityBox->setSuffix(QChar(Qt::Key_Percent)); } }; KisHairyBristleOption::KisHairyBristleOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisHairyBristleOption"); m_checkable = false; m_options = new KisBristleOptionsWidget(); // signals connect(m_options->mousePressureCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->thresholdCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->rndBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->scaleBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->shearBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->densityBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->connectedCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->antialiasCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->compositingCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisHairyBristleOption::~KisHairyBristleOption() { delete m_options; } -void KisHairyBristleOption::readOptionSetting(const KisPropertiesConfiguration* config) +void KisHairyBristleOption::readOptionSetting(const KisPropertiesConfigurationSP config) { m_options->thresholdCBox->setChecked(config->getBool(HAIRY_BRISTLE_THRESHOLD)); m_options->mousePressureCBox->setChecked(config->getBool(HAIRY_BRISTLE_USE_MOUSEPRESSURE)); m_options->shearBox->setValue(config->getDouble(HAIRY_BRISTLE_SHEAR)); m_options->rndBox->setValue(config->getDouble(HAIRY_BRISTLE_RANDOM)); m_options->scaleBox->setValue(config->getDouble(HAIRY_BRISTLE_SCALE)); m_options->densityBox->setValue(config->getDouble(HAIRY_BRISTLE_DENSITY)); m_options->connectedCBox->setChecked(config->getBool(HAIRY_BRISTLE_CONNECTED)); m_options->antialiasCBox->setChecked(config->getBool(HAIRY_BRISTLE_ANTI_ALIASING)); m_options->compositingCBox->setChecked(config->getBool(HAIRY_BRISTLE_USE_COMPOSITING)); } -void KisHairyBristleOption::writeOptionSetting(KisPropertiesConfiguration* config) const +void KisHairyBristleOption::writeOptionSetting(KisPropertiesConfigurationSP config) const { config->setProperty(HAIRY_BRISTLE_THRESHOLD, m_options->thresholdCBox->isChecked()); config->setProperty(HAIRY_BRISTLE_USE_MOUSEPRESSURE, m_options->mousePressureCBox->isChecked()); config->setProperty(HAIRY_BRISTLE_SCALE, m_options->scaleBox->value()); config->setProperty(HAIRY_BRISTLE_SHEAR, m_options->shearBox->value()); config->setProperty(HAIRY_BRISTLE_RANDOM, m_options->rndBox->value()); config->setProperty(HAIRY_BRISTLE_DENSITY, m_options->densityBox->value()); config->setProperty(HAIRY_BRISTLE_CONNECTED, m_options->connectedCBox->isChecked()); config->setProperty(HAIRY_BRISTLE_ANTI_ALIASING, m_options->antialiasCBox->isChecked()); config->setProperty(HAIRY_BRISTLE_USE_COMPOSITING, m_options->compositingCBox->isChecked()); } void KisHairyBristleOption::lodLimitations(KisPaintopLodLimitations *l) const { l->limitations << KoID("hairy-brush", i18nc("PaintOp instant preview limitation", "Bristle Brush (the lines will be thinner than on preview)")); } diff --git a/plugins/paintops/hairy/kis_hairy_bristle_option.h b/plugins/paintops/hairy/kis_hairy_bristle_option.h index 7e35159bed..a9b162e467 100644 --- a/plugins/paintops/hairy/kis_hairy_bristle_option.h +++ b/plugins/paintops/hairy/kis_hairy_bristle_option.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_HAIRY_BRISTLE_OPTION_H #define KIS_HAIRY_BRISTLE_OPTION_H #include class KisPaintopLodLimitations; const QString HAIRY_BRISTLE_USE_MOUSEPRESSURE = "HairyBristle/useMousePressure"; const QString HAIRY_BRISTLE_SCALE = "HairyBristle/scale"; const QString HAIRY_BRISTLE_SHEAR = "HairyBristle/shear"; const QString HAIRY_BRISTLE_RANDOM = "HairyBristle/random"; const QString HAIRY_BRISTLE_DENSITY = "HairyBristle/density"; const QString HAIRY_BRISTLE_THRESHOLD = "HairyBristle/threshold"; const QString HAIRY_BRISTLE_ANTI_ALIASING = "HairyBristle/antialias"; const QString HAIRY_BRISTLE_USE_COMPOSITING = "HairyBristle/useCompositing"; const QString HAIRY_BRISTLE_CONNECTED = "HairyBristle/isConnected"; class KisBristleOptionsWidget; class KisHairyBristleOption : public KisPaintOpOption { public: KisHairyBristleOption(); ~KisHairyBristleOption(); void setScaleFactor(qreal scale) const; bool useMousePressure() const; double scaleFactor() const; double shearFactor() const; double randomFactor() const; - void writeOptionSetting(KisPropertiesConfiguration* config) const; - void readOptionSetting(const KisPropertiesConfiguration* config); + void writeOptionSetting(KisPropertiesConfigurationSP config) const; + void readOptionSetting(const KisPropertiesConfigurationSP config); void lodLimitations(KisPaintopLodLimitations *l) const; private: KisBristleOptionsWidget * m_options; }; #endif // KIS_HAIRY_BRISTLE_OPTION_H diff --git a/plugins/paintops/hairy/kis_hairy_ink_option.cpp b/plugins/paintops/hairy/kis_hairy_ink_option.cpp index 582e7b7e2f..820a116c91 100644 --- a/plugins/paintops/hairy/kis_hairy_ink_option.cpp +++ b/plugins/paintops/hairy/kis_hairy_ink_option.cpp @@ -1,158 +1,158 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_hairy_ink_option.h" #include "kis_hairy_paintop_settings.h" #include #include "ui_wdgInkOptions.h" class KisInkOptionsWidget: public QWidget, public Ui::WdgInkOptions { public: KisInkOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisHairyInkOption::KisHairyInkOption() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { setObjectName("KisHairyInkOption"); m_checkable = true; m_options = new KisInkOptionsWidget(); // init values for slider m_options->pressureSlider->setRange(0.0, 100, 0); m_options->pressureSlider->setValue(50); m_options->pressureSlider->setSuffix("%"); m_options->bristleLengthSlider->setRange(0, 100, 0); m_options->bristleLengthSlider->setValue(50); m_options->bristleLengthSlider->setSuffix("%"); m_options->bristleInkAmountSlider->setRange(0, 100, 0); m_options->bristleInkAmountSlider->setValue(50); m_options->bristleInkAmountSlider->setSuffix("%"); m_options->inkDepletionSlider->setRange(0, 100, 0); m_options->inkDepletionSlider->setValue(50); m_options->inkDepletionSlider->setSuffix("%"); connect(m_options->inkAmountSpinBox, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->saturationCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->opacityCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->useWeightCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->pressureSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->bristleLengthSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->bristleInkAmountSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->inkDepletionSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->inkCurve, SIGNAL(modified()), SLOT(emitSettingChanged())); connect(m_options->soakInkCBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisHairyInkOption::~KisHairyInkOption() { delete m_options; } -void KisHairyInkOption::readOptionSetting(const KisPropertiesConfiguration* settings) +void KisHairyInkOption::readOptionSetting(const KisPropertiesConfigurationSP settings) { setChecked(settings->getBool(HAIRY_INK_DEPLETION_ENABLED)); m_options->inkAmountSpinBox->setValue(settings->getInt(HAIRY_INK_AMOUNT)); m_options->saturationCBox->setChecked(settings->getBool(HAIRY_INK_USE_SATURATION)); m_options->opacityCBox->setChecked(settings->getBool(HAIRY_INK_USE_OPACITY)); m_options->useWeightCHBox->setChecked(settings->getBool(HAIRY_INK_USE_WEIGHTS)); m_options->pressureSlider->setValue(settings->getInt(HAIRY_INK_PRESSURE_WEIGHT)); m_options->bristleLengthSlider->setValue(settings->getInt(HAIRY_INK_BRISTLE_LENGTH_WEIGHT)); m_options->bristleInkAmountSlider->setValue(settings->getInt(HAIRY_INK_BRISTLE_INK_AMOUNT_WEIGHT)); m_options->inkDepletionSlider->setValue(settings->getInt(HAIRY_INK_DEPLETION_WEIGHT)); m_options->inkCurve->setCurve(settings->getCubicCurve(HAIRY_INK_DEPLETION_CURVE)); m_options->soakInkCBox->setChecked(settings->getBool(HAIRY_INK_SOAK)); } -void KisHairyInkOption::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisHairyInkOption::writeOptionSetting(KisPropertiesConfigurationSP settings) const { settings->setProperty(HAIRY_INK_DEPLETION_ENABLED, isChecked()); settings->setProperty(HAIRY_INK_AMOUNT, inkAmount()); settings->setProperty(HAIRY_INK_USE_SATURATION, useSaturation()); settings->setProperty(HAIRY_INK_USE_OPACITY, useOpacity()); settings->setProperty(HAIRY_INK_USE_WEIGHTS, useWeights()); settings->setProperty(HAIRY_INK_PRESSURE_WEIGHT, pressureWeight()); settings->setProperty(HAIRY_INK_BRISTLE_LENGTH_WEIGHT, bristleLengthWeight()); settings->setProperty(HAIRY_INK_BRISTLE_INK_AMOUNT_WEIGHT, bristleInkAmountWeight()); settings->setProperty(HAIRY_INK_DEPLETION_WEIGHT, inkDepletionWeight()); settings->setProperty(HAIRY_INK_DEPLETION_CURVE, qVariantFromValue(m_options->inkCurve->curve())); settings->setProperty(HAIRY_INK_SOAK, m_options->soakInkCBox->isChecked()); } int KisHairyInkOption::inkAmount() const { return m_options->inkAmountSpinBox->value(); } bool KisHairyInkOption::useOpacity() const { return m_options->opacityCBox->isChecked(); } bool KisHairyInkOption::useSaturation() const { return m_options->saturationCBox->isChecked(); } bool KisHairyInkOption::useWeights() const { return m_options->useWeightCHBox->isChecked(); } int KisHairyInkOption::pressureWeight() const { return m_options->pressureSlider->value(); } int KisHairyInkOption::bristleLengthWeight() const { return m_options->bristleLengthSlider->value(); } int KisHairyInkOption::bristleInkAmountWeight() const { return m_options->bristleInkAmountSlider->value(); } int KisHairyInkOption::inkDepletionWeight() const { return m_options->inkDepletionSlider->value(); } diff --git a/plugins/paintops/hairy/kis_hairy_ink_option.h b/plugins/paintops/hairy/kis_hairy_ink_option.h index 94a40ddc18..39a2680170 100644 --- a/plugins/paintops/hairy/kis_hairy_ink_option.h +++ b/plugins/paintops/hairy/kis_hairy_ink_option.h @@ -1,63 +1,63 @@ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_HAIRY_INK_OPTION_H #define KIS_HAIRY_INK_OPTION_H #include const QString HAIRY_INK_DEPLETION_ENABLED = "HairyInk/enabled"; const QString HAIRY_INK_AMOUNT = "HairyInk/inkAmount"; const QString HAIRY_INK_USE_SATURATION = "HairyInk/useSaturation"; const QString HAIRY_INK_USE_OPACITY = "HairyInk/useOpacity"; const QString HAIRY_INK_USE_WEIGHTS = "HairyInk/useWeights"; const QString HAIRY_INK_PRESSURE_WEIGHT = "HairyInk/pressureWeights"; const QString HAIRY_INK_BRISTLE_LENGTH_WEIGHT = "HairyInk/bristleLengthWeights"; const QString HAIRY_INK_BRISTLE_INK_AMOUNT_WEIGHT = "HairyInk/bristleInkAmountWeight"; const QString HAIRY_INK_DEPLETION_WEIGHT = "HairyInk/inkDepletionWeight"; const QString HAIRY_INK_DEPLETION_CURVE = "HairyInk/inkDepletionCurve"; const QString HAIRY_INK_SOAK = "HairyInk/soak"; class KisInkOptionsWidget; class KisHairyInkOption : public KisPaintOpOption { public: KisHairyInkOption(); ~KisHairyInkOption(); int inkAmount() const; QList curve() const; bool useSaturation() const; bool useOpacity() const; bool useWeights() const; int pressureWeight() const; int bristleLengthWeight() const; int bristleInkAmountWeight() const; int inkDepletionWeight() const; int m_curveSamples; - void writeOptionSetting(KisPropertiesConfiguration* config) const; - void readOptionSetting(const KisPropertiesConfiguration* config); + void writeOptionSetting(KisPropertiesConfigurationSP config) const; + void readOptionSetting(const KisPropertiesConfigurationSP config); private: KisInkOptionsWidget * m_options; }; #endif // KIS_HAIRY_SHAPE_OPTION_H diff --git a/plugins/paintops/hairy/kis_hairy_paintop.cpp b/plugins/paintops/hairy/kis_hairy_paintop.cpp index 90f2f9d01e..77f663c9e4 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop.cpp +++ b/plugins/paintops/hairy/kis_hairy_paintop.cpp @@ -1,139 +1,139 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_hairy_paintop.h" #include "kis_hairy_paintop_settings.h" #include #include #include #include #include "kis_paint_device.h" #include "kis_painter.h" #include #include #include #include #include #include #include #include #include "kis_brush.h" -KisHairyPaintOp::KisHairyPaintOp(const KisBrushBasedPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisHairyPaintOp::KisHairyPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image) Q_ASSERT(settings); m_dev = node ? node->paintDevice() : 0; KisBrushOption brushOption; brushOption.readOptionSetting(settings, true); KisBrushSP brush = brushOption.brush(); KisFixedPaintDeviceSP dab = cachedDab(painter->device()->compositionSourceColorSpace()); if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { dab = brush->paintDevice(source()->colorSpace(), KisDabShape(), KisPaintInformation()); } else { brush->mask(dab, painter->paintColor(), KisDabShape(), KisPaintInformation()); } m_brush.fromDabWithDensity(dab, settings->getDouble(HAIRY_BRISTLE_DENSITY) * 0.01); m_brush.setInkColor(painter->paintColor()); - loadSettings(settings); + loadSettings(static_cast(settings.data())); m_brush.setProperties(&m_properties); m_rotationOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_rotationOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); } -void KisHairyPaintOp::loadSettings(const KisBrushBasedPaintOpSettings* settings) +void KisHairyPaintOp::loadSettings(const KisBrushBasedPaintOpSettings *settings) { m_properties.inkAmount = settings->getInt(HAIRY_INK_AMOUNT); //TODO: wait for the transfer function with variable size m_properties.inkDepletionCurve = settings->getCubicCurve(HAIRY_INK_DEPLETION_CURVE).floatTransfer(m_properties.inkAmount); m_properties.inkDepletionEnabled = settings->getBool(HAIRY_INK_DEPLETION_ENABLED); m_properties.useSaturation = settings->getBool(HAIRY_INK_USE_SATURATION); m_properties.useOpacity = settings->getBool(HAIRY_INK_USE_OPACITY); m_properties.useWeights = settings->getBool(HAIRY_INK_USE_WEIGHTS); m_properties.pressureWeight = settings->getDouble(HAIRY_INK_PRESSURE_WEIGHT) / 100.0; m_properties.bristleLengthWeight = settings->getDouble(HAIRY_INK_BRISTLE_LENGTH_WEIGHT) / 100.0; m_properties.bristleInkAmountWeight = settings->getDouble(HAIRY_INK_BRISTLE_INK_AMOUNT_WEIGHT) / 100.0; m_properties.inkDepletionWeight = settings->getDouble(HAIRY_INK_DEPLETION_WEIGHT); m_properties.useSoakInk = settings->getBool(HAIRY_INK_SOAK); m_properties.useMousePressure = settings->getBool(HAIRY_BRISTLE_USE_MOUSEPRESSURE); m_properties.shearFactor = settings->getDouble(HAIRY_BRISTLE_SHEAR); m_properties.randomFactor = settings->getDouble(HAIRY_BRISTLE_RANDOM); m_properties.scaleFactor = settings->getDouble(HAIRY_BRISTLE_SCALE); m_properties.threshold = settings->getBool(HAIRY_BRISTLE_THRESHOLD); m_properties.antialias = settings->getBool(HAIRY_BRISTLE_ANTI_ALIASING); m_properties.useCompositing = settings->getBool(HAIRY_BRISTLE_USE_COMPOSITING); m_properties.connectedPath = settings->getBool(HAIRY_BRISTLE_CONNECTED); } KisSpacingInformation KisHairyPaintOp::paintAt(const KisPaintInformation& info) { Q_UNUSED(info); return KisSpacingInformation(0.5); } void KisHairyPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); if (!painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } // Hairy Brush is capable of working with zero scale, // so no additional checks for 'zero'ness are needed qreal scale = m_sizeOption.apply(pi2); scale *= KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(pi2); quint8 origOpacity = m_opacityOption.apply(painter(), pi2); m_brush.paintLine(m_dab, m_dev, pi1, pi2, scale * m_properties.scaleFactor, rotation); //QRect rc = m_dab->exactBounds(); QRect rc = m_dab->extent(); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); } diff --git a/plugins/paintops/hairy/kis_hairy_paintop.h b/plugins/paintops/hairy/kis_hairy_paintop.h index d1f945c886..0396fdf1a0 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop.h +++ b/plugins/paintops/hairy/kis_hairy_paintop.h @@ -1,59 +1,59 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_HAIRYPAINTOP_H_ #define KIS_HAIRYPAINTOP_H_ #include #include #include #include #include "hairy_brush.h" #include #include #include class KisPainter; class KisBrushBasedPaintOpSettings; class KisHairyPaintOp : public KisPaintOp { public: - KisHairyPaintOp(const KisBrushBasedPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisHairyPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); private: KisHairyProperties m_properties; KisPaintDeviceSP m_dab; KisPaintDeviceSP m_dev; HairyBrush m_brush; KisPressureRotationOption m_rotationOption; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; void loadSettings(const KisBrushBasedPaintOpSettings* settings); }; #endif // KIS_HAIRYPAINTOP_H_ diff --git a/plugins/paintops/hairy/kis_hairy_paintop_settings.cpp b/plugins/paintops/hairy/kis_hairy_paintop_settings.cpp index ceaf5c575f..382b51af3d 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop_settings.cpp +++ b/plugins/paintops/hairy/kis_hairy_paintop_settings.cpp @@ -1,37 +1,37 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008-2010 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "kis_image.h" #include "kis_hairy_paintop_settings.h" #include "kis_hairy_bristle_option.h" #include "kis_hairy_shape_option.h" #include "kis_brush_based_paintop_options_widget.h" #include "kis_boundary.h" KisHairyPaintOpSettings::KisHairyPaintOpSettings() { } -QPainterPath KisHairyPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisHairyPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { return brushOutlineImpl(info, mode, getDouble(HAIRY_BRISTLE_SCALE)); } diff --git a/plugins/paintops/hairy/kis_hairy_paintop_settings.h b/plugins/paintops/hairy/kis_hairy_paintop_settings.h index 938564ee70..63e786ebf9 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop_settings.h +++ b/plugins/paintops/hairy/kis_hairy_paintop_settings.h @@ -1,40 +1,41 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_HAIRYPAINTOP_SETTINGS_H_ #define KIS_HAIRYPAINTOP_SETTINGS_H_ #include #include #include class KisHairyPaintOpSettings : public KisBrushBasedPaintOpSettings { public: using KisPaintOpSettings::fromXML; KisHairyPaintOpSettings(); - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + using KisBrushBasedPaintOpSettings::brushOutline; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); }; #endif diff --git a/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.cpp b/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.cpp index c692989ec6..a363b6c37d 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.cpp +++ b/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.cpp @@ -1,59 +1,59 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008 Lukáš Tvrdý * * 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_hairy_paintop_settings_widget.h" #include "kis_hairy_paintop_settings.h" #include "kis_hairy_shape_option.h" #include "kis_hairy_ink_option.h" #include #include "kis_hairy_bristle_option.h" #include #include #include #include #include KisHairyPaintOpSettingsWidget:: KisHairyPaintOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { //m_hairyShapeOption = new KisHairyShapeOption(); //addPaintOpOption(m_hairyShapeOption); addPaintOpOption(new KisHairyBristleOption(), i18n("Bristle options")); addPaintOpOption(new KisHairyInkOption(), i18n("Ink depletion")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisHairyPaintOpSettingsWidget::~ KisHairyPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisHairyPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisHairyPaintOpSettingsWidget::configuration() const { KisHairyPaintOpSettings* config = new KisHairyPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "hairybrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.h b/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.h index c7657c1b05..5216f8e370 100644 --- a/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.h +++ b/plugins/paintops/hairy/kis_hairy_paintop_settings_widget.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_HAIRYPAINTOP_SETTINGS_WIDGET_H_ #define KIS_HAIRYPAINTOP_SETTINGS_WIDGET_H_ #include class KisHairyPaintOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisHairyPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisHairyPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif diff --git a/plugins/paintops/hairy/kis_hairy_shape_option.cpp b/plugins/paintops/hairy/kis_hairy_shape_option.cpp index e00929e4b8..33e84439a3 100644 --- a/plugins/paintops/hairy/kis_hairy_shape_option.cpp +++ b/plugins/paintops/hairy/kis_hairy_shape_option.cpp @@ -1,84 +1,84 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_hairy_shape_option.h" #include #include "ui_wdghairyshapeoptions.h" class KisShapeOptionsWidget: public QWidget, public Ui::WdgHairyShapeOptions { public: KisShapeOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisHairyShapeOption::KisHairyShapeOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisHairyShapeOption"); m_checkable = false; m_options = new KisShapeOptionsWidget(); connect(m_options->oneDimBrushBtn, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->twoDimBrushBtn, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->radiusSpinBox, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->sigmaSpinBox, SIGNAL(valueChanged(double)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisHairyShapeOption::~KisHairyShapeOption() { delete m_options; } int KisHairyShapeOption::radius() const { return m_options->radiusSpinBox->value(); } void KisHairyShapeOption::setRadius(int radius) const { m_options->radiusSpinBox->setValue(radius); } -void KisHairyShapeOption::readOptionSetting(const KisPropertiesConfiguration* config) +void KisHairyShapeOption::readOptionSetting(const KisPropertiesConfigurationSP config) { m_options->radiusSpinBox->setValue(config->getInt(HAIRY_RADIUS)); m_options->sigmaSpinBox->setValue(config->getDouble(HAIRY_SIGMA)); if (config->getBool(HAIRY_IS_DIMENSION_1D)) { m_options->oneDimBrushBtn->setChecked(true); } else { m_options->twoDimBrushBtn->setChecked(true); } } -void KisHairyShapeOption::writeOptionSetting(KisPropertiesConfiguration* config) const +void KisHairyShapeOption::writeOptionSetting(KisPropertiesConfigurationSP config) const { config->setProperty(HAIRY_RADIUS, radius()); config->setProperty(HAIRY_SIGMA, m_options->sigmaSpinBox->value()); config->setProperty(HAIRY_IS_DIMENSION_1D, m_options->oneDimBrushBtn->isChecked()); } diff --git a/plugins/paintops/hairy/kis_hairy_shape_option.h b/plugins/paintops/hairy/kis_hairy_shape_option.h index 3bcfaffd27..c994cea29b 100644 --- a/plugins/paintops/hairy/kis_hairy_shape_option.h +++ b/plugins/paintops/hairy/kis_hairy_shape_option.h @@ -1,51 +1,51 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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_HAIRY_SHAPE_OPTION_H #define KIS_HAIRY_SHAPE_OPTION_H #include const QString HAIRY_RADIUS = "Hairy/radius"; const QString HAIRY_SIGMA = "Hairy/sigma"; const QString HAIRY_IS_DIMENSION_1D = "Hairy/isDimension1D"; class KisShapeOptionsWidget; class KisHairyShapeOption : public KisPaintOpOption { public: KisHairyShapeOption(); ~KisHairyShapeOption(); void setRadius(int radius) const; void setScaleFactor(qreal scale) const; int radius() const; double sigma() const; bool isbrushDimension1D() const; bool useMousePressure() const; - void writeOptionSetting(KisPropertiesConfiguration* config) const; - void readOptionSetting(const KisPropertiesConfiguration* config); + void writeOptionSetting(KisPropertiesConfigurationSP config) const; + void readOptionSetting(const KisPropertiesConfigurationSP config); private: KisShapeOptionsWidget * m_options; }; #endif // KIS_HAIRY_SHAPE_OPTION_H diff --git a/plugins/paintops/hatching/kis_hatching_options.cpp b/plugins/paintops/hatching/kis_hatching_options.cpp index f3b0693157..87bd75f590 100644 --- a/plugins/paintops/hatching/kis_hatching_options.cpp +++ b/plugins/paintops/hatching/kis_hatching_options.cpp @@ -1,131 +1,131 @@ /* * Copyright (c) 2008 Lukas Tvrdy * Copyright (c) 2010 José Luis Vergara * * 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_hatching_options.h" #include #include "ui_wdghatchingoptions.h" class KisHatchingOptionsWidget: public QWidget, public Ui::WdgHatchingOptions { public: KisHatchingOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); QString degree = QChar(Qt::Key_degree); QString px = i18n(" px"); //setRange(minimum, maximum, decimals) angleKisDoubleSliderSpinBox -> setRange(-90.0, 90.0, 1); separationKisDoubleSliderSpinBox-> setRange(1.0, 30.0, 1); thicknessKisDoubleSliderSpinBox -> setRange(1.0, 30.0, 1); originXKisDoubleSliderSpinBox -> setRange(-300, 300, 0); originYKisDoubleSliderSpinBox -> setRange(-300, 300, 0); angleKisDoubleSliderSpinBox -> setValue(-60); separationKisDoubleSliderSpinBox-> setValue(6); thicknessKisDoubleSliderSpinBox -> setValue(1); originXKisDoubleSliderSpinBox -> setValue(50); originYKisDoubleSliderSpinBox -> setValue(50); angleKisDoubleSliderSpinBox -> setSuffix(degree); separationKisDoubleSliderSpinBox-> setSuffix(px); thicknessKisDoubleSliderSpinBox -> setSuffix(px); originXKisDoubleSliderSpinBox -> setSuffix(px); originYKisDoubleSliderSpinBox -> setSuffix(px); } }; KisHatchingOptions::KisHatchingOptions() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisHatchingOptions"); m_checkable = false; m_options = new KisHatchingOptionsWidget(); connect(m_options->angleKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->separationKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->thicknessKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->originXKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->originYKisDoubleSliderSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->noCrosshatchingRadioButton, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->perpendicularRadioButton, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->minusThenPlusRadioButton, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->plusThenMinusRadioButton, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->moirePatternRadioButton, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->separationIntervalSpinBox, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisHatchingOptions::~KisHatchingOptions() { } -void KisHatchingOptions::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisHatchingOptions::writeOptionSetting(KisPropertiesConfigurationSP setting) const { HatchingOption op; op.angle = m_options->angleKisDoubleSliderSpinBox->value(); op.separation = m_options->separationKisDoubleSliderSpinBox->value(); op.thickness = m_options->thicknessKisDoubleSliderSpinBox->value(); op.origin_x = m_options->originXKisDoubleSliderSpinBox->value(); op.origin_y = m_options->originYKisDoubleSliderSpinBox->value(); op.bool_nocrosshatching = m_options->noCrosshatchingRadioButton->isChecked(); op.bool_perpendicular = m_options->perpendicularRadioButton->isChecked(); op.bool_minusthenplus = m_options->minusThenPlusRadioButton->isChecked(); op.bool_plusthenminus = m_options->plusThenMinusRadioButton->isChecked(); op.bool_moirepattern = m_options->moirePatternRadioButton->isChecked(); op.separationintervals = m_options->separationIntervalSpinBox->value(); op.writeOptionSetting(setting); } -void KisHatchingOptions::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisHatchingOptions::readOptionSetting(const KisPropertiesConfigurationSP setting) { HatchingOption op; op.readOptionSetting(setting); m_options->angleKisDoubleSliderSpinBox->setValue(op.angle); m_options->separationKisDoubleSliderSpinBox->setValue(op.separation); m_options->thicknessKisDoubleSliderSpinBox->setValue(op.thickness); m_options->originXKisDoubleSliderSpinBox->setValue(op.origin_x); m_options->originYKisDoubleSliderSpinBox->setValue(op.origin_y); m_options->noCrosshatchingRadioButton->setChecked(op.bool_nocrosshatching); m_options->perpendicularRadioButton->setChecked(op.bool_perpendicular); m_options->minusThenPlusRadioButton->setChecked(op.bool_minusthenplus); m_options->plusThenMinusRadioButton->setChecked(op.bool_plusthenminus); m_options->moirePatternRadioButton->setChecked(op.bool_moirepattern); m_options->separationIntervalSpinBox->setValue(op.separationintervals); } void KisHatchingOptions::lodLimitations(KisPaintopLodLimitations *l) const { l->limitations << KoID("hatching-brush", i18nc("PaintOp instant preview limitation", "Hatching Brush (heavy aliasing in preview mode)")); } diff --git a/plugins/paintops/hatching/kis_hatching_options.h b/plugins/paintops/hatching/kis_hatching_options.h index 985735daf2..2f3d75c1bc 100644 --- a/plugins/paintops/hatching/kis_hatching_options.h +++ b/plugins/paintops/hatching/kis_hatching_options.h @@ -1,93 +1,93 @@ /* * 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_HATCHING_OPTIONS_H #define KIS_HATCHING_OPTIONS_H #include class KisPaintopLodLimitations; class KisHatchingOptionsWidget; class KisHatchingOptions : public KisPaintOpOption { public: KisHatchingOptions(); ~KisHatchingOptions(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private: - KisHatchingOptionsWidget * m_options; + KisHatchingOptionsWidget *m_options; }; struct HatchingOption { qreal angle; qreal separation; qreal thickness; qreal origin_x; qreal origin_y; bool bool_nocrosshatching; bool bool_perpendicular; bool bool_minusthenplus; bool bool_plusthenminus; bool bool_moirepattern; int separationintervals; - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty("Hatching/angle", angle); setting->setProperty("Hatching/separation", separation); setting->setProperty("Hatching/thickness", thickness); setting->setProperty("Hatching/origin_x", origin_x); setting->setProperty("Hatching/origin_y", origin_y); setting->setProperty("Hatching/bool_nocrosshatching", bool_nocrosshatching); setting->setProperty("Hatching/bool_perpendicular", bool_perpendicular); setting->setProperty("Hatching/bool_minusthenplus", bool_minusthenplus); setting->setProperty("Hatching/bool_plusthenminus", bool_plusthenminus); setting->setProperty("Hatching/bool_moirepattern", bool_moirepattern); setting->setProperty("Hatching/separationintervals", separationintervals); } - void readOptionSetting(const KisPropertiesConfiguration* setting) { + void readOptionSetting(const KisPropertiesConfigurationSP setting) { angle = setting->getDouble("Hatching/angle"); separation = setting->getDouble("Hatching/separation"); thickness = setting->getDouble("Hatching/thickness"); origin_x = setting->getDouble("Hatching/origin_x"); origin_y = setting->getDouble("Hatching/origin_y"); bool_nocrosshatching = setting->getBool("Hatching/bool_nocrosshatching"); bool_perpendicular = setting->getBool("Hatching/bool_perpendicular"); bool_minusthenplus = setting->getBool("Hatching/bool_minusthenplus"); bool_plusthenminus = setting->getBool("Hatching/bool_plusthenminus"); bool_moirepattern = setting->getBool("Hatching/bool_moirepattern"); separationintervals = setting->getInt("Hatching/separationintervals"); } }; #endif diff --git a/plugins/paintops/hatching/kis_hatching_paintop.cpp b/plugins/paintops/hatching/kis_hatching_paintop.cpp index 553671b442..3f9eac170f 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop.cpp +++ b/plugins/paintops/hatching/kis_hatching_paintop.cpp @@ -1,203 +1,203 @@ /* * Copyright (c) 2008,2009 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara * * 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_hatching_paintop.h" #include "kis_hatching_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisHatchingPaintOp::KisHatchingPaintOp(const KisHatchingPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisHatchingPaintOp::KisHatchingPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_image(image) { Q_UNUSED(node); m_settings = new KisHatchingPaintOpSettings(); - settings->initializeTwin(m_settings); + static_cast(settings.data())->initializeTwin(m_settings); m_hatchingBrush = new HatchingBrush(m_settings); m_crosshatchingOption.readOptionSetting(settings); m_separationOption.readOptionSetting(settings); m_thicknessOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_crosshatchingOption.resetAllSensors(); m_separationOption.resetAllSensors(); m_thicknessOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); } KisHatchingPaintOp::~KisHatchingPaintOp() { delete m_hatchingBrush; } KisSpacingInformation KisHatchingPaintOp::paintAt(const KisPaintInformation& info) { //------START SIMPLE ERROR CATCHING------- if (!painter()->device()) return KisSpacingInformation(1.0); if (!m_hatchedDab) m_hatchedDab = source()->createCompositionSourceDevice(); else m_hatchedDab->clear(); //Simple convenience renaming, I'm thinking of removing these inherited quirks KisBrushSP brush = m_brush; KisPaintDeviceSP device = painter()->device(); //Macro to catch errors Q_ASSERT(brush); //----------SIMPLE error catching code, maybe it's not even needed------ if (!brush) return KisSpacingInformation(1.0); if (!brush->canPaintFor(info)) return KisSpacingInformation(1.0); //SENSOR-depending settings m_settings->crosshatchingsensorvalue = m_crosshatchingOption.apply(info); m_settings->separationsensorvalue = m_separationOption.apply(info); m_settings->thicknesssensorvalue = m_thicknessOption.apply(info); const qreal additionalScale = KisLodTransform::lodToScale(painter()->device()); const double scale = additionalScale * m_sizeOption.apply(info); if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) return KisSpacingInformation(1.0); KisDabShape shape(scale, 1.0, 0.0); quint8 origOpacity = m_opacityOption.apply(painter(), info); /*----Fetch the Dab----*/ static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); static KoColor color(Qt::black, cs); QRect dstRect; KisFixedPaintDeviceSP maskDab = m_dabCache->fetchDab(cs, color, info.pos(), shape, info, 1.0, &dstRect); // sanity check KIS_ASSERT_RECOVER_NOOP(dstRect.size() == maskDab->bounds().size()); /*-----Convenient renaming for the limits of the maskDab, this will be used to hatch a dab of just the right size------*/ qint32 x, y, sw, sh; dstRect.getRect(&x, &y, &sw, &sh); //------This If_block pre-fills the future m_hatchedDab with a pretty backgroundColor if (m_settings->opaquebackground) { KoColor aersh = painter()->backgroundColor(); m_hatchedDab->fill(0, 0, (sw - 1), (sh - 1), aersh.data()); //this plus yellow background = french fry brush } // Trick for moire pattern to look better bool donotbasehatch = false; /* If block describing how to stack hatching passes to generate crosshatching according to user specifications */ if (m_settings->enabledcurvecrosshatching) { if (m_settings->perpendicular) { if (m_settings->crosshatchingsensorvalue > 0.5) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(90), painter()->paintColor(), additionalScale); } else if (m_settings->minusthenplus) { if (m_settings->crosshatchingsensorvalue > 0.33) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(-45), painter()->paintColor(), additionalScale); if (m_settings->crosshatchingsensorvalue > 0.67) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(45), painter()->paintColor(), additionalScale); } else if (m_settings->plusthenminus) { if (m_settings->crosshatchingsensorvalue > 0.33) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(45), painter()->paintColor(), additionalScale); if (m_settings->crosshatchingsensorvalue > 0.67) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(-45), painter()->paintColor(), additionalScale); } else if (m_settings->moirepattern) { m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle((m_settings->crosshatchingsensorvalue) * 180), painter()->paintColor(), additionalScale); donotbasehatch = true; } } else { if (m_settings->perpendicular) { m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(90), painter()->paintColor(), additionalScale); } else if (m_settings->minusthenplus) { m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(-45), painter()->paintColor(), additionalScale); m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(45), painter()->paintColor(), additionalScale); } else if (m_settings->plusthenminus) { m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(45), painter()->paintColor(), additionalScale); m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(-45), painter()->paintColor(), additionalScale); } else if (m_settings->moirepattern) { m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, spinAngle(-10), painter()->paintColor(), additionalScale); } } if (!donotbasehatch) m_hatchingBrush->hatch(m_hatchedDab, x, y, sw, sh, m_settings->angle, painter()->paintColor(), additionalScale); // The most important line, the one that paints to the screen. painter()->bitBltWithFixedSelection(x, y, m_hatchedDab, maskDab, sw, sh); painter()->renderMirrorMaskSafe(QRect(QPoint(x, y), QSize(sw, sh)), m_hatchedDab, 0, 0, maskDab, !m_dabCache->needSeparateOriginal()); painter()->setOpacity(origOpacity); return effectiveSpacing(scale, 0.0); } double KisHatchingPaintOp::spinAngle(double spin) { double tempangle = m_settings->angle + spin; qint8 factor = 1; if (tempangle < 0) factor = -1; tempangle = fabs(fmod(tempangle, 180)); if ((tempangle >= 0) && (tempangle <= 90)) return factor * tempangle; else if ((tempangle > 90) && (tempangle <= 180)) return factor * -(180 - tempangle); return 0; // this should never be executed except if NAN } diff --git a/plugins/paintops/hatching/kis_hatching_paintop.h b/plugins/paintops/hatching/kis_hatching_paintop.h index 77accb105f..e1b37a8fd0 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop.h +++ b/plugins/paintops/hatching/kis_hatching_paintop.h @@ -1,104 +1,104 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008, 2009 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * * 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_HATCHING_PAINTOP_H_ #define KIS_HATCHING_PAINTOP_H_ #include #include #include #include "hatching_brush.h" #include "kis_hatching_paintop_settings.h" #include #include #include #include #include class KisPainter; class KisHatchingPaintOp : public KisBrushBasedPaintOp { public: - KisHatchingPaintOp(const KisHatchingPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisHatchingPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); virtual ~KisHatchingPaintOp(); /** * Paint a hatched dab around the mouse cursor according to * sensor settings and user preferences. */ KisSpacingInformation paintAt(const KisPaintInformation& info); /** * Returns a number between -90 and 90, and corresponds to the * angle that results from adding angle 'spin' to 'm_settings->angle', * corrected to coincide with the way the GUI operates. */ double spinAngle(double spin); private: - KisHatchingPaintOpSettings* m_settings; + KisHatchingPaintOpSettingsSP m_settings; KisImageWSP m_image; - HatchingBrush * m_hatchingBrush; + HatchingBrush *m_hatchingBrush; /** * PaintDevice that will be filled with a single pass of * hatching by HatchingBrush::hatch */ KisPaintDeviceSP m_hatchedDab; /** * Curve to control the intensity of crosshatching * according to user preferences set in the GUI */ KisHatchingPressureCrosshatchingOption m_crosshatchingOption; /** * Curve to control the dynamics of separation with * device input */ KisHatchingPressureSeparationOption m_separationOption; /** * Curve to control the thickness of the hatching lines * with device input */ KisHatchingPressureThicknessOption m_thicknessOption; /** * Curve to control the opacity of the entire dab * with device input */ KisPressureOpacityOption m_opacityOption; /** * Curve to control the size of the entire dab * with device input */ KisPressureSizeOption m_sizeOption; }; #endif // KIS_HATCHING_PAINTOP_H_ diff --git a/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp b/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp index 6ad92a4190..7fee9789dd 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp +++ b/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp @@ -1,215 +1,219 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara * * 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_hatching_paintop_settings.h" #include #include #include const QString HATCHING_VERSION = "Hatching/Version"; struct KisHatchingPaintOpSettings::Private { QList uniformProperties; }; KisHatchingPaintOpSettings::KisHatchingPaintOpSettings() : m_d(new Private) { setProperty(HATCHING_VERSION, "2"); } KisHatchingPaintOpSettings::~KisHatchingPaintOpSettings() { } -void KisHatchingPaintOpSettings::initializeTwin(KisHatchingPaintOpSettings* convenienttwin) const +void KisHatchingPaintOpSettings::initializeTwin(KisPaintOpSettingsSP settings) const { + // XXX: this is a nice way to reinvent the copy constructor? + /*--------DO NOT REMOVE please, use this to review the XML config tree QMap rofl = QMap(getProperties()); QMap::const_iterator i; for (i = rofl.constBegin(); i != rofl.constEnd(); ++i) dbgKrita << i.key() << ":" << i.value(); /----------DO NOT REMOVE----------------*/ + KisHatchingPaintOpSettings *convenienttwin = static_cast(settings.data()); + convenienttwin->enabledcurvecrosshatching = getBool("PressureCrosshatching"); convenienttwin->enabledcurveopacity = getBool("PressureOpacity"); convenienttwin->enabledcurveseparation = getBool("PressureSeparation"); convenienttwin->enabledcurvesize = getBool("PressureSize"); convenienttwin->enabledcurvethickness = getBool("PressureThickness"); convenienttwin->angle = getDouble("Hatching/angle"); convenienttwin->separation = getDouble("Hatching/separation"); convenienttwin->thickness = getDouble("Hatching/thickness"); convenienttwin->origin_x = getDouble("Hatching/origin_x"); convenienttwin->origin_y = getDouble("Hatching/origin_y"); convenienttwin->nocrosshatching = getBool("Hatching/bool_nocrosshatching"); convenienttwin->perpendicular = getBool("Hatching/bool_perpendicular"); convenienttwin->minusthenplus = getBool("Hatching/bool_minusthenplus"); convenienttwin->plusthenminus = getBool("Hatching/bool_plusthenminus"); convenienttwin->moirepattern = getBool("Hatching/bool_moirepattern"); convenienttwin->separationintervals = getInt("Hatching/separationintervals"); //convenienttwin->trigonometryalgebra = getBool("Hatching/bool_trigonometryalgebra"); //convenienttwin->scratchoff = getBool("Hatching/bool_scratchoff"); convenienttwin->antialias = getBool("Hatching/bool_antialias"); convenienttwin->opaquebackground = getBool("Hatching/bool_opaquebackground"); convenienttwin->subpixelprecision = getBool("Hatching/bool_subpixelprecision"); if (getBool("Hatching/bool_nocrosshatching")) convenienttwin->crosshatchingstyle = 0; else if (getBool("Hatching/bool_perpendicular")) convenienttwin->crosshatchingstyle = 1; else if (getBool("Hatching/bool_minusthenplus")) convenienttwin->crosshatchingstyle = 2; else if (getBool("Hatching/bool_plusthenminus")) convenienttwin->crosshatchingstyle = 3; if (getBool("Hatching/bool_moirepattern")) convenienttwin->crosshatchingstyle = 4; } void KisHatchingPaintOpSettings::fromXML(const QDomElement& elt) { setProperty(HATCHING_VERSION, "1"); // This make sure that fromXML will override HAIRY_VERSION with 2, or will default to 1 KisBrushBasedPaintOpSettings::fromXML(elt); QVariant v; if (!getProperty(HATCHING_VERSION, v) || v == "1") { setProperty("Hatching/thickness", 2.0 * getDouble("Hatching/thickness")); } setProperty(HATCHING_VERSION, "2"); // make sure it's saved as version 2 next time } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_hatching_options.h" QList KisHatchingPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_angle", i18n("Hatching Angle"), this, 0); const QString degree = QChar(Qt::Key_degree); prop->setRange(-90, 90); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(degree); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.angle); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.angle = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_separation", i18n("Separation"), this, 0); prop->setRange(1.0, 30); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.separation); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.separation = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_thickness", i18n("Thickness"), this, 0); prop->setRange(1.0, 30); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.thickness); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.thickness = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties() + props; } diff --git a/plugins/paintops/hatching/kis_hatching_paintop_settings.h b/plugins/paintops/hatching/kis_hatching_paintop_settings.h index 1d09212935..f1a2004074 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop_settings.h +++ b/plugins/paintops/hatching/kis_hatching_paintop_settings.h @@ -1,82 +1,87 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara * * 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_HATCHING_PAINTOP_SETTINGS_H_ #define KIS_HATCHING_PAINTOP_SETTINGS_H_ #include #include #include "kis_hatching_paintop_settings_widget.h" #include class KisHatchingPaintOpSettings : public KisBrushBasedPaintOpSettings { public: KisHatchingPaintOpSettings(); ~KisHatchingPaintOpSettings(); //Dialogs enabled bool enabledcurvecrosshatching; bool enabledcurveopacity; bool enabledcurveseparation; bool enabledcurvesize; bool enabledcurvethickness; //Hatching Options double angle; double separation; double thickness; double origin_x; double origin_y; bool nocrosshatching; bool perpendicular; bool minusthenplus; bool plusthenminus; bool moirepattern; int crosshatchingstyle; int separationintervals; //Hatching Preferences //bool trigonometryalgebra; //bool scratchoff; bool antialias; bool subpixelprecision; bool opaquebackground; //Crosshatching, Separation and Thickness curves double crosshatchingsensorvalue; double separationsensorvalue; double thicknesssensorvalue; - void initializeTwin(KisHatchingPaintOpSettings* convenienttwin) const; + void initializeTwin(KisPaintOpSettingsSP convenienttwin) const; using KisPropertiesConfiguration::fromXML; virtual void fromXML(const QDomElement&); QList uniformProperties(); private: + Q_DISABLE_COPY(KisHatchingPaintOpSettings) + struct Private; const QScopedPointer m_d; + }; +typedef KisSharedPtr KisHatchingPaintOpSettingsSP; + #endif diff --git a/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.cpp b/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.cpp index ceefb11a76..0b9c4134d0 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.cpp +++ b/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.cpp @@ -1,138 +1,138 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara * * 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_hatching_paintop_settings_widget.h" #include "kis_hatching_options.h" #include "kis_hatching_preferences.h" #include "kis_hatching_paintop_settings.h" #include "kis_hatching_pressure_crosshatching_option.h" #include "kis_hatching_pressure_separation_option.h" #include "kis_hatching_pressure_thickness_option.h" #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" #include #include KisHatchingPaintOpSettingsWidget:: KisHatchingPaintOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { setPrecisionEnabled(true); //-------Adding widgets to the screen------------ addPaintOpOption(new KisHatchingOptions(), i18n("Hatching options")); addPaintOpOption(new KisHatchingPreferences(), i18n("Hatching preferences")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisHatchingPressureSeparationOption(), i18n("0.0"), i18n("1.0")), i18n("Separation")); addPaintOpOption(new KisCurveOptionWidget(new KisHatchingPressureThicknessOption(), i18n("0.0"), i18n("1.0")), i18n("Thickness")); addPaintOpOption(new KisCurveOptionWidget(new KisHatchingPressureCrosshatchingOption(), i18n("0.0"), i18n("1.0")), i18n("Crosshatching")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); addPaintOpOption(new KisTextureOption(), i18n("Pattern")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength")); //-----Useful to read first:------ /* Below you will encounter a reasonably correct solution to the problem of changing the default presets of the "BrushTip" popup configuration dialogue. In my (Pentalis) opinion, the best solution is code refactoring (simpler ways to change the defaults). On the meanwhile, copypasting this code won't give your class a charisma penalty. In kis_hatching_paintop_settings.cpp you will find a snippet of code to discover the structure of your XML config tree if you need to edit it at build time like here. */ //---------START ALTERING DEFAULT VALUES----------- - //As the name implies, reconfigurationCourier is the KisPropertiesConfiguration* + //As the name implies, reconfigurationCourier is the KisPropertiesConfigurationSP //we'll use as an intermediary to edit the default settings - KisPropertiesConfiguration* reconfigurationCourier = configuration(); + KisPropertiesConfigurationSP reconfigurationCourier = configuration(); /*xMLAnalyzer is an empty document we'll use to analyze and edit the config string part by part I know the important string is "brush_definition" because I read the tree with the snippet in kis_hatching_paintop_settings.cpp */ QDomDocument xMLAnalyzer(""); xMLAnalyzer.setContent(reconfigurationCourier->getString("brush_definition")); /*More things I know by reading the XML tree. At this point you can just read it with: dbgKrita << xMLAnalyzer.toString() ; those QDomElements are the way to navigate the XML tree, read http://doc.qt.nokia.com/latest/qdomdocument.html for more information */ QDomElement firstTag = xMLAnalyzer.documentElement(); QDomElement firstTagsChild = firstTag.elementsByTagName("MaskGenerator").item(0).toElement(); // SET THE DEFAULT VALUES firstTag.attributeNode("spacing").setValue("0.4"); firstTagsChild.attributeNode("diameter").setValue("30"); //Write them into the intermediary config file reconfigurationCourier->setProperty("brush_definition", xMLAnalyzer.toString()); KisCubicCurve CurveSize; CurveSize.fromString("0,1;1,0.1;"); //dbgKrita << "\n\n\n" << CurveSize.toString() << "\n\n\n"; QVariant QVCurveSize = QVariant::fromValue(CurveSize); reconfigurationCourier->setProperty("CurveSize", QVCurveSize); setConfiguration(reconfigurationCourier); // Finished. /* Debugging block QMap rofl = QMap(reconfigurationCourier->getProperties()); QMap::const_iterator i; for (i = rofl.constBegin(); i != rofl.constEnd(); ++i) dbgKrita << i.key() << ":" << i.value(); */ delete reconfigurationCourier; } KisHatchingPaintOpSettingsWidget::~ KisHatchingPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisHatchingPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisHatchingPaintOpSettingsWidget::configuration() const { KisHatchingPaintOpSettings* config = new KisHatchingPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "hatchingbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.h b/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.h index 6dc3e998e7..4152e8cdde 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.h +++ b/plugins/paintops/hatching/kis_hatching_paintop_settings_widget.h @@ -1,41 +1,41 @@ /* * Copyright (c) 2008 Lukas Tvrdy * Copyright (c) 2010 José Luis Vergara * * 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_HATCHING_PAINTOP_SETTINGS_WIDGET_H_ #define KIS_HATCHING_PAINTOP_SETTINGS_WIDGET_H_ #include #include #include "ui_wdghatchingoptions.h" #include "ui_wdghatchingpreferences.h" class KisHatchingPaintOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisHatchingPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisHatchingPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif diff --git a/plugins/paintops/hatching/kis_hatching_preferences.cpp b/plugins/paintops/hatching/kis_hatching_preferences.cpp index 70ec486b43..50343b4da7 100644 --- a/plugins/paintops/hatching/kis_hatching_preferences.cpp +++ b/plugins/paintops/hatching/kis_hatching_preferences.cpp @@ -1,79 +1,79 @@ /* * Copyright (c) 2008 Lukas Tvrdy * Copyright (c) 2010 José Luis Vergara * * 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_hatching_preferences.h" #include "ui_wdghatchingpreferences.h" class KisHatchingPreferencesWidget: public QWidget, public Ui::WdgHatchingPreferences { public: KisHatchingPreferencesWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisHatchingPreferences::KisHatchingPreferences() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisHatchingPreferences"); m_checkable = false; m_options = new KisHatchingPreferencesWidget(); /* connect(m_options->trigonometryAlgebraRadioButton, SIGNAL(clicked(bool)),SLOT(emitSettingChanged())); connect(m_options->scratchOffRadioButton, SIGNAL(clicked(bool)),SLOT(emitSettingChanged())); */ connect(m_options->antialiasCheckBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->opaqueBackgroundCheckBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->subpixelPrecisionCheckBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisHatchingPreferences::~KisHatchingPreferences() { } -void KisHatchingPreferences::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisHatchingPreferences::writeOptionSetting(KisPropertiesConfigurationSP setting) const { /* setting->setProperty("Hatching/bool_trigonometryalgebra", m_options->trigonometryAlgebraRadioButton->isChecked() ); setting->setProperty("Hatching/bool_scratchoff", m_options->scratchOffRadioButton->isChecked() ); */ setting->setProperty("Hatching/bool_antialias", m_options->antialiasCheckBox->isChecked()); setting->setProperty("Hatching/bool_opaquebackground", m_options->opaqueBackgroundCheckBox->isChecked()); setting->setProperty("Hatching/bool_subpixelprecision", m_options->subpixelPrecisionCheckBox->isChecked()); } -void KisHatchingPreferences::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisHatchingPreferences::readOptionSetting(const KisPropertiesConfigurationSP setting) { /* m_options->trigonometryAlgebraRadioButton->setChecked( setting->getBool("Hatching/bool_trigonometryalgebra") ); m_options->scratchOffRadioButton->setChecked( setting->getBool("Hatching/bool_scratchoff") ); */ m_options->antialiasCheckBox->setChecked(setting->getBool("Hatching/bool_antialias")); m_options->opaqueBackgroundCheckBox->setChecked(setting->getBool("Hatching/bool_opaquebackground")); m_options->subpixelPrecisionCheckBox->setChecked(setting->getBool("Hatching/bool_subpixelprecision")); } diff --git a/plugins/paintops/hatching/kis_hatching_preferences.h b/plugins/paintops/hatching/kis_hatching_preferences.h index 9a4bd91fdf..cf34f50eb4 100644 --- a/plugins/paintops/hatching/kis_hatching_preferences.h +++ b/plugins/paintops/hatching/kis_hatching_preferences.h @@ -1,41 +1,41 @@ /* * Copyright (c) 2010 José Luis Vergara * * 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_HATCHING_PREFERENCES_H #define KIS_HATCHING_PREFERENCES_H #include class KisHatchingPreferencesWidget; class KisHatchingPreferences : public KisPaintOpOption { public: KisHatchingPreferences(); ~KisHatchingPreferences(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisHatchingPreferencesWidget * m_options; }; #endif diff --git a/plugins/paintops/libpaintop/kis_airbrush_option.cpp b/plugins/paintops/libpaintop/kis_airbrush_option.cpp index 441520d1a7..2e28201d07 100644 --- a/plugins/paintops/libpaintop/kis_airbrush_option.cpp +++ b/plugins/paintops/libpaintop/kis_airbrush_option.cpp @@ -1,68 +1,68 @@ /* * 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 "kis_airbrush_option.h" #include #include #include #include "ui_wdgairbrush.h" const int MAXIMUM_RATE = 1000; class KisAirbrushWidget: public QWidget, public Ui::WdgAirbrush { public: KisAirbrushWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); sliderRate->setRange(0, MAXIMUM_RATE); sliderRate->setExponentRatio(1.8); sliderRate->setValue(100); } }; KisAirbrushOption::KisAirbrushOption(bool enabled) : KisPaintOpOption(KisPaintOpOption::COLOR, enabled) { setObjectName("KisAirBrushOption"); m_checkable = true; m_optionWidget = new KisAirbrushWidget(); connect(m_optionWidget->sliderRate, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); setConfigurationPage(m_optionWidget); } KisAirbrushOption::~KisAirbrushOption() { } -void KisAirbrushOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisAirbrushOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(AIRBRUSH_ENABLED, isChecked()); setting->setProperty(AIRBRUSH_RATE, m_optionWidget->sliderRate->value()); } -void KisAirbrushOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisAirbrushOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { setChecked(setting->getBool(AIRBRUSH_ENABLED)); m_optionWidget->sliderRate->setValue(setting->getInt(AIRBRUSH_RATE, 100)); } diff --git a/plugins/paintops/libpaintop/kis_airbrush_option.h b/plugins/paintops/libpaintop/kis_airbrush_option.h index 5584b1e6e8..9a003f390b 100644 --- a/plugins/paintops/libpaintop/kis_airbrush_option.h +++ b/plugins/paintops/libpaintop/kis_airbrush_option.h @@ -1,47 +1,47 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_AIRBRUSH_OPTION_H #define KIS_AIRBRUSH_OPTION_H #include #include const QString AIRBRUSH_ENABLED = "AirbrushOption/isAirbrushing"; const QString AIRBRUSH_RATE = "AirbrushOption/rate"; class KisAirbrushWidget; /** * Allows the user to activate airbrushing of the brush mask (brush is painted at the same position over and over) * Rate is set in miliseconds. */ class PAINTOP_EXPORT KisAirbrushOption : public KisPaintOpOption { public: KisAirbrushOption(bool enabled = true); ~KisAirbrushOption(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisAirbrushWidget * m_optionWidget; }; #endif diff --git a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.cpp b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.cpp index 6e3a92da85..80afa13347 100644 --- a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.cpp +++ b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.cpp @@ -1,131 +1,131 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008 Emanuele Tamponi * * 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_bidirectional_mixing_option.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_bidirectional_mixing_option_widget.h" #include KisBidirectionalMixingOption::KisBidirectionalMixingOption() : m_mixingEnabled(false) { } KisBidirectionalMixingOption::~KisBidirectionalMixingOption() { } void KisBidirectionalMixingOption::apply(KisPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect) { if (!m_mixingEnabled) return; const KoColorSpace *cs = dab->colorSpace(); KisPaintDeviceSP canvas = new KisPaintDevice(cs); KisPainter p(canvas); p.setCompositeOp(COMPOSITE_COPY); p.bitBlt(sx, sy, device, dstRect.x(), dstRect.y(), sw, sh); int count = cs->channelCount(); QRect srcRect(sx, sy, sw, sh); KisSequentialConstIterator cit(canvas, srcRect); KisSequentialIterator dit(dab, srcRect); QVector cc(count), dc(count); do { if (cs->opacityU8(dit.rawData()) > 10 && cs->opacityU8(cit.rawDataConst()) > 10) { cs->normalisedChannelsValue(cit.rawDataConst(), cc); cs->normalisedChannelsValue(dit.rawData(), dc); for (int i = 0; i < count; i++) { dc[i] = (1.0 - 0.4 * pressure) * cc[i] + 0.4 * pressure * dc[i]; } cs->fromNormalisedChannelsValue(dit.rawData(), dc); if (dit.x() == (int)(sw / 2) && dit.y() == (int)(sh / 2)) { painter->setPaintColor(KoColor(dit.rawData(), cs)); } } dit.nextPixel(); } while(cit.nextPixel()); } void KisBidirectionalMixingOption::applyFixed(KisFixedPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect) { Q_UNUSED(sx); Q_UNUSED(sy); if (!m_mixingEnabled) return; KisFixedPaintDevice canvas(device->colorSpace()); canvas.setRect(QRect(dstRect.x(), dstRect.y(), sw, sh)); canvas.initialize(); device->readBytes(canvas.data(), canvas.bounds()); const KoColorSpace* cs = dab->colorSpace(); int channelCount = cs->channelCount(); quint8* dabPointer = dab->data(); quint8* canvasPointer = canvas.data(); QVector cc(channelCount); QVector dc(channelCount); for (int y = 0; y < sh; y++) { for (int x = 0; x < sw; x++) { if (cs->opacityU8(dabPointer) > 10 && cs->opacityU8(canvasPointer) > 10) { cs->normalisedChannelsValue(canvasPointer, cc); cs->normalisedChannelsValue(dabPointer, dc); for (int i = 0; i < channelCount ; i++) { dc[i] = (1.0 - 0.4 * pressure) * cc[i] + 0.4 * pressure * dc[i]; } cs->fromNormalisedChannelsValue(dabPointer, dc); if (x == (int)(sw / 2) && y == (int)(sh / 2)) { painter->setPaintColor(KoColor(dabPointer, cs)); } } } dabPointer += dab->pixelSize(); canvasPointer += canvas.pixelSize(); } } -void KisBidirectionalMixingOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisBidirectionalMixingOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_mixingEnabled = setting->getBool(BIDIRECTIONAL_MIXING_ENABLED, false); } diff --git a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.h b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.h index f17a075b64..20acbd5a42 100644 --- a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.h +++ b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option.h @@ -1,56 +1,56 @@ /* This file is part of the KDE project * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008 Emanuele Tamponi * * 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_BIDIRECTIONAL_MIXING_OPTION_H #define KIS_BIDIRECTIONAL_MIXING_OPTION_H #include "kis_paintop_option.h" #include #include class KisPropertiesConfiguration; class KisPainter; class QRect; /** * The bidirectional mixing option uses the painterly framework to * implement bidirectional paint mixing (that is, paint on the canvas * dirties the brush, and the brush mixes its color with that on the * canvas. * * Taken from the complex paintop */ class PAINTOP_EXPORT KisBidirectionalMixingOption { public: KisBidirectionalMixingOption(); ~KisBidirectionalMixingOption(); void apply(KisPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect); void applyFixed(KisFixedPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect); - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: bool m_mixingEnabled; }; #endif diff --git a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.cpp b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.cpp index 994ee34d03..132844bd6a 100644 --- a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.cpp @@ -1,49 +1,49 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008 Emanuele Tamponi * * 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_bidirectional_mixing_option_widget.h" #include #include #include KisBidirectionalMixingOptionWidget::KisBidirectionalMixingOptionWidget() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { m_checkable = true; m_optionWidget = new QLabel(i18n("The mixing option mixes the paint on the brush with that on the canvas.")); m_optionWidget->hide(); setConfigurationPage(m_optionWidget); setObjectName("KisBidirectionalMixingOptionWidget"); } KisBidirectionalMixingOptionWidget::~KisBidirectionalMixingOptionWidget() { } -void KisBidirectionalMixingOptionWidget::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisBidirectionalMixingOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(BIDIRECTIONAL_MIXING_ENABLED, isChecked()); } -void KisBidirectionalMixingOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisBidirectionalMixingOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { setChecked(setting->getBool(BIDIRECTIONAL_MIXING_ENABLED, false)); } diff --git a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.h b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.h index e56d5049a1..de9841b964 100644 --- a/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.h +++ b/plugins/paintops/libpaintop/kis_bidirectional_mixing_option_widget.h @@ -1,57 +1,57 @@ /* This file is part of the KDE project * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2008 Emanuele Tamponi * * 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_BIDIRECTIONAL_MIXING_OPTION_WIDGET_H #define KIS_BIDIRECTIONAL_MIXING_OPTION_WIDGET_H #include "kis_paintop_option.h" #include #include class KisPropertiesConfiguration; class QLabel; const QString BIDIRECTIONAL_MIXING_ENABLED = "BidirectionalMixing/Enabled"; /** * The bidirectional mixing option uses the painterly framework to * implement bidirectional paint mixing (that is, paint on the canvas * dirties the brush, and the brush mixes its color with that on the * canvas. * * Taken from the complex paintop */ class PAINTOP_EXPORT KisBidirectionalMixingOptionWidget : public KisPaintOpOption { public: KisBidirectionalMixingOptionWidget(); ~KisBidirectionalMixingOptionWidget(); ///Reimplemented - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; ///Reimplemented - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: QLabel * m_optionWidget; }; #endif diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp index 242a38d979..584cac709f 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp @@ -1,179 +1,182 @@ /* * 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 "kis_brush_based_paintop.h" #include "kis_properties_configuration.h" #include #include "kis_brush_option.h" #include #include "kis_painter.h" #include #include #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND Q_GLOBAL_STATIC(TextBrushInitializationWorkaround, s_instance) -TextBrushInitializationWorkaround *TextBrushInitializationWorkaround::instance() { +TextBrushInitializationWorkaround *TextBrushInitializationWorkaround::instance() +{ return s_instance; } -void TextBrushInitializationWorkaround::preinitialize(const KisPropertiesConfiguration *settings) { +void TextBrushInitializationWorkaround::preinitialize(KisPropertiesConfigurationSP settings) +{ if (KisBrushOption::isTextBrush(settings)) { KisBrushOption brushOption; brushOption.readOptionSetting(settings, true); m_brush = brushOption.brush(); m_settings = settings; } else { m_brush = 0; m_settings = 0; } } -KisBrushSP TextBrushInitializationWorkaround::tryGetBrush(const KisPropertiesConfiguration *settings) { - return settings && settings == m_settings ? m_brush : 0; +KisBrushSP TextBrushInitializationWorkaround::tryGetBrush(const KisPropertiesConfigurationSP settings) +{ + return (settings && settings == m_settings ? m_brush : 0); } TextBrushInitializationWorkaround::TextBrushInitializationWorkaround() : m_settings(0) {} TextBrushInitializationWorkaround::~TextBrushInitializationWorkaround() {} -void KisBrushBasedPaintOp::preinitializeOpStatically(const KisPaintOpSettingsSP settings) +void KisBrushBasedPaintOp::preinitializeOpStatically(KisPaintOpSettingsSP settings) { - TextBrushInitializationWorkaround::instance()->preinitialize(settings.data()); + TextBrushInitializationWorkaround::instance()->preinitialize(settings); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ -KisBrushBasedPaintOp::KisBrushBasedPaintOp(const KisPropertiesConfiguration* settings, KisPainter* painter) +KisBrushBasedPaintOp::KisBrushBasedPaintOp(const KisPropertiesConfigurationSP settings, KisPainter* painter) : KisPaintOp(painter), m_textureProperties(painter->device()->defaultBounds()->currentLevelOfDetail()) { Q_ASSERT(settings); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND m_brush = TextBrushInitializationWorkaround::instance()->tryGetBrush(settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ if (!m_brush) { KisBrushOption brushOption; brushOption.readOptionSetting(settings, true); m_brush = brushOption.brush(); } m_brush->notifyStrokeStarted(); m_precisionOption.readOptionSetting(settings); m_dabCache = new KisDabCache(m_brush); m_dabCache->setPrecisionOption(&m_precisionOption); m_mirrorOption.readOptionSetting(settings); m_dabCache->setMirrorPostprocessing(&m_mirrorOption); m_textureProperties.fillProperties(settings); m_dabCache->setTexturePostprocessing(&m_textureProperties); } KisBrushBasedPaintOp::~KisBrushBasedPaintOp() { delete m_dabCache; } bool KisBrushBasedPaintOp::checkSizeTooSmall(qreal scale) { scale *= m_brush->scale(); return (scale * m_brush->width() < 0.01 || scale * m_brush->height() < 0.01); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation) const { // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(scale, scale, 0); return effectiveSpacing(metric.width(), metric.height(), 1.0, false, rotation); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisPressureSpacingOption &spacingOption, const KisPaintInformation &pi) const { qreal extraSpacingScale = 1.0; if (spacingOption.isChecked()) { extraSpacingScale = spacingOption.apply(pi); } // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(scale, scale, 0); return effectiveSpacing(metric.width(), metric.height(), extraSpacingScale, spacingOption.isotropicSpacing(), rotation); } inline qreal KisBrushBasedPaintOp::calcAutoSpacing(qreal value, qreal coeff) { return coeff * (value < 1.0 ? value : sqrt(value)); } QPointF KisBrushBasedPaintOp::calcAutoSpacing(const QPointF &pt, qreal coeff) const { const qreal lodScale = KisLodTransform::lodToScale(painter()->device()); const qreal invLodScale = 1.0 / lodScale; const QPointF lod0Point = invLodScale * pt; return lodScale * QPointF(calcAutoSpacing(lod0Point.x(), coeff), calcAutoSpacing(lod0Point.y(), coeff)); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool isotropicSpacing, qreal rotation) const { QPointF spacing; if (!isotropicSpacing) { if (m_brush->autoSpacingActive()) { spacing = calcAutoSpacing(QPointF(dabWidth, dabHeight), m_brush->autoSpacingCoeff()); } else { spacing = QPointF(dabWidth, dabHeight); spacing *= m_brush->spacing(); } } else { qreal significantDimension = qMax(dabWidth, dabHeight); if (m_brush->autoSpacingActive()) { significantDimension = calcAutoSpacing(significantDimension, m_brush->autoSpacingCoeff()); } else { significantDimension *= m_brush->spacing(); } spacing = QPointF(significantDimension, significantDimension); rotation = 0.0; } spacing *= extraScale; return KisSpacingInformation(spacing, rotation); } bool KisBrushBasedPaintOp::canPaint() const { return m_brush != 0; } diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.h b/plugins/paintops/libpaintop/kis_brush_based_paintop.h index ec38fc8415..3971de8c79 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop.h +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.h @@ -1,94 +1,94 @@ /* * 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. */ #ifndef KIS_BRUSH_BASED_PAINTOP_H #define KIS_BRUSH_BASED_PAINTOP_H #include "kritapaintop_export.h" #include #include "kis_dab_cache.h" #include "kis_brush.h" #include "kis_texture_option.h" #include "kis_precision_option.h" #include "kis_pressure_mirror_option.h" #include class KisPropertiesConfiguration; class KisPressureSpacingOption; class KisDabCache; /// Internal class TextBrushInitializationWorkaround { public: TextBrushInitializationWorkaround(); ~TextBrushInitializationWorkaround(); static TextBrushInitializationWorkaround* instance(); - void preinitialize(const KisPropertiesConfiguration *settings); + void preinitialize(KisPropertiesConfigurationSP settings); - KisBrushSP tryGetBrush(const KisPropertiesConfiguration *settings); + KisBrushSP tryGetBrush(const KisPropertiesConfigurationSP settings); private: KisBrushSP m_brush; - const KisPropertiesConfiguration *m_settings; + KisPropertiesConfigurationSP m_settings; }; /** * This is a base class for paintops that use a KisBrush or derived * brush to paint with. This is mainly important for the spacing * generation. */ class PAINTOP_EXPORT KisBrushBasedPaintOp : public KisPaintOp { public: - KisBrushBasedPaintOp(const KisPropertiesConfiguration* settings, KisPainter* painter); + KisBrushBasedPaintOp(const KisPropertiesConfigurationSP settings, KisPainter* painter); ~KisBrushBasedPaintOp(); bool checkSizeTooSmall(qreal scale); KisSpacingInformation effectiveSpacing(qreal scale, qreal rotation) const; KisSpacingInformation effectiveSpacing(qreal scale, qreal rotation, const KisPressureSpacingOption &spacingOption, const KisPaintInformation &pi) const; ///Reimplemented, false if brush is 0 virtual bool canPaint() const; #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND typedef int needs_preinitialization; - static void preinitializeOpStatically(const KisPaintOpSettingsSP settings); + static void preinitializeOpStatically(KisPaintOpSettingsSP settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ private: KisSpacingInformation effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool isotropicSpacing, qreal rotation) const; QPointF calcAutoSpacing(const QPointF &pt, qreal coeff) const; static inline qreal calcAutoSpacing(qreal value, qreal coeff); protected: // XXX: make private! KisBrushSP m_brush; KisTextureProperties m_textureProperties; KisPressureMirrorOption m_mirrorOption; KisPrecisionOption m_precisionOption; KisDabCache *m_dabCache; }; #endif diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp index e93adcc320..7d277bf54e 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp @@ -1,328 +1,327 @@ /* * Copyright (c) 2010 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_based_paintop_settings.h" #include #include #include "kis_brush_based_paintop_options_widget.h" #include #include "kis_brush_server.h" #include #include "kis_signals_blocker.h" KisBrushBasedPaintOpSettings::KisBrushBasedPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION | KisCurrentOutlineFetcher::MIRROR_OPTION) { } bool KisBrushBasedPaintOpSettings::paintIncremental() { if (hasProperty("PaintOpAction")) { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } return true; } bool KisBrushBasedPaintOpSettings::isAirbrushing() const { return getBool(AIRBRUSH_ENABLED); } int KisBrushBasedPaintOpSettings::rate() const { return getInt(AIRBRUSH_RATE); } KisPaintOpSettingsSP KisBrushBasedPaintOpSettings::clone() const { KisPaintOpSettingsSP _settings = KisOutlineGenerationPolicy::clone(); - KisBrushBasedPaintOpSettings *settings = - dynamic_cast(_settings.data()); + KisBrushBasedPaintOpSettingsSP settings = dynamic_cast(_settings.data()); settings->m_savedBrush = this->brush(); return settings; } KisBrushSP KisBrushBasedPaintOpSettings::brush() const { KisBrushBasedPaintopOptionWidget *widget = dynamic_cast(optionsWidget()); return widget ? widget->brush() : m_savedBrush; } QPainterPath KisBrushBasedPaintOpSettings::brushOutlineImpl(const KisPaintInformation &info, OutlineMode mode, qreal additionalScale, - bool forceOutline) const + bool forceOutline) { QPainterPath path; if (forceOutline || mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { KisBrushSP brush = this->brush(); if (!brush) return path; qreal finalScale = brush->scale() * additionalScale; QPainterPath realOutline = brush->outline(); if (mode == CursorIsCircleOutline || mode == CursorTiltOutline || (forceOutline && mode == CursorNoOutline)) { QPainterPath ellipse; ellipse.addEllipse(realOutline.boundingRect()); realOutline = ellipse; } path = outlineFetcher()->fetchOutline(info, this, realOutline, finalScale, brush->angle()); if (mode == CursorTiltOutline) { QPainterPath tiltLine = makeTiltIndicator(info, realOutline.boundingRect().center(), realOutline.boundingRect().width() * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, finalScale, 0.0, true, realOutline.boundingRect().center().x(), realOutline.boundingRect().center().y())); } } return path; } -QPainterPath KisBrushBasedPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisBrushBasedPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { return brushOutlineImpl(info, mode, 1.0); } bool KisBrushBasedPaintOpSettings::isValid() const { QString filename = getString("requiredBrushFile", ""); if (!filename.isEmpty()) { KisBrushSP brush = KisBrushServer::instance()->brushServer()->resourceByFilename(filename); if (!brush) { return false; } } return true; } bool KisBrushBasedPaintOpSettings::isLoadable() { return (KisBrushServer::instance()->brushServer()->resources().count() > 0); } struct BrushReader { - BrushReader(const KisBrushBasedPaintOpSettings *parent) + BrushReader(KisBrushBasedPaintOpSettingsSP parent) : m_parent(parent) { if (m_parent->optionsWidget()) { KisSignalsBlocker b(m_parent->optionsWidget()); m_parent->optionsWidget()->setConfigurationSafe(m_parent); } else { m_parent = 0; } } KisBrushSP brush() { return m_parent ? m_parent->brush() : 0; } - const KisBrushBasedPaintOpSettings *m_parent; + KisBrushBasedPaintOpSettingsSP m_parent; }; struct BrushWriter { - BrushWriter(KisBrushBasedPaintOpSettings *parent) + BrushWriter(KisBrushBasedPaintOpSettingsSP parent) : m_parent(parent) { if (!m_parent->optionsWidget()) { m_parent = 0; } } ~BrushWriter() { if (m_parent && m_parent->optionsWidget()) { m_parent->optionsWidget()->writeConfigurationSafe(m_parent); } } KisBrushSP brush() { return m_parent ? m_parent->brush() : 0; } - KisBrushBasedPaintOpSettings *m_parent; + KisBrushBasedPaintOpSettingsSP m_parent; }; void KisBrushBasedPaintOpSettings::setAngle(qreal value) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setAngle(value); } -qreal KisBrushBasedPaintOpSettings::angle() const +qreal KisBrushBasedPaintOpSettings::angle() { BrushReader w(this); if (!w.brush()) return 0.0; return w.brush()->angle(); } void KisBrushBasedPaintOpSettings::setSpacing(qreal value) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setSpacing(value); } -qreal KisBrushBasedPaintOpSettings::spacing() const +qreal KisBrushBasedPaintOpSettings::spacing() { BrushReader w(this); if (!w.brush()) return 0.0; return w.brush()->spacing(); } void KisBrushBasedPaintOpSettings::setAutoSpacing(bool active, qreal coeff) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setAutoSpacing(active, coeff); } -bool KisBrushBasedPaintOpSettings::autoSpacingActive() const +bool KisBrushBasedPaintOpSettings::autoSpacingActive() { BrushReader w(this); if (!w.brush()) return 0.0; return w.brush()->autoSpacingActive(); } -qreal KisBrushBasedPaintOpSettings::autoSpacingCoeff() const +qreal KisBrushBasedPaintOpSettings::autoSpacingCoeff() { BrushReader w(this); if (!w.brush()) return 0.0; return w.brush()->autoSpacingCoeff(); } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" QList KisBrushBasedPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "angle", "Angle", this, 0); prop->setRange(0, 360); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); const qreal angleResult = kisRadiansToDegrees(s->angle()); prop->setValue(angleResult); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); s->setAngle(kisDegreesToRadians(prop->value().toReal())); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "auto_spacing", "Auto Spacing", this, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); prop->setValue(s->autoSpacingActive()); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); s->setAutoSpacing(prop->value().toBool(), s->autoSpacingCoeff()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spacing", "Spacing", this, 0); prop->setRange(0.01, 10); prop->setSingleStep(0.01); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); const qreal value = s->autoSpacingActive() ? s->autoSpacingCoeff() : s->spacing(); prop->setValue(value); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); if (s->autoSpacingActive()) { s->setAutoSpacing(true, prop->value().toReal()); } else { s->setSpacing(prop->value().toReal()); } }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties() + props; } diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.h b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.h index 5a6d1b6233..947550c791 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.h +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.h @@ -1,75 +1,86 @@ /* * Copyright (c) 2010 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_BRUSH_BASED_PAINTOP_SETTINGS_H #define KIS_BRUSH_BASED_PAINTOP_SETTINGS_H #include #include #include -#include "kis_brush.h" +#include +#include +#include +class KisBrushBasedPaintOpSettings; +typedef KisSharedPtr KisBrushBasedPaintOpSettingsSP; + class PAINTOP_EXPORT KisBrushBasedPaintOpSettings : public KisOutlineGenerationPolicy { public: KisBrushBasedPaintOpSettings(); + virtual ~KisBrushBasedPaintOpSettings() {} ///Reimplemented virtual bool paintIncremental(); ///Reimplemented virtual bool isAirbrushing() const; ///Reimplemented virtual int rate() const; using KisPaintOpSettings::brushOutline; - virtual QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + virtual QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); ///Reimplemented virtual bool isValid() const; ///Reimplemented virtual bool isLoadable(); KisBrushSP brush() const; KisPaintOpSettingsSP clone() const; void setAngle(qreal value); - qreal angle() const; + qreal angle(); void setSpacing(qreal spacing); - qreal spacing() const; + qreal spacing(); void setAutoSpacing(bool active, qreal coeff); - bool autoSpacingActive() const; - qreal autoSpacingCoeff() const; + bool autoSpacingActive(); + qreal autoSpacingCoeff(); QList uniformProperties(); protected: - QPainterPath brushOutlineImpl(const KisPaintInformation &info, OutlineMode mode, qreal additionalScale, bool forceOutline = false) const; + QPainterPath brushOutlineImpl(const KisPaintInformation &info, OutlineMode mode, qreal additionalScale, bool forceOutline = false); KisBrushSP m_savedBrush; QList m_uniformProperties; + +private: + + Q_DISABLE_COPY(KisBrushBasedPaintOpSettings) + }; #endif // KIS_BRUSH_BASED_PAINTOP_SETTINGS_H diff --git a/plugins/paintops/libpaintop/kis_brush_option.cpp b/plugins/paintops/libpaintop/kis_brush_option.cpp index 6ec520e054..f2f7b43049 100644 --- a/plugins/paintops/libpaintop/kis_brush_option.cpp +++ b/plugins/paintops/libpaintop/kis_brush_option.cpp @@ -1,92 +1,92 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) Sven Langkamp , (C) 2008 * * 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_brush_option.h" #include #include #include "kis_properties_configuration.h" -void KisBrushOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisBrushOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { if (!m_brush) return; QDomDocument d; QDomElement e = d.createElement("Brush"); m_brush->toXML(d, e); d.appendChild(e); setting->setProperty("brush_definition", d.toString()); QString brushFileName = !m_brush->filename().isEmpty() ? m_brush->shortFilename() : QString(); setting->setProperty("requiredBrushFile", brushFileName); } -QDomElement getBrushXMLElement(const KisPropertiesConfiguration* setting) +QDomElement getBrushXMLElement(const KisPropertiesConfigurationSP setting) { QDomElement element; QString brushDefinition = setting->getString("brush_definition"); if (!brushDefinition.isEmpty()) { QDomDocument d; d.setContent(brushDefinition, false); element = d.firstChildElement("Brush"); } return element; } -void KisBrushOption::readOptionSetting(const KisPropertiesConfiguration* setting, bool forceCopy) +void KisBrushOption::readOptionSetting(const KisPropertiesConfigurationSP setting, bool forceCopy) { QDomElement element = getBrushXMLElement(setting); if (!element.isNull()) { m_brush = KisBrush::fromXML(element, forceCopy); } } #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND #include "kis_text_brush_factory.h" -bool KisBrushOption::isTextBrush(const KisPropertiesConfiguration* setting) +bool KisBrushOption::isTextBrush(const KisPropertiesConfigurationSP setting) { static QString textBrushId = KisTextBrushFactory().id(); QDomElement element = getBrushXMLElement(setting); QString brushType = element.attribute("type"); return brushType == textBrushId; } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ KisBrushSP KisBrushOption::brush() const { return m_brush; } void KisBrushOption::setBrush(KisBrushSP brush) { m_brush = brush; } diff --git a/plugins/paintops/libpaintop/kis_brush_option.h b/plugins/paintops/libpaintop/kis_brush_option.h index 89c5c72deb..ab45f4407e 100644 --- a/plugins/paintops/libpaintop/kis_brush_option.h +++ b/plugins/paintops/libpaintop/kis_brush_option.h @@ -1,48 +1,49 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) Sven Langkamp , (C) 2008 * * 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_BRUSH_OPTION_H_ #define KIS_BRUSH_OPTION_H_ -#include "kis_brush.h" +#include +#include #include -#include -class KisPropertiesConfiguration; + +#include class PAINTOP_EXPORT KisBrushOption { public: - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting, bool forceCopy); + void readOptionSetting(const KisPropertiesConfigurationSP setting, bool forceCopy); KisBrushSP brush() const; void setBrush(KisBrushSP brush); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND - static bool isTextBrush(const KisPropertiesConfiguration* setting); + static bool isTextBrush(const KisPropertiesConfigurationSP setting); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ private: KisBrushSP m_brush; }; #endif diff --git a/plugins/paintops/libpaintop/kis_brush_option_widget.cpp b/plugins/paintops/libpaintop/kis_brush_option_widget.cpp index 7ac9c0d6dd..b72ece263b 100644 --- a/plugins/paintops/libpaintop/kis_brush_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_brush_option_widget.cpp @@ -1,118 +1,118 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_brush_option_widget.h" #include #include #include "kis_brush_selection_widget.h" #include "kis_brush.h" KisBrushOptionWidget::KisBrushOptionWidget() : KisPaintOpOption(KisPaintOpOption::GENERAL, true) { m_checkable = false; m_brushSelectionWidget = new KisBrushSelectionWidget(); connect(m_brushSelectionWidget, SIGNAL(sigPrecisionChanged()), SLOT(emitSettingChanged())); connect(m_brushSelectionWidget, SIGNAL(sigBrushChanged()), SLOT(brushChanged())); m_brushSelectionWidget->hide(); setConfigurationPage(m_brushSelectionWidget); m_brushOption.setBrush(brush()); setObjectName("KisBrushOptionWidget"); } KisBrushSP KisBrushOptionWidget::brush() const { return m_brushSelectionWidget->brush(); } void KisBrushOptionWidget::setAutoBrush(bool on) { m_brushSelectionWidget->setAutoBrush(on); } void KisBrushOptionWidget::setPredefinedBrushes(bool on) { m_brushSelectionWidget->setPredefinedBrushes(on); } void KisBrushOptionWidget::setCustomBrush(bool on) { m_brushSelectionWidget->setCustomBrush(on); } void KisBrushOptionWidget::setTextBrush(bool on) { m_brushSelectionWidget->setTextBrush(on); } void KisBrushOptionWidget::setImage(KisImageWSP image) { m_brushSelectionWidget->setImage(image); } void KisBrushOptionWidget::setPrecisionEnabled(bool value) { m_brushSelectionWidget->setPrecisionEnabled(value); } -void KisBrushOptionWidget::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisBrushOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP settings) const { m_brushSelectionWidget->writeOptionSetting(settings); m_brushOption.writeOptionSetting(settings); } -void KisBrushOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisBrushOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_brushSelectionWidget->readOptionSetting(setting); m_brushOption.readOptionSetting(setting, false); m_brushSelectionWidget->setCurrentBrush(m_brushOption.brush()); } void KisBrushOptionWidget::lodLimitations(KisPaintopLodLimitations *l) const { KisBrushSP brush = this->brush(); brush->lodLimitations(l); } void KisBrushOptionWidget::setBrushSize(qreal dxPixels, qreal dyPixels) { m_brushSelectionWidget->setBrushSize(dxPixels, dyPixels); } QSizeF KisBrushOptionWidget::brushSize() const { return m_brushSelectionWidget->brushSize(); } void KisBrushOptionWidget::brushChanged() { m_brushOption.setBrush(brush()); emitSettingChanged(); } bool KisBrushOptionWidget::presetIsValid() { return m_brushSelectionWidget->presetIsValid(); } #include "moc_kis_brush_option_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_brush_option_widget.h b/plugins/paintops/libpaintop/kis_brush_option_widget.h index 0c230fc832..ff7e532c7c 100644 --- a/plugins/paintops/libpaintop/kis_brush_option_widget.h +++ b/plugins/paintops/libpaintop/kis_brush_option_widget.h @@ -1,75 +1,75 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_BRUSH_OPTION_H #define KIS_BRUSH_OPTION_H #include "kis_paintop_option.h" #include "kis_brush_option.h" #include #include "kis_brush.h" class KisBrushSelectionWidget; /** * The brush option allows the user to select a particular brush * footprint for suitable paintops */ class PAINTOP_EXPORT KisBrushOptionWidget : public KisPaintOpOption { Q_OBJECT public: KisBrushOptionWidget(); /** * @return the currently selected brush */ KisBrushSP brush() const; void setAutoBrush(bool on); void setPredefinedBrushes(bool on); void setCustomBrush(bool on); void setTextBrush(bool on); void setImage(KisImageWSP image); void setPrecisionEnabled(bool value); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; void setBrushSize(qreal dxPixels, qreal dyPixels); QSizeF brushSize() const; bool presetIsValid(); private Q_SLOTS: void brushChanged(); private: KisBrushSelectionWidget * m_brushSelectionWidget; KisBrushOption m_brushOption; }; #endif diff --git a/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp b/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp index 9456146f21..e95586340f 100644 --- a/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp +++ b/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp @@ -1,374 +1,374 @@ /* * Copyright (c) 2008 Boudewijn Rempt * 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_brush_selection_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_brush.h" #include "kis_auto_brush.h" #include "kis_imagepipe_brush.h" #include "kis_brush_chooser.h" #include "kis_auto_brush_widget.h" #include "kis_custom_brush_widget.h" #include "kis_clipboard_brush_widget.h" #include "kis_text_brush_chooser.h" KisBrushSelectionWidget::KisBrushSelectionWidget(QWidget * parent) : QWidget(parent), m_currentBrushWidget(0) { uiWdgBrushChooser.setupUi(this); m_buttonGroup = new QButtonGroup(this); m_buttonGroup->setExclusive(true); m_layout = new QGridLayout(uiWdgBrushChooser.settingsFrame); m_autoBrushWidget = new KisAutoBrushWidget(this, "autobrush"); connect(m_autoBrushWidget, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Auto"), m_autoBrushWidget, AUTOBRUSH, KoGroupButton::GroupLeft); m_brushChooser = new KisBrushChooser(this); connect(m_brushChooser, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Predefined"), m_brushChooser, PREDEFINEDBRUSH, KoGroupButton::GroupCenter); m_textBrushWidget = new KisTextBrushChooser(this, "textbrush", i18n("Text")); connect(m_textBrushWidget, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Text"), m_textBrushWidget, TEXTBRUSH, KoGroupButton::GroupRight); connect(m_buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(buttonClicked(int))); Q_FOREACH (QWidget * widget, m_chooserMap.values()) { m_mininmumSize = m_mininmumSize.expandedTo(widget->sizeHint()); } setCurrentWidget(m_autoBrushWidget); uiWdgBrushChooser.sliderPrecision->setRange(1, 5); uiWdgBrushChooser.sliderPrecision->setSingleStep(1); uiWdgBrushChooser.sliderPrecision->setPageStep(1); connect(uiWdgBrushChooser.sliderPrecision, SIGNAL(valueChanged(int)), SLOT(precisionChanged(int))); connect(uiWdgBrushChooser.autoPrecisionCheckBox, SIGNAL(stateChanged(int)), SLOT(setAutoPrecisionEnabled(int))); connect(uiWdgBrushChooser.deltaValueSpinBox, SIGNAL(valueChanged(double)), SLOT(setDeltaValue(double))); connect(uiWdgBrushChooser.sizeToStartFromSpinBox, SIGNAL(valueChanged(double)), SLOT(setSizeToStartFrom(double))); uiWdgBrushChooser.sliderPrecision->setValue(4); setPrecisionEnabled(false); uiWdgBrushChooser.label->setVisible(false); uiWdgBrushChooser.label_2->setVisible(false); uiWdgBrushChooser.deltaValueSpinBox->setVisible(false); uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(false); uiWdgBrushChooser.lblPrecisionValue->setVisible(false); uiWdgBrushChooser.label ->setToolTip(i18n("Use to set the size from which the Automatic Precision Setting should begin. \nThe Precision will remain 5 before this value.")); uiWdgBrushChooser.label_2 ->setToolTip(i18n("Use to set the interval at which the Automatic Precision will change. \nThe Precision will decrease as brush size increases.")); m_presetIsValid = true; } KisBrushSelectionWidget::~KisBrushSelectionWidget() { } KisBrushSP KisBrushSelectionWidget::brush() const { KisBrushSP theBrush; switch (m_buttonGroup->checkedId()) { case AUTOBRUSH: theBrush = m_autoBrushWidget->brush(); break; case PREDEFINEDBRUSH: theBrush = m_brushChooser->brush(); break; case TEXTBRUSH: theBrush = m_textBrushWidget->brush(); break; default: ; } // Fallback to auto brush if no brush selected // Can happen if there is no predefined brush found if (!theBrush) theBrush = m_autoBrushWidget->brush(); return theBrush; } void KisBrushSelectionWidget::setAutoBrush(bool on) { m_buttonGroup->button(AUTOBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setPredefinedBrushes(bool on) { m_buttonGroup->button(PREDEFINEDBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setCustomBrush(bool on) { m_buttonGroup->button(CUSTOMBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setClipboardBrush(bool on) { m_buttonGroup->button(CLIPBOARDBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setTextBrush(bool on) { m_buttonGroup->button(TEXTBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setImage(KisImageWSP image) { m_brushChooser->setImage(image); } void KisBrushSelectionWidget::setCurrentBrush(KisBrushSP brush) { if (!brush) { return; } // XXX: clever code have brush plugins know their configuration // pane, so we don't have to have this if statement and // have an extensible set of brush types if (dynamic_cast(brush.data())) { setCurrentWidget(m_autoBrushWidget); m_autoBrushWidget->setBrush(brush); } else if (dynamic_cast(brush.data())) { setCurrentWidget(m_textBrushWidget); m_textBrushWidget->setBrush(brush); } else { setCurrentWidget(m_brushChooser); m_brushChooser->setBrush(brush); } } void KisBrushSelectionWidget::setBrushSize(qreal dxPixels, qreal dyPixels) { if (m_buttonGroup->checkedId() == AUTOBRUSH) { m_autoBrushWidget->setBrushSize(dxPixels, dyPixels); } else if (m_buttonGroup->checkedId() == PREDEFINEDBRUSH) { m_brushChooser->setBrushSize(dxPixels, dyPixels); } else if (m_buttonGroup->checkedId() == CUSTOMBRUSH || m_buttonGroup->checkedId() == CLIPBOARDBRUSH) { // switch to the predefined brush and resize it KisBrushSP brush = this->brush(); if (brush) { setCurrentWidget(m_brushChooser); m_brushChooser->setBrush(brush); m_brushChooser->setBrushSize(dxPixels, dyPixels); } } if(m_precisionOption.autoPrecisionEnabled()) { m_precisionOption.setAutoPrecision(this->brushSize().width()); uiWdgBrushChooser.lblPrecisionValue->setText("Precision:"+QString::number(m_precisionOption.precisionLevel())); emit sigPrecisionChanged(); } } QSizeF KisBrushSelectionWidget::brushSize() const { if (m_buttonGroup->checkedId() == AUTOBRUSH) { return m_autoBrushWidget->brushSize(); } else if (KisBrushSP brush = this->brush()) { qreal width = brush->width() * brush->scale(); qreal height = brush->height() * brush->scale(); return QSizeF(width, height); } // return neutral value return QSizeF(1.0, 1.0); } void KisBrushSelectionWidget::buttonClicked(int id) { setCurrentWidget(m_chooserMap[id]); emit sigBrushChanged(); } void KisBrushSelectionWidget::precisionChanged(int value) { QString toolTip; switch (value) { case 1: toolTip = i18n("Precision Level 1 (fastest)\n" "Subpixel precision: disabled\n" "Brush size precision: 5%\n" "\n" "Optimal for very big brushes"); break; case 2: toolTip = i18n("Precision Level 2\n" "Subpixel precision: disabled\n" "Brush size precision: 1%\n" "\n" "Optimal for big brushes"); break; case 3: toolTip = i18n("Precision Level 3\n" "Subpixel precision: disabled\n" "Brush size precision: exact"); break; case 4: toolTip = i18n("Precision Level 4 (optimal)\n" "Subpixel precision: 50%\n" "Brush size precision: exact\n" "\n" "Gives up to 50% better performance in comparison to Level 5"); break; case 5: toolTip = i18n("Precision Level 5 (best quality)\n" "Subpixel precision: exact\n" "Brush size precision: exact\n" "\n" "The slowest performance. Best quality."); break; } uiWdgBrushChooser.sliderPrecision->blockSignals(true); uiWdgBrushChooser.sliderPrecision->setValue(value); uiWdgBrushChooser.sliderPrecision->blockSignals(false); uiWdgBrushChooser.sliderPrecision->setToolTip(toolTip); m_precisionOption.setPrecisionLevel(value); emit sigPrecisionChanged(); } -void KisBrushSelectionWidget::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisBrushSelectionWidget::writeOptionSetting(KisPropertiesConfigurationSP settings) const { m_precisionOption.writeOptionSetting(settings); } -void KisBrushSelectionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisBrushSelectionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_precisionOption.readOptionSetting(setting); uiWdgBrushChooser.sliderPrecision->setValue(m_precisionOption.precisionLevel()); uiWdgBrushChooser.autoPrecisionCheckBox->setChecked(m_precisionOption.autoPrecisionEnabled()); uiWdgBrushChooser.deltaValueSpinBox ->setValue(m_precisionOption.deltaValue()); uiWdgBrushChooser.sizeToStartFromSpinBox ->setValue(m_precisionOption.sizeToStartFrom()); } void KisBrushSelectionWidget::setPrecisionEnabled(bool value) { uiWdgBrushChooser.sliderPrecision->setVisible(value); uiWdgBrushChooser.lblPrecision->setVisible(value); } void KisBrushSelectionWidget::setCurrentWidget(QWidget* widget) { if (widget == m_currentBrushWidget) return; if (m_currentBrushWidget) { m_layout->removeWidget(m_currentBrushWidget); m_currentBrushWidget->setParent(this); m_currentBrushWidget->hide(); } widget->setMinimumSize(m_mininmumSize); m_currentBrushWidget = widget; m_layout->addWidget(widget); m_currentBrushWidget->show(); m_buttonGroup->button(m_chooserMap.key(widget))->setChecked(true); m_presetIsValid = (m_buttonGroup->checkedId() != CUSTOMBRUSH); } void KisBrushSelectionWidget::addChooser(const QString& text, QWidget* widget, int id, KoGroupButton::GroupPosition pos) { KoGroupButton * button = new KoGroupButton(this); button->setGroupPosition(pos); button->setText(text); button->setAutoRaise(true); button->setCheckable(true); uiWdgBrushChooser.brushChooserButtonLayout->addWidget(button); m_buttonGroup->addButton(button, id); m_chooserMap[m_buttonGroup->id(button)] = widget; widget->hide(); } void KisBrushSelectionWidget::setAutoPrecisionEnabled(int value) { m_precisionOption.setAutoPrecisionEnabled(value); if(m_precisionOption.autoPrecisionEnabled()) { m_precisionOption.setAutoPrecision(this->brushSize().height()); setPrecisionEnabled(false); precisionChanged(m_precisionOption.precisionLevel()); uiWdgBrushChooser.label->setVisible(true); uiWdgBrushChooser.label_2->setVisible(true); uiWdgBrushChooser.deltaValueSpinBox->setVisible(true); uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(true); uiWdgBrushChooser.lblPrecisionValue->setVisible(true); uiWdgBrushChooser.lblPrecisionValue->setText("Precision:"+QString::number(m_precisionOption.precisionLevel())); } else { setPrecisionEnabled(true); uiWdgBrushChooser.label->setVisible(false); uiWdgBrushChooser.label_2->setVisible(false); uiWdgBrushChooser.deltaValueSpinBox->setVisible(false); uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(false); uiWdgBrushChooser.lblPrecisionValue->setVisible(false); } emit sigPrecisionChanged(); } void KisBrushSelectionWidget::setSizeToStartFrom(double value) { m_precisionOption.setSizeToStartFrom(value); emit sigPrecisionChanged(); } void KisBrushSelectionWidget::setDeltaValue(double value) { m_precisionOption.setDeltaValue(value); emit sigPrecisionChanged(); } #include "moc_kis_brush_selection_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_brush_selection_widget.h b/plugins/paintops/libpaintop/kis_brush_selection_widget.h index 8f187bdd72..cf262291c7 100644 --- a/plugins/paintops/libpaintop/kis_brush_selection_widget.h +++ b/plugins/paintops/libpaintop/kis_brush_selection_widget.h @@ -1,113 +1,117 @@ /* * Copyright (c) 2008 Boudewijn Rempt * 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. */ #ifndef KIS_BRUSH_SELECTION_WIDGET_H #define KIS_BRUSH_SELECTION_WIDGET_H #include + #include -#include "kis_brush.h" + +#include +#include + #include "kis_precision_option.h" #include "ui_wdgbrushchooser.h" class KisAutoBrushWidget; class KisBrushChooser; class KisTextBrushChooser; class KisCustomBrushWidget; class KisClipboardBrushWidget; class KisBrush; /** * Compound widget that collects all the various brush selection widgets. */ class PAINTOP_EXPORT KisBrushSelectionWidget : public QWidget { Q_OBJECT public: KisBrushSelectionWidget(QWidget * parent = 0); ~KisBrushSelectionWidget(); KisBrushSP brush() const; void setAutoBrush(bool on); void setPredefinedBrushes(bool on); void setCustomBrush(bool on); void setClipboardBrush(bool on); void setTextBrush(bool on); void setImage(KisImageWSP image); void setCurrentBrush(KisBrushSP brush); void setBrushSize(qreal dxPixels, qreal dyPixels); QSizeF brushSize() const; bool presetIsValid() { return m_presetIsValid; } - void writeOptionSetting(KisPropertiesConfiguration* settings) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP settings) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void setPrecisionEnabled(bool value); bool autoPrecisionEnabled(); Q_SIGNALS: void sigBrushChanged(); void sigPrecisionChanged(); private Q_SLOTS: void buttonClicked(int id); void precisionChanged(int value); void setAutoPrecisionEnabled(int value); void setSizeToStartFrom(double value); void setDeltaValue(double value); private: void setCurrentWidget(QWidget * widget); void addChooser(const QString & text, QWidget * widget, int id, KoGroupButton::GroupPosition pos); private: enum Type { AUTOBRUSH, PREDEFINEDBRUSH, CUSTOMBRUSH, TEXTBRUSH, CLIPBOARDBRUSH }; bool m_presetIsValid; Ui_WdgBrushChooser uiWdgBrushChooser; QGridLayout * m_layout; QWidget * m_currentBrushWidget; QHash m_chooserMap; QButtonGroup * m_buttonGroup; QSize m_mininmumSize; KisAutoBrushWidget * m_autoBrushWidget; KisBrushChooser * m_brushChooser; KisTextBrushChooser * m_textBrushWidget; KisPrecisionOption m_precisionOption; }; #endif diff --git a/plugins/paintops/libpaintop/kis_color_option.cpp b/plugins/paintops/libpaintop/kis_color_option.cpp index 6f6bd37d9a..24f22f1784 100644 --- a/plugins/paintops/libpaintop/kis_color_option.cpp +++ b/plugins/paintops/libpaintop/kis_color_option.cpp @@ -1,171 +1,171 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_color_option.h" #include #include "ui_wdgcoloroptions.h" class KisColorOptionsWidget: public QWidget, public Ui::WdgColorOptions { public: KisColorOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); hueSlider->setRange(-180, 180); hueSlider->setValue(0); saturationSlider->setRange(-100, 100); saturationSlider->setValue(0); valueSlider->setRange(-100, 100); valueSlider->setValue(0); } }; KisColorOption::KisColorOption() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { m_checkable = false; m_options = new KisColorOptionsWidget(); setObjectName("KisColorOption"); // ui connect(m_options->randomHSVCHBox, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); // settings connect(m_options->randomOpacityCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->randomHSVCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->hueSlider, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->saturationSlider, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->valueSlider, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_options->sampleInputCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->colorPerParticleCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->fillBackgroundCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->mixBgColorCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisColorOption::~KisColorOption() { // delete m_options; } -void KisColorOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisColorOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(COLOROP_HUE, hue()); setting->setProperty(COLOROP_SATURATION, saturation()); setting->setProperty(COLOROP_VALUE, value()); setting->setProperty(COLOROP_USE_RANDOM_HSV, useRandomHSV()); setting->setProperty(COLOROP_USE_RANDOM_OPACITY, useRandomOpacity()); setting->setProperty(COLOROP_SAMPLE_COLOR, sampleInputColor()); setting->setProperty(COLOROP_FILL_BG, fillBackground()); setting->setProperty(COLOROP_COLOR_PER_PARTICLE, colorPerParticle()); setting->setProperty(COLOROP_MIX_BG_COLOR, mixBgColor()); } -void KisColorOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisColorOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_options->hueSlider->setValue(setting->getInt(COLOROP_HUE)); m_options->saturationSlider->setValue(setting->getInt(COLOROP_SATURATION)); m_options->valueSlider->setValue(setting->getInt(COLOROP_VALUE)); m_options->randomOpacityCHBox->setChecked(setting->getBool(COLOROP_USE_RANDOM_OPACITY)); m_options->randomHSVCHBox->setChecked(setting->getBool(COLOROP_USE_RANDOM_HSV)); setEnabled(setting->getBool(COLOROP_USE_RANDOM_HSV)); m_options->sampleInputCHBox->setChecked(setting->getBool(COLOROP_SAMPLE_COLOR)); m_options->fillBackgroundCHBox->setChecked(setting->getBool(COLOROP_FILL_BG)); m_options->colorPerParticleCHBox->setChecked(setting->getBool(COLOROP_COLOR_PER_PARTICLE)); m_options->mixBgColorCHBox->setChecked(setting->getBool(COLOROP_MIX_BG_COLOR)); } void KisColorOption::setEnabled(bool enabled) { m_options->hueSlider->setEnabled(!enabled); m_options->saturationSlider->setEnabled(!enabled); m_options->valueSlider->setEnabled(!enabled); } bool KisColorOption::useRandomOpacity() const { return m_options->randomOpacityCHBox->isChecked(); } bool KisColorOption::useRandomHSV() const { return m_options->randomHSVCHBox->isChecked(); } int KisColorOption::hue() const { return m_options->hueSlider->value(); } int KisColorOption::saturation() const { return m_options->saturationSlider->value(); } int KisColorOption::value() const { return m_options->valueSlider->value(); } bool KisColorOption::sampleInputColor() const { return m_options->sampleInputCHBox->isChecked(); } bool KisColorOption::colorPerParticle() const { return m_options->colorPerParticleCHBox->isChecked(); } bool KisColorOption::fillBackground() const { return m_options->fillBackgroundCHBox->isChecked(); } bool KisColorOption::mixBgColor() const { return m_options->mixBgColorCHBox->isChecked(); } -void KisColorProperties::fillProperties(const KisPropertiesConfiguration* setting) +void KisColorProperties::fillProperties(const KisPropertiesConfigurationSP setting) { hue = setting->getInt(COLOROP_HUE); saturation = setting->getInt(COLOROP_SATURATION); value = setting->getInt(COLOROP_VALUE); useRandomOpacity = setting->getBool(COLOROP_USE_RANDOM_OPACITY); useRandomHSV = setting->getBool(COLOROP_USE_RANDOM_HSV); sampleInputColor = setting->getBool(COLOROP_SAMPLE_COLOR); fillBackground = setting->getBool(COLOROP_FILL_BG); colorPerParticle = setting->getBool(COLOROP_COLOR_PER_PARTICLE); mixBgColor = setting->getBool(COLOROP_MIX_BG_COLOR); } diff --git a/plugins/paintops/libpaintop/kis_color_option.h b/plugins/paintops/libpaintop/kis_color_option.h index b3b6dd807e..afc62e4531 100644 --- a/plugins/paintops/libpaintop/kis_color_option.h +++ b/plugins/paintops/libpaintop/kis_color_option.h @@ -1,92 +1,92 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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_OPTION_H #define KIS_COLOR_OPTION_H #include #include const QString COLOROP_HUE = "ColorOption/hue"; const QString COLOROP_SATURATION = "ColorOption/saturation"; const QString COLOROP_VALUE = "ColorOption/value"; const QString COLOROP_USE_RANDOM_HSV = "ColorOption/useRandomHSV"; const QString COLOROP_USE_RANDOM_OPACITY = "ColorOption/useRandomOpacity"; const QString COLOROP_SAMPLE_COLOR = "ColorOption/sampleInputColor"; const QString COLOROP_FILL_BG = "ColorOption/fillBackground"; const QString COLOROP_COLOR_PER_PARTICLE = "ColorOption/colorPerParticle"; const QString COLOROP_MIX_BG_COLOR = "ColorOption/mixBgColor"; class KisColorOptionsWidget; class PAINTOP_EXPORT KisColorOption : public KisPaintOpOption { Q_OBJECT public: KisColorOption(); ~KisColorOption(); bool useRandomHSV() const; bool useRandomOpacity() const; bool sampleInputColor() const; bool fillBackground() const; bool colorPerParticle() const; bool mixBgColor() const; // TODO: these should be intervals like 20..180 int hue() const; int saturation() const; int value() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private Q_SLOTS: void setEnabled(bool); private: KisColorOptionsWidget * m_options; }; class PAINTOP_EXPORT KisColorProperties { public: bool useRandomHSV; bool useRandomOpacity; bool sampleInputColor; bool fillBackground; bool colorPerParticle; bool mixBgColor; int hue; int saturation; int value; public: /// fill the class members with related properties - void fillProperties(const KisPropertiesConfiguration* setting); + void fillProperties(const KisPropertiesConfigurationSP setting); }; #endif // KIS_COLOR_OPTION_H diff --git a/plugins/paintops/libpaintop/kis_color_source_option.cpp b/plugins/paintops/libpaintop/kis_color_source_option.cpp index b83ac7c07b..c73d95fdc1 100644 --- a/plugins/paintops/libpaintop/kis_color_source_option.cpp +++ b/plugins/paintops/libpaintop/kis_color_source_option.cpp @@ -1,136 +1,136 @@ /* * Copyright (c) 2011 Cyrille Berger * * 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_source_option.h" #include #include #include #include "kis_color_source.h" #include #include #include struct KisColorSourceOption::Private { Private() : type(PLAIN) {} KisColorSourceOption::Type type; static QMap type2id; static QMap id2type; static void addType(KisColorSourceOption::Type _type, KoID _id); }; QMap KisColorSourceOption::Private::type2id; QMap KisColorSourceOption::Private::id2type; void KisColorSourceOption::Private::addType(KisColorSourceOption::Type _type, KoID _id) { type2id[_type] = _id; id2type[_id.id()] = _type; } KisColorSourceOption::KisColorSourceOption() : d(new Private) { if (Private::type2id.isEmpty()) { Private::addType(PLAIN, KoID("plain", i18n("Plain color"))); Private::addType(GRADIENT, KoID("gradient", i18n("Gradient"))); Private::addType(UNIFORM_RANDOM, KoID("uniform_random", i18n("Uniform random"))); Private::addType(TOTAL_RANDOM, KoID("total_random", i18n("Total random"))); Private::addType(PATTERN, KoID("pattern", i18n("Pattern"))); Private::addType(PATTERN_LOCKED, KoID("lockedpattern", i18n("Locked pattern"))); } } KisColorSourceOption::~KisColorSourceOption() { delete d; } -void KisColorSourceOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisColorSourceOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty("ColorSource/Type", Private::type2id.value(d->type).id()); } -void KisColorSourceOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisColorSourceOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { QString colorSourceType = setting->getString("ColorSource/Type", "plain"); d->type = Private::id2type.value(colorSourceType, PLAIN); } KisColorSource* KisColorSourceOption::createColorSource(const KisPainter* _painter) const { Q_ASSERT(_painter); switch (d->type) { case PLAIN: return new KisPlainColorSource(_painter->backgroundColor(), _painter->paintColor()); case GRADIENT: return new KisGradientColorSource(_painter->gradient(), _painter->paintColor().colorSpace()); case UNIFORM_RANDOM: return new KisUniformRandomColorSource(); case TOTAL_RANDOM: return new KisTotalRandomColorSource(); case PATTERN: { if (_painter->pattern()) { KisPaintDevice* dev = new KisPaintDevice(_painter->paintColor().colorSpace(), _painter->pattern()->name()); dev->convertFromQImage(_painter->pattern()->pattern(), 0); return new KoPatternColorSource(dev, _painter->pattern()->width(), _painter->pattern()->height(), false); } } case PATTERN_LOCKED: { if (_painter->pattern()) { KisPaintDevice* dev = new KisPaintDevice(_painter->paintColor().colorSpace(), _painter->pattern()->name()); dev->convertFromQImage(_painter->pattern()->pattern(), 0); return new KoPatternColorSource(dev, _painter->pattern()->width(), _painter->pattern()->height(), true); } } } // Fallback in case the patterns are messed up return new KisPlainColorSource(_painter->backgroundColor(), _painter->paintColor()); } QString KisColorSourceOption::colorSourceTypeId() const { return Private::type2id.value(d->type).id(); } void KisColorSourceOption::setColorSourceType(Type _type) { d->type = _type; } void KisColorSourceOption::setColorSourceType(const QString& _id) { d->type = Private::id2type[_id]; } QList KisColorSourceOption::sourceIds() { return Private::type2id.values(); } KisColorSourceOption::Type KisColorSourceOption::type() const { return d->type; } diff --git a/plugins/paintops/libpaintop/kis_color_source_option.h b/plugins/paintops/libpaintop/kis_color_source_option.h index eb984dc97f..6f55f9cbe9 100644 --- a/plugins/paintops/libpaintop/kis_color_source_option.h +++ b/plugins/paintops/libpaintop/kis_color_source_option.h @@ -1,61 +1,63 @@ /* This file is part of the Calligra project * Copyright (C) 2008 Thomas Zander * * 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_COLOR_SOURCE_OPTION_H #define _KIS_COLOR_SOURCE_OPTION_H #include + #include +#include + class KisColorSource; -class KisPropertiesConfiguration; class KoID; class KisPainter; class PAINTOP_EXPORT KisColorSourceOption { public: enum Type { PLAIN, GRADIENT, UNIFORM_RANDOM, TOTAL_RANDOM, PATTERN, PATTERN_LOCKED }; public: KisColorSourceOption(); ~KisColorSourceOption(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); KisColorSource* createColorSource(const KisPainter* _painter) const; QString colorSourceTypeId() const; void setColorSourceType(Type _type); void setColorSourceType(const QString& _type); static QList sourceIds(); Type type() const; private: struct Private; Private* const d; }; #endif diff --git a/plugins/paintops/libpaintop/kis_color_source_option_widget.cpp b/plugins/paintops/libpaintop/kis_color_source_option_widget.cpp index 755785282c..7a7f6ae074 100644 --- a/plugins/paintops/libpaintop/kis_color_source_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_color_source_option_widget.cpp @@ -1,108 +1,108 @@ /* * Copyright (c) 2011 Cyrille Berger * * 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_source_option_widget.h" #include #include #include #include #include "kis_color_source_option.h" #include "kis_color_source.h" #include #include struct KisColorSourceOptionWidget::Private { KisColorSourceOption option; QMap id2radio; }; KisColorSourceOptionWidget::KisColorSourceOptionWidget() : KisPaintOpOption(KisPaintOpOption::COLOR, true) , d(new Private) { m_checkable = false; QWidget* configurationWidget = new QWidget; QGroupBox* groupBox = new QGroupBox(configurationWidget); groupBox->setObjectName(QString::fromUtf8("groupBox")); QVBoxLayout* verticalLayout = new QVBoxLayout(groupBox); Q_FOREACH (const KoID & id, KisColorSourceOption::sourceIds()) { QRadioButton* radioButton = new QRadioButton(groupBox); radioButton->setText(id.name()); d->id2radio[id.id()] = radioButton; connect(radioButton, SIGNAL(toggled(bool)), SLOT(sourceChanged())); verticalLayout->addWidget(radioButton); } QVBoxLayout* verticalLayout_2 = new QVBoxLayout(configurationWidget); verticalLayout_2->setMargin(0); verticalLayout_2->addWidget(groupBox); verticalLayout_2->addStretch(); setConfigurationPage(configurationWidget); setObjectName("KisColorSourceOptionWidget"); } KisColorSourceOptionWidget::~KisColorSourceOptionWidget() { delete d; } -void KisColorSourceOptionWidget::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisColorSourceOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP setting) const { d->option.writeOptionSetting(setting); } -void KisColorSourceOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisColorSourceOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { d->option.readOptionSetting(setting); QRadioButton* rb = d->id2radio.value(d->option.colorSourceTypeId()); if (rb) { rb->setChecked(true); } } void KisColorSourceOptionWidget::lodLimitations(KisPaintopLodLimitations *l) const { if (d->option.type() == KisColorSourceOption::TOTAL_RANDOM) { l->limitations << KoID("source-total-random", i18nc("PaintOp instant preview limitation", "Source -> Total Random")); } else if (d->option.type() == KisColorSourceOption::PATTERN) { l->blockers << KoID("source-pattern", i18nc("PaintOp instant preview limitation", "Source -> Pattern")); } else if (d->option.type() == KisColorSourceOption::PATTERN_LOCKED) { l->blockers << KoID("source-pattern-locked", i18nc("PaintOp instant preview limitation", "Source -> Pattern Locked")); } } void KisColorSourceOptionWidget::sourceChanged() { for (QMap::iterator it = d->id2radio.begin(); it != d->id2radio.end(); ++it) { if (it.value()->isChecked()) { d->option.setColorSourceType(it.key()); break; } } emitSettingChanged(); } diff --git a/plugins/paintops/libpaintop/kis_color_source_option_widget.h b/plugins/paintops/libpaintop/kis_color_source_option_widget.h index 82c7b57d4d..7995e52b24 100644 --- a/plugins/paintops/libpaintop/kis_color_source_option_widget.h +++ b/plugins/paintops/libpaintop/kis_color_source_option_widget.h @@ -1,51 +1,51 @@ /* * Copyright (c) 2011 Cyrille Berger * * 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_COLOR_SOURCE_OPTION_WIDGET_H #define KIS_COLOR_SOURCE_OPTION_WIDGET_H #include "kis_paintop_option.h" #include class KisPaintopLodLimitations; /** * The brush option allows the user to select a particular brush * footprint for suitable paintops */ class PAINTOP_EXPORT KisColorSourceOptionWidget : public KisPaintOpOption { Q_OBJECT public: KisColorSourceOptionWidget(); ~KisColorSourceOptionWidget(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private Q_SLOTS: void sourceChanged(); private: struct Private; Private* const d; }; #endif diff --git a/plugins/paintops/libpaintop/kis_compositeop_option.cpp b/plugins/paintops/libpaintop/kis_compositeop_option.cpp index 17b1913e94..d9563c0f8c 100644 --- a/plugins/paintops/libpaintop/kis_compositeop_option.cpp +++ b/plugins/paintops/libpaintop/kis_compositeop_option.cpp @@ -1,113 +1,113 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_compositeop_option.h" #include #include #include #include #include #include #include #include #include "kis_signals_blocker.h" KisCompositeOpOption::KisCompositeOpOption(bool createConfigWidget): KisPaintOpOption(KisPaintOpOption::GENERAL, true), m_createConfigWidget(createConfigWidget), m_eraserMode(false) { m_checkable = false; m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); if (createConfigWidget) { QWidget* widget = new QWidget(); Ui_wdgCompositeOpOption ui; ui.setupUi(widget); ui.bnEraser->setIcon(KisIconUtils::loadIcon("draw-eraser")); m_label = ui.lbChoosenMode; m_list = ui.list; m_bnEraser = ui.bnEraser; setConfigurationPage(widget); connect(ui.list , SIGNAL(clicked(const QModelIndex&)), this, SLOT(slotCompositeOpChanged(const QModelIndex&))); connect(ui.bnEraser, SIGNAL(toggled(bool)) , this, SLOT(slotEraserToggled(bool))); } setObjectName("KisCompositeOpOption"); } KisCompositeOpOption::~KisCompositeOpOption() { } -void KisCompositeOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisCompositeOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty("CompositeOp", m_currCompositeOpID); setting->setProperty("EraserMode", m_eraserMode); } -void KisCompositeOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisCompositeOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { QString ompositeOpID = setting->getString("CompositeOp", KoCompositeOpRegistry::instance().getDefaultCompositeOp().id()); KoID compositeOp = KoCompositeOpRegistry::instance().getKoID(ompositeOpID); changeCompositeOp(compositeOp); const bool eraserMode = setting->getBool("EraserMode", false);; slotEraserToggled(eraserMode); } void KisCompositeOpOption::changeCompositeOp(const KoID& compositeOp) { if (compositeOp.id() == m_currCompositeOpID) return; m_currCompositeOpID = compositeOp.id(); if (m_createConfigWidget) { m_label->setText(compositeOp.name()); } emitSettingChanged(); } void KisCompositeOpOption::slotCompositeOpChanged(const QModelIndex& index) { Q_UNUSED(index); KoID compositeOp = m_list->selectedCompositeOp(); changeCompositeOp(compositeOp); } void KisCompositeOpOption::slotEraserToggled(bool toggled) { if (m_bnEraser->isChecked() != toggled) { KisSignalsBlocker b(m_bnEraser); m_bnEraser->setChecked(toggled); } m_eraserMode = toggled; emitSettingChanged(); } diff --git a/plugins/paintops/libpaintop/kis_compositeop_option.h b/plugins/paintops/libpaintop/kis_compositeop_option.h index ab4822d28c..a9373eea7e 100644 --- a/plugins/paintops/libpaintop/kis_compositeop_option.h +++ b/plugins/paintops/libpaintop/kis_compositeop_option.h @@ -1,62 +1,62 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_COMPOSITEOP_OPTION_H #define KIS_COMPOSITEOP_OPTION_H #include #include #include // const QString AIRBRUSH_ENABLED = "AirbrushOption/isAirbrushing"; // const QString AIRBRUSH_RATE = "AirbrushOption/rate"; class QLabel; class QModelIndex; class QPushButton; class KisCompositeOpListWidget; class KoID; class PAINTOP_EXPORT KisCompositeOpOption: public KisPaintOpOption { Q_OBJECT public: KisCompositeOpOption(bool createConfigWidget = false); ~KisCompositeOpOption(); - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); private Q_SLOTS: void slotCompositeOpChanged(const QModelIndex& index); void slotEraserToggled(bool toggled); private: void changeCompositeOp(const KoID& compositeOp); private: QLabel* m_label; QPushButton* m_bnEraser; KisCompositeOpListWidget* m_list; QString m_currCompositeOpID; bool m_createConfigWidget; bool m_eraserMode; }; #endif diff --git a/plugins/paintops/libpaintop/kis_current_outline_fetcher.cpp b/plugins/paintops/libpaintop/kis_current_outline_fetcher.cpp index f3293b6c13..fc48ce7b07 100644 --- a/plugins/paintops/libpaintop/kis_current_outline_fetcher.cpp +++ b/plugins/paintops/libpaintop/kis_current_outline_fetcher.cpp @@ -1,160 +1,161 @@ /* * 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_current_outline_fetcher.h" #include "kis_pressure_size_option.h" #include "kis_pressure_rotation_option.h" #include "kis_pressure_mirror_option.h" #include - +#include +#include "kis_paintop_settings.h" #include #define NOISY_UPDATE_SPEED 50 // Time in ms for outline updates to noisy brushes struct KisCurrentOutlineFetcher::Private { Private(Options optionsAvailable) : isDirty(true) { if (optionsAvailable & SIZE_OPTION) { sizeOption.reset(new KisPressureSizeOption()); } if (optionsAvailable & ROTATION_OPTION) { rotationOption.reset(new KisPressureRotationOption()); } if (optionsAvailable & MIRROR_OPTION) { mirrorOption.reset(new KisPressureMirrorOption()); } } QScopedPointer sizeOption; QScopedPointer rotationOption; QScopedPointer mirrorOption; bool isDirty; QElapsedTimer lastUpdateTime; qreal lastRotationApplied; qreal lastSizeApplied; MirrorProperties lastMirrorApplied; }; KisCurrentOutlineFetcher::KisCurrentOutlineFetcher(Options optionsAvailable) : d(new Private(optionsAvailable)) { d->lastUpdateTime.start(); } KisCurrentOutlineFetcher::~KisCurrentOutlineFetcher() { } void KisCurrentOutlineFetcher::setDirty() { d->isDirty = true; } QPainterPath KisCurrentOutlineFetcher::fetchOutline(const KisPaintInformation &info, - const KisPaintOpSettings *settings, + const KisPaintOpSettingsSP settings, const QPainterPath &originalOutline, qreal additionalScale, qreal additionalRotation, bool tilt, qreal tiltcenterx, qreal tiltcentery) const { if (d->isDirty) { if (d->sizeOption) { d->sizeOption->readOptionSetting(settings); d->sizeOption->resetAllSensors(); } if (d->rotationOption) { d->rotationOption->readOptionSetting(settings); d->rotationOption->resetAllSensors(); } if (d->mirrorOption) { d->mirrorOption->readOptionSetting(settings); d->mirrorOption->resetAllSensors(); } d->isDirty = false; } qreal scale = additionalScale; qreal rotation = additionalRotation; MirrorProperties mirrorProperties; bool needsUpdate = false; // Randomized rotation at full speed looks noisy, so slow it down if (d->lastUpdateTime.elapsed() > NOISY_UPDATE_SPEED) { needsUpdate = true; d->lastUpdateTime.restart(); } if (d->sizeOption && tilt == false) { if (!d->sizeOption->isRandom() || needsUpdate) { d->lastSizeApplied = d->sizeOption->apply(info); } scale *= d->lastSizeApplied; } if (d->rotationOption && tilt == false) { if (!d->rotationOption->isRandom() || needsUpdate) { d->lastRotationApplied = d->rotationOption->apply(info); } rotation += d->lastRotationApplied; } else if (d->rotationOption && tilt == true) { rotation += settings->getDouble("runtimeCanvasRotation", 0.0) * M_PI / 180.0; } qreal xFlip = 1.0; qreal yFlip = 1.0; if (d->mirrorOption) { if (!d->mirrorOption->isRandom() || needsUpdate) { d->lastMirrorApplied = d->mirrorOption->apply(info); } if (d->lastMirrorApplied.coordinateSystemFlipped) { rotation = 2 * M_PI - rotation; } if (d->lastMirrorApplied.horizontalMirror) { xFlip = -1.0; } if (d->lastMirrorApplied.verticalMirror) { yFlip = -1.0; } } QTransform rot; rot.rotateRadians(-rotation); QPointF hotSpot = originalOutline.boundingRect().center(); - if (tilt==true) { + if (tilt==true) { hotSpot.setX(tiltcenterx);hotSpot.setY(tiltcentery); } QTransform T1 = QTransform::fromTranslate(-hotSpot.x(), -hotSpot.y()); QTransform T2 = QTransform::fromTranslate(info.pos().x(), info.pos().y()); QTransform S = QTransform::fromScale(xFlip * scale, yFlip * scale); return (T1 * rot * S * T2).map(originalOutline); } diff --git a/plugins/paintops/libpaintop/kis_current_outline_fetcher.h b/plugins/paintops/libpaintop/kis_current_outline_fetcher.h index 810a92720f..052e188f9d 100644 --- a/plugins/paintops/libpaintop/kis_current_outline_fetcher.h +++ b/plugins/paintops/libpaintop/kis_current_outline_fetcher.h @@ -1,65 +1,68 @@ /* * 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. */ #ifndef __KIS_CURRENT_OUTLINE_FETCHER_H #define __KIS_CURRENT_OUTLINE_FETCHER_H #include #include #include #include #include +#include + class KisPaintInformation; -class KisPaintOpSettings; + class PAINTOP_EXPORT KisCurrentOutlineFetcher { public: enum Option { NO_OPTION, SIZE_OPTION, ROTATION_OPTION, MIRROR_OPTION }; Q_DECLARE_FLAGS(Options, Option); public: KisCurrentOutlineFetcher(Options optionsAvailable); ~KisCurrentOutlineFetcher(); void setDirty(); QPainterPath fetchOutline(const KisPaintInformation &info, - const KisPaintOpSettings *settings, + const KisPaintOpSettingsSP settings, const QPainterPath &originalOutline, qreal additionalScale = 1.0, qreal additionalRotation = 0.0, bool tilt = false, qreal tiltcenterx = 1.0, qreal tiltcentery = 1.0) const; private: + Q_DISABLE_COPY(KisCurrentOutlineFetcher); struct Private; const QScopedPointer d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisCurrentOutlineFetcher::Options); #endif /* __KIS_CURRENT_OUTLINE_FETCHER_H */ diff --git a/plugins/paintops/libpaintop/kis_curve_option.cpp b/plugins/paintops/libpaintop/kis_curve_option.cpp index 280cf15f52..8f4db58507 100644 --- a/plugins/paintops/libpaintop/kis_curve_option.cpp +++ b/plugins/paintops/libpaintop/kis_curve_option.cpp @@ -1,389 +1,389 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * 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 "kis_curve_option.h" #include KisCurveOption::KisCurveOption(const QString& name, KisPaintOpOption::PaintopCategory category, bool checked, qreal value, qreal min, qreal max) : m_name(name) , m_category(category) , m_checkable(true) , m_checked(checked) , m_useCurve(true) , m_useSameCurve(true) , m_separateCurveValue(false) { Q_FOREACH (const DynamicSensorType sensorType, KisDynamicSensor::sensorsTypes()) { KisDynamicSensorSP sensor = KisDynamicSensor::type2Sensor(sensorType); sensor->setActive(false); replaceSensor(sensor); } m_sensorMap[PRESSURE]->setActive(true); setValueRange(min, max); setValue(value); } KisCurveOption::~KisCurveOption() { } const QString& KisCurveOption::name() const { return m_name; } KisPaintOpOption::PaintopCategory KisCurveOption::category() const { return m_category; } qreal KisCurveOption::minValue() const { return m_minValue; } qreal KisCurveOption::maxValue() const { return m_maxValue; } qreal KisCurveOption::value() const { return m_value; } void KisCurveOption::resetAllSensors() { Q_FOREACH (KisDynamicSensorSP sensor, m_sensorMap.values()) { if (sensor->isActive()) { sensor->reset(); } } } -void KisCurveOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisCurveOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { if (m_checkable) { setting->setProperty("Pressure" + m_name, isChecked()); } if (activeSensors().size() == 1) { setting->setProperty(m_name + "Sensor", activeSensors().first()->toXML()); } else { QDomDocument doc = QDomDocument("params"); QDomElement root = doc.createElement("params"); doc.appendChild(root); root.setAttribute("id", "sensorslist"); Q_FOREACH (KisDynamicSensorSP sensor, activeSensors()) { QDomElement childelt = doc.createElement("ChildSensor"); sensor->toXML(doc, childelt); root.appendChild(childelt); } setting->setProperty(m_name + "Sensor", doc.toString()); } setting->setProperty(m_name + "UseCurve", m_useCurve); setting->setProperty(m_name + "UseSameCurve", m_useSameCurve); setting->setProperty(m_name + "Value", m_value); } -void KisCurveOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisCurveOption::readOptionSetting(KisPropertiesConfigurationSP setting) { m_curveCache.clear(); readNamedOptionSetting(m_name, setting); } void KisCurveOption::lodLimitations(KisPaintopLodLimitations *l) const { Q_UNUSED(l); } -void KisCurveOption::readNamedOptionSetting(const QString& prefix, const KisPropertiesConfiguration* setting) +void KisCurveOption::readNamedOptionSetting(const QString& prefix, const KisPropertiesConfigurationSP setting) { if (!setting) return; //dbgKrita << "readNamedOptionSetting" << prefix; setting->dump(); if (m_checkable) { setChecked(setting->getBool("Pressure" + prefix, false)); } //dbgKrita << "\tPressure" + prefix << isChecked(); m_sensorMap.clear(); // Replace all sensors with the inactive defaults Q_FOREACH (const DynamicSensorType sensorType, KisDynamicSensor::sensorsTypes()) { replaceSensor(KisDynamicSensor::type2Sensor(sensorType)); } QString sensorDefinition = setting->getString(prefix + "Sensor"); if (!sensorDefinition.contains("sensorslist")) { KisDynamicSensorSP s = KisDynamicSensor::createFromXML(sensorDefinition); if (s) { replaceSensor(s); s->setActive(true); //dbgKrita << "\tsingle sensor" << s::id(s->sensorType()) << s->isActive() << "added"; } } else { QDomDocument doc; doc.setContent(sensorDefinition); QDomElement elt = doc.documentElement(); QDomNode node = elt.firstChild(); while (!node.isNull()) { if (node.isElement()) { QDomElement childelt = node.toElement(); if (childelt.tagName() == "ChildSensor") { KisDynamicSensorSP s = KisDynamicSensor::createFromXML(childelt); if (s) { replaceSensor(s); s->setActive(true); //dbgKrita << "\tchild sensor" << s::id(s->sensorType()) << s->isActive() << "added"; } } } node = node.nextSibling(); } } // Only load the old curve format if the curve wasn't saved by the sensor // This will give every sensor the same curve. //dbgKrita << ">>>>>>>>>>>" << prefix + "Sensor" << setting->getString(prefix + "Sensor"); if (!setting->getString(prefix + "Sensor").contains("curve")) { //dbgKrita << "\told format"; if (setting->getBool("Custom" + prefix, false)) { Q_FOREACH (KisDynamicSensorSP s, m_sensorMap.values()) { s->setCurve(setting->getCubicCurve("Curve" + prefix)); } } } // At least one sensor needs to be active if (activeSensors().size() == 0) { m_sensorMap[PRESSURE]->setActive(true); } m_value = setting->getDouble(m_name + "Value", m_maxValue); //dbgKrita << "\t" + m_name + "Value" << m_value; m_useCurve = setting->getBool(m_name + "UseCurve", true); //dbgKrita << "\t" + m_name + "UseCurve" << m_useSameCurve; m_useSameCurve = setting->getBool(m_name + "UseSameCurve", true); //dbgKrita << "\t" + m_name + "UseSameCurve" << m_useSameCurve; //dbgKrita << "-----------------"; } void KisCurveOption::replaceSensor(KisDynamicSensorSP s) { Q_ASSERT(s); m_sensorMap[s->sensorType()] = s; } KisDynamicSensorSP KisCurveOption::sensor(DynamicSensorType sensorType, bool active) const { if (m_sensorMap.contains(sensorType)) { if (!active) { return m_sensorMap[sensorType]; } else { if (m_sensorMap[sensorType]->isActive()) { return m_sensorMap[sensorType]; } } } return 0; } bool KisCurveOption::isRandom() const { return bool(sensor(FUZZY_PER_DAB, true)) || bool(sensor(FUZZY_PER_STROKE, true)); } bool KisCurveOption::isCurveUsed() const { return m_useCurve; } bool KisCurveOption::isSameCurveUsed() const { return m_useSameCurve; } void KisCurveOption::setSeparateCurveValue(bool separateCurveValue) { m_separateCurveValue = separateCurveValue; } bool KisCurveOption::isCheckable() { return m_checkable; } bool KisCurveOption::isChecked() const { return m_checked; } void KisCurveOption::setChecked(bool checked) { m_checked = checked; } void KisCurveOption::setCurveUsed(bool useCurve) { m_useCurve = useCurve; } void KisCurveOption::setCurve(DynamicSensorType sensorType, bool useSameCurve, const KisCubicCurve &curve) { // No switch in state, don't mess with the cache if (useSameCurve == m_useSameCurve) { if (useSameCurve) { Q_FOREACH (KisDynamicSensorSP s, m_sensorMap.values()) { s->setCurve(curve); } } else { KisDynamicSensorSP s = sensor(sensorType, false); if (s) { s->setCurve(curve); } } } else { // moving from not use same curve to use same curve: backup the custom curves if (!m_useSameCurve && useSameCurve) { // Copy the custom curves to the cache and set the new curve on all sensors, active or not m_curveCache.clear(); Q_FOREACH (KisDynamicSensorSP s, m_sensorMap.values()) { m_curveCache[s->sensorType()] = s->curve(); s->setCurve(curve); } } else { //if (m_useSameCurve && !useSameCurve) // Restore the cached curves KisDynamicSensorSP s = 0; Q_FOREACH (DynamicSensorType sensorType, m_curveCache.keys()) { if (m_sensorMap.contains(sensorType)) { s = m_sensorMap[sensorType]; } else { s = KisDynamicSensor::type2Sensor(sensorType); } s->setCurve(m_curveCache[sensorType]); m_sensorMap[sensorType] = s; } s = 0; // And set the current sensor to the current curve if (!m_sensorMap.contains(sensorType)) { s = KisDynamicSensor::type2Sensor(sensorType); } if (s) { s->setCurve(curve); s->setCurve(m_curveCache[sensorType]); } } m_useSameCurve = useSameCurve; } } void KisCurveOption::setValueRange(qreal min, qreal max) { m_minValue = qMin(min, max); m_maxValue = qMax(min, max); } void KisCurveOption::setValue(qreal value) { m_value = qBound(m_minValue, value, m_maxValue); } KisCurveOption::ValueComponents KisCurveOption::computeValueComponents(const KisPaintInformation& info) const { ValueComponents components; if (m_useCurve) { QVector additiveSensors; Q_FOREACH (KisDynamicSensorSP s, m_sensorMap.values()) { if (s->isActive()) { if (s->isAdditive()) { components.additive += s->parameter(info); components.hasAdditive = true; } else if (s->isAbsoluteRotation()) { components.absoluteOffset = s->parameter(info); components.hasAbsoluteOffset =true; } else { components.scaling *= s->parameter(info); components.hasScaling = true; } } } } if (!m_separateCurveValue) { components.constant = m_value; } components.minSizeLikeValue = m_minValue; components.maxSizeLikeValue = m_maxValue; return components; } qreal KisCurveOption::computeSizeLikeValue(const KisPaintInformation& info) const { const ValueComponents components = computeValueComponents(info); return components.sizeLikeValue(); } qreal KisCurveOption::computeRotationLikeValue(const KisPaintInformation& info, qreal baseValue) const { const ValueComponents components = computeValueComponents(info); return components.rotationLikeValue(baseValue); } QList KisCurveOption::sensors() { //dbgKrita << "ID" << name() << "has" << m_sensorMap.count() << "Sensors of which" << sensorList.count() << "are active."; return m_sensorMap.values(); } QList KisCurveOption::activeSensors() const { QList sensorList; Q_FOREACH (KisDynamicSensorSP sensor, m_sensorMap.values()) { if (sensor->isActive()) { sensorList << sensor; } } //dbgKrita << "ID" << name() << "has" << m_sensorMap.count() << "Sensors of which" << sensorList.count() << "are active."; return sensorList; } diff --git a/plugins/paintops/libpaintop/kis_curve_option.h b/plugins/paintops/libpaintop/kis_curve_option.h index c7b3c89257..4f9bf6149d 100644 --- a/plugins/paintops/libpaintop/kis_curve_option.h +++ b/plugins/paintops/libpaintop/kis_curve_option.h @@ -1,190 +1,190 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * 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_CURVE_OPTION_H #define KIS_CURVE_OPTION_H #include #include #include "kis_paintop_option.h" #include "kis_global.h" #include "kis_paintop_option.h" #include #include "kritapaintop_export.h" #include "kis_dynamic_sensor.h" class KisDynamicSensor; /** * KisCurveOption is the base class for paintop options that are * defined through one or more curves. * * Note: it is NOT a KisPaintOpOption, even though the API is pretty similar! * */ class PAINTOP_EXPORT KisCurveOption { public: KisCurveOption(const QString& name, KisPaintOpOption::PaintopCategory category, bool checked, qreal value = 1.0, qreal min = 0.0, qreal max = 1.0); virtual ~KisCurveOption(); - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(KisPropertiesConfigurationSP setting); virtual void lodLimitations(KisPaintopLodLimitations *l) const; const QString& name() const; KisPaintOpOption::PaintopCategory category() const; qreal minValue() const; qreal maxValue() const; qreal value() const; void resetAllSensors(); KisDynamicSensorSP sensor(DynamicSensorType sensorType, bool active) const; void replaceSensor(KisDynamicSensorSP sensor); QList sensors(); QList activeSensors() const; bool isCheckable(); bool isChecked() const; bool isCurveUsed() const; bool isSameCurveUsed() const; bool isRandom() const; void setSeparateCurveValue(bool separateCurveValue); void setChecked(bool checked); void setCurveUsed(bool useCurve); void setCurve(DynamicSensorType sensorType, bool useSameCurve, const KisCubicCurve &curve); void setValue(qreal value); struct ValueComponents { ValueComponents() : constant(1.0), scaling(1.0), additive(0.0), absoluteOffset(0.0), hasAbsoluteOffset(false), hasScaling(false), hasAdditive(false) { } qreal constant; qreal scaling; qreal additive; qreal absoluteOffset; bool hasAbsoluteOffset; bool hasScaling; bool hasAdditive; qreal minSizeLikeValue; qreal maxSizeLikeValue; qreal rotationLikeValue(qreal baseAngle) const { const qreal offset = hasAbsoluteOffset ? absoluteOffset : baseAngle; const qreal realScalingPart = hasScaling ? KisDynamicSensor::scalingToAdditive(scaling) : 0.0; const qreal realAdditivePart = hasAdditive ? additive : 0; return wrapInRange( 2 * offset + constant * realScalingPart + realAdditivePart, -1.0, 1.0); } qreal sizeLikeValue() const { const qreal offset = hasAbsoluteOffset ? absoluteOffset : 1.0; const qreal realScalingPart = hasScaling ? scaling : 1.0; const qreal realAdditivePart = hasAdditive ? KisDynamicSensor::additiveToScaling(additive) : 1.0; return qBound(minSizeLikeValue, constant * offset * realScalingPart * realAdditivePart, maxSizeLikeValue); } private: static inline qreal wrapInRange(qreal x, qreal min, qreal max) { const qreal range = max - min; x -= min; if (x < 0.0) { x = range + fmod(x, range); } if (x > range) { x = fmod(x, range); } return x + min; } }; /** * Uses the curves set on the sensors to compute a single * double value that can control the parameters of a brush. * * This value is derives from the falues stored in * ValuesComponents opject. */ ValueComponents computeValueComponents(const KisPaintInformation& info) const; qreal computeSizeLikeValue(const KisPaintInformation &info) const; qreal computeRotationLikeValue(const KisPaintInformation& info, qreal baseValue) const; protected: void setValueRange(qreal min, qreal max); /** * Read the option using the prefix in argument */ - void readNamedOptionSetting(const QString& prefix, const KisPropertiesConfiguration* setting); + void readNamedOptionSetting(const QString& prefix, const KisPropertiesConfigurationSP setting); QString m_name; KisPaintOpOption::PaintopCategory m_category; bool m_checkable; bool m_checked; bool m_useCurve; bool m_useSameCurve; bool m_separateCurveValue; QMap m_sensorMap; QMap m_curveCache; private: qreal m_value; qreal m_minValue; qreal m_maxValue; }; #endif diff --git a/plugins/paintops/libpaintop/kis_curve_option_widget.cpp b/plugins/paintops/libpaintop/kis_curve_option_widget.cpp index e67e1e57a4..9490ca4a1b 100644 --- a/plugins/paintops/libpaintop/kis_curve_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_curve_option_widget.cpp @@ -1,188 +1,188 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * Copyright (C) 2009 Sven Langkamp * 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 "kis_curve_option_widget.h" #include "ui_wdgcurveoption.h" #include "widgets/kis_curve_widget.h" #include "kis_dynamic_sensor.h" #include "kis_global.h" #include "kis_curve_option.h" #include "kis_signals_blocker.h" inline void setLabel(QLabel* label, const KisCurveLabel& curve_label) { if (curve_label.icon().isNull()) { label->setText(curve_label.name()); } else { label->setPixmap(QPixmap::fromImage(curve_label.icon())); } } KisCurveOptionWidget::KisCurveOptionWidget(KisCurveOption* curveOption, const QString &minLabel, const QString &maxLabel, bool hideSlider) : KisPaintOpOption(curveOption->category(), curveOption->isChecked()) , m_widget(new QWidget) , m_curveOptionWidget(new Ui_WdgCurveOption()) , m_curveOption(curveOption) { setObjectName("KisCurveOptionWidget"); m_curveOptionWidget->setupUi(m_widget); setConfigurationPage(m_widget); m_curveOptionWidget->sensorSelector->setCurveOption(curveOption); updateSensorCurveLabels(m_curveOptionWidget->sensorSelector->currentHighlighted()); updateCurve(m_curveOptionWidget->sensorSelector->currentHighlighted()); connect(m_curveOptionWidget->curveWidget, SIGNAL(modified()), this, SLOT(transferCurve())); connect(m_curveOptionWidget->sensorSelector, SIGNAL(parametersChanged()), SLOT(emitSettingChanged())); connect(m_curveOptionWidget->sensorSelector, SIGNAL(parametersChanged()), SLOT(updateLabelsOfCurrentSensor())); connect(m_curveOptionWidget->sensorSelector, SIGNAL(highlightedSensorChanged(KisDynamicSensorSP )), SLOT(updateSensorCurveLabels(KisDynamicSensorSP ))); connect(m_curveOptionWidget->sensorSelector, SIGNAL(highlightedSensorChanged(KisDynamicSensorSP )), SLOT(updateCurve(KisDynamicSensorSP ))); connect(m_curveOptionWidget->checkBoxUseSameCurve, SIGNAL(stateChanged(int)), SLOT(transferCurve())); m_curveOptionWidget->label_ymin->setText(minLabel); m_curveOptionWidget->label_ymax->setText(maxLabel); m_curveOptionWidget->slider->setRange(curveOption->minValue(), curveOption->maxValue(), 2); m_curveOptionWidget->slider->setValue(curveOption->value()); if (hideSlider) { m_curveOptionWidget->slider->hide(); m_curveOptionWidget->strengthLabel->hide(); } connect(m_curveOptionWidget->checkBoxUseCurve, SIGNAL(stateChanged(int)) , SLOT(updateValues())); connect(m_curveOptionWidget->slider, SIGNAL(valueChanged(qreal)), SLOT(updateValues())); } KisCurveOptionWidget::~KisCurveOptionWidget() { delete m_curveOption; delete m_curveOptionWidget; } -void KisCurveOptionWidget::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisCurveOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP setting) const { m_curveOption->writeOptionSetting(setting); } -void KisCurveOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisCurveOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { setting->dump(); m_curveOption->readOptionSetting(setting); m_curveOptionWidget->checkBoxUseCurve->setChecked(m_curveOption->isCurveUsed()); m_curveOptionWidget->slider->setValue(m_curveOption->value()); m_curveOptionWidget->checkBoxUseSameCurve->setChecked(m_curveOption->isSameCurveUsed()); disableWidgets(!m_curveOption->isCurveUsed()); m_curveOptionWidget->sensorSelector->reload(); m_curveOptionWidget->sensorSelector->setCurrent(m_curveOption->activeSensors().first()); updateSensorCurveLabels(m_curveOptionWidget->sensorSelector->currentHighlighted()); updateCurve(m_curveOptionWidget->sensorSelector->currentHighlighted()); } void KisCurveOptionWidget::lodLimitations(KisPaintopLodLimitations *l) const { m_curveOption->lodLimitations(l); } bool KisCurveOptionWidget::isCheckable() const { return m_curveOption->isCheckable(); } bool KisCurveOptionWidget::isChecked() const { return m_curveOption->isChecked(); } void KisCurveOptionWidget::setChecked(bool checked) { m_curveOption->setChecked(checked); } KisCurveOption* KisCurveOptionWidget::curveOption() { return m_curveOption; } QWidget* KisCurveOptionWidget::curveWidget() { return m_widget; } void KisCurveOptionWidget::transferCurve() { m_curveOptionWidget->sensorSelector->setCurrentCurve(m_curveOptionWidget->curveWidget->curve(), m_curveOptionWidget->checkBoxUseSameCurve->isChecked()); emitSettingChanged(); } void KisCurveOptionWidget::updateSensorCurveLabels(KisDynamicSensorSP sensor) { if (sensor) { m_curveOptionWidget->label_xmin->setText(KisDynamicSensor::minimumLabel(sensor->sensorType())); m_curveOptionWidget->label_xmax->setText(KisDynamicSensor::maximumLabel(sensor->sensorType(), sensor->length())); } } void KisCurveOptionWidget::updateCurve(KisDynamicSensorSP sensor) { if (sensor) { bool blockSignal = m_curveOptionWidget->curveWidget->blockSignals(true); m_curveOptionWidget->curveWidget->setCurve(sensor->curve()); m_curveOptionWidget->curveWidget->blockSignals(blockSignal); } } void KisCurveOptionWidget::updateLabelsOfCurrentSensor() { updateSensorCurveLabels(m_curveOptionWidget->sensorSelector->currentHighlighted()); updateCurve(m_curveOptionWidget->sensorSelector->currentHighlighted()); } void KisCurveOptionWidget::updateValues() { m_curveOption->setValue(m_curveOptionWidget->slider->value()); m_curveOption->setCurveUsed(m_curveOptionWidget->checkBoxUseCurve->isChecked()); disableWidgets(!m_curveOptionWidget->checkBoxUseCurve->isChecked()); emitSettingChanged(); } void KisCurveOptionWidget::disableWidgets(bool disable) { m_curveOptionWidget->checkBoxUseSameCurve->setDisabled(disable); m_curveOptionWidget->curveWidget->setDisabled(disable); m_curveOptionWidget->sensorSelector->setDisabled(disable); m_curveOptionWidget->label_xmax->setDisabled(disable); m_curveOptionWidget->label_xmin->setDisabled(disable); m_curveOptionWidget->label_ymax->setDisabled(disable); m_curveOptionWidget->label_ymin->setDisabled(disable); } diff --git a/plugins/paintops/libpaintop/kis_curve_option_widget.h b/plugins/paintops/libpaintop/kis_curve_option_widget.h index 4cfac86f2e..ef575d5027 100644 --- a/plugins/paintops/libpaintop/kis_curve_option_widget.h +++ b/plugins/paintops/libpaintop/kis_curve_option_widget.h @@ -1,70 +1,70 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * Copyright (C) 2009 Sven Langkamp * 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_CURVE_OPTION_WIDGET_H #define KIS_CURVE_OPTION_WIDGET_H #include class Ui_WdgCurveOption; class KisCurveOption; #include /** * XXX; Add a reset button! */ class PAINTOP_EXPORT KisCurveOptionWidget : public KisPaintOpOption { Q_OBJECT public: KisCurveOptionWidget(KisCurveOption* curveOption, const QString &minLabel, const QString &maxLabel, bool hideSlider = false); ~KisCurveOptionWidget(); - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); virtual void lodLimitations(KisPaintopLodLimitations *l) const; bool isCheckable() const; bool isChecked() const; void setChecked(bool checked); protected: KisCurveOption* curveOption(); QWidget* curveWidget(); private Q_SLOTS: void transferCurve(); void updateSensorCurveLabels(KisDynamicSensorSP sensor); void updateCurve(KisDynamicSensorSP sensor); void updateValues(); void updateLabelsOfCurrentSensor(); void disableWidgets(bool disable); private: QWidget* m_widget; Ui_WdgCurveOption* m_curveOptionWidget; KisCurveOption* m_curveOption; }; #endif // KIS_CURVE_OPTION_WIDGET_H diff --git a/plugins/paintops/libpaintop/kis_dynamic_sensor.h b/plugins/paintops/libpaintop/kis_dynamic_sensor.h index 586e9f5a6b..4773546040 100644 --- a/plugins/paintops/libpaintop/kis_dynamic_sensor.h +++ b/plugins/paintops/libpaintop/kis_dynamic_sensor.h @@ -1,217 +1,217 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2011 Lukáš Tvrdý * * 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_DYNAMIC_SENSOR_H_ #define _KIS_DYNAMIC_SENSOR_H_ #include #include #include #include #include "kis_serializable_configuration.h" #include "kis_curve_label.h" #include #include #include class QWidget; class KisPaintInformation; const KoID FuzzyPerDabId("fuzzy", ki18n("Fuzzy Dab")); ///< generate a random number const KoID FuzzyPerStrokeId("fuzzystroke", ki18n("Fuzzy Stroke")); ///< generate a random number const KoID SpeedId("speed", ki18n("Speed")); ///< generate a number depending on the speed of the cursor const KoID FadeId("fade", ki18n("Fade")); ///< generate a number that increase every time you call it (e.g. per dab) const KoID DistanceId("distance", ki18n("Distance")); ///< generate a number that increase with distance const KoID TimeId("time", ki18n("Time")); ///< generate a number that increase with time const KoID DrawingAngleId("drawingangle", ki18n("Drawing angle")); ///< number depending on the angle const KoID RotationId("rotation", ki18n("Rotation")); ///< rotation coming from the device const KoID PressureId("pressure", ki18n("Pressure")); ///< number depending on the pressure const KoID PressureInId("pressurein", ki18n("PressureIn")); ///< number depending on the pressure const KoID XTiltId("xtilt", ki18n("X-Tilt")); ///< number depending on X-tilt const KoID YTiltId("ytilt", ki18n("Y-Tilt")); ///< number depending on Y-tilt /** * "TiltDirection" and "TiltElevation" parameters are written to * preset files as "ascension" and "declination" to keep backward * compatibility with older presets from the days when they were called * differently. */ const KoID TiltDirectionId("ascension", ki18n("Tilt direction")); /// < number depending on the X and Y tilt, tilt direction is 0 when stylus nib points to you and changes clockwise from -180 to +180. const KoID TiltElevationId("declination", ki18n("Tilt elevation")); /// < tilt elevation is 90 when stylus is perpendicular to tablet and 0 when it's parallel to tablet const KoID PerspectiveId("perspective", ki18n("Perspective")); ///< number depending on the distance on the perspective grid const KoID TangentialPressureId("tangentialpressure", ki18n("Tangential pressure")); ///< the wheel on an airbrush device const KoID SensorsListId("sensorslist", "SHOULD NOT APPEAR IN THE UI !"); ///< this a non user-visible sensor that can store a list of other sensors, and multiply their output class KisDynamicSensor; typedef KisSharedPtr KisDynamicSensorSP; enum DynamicSensorType { FUZZY_PER_DAB, FUZZY_PER_STROKE, SPEED, FADE, DISTANCE, TIME, ANGLE, ROTATION, PRESSURE, XTILT, YTILT, TILT_DIRECTION, TILT_ELEVATATION, PERSPECTIVE, TANGENTIAL_PRESSURE, SENSORS_LIST, PRESSURE_IN, UNKNOWN = 255 }; /** * Sensors are used to extract from KisPaintInformation a single * double value which can be used to control the parameters of * a brush. */ -class PAINTOP_EXPORT KisDynamicSensor : public KisSerializableConfiguration, public KisShared +class PAINTOP_EXPORT KisDynamicSensor : public KisSerializableConfiguration { public: enum ParameterSign { NegativeParameter = -1, UnSignedParameter = 0, PositiveParameter = 1 }; protected: KisDynamicSensor(DynamicSensorType type); public: virtual ~KisDynamicSensor(); /** * @return the value of this sensor for the given KisPaintInformation */ qreal parameter(const KisPaintInformation& info); /** * This function is call before beginning a stroke to reset the sensor. * Default implementation does nothing. */ virtual void reset(); /** * @param selector is a \ref QWidget that countains a signal called "parametersChanged()" */ virtual QWidget* createConfigurationWidget(QWidget* parent, QWidget* selector); /** * Creates a sensor from its identifiant. */ static KisDynamicSensorSP id2Sensor(const KoID& id); static KisDynamicSensorSP id2Sensor(const QString& s) { return id2Sensor(KoID(s)); } static DynamicSensorType id2Type(const KoID& id); static DynamicSensorType id2Type(const QString& s) { return id2Type(KoID(s)); } /** * type2Sensor creates a new sensor for the give type */ static KisDynamicSensorSP type2Sensor(DynamicSensorType sensorType); static QString minimumLabel(DynamicSensorType sensorType); static QString maximumLabel(DynamicSensorType sensorType, int max = -1); static KisDynamicSensorSP createFromXML(const QString&); static KisDynamicSensorSP createFromXML(const QDomElement&); /** * @return the list of sensors */ static QList sensorsIds(); static QList sensorsTypes(); /** * @return the identifiant of this sensor */ static QString id(DynamicSensorType sensorType); using KisSerializableConfiguration::fromXML; using KisSerializableConfiguration::toXML; virtual void toXML(QDomDocument&, QDomElement&) const; virtual void fromXML(const QDomElement&); void setCurve(const KisCubicCurve& curve); const KisCubicCurve& curve() const; void removeCurve(); bool hasCustomCurve() const; void setActive(bool active); bool isActive() const; virtual bool dependsOnCanvasRotation() const; virtual bool isAdditive() const; virtual bool isAbsoluteRotation() const; inline DynamicSensorType sensorType() const { return m_type; } /** * @return the currently set length or -1 if not relevant */ int length() { return m_length; } public: static inline qreal scalingToAdditive(qreal x) { return -1.0 + 2.0 * x; } static inline qreal additiveToScaling(qreal x) { return 0.5 * (1.0 + x); } protected: virtual qreal value(const KisPaintInformation& info) = 0; int m_length; private: Q_DISABLE_COPY(KisDynamicSensor) DynamicSensorType m_type; bool m_customCurve; KisCubicCurve m_curve; bool m_active; }; #endif diff --git a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp index da3c0b3f0b..d92c20f2b5 100644 --- a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp +++ b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp @@ -1,130 +1,130 @@ /* * 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_embedded_pattern_manager.h" #include #include #include #include #include struct KisEmbeddedPatternManager::Private { - static KoPattern* tryLoadEmbeddedPattern(const KisPropertiesConfiguration* setting) { + static KoPattern* tryLoadEmbeddedPattern(const KisPropertiesConfigurationSP setting) { KoPattern *pattern = 0; QByteArray ba = QByteArray::fromBase64(setting->getString("Texture/Pattern/Pattern").toLatin1()); QImage img; img.loadFromData(ba, "PNG"); QString name = setting->getString("Texture/Pattern/Name"); QString filename = setting->getString("Texture/Pattern/PatternFileName"); if (name.isEmpty() || name != QFileInfo(name).fileName()) { QFileInfo info(filename); name = info.baseName(); } if (!img.isNull()) { pattern = new KoPattern(img, name, KoResourceServerProvider::instance()->patternServer()->saveLocation()); } return pattern; } static KoPattern* tryFetchPatternByMd5(const QByteArray &md5) { KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); return server->resourceByMD5(md5); } static KoPattern* tryFetchPatternByName(const QString &name) { KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); return server->resourceByName(name); } static KoPattern* tryFetchPatternByFileName(const QString &fileName) { KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); return server->resourceByFilename(fileName); } }; -void KisEmbeddedPatternManager::saveEmbeddedPattern(KisPropertiesConfiguration* setting, const KoPattern *pattern) +void KisEmbeddedPatternManager::saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPattern *pattern) { QByteArray patternMD5 = pattern->md5(); /** * The process of saving a pattern may be quite expensive, so * we won't rewrite the pattern if has the same md5-sum and at * least some data is present */ QByteArray existingMD5 = QByteArray::fromBase64(setting->getString("Texture/Pattern/PatternMD5").toLatin1()); QString existingPatternBase64 = setting->getString("Texture/Pattern/PatternMD5").toLatin1(); if (patternMD5 == existingMD5 && !existingPatternBase64.isEmpty()) { return; } setting->setProperty("Texture/Pattern/PatternMD5", patternMD5.toBase64()); setting->setProperty("Texture/Pattern/PatternFileName", pattern->filename()); setting->setProperty("Texture/Pattern/Name", pattern->name()); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); pattern->pattern().save(&buffer, "PNG"); setting->setProperty("Texture/Pattern/Pattern", ba.toBase64()); } -KoPattern* KisEmbeddedPatternManager::loadEmbeddedPattern(const KisPropertiesConfiguration* setting) +KoPattern* KisEmbeddedPatternManager::loadEmbeddedPattern(const KisPropertiesConfigurationSP setting) { KoPattern *pattern = 0; QByteArray md5 = QByteArray::fromBase64(setting->getString("Texture/Pattern/PatternMD5").toLatin1()); pattern = Private::tryFetchPatternByMd5(md5); if (pattern) return pattern; QString name = setting->getString("Texture/Pattern/Name"); pattern = Private::tryFetchPatternByName(name); if (pattern) return pattern; QString fileName = setting->getString("Texture/Pattern/PatternFileName"); pattern = Private::tryFetchPatternByFileName(fileName); if (pattern) return pattern; pattern = Private::tryLoadEmbeddedPattern(setting); if (pattern) { KoPattern *existingPattern = Private::tryFetchPatternByMd5(pattern->md5()); if (existingPattern) { delete pattern; pattern = existingPattern; } else { KoResourceServerProvider::instance()->patternServer()->addResource(pattern, false); } } return pattern; } diff --git a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h index afc21e67f3..1908de5bb4 100644 --- a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h +++ b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h @@ -1,39 +1,38 @@ /* * 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. */ #ifndef __KIS_EMBEDDED_PATTERN_MANAGER_H #define __KIS_EMBEDDED_PATTERN_MANAGER_H #include +#include class KoPattern; class KoAbstractGradient; -class KisPropertiesConfiguration; - class PAINTOP_EXPORT KisEmbeddedPatternManager { public: - static void saveEmbeddedPattern(KisPropertiesConfiguration* setting, const KoPattern *pattern); - static KoPattern* loadEmbeddedPattern(const KisPropertiesConfiguration* setting); + static void saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPattern *pattern); + static KoPattern* loadEmbeddedPattern(const KisPropertiesConfigurationSP setting); private: struct Private; }; #endif /* __KIS_EMBEDDED_PATTERN_MANAGER_H */ diff --git a/plugins/paintops/libpaintop/kis_filter_option.cpp b/plugins/paintops/libpaintop/kis_filter_option.cpp index 0a3c5c6d27..7409fd0ca8 100644 --- a/plugins/paintops/libpaintop/kis_filter_option.cpp +++ b/plugins/paintops/libpaintop/kis_filter_option.cpp @@ -1,207 +1,207 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_filter_option.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_wdgfilteroption.h" #include class KisFilterOptionWidget : public QWidget, public Ui::FilterOpOptions { public: KisFilterOptionWidget(QWidget* parent = 0) : QWidget(parent) { setupUi(this); } }; KisFilterOption::KisFilterOption() : KisPaintOpOption(KisPaintOpOption::FILTER, true) { setObjectName("KisFilterOption"); m_checkable = false; m_currentFilterConfigWidget = 0; m_options = new KisFilterOptionWidget; m_options->hide(); setConfigurationPage(m_options); m_layout = new QGridLayout(m_options->grpFilterOptions); // Check which filters support painting QList l = KisFilterRegistry::instance()->keys(); QList l2; QList::iterator it; for (it = l.begin(); it != l.end(); ++it) { KisFilterSP f = KisFilterRegistry::instance()->value((*it)); if (f->supportsPainting()) { l2.push_back(KoID(*it, f->name())); } } m_options->filtersList->setIDList(l2); connect(m_options->filtersList, SIGNAL(activated(const KoID &)), SLOT(setCurrentFilter(const KoID &))); if (!l2.empty()) { setCurrentFilter(l2.first()); } connect(m_options->checkBoxSmudgeMode, SIGNAL(stateChanged(int)), this, SLOT(emitSettingChanged())); } const KisFilterSP KisFilterOption::filter() const { return m_currentFilter; } -KisFilterConfiguration* KisFilterOption::filterConfig() const +KisFilterConfigurationSP KisFilterOption::filterConfig() const { if (!m_currentFilterConfigWidget) return 0; - return static_cast(m_currentFilterConfigWidget->configuration()); + return static_cast(m_currentFilterConfigWidget->configuration().data()); } bool KisFilterOption::smudgeMode() const { return m_options->checkBoxSmudgeMode->isChecked(); } void KisFilterOption::setNode(KisNodeWSP node) { if (node && node->paintDevice()) { m_paintDevice = node->paintDevice(); // The "not m_currentFilterConfigWidget" is a corner case // which happens because the first configuration settings is // created before any layer is selected in the view if (!m_currentFilterConfigWidget || (m_currentFilterConfigWidget - && static_cast(m_currentFilterConfigWidget->configuration())->isCompatible(m_paintDevice) + && static_cast(m_currentFilterConfigWidget->configuration().data())->isCompatible(m_paintDevice) ) ) { if (m_currentFilter) { - KisPropertiesConfiguration* configuration = 0; - if (m_currentFilterConfigWidget) + KisPropertiesConfigurationSP configuration = 0; + if (m_currentFilterConfigWidget) { configuration = m_currentFilterConfigWidget->configuration(); - + } setCurrentFilter(KoID(m_currentFilter->id())); - if (configuration) + if (configuration) { m_currentFilterConfigWidget->setConfiguration(configuration); - delete configuration; + } } } } else { m_paintDevice = 0; } } void KisFilterOption::setImage(KisImageWSP image) { m_image = image; if (!m_currentFilterConfigWidget) { updateFilterConfigWidget(); } } void KisFilterOption::setCurrentFilter(const KoID& id) { m_currentFilter = KisFilterRegistry::instance()->get(id.id()); m_options->filtersList->setCurrent(id); updateFilterConfigWidget(); emitSettingChanged(); } void KisFilterOption::updateFilterConfigWidget() { if (m_currentFilterConfigWidget) { m_currentFilterConfigWidget->hide(); m_layout->removeWidget(m_currentFilterConfigWidget); m_layout->invalidate(); delete m_currentFilterConfigWidget; } m_currentFilterConfigWidget = 0; if (m_currentFilter && m_image && m_paintDevice) { m_currentFilterConfigWidget = m_currentFilter->createConfigurationWidget(m_options->grpFilterOptions, m_paintDevice); if (m_currentFilterConfigWidget) { m_layout->addWidget(m_currentFilterConfigWidget); m_options->grpFilterOptions->updateGeometry(); m_currentFilterConfigWidget->show(); connect(m_currentFilterConfigWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(emitSettingChanged())); } } m_layout->update(); } -void KisFilterOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisFilterOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { if (!m_currentFilter) return; setting->setProperty(FILTER_ID, m_currentFilter->id()); setting->setProperty(FILTER_SMUDGE_MODE, smudgeMode()); if (filterConfig()) { setting->setProperty(FILTER_CONFIGURATION, filterConfig()->toXML()); } } -void KisFilterOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisFilterOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KoID id(setting->getString(FILTER_ID), ""); setCurrentFilter(id); m_options->checkBoxSmudgeMode->setChecked(setting->getBool(FILTER_SMUDGE_MODE)); - KisFilterConfiguration* configuration = filterConfig(); + KisFilterConfigurationSP configuration = filterConfig(); if (configuration) { configuration->fromXML(setting->getString(FILTER_CONFIGURATION)); m_currentFilterConfigWidget->setConfiguration(configuration); } } void KisFilterOption::lodLimitations(KisPaintopLodLimitations *l) const { - KisFilterConfiguration *config = filterConfig(); + KisFilterConfigurationSP config = filterConfig(); if (m_currentFilter && config) { QRect testRect(0,0,100,100); if (m_currentFilter->neededRect(testRect, config, 0) != testRect || m_currentFilter->changedRect(testRect, config, 0) != testRect) { l->blockers << KoID("filter-nonlinear", i18nc("PaintOp instant preview limitation", "\"%1\" does not support scaled preview (non-linear filter)", config->name())); } } } #include "moc_kis_filter_option.cpp" diff --git a/plugins/paintops/libpaintop/kis_filter_option.h b/plugins/paintops/libpaintop/kis_filter_option.h index 0c7452a087..c51aa3e84e 100644 --- a/plugins/paintops/libpaintop/kis_filter_option.h +++ b/plugins/paintops/libpaintop/kis_filter_option.h @@ -1,96 +1,96 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_FILTER_OPTION_H #define KIS_FILTER_OPTION_H #include "kis_paintop_option.h" #include #include class QGridLayout; class KoID; class KisConfigWidget; class KisFilterConfiguration; class KisFilterOptionWidget; class KisPaintopLodLimitations; const QString FILTER_ID = "Filter/id"; const QString FILTER_SMUDGE_MODE = "Filter/smudgeMode"; const QString FILTER_CONFIGURATION = "Filter/configuration"; /** * The filter option allows the user to select a particular filter * that can be applied by the paintop to the brush footprint or the * original paint device data. */ class PAINTOP_EXPORT KisFilterOption : public KisPaintOpOption { Q_OBJECT public: KisFilterOption(); /** * Return the currently selected filter */ const KisFilterSP filter() const; /** * Return the currently selected filter configuration */ - KisFilterConfiguration* filterConfig() const; + KisFilterConfigurationSP filterConfig() const; bool smudgeMode() const; /** * XXX */ void setNode(KisNodeWSP node); /** * XXX */ void setImage(KisImageWSP image); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private Q_SLOTS: void setCurrentFilter(const KoID&); void updateFilterConfigWidget(); private: QGridLayout* m_layout; KisFilterOptionWidget* m_options; KisFilterSP m_currentFilter; KisConfigWidget* m_currentFilterConfigWidget; KisPaintDeviceSP m_paintDevice; KisImageSP m_image; }; #endif diff --git a/plugins/paintops/libpaintop/kis_outline_generation_policy.h b/plugins/paintops/libpaintop/kis_outline_generation_policy.h index c0590cdc68..4f910ef88a 100644 --- a/plugins/paintops/libpaintop/kis_outline_generation_policy.h +++ b/plugins/paintops/libpaintop/kis_outline_generation_policy.h @@ -1,54 +1,63 @@ /* * 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. */ #ifndef __KIS_OUTLINE_GENERATION_POLICY_H #define __KIS_OUTLINE_GENERATION_POLICY_H #include /** * This is a policy class that adds an ability to have a Outline Generator * to a KisPaintOpSettings-based class. * * \see Andrei Alexandrescu "Modern C++ Design: Generic Programming and Design Patterns Applied" */ template class KisOutlineGenerationPolicy : public ParentClass { public: KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::Options options) - : m_outlineFetcher(options) { + : m_outlineFetcher(options) + { } - virtual ~KisOutlineGenerationPolicy() { + virtual ~KisOutlineGenerationPolicy() + { } - const KisCurrentOutlineFetcher* outlineFetcher() const { + KisOutlineGenerationPolicy(const KisOutlineGenerationPolicy &rhs) + : ParentClass(rhs) + { + } + + const KisCurrentOutlineFetcher *outlineFetcher() const + { return &m_outlineFetcher; } - void onPropertyChanged() { + void onPropertyChanged() + { m_outlineFetcher.setDirty(); ParentClass::onPropertyChanged(); } private: KisCurrentOutlineFetcher m_outlineFetcher; }; #endif /* __KIS_OUTLINE_GENERATION_POLICY_H */ diff --git a/plugins/paintops/libpaintop/kis_paint_action_type_option.cpp b/plugins/paintops/libpaintop/kis_paint_action_type_option.cpp index cff78d3d4a..e834438f00 100644 --- a/plugins/paintops/libpaintop/kis_paint_action_type_option.cpp +++ b/plugins/paintops/libpaintop/kis_paint_action_type_option.cpp @@ -1,80 +1,80 @@ /* * 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 "kis_paint_action_type_option.h" #include #include #include #include "ui_wdgincremental.h" class KisPaintActionWidget: public QWidget, public Ui::WdgIncremental { public: KisPaintActionWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisPaintActionTypeOption::KisPaintActionTypeOption() : KisPaintOpOption(KisPaintOpOption::COLOR, false) { setObjectName("KisPaintActionTypeOption"); m_checkable = false; m_optionWidget = new KisPaintActionWidget(); connect(m_optionWidget->radioBuildup, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->radioWash, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); m_optionWidget->hide(); setConfigurationPage(m_optionWidget); } KisPaintActionTypeOption::~KisPaintActionTypeOption() { } enumPaintActionType KisPaintActionTypeOption::paintActionType() const { if (m_optionWidget->radioBuildup->isChecked()) { return BUILDUP; } else if (m_optionWidget->radioWash->isChecked()) { return WASH; } else { return WASH; } } -void KisPaintActionTypeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPaintActionTypeOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty("PaintOpAction", paintActionType()); } -void KisPaintActionTypeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPaintActionTypeOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { enumPaintActionType type = (enumPaintActionType)setting->getInt("PaintOpAction", WASH); m_optionWidget->radioBuildup->setChecked(type == BUILDUP); m_optionWidget->radioWash->setChecked(type == WASH); } diff --git a/plugins/paintops/libpaintop/kis_paint_action_type_option.h b/plugins/paintops/libpaintop/kis_paint_action_type_option.h index ba69399cdb..c32e86409e 100644 --- a/plugins/paintops/libpaintop/kis_paint_action_type_option.h +++ b/plugins/paintops/libpaintop/kis_paint_action_type_option.h @@ -1,58 +1,58 @@ /* * 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. */ #ifndef KIS_PAINT_ACTION_TYPE_OPTION_H #define KIS_PAINT_ACTION_TYPE_OPTION_H #include #include class KisPaintActionWidget; enum enumPaintActionType { UNSUPPORTED, BUILDUP, WASH, FRINGED // not used yet }; /** * Allows the user to choose between two types of paint action: * * incremental (going over the same spot in one stroke makes it darker) * * indirect (like photoshop and gimp) */ class PAINTOP_EXPORT KisPaintActionTypeOption : public KisPaintOpOption { public: KisPaintActionTypeOption(); ~KisPaintActionTypeOption(); enumPaintActionType paintActionType() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisPaintActionWidget * m_optionWidget; }; #endif diff --git a/plugins/paintops/libpaintop/kis_precision_option.cpp b/plugins/paintops/libpaintop/kis_precision_option.cpp index 58acf810ef..425d5733f3 100644 --- a/plugins/paintops/libpaintop/kis_precision_option.cpp +++ b/plugins/paintops/libpaintop/kis_precision_option.cpp @@ -1,101 +1,101 @@ /* * Copyright (c) 2012 Dmitry Kazakov * 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_precision_option.h" #include "kis_properties_configuration.h" -void KisPrecisionOption::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisPrecisionOption::writeOptionSetting(KisPropertiesConfigurationSP settings) const { settings->setProperty(PRECISION_LEVEL, m_precisionLevel); settings->setProperty(AUTO_PRECISION_ENABLED,m_autoPrecisionEnabled); settings->setProperty(STARTING_SIZE,m_sizeToStartFrom); settings->setProperty(DELTA_VALUE,m_deltaValue); } -void KisPrecisionOption::readOptionSetting(const KisPropertiesConfiguration* settings) +void KisPrecisionOption::readOptionSetting(const KisPropertiesConfigurationSP settings) { m_precisionLevel = settings->getInt(PRECISION_LEVEL, 5); m_autoPrecisionEnabled = settings->getBool(AUTO_PRECISION_ENABLED,false); m_deltaValue = settings->getDouble(DELTA_VALUE,15.00); m_sizeToStartFrom = settings ->getDouble(STARTING_SIZE,0); } int KisPrecisionOption::precisionLevel() const { return m_precisionLevel; } void KisPrecisionOption::setPrecisionLevel(int precisionLevel) { m_precisionLevel = precisionLevel; } void KisPrecisionOption::setAutoPrecisionEnabled(int value) { m_autoPrecisionEnabled = value; } void KisPrecisionOption::setDeltaValue(double value) { m_deltaValue = value; } void KisPrecisionOption::setSizeToStartFrom(double value) { m_sizeToStartFrom = value; } bool KisPrecisionOption::autoPrecisionEnabled() { return m_autoPrecisionEnabled; } double KisPrecisionOption::deltaValue() { return m_deltaValue; } double KisPrecisionOption::sizeToStartFrom() { return m_sizeToStartFrom; } void KisPrecisionOption::setAutoPrecision(double brushSize) { double deltaValue = this->deltaValue(); double sizeToStartFrom = this ->sizeToStartFrom(); if (brushSize <= sizeToStartFrom + deltaValue) { this->setPrecisionLevel(5); } else if (brushSize > sizeToStartFrom + deltaValue && brushSize <= sizeToStartFrom + deltaValue*3) { this->setPrecisionLevel(4); } else if (brushSize > sizeToStartFrom + deltaValue*2 && brushSize <= sizeToStartFrom + deltaValue*4) { this->setPrecisionLevel(3); } else if (brushSize > sizeToStartFrom + deltaValue*3 && brushSize <= sizeToStartFrom + deltaValue*5) { this->setPrecisionLevel(2); } else if (brushSize > sizeToStartFrom + deltaValue*4) { this->setPrecisionLevel(1); } } diff --git a/plugins/paintops/libpaintop/kis_precision_option.h b/plugins/paintops/libpaintop/kis_precision_option.h index 840fb881fb..f7089c3a96 100644 --- a/plugins/paintops/libpaintop/kis_precision_option.h +++ b/plugins/paintops/libpaintop/kis_precision_option.h @@ -1,56 +1,56 @@ /* * Copyright (c) 2012 Dmitry Kazakov * 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. */ #ifndef __KIS_PRECISION_OPTION_H #define __KIS_PRECISION_OPTION_H #include #include -class KisPropertiesConfiguration; +#include const QString PRECISION_LEVEL = "KisPrecisionOption/precisionLevel"; const QString AUTO_PRECISION_ENABLED = "KisPrecisionOption/AutoPrecisionEnabled"; const QString STARTING_SIZE = "KisPrecisionOption/SizeToStartFrom"; const QString DELTA_VALUE = "KisPrecisionOption/DeltaValue"; class PAINTOP_EXPORT KisPrecisionOption { public: - void writeOptionSetting(KisPropertiesConfiguration* settings) const; - void readOptionSetting(const KisPropertiesConfiguration* settings); + void writeOptionSetting(KisPropertiesConfigurationSP settings) const; + void readOptionSetting(const KisPropertiesConfigurationSP settings); int precisionLevel() const; void setPrecisionLevel(int precisionLevel); void setAutoPrecisionEnabled(int); void setDeltaValue(double); void setSizeToStartFrom(double); bool autoPrecisionEnabled(); double deltaValue(); double sizeToStartFrom(); void setAutoPrecision(double brushSize); private: int m_precisionLevel; bool m_autoPrecisionEnabled; double m_sizeToStartFrom; double m_deltaValue; }; #endif /* __KIS_PRECISION_OPTION_H */ diff --git a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.cpp b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.cpp index 660e050077..c05e72927e 100644 --- a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.cpp @@ -1,91 +1,91 @@ /* * 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 "kis_pressure_flow_opacity_option.h" #include "kis_paint_action_type_option.h" #include #include #include #include #include #include KisFlowOpacityOption::KisFlowOpacityOption(KisNodeSP currentNode) : KisCurveOption("Opacity", KisPaintOpOption::GENERAL, true, 1.0, 0.0, 1.0) , m_flow(1.0) { setCurveUsed(true); setSeparateCurveValue(true); m_checkable = false; m_nodeHasIndirectPaintingSupport = currentNode && dynamic_cast(currentNode.data()); } -void KisFlowOpacityOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisFlowOpacityOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty("FlowValue", m_flow); } -void KisFlowOpacityOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisFlowOpacityOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); setFlow(setting->getDouble("FlowValue", 1.0)); m_paintActionType = setting->getInt("PaintOpAction", BUILDUP); } qreal KisFlowOpacityOption::getFlow() const { return m_flow; } qreal KisFlowOpacityOption::getStaticOpacity() const { return value(); } qreal KisFlowOpacityOption::getDynamicOpacity(const KisPaintInformation& info) const { return computeSizeLikeValue(info); } void KisFlowOpacityOption::setFlow(qreal flow) { m_flow = qBound(qreal(0), flow, qreal(1)); } void KisFlowOpacityOption::setOpacity(qreal opacity) { setValue(opacity); } void KisFlowOpacityOption::apply(KisPainter* painter, const KisPaintInformation& info) { if (m_paintActionType == WASH && m_nodeHasIndirectPaintingSupport) painter->setOpacityUpdateAverage(quint8(getDynamicOpacity(info) * 255.0)); else painter->setOpacityUpdateAverage(quint8(getStaticOpacity() * getDynamicOpacity(info) * 255.0)); painter->setFlow(quint8(getFlow() * 255.0)); } diff --git a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.h b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.h index aa2a000baa..d7cb7d7486 100644 --- a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option.h @@ -1,54 +1,54 @@ /* * 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_PRESSURE_FLOW_OPACITY_OPTION_H #define KIS_PRESSURE_FLOW_OPACITY_OPTION_H #include "kis_curve_option.h" #include #include #include class KisPaintInformation; class KisPainter; class PAINTOP_EXPORT KisFlowOpacityOption: public KisCurveOption { public: KisFlowOpacityOption(KisNodeSP currentNode); virtual ~KisFlowOpacityOption() { } - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); void setFlow(qreal flow); void setOpacity(qreal opacity); void apply(KisPainter* painter, const KisPaintInformation& info); qreal getFlow() const; qreal getStaticOpacity() const; qreal getDynamicOpacity(const KisPaintInformation& info) const; protected: qreal m_flow; int m_paintActionType; bool m_nodeHasIndirectPaintingSupport; }; #endif //KIS_PRESSURE_FLOW_OPACITY_OPTION_H diff --git a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.cpp b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.cpp index 70e39dbc06..0060f2c294 100644 --- a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.cpp @@ -1,72 +1,72 @@ /* * 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 #include #include #include #include #include #include #include #include "kis_pressure_flow_opacity_option_widget.h" #include "kis_curve_option_widget.h" #include "kis_node.h" #include #include "ui_wdgflowopacityoption.h" KisFlowOpacityOptionWidget::KisFlowOpacityOptionWidget(): KisCurveOptionWidget(new KisFlowOpacityOption(0), i18n("Transparent"), i18n("Opaque"), true) { setObjectName("KisFlowOpacityOptionWidget"); QWidget* widget = new QWidget(); Ui_wdgFlowOpacityOption ui; ui.setupUi(widget); ui.layout->addWidget(curveWidget()); m_opacitySlider = ui.opacitySlider; m_opacitySlider->setRange(0.0, 1.0, 2); m_opacitySlider->setValue(1.0); setConfigurationPage(widget); connect(m_opacitySlider, SIGNAL(valueChanged(qreal)), SLOT(slotSliderValueChanged())); } -void KisFlowOpacityOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisFlowOpacityOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOptionWidget::readOptionSetting(setting); KisFlowOpacityOption* option = static_cast(curveOption()); m_opacitySlider->blockSignals(true); m_opacitySlider->setValue(option->getStaticOpacity()); m_opacitySlider->blockSignals(false); } void KisFlowOpacityOptionWidget::slotSliderValueChanged() { KisFlowOpacityOption* option = static_cast(curveOption()); option->setOpacity(m_opacitySlider->value()); emitSettingChanged(); } diff --git a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.h b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.h index 8e3665f4b1..e62106095c 100644 --- a/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.h +++ b/plugins/paintops/libpaintop/kis_pressure_flow_opacity_option_widget.h @@ -1,45 +1,45 @@ /* * 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_PRESSURE_FLOW_OPACITY_OPTION_WIDGET_H #define KIS_PRESSURE_FLOW_OPACITY_OPTION_WIDGET_H #include "kis_pressure_flow_opacity_option.h" #include "kis_curve_option_widget.h" class KisDoubleSliderSpinBox; class KisCurveOptionWidget; class PAINTOP_EXPORT KisFlowOpacityOptionWidget: public KisCurveOptionWidget { Q_OBJECT public: KisFlowOpacityOptionWidget(); - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); private Q_SLOTS: void slotSliderValueChanged(); private: KisDoubleSliderSpinBox* m_opacitySlider; }; #endif // KIS_PRESSURE_FLOW_OPACITY_OPTION_WIDGET_H diff --git a/plugins/paintops/libpaintop/kis_pressure_mirror_option.cpp b/plugins/paintops/libpaintop/kis_pressure_mirror_option.cpp index cdca9717ce..f32d6158b4 100644 --- a/plugins/paintops/libpaintop/kis_pressure_mirror_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_mirror_option.cpp @@ -1,101 +1,101 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_pressure_mirror_option.h" #include #include #include #include KisPressureMirrorOption::KisPressureMirrorOption() : KisCurveOption("Mirror", KisPaintOpOption::GENERAL, false) { m_enableHorizontalMirror = false; m_enableVerticalMirror = false; } void KisPressureMirrorOption::enableHorizontalMirror(bool mirror) { m_enableHorizontalMirror = mirror; } void KisPressureMirrorOption::enableVerticalMirror(bool mirror) { m_enableVerticalMirror = mirror; } bool KisPressureMirrorOption::isHorizontalMirrorEnabled() { return m_enableHorizontalMirror; } bool KisPressureMirrorOption::isVerticalMirrorEnabled() { return m_enableVerticalMirror; } -void KisPressureMirrorOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureMirrorOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty(MIRROR_HORIZONTAL_ENABLED, m_enableHorizontalMirror); setting->setProperty(MIRROR_VERTICAL_ENABLED, m_enableVerticalMirror); } -void KisPressureMirrorOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureMirrorOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); m_enableHorizontalMirror = setting->getBool(MIRROR_HORIZONTAL_ENABLED, false); m_enableVerticalMirror = setting->getBool(MIRROR_VERTICAL_ENABLED, false); m_canvasAxisXMirrored = setting->getBool("runtimeCanvasMirroredX", false); m_canvasAxisYMirrored = setting->getBool("runtimeCanvasMirroredY", false); } MirrorProperties KisPressureMirrorOption::apply(const KisPaintInformation& info) const { int mirrorXIncrement = m_canvasAxisXMirrored; int mirrorYIncrement = m_canvasAxisYMirrored; bool coordinateSystemFlipped = false; if (isChecked() && (m_enableHorizontalMirror || m_enableVerticalMirror)) { qreal sensorResult = computeSizeLikeValue(info); bool result = (sensorResult >= 0.5); mirrorXIncrement += result && m_enableHorizontalMirror; mirrorYIncrement += result && m_enableVerticalMirror; coordinateSystemFlipped = result && (m_enableHorizontalMirror != m_enableVerticalMirror); } MirrorProperties mirrors; mirrors.verticalMirror = mirrorYIncrement % 2; mirrors.horizontalMirror = mirrorXIncrement % 2; mirrors.coordinateSystemFlipped = coordinateSystemFlipped; return mirrors; } diff --git a/plugins/paintops/libpaintop/kis_pressure_mirror_option.h b/plugins/paintops/libpaintop/kis_pressure_mirror_option.h index 0bce18d3bc..c2f5eea716 100644 --- a/plugins/paintops/libpaintop/kis_pressure_mirror_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_mirror_option.h @@ -1,76 +1,76 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PRESSURE_MIRROR_OPTION_H #define KIS_PRESSURE_MIRROR_OPTION_H #include "kis_curve_option.h" #include #include #include struct MirrorProperties { MirrorProperties() : horizontalMirror(false), verticalMirror(false), coordinateSystemFlipped(false) {} bool horizontalMirror; bool verticalMirror; bool coordinateSystemFlipped; bool isEmpty() const { return !horizontalMirror && !verticalMirror; } }; const QString MIRROR_HORIZONTAL_ENABLED = "HorizontalMirrorEnabled"; const QString MIRROR_VERTICAL_ENABLED = "VerticalMirrorEnabled"; /** * If the sensor value is higher then 0.5, then the related mirror option is true, false otherwise */ class PAINTOP_EXPORT KisPressureMirrorOption : public KisCurveOption { public: KisPressureMirrorOption(); /** * Set the */ MirrorProperties apply(const KisPaintInformation& info) const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void enableVerticalMirror(bool mirror); void enableHorizontalMirror(bool mirror); bool isVerticalMirrorEnabled(); bool isHorizontalMirrorEnabled(); private: bool m_enableVerticalMirror; bool m_enableHorizontalMirror; bool m_canvasAxisXMirrored; bool m_canvasAxisYMirrored; }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.cpp b/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.cpp index d357c44216..ce0d7fa8aa 100644 --- a/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.cpp @@ -1,81 +1,81 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_pressure_mirror_option_widget.h" #include #include #include #include #include #include "kis_pressure_mirror_option.h" KisPressureMirrorOptionWidget::KisPressureMirrorOptionWidget() : KisCurveOptionWidget(new KisPressureMirrorOption(), i18n("Not mirrored"), i18n("Mirrored")) { setObjectName("KisPressureMirrorOptionWidget"); QWidget* w = new QWidget; m_horizontalMirror = new QCheckBox(i18n("Horizontally")); m_horizontalMirror->setChecked(false); m_verticalMirror = new QCheckBox(i18n("Vertically")); m_verticalMirror->setChecked(false); connect(m_horizontalMirror, SIGNAL(toggled(bool)), SLOT(horizontalMirrorChanged(bool))); connect(m_verticalMirror, SIGNAL(toggled(bool)), SLOT(verticalMirrorChanged(bool))); QHBoxLayout* hl = new QHBoxLayout; hl->addWidget(m_horizontalMirror); hl->addWidget(m_verticalMirror); QVBoxLayout* vl = new QVBoxLayout; vl->setMargin(0); vl->addLayout(hl); vl->addWidget(curveWidget()); w->setLayout(vl); setConfigurationPage(w); horizontalMirrorChanged(m_horizontalMirror->isChecked()); verticalMirrorChanged(m_verticalMirror->isChecked()); } -void KisPressureMirrorOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureMirrorOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOptionWidget::readOptionSetting(setting); m_verticalMirror->setChecked(static_cast(curveOption())->isVerticalMirrorEnabled()); m_horizontalMirror->setChecked(static_cast(curveOption())->isHorizontalMirrorEnabled()); } void KisPressureMirrorOptionWidget::horizontalMirrorChanged(bool mirror) { static_cast(curveOption())->enableHorizontalMirror(mirror); emitSettingChanged(); } void KisPressureMirrorOptionWidget::verticalMirrorChanged(bool mirror) { static_cast(curveOption())->enableVerticalMirror(mirror); emitSettingChanged(); } diff --git a/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.h b/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.h index 8f6137ffe3..6a61e88583 100644 --- a/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.h +++ b/plugins/paintops/libpaintop/kis_pressure_mirror_option_widget.h @@ -1,45 +1,45 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PRESSURE_MIRROR_OPTION_WIDGET_H #define KIS_PRESSURE_MIRROR_OPTION_WIDGET_H #include "kis_curve_option_widget.h" class QCheckBox; class PAINTOP_EXPORT KisPressureMirrorOptionWidget : public KisCurveOptionWidget { Q_OBJECT public: KisPressureMirrorOptionWidget(); - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); private Q_SLOTS: void horizontalMirrorChanged(bool mirror); void verticalMirrorChanged(bool mirror); private: QCheckBox* m_horizontalMirror; QCheckBox* m_verticalMirror; }; #endif // KIS_PRESSURE_RATE_OPTION_WIDGET_H diff --git a/plugins/paintops/libpaintop/kis_pressure_opacity_option.cpp b/plugins/paintops/libpaintop/kis_pressure_opacity_option.cpp index b9b556461e..22ad698b97 100644 --- a/plugins/paintops/libpaintop/kis_pressure_opacity_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_opacity_option.cpp @@ -1,74 +1,74 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_pressure_opacity_option.h" #include #include #include KisPressureOpacityOption::KisPressureOpacityOption() : KisCurveOption("Opacity", KisPaintOpOption::GENERAL, true) { m_checkable = false; } -void KisPressureOpacityOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureOpacityOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty("OpacityVersion", "2"); } -void KisPressureOpacityOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureOpacityOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); if (setting->getString("OpacityVersion", "1") == "1") { KisDynamicSensorSP pressureSensor = sensor(PRESSURE, true); if (pressureSensor) { QList points = pressureSensor->curve().points(); QList points_new; Q_FOREACH (const QPointF & p, points) { points_new.push_back(QPointF(p.x() * 0.5, p.y())); } pressureSensor->setCurve(KisCubicCurve(points_new)); } } } quint8 KisPressureOpacityOption::apply(KisPainter* painter, const KisPaintInformation& info) const { if (!isChecked()) { return painter->opacity(); } quint8 origOpacity = painter->opacity(); qreal opacity = (qreal)(origOpacity * computeSizeLikeValue(info)); quint8 opacity2 = (quint8)qRound(qBound(OPACITY_TRANSPARENT_U8, opacity, OPACITY_OPAQUE_U8)); painter->setOpacityUpdateAverage(opacity2); return origOpacity; } qreal KisPressureOpacityOption::getOpacityf(const KisPaintInformation& info) { if (!isChecked()) return 1.0; return computeSizeLikeValue(info); } diff --git a/plugins/paintops/libpaintop/kis_pressure_opacity_option.h b/plugins/paintops/libpaintop/kis_pressure_opacity_option.h index e2eff74cc7..f96b4236b1 100644 --- a/plugins/paintops/libpaintop/kis_pressure_opacity_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_opacity_option.h @@ -1,51 +1,51 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * 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_PRESSURE_OPACITY_OPTION #define KIS_PRESSURE_OPACITY_OPTION #include "kis_curve_option.h" #include class KisPainter; /** * The pressure opacity option defines a curve that is used to * calculate the effect of pressure on opacity */ class PAINTOP_EXPORT KisPressureOpacityOption : public KisCurveOption { public: KisPressureOpacityOption(); /** * Set the opacity of the painter based on the pressure * and the curve (if checked) and return the old opacity * of the painter. */ quint8 apply(KisPainter* painter, const KisPaintInformation& info) const; qreal getOpacityf(const KisPaintInformation& info); - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_rotation_option.cpp b/plugins/paintops/libpaintop/kis_pressure_rotation_option.cpp index e4829ae19b..93021666e9 100644 --- a/plugins/paintops/libpaintop/kis_pressure_rotation_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_rotation_option.cpp @@ -1,69 +1,69 @@ /* This file is part of the KDE project * Copyright (c) 2009 Cyrille Berger * * 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_pressure_rotation_option.h" #include "kis_pressure_opacity_option.h" #include "sensors/kis_dynamic_sensor_drawing_angle.h" #include "sensors/kis_dynamic_sensor_fuzzy.h" #include #include #include #include KisPressureRotationOption::KisPressureRotationOption() : KisCurveOption("Rotation", KisPaintOpOption::GENERAL, false), m_defaultAngle(0.0), m_canvasAxisXMirrored(false), m_canvasAxisYMirrored(false) { } double KisPressureRotationOption::apply(const KisPaintInformation & info) const { if (!isChecked()) return m_defaultAngle; qreal value = computeRotationLikeValue(info, m_defaultAngle); if (m_canvasAxisXMirrored == m_canvasAxisYMirrored) { value = 1.0 - value; } return normalizeAngle(value * M_PI); } -void KisPressureRotationOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureRotationOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_defaultAngle = setting->getDouble("runtimeCanvasRotation", 0.0) * M_PI / 180.0; KisCurveOption::readOptionSetting(setting); m_canvasAxisXMirrored = setting->getBool("runtimeCanvasMirroredX", false); m_canvasAxisYMirrored = setting->getBool("runtimeCanvasMirroredY", false); } void KisPressureRotationOption::applyFanCornersInfo(KisPaintOp *op) { KisDynamicSensorDrawingAngle *sensor = dynamic_cast(this->sensor(ANGLE, true).data()); /** * A special case for the Drawing Angle sensor, because it * changes the behavior of KisPaintOp::paintLine() */ if (sensor) { op->setFanCornersInfo(sensor->fanCornersEnabled(), qreal(sensor->fanCornersStep()) * M_PI / 180.0); } } diff --git a/plugins/paintops/libpaintop/kis_pressure_rotation_option.h b/plugins/paintops/libpaintop/kis_pressure_rotation_option.h index a9ca193fdc..d933345a2f 100644 --- a/plugins/paintops/libpaintop/kis_pressure_rotation_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_rotation_option.h @@ -1,50 +1,50 @@ /* This file is part of the KDE project * Copyright (c) 2009 Cyrille Berger * * 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_PRESSURE_ROTATION_OPTION_H #define KIS_PRESSURE_ROTATION_OPTION_H #include "kis_curve_option.h" #include #include /** * The pressure opacity option defines a curve that is used to * calculate the effect of pressure on the size of the dab */ class PAINTOP_EXPORT KisPressureRotationOption : public KisCurveOption { public: KisPressureRotationOption(); double apply(const KisPaintInformation & info) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void readOptionSetting(const KisPropertiesConfigurationSP setting); void applyFanCornersInfo(KisPaintOp *op); private: qreal m_defaultAngle; bool m_canvasAxisXMirrored; bool m_canvasAxisYMirrored; }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_scatter_option.cpp b/plugins/paintops/libpaintop/kis_pressure_scatter_option.cpp index 1a914d9451..6f5f35d143 100644 --- a/plugins/paintops/libpaintop/kis_pressure_scatter_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_scatter_option.cpp @@ -1,122 +1,122 @@ /* * 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 "kis_pressure_scatter_option.h" #include #include #include #include #include KisPressureScatterOption::KisPressureScatterOption() : KisCurveOption("Scatter", KisPaintOpOption::GENERAL, false, 1.0, 0.0, 5.0) { m_axisX = true; m_axisY = true; } void KisPressureScatterOption::enableAxisX(bool enable) { m_axisX = enable; } void KisPressureScatterOption::enableAxisY(bool enable) { m_axisY = enable; } bool KisPressureScatterOption::isAxisXEnabled() { return m_axisX; } bool KisPressureScatterOption::isAxisYEnabled() { return m_axisY; } void KisPressureScatterOption::setScatterAmount(qreal amount) { KisCurveOption::setValue(amount); } qreal KisPressureScatterOption::scatterAmount() { return KisCurveOption::value(); } -void KisPressureScatterOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureScatterOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty(SCATTER_X, m_axisX); setting->setProperty(SCATTER_Y, m_axisY); } -void KisPressureScatterOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureScatterOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); m_axisX = setting->getBool(SCATTER_X, true); m_axisY = setting->getBool(SCATTER_Y, true); // backward compatibility: test for a "scatter amount" property // and use this value if it does exist if (setting->hasProperty(SCATTER_AMOUNT) && !setting->hasProperty("ScatterValue")) KisCurveOption::setValue(setting->getDouble(SCATTER_AMOUNT)); } QPointF KisPressureScatterOption::apply(const KisPaintInformation& info, qreal width, qreal height) const { if ((!m_axisX && !m_axisY) || (!isChecked())) { return info.pos(); } // just use the most significant dimension for calculations qreal diameter = qMax(width, height); qreal sensorValue = computeSizeLikeValue(info); qreal jitter = (2.0 * info.randomSource()->generateNormalized() - 1.0) * diameter * sensorValue; QPointF result(0.0, 0.0); if (m_axisX && m_axisY) { qreal jitterY = (2.0 * info.randomSource()->generateNormalized() - 1.0) * diameter * sensorValue; result = QPointF(jitter, jitterY); return info.pos() + result; } qreal drawingAngle = info.drawingAngle(); QVector2D movement(cos(drawingAngle), sin(drawingAngle)); if (m_axisX) { movement *= jitter; result = movement.toPointF(); } else if (m_axisY) { QVector2D movementNormal(-movement.y(), movement.x()); movementNormal *= jitter; result = movementNormal.toPointF(); } return info.pos() + result; } diff --git a/plugins/paintops/libpaintop/kis_pressure_scatter_option.h b/plugins/paintops/libpaintop/kis_pressure_scatter_option.h index f9977261f0..92783b3c9e 100644 --- a/plugins/paintops/libpaintop/kis_pressure_scatter_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_scatter_option.h @@ -1,58 +1,58 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PRESSURE_SCATTER_OPTION_H #define KIS_PRESSURE_SCATTER_OPTION_H #include "kis_curve_option.h" #include #include #include const QString SCATTER_X = "Scattering/AxisX"; const QString SCATTER_Y = "Scattering/AxisY"; const QString SCATTER_AMOUNT = "Scattering/Amount"; /** * Scatters the position of the dab */ class PAINTOP_EXPORT KisPressureScatterOption : public KisCurveOption { public: KisPressureScatterOption(); QPointF apply(const KisPaintInformation& info, qreal width, qreal height) const; - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); void enableAxisY(bool enable); void enableAxisX(bool enable); bool isAxisXEnabled(); bool isAxisYEnabled(); void setScatterAmount(qreal amount); qreal scatterAmount(); private: bool m_axisX; bool m_axisY; }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.cpp b/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.cpp index 31000da1af..044c1bc2ad 100644 --- a/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.cpp @@ -1,84 +1,84 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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 #include #include #include #include #include #include "kis_pressure_scatter_option.h" #include "kis_pressure_scatter_option_widget.h" KisPressureScatterOptionWidget::KisPressureScatterOptionWidget() : KisCurveOptionWidget(new KisPressureScatterOption(), i18n("0.0"), i18n("1.0")) { setObjectName("setObjectName("");"); QWidget* w = new QWidget; m_axisX = new QCheckBox(i18n("Axis X")); m_axisX->setChecked(true); m_axisY = new QCheckBox(i18n("Axis Y")); m_axisY->setChecked(true); QLabel* scatterLbl = new QLabel(i18n("Scatter amount")); QHBoxLayout* hl = new QHBoxLayout; hl->addWidget(scatterLbl); hl->addWidget(m_axisX); hl->addWidget(m_axisY); QVBoxLayout* vl = new QVBoxLayout; vl->setMargin(0); vl->addLayout(hl); vl->addWidget(curveWidget()); w->setLayout(vl); connect(m_axisX, SIGNAL(toggled(bool)), SLOT(xAxisEnabled(bool))); connect(m_axisY, SIGNAL(toggled(bool)), SLOT(yAxisEnabled(bool))); setConfigurationPage(w); xAxisEnabled(m_axisX->isChecked()); yAxisEnabled(m_axisY->isChecked()); } -void KisPressureScatterOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureScatterOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOptionWidget::readOptionSetting(setting); m_axisX->setChecked(static_cast(curveOption())->isAxisXEnabled()); m_axisY->setChecked(static_cast(curveOption())->isAxisYEnabled()); } void KisPressureScatterOptionWidget::xAxisEnabled(bool enable) { static_cast(curveOption())->enableAxisX(enable); emitSettingChanged(); } void KisPressureScatterOptionWidget::yAxisEnabled(bool enable) { static_cast(curveOption())->enableAxisY(enable); emitSettingChanged(); } diff --git a/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.h b/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.h index a10fba18b6..59b96a4ad2 100644 --- a/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.h +++ b/plugins/paintops/libpaintop/kis_pressure_scatter_option_widget.h @@ -1,46 +1,46 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PRESSURE_SCATTER_OPTION_WIDGET_H #define KIS_PRESSURE_SCATTER_OPTION_WIDGET_H #include "kis_curve_option_widget.h" class QCheckBox; class PAINTOP_EXPORT KisPressureScatterOptionWidget: public KisCurveOptionWidget { Q_OBJECT public: KisPressureScatterOptionWidget(); - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); private Q_SLOTS: void xAxisEnabled(bool enable); void yAxisEnabled(bool enable); private: QCheckBox* m_axisX; QCheckBox* m_axisY; }; #endif // KIS_PRESSURE_RATE_OPTION_WIDGET_H diff --git a/plugins/paintops/libpaintop/kis_pressure_sharpness_option.cpp b/plugins/paintops/libpaintop/kis_pressure_sharpness_option.cpp index 42f06e3014..2916c7c293 100644 --- a/plugins/paintops/libpaintop/kis_pressure_sharpness_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_sharpness_option.cpp @@ -1,110 +1,110 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_pressure_sharpness_option.h" #include #include #include #include #include #include KisPressureSharpnessOption::KisPressureSharpnessOption() : KisCurveOption("Sharpness", KisPaintOpOption::GENERAL, false) { m_threshold = 40; } -void KisPressureSharpnessOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureSharpnessOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty(SHARPNESS_THRESHOLD, m_threshold); } -void KisPressureSharpnessOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureSharpnessOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); m_threshold = setting->getInt(SHARPNESS_THRESHOLD, 4); // backward compatibility: test for a "sharpness factor" property // and use this value if it does exist if (setting->hasProperty(SHARPNESS_FACTOR) && !setting->hasProperty("SharpnessValue")) KisCurveOption::setValue(setting->getDouble(SHARPNESS_FACTOR)); } void KisPressureSharpnessOption::apply(const KisPaintInformation &info, const QPointF &pt, qint32 &x, qint32 &y, qreal &xFraction, qreal &yFraction) const { if (!isChecked() || KisCurveOption::value() == 0.0) { // brush KisPaintOp::splitCoordinate(pt.x(), &x, &xFraction); KisPaintOp::splitCoordinate(pt.y(), &y, &yFraction); } else { qreal processedSharpnes = computeSizeLikeValue(info); if (processedSharpnes == 1.0) { // pen xFraction = 0.0; yFraction = 0.0; x = qRound(pt.x()); y = qRound(pt.y()); } else { // something in between qint32 xi = qRound(pt.x()); qint32 yi = qRound(pt.y()); qreal xf = processedSharpnes * xi + (1.0 - processedSharpnes) * pt.x(); qreal yf = processedSharpnes * yi + (1.0 - processedSharpnes) * pt.y(); KisPaintOp::splitCoordinate(xf, &x, &xFraction); KisPaintOp::splitCoordinate(yf, &y, &yFraction); } } } void KisPressureSharpnessOption::applyThreshold(KisFixedPaintDeviceSP dab) { if (!isChecked()) return; const KoColorSpace * cs = dab->colorSpace(); // Set all alpha > opaque/2 to opaque, the rest to transparent. // XXX: Using 4/10 as the 1x1 circle brush paints nothing with 0.5. quint8* dabPointer = dab->data(); QRect rc = dab->bounds(); int pixelSize = dab->pixelSize(); int pixelCount = rc.width() * rc.height(); for (int i = 0; i < pixelCount; i++) { quint8 alpha = cs->opacityU8(dabPointer); if (alpha < (m_threshold * OPACITY_OPAQUE_U8) / 100) { cs->setOpacity(dabPointer, OPACITY_TRANSPARENT_U8, 1); } else { cs->setOpacity(dabPointer, OPACITY_OPAQUE_U8, 1); } dabPointer += pixelSize; } } diff --git a/plugins/paintops/libpaintop/kis_pressure_sharpness_option.h b/plugins/paintops/libpaintop/kis_pressure_sharpness_option.h index eff559ac2c..620e2d0c58 100644 --- a/plugins/paintops/libpaintop/kis_pressure_sharpness_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_sharpness_option.h @@ -1,72 +1,72 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PRESSURE_SHARPNESS_OPTION_H #define KIS_PRESSURE_SHARPNESS_OPTION_H #include "kis_curve_option.h" #include #include #include const QString SHARPNESS_FACTOR = "Sharpness/factor"; const QString SHARPNESS_THRESHOLD = "Sharpness/threshold"; /** * This option is responsible to mimic pencil effect from former Pixel Pencil brush engine.auto */ class PAINTOP_EXPORT KisPressureSharpnessOption : public KisCurveOption { public: KisPressureSharpnessOption(); /** * First part of the sharpness is the coordinates: in pen mode they are integers without fractions */ void apply(const KisPaintInformation &info, const QPointF &pt, qint32 &x, qint32 &y, qreal &xFraction, qreal &yFraction) const; /** * Apply threshold specified by user */ void applyThreshold(KisFixedPaintDeviceSP dab); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); /// threshold has 100 levels (like opacity) void setThreshold(qint32 threshold) { m_threshold = qBound(0, threshold, 100); } qint32 threshold() { return m_threshold; } void setSharpnessFactor(qreal factor) { KisCurveOption::setValue(factor); } qreal sharpnessFactor() { return KisCurveOption::value(); } private: qint32 m_threshold; }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_spacing_option.cpp b/plugins/paintops/libpaintop/kis_pressure_spacing_option.cpp index 47e753f197..1d182d0e0c 100644 --- a/plugins/paintops/libpaintop/kis_pressure_spacing_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_spacing_option.cpp @@ -1,59 +1,59 @@ /* This file is part of the KDE project * Copyright (c) 2011 Cyrille Berger * * 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_pressure_spacing_option.h" #include const QString ISOTROPIC_SPACING = "Spacing/Isotropic"; KisPressureSpacingOption::KisPressureSpacingOption() : KisCurveOption("Spacing", KisPaintOpOption::GENERAL, false), m_isotropicSpacing(false) { } double KisPressureSpacingOption::apply(const KisPaintInformation & info) const { if (!isChecked()) return 1.0; return computeSizeLikeValue(info); } void KisPressureSpacingOption::setIsotropicSpacing(bool isotropic) { m_isotropicSpacing = isotropic; } bool KisPressureSpacingOption::isotropicSpacing() const { return m_isotropicSpacing; } -void KisPressureSpacingOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureSpacingOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); setting->setProperty(ISOTROPIC_SPACING, m_isotropicSpacing); } -void KisPressureSpacingOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureSpacingOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); m_isotropicSpacing = setting->getBool(ISOTROPIC_SPACING, false); } diff --git a/plugins/paintops/libpaintop/kis_pressure_spacing_option.h b/plugins/paintops/libpaintop/kis_pressure_spacing_option.h index 617711224e..a191031cbd 100644 --- a/plugins/paintops/libpaintop/kis_pressure_spacing_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_spacing_option.h @@ -1,47 +1,47 @@ /* This file is part of the KDE project * Copyright (c) 2011 Cyrille Berger * * 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_PRESSURE_SPACING_OPTION_H #define KIS_PRESSURE_SPACING_OPTION_H #include "kis_curve_option.h" #include #include /** * The pressure spacing option defines a curve that is used to * calculate the effect of pressure on the spacing of the dab */ class PAINTOP_EXPORT KisPressureSpacingOption : public KisCurveOption { public: KisPressureSpacingOption(); double apply(const KisPaintInformation & info) const; void setIsotropicSpacing(bool isotropic); bool isotropicSpacing() const; - void readOptionSetting(const KisPropertiesConfiguration* setting); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; private: bool m_isotropicSpacing; }; #endif diff --git a/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.cpp b/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.cpp index 18e3c9427c..6597a8de95 100644 --- a/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.cpp @@ -1,66 +1,66 @@ /* * 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_pressure_texture_strength_option.h" #include KisPressureTextureStrengthOption::KisPressureTextureStrengthOption() : KisCurveOption("Texture/Strength/", KisPaintOpOption::TEXTURE, false) { } double KisPressureTextureStrengthOption::apply(const KisPaintInformation & info) const { if (!isChecked()) return 1.0; return computeSizeLikeValue(info); } -void KisPressureTextureStrengthOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisPressureTextureStrengthOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisCurveOption::readOptionSetting(setting); /** * Backward compatibility with Krita < 2.7. * * Process the presets created with the old UI, when the * strength was a part of Texture/Pattern option. */ int strengthVersion = setting->getInt("Texture/Strength/StrengthVersion", 1); if (strengthVersion == 1) { double legacyStrength = setting->getDouble("Texture/Pattern/Strength", 1.0); setChecked(true); setValue(legacyStrength); } } -void KisPressureTextureStrengthOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisPressureTextureStrengthOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisCurveOption::writeOptionSetting(setting); /** * Forward compatibility with the Krita < 2.7 * * Duplicate the value of the maximum strength into the * property used by older versions of Krita. */ setting->setProperty("Texture/Strength/StrengthVersion", 2); if (isChecked()) { setting->setProperty("Texture/Pattern/Strength", value()); } } diff --git a/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.h b/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.h index faddfbc4df..8c6c4b6f0f 100644 --- a/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_texture_strength_option.h @@ -1,41 +1,41 @@ /* * 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. */ #ifndef __KIS_PRESSURE_TEXTURE_STRENGTH_OPTION_H #define __KIS_PRESSURE_TEXTURE_STRENGTH_OPTION_H #include "kis_curve_option.h" #include #include /** * This curve defines how deep the ink (or a pointer) of a brush * penetrates the surface of the canvas, that is how strong we * press on the paper */ class PAINTOP_EXPORT KisPressureTextureStrengthOption : public KisCurveOption { public: KisPressureTextureStrengthOption(); double apply(const KisPaintInformation & info) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; }; #endif /* __KIS_PRESSURE_TEXTURE_STRENGTH_OPTION_H */ diff --git a/plugins/paintops/libpaintop/kis_simple_paintop_factory.h b/plugins/paintops/libpaintop/kis_simple_paintop_factory.h index 43725826f5..91bf8a1a2a 100644 --- a/plugins/paintops/libpaintop/kis_simple_paintop_factory.h +++ b/plugins/paintops/libpaintop/kis_simple_paintop_factory.h @@ -1,135 +1,132 @@ /* * Copyright (c) 2009 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_SIMPLE_PAINTOP_FACTORY_H #define KIS_SIMPLE_PAINTOP_FACTORY_H #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND #include #include template struct __impl_has_typedef_needs_preinitialization { typedef char yes[1]; typedef char no[2]; template static yes& test(typename C::needs_preinitialization*); template static no& test(...); static const bool value = sizeof(test(0)) == sizeof(yes); }; template struct has_typedef_needs_preinitialization : public boost::integral_constant ::value> {}; template void preinitializeOpStatically(const KisPaintOpSettingsSP settings, typename boost::enable_if >::type * = 0) { T::preinitializeOpStatically(settings); } template void preinitializeOpStatically(const KisPaintOpSettingsSP settings, typename boost::disable_if >::type * = 0) { Q_UNUSED(settings); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ /** * Base template class for simple paintop factories */ template class KisSimplePaintOpFactory : public KisPaintOpFactory { public: KisSimplePaintOpFactory(const QString& id, const QString& name, const QString& category, const QString& pixmap, const QString& model = QString(), const QStringList& whiteListedCompositeOps = QStringList(), int priority = 100) : KisPaintOpFactory(whiteListedCompositeOps) , m_id(id) , m_name(name) , m_category(category) , m_pixmap(pixmap) , m_model(model) { setPriority(priority); } virtual ~KisSimplePaintOpFactory() { } #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND void preinitializePaintOpIfNeeded(const KisPaintOpSettingsSP settings) { preinitializeOpStatically(settings); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ - KisPaintOp * createOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) { - const OpSettings *opSettings = dynamic_cast(settings.data()); - Q_ASSERT(settings == 0 || opSettings != 0); - - KisPaintOp * op = new Op(opSettings, painter, node, image); + KisPaintOp *createOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) { + KisPaintOp * op = new Op(settings, painter, node, image); Q_CHECK_PTR(op); return op; } KisPaintOpSettingsSP settings() { KisPaintOpSettingsSP settings = new OpSettings(); settings->setModelName(m_model); return settings; } KisPaintOpConfigWidget* createConfigWidget(QWidget* parent) { return new OpSettingsWidget(parent); } QString id() const { return m_id; } QString name() const { return m_name; } QString pixmap() { return m_pixmap; } QString category() const { return m_category; } private: QString m_id; QString m_name; QString m_category; QString m_pixmap; QString m_model; }; #endif // KIS_SIMPLE_PAINTOP_FACTORY_H diff --git a/plugins/paintops/libpaintop/kis_texture_option.cpp b/plugins/paintops/libpaintop/kis_texture_option.cpp index 5bdc3cac7a..5ab256f806 100644 --- a/plugins/paintops/libpaintop/kis_texture_option.cpp +++ b/plugins/paintops/libpaintop/kis_texture_option.cpp @@ -1,416 +1,416 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2012 * Copyright (C) Mohit Goyal , (C) 2014 * * 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_texture_option.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 "kis_embedded_pattern_manager.h" #include "kis_algebra_2d.h" #include "kis_lod_transform.h" #include #include class KisTextureOptionWidget : public QWidget { public: KisTextureOptionWidget(QWidget *parent = 0) : QWidget(parent) { QFormLayout *formLayout = new QFormLayout(this); formLayout->setMargin(0); chooser = new KisPatternChooser(this); chooser->setGrayscalePreview(true); chooser->setMaximumHeight(250); chooser->setCurrentItem(0, 0); formLayout->addRow(chooser); scaleSlider = new KisMultipliersDoubleSliderSpinBox(this); scaleSlider->setRange(0.0, 2.0, 2); scaleSlider->setValue(1.0); scaleSlider->addMultiplier(0.1); scaleSlider->addMultiplier(2); scaleSlider->addMultiplier(10); formLayout->addRow(i18n("Scale:"), scaleSlider); QBoxLayout *offsetLayoutX = new QBoxLayout(QBoxLayout::LeftToRight); offsetSliderX = new KisSliderSpinBox(this); offsetSliderX->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); offsetSliderX->setSuffix(i18n(" px")); randomOffsetX = new QCheckBox(i18n("Random Offset"),this); offsetLayoutX->addWidget(offsetSliderX,1,0); offsetLayoutX->addWidget(randomOffsetX,0,0); formLayout->addRow(i18n("Horizontal Offset:"), offsetLayoutX); QBoxLayout *offsetLayoutY = new QBoxLayout(QBoxLayout::LeftToRight); offsetSliderY = new KisSliderSpinBox(this); offsetSliderY->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); offsetSliderY->setSuffix(i18n(" px")); randomOffsetY = new QCheckBox(i18n("Random Offset"),this); offsetLayoutY->addWidget(offsetSliderY,1,0); offsetLayoutY->addWidget(randomOffsetY,0,0); formLayout->addRow(i18n("Vertical Offset:"), offsetLayoutY); cmbTexturingMode = new QComboBox(this); cmbTexturingMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QStringList texturingModes; texturingModes << i18n("Multiply") << i18n("Subtract"); cmbTexturingMode->addItems(texturingModes); formLayout->addRow(i18n("Texturing Mode:"), cmbTexturingMode); cmbTexturingMode->setCurrentIndex(KisTextureProperties::SUBTRACT); cmbCutoffPolicy = new QComboBox(this); cmbCutoffPolicy->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); QStringList cutOffPolicies; cutOffPolicies << i18n("Cut Off Disabled") << i18n("Cut Off Brush") << i18n("Cut Off Pattern"); cmbCutoffPolicy->addItems(cutOffPolicies); formLayout->addRow(i18n("Cutoff Policy:"), cmbCutoffPolicy); cutoffSlider = new KisGradientSlider(this); cutoffSlider->setMinimumSize(256, 30); cutoffSlider->enableGamma(false); cutoffSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); cutoffSlider->setToolTip(i18n("When pattern texture values are outside the range specified" " by the slider, the cut-off policy will be applied.")); formLayout->addRow(i18n("Cutoff:"), cutoffSlider); chkInvert = new QCheckBox(this); chkInvert->setChecked(false); formLayout->addRow(i18n("Invert Pattern:"), chkInvert); setLayout(formLayout); } KisPatternChooser *chooser; KisMultipliersDoubleSliderSpinBox *scaleSlider; KisSliderSpinBox *offsetSliderX; QCheckBox *randomOffsetX; KisSliderSpinBox *offsetSliderY; QCheckBox *randomOffsetY; QComboBox *cmbTexturingMode; KisGradientSlider *cutoffSlider; QComboBox *cmbCutoffPolicy; QCheckBox *chkInvert; }; KisTextureOption::KisTextureOption() : KisPaintOpOption(KisPaintOpOption::TEXTURE, true) { setObjectName("KisTextureOption"); setChecked(false); m_optionWidget = new KisTextureOptionWidget; m_optionWidget->hide(); setConfigurationPage(m_optionWidget); connect(m_optionWidget->chooser, SIGNAL(resourceSelected(KoResource*)), SLOT(resetGUI(KoResource*))); connect(m_optionWidget->chooser, SIGNAL(resourceSelected(KoResource*)), SLOT(emitSettingChanged())); connect(m_optionWidget->scaleSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_optionWidget->offsetSliderX, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->randomOffsetX, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->randomOffsetY, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_optionWidget->offsetSliderY, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->cmbTexturingMode, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->cmbCutoffPolicy, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->cutoffSlider, SIGNAL(sigModifiedBlack(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->cutoffSlider, SIGNAL(sigModifiedWhite(int)), SLOT(emitSettingChanged())); connect(m_optionWidget->chkInvert, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); resetGUI(m_optionWidget->chooser->currentResource()); } KisTextureOption::~KisTextureOption() { delete m_optionWidget; } -void KisTextureOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisTextureOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { m_optionWidget->chooser->blockSignals(true); // Checking if (!m_optionWidget->chooser->currentResource()) return; KoPattern *pattern = static_cast(m_optionWidget->chooser->currentResource()); m_optionWidget->chooser->blockSignals(false); // Checking if (!pattern) return; setting->setProperty("Texture/Pattern/Enabled", isChecked()); if (!isChecked()) { return; } qreal scale = m_optionWidget->scaleSlider->value(); int offsetX = m_optionWidget->offsetSliderX->value(); if (m_optionWidget ->randomOffsetX->isChecked()) { m_optionWidget -> offsetSliderX ->setEnabled(false); m_optionWidget -> offsetSliderX ->blockSignals(true); m_optionWidget -> offsetSliderX ->setValue(offsetX); m_optionWidget -> offsetSliderX ->blockSignals(false); srand(time(0)); } else { m_optionWidget -> offsetSliderX ->setEnabled(true); } int offsetY = m_optionWidget->offsetSliderY->value(); if (m_optionWidget ->randomOffsetY->isChecked()) { m_optionWidget -> offsetSliderY ->setEnabled(false); m_optionWidget -> offsetSliderY ->blockSignals(true); m_optionWidget -> offsetSliderY ->setValue(offsetY); m_optionWidget -> offsetSliderY ->blockSignals(false); srand(time(0)); } else { m_optionWidget -> offsetSliderY ->setEnabled(true); } int texturingMode = m_optionWidget->cmbTexturingMode->currentIndex(); bool invert = (m_optionWidget->chkInvert->checkState() == Qt::Checked); setting->setProperty("Texture/Pattern/Scale", scale); setting->setProperty("Texture/Pattern/OffsetX", offsetX); setting->setProperty("Texture/Pattern/OffsetY", offsetY); setting->setProperty("Texture/Pattern/TexturingMode", texturingMode); setting->setProperty("Texture/Pattern/CutoffLeft", m_optionWidget->cutoffSlider->black()); setting->setProperty("Texture/Pattern/CutoffRight", m_optionWidget->cutoffSlider->white()); setting->setProperty("Texture/Pattern/CutoffPolicy", m_optionWidget->cmbCutoffPolicy->currentIndex()); setting->setProperty("Texture/Pattern/Invert", invert); setting->setProperty("Texture/Pattern/MaximumOffsetX",m_optionWidget -> offsetSliderX ->maximum()); setting->setProperty("Texture/Pattern/MaximumOffsetY",m_optionWidget -> offsetSliderY ->maximum()); setting->setProperty("Texture/Pattern/isRandomOffsetX",m_optionWidget ->randomOffsetX ->isChecked()); setting->setProperty("Texture/Pattern/isRandomOffsetY",m_optionWidget ->randomOffsetY ->isChecked()); KisEmbeddedPatternManager::saveEmbeddedPattern(setting, pattern); } -void KisTextureOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisTextureOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { setChecked(setting->getBool("Texture/Pattern/Enabled")); if (!isChecked()) { return; } KoPattern *pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); if (!pattern) { pattern = static_cast(m_optionWidget->chooser->currentResource()); } m_optionWidget->chooser->setCurrentPattern(pattern); m_optionWidget->scaleSlider->setValue(setting->getDouble("Texture/Pattern/Scale", 1.0)); m_optionWidget->offsetSliderX->setValue(setting->getInt("Texture/Pattern/OffsetX")); m_optionWidget->offsetSliderY->setValue(setting->getInt("Texture/Pattern/OffsetY")); m_optionWidget->randomOffsetX->setChecked(setting->getBool("Texture/Pattern/isRandomOffsetX")); m_optionWidget->randomOffsetY->setChecked(setting->getBool("Texture/Pattern/isRandomOffsetY")); m_optionWidget->cmbTexturingMode->setCurrentIndex(setting->getInt("Texture/Pattern/TexturingMode", KisTextureProperties::MULTIPLY)); m_optionWidget->cmbCutoffPolicy->setCurrentIndex(setting->getInt("Texture/Pattern/CutoffPolicy")); m_optionWidget->cutoffSlider->slotModifyBlack(setting->getInt("Texture/Pattern/CutoffLeft", 0)); m_optionWidget->cutoffSlider->slotModifyWhite(setting->getInt("Texture/Pattern/CutoffRight", 255)); m_optionWidget->chkInvert->setChecked(setting->getBool("Texture/Pattern/Invert")); } void KisTextureOption::lodLimitations(KisPaintopLodLimitations *l) const { l->limitations << KoID("texture-pattern", i18nc("PaintOp instant preview limitation", "Texture -> Pattern (low quality preview)")); } void KisTextureOption::resetGUI(KoResource* res) { KoPattern *pattern = static_cast(res); if (!pattern) return; m_optionWidget->offsetSliderX->setRange(0, pattern->pattern().width() / 2); m_optionWidget->offsetSliderY->setRange(0, pattern->pattern().height() / 2); } KisTextureProperties::KisTextureProperties(int levelOfDetail) : m_pattern(0), m_levelOfDetail(levelOfDetail) { } void KisTextureProperties::recalculateMask() { if (!m_pattern) return; m_mask = 0; QImage mask = m_pattern->pattern(); if ((mask.format() != QImage::Format_RGB32) | (mask.format() != QImage::Format_ARGB32)) { mask = mask.convertToFormat(QImage::Format_ARGB32); } qreal scale = m_scale * KisLodTransform::lodToScale(m_levelOfDetail); if (!qFuzzyCompare(scale, 0.0)) { QTransform tf; tf.scale(scale, scale); QRect rc = KisAlgebra2D::ensureRectNotSmaller(tf.mapRect(mask.rect()), QSize(2,2)); mask = mask.scaled(rc.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } const QRgb* pixel = reinterpret_cast(mask.constBits()); int width = mask.width(); int height = mask.height(); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); m_mask = new KisPaintDevice(cs); KisHLineIteratorSP iter = m_mask->createHLineIteratorNG(0, 0, width); for (int row = 0; row < height; ++row) { for (int col = 0; col < width; ++col) { const QRgb currentPixel = pixel[row * width + col]; const int red = qRed(currentPixel); const int green = qGreen(currentPixel); const int blue = qBlue(currentPixel); float alpha = qAlpha(currentPixel) / 255.0; const int grayValue = (red * 11 + green * 16 + blue * 5) / 32; float maskValue = (grayValue / 255.0) * alpha + (1 - alpha); if (m_invert) { maskValue = 1 - maskValue; } if (m_cutoffPolicy == 1 && (maskValue < (m_cutoffLeft / 255.0) || maskValue > (m_cutoffRight / 255.0))) { // mask out the dab if it's outside the pattern's cuttoff points maskValue = OPACITY_TRANSPARENT_F; } else if (m_cutoffPolicy == 2 && (maskValue < (m_cutoffLeft / 255.0) || maskValue > (m_cutoffRight / 255.0))) { maskValue = OPACITY_OPAQUE_F; } cs->setOpacity(iter->rawData(), maskValue, 1); iter->nextPixel(); } iter->nextRow(); } m_maskBounds = QRect(0, 0, width, height); } -void KisTextureProperties::fillProperties(const KisPropertiesConfiguration *setting) +void KisTextureProperties::fillProperties(const KisPropertiesConfigurationSP setting) { if (!setting->hasProperty("Texture/Pattern/PatternMD5")) { m_enabled = false; return; } m_pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); if (!m_pattern) { warnKrita << "WARNING: Couldn't load the pattern for a stroke"; m_enabled = false; return; } m_enabled = setting->getBool("Texture/Pattern/Enabled", false); m_scale = setting->getDouble("Texture/Pattern/Scale", 1.0); m_offsetX = setting->getInt("Texture/Pattern/OffsetX"); m_offsetY = setting->getInt("Texture/Pattern/OffsetY"); m_texturingMode = (TexturingMode) setting->getInt("Texture/Pattern/TexturingMode", MULTIPLY); m_invert = setting->getBool("Texture/Pattern/Invert"); m_cutoffLeft = setting->getInt("Texture/Pattern/CutoffLeft", 0); m_cutoffRight = setting->getInt("Texture/Pattern/CutoffRight", 255); m_cutoffPolicy = setting->getInt("Texture/Pattern/CutoffPolicy", 0); m_strengthOption.readOptionSetting(setting); m_strengthOption.resetAllSensors(); recalculateMask(); } void KisTextureProperties::apply(KisFixedPaintDeviceSP dab, const QPoint &offset, const KisPaintInformation & info) { if (!m_enabled) return; KisPaintDeviceSP fillDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); QRect rect = dab->bounds(); int x = offset.x() % m_maskBounds.width() - m_offsetX; int y = offset.y() % m_maskBounds.height() - m_offsetY; KisFillPainter fillPainter(fillDevice); fillPainter.fillRect(x - 1, y - 1, rect.width() + 2, rect.height() + 2, m_mask, m_maskBounds); fillPainter.end(); qreal pressure = m_strengthOption.apply(info); quint8 *dabData = dab->data(); KisHLineIteratorSP iter = fillDevice->createHLineIteratorNG(x, y, rect.width()); for (int row = 0; row < rect.height(); ++row) { for (int col = 0; col < rect.width(); ++col) { if (m_texturingMode == MULTIPLY) { dab->colorSpace()->multiplyAlpha(dabData, quint8(*iter->oldRawData() * pressure), 1); } else { int pressureOffset = (1.0 - pressure) * 255; qint16 maskA = *iter->oldRawData() + pressureOffset; quint8 dabA = dab->colorSpace()->opacityU8(dabData); dabA = qMax(0, (qint16)dabA - maskA); dab->colorSpace()->setOpacity(dabData, dabA, 1); } iter->nextPixel(); dabData += dab->pixelSize(); } iter->nextRow(); } } diff --git a/plugins/paintops/libpaintop/kis_texture_option.h b/plugins/paintops/libpaintop/kis_texture_option.h index 9ae3ddeac1..52d76daccb 100644 --- a/plugins/paintops/libpaintop/kis_texture_option.h +++ b/plugins/paintops/libpaintop/kis_texture_option.h @@ -1,103 +1,103 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2012 * * 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_TEXTURE_OPTION_H #define KIS_TEXTURE_OPTION_H #include #include #include #include "kis_paintop_option.h" #include "kis_pressure_texture_strength_option.h" #include class KisTextureOptionWidget; class KoPattern; class KoResource; class KisPropertiesConfiguration; class KisPaintopLodLimitations; class PAINTOP_EXPORT KisTextureOption : public KisPaintOpOption { Q_OBJECT public: explicit KisTextureOption(); virtual ~KisTextureOption(); public Q_SLOTS: - virtual void writeOptionSetting(KisPropertiesConfiguration* setting) const; - virtual void readOptionSetting(const KisPropertiesConfiguration* setting); + virtual void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + virtual void readOptionSetting(const KisPropertiesConfigurationSP setting); virtual void lodLimitations(KisPaintopLodLimitations *l) const; private Q_SLOTS: void resetGUI(KoResource*); /// called when a new pattern is selected private: KisTextureOptionWidget *m_optionWidget; }; class PAINTOP_EXPORT KisTextureProperties { public: KisTextureProperties(int levelOfDetail); enum TexturingMode { MULTIPLY, SUBTRACT }; bool m_enabled; /** * @brief apply combine the texture map with the dab * @param dab the colored, final representation of the dab, after mirroring and everything. * @param offset the position of the dab on the image. used to calculate the position of the mask pattern */ void apply(KisFixedPaintDeviceSP dab, const QPoint& offset, const KisPaintInformation & info); - void fillProperties(const KisPropertiesConfiguration *setting); + void fillProperties(const KisPropertiesConfigurationSP setting); private: qreal m_scale; int m_offsetX; int m_offsetY; TexturingMode m_texturingMode; bool m_invert; KoPattern *m_pattern; int m_cutoffLeft; int m_cutoffRight; int m_cutoffPolicy; int m_levelOfDetail; private: KisPressureTextureStrengthOption m_strengthOption; QRect m_maskBounds; // this can be different from the extent if we mask out too many pixels in a big mask! KisPaintDeviceSP m_mask; void recalculateMask(); }; #endif // KIS_TEXTURE_OPTION_H diff --git a/plugins/paintops/particle/kis_particle_paintop.cpp b/plugins/paintops/particle/kis_particle_paintop.cpp index a302c5205f..ecb8d27428 100644 --- a/plugins/paintops/particle/kis_particle_paintop.cpp +++ b/plugins/paintops/particle/kis_particle_paintop.cpp @@ -1,94 +1,94 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_particle_paintop.h" #include "kis_particle_paintop_settings.h" #include #include "kis_vec.h" #include #include #include #include #include #include #include #include #include #include "kis_particleop_option.h" #include "particle_brush.h" -KisParticlePaintOp::KisParticlePaintOp(const KisParticlePaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisParticlePaintOp::KisParticlePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); m_properties.particleCount = settings->getInt(PARTICLE_COUNT); m_properties.iterations = settings->getInt(PARTICLE_ITERATIONS); m_properties.gravity = settings->getDouble(PARTICLE_GRAVITY); m_properties.weight = settings->getDouble(PARTICLE_WEIGHT); m_properties.scale = QPointF(settings->getDouble(PARTICLE_SCALE_X), settings->getDouble(PARTICLE_SCALE_Y)); m_particleBrush.setProperties(&m_properties); m_particleBrush.initParticles(); m_first = true; } KisParticlePaintOp::~KisParticlePaintOp() { } KisSpacingInformation KisParticlePaintOp::paintAt(const KisPaintInformation& info) { KisDistanceInformation di; paintLine(info, info, &di); return di.currentSpacing(); } void KisParticlePaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); if (!painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } if (m_first) { m_particleBrush.setInitialPosition(pi1.pos()); m_first = false; } m_particleBrush.draw(m_dab, painter()->paintColor(), pi2.pos()); QRect rc = m_dab->extent(); painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_dab); } diff --git a/plugins/paintops/particle/kis_particle_paintop.h b/plugins/paintops/particle/kis_particle_paintop.h index d397d45b74..64bea4dc65 100644 --- a/plugins/paintops/particle/kis_particle_paintop.h +++ b/plugins/paintops/particle/kis_particle_paintop.h @@ -1,49 +1,49 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PARTICLE_PAINTOP_H_ #define KIS_PARTICLE_PAINTOP_H_ #include #include #include "kis_particle_paintop_settings.h" #include "particle_brush.h" class KisPainter; class KisPaintInformation; class KisParticlePaintOp : public KisPaintOp { public: - KisParticlePaintOp(const KisParticlePaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisParticlePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisParticlePaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); private: KisParticleBrushProperties m_properties; KisPaintDeviceSP m_dab; ParticleBrush m_particleBrush; bool m_first; }; #endif // KIS_PARTICLE_PAINTOP_H_ diff --git a/plugins/paintops/particle/kis_particle_paintop_settings_widget.cpp b/plugins/paintops/particle/kis_particle_paintop_settings_widget.cpp index 9880210a00..7956eed888 100644 --- a/plugins/paintops/particle/kis_particle_paintop_settings_widget.cpp +++ b/plugins/paintops/particle/kis_particle_paintop_settings_widget.cpp @@ -1,52 +1,52 @@ /* * Copyright (c) 2008 Lukáš Tvrdý * * 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_particle_paintop_settings_widget.h" #include "kis_particleop_option.h" #include "kis_particle_paintop_settings.h" #include #include #include #include KisParticlePaintOpSettingsWidget:: KisParticlePaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) { m_paintActionTypeOption = new KisPaintActionTypeOption(); m_particleOption = new KisParticleOpOption(); addPaintOpOption(m_particleOption, i18n("Brush size")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisAirbrushOption(), i18n("Airbrush")); addPaintOpOption(m_paintActionTypeOption, i18n("Painting Mode")); } KisParticlePaintOpSettingsWidget::~ KisParticlePaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisParticlePaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisParticlePaintOpSettingsWidget::configuration() const { KisParticlePaintOpSettings* config = new KisParticlePaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "particlebrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/particle/kis_particle_paintop_settings_widget.h b/plugins/paintops/particle/kis_particle_paintop_settings_widget.h index 314b1f26ba..2bcbf2c170 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" class KisPaintActionTypeOption; class KisParticleOpOption; class KisParticlePaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisParticlePaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisParticlePaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; public: KisPaintActionTypeOption* m_paintActionTypeOption; KisParticleOpOption* m_particleOption; }; #endif diff --git a/plugins/paintops/particle/kis_particleop_option.cpp b/plugins/paintops/particle/kis_particleop_option.cpp index 10d6b1bfcd..3fd87acb6d 100644 --- a/plugins/paintops/particle/kis_particleop_option.cpp +++ b/plugins/paintops/particle/kis_particleop_option.cpp @@ -1,139 +1,139 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_particleop_option.h" #include #include #include #include #include "ui_wdgparticleoptions.h" class KisParticleOpOptionsWidget: public QWidget, public Ui::WdgParticleOptions { public: KisParticleOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisParticleOpOption::KisParticleOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisParticleOpOption"); m_checkable = false; m_options = new KisParticleOpOptionsWidget(); m_options->gravSPBox->setRange(-1.0, 1.0, 3); m_options->gravSPBox->setValue(0.989); m_options->dySPBox->setRange(-10.0, 10.0, 2); m_options->dySPBox->setValue(0.3); m_options->dxSPBox->setRange(-10.0, 10.0, 2); m_options->dxSPBox->setValue(0.3); m_options->weightSPBox->setRange(0.01, 1.0, 2); m_options->weightSPBox->setValue(0.2); m_options->particleSpinBox->setRange(1.0, 500.0, 0); m_options->particleSpinBox->setValue(50); m_options->particleSpinBox->setExponentRatio(3.0); m_options->itersSPBox->setRange(1, 200, 0); m_options->itersSPBox->setValue(10); connect(m_options->particleSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->itersSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->gravSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->weightSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->dxSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->dySPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisParticleOpOption::~KisParticleOpOption() { delete m_options; } int KisParticleOpOption::particleCount() const { return m_options->particleSpinBox->value(); } qreal KisParticleOpOption::weight() const { return m_options->weightSPBox->value(); } QPointF KisParticleOpOption::scale() const { return QPointF(m_options->dxSPBox->value(), m_options->dySPBox->value()); } int KisParticleOpOption::iterations() const { return m_options->itersSPBox->value(); } qreal KisParticleOpOption::gravity() const { return m_options->gravSPBox->value(); } -void KisParticleOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisParticleOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { ParticleOption op; op.particle_count = particleCount(); op.particle_iterations = iterations(); op.particle_gravity = gravity(); op.particle_weight = weight(); op.particle_scale_x = scale().x(); op.particle_scale_y = scale().y(); op.writeOptionSetting(setting); } -void KisParticleOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisParticleOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { ParticleOption op; op.readOptionSetting(setting); m_options->particleSpinBox->setValue(op.particle_count); m_options->itersSPBox->setValue(op.particle_iterations); m_options->gravSPBox->setValue(op.particle_gravity); m_options->weightSPBox->setValue(op.particle_weight); m_options->dxSPBox->setValue(op.particle_scale_x); m_options->dySPBox->setValue(op.particle_scale_y); } void KisParticleOpOption::lodLimitations(KisPaintopLodLimitations *l) const { l->blockers << KoID("particle-brush", i18nc("PaintOp instant preview limitation", "Particle Brush (not supported)")); } diff --git a/plugins/paintops/particle/kis_particleop_option.h b/plugins/paintops/particle/kis_particleop_option.h index 65c411da4b..2fdabcc33f 100644 --- a/plugins/paintops/particle/kis_particleop_option.h +++ b/plugins/paintops/particle/kis_particleop_option.h @@ -1,81 +1,81 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_PARTICLEOP_OPTION_H #define KIS_PARTICLEOP_OPTION_H #include const QString PARTICLE_COUNT = "Particle/count"; const QString PARTICLE_GRAVITY = "Particle/gravity"; const QString PARTICLE_WEIGHT = "Particle/weight"; const QString PARTICLE_ITERATIONS = "Particle/iterations"; const QString PARTICLE_SCALE_X = "Particle/scaleX"; const QString PARTICLE_SCALE_Y = "Particle/scaleY"; class KisParticleOpOptionsWidget; class KisPaintopLodLimitations; class KisParticleOpOption : public KisPaintOpOption { public: KisParticleOpOption(); ~KisParticleOpOption(); int particleCount() const; qreal weight() const; qreal gravity() const; int iterations() const; QPointF scale() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); void lodLimitations(KisPaintopLodLimitations *l) const; private: KisParticleOpOptionsWidget * m_options; }; struct ParticleOption { int particle_count; int particle_iterations; qreal particle_gravity; qreal particle_weight; qreal particle_scale_x; qreal particle_scale_y; - void readOptionSetting(const KisPropertiesConfiguration* setting) { + void readOptionSetting(const KisPropertiesConfigurationSP setting) { particle_count = setting->getInt(PARTICLE_COUNT); particle_iterations = setting->getInt(PARTICLE_ITERATIONS); particle_gravity = setting->getDouble(PARTICLE_GRAVITY); particle_weight = setting->getDouble(PARTICLE_WEIGHT); particle_scale_x = setting->getDouble(PARTICLE_SCALE_X); particle_scale_y = setting->getDouble(PARTICLE_SCALE_Y); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(PARTICLE_COUNT, particle_count); setting->setProperty(PARTICLE_ITERATIONS, particle_iterations); setting->setProperty(PARTICLE_GRAVITY, particle_gravity); setting->setProperty(PARTICLE_WEIGHT, particle_weight); setting->setProperty(PARTICLE_SCALE_X, particle_scale_x); setting->setProperty(PARTICLE_SCALE_Y, particle_scale_y); } }; #endif diff --git a/plugins/paintops/sketch/kis_sketch_paintop.cpp b/plugins/paintops/sketch/kis_sketch_paintop.cpp index bd1331a51e..7a277a393b 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop.cpp +++ b/plugins/paintops/sketch/kis_sketch_paintop.cpp @@ -1,300 +1,300 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 Ricardo Cabello * * 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_sketch_paintop.h" #include "kis_sketch_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_lod_transform.h" #include /* * Based on Harmony project http://github.com/mrdoob/harmony/ */ // chrome : diff 0.2, sketchy : 0.3, fur: 0.5 // fur : distance / thresholdDistance // shaded: opacity per line :/ // ((1 - (d / 1000)) * 0.1 * BRUSH_PRESSURE), offset == 0 // chrome: color per line :/ //this.context.strokeStyle = "rgba(" + Math.floor(Math.random() * COLOR[0]) + ", " + Math.floor(Math.random() * COLOR[1]) + ", " + Math.floor(Math.random() * COLOR[2]) + ", " + 0.1 * BRUSH_PRESSURE + " )"; // long fur // from: count + offset * -random // to: i point - (offset * -random) + random * 2 // probability distance / thresholdDistnace // shaded: probabity : paint always - 0.0 density -KisSketchPaintOp::KisSketchPaintOp(const KisSketchPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image) +KisSketchPaintOp::KisSketchPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_sketchProperties.readOptionSetting(settings); m_brushOption.readOptionSetting(settings, true); m_densityOption.readOptionSetting(settings); m_lineWidthOption.readOptionSetting(settings); m_offsetScaleOption.readOptionSetting(settings); m_brush = m_brushOption.brush(); m_dabCache = new KisDabCache(m_brush); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_painter = 0; m_count = 0; } KisSketchPaintOp::~KisSketchPaintOp() { delete m_painter; delete m_dabCache; } void KisSketchPaintOp::drawConnection(const QPointF& start, const QPointF& end, double lineWidth) { if (lineWidth == 1.0) { m_painter->drawThickLine(start, end, lineWidth, lineWidth); } else { m_painter->drawLine(start, end, lineWidth, true); } } void KisSketchPaintOp::updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation) { QRect dstRect; m_maskDab = m_dabCache->fetchDab(m_dab->colorSpace(), painter()->paintColor(), info.pos(), KisDabShape(scale, 1.0, rotation), info, 1.0, &dstRect); m_brushBoundingBox = dstRect; m_hotSpot = QPointF(0.5 * m_brushBoundingBox.width(), 0.5 * m_brushBoundingBox.height()); } void KisSketchPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { Q_UNUSED(currentDistance); if (!m_brush || !painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); m_painter = new KisPainter(m_dab); m_painter->setPaintColor(painter()->paintColor()); } else { m_dab->clear(); } QPointF prevMouse = pi1.pos(); QPointF mousePosition = pi2.pos(); m_points.append(mousePosition); const qreal lodAdditionalScale = KisLodTransform::lodToScale(painter()->device()); const qreal scale = lodAdditionalScale * m_sizeOption.apply(pi2); if ((scale * m_brush->width()) <= 0.01 || (scale * m_brush->height()) <= 0.01) return; const qreal currentLineWidth = qMax(0.9, lodAdditionalScale * m_lineWidthOption.apply(pi2, m_sketchProperties.lineWidth)); const qreal currentOffsetScale = m_offsetScaleOption.apply(pi2, m_sketchProperties.offset); const double rotation = m_rotationOption.apply(pi2); const double currentProbability = m_densityOption.apply(pi2, m_sketchProperties.probability); // shaded: does not draw this line, chrome does, fur does if (m_sketchProperties.makeConnection) { drawConnection(prevMouse, mousePosition, currentLineWidth); } qreal thresholdDistance = 0.0; // update the mask for simple mode only once // determine the radius if (m_count == 0 && m_sketchProperties.simpleMode) { updateBrushMask(pi2, 1.0, 0.0); //m_radius = qMax(m_maskDab->bounds().width(),m_maskDab->bounds().height()) * 0.5; m_radius = 0.5 * qMax(m_brush->width(), m_brush->height()); } if (!m_sketchProperties.simpleMode) { updateBrushMask(pi2, scale, rotation); m_radius = qMax(m_maskDab->bounds().width(), m_maskDab->bounds().height()) * 0.5; thresholdDistance = pow(m_radius, 2); } if (m_sketchProperties.simpleMode) { // update the radius according scale in simple mode thresholdDistance = pow(m_radius * scale, 2); } // determine density const qreal density = thresholdDistance * currentProbability; // probability behaviour qreal probability = 1.0 - currentProbability; QColor painterColor = painter()->paintColor().toQColor(); QColor randomColor; KoColor color(m_dab->colorSpace()); int w = m_maskDab->bounds().width(); quint8 opacityU8 = 0; quint8 * pixel; qreal distance; QPoint positionInMask; QPointF diff; int size = m_points.size(); // MAIN LOOP for (int i = 0; i < size; i++) { diff = m_points.at(i) - mousePosition; distance = diff.x() * diff.x() + diff.y() * diff.y(); // circle test bool makeConnection = false; if (m_sketchProperties.simpleMode) { if (distance < thresholdDistance) { makeConnection = true; } // mask test } else { if (m_brushBoundingBox.contains(m_points.at(i))) { positionInMask = (diff + m_hotSpot).toPoint(); uint pos = ((positionInMask.y() * w + positionInMask.x()) * m_maskDab->pixelSize()); if (pos < m_maskDab->allocatedPixels() * m_maskDab->pixelSize()) { pixel = m_maskDab->data() + pos; opacityU8 = m_maskDab->colorSpace()->opacityU8(pixel); if (opacityU8 != 0) { makeConnection = true; } } } } if (!makeConnection) { // check next point continue; } if (m_sketchProperties.distanceDensity) { probability = distance / density; } KisRandomSourceSP randomSource = pi2.randomSource(); // density check if (randomSource->generateNormalized() >= probability) { QPointF offsetPt = diff * currentOffsetScale; if (m_sketchProperties.randomRGB) { /** * Since the order of calculation of function * parameters is not defined by C++ standard, we * should generate values in an external code snippet * which has a definite order of execution. */ qreal r1 = randomSource->generateNormalized(); qreal r2 = randomSource->generateNormalized(); qreal r3 = randomSource->generateNormalized(); // some color transformation per line goes here randomColor.setRgbF(r1 * painterColor.redF(), r2 * painterColor.greenF(), r3 * painterColor.blueF()); color.fromQColor(randomColor); m_painter->setPaintColor(color); } // distance based opacity quint8 opacity = OPACITY_OPAQUE_U8; if (m_sketchProperties.distanceOpacity) { opacity *= qRound((1.0 - (distance / thresholdDistance))); } if (m_sketchProperties.randomOpacity) { opacity *= randomSource->generateNormalized(); } m_painter->setOpacity(opacity); if (m_sketchProperties.magnetify) { drawConnection(mousePosition + offsetPt, m_points.at(i) - offsetPt, currentLineWidth); } else { drawConnection(mousePosition + offsetPt, mousePosition - offsetPt, currentLineWidth); } } }// end of MAIN LOOP m_count++; QRect rc = m_dab->extent(); quint8 origOpacity = m_opacityOption.apply(painter(), pi2); painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); } KisSpacingInformation KisSketchPaintOp::paintAt(const KisPaintInformation& info) { KisDistanceInformation di; paintLine(info, info, &di); return di.currentSpacing(); } diff --git a/plugins/paintops/sketch/kis_sketch_paintop.h b/plugins/paintops/sketch/kis_sketch_paintop.h index 61ed5edb87..0f4995149f 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop.h +++ b/plugins/paintops/sketch/kis_sketch_paintop.h @@ -1,84 +1,84 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_SKETCH_PAINTOP_H_ #define KIS_SKETCH_PAINTOP_H_ #include #include #include "kis_density_option.h" #include "kis_sketchop_option.h" #include "kis_sketch_paintop_settings.h" #include "kis_painter.h" #include #include #include #include "kis_linewidth_option.h" #include "kis_offset_scale_option.h" class KisDabCache; class KisSketchPaintOp : public KisPaintOp { public: - KisSketchPaintOp(const KisSketchPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisSketchPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); ~KisSketchPaintOp(); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); KisSpacingInformation paintAt(const KisPaintInformation& info); private: // pixel buffer KisPaintDeviceSP m_dab; // mask detection area KisFixedPaintDeviceSP m_maskDab; QRectF m_brushBoundingBox; QPointF m_hotSpot; // simple mode qreal m_radius; KisPressureOpacityOption m_opacityOption; KisPressureSizeOption m_sizeOption; KisPressureRotationOption m_rotationOption; KisDensityOption m_densityOption; KisLineWidthOption m_lineWidthOption; KisOffsetScaleOption m_offsetScaleOption; KisBrushOption m_brushOption; SketchProperties m_sketchProperties; QVector m_points; int m_count; KisPainter * m_painter; KisBrushSP m_brush; KisDabCache *m_dabCache; private: void drawConnection(const QPointF &start, const QPointF &end, double lineWidth); void updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation); }; #endif // KIS_SKETCH_PAINTOP_H_ diff --git a/plugins/paintops/sketch/kis_sketch_paintop_settings.cpp b/plugins/paintops/sketch/kis_sketch_paintop_settings.cpp index da5ba34a80..43588bbf1e 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop_settings.cpp +++ b/plugins/paintops/sketch/kis_sketch_paintop_settings.cpp @@ -1,74 +1,74 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_sketch_paintop_settings.h" #include #include #include #include "kis_current_outline_fetcher.h" KisSketchPaintOpSettings::KisSketchPaintOpSettings() { } bool KisSketchPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } bool KisSketchPaintOpSettings::isAirbrushing() const { return getBool(AIRBRUSH_ENABLED); } int KisSketchPaintOpSettings::rate() const { return getInt(AIRBRUSH_RATE); } -QPainterPath KisSketchPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisSketchPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { bool isSimpleMode = getBool(SKETCH_USE_SIMPLE_MODE); if (!isSimpleMode) { return KisBrushBasedPaintOpSettings::brushOutline(info, mode); } KisBrushBasedPaintopOptionWidget *widget = dynamic_cast(optionsWidget()); QPainterPath path; if (widget && (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline)) { KisBrushSP brush = widget->brush(); // just circle supported qreal diameter = qMax(brush->width(), brush->height()); path = ellipseOutline(diameter, diameter, 1.0, 0.0/*brush->scale(), brush->angle()*/); QPainterPath tiltLine = makeTiltIndicator(info, path.boundingRect().center(), diameter * 0.5, 3.0); path = outlineFetcher()->fetchOutline(info, this, path); if (mode == CursorTiltOutline) { tiltLine.translate(info.pos()); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, 1.0, 0.0, true, path.boundingRect().center().x(), path.boundingRect().center().y())); } } return path; } diff --git a/plugins/paintops/sketch/kis_sketch_paintop_settings.h b/plugins/paintops/sketch/kis_sketch_paintop_settings.h index 914d8a45fe..28609141bb 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop_settings.h +++ b/plugins/paintops/sketch/kis_sketch_paintop_settings.h @@ -1,44 +1,44 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_SKETCH_PAINTOP_SETTINGS_H_ #define KIS_SKETCH_PAINTOP_SETTINGS_H_ #include #include #include "kis_sketch_paintop_settings_widget.h" #include class KisSketchPaintOpSettings : public KisBrushBasedPaintOpSettings { public: KisSketchPaintOpSettings(); virtual ~KisSketchPaintOpSettings() {} - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); bool paintIncremental(); bool isAirbrushing() const; int rate() const; }; #endif diff --git a/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.cpp b/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.cpp index 3cd3a40ee0..d3bdf7b3ea 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.cpp +++ b/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.cpp @@ -1,87 +1,87 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_sketch_paintop_settings_widget.h" #include "kis_sketchop_option.h" #include "kis_sketch_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include "kis_density_option.h" #include "kis_linewidth_option.h" #include "kis_offset_scale_option.h" KisSketchPaintOpSettingsWidget::KisSketchPaintOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) { m_sketchOption = new KisSketchOpOption(); addPaintOpOption(m_sketchOption, i18n("Brush size")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisCurveOptionWidget(new KisLineWidthOption() , i18n("0%"), i18n("100%")), i18n("Line width")); addPaintOpOption(new KisCurveOptionWidget(new KisOffsetScaleOption(), i18n("0%"), i18n("100%")), i18n("Offset scale")); addPaintOpOption(new KisCurveOptionWidget(new KisDensityOption(), i18n("0%"), i18n("100%")), i18n("Density")); addPaintOpOption(new KisAirbrushOption(false), i18n("Airbrush")); m_paintActionType = new KisPaintActionTypeOption(); KisPropertiesConfiguration defaultSetting; defaultSetting.setProperty("PaintOpAction", BUILDUP); m_paintActionType->readOptionSetting(&defaultSetting); addPaintOpOption(m_paintActionType, i18n("Painting Mode")); - KisPropertiesConfiguration* reconfigurationCourier = configuration(); + KisPropertiesConfigurationSP reconfigurationCourier = configuration(); QDomDocument xMLAnalyzer(""); xMLAnalyzer.setContent(reconfigurationCourier->getString("brush_definition")); QDomElement firstTag = xMLAnalyzer.documentElement(); QDomElement firstTagsChild = firstTag.elementsByTagName("MaskGenerator").item(0).toElement(); firstTagsChild.attributeNode("diameter").setValue("128"); reconfigurationCourier->setProperty("brush_definition", xMLAnalyzer.toString()); setConfiguration(reconfigurationCourier); delete reconfigurationCourier; } KisSketchPaintOpSettingsWidget::~ KisSketchPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisSketchPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisSketchPaintOpSettingsWidget::configuration() const { KisSketchPaintOpSettings* config = new KisSketchPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "sketchbrush"); // XXX: make this a const id string writeConfiguration(config); return config; } diff --git a/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.h b/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.h index 1d586d3717..c484ce4131 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.h +++ b/plugins/paintops/sketch/kis_sketch_paintop_settings_widget.h @@ -1,45 +1,45 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_SKETCHPAINTOP_SETTINGS_WIDGET_H_ #define KIS_SKETCHPAINTOP_SETTINGS_WIDGET_H_ #include #include #include "ui_wdgsketchoptions.h" class KisPaintActionTypeOption; class KisSketchOpOption; class KisSketchPaintOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisSketchPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisSketchPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; public: KisSketchOpOption* m_sketchOption; KisPaintActionTypeOption* m_paintActionType; }; #endif diff --git a/plugins/paintops/sketch/kis_sketchop_option.cpp b/plugins/paintops/sketch/kis_sketchop_option.cpp index c440292303..4e744e4146 100644 --- a/plugins/paintops/sketch/kis_sketchop_option.cpp +++ b/plugins/paintops/sketch/kis_sketchop_option.cpp @@ -1,108 +1,108 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_sketchop_option.h" #include "ui_wdgsketchoptions.h" #include class KisSketchOpOptionsWidget: public QWidget, public Ui::WdgSketchOptions { public: KisSketchOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisSketchOpOption::KisSketchOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisSketchOpOption"); m_checkable = false; m_options = new KisSketchOpOptionsWidget(); // initialize slider values m_options->lineWidthSPBox->setRange(1.0, 100.0, 0); m_options->lineWidthSPBox->setValue(1.0); m_options->lineWidthSPBox->setSuffix(i18n(" px")); m_options->lineWidthSPBox->setExponentRatio(1.5); m_options->offsetSPBox->setRange(0.0, 200.0, 0); m_options->offsetSPBox->setValue(30.0); m_options->offsetSPBox->setSuffix("%"); m_options->densitySPBox->setRange(0.0, 100.0, 0); m_options->densitySPBox->setValue(50.0); m_options->densitySPBox->setSuffix("%"); connect(m_options->offsetSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->lineWidthSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->densitySPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->simpleModeCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->connectionCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->magnetifyCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->randomRGBCHbox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->randomOpacityCHbox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->distanceDensityCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->distanceOpacityCHbox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisSketchOpOption::~KisSketchOpOption() { // delete m_options; } -void KisSketchOpOption::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisSketchOpOption::writeOptionSetting(KisPropertiesConfigurationSP settings) const { settings->setProperty(SKETCH_OFFSET, m_options->offsetSPBox->value()); settings->setProperty(SKETCH_PROBABILITY, m_options->densitySPBox->value() * 0.01); settings->setProperty(SKETCH_USE_SIMPLE_MODE, m_options->simpleModeCHBox->isChecked()); settings->setProperty(SKETCH_MAKE_CONNECTION, m_options->connectionCHBox->isChecked()); settings->setProperty(SKETCH_MAGNETIFY, m_options->magnetifyCHBox->isChecked()); settings->setProperty(SKETCH_RANDOM_RGB, m_options->randomRGBCHbox->isChecked()); settings->setProperty(SKETCH_LINE_WIDTH, m_options->lineWidthSPBox->value()); settings->setProperty(SKETCH_RANDOM_OPACITY, m_options->randomOpacityCHbox->isChecked()); settings->setProperty(SKETCH_DISTANCE_DENSITY, m_options->distanceDensityCHBox->isChecked()); settings->setProperty(SKETCH_DISTANCE_OPACITY, m_options->distanceOpacityCHbox->isChecked()); } -void KisSketchOpOption::readOptionSetting(const KisPropertiesConfiguration* settings) +void KisSketchOpOption::readOptionSetting(const KisPropertiesConfigurationSP settings) { m_options->offsetSPBox->setValue(settings->getDouble(SKETCH_OFFSET)); m_options->simpleModeCHBox->setChecked(settings->getBool(SKETCH_USE_SIMPLE_MODE)); m_options->connectionCHBox->setChecked(settings->getBool(SKETCH_MAKE_CONNECTION)); m_options->magnetifyCHBox->setChecked(settings->getBool(SKETCH_MAGNETIFY)); m_options->lineWidthSPBox->setValue(settings->getInt(SKETCH_LINE_WIDTH)); m_options->densitySPBox->setValue(settings->getDouble(SKETCH_PROBABILITY) * 100.0); m_options->randomRGBCHbox->setChecked(settings->getBool(SKETCH_RANDOM_RGB)); m_options->randomOpacityCHbox->setChecked(settings->getBool(SKETCH_RANDOM_OPACITY)); m_options->distanceDensityCHBox->setChecked(settings->getBool(SKETCH_DISTANCE_DENSITY)); m_options->distanceOpacityCHbox->setChecked(settings->getBool(SKETCH_DISTANCE_OPACITY)); } void KisSketchOpOption::lodLimitations(KisPaintopLodLimitations *l) const { l->limitations << KoID("sketch-brush", i18nc("PaintOp instant preview limitation", "Sketch brush (differences in connecting lines are possible)")); } diff --git a/plugins/paintops/sketch/kis_sketchop_option.h b/plugins/paintops/sketch/kis_sketchop_option.h index bd98fab047..3b986a7189 100644 --- a/plugins/paintops/sketch/kis_sketchop_option.h +++ b/plugins/paintops/sketch/kis_sketchop_option.h @@ -1,84 +1,84 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_SKETCHOP_OPTION_H #define KIS_SKETCHOP_OPTION_H #include const QString SKETCH_PROBABILITY = "Sketch/probability"; const QString SKETCH_DISTANCE_DENSITY = "Sketch/distanceDensity"; const QString SKETCH_OFFSET = "Sketch/offset"; const QString SKETCH_USE_SIMPLE_MODE = "Sketch/simpleMode"; const QString SKETCH_MAKE_CONNECTION = "Sketch/makeConnection"; const QString SKETCH_MAGNETIFY = "Sketch/magnetify"; const QString SKETCH_LINE_WIDTH = "Sketch/lineWidth"; const QString SKETCH_RANDOM_RGB = "Sketch/randomRGB"; const QString SKETCH_RANDOM_OPACITY = "Sketch/randomOpacity"; const QString SKETCH_DISTANCE_OPACITY = "Sketch/distanceOpacity"; class KisSketchOpOptionsWidget; class KisSketchOpOption : public KisPaintOpOption { public: KisSketchOpOption(); ~KisSketchOpOption(); void setThreshold(int radius) const; int threshold() const; - void writeOptionSetting(KisPropertiesConfiguration* settings) const; - void readOptionSetting(const KisPropertiesConfiguration* settings); + void writeOptionSetting(KisPropertiesConfigurationSP settings) const; + void readOptionSetting(const KisPropertiesConfigurationSP settings); void lodLimitations(KisPaintopLodLimitations *l) const; private: KisSketchOpOptionsWidget * m_options; }; class SketchProperties { public: qreal offset; // perc qreal probability; // perc bool simpleMode; bool makeConnection; bool magnetify; bool randomRGB; bool randomOpacity; bool distanceOpacity; bool distanceDensity; int lineWidth; // px - void readOptionSetting(const KisPropertiesConfiguration* settings) { + void readOptionSetting(const KisPropertiesConfigurationSP settings) { probability = settings->getDouble(SKETCH_PROBABILITY); offset = settings->getDouble(SKETCH_OFFSET) * 0.01; lineWidth = settings->getInt(SKETCH_LINE_WIDTH); simpleMode = settings->getBool(SKETCH_USE_SIMPLE_MODE); makeConnection = settings->getBool(SKETCH_MAKE_CONNECTION); magnetify = settings->getBool(SKETCH_MAGNETIFY); randomRGB = settings->getBool(SKETCH_RANDOM_RGB); randomOpacity = settings->getBool(SKETCH_RANDOM_OPACITY); distanceDensity = settings->getBool(SKETCH_DISTANCE_DENSITY); distanceOpacity = settings->getBool(SKETCH_DISTANCE_OPACITY); } }; #endif diff --git a/plugins/paintops/spray/kis_spray_paintop.cpp b/plugins/paintops/spray/kis_spray_paintop.cpp index 5d83c8ec60..d431f5a394 100644 --- a/plugins/paintops/spray/kis_spray_paintop.cpp +++ b/plugins/paintops/spray/kis_spray_paintop.cpp @@ -1,131 +1,131 @@ /* * Copyright (c) 2008-2012 Lukáš Tvrdý * * 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_spray_paintop.h" #include "kis_spray_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -KisSprayPaintOp::KisSprayPaintOp(const KisSprayPaintOpSettings *settings, KisPainter *painter, KisNodeSP node, KisImageSP image) +KisSprayPaintOp::KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) - , m_settings(settings) + , m_settings(static_cast(const_cast(settings.data()))) , m_isPresetValid(true) , m_node(node) { Q_ASSERT(settings); Q_ASSERT(painter); Q_UNUSED(image); m_rotationOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_rotationOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_brushOption.readOptionSetting(settings, true); m_colorProperties.fillProperties(settings); m_properties.readOptionSetting(settings); // first load tip properties as shape properties are dependent on diameter/scale/aspect m_shapeProperties.loadSettings(settings, m_properties.diameter * m_properties.scale, m_properties.diameter * m_properties.aspect * m_properties.scale); // TODO: what to do with proportional sizes? m_shapeDynamicsProperties.loadSettings(settings); if (!m_shapeProperties.enabled && !m_brushOption.brush()) { // in case the preset does not contain the definition for KisBrush m_isPresetValid = false; dbgKrita << "Preset is not valid. Painting is not possible. Use the preset editor to fix current brush engine preset."; } m_sprayBrush.setProperties(&m_properties, &m_colorProperties, &m_shapeProperties, &m_shapeDynamicsProperties, m_brushOption.brush()); m_sprayBrush.setFixedDab(cachedDab()); // spacing if ((m_properties.diameter * 0.5) > 1) { m_ySpacing = m_xSpacing = m_properties.diameter * 0.5 * m_properties.spacing; } else { m_ySpacing = m_xSpacing = 1.0; } m_spacing = m_xSpacing; } KisSprayPaintOp::~KisSprayPaintOp() { } KisSpacingInformation KisSprayPaintOp::paintAt(const KisPaintInformation& info) { if (!painter() || !m_isPresetValid) { return KisSpacingInformation(m_spacing); } if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } qreal rotation = m_rotationOption.apply(info); quint8 origOpacity = m_opacityOption.apply(painter(), info); // Spray Brush is capable of working with zero scale, // so no additional checks for 'zero'ness are needed const qreal scale = m_sizeOption.apply(info); const qreal additionalScale = KisLodTransform::lodToScale(painter()->device()); m_sprayBrush.paint(m_dab, m_node->paintDevice(), info, rotation, scale, additionalScale, painter()->paintColor(), painter()->backgroundColor()); QRect rc = m_dab->extent(); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); return KisSpacingInformation(m_spacing * additionalScale); } diff --git a/plugins/paintops/spray/kis_spray_paintop.h b/plugins/paintops/spray/kis_spray_paintop.h index 0e26bcc90d..f19320057f 100644 --- a/plugins/paintops/spray/kis_spray_paintop.h +++ b/plugins/paintops/spray/kis_spray_paintop.h @@ -1,64 +1,64 @@ /* * Copyright (c) 2008-2012 Lukáš Tvrdý * * 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_SPRAY_PAINTOP_H_ #define KIS_SPRAY_PAINTOP_H_ #include #include #include "spray_brush.h" #include "kis_spray_paintop_settings.h" #include "kis_brush_option.h" #include #include #include class KisPainter; class KisSprayPaintOp : public KisPaintOp { public: - KisSprayPaintOp(const KisSprayPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image); + KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisSprayPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info); private: KisShapeProperties m_shapeProperties; KisSprayProperties m_properties; KisShapeDynamicsProperties m_shapeDynamicsProperties; KisColorProperties m_colorProperties; KisBrushOption m_brushOption; - const KisSprayPaintOpSettings *m_settings; + KisSprayPaintOpSettingsSP m_settings; KisPaintDeviceSP m_dab; SprayBrush m_sprayBrush; qreal m_xSpacing, m_ySpacing, m_spacing; bool m_isPresetValid; KisPressureRotationOption m_rotationOption; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisNodeSP m_node; }; #endif // KIS_SPRAY_PAINTOP_H_ diff --git a/plugins/paintops/spray/kis_spray_paintop_settings.cpp b/plugins/paintops/spray/kis_spray_paintop_settings.cpp index 54c64e410a..fea4319b20 100644 --- a/plugins/paintops/spray/kis_spray_paintop_settings.cpp +++ b/plugins/paintops/spray/kis_spray_paintop_settings.cpp @@ -1,211 +1,222 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "kis_spray_paintop_settings.h" #include "kis_sprayop_option.h" #include "kis_spray_shape_option.h" #include struct KisSprayPaintOpSettings::Private { QList uniformProperties; }; KisSprayPaintOpSettings::KisSprayPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION), m_d(new Private) { } KisSprayPaintOpSettings::~KisSprayPaintOpSettings() { } bool KisSprayPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } bool KisSprayPaintOpSettings::isAirbrushing() const { return getBool(AIRBRUSH_ENABLED); } int KisSprayPaintOpSettings::rate() const { return getInt(AIRBRUSH_RATE); } -QPainterPath KisSprayPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const +QPainterPath KisSprayPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) { QPainterPath path; if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) { qreal width = getInt(SPRAY_DIAMETER); qreal height = getInt(SPRAY_DIAMETER) * getDouble(SPRAY_ASPECT); path = ellipseOutline(width, height, getDouble(SPRAY_SCALE), getDouble(SPRAY_ROTATION)); + + QPainterPath tiltLine; + QLineF tiltAngle(QPointF(0.0,0.0), QPointF(0.0,width)); + tiltAngle.setLength(qMax(width*0.5, 50.0) * (1 - info.tiltElevation(info, 60.0, 60.0, true))); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))-3.0); + tiltLine.moveTo(tiltAngle.p1()); + tiltLine.lineTo(tiltAngle.p2()); + tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))+3.0); + tiltLine.lineTo(tiltAngle.p2()); + tiltLine.lineTo(tiltAngle.p1()); + path = outlineFetcher()->fetchOutline(info, this, path); if (mode == CursorTiltOutline) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), width * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_sprayop_option.h" #include "kis_standard_uniform_properties_factory.h" QList KisSprayPaintOpSettings::uniformProperties() { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spacing", i18n("Spacing"), this, 0); prop->setRange(0.01, 10); prop->setSingleStep(0.01); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.spacing); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); option.spacing = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "spray_particlecount", i18n("Particle Count"), this, 0); prop->setRange(0, 1000); prop->setExponentRatio(3); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.particleCount)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); option.particleCount = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); return !option.useDensity; }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spray_density", i18n("Density"), this, 0); prop->setRange(0.1, 100); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setExponentRatio(3); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.coverage); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); option.coverage = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { KisSprayProperties option; option.readOptionSetting(prop->settings().data()); return option.useDensity; }); QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties()) { if (prop->id() == opacity.id() || prop->id() == size.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/spray/kis_spray_paintop_settings.h b/plugins/paintops/spray/kis_spray_paintop_settings.h index 9da8eca8b0..6320fb5d65 100644 --- a/plugins/paintops/spray/kis_spray_paintop_settings.h +++ b/plugins/paintops/spray/kis_spray_paintop_settings.h @@ -1,55 +1,61 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_SPRAY_PAINTOP_SETTINGS_H_ #define KIS_SPRAY_PAINTOP_SETTINGS_H_ #include #include #include #include #include "kis_spray_paintop_settings_widget.h" class KisSprayPaintOpSettings : public KisOutlineGenerationPolicy { public: KisSprayPaintOpSettings(); - ~KisSprayPaintOpSettings(); + virtual ~KisSprayPaintOpSettings(); - - QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode) const; + QPainterPath brushOutline(const KisPaintInformation &info, OutlineMode mode); QString modelName() const { return "airbrush"; } bool paintIncremental(); bool isAirbrushing() const; int rate() const; +protected: + QList uniformProperties(); private: + Q_DISABLE_COPY(KisSprayPaintOpSettings) + struct Private; const QScopedPointer m_d; + }; +typedef KisSharedPtr KisSprayPaintOpSettingsSP; + #endif diff --git a/plugins/paintops/spray/kis_spray_paintop_settings_widget.cpp b/plugins/paintops/spray/kis_spray_paintop_settings_widget.cpp index d12db6724e..342d79cb4a 100644 --- a/plugins/paintops/spray/kis_spray_paintop_settings_widget.cpp +++ b/plugins/paintops/spray/kis_spray_paintop_settings_widget.cpp @@ -1,80 +1,80 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_spray_paintop_settings_widget.h" #include "kis_sprayop_option.h" #include "kis_spray_paintop_settings.h" #include "kis_spray_shape_option.h" #include #include #include #include #include #include #include #include #include "kis_spray_shape_dynamics.h" #include #include KisSprayPaintOpSettingsWidget:: KisSprayPaintOpSettingsWidget(QWidget* parent) : KisPaintOpSettingsWidget(parent) , m_sprayArea(new KisSprayOpOption()) { addPaintOpOption(m_sprayArea, i18n("Spray Area")); addPaintOpOption(new KisSprayShapeOption(), i18n("Spray shape")); addPaintOpOption(new KisBrushOptionWidget(), i18n("Brush Tip")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisSprayShapeDynamicsOption(), i18n("Shape dynamics")); addPaintOpOption(new KisColorOption(), i18n("Color options")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisAirbrushOption(), i18n("Airbrush")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); } KisSprayPaintOpSettingsWidget::~ KisSprayPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisSprayPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisSprayPaintOpSettingsWidget::configuration() const { KisSprayPaintOpSettings* config = new KisSprayPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "spraybrush"); // XXX: make this a const id string writeConfiguration(config); return config; } void KisSprayPaintOpSettingsWidget::changePaintOpSize(qreal x, qreal y) { Q_UNUSED(y); m_sprayArea->setDiameter(m_sprayArea->diameter() + qRound(x)); } QSizeF KisSprayPaintOpSettingsWidget::paintOpSize() const { qreal width = m_sprayArea->diameter(); qreal height = width * m_sprayArea->brushAspect(); return QSizeF(width, height); } diff --git a/plugins/paintops/spray/kis_spray_paintop_settings_widget.h b/plugins/paintops/spray/kis_spray_paintop_settings_widget.h index 9f3fef70d7..ba398fe590 100644 --- a/plugins/paintops/spray/kis_spray_paintop_settings_widget.h +++ b/plugins/paintops/spray/kis_spray_paintop_settings_widget.h @@ -1,43 +1,43 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_SPRAYPAINTOP_SETTINGS_WIDGET_H_ #define KIS_SPRAYPAINTOP_SETTINGS_WIDGET_H_ #include class KisSprayOpOption; class KisSprayPaintOpSettingsWidget : public KisPaintOpSettingsWidget { Q_OBJECT public: KisSprayPaintOpSettingsWidget(QWidget* parent = 0); virtual ~KisSprayPaintOpSettingsWidget(); virtual void changePaintOpSize(qreal x, qreal y); virtual QSizeF paintOpSize() const; - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; public: KisSprayOpOption* m_sprayArea; }; #endif diff --git a/plugins/paintops/spray/kis_spray_shape_dynamics.cpp b/plugins/paintops/spray/kis_spray_shape_dynamics.cpp index f7dd5622ae..ef7055aeae 100644 --- a/plugins/paintops/spray/kis_spray_shape_dynamics.cpp +++ b/plugins/paintops/spray/kis_spray_shape_dynamics.cpp @@ -1,131 +1,131 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_spray_shape_dynamics.h" #include #include "ui_wdgshapedynamicsoptions.h" class KisShapeDynamicsOptionsWidget: public QWidget, public Ui::WdgShapeDynamicsOptions { public: KisShapeDynamicsOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisSprayShapeDynamicsOption::KisSprayShapeDynamicsOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, true) { setObjectName("KisSprayShapeDynamicsOption"); m_checkable = true; m_options = new KisShapeDynamicsOptionsWidget(); // UI signals connect(m_options->fixedRotation, SIGNAL(toggled(bool)), m_options->fixedAngleBox, SLOT(setEnabled(bool))); connect(m_options->randomRotation, SIGNAL(toggled(bool)), m_options->randomAngleWeight, SLOT(setEnabled(bool))); connect(m_options->followCursor, SIGNAL(toggled(bool)), m_options->followCursorWeight, SLOT(setEnabled(bool))); connect(m_options->drawingAngle, SIGNAL(toggled(bool)), m_options->drawingAngleWeight, SLOT(setEnabled(bool))); setupBrushPreviewSignals(); setConfigurationPage(m_options); } void KisSprayShapeDynamicsOption::setupBrushPreviewSignals() { // initialize sliders m_options->drawingAngleWeight->setRange(0.0, 1.0, 2); m_options->drawingAngleWeight->setDisabled(true); m_options->followCursorWeight->setRange(0.0, 1.0, 2); m_options->followCursorWeight->setDisabled(true); m_options->randomAngleWeight->setRange(0.0, 1.0, 2); m_options->randomAngleWeight->setDisabled(true); m_options->fixedAngleBox->setRange(0, 360, 0); m_options->fixedAngleBox->setValue(30); m_options->fixedAngleBox->setSuffix(QChar(Qt::Key_degree)); m_options->fixedAngleBox->setDisabled(true); connect(m_options->randomSizeCHBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->fixedRotation, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->fixedAngleBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->randomRotation, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->randomAngleWeight, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->followCursor, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->followCursorWeight, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->drawingAngle, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->drawingAngleWeight, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); } KisSprayShapeDynamicsOption::~KisSprayShapeDynamicsOption() { delete m_options; } -void KisSprayShapeDynamicsOption::writeOptionSetting(KisPropertiesConfiguration* settings) const +void KisSprayShapeDynamicsOption::writeOptionSetting(KisPropertiesConfigurationSP settings) const { settings->setProperty(SHAPE_DYNAMICS_VERSION, "2.3"); settings->setProperty(SHAPE_DYNAMICS_ENABLED, isChecked()); settings->setProperty(SHAPE_DYNAMICS_RANDOM_SIZE, m_options->randomSizeCHBox->isChecked()); settings->setProperty(SHAPE_DYNAMICS_FIXED_ROTATION, m_options->fixedRotation->isChecked()); settings->setProperty(SHAPE_DYNAMICS_FIXED_ANGEL, m_options->fixedAngleBox->value()); settings->setProperty(SHAPE_DYNAMICS_RANDOM_ROTATION, m_options->randomRotation->isChecked()); settings->setProperty(SHAPE_DYNAMICS_RANDOM_ROTATION_WEIGHT, m_options->randomAngleWeight->value()); settings->setProperty(SHAPE_DYNAMICS_FOLLOW_CURSOR, m_options->followCursor->isChecked()); settings->setProperty(SHAPE_DYNAMICS_FOLLOW_CURSOR_WEIGHT, m_options->followCursorWeight->value()); settings->setProperty(SHAPE_DYNAMICS_DRAWING_ANGLE, m_options->drawingAngle->isChecked()); settings->setProperty(SHAPE_DYNAMICS_DRAWING_ANGLE_WEIGHT, m_options->drawingAngleWeight->value()); } -void KisSprayShapeDynamicsOption::readOptionSetting(const KisPropertiesConfiguration* settings) +void KisSprayShapeDynamicsOption::readOptionSetting(const KisPropertiesConfigurationSP settings) { // backward compatibility with 2.2 if (settings->getString(SHAPE_DYNAMICS_VERSION, "2.2") == "2.2") { setChecked(true); m_options->randomSizeCHBox->setChecked(settings->getBool(SPRAYSHAPE_RANDOM_SIZE)); m_options->fixedRotation->setChecked(settings->getBool(SPRAYSHAPE_FIXED_ROTATION)); m_options->fixedAngleBox->setValue(settings->getDouble(SPRAYSHAPE_FIXED_ANGEL)); m_options->followCursor->setChecked(settings->getBool(SPRAYSHAPE_FOLLOW_CURSOR)); m_options->followCursorWeight->setValue(settings->getDouble(SPRAYSHAPE_FOLLOW_CURSOR_WEIGHT)); m_options->drawingAngle->setChecked(settings->getBool(SPRAYSHAPE_DRAWING_ANGLE)); m_options->drawingAngleWeight->setValue(settings->getDouble(SPRAYSHAPE_DRAWING_ANGLE_WEIGHT)); m_options->randomRotation->setChecked(settings->getBool(SPRAYSHAPE_RANDOM_ROTATION)); m_options->randomAngleWeight->setValue(settings->getDouble(SPRAYSHAPE_RANDOM_ROTATION_WEIGHT)); } else { setChecked(settings->getBool(SHAPE_DYNAMICS_ENABLED)); m_options->randomSizeCHBox->setChecked(settings->getBool(SHAPE_DYNAMICS_RANDOM_SIZE)); m_options->fixedRotation->setChecked(settings->getBool(SHAPE_DYNAMICS_FIXED_ROTATION)); m_options->fixedAngleBox->setValue(settings->getDouble(SHAPE_DYNAMICS_FIXED_ANGEL)); m_options->followCursor->setChecked(settings->getBool(SHAPE_DYNAMICS_FOLLOW_CURSOR)); m_options->followCursorWeight->setValue(settings->getDouble(SHAPE_DYNAMICS_FOLLOW_CURSOR_WEIGHT)); m_options->drawingAngle->setChecked(settings->getBool(SHAPE_DYNAMICS_DRAWING_ANGLE)); m_options->drawingAngleWeight->setValue(settings->getDouble(SHAPE_DYNAMICS_DRAWING_ANGLE_WEIGHT)); m_options->randomRotation->setChecked(settings->getBool(SHAPE_DYNAMICS_RANDOM_ROTATION)); m_options->randomAngleWeight->setValue(settings->getDouble(SHAPE_DYNAMICS_RANDOM_ROTATION_WEIGHT)); } } diff --git a/plugins/paintops/spray/kis_spray_shape_dynamics.h b/plugins/paintops/spray/kis_spray_shape_dynamics.h index 8169a271ab..6b594d3a63 100644 --- a/plugins/paintops/spray/kis_spray_shape_dynamics.h +++ b/plugins/paintops/spray/kis_spray_shape_dynamics.h @@ -1,122 +1,122 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_SPRAY_SHAPE_DYNAMICS_OPTION_H #define KIS_SPRAY_SHAPE_DYNAMICS_OPTION_H #include const QString SHAPE_DYNAMICS_VERSION = "ShapeDynamicsVersion"; // Old Krita 2.2.x strings for backward compatibility const QString SPRAYSHAPE_RANDOM_SIZE = "SprayShape/randomSize"; const QString SPRAYSHAPE_FIXED_ROTATION = "SprayShape/fixedRotation"; const QString SPRAYSHAPE_FIXED_ANGEL = "SprayShape/fixedAngle"; const QString SPRAYSHAPE_RANDOM_ROTATION = "SprayShape/randomRotation"; const QString SPRAYSHAPE_RANDOM_ROTATION_WEIGHT = "SprayShape/randomRotationWeight"; const QString SPRAYSHAPE_FOLLOW_CURSOR = "SprayShape/followCursor"; const QString SPRAYSHAPE_FOLLOW_CURSOR_WEIGHT = "SprayShape/followCursorWeigth"; const QString SPRAYSHAPE_DRAWING_ANGLE = "SprayShape/followDrawingAngle"; const QString SPRAYSHAPE_DRAWING_ANGLE_WEIGHT = "SprayShape/followDrawingAngleWeigth"; // My intention is to have the option dialog more general so that it can be share // hence the suffix ShapeDynamics const QString SHAPE_DYNAMICS_ENABLED = "ShapeDynamics/enabled"; const QString SHAPE_DYNAMICS_RANDOM_SIZE = "ShapeDynamics/randomSize"; const QString SHAPE_DYNAMICS_FIXED_ROTATION = "ShapeDynamics/fixedRotation"; const QString SHAPE_DYNAMICS_FIXED_ANGEL = "ShapeDynamics/fixedAngle"; const QString SHAPE_DYNAMICS_RANDOM_ROTATION = "ShapeDynamics/randomRotation"; const QString SHAPE_DYNAMICS_RANDOM_ROTATION_WEIGHT = "ShapeDynamics/randomRotationWeight"; const QString SHAPE_DYNAMICS_FOLLOW_CURSOR = "ShapeDynamics/followCursor"; const QString SHAPE_DYNAMICS_FOLLOW_CURSOR_WEIGHT = "ShapeDynamics/followCursorWeigth"; const QString SHAPE_DYNAMICS_DRAWING_ANGLE = "ShapeDynamics/followDrawingAngle"; const QString SHAPE_DYNAMICS_DRAWING_ANGLE_WEIGHT = "ShapeDynamics/followDrawingAngleWeigth"; class KisShapeDynamicsOptionsWidget; class KisSprayShapeDynamicsOption : public KisPaintOpOption { Q_OBJECT public: KisSprayShapeDynamicsOption(); ~KisSprayShapeDynamicsOption(); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: void setupBrushPreviewSignals(); private: KisShapeDynamicsOptionsWidget * m_options; }; class KisShapeDynamicsProperties { public: bool enabled; // particle size dynamics bool randomSize; // rotation dynamics bool fixedRotation; bool randomRotation; bool followCursor; bool followDrawingAngle; quint16 fixedAngle; qreal randomRotationWeight; qreal followCursorWeigth; qreal followDrawingAngleWeight; public: - void loadSettings(const KisPropertiesConfiguration* settings) { + void loadSettings(const KisPropertiesConfigurationSP settings) { // Krita 2.2 if (settings->getString(SHAPE_DYNAMICS_VERSION, "2.2") == "2.2") { randomSize = settings->getBool(SPRAYSHAPE_RANDOM_SIZE); // rotation fixedRotation = settings->getBool(SPRAYSHAPE_FIXED_ROTATION); randomRotation = settings->getBool(SPRAYSHAPE_RANDOM_ROTATION); followCursor = settings->getBool(SPRAYSHAPE_FOLLOW_CURSOR); followDrawingAngle = settings->getBool(SPRAYSHAPE_DRAWING_ANGLE); fixedAngle = settings->getInt(SPRAYSHAPE_FIXED_ANGEL); randomRotationWeight = settings->getDouble(SPRAYSHAPE_RANDOM_ROTATION_WEIGHT); followCursorWeigth = settings->getDouble(SPRAYSHAPE_FOLLOW_CURSOR_WEIGHT); followDrawingAngleWeight = settings->getDouble(SPRAYSHAPE_DRAWING_ANGLE_WEIGHT); enabled = true; } // Krita latest else { enabled = settings->getBool(SHAPE_DYNAMICS_ENABLED); // particle type size randomSize = settings->getBool(SHAPE_DYNAMICS_RANDOM_SIZE); // rotation dynamics fixedRotation = settings->getBool(SHAPE_DYNAMICS_FIXED_ROTATION); randomRotation = settings->getBool(SHAPE_DYNAMICS_RANDOM_ROTATION); followCursor = settings->getBool(SHAPE_DYNAMICS_FOLLOW_CURSOR); followDrawingAngle = settings->getBool(SHAPE_DYNAMICS_DRAWING_ANGLE); fixedAngle = settings->getInt(SHAPE_DYNAMICS_FIXED_ANGEL); randomRotationWeight = settings->getDouble(SHAPE_DYNAMICS_RANDOM_ROTATION_WEIGHT); followCursorWeigth = settings->getDouble(SHAPE_DYNAMICS_FOLLOW_CURSOR_WEIGHT); followDrawingAngleWeight = settings->getDouble(SHAPE_DYNAMICS_DRAWING_ANGLE_WEIGHT); } } }; #endif // KIS_SPRAY_SHAPE_DYNAMICS_OPTION_H diff --git a/plugins/paintops/spray/kis_spray_shape_option.cpp b/plugins/paintops/spray/kis_spray_shape_option.cpp index 988ae9baaa..71c421bf1c 100644 --- a/plugins/paintops/spray/kis_spray_shape_option.cpp +++ b/plugins/paintops/spray/kis_spray_shape_option.cpp @@ -1,144 +1,144 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_spray_shape_option.h" #include #include #include #include #include #include "kis_aspect_ratio_locker.h" #include "kis_signals_blocker.h" #include "ui_wdgsprayshapeoptions.h" class KisShapeOptionsWidget: public QWidget, public Ui::WdgSprayShapeOptions { public: KisShapeOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); imageUrl->setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); } }; KisSprayShapeOption::KisSprayShapeOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, true), m_sizeRatioLocker(new KisAspectRatioLocker(this)) { setObjectName("KisSprayShapeOption"); m_checkable = true; // save this to be able to restore it back m_maxSize = 1000; m_options = new KisShapeOptionsWidget(); //initializer slider values m_options->widthSpin->setRange(1, 1000, 0); m_options->widthSpin->setValue(6); m_options->widthSpin->setSuffix(i18n(" px")); m_options->heightSpin->setRange(1, 1000, 0); m_options->heightSpin->setValue(6); m_options->heightSpin->setSuffix(i18n(" px")); // UI signals connect(m_options->proportionalBox, SIGNAL(clicked(bool)), SLOT(changeSizeUI(bool))); connect(m_options->imageUrl, SIGNAL(textChanged(QString)), this, SLOT(prepareImage())); m_sizeRatioLocker->connectSpinBoxes(m_options->widthSpin, m_options->heightSpin, m_options->aspectButton); m_sizeRatioLocker->setBlockUpdateSignalOnDrag(true); connect(m_sizeRatioLocker, SIGNAL(sliderValueChanged()), SLOT(emitSettingChanged())); connect(m_sizeRatioLocker, SIGNAL(aspectButtonChanged()), SLOT(emitSettingChanged())); connect(m_options->proportionalBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->proportionalBox, SIGNAL(clicked(bool)), SLOT(emitSettingChanged())); connect(m_options->shapeBox, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_options->imageUrl, SIGNAL(textChanged(QString)), SLOT(emitSettingChanged())); setConfigurationPage(m_options); } KisSprayShapeOption::~KisSprayShapeOption() { delete m_options; } int KisSprayShapeOption::shape() const { return m_options->shapeBox->currentIndex(); } -void KisSprayShapeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisSprayShapeOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(SPRAYSHAPE_ENABLED, isChecked()); setting->setProperty(SPRAYSHAPE_SHAPE, shape()); setting->setProperty(SPRAYSHAPE_USE_ASPECT, m_options->aspectButton->keepAspectRatio()); setting->setProperty(SPRAYSHAPE_PROPORTIONAL, m_options->proportionalBox->isChecked()); setting->setProperty(SPRAYSHAPE_WIDTH, m_options->widthSpin->value()); setting->setProperty(SPRAYSHAPE_HEIGHT, m_options->heightSpin->value()); setting->setProperty(SPRAYSHAPE_IMAGE_URL, m_options->imageUrl->fileName()); } -void KisSprayShapeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisSprayShapeOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { // in 2.2 there is not shape enabled so true by default setChecked(setting->getBool(SPRAYSHAPE_ENABLED, true)); m_options->shapeBox->setCurrentIndex(setting->getInt(SPRAYSHAPE_SHAPE)); m_options->proportionalBox->setChecked(setting->getBool(SPRAYSHAPE_PROPORTIONAL)); m_options->aspectButton->setKeepAspectRatio(setting->getBool(SPRAYSHAPE_USE_ASPECT, false)); m_options->widthSpin->setValue(setting->getInt(SPRAYSHAPE_WIDTH)); m_options->heightSpin->setValue(setting->getInt(SPRAYSHAPE_HEIGHT)); m_options->imageUrl->setFileName(setting->getString(SPRAYSHAPE_IMAGE_URL)); } void KisSprayShapeOption::prepareImage() { QString path = m_options->imageUrl->fileName(); if (QFile::exists(path)) { QImage image(path); if (!image.isNull()) { KisSignalsBlocker b(m_options->widthSpin, m_options->heightSpin); m_options->widthSpin->setValue(image.width()); m_options->heightSpin->setValue(image.height()); } } } void KisSprayShapeOption::changeSizeUI(bool proportionalSize) { // if proportionalSize is false, pixel size is used if (!proportionalSize) { m_options->widthSpin->setMaximum(m_maxSize); m_options->widthSpin->setSuffix(i18n(" px")); m_options->heightSpin->setMaximum(m_maxSize); m_options->heightSpin->setSuffix(i18n(" px")); } else { m_options->widthSpin->setMaximum(100); m_options->widthSpin->setSuffix("%"); m_options->heightSpin->setMaximum(100); m_options->heightSpin->setSuffix("%"); } } diff --git a/plugins/paintops/spray/kis_spray_shape_option.h b/plugins/paintops/spray/kis_spray_shape_option.h index 73dae51f2c..99539434c8 100644 --- a/plugins/paintops/spray/kis_spray_shape_option.h +++ b/plugins/paintops/spray/kis_spray_shape_option.h @@ -1,95 +1,95 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_SPRAY_SHAPE_OPTION_H #define KIS_SPRAY_SHAPE_OPTION_H #include const QString SPRAYSHAPE_ENABLED = "SprayShape/enabled"; const QString SPRAYSHAPE_SHAPE = "SprayShape/shape"; const QString SPRAYSHAPE_PROPORTIONAL = "SprayShape/proportional"; const QString SPRAYSHAPE_WIDTH = "SprayShape/width"; const QString SPRAYSHAPE_HEIGHT = "SprayShape/height"; const QString SPRAYSHAPE_IMAGE_URL = "SprayShape/imageUrl"; const QString SPRAYSHAPE_USE_ASPECT = "SprayShape/useAspect"; class KisShapeOptionsWidget; class KisAspectRatioLocker; class KisSprayShapeOption : public KisPaintOpOption { Q_OBJECT public: KisSprayShapeOption(); ~KisSprayShapeOption(); /// 0 - ellipse, 1 - rectangle, 2 - anti-aliased pixel, 2 - pixel int shape() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisShapeOptionsWidget * m_options; int m_maxSize; KisAspectRatioLocker *m_sizeRatioLocker; private Q_SLOTS: void prepareImage(); void changeSizeUI(bool proportionalSize); }; #include class KisShapeProperties { public: // particle type size quint8 shape; quint16 width; quint16 height; bool enabled; bool proportional; // rotation QImage image; public: - void loadSettings(const KisPropertiesConfiguration* settings, qreal proportionalWidth, qreal proportionalHeight) { + void loadSettings(const KisPropertiesConfigurationSP settings, qreal proportionalWidth, qreal proportionalHeight) { enabled = settings->getBool(SPRAYSHAPE_ENABLED, true); width = settings->getInt(SPRAYSHAPE_WIDTH); height = settings->getInt(SPRAYSHAPE_HEIGHT); proportional = settings->getBool(SPRAYSHAPE_PROPORTIONAL); if (proportional) { width = (width / 100.0) * proportionalWidth; height = (height / 100.0) * proportionalHeight; } // particle type size shape = settings->getInt(SPRAYSHAPE_SHAPE); // you have to check if the image is null in client image = QImage(settings->getString(SPRAYSHAPE_IMAGE_URL)); } }; #endif // KIS_SPRAY_SHAPE_OPTION_H diff --git a/plugins/paintops/spray/kis_sprayop_option.cpp b/plugins/paintops/spray/kis_sprayop_option.cpp index f96f1ef1b8..5a6991dab9 100644 --- a/plugins/paintops/spray/kis_sprayop_option.cpp +++ b/plugins/paintops/spray/kis_sprayop_option.cpp @@ -1,151 +1,151 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_sprayop_option.h" #include #include "ui_wdgsprayoptions.h" class KisSprayOpOptionsWidget: public QWidget, public Ui::WdgSprayOptions { public: KisSprayOpOptionsWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisSprayOpOption::KisSprayOpOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false) { setObjectName("KisSprayOpOption"); m_checkable = false; m_options = new KisSprayOpOptionsWidget(); m_options->diameterSpinBox->setRange(1, 1000, 0); m_options->diameterSpinBox->setValue(100); m_options->diameterSpinBox->setExponentRatio(1.5); m_options->diameterSpinBox->setSuffix(i18n(" px")); m_options->aspectSPBox->setRange(0.0, 2.0, 2); m_options->aspectSPBox->setValue(1.0); m_options->rotationSPBox->setRange(0.0, 360.0, 0); m_options->rotationSPBox->setValue(0.0); m_options->rotationSPBox->setSuffix(QChar(Qt::Key_degree)); m_options->scaleSpin->setRange(0.0, 10.0, 2); m_options->scaleSpin->setValue(1.0); m_options->spacingSpin->setRange(0.0, 5.0, 2); m_options->spacingSpin->setValue(0.5); m_options->coverageSpin->setRange(0.0, 100.0, 3); m_options->coverageSpin->setValue(0.1); m_options->coverageSpin->setSuffix("%"); m_options->coverageSpin->setExponentRatio(3); m_options->particlesSpinBox->setRange(1.0, 1000.0, 0); m_options->particlesSpinBox->setValue(12); m_options->particlesSpinBox->setExponentRatio(3.0); m_options->jitterMovementSpin->setRange(0.0,5.0, 1); m_options->jitterMovementSpin->setValue(1.0); connect(m_options->diameterSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->coverageSpin, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->jitterMovementSpin, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->spacingSpin, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->scaleSpin, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->particlesSpinBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->countRadioButton, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->densityRadioButton, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->gaussianBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->aspectSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->rotationSPBox, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->jitterMoveBox, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->countRadioButton, SIGNAL(toggled(bool)), m_options->particlesSpinBox, SLOT(setEnabled(bool))); connect(m_options->densityRadioButton, SIGNAL(toggled(bool)), m_options->coverageSpin, SLOT(setEnabled(bool))); connect(m_options->jitterMoveBox, SIGNAL(toggled(bool)), m_options->jitterMovementSpin, SLOT(setEnabled(bool))); setConfigurationPage(m_options); } KisSprayOpOption::~KisSprayOpOption() { delete m_options; } -void KisSprayOpOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisSprayOpOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KisSprayProperties op; op.diameter = m_options->diameterSpinBox->value(); op.particleCount = m_options->particlesSpinBox->value(); op.aspect = m_options->aspectSPBox->value(); op.coverage = m_options->coverageSpin->value(); op.amount = m_options->jitterMovementSpin->value(); op.spacing = m_options->spacingSpin->value(); op.scale = m_options->scaleSpin->value(); op.brushRotation = m_options->rotationSPBox->value(); op.jitterMovement = m_options->jitterMoveBox->isChecked(); op.useDensity = m_options->densityRadioButton->isChecked(); op.gaussian = m_options->gaussianBox->isChecked(); op.writeOptionSetting(setting); } -void KisSprayOpOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisSprayOpOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { KisSprayProperties op; op.readOptionSetting(setting); m_options->diameterSpinBox->setValue(op.diameter); m_options->aspectSPBox->setValue(op.aspect); m_options->coverageSpin->setValue(op.coverage); m_options->scaleSpin->setValue(op.scale); m_options->rotationSPBox->setValue(op.brushRotation); m_options->particlesSpinBox->setValue(op.particleCount); m_options->jitterMovementSpin->setValue(op.amount); m_options->jitterMoveBox->setChecked(op.jitterMovement); m_options->spacingSpin->setValue(op.spacing); m_options->gaussianBox->setChecked(op.gaussian); //TODO: come on, do this nicer! e.g. button group or something bool useDensity = op.useDensity; m_options->densityRadioButton->setChecked(useDensity); m_options->countRadioButton->setChecked(!useDensity); } void KisSprayOpOption::setDiameter(int diameter) const { m_options->diameterSpinBox->setValue(diameter); } int KisSprayOpOption::diameter() const { return m_options->diameterSpinBox->value(); } qreal KisSprayOpOption::brushAspect() const { return m_options->aspectSPBox->value(); } diff --git a/plugins/paintops/spray/kis_sprayop_option.h b/plugins/paintops/spray/kis_sprayop_option.h index a91300b697..2b6db2b6ee 100644 --- a/plugins/paintops/spray/kis_sprayop_option.h +++ b/plugins/paintops/spray/kis_sprayop_option.h @@ -1,105 +1,106 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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_SPRAYOP_OPTION_H #define KIS_SPRAYOP_OPTION_H #include const QString SPRAY_DIAMETER = "Spray/diameter"; const QString SPRAY_ASPECT = "Spray/aspect"; const QString SPRAY_COVERAGE = "Spray/coverage"; const QString SPRAY_SCALE = "Spray/scale"; const QString SPRAY_ROTATION = "Spray/rotation"; const QString SPRAY_PARTICLE_COUNT = "Spray/particleCount"; const QString SPRAY_JITTER_MOVE_AMOUNT = "Spray/jitterMoveAmount"; const QString SPRAY_JITTER_MOVEMENT = "Spray/jitterMovement"; const QString SPRAY_SPACING = "Spray/spacing"; const QString SPRAY_GAUSS_DISTRIBUTION = "Spray/gaussianDistribution"; const QString SPRAY_USE_DENSITY = "Spray/useDensity"; class KisSprayOpOptionsWidget; class KisSprayOpOption : public KisPaintOpOption { public: KisSprayOpOption(); ~KisSprayOpOption(); void setDiameter(int diameter) const; int diameter() const; qreal brushAspect() const; - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: - KisSprayOpOptionsWidget * m_options; + KisSprayOpOptionsWidget *m_options; }; class KisSprayProperties { public: quint16 diameter; quint16 particleCount; qreal aspect; qreal coverage; qreal amount; qreal spacing; qreal scale; qreal brushRotation; bool jitterMovement; bool useDensity; bool gaussian; int radius() const { return diameter / 2; } public: - void readOptionSetting(const KisPropertiesConfiguration* settings) { + + void readOptionSetting(const KisPropertiesConfigurationSP settings) { diameter = settings->getInt(SPRAY_DIAMETER); aspect = settings->getDouble(SPRAY_ASPECT); particleCount = settings->getDouble(SPRAY_PARTICLE_COUNT); coverage = (settings->getDouble(SPRAY_COVERAGE) / 100.0); amount = settings->getDouble(SPRAY_JITTER_MOVE_AMOUNT); spacing = settings->getDouble(SPRAY_SPACING); scale = settings->getDouble(SPRAY_SCALE); brushRotation = settings->getDouble(SPRAY_ROTATION); jitterMovement = settings->getBool(SPRAY_JITTER_MOVEMENT); useDensity = settings->getBool(SPRAY_USE_DENSITY); gaussian = settings->getBool(SPRAY_GAUSS_DISTRIBUTION); } - void writeOptionSetting(KisPropertiesConfiguration* setting) const { + void writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(SPRAY_DIAMETER, diameter); setting->setProperty(SPRAY_ASPECT, aspect); setting->setProperty(SPRAY_COVERAGE, coverage * 100.0); setting->setProperty(SPRAY_SCALE, scale); setting->setProperty(SPRAY_ROTATION, brushRotation); setting->setProperty(SPRAY_PARTICLE_COUNT, particleCount); setting->setProperty(SPRAY_JITTER_MOVE_AMOUNT, amount); setting->setProperty(SPRAY_JITTER_MOVEMENT, jitterMovement); setting->setProperty(SPRAY_SPACING, spacing); setting->setProperty(SPRAY_GAUSS_DISTRIBUTION, gaussian); setting->setProperty(SPRAY_USE_DENSITY, useDensity); } }; #endif diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp index 8a0e9ac7da..871b5750cb 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp @@ -1,232 +1,232 @@ /* * Copyright (C) 2015 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. */ #include "kis_tangent_normal_paintop.h" #include #include #include #include #include #include #include #include #include #include #include -KisTangentNormalPaintOp::KisTangentNormalPaintOp(const KisBrushBasedPaintOpSettings* settings, KisPainter* painter, KisNodeSP node, KisImageSP image): +KisTangentNormalPaintOp::KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image): KisBrushBasedPaintOp(settings, painter), m_opacityOption(node), m_tempDev(painter->device()->createCompositionSourceDevice()) { Q_UNUSED(image); //Init, read settings, etc// m_tangentTiltOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_flowOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_softnessOption.readOptionSetting(settings); m_sharpnessOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_flowOption.resetAllSensors(); m_spacingOption.resetAllSensors(); m_softnessOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_dabCache->setSharpnessPostprocessing(&m_sharpnessOption); m_rotationOption.applyFanCornersInfo(this); } KisTangentNormalPaintOp::~KisTangentNormalPaintOp() { //destroy things here// } KisSpacingInformation KisTangentNormalPaintOp::paintAt(const KisPaintInformation& info) { /* * For the color, the precision of tilt is only 60x60, and the precision of direction and rotation are 360 and 360*90. * You can't get more precise than 8bit. Therefore, we will check if the current space is RGB, * if so we request a profile with that space and 8bit bit depth, if not, just sRGB */ KoColor currentColor = painter()->paintColor(); QString currentSpace = currentColor.colorSpace()->colorModelId().id(); const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); if (currentSpace != "RGBA") { - rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); + rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { - rgbColorSpace = currentColor.colorSpace(); + rgbColorSpace = currentColor.colorSpace(); } QVector channelValues(4); qreal r, g, b; if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){ channelValues[0] = 0.5;//red channelValues[1] = 0.5;//green channelValues[2] = 1.0;//blue channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(info, &r, &g, &b); channelValues[0] = r;//red channelValues[1] = g;//green channelValues[2] = b;//blue } else { channelValues[0] = 1.0;//blue channelValues[1] = 0.5;//green channelValues[2] = 0.5;//red channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(info, &r, &g, &b); channelValues[0] = b;//blue channelValues[1] = g;//green channelValues[2] = r;//red } quint8 data[4]; rgbColorSpace->fromNormalisedChannelsValue(data, channelValues); KoColor color(data, rgbColorSpace);//Should be default RGB(0.5,0.5,1.0) //draw stuff here, return kisspacinginformation. KisBrushSP brush = m_brush; if (!painter()->device() || !brush || !brush->canPaintFor(info)) { return KisSpacingInformation(1.0); } qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); KisDabShape shape(scale, 1.0, rotation); QPointF cursorPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); m_maskDab = m_dabCache->fetchDab(rgbColorSpace, color, cursorPos, shape, info, m_softnessOption.apply(info), &m_dstDabRect); if (m_dstDabRect.isEmpty()) return KisSpacingInformation(1.0); QRect dabRect = m_maskDab->bounds(); // sanity check Q_ASSERT(m_dstDabRect.size() == dabRect.size()); Q_UNUSED(dabRect); quint8 oldOpacity = painter()->opacity(); QString oldCompositeOpId = painter()->compositeOp()->id(); m_opacityOption.setFlow(m_flowOption.apply(info)); m_opacityOption.apply(painter(), info); //paint with the default color? Copied this from color smudge.// //painter()->setCompositeOp(COMPOSITE_COPY); //painter()->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color); painter()->bltFixed(m_dstDabRect.topLeft(), m_maskDab, m_maskDab->bounds()); painter()->renderMirrorMaskSafe(m_dstDabRect, m_maskDab, !m_dabCache->needSeparateOriginal()); // restore orginal opacity and composite mode values painter()->setOpacity(oldOpacity); painter()->setCompositeOp(oldCompositeOpId); return effectiveSpacing(scale, rotation, m_spacingOption, info); } void KisTangentNormalPaintOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance) { if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) { if (!m_lineCacheDevice) { m_lineCacheDevice = m_tempDev; } else { m_lineCacheDevice->clear(); } KisPainter p(m_lineCacheDevice); - KoColor currentColor = painter()->paintColor(); - QString currentSpace = currentColor.colorSpace()->colorModelId().id(); - const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); - if (currentSpace != "RGBA") { - rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); - } else { - rgbColorSpace = currentColor.colorSpace(); - } - QVector channelValues(4); + KoColor currentColor = painter()->paintColor(); + QString currentSpace = currentColor.colorSpace()->colorModelId().id(); + const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); + if (currentSpace != "RGBA") { + rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); + } else { + rgbColorSpace = currentColor.colorSpace(); + } + QVector channelValues(4); qreal r, g, b; - if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){ + if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){ channelValues[0] = 0.5;//red channelValues[1] = 0.5;//green channelValues[2] = 1.0;//blue channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(pi2, &r, &g, &b); channelValues[0] = r;//red channelValues[1] = g;//green channelValues[2] = b;//blue } else { channelValues[0] = 1.0;//blue channelValues[1] = 0.5;//green channelValues[2] = 0.5;//red channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(pi2, &r, &g, &b); channelValues[0] = b;//blue channelValues[1] = g;//green channelValues[2] = r;//red } - quint8 data[4]; - rgbColorSpace->fromNormalisedChannelsValue(data, channelValues); - KoColor color(data, rgbColorSpace); + quint8 data[4]; + rgbColorSpace->fromNormalisedChannelsValue(data, channelValues); + KoColor color(data, rgbColorSpace); p.setPaintColor(color); p.drawDDALine(pi1.pos(), pi2.pos()); QRect rc = m_lineCacheDevice->extent(); painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height()); - painter()->renderMirrorMask(rc, m_lineCacheDevice); + painter()->renderMirrorMask(rc, m_lineCacheDevice); } else { KisPaintOp::paintLine(pi1, pi2, currentDistance); } } diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h index 37b5858bca..eb76845b0c 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h @@ -1,70 +1,70 @@ /* * Copyright (C) 2015 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_TANGENTNORMALPAINTOP_H_ #define _KIS_TANGENTNORMALPAINTOP_H_ #include #include #include #include #include #include #include #include #include #include #include #include class KisBrushBasedPaintOpSettings; class KisPainter; class KisTangentNormalPaintOp: public KisBrushBasedPaintOp { public: //public functions// /* Create a Tangent Normal Brush Operator*/ - KisTangentNormalPaintOp(const KisBrushBasedPaintOpSettings* settings, KisPainter* painter, KisNodeSP node, KisImageSP image); + KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image); virtual ~KisTangentNormalPaintOp(); /*paint the dabs*/ KisSpacingInformation paintAt(const KisPaintInformation& info); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); private: //private functions// KisPressureSizeOption m_sizeOption; KisFlowOpacityOption m_opacityOption; KisPressureSpacingOption m_spacingOption; KisPressureRotationOption m_rotationOption; KisPressureScatterOption m_scatterOption; KisTangentTiltOption m_tangentTiltOption; KisPressureSoftnessOption m_softnessOption; KisPressureSharpnessOption m_sharpnessOption; KisPressureFlowOption m_flowOption; KisFixedPaintDeviceSP m_maskDab; KisPaintDeviceSP m_tempDev; QRect m_dstDabRect; KisPaintDeviceSP m_lineCacheDevice; }; #endif // _KIS_TANGENTNORMALPAINTOP_H_ diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.cpp b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.cpp index 25d84a6d25..94babbbe01 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.cpp +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.cpp @@ -1,86 +1,86 @@ /* * Copyright (C) 2015 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. */ #include "kis_tangent_normal_paintop_settings_widget.h" #include "kis_brush_based_paintop_settings.h" #include "kis_tangent_tilt_option.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_texture_option.h" #include "kis_curve_option_widget.h" #include #include "kis_pressure_texture_strength_option.h" KisTangentNormalPaintOpSettingsWidget::KisTangentNormalPaintOpSettingsWidget(QWidget* parent): KisBrushBasedPaintopOptionWidget(parent) { setObjectName("brush option widget"); setPrecisionEnabled(true); addPaintOpOption(new KisCompositeOpOption(true), i18n("Blending Mode")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption(), i18n("Transparent"), i18n("Opaque")), i18n("Opacity")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureFlowOption(), i18n("0%"), i18n("100%")), i18n("Flow")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption(), i18n("0%"), i18n("100%")), i18n("Size")); addPaintOpOption(new KisTangentTiltOption(), i18n("Tangent Tilt")); addPaintOpOption(new KisPressureSpacingOptionWidget(), i18n("Spacing")); addPaintOpOption(new KisPressureMirrorOptionWidget(), i18n("Mirror")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSoftnessOption(), i18n("Soft"), i18n("Hard")), i18n("Softness")); addPaintOpOption(new KisPressureSharpnessOptionWidget(), i18n("Sharpness")); addPaintOpOption(new KisPressureScatterOptionWidget(), i18n("Scatter")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureRotationOption(), i18n("-180°"), i18n("180°")), i18n("Rotation")); addPaintOpOption(new KisAirbrushOption(false), i18n("Airbrush")); addPaintOpOption(new KisPaintActionTypeOption(), i18n("Painting Mode")); addPaintOpOption(new KisTextureOption(), i18n("Pattern")); addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength")); } KisTangentNormalPaintOpSettingsWidget::~KisTangentNormalPaintOpSettingsWidget() { } -KisPropertiesConfiguration* KisTangentNormalPaintOpSettingsWidget::configuration() const +KisPropertiesConfigurationSP KisTangentNormalPaintOpSettingsWidget::configuration() const { - KisBrushBasedPaintOpSettings *config = new KisBrushBasedPaintOpSettings(); + KisBrushBasedPaintOpSettingsSP config = new KisBrushBasedPaintOpSettings(); config->setOptionsWidget(const_cast(this)); config->setProperty("paintop", "tangentnormal"); writeConfiguration(config); return config; } diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.h b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.h index 6f7970ed1a..c8c4d9832f 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.h +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop_settings_widget.h @@ -1,38 +1,38 @@ /* * Copyright (C) 2015 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_TANGENTNORMAL_PAINTOP_SETTINGS_WIDGET_H_ #define KIS_TANGENTNORMAL_PAINTOP_SETTINGS_WIDGET_H_ #include class KisTangentNormalPaintOpSettingsWidget : public KisBrushBasedPaintopOptionWidget { Q_OBJECT public: KisTangentNormalPaintOpSettingsWidget(QWidget* parent = 0); ~KisTangentNormalPaintOpSettingsWidget(); - KisPropertiesConfiguration* configuration() const; + KisPropertiesConfigurationSP configuration() const; }; #endif // KIS_TANGENTNORMAL_PAINTOP_SETTINGS_WIDGET_H_ diff --git a/plugins/paintops/tangentnormal/kis_tangent_tilt_option.cpp b/plugins/paintops/tangentnormal/kis_tangent_tilt_option.cpp index 1e1733d61d..ecb5cf77b8 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_tilt_option.cpp +++ b/plugins/paintops/tangentnormal/kis_tangent_tilt_option.cpp @@ -1,269 +1,269 @@ /* This file is part of the KDE project * * Copyright (C) 2015 Wolthera van Hövell tot Westerflier * * 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_tangent_tilt_option.h" #include #include #include #include "ui_wdgtangenttiltoption.h" #include "kis_global.h" class KisTangentTiltOptionWidget: public QWidget, public Ui::WdgTangentTiltOptions { public: KisTangentTiltOptionWidget(QWidget *parent = 0) : QWidget(parent) { setupUi(this); } }; KisTangentTiltOption::KisTangentTiltOption() : KisPaintOpOption(KisPaintOpOption::GENERAL, false), m_canvasAngle(0.0), m_canvasAxisXMirrored(false), m_canvasAxisYMirrored(false) { m_checkable = false; m_options = new KisTangentTiltOptionWidget(); //Setup tangent tilt. m_options->comboRed->setCurrentIndex(0); m_options->comboGreen->setCurrentIndex(2); m_options->comboBlue->setCurrentIndex(4); m_options->sliderElevationSensitivity->setRange(0, 100, 0); m_options->sliderElevationSensitivity->setValue(100); m_options->sliderElevationSensitivity->setSuffix("%"); m_options->sliderMixValue->setRange(0, 100, 0); m_options->sliderMixValue->setValue(50); m_options->sliderMixValue->setSuffix("%"); connect(m_options->comboRed, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_options->comboGreen, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_options->comboBlue, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_options->comboRed, SIGNAL(currentIndexChanged(int)), m_options->TangentTiltPreview, SLOT(setRedChannel(int) )); connect(m_options->comboGreen, SIGNAL(currentIndexChanged(int)), m_options->TangentTiltPreview, SLOT(setGreenChannel(int) )); connect(m_options->comboBlue, SIGNAL(currentIndexChanged(int)), m_options->TangentTiltPreview, SLOT(setBlueChannel(int) )); connect(m_options->optionTilt, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->optionDirection, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->optionRotation, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->optionMix, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_options->sliderElevationSensitivity, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_options->sliderMixValue, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); m_options->sliderMixValue->setVisible(false); setConfigurationPage(m_options); } KisTangentTiltOption::~KisTangentTiltOption() { delete m_options; } //options int KisTangentTiltOption::redChannel() const { return m_options->comboRed->currentIndex(); } int KisTangentTiltOption::greenChannel() const { return m_options->comboGreen->currentIndex(); } int KisTangentTiltOption::blueChannel() const { return m_options->comboBlue->currentIndex(); } int KisTangentTiltOption::directionType() const { int type=0; if (m_options->optionTilt->isChecked()==true) { type=0; } else if (m_options->optionDirection->isChecked()==true) { type=1; } else if (m_options->optionRotation->isChecked()==true) { type=2; } else if (m_options->optionMix->isChecked()==true) { type=3; } else { warnKrita<<"There's something odd with the radio buttons. We'll use Tilt"; } return type; } double KisTangentTiltOption::elevationSensitivity() const { return m_options->sliderElevationSensitivity->value(); } double KisTangentTiltOption::mixValue() const { return m_options->sliderMixValue->value(); } void KisTangentTiltOption::swizzleAssign(qreal const horizontal, qreal const vertical, qreal const depth, qreal *component, int index, qreal maxvalue) { switch(index) { case 0: *component = horizontal; break; case 1: *component = maxvalue-horizontal; break; case 2: *component = vertical; break; case 3: *component = maxvalue-vertical; break; case 4: *component = depth; break; case 5: *component = maxvalue-depth; break; } } void KisTangentTiltOption::apply(const KisPaintInformation& info,qreal *r,qreal *g,qreal *b) { //formula based on http://www.cerebralmeltdown.com/programming_projects/Altitude%20and%20Azimuth%20to%20Vector/index.html /* It doesn't make sense of have higher than 8bit color depth. * Instead we make sure in the paintAt function of kis_tangent_normal_paintop to pick an 8bit space of the current * color space if the space is an RGB space. If not, it'll pick sRGB 8bit. */ qreal halfvalue = 0.5; qreal maxvalue = 1.0; //have the azimuth and altitude in degrees. qreal direction = KisPaintInformation::tiltDirection(info, true)*360.0; qreal elevation= (info.tiltElevation(info, 60.0, 60.0, true)*90.0); if (directionType()==0) { direction = KisPaintInformation::tiltDirection(info, true)*360.0; elevation= (info.tiltElevation(info, 60.0, 60.0, true)*90.0); } else if (directionType()==1) { direction = (0.75 + info.drawingAngle() / (2.0 * M_PI))*360.0; elevation= 0;//turns out that tablets that don't support tilt just return 90 degrees for elevation. } else if (directionType()==2) { direction = info.rotation(); elevation= (info.tiltElevation(info, 60.0, 60.0, true)*90.0);//artpens have tilt-recognition, so this should work. } else if (directionType()==3) {//mix of tilt+direction qreal mixamount = mixValue()/100.0; direction = (KisPaintInformation::tiltDirection(info, true)*360.0*(1.0-mixamount))+((0.75 + info.drawingAngle() / (2.0 * M_PI))*360.0*(mixamount)); elevation= (info.tiltElevation(info, 60.0, 60.0, true)*90.0); } //subtract/add the rotation of the canvas. if (info.canvasRotation()!=m_canvasAngle && info.canvasMirroredH()==m_canvasAxisXMirrored) { m_canvasAngle=info.canvasRotation(); } if (directionType()!=1) { direction = direction-m_canvasAngle; } //limit the direction/elevation //qreal elevationMax = (elevationSensitivity()*90.0)/100.0; qreal elevationT = elevation*(elevationSensitivity()/100.0)+(90-(elevationSensitivity()*90.0)/100.0); elevation = static_cast(elevationT); //convert to radians. // Convert this to kis_global's radian function. direction = kisDegreesToRadians(direction); elevation = kisDegreesToRadians(elevation); //make variables for axes for easy switching later on. qreal horizontal, vertical, depth; //spherical coordinates always center themselves around the origin, leading to values. We need to work around those... horizontal = cos(elevation)*sin(direction); if (horizontal>0.0) { horizontal= halfvalue+(fabs(horizontal)*halfvalue); } else { horizontal= halfvalue-(fabs(horizontal)*halfvalue); } vertical = cos(elevation)*cos(direction); if (vertical>0.0) { vertical = halfvalue+(fabs(vertical)*halfvalue); } else { vertical = halfvalue-(fabs(vertical)*halfvalue); } if (m_canvasAxisXMirrored && info.canvasMirroredH()) {horizontal = maxvalue-horizontal;} if (m_canvasAxisYMirrored && info.canvasMirroredH()) {vertical = maxvalue-vertical;} depth = sin(elevation)*maxvalue; //assign right components to correct axes. swizzleAssign(horizontal, vertical, depth, r, redChannel(), maxvalue); swizzleAssign(horizontal, vertical, depth, g, greenChannel(), maxvalue); swizzleAssign(horizontal, vertical, depth, b, blueChannel(), maxvalue); } /*settings*/ -void KisTangentTiltOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +void KisTangentTiltOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { setting->setProperty(TANGENT_RED, redChannel()); setting->setProperty(TANGENT_GREEN, greenChannel()); setting->setProperty(TANGENT_BLUE, blueChannel()); setting->setProperty(TANGENT_TYPE, directionType()); setting->setProperty(TANGENT_EV_SEN, elevationSensitivity()); setting->setProperty(TANGENT_MIX_VAL, mixValue()); } -void KisTangentTiltOption::readOptionSetting(const KisPropertiesConfiguration* setting) +void KisTangentTiltOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_options->comboRed->setCurrentIndex(setting->getInt(TANGENT_RED, 0)); m_options->comboGreen->setCurrentIndex(setting->getInt(TANGENT_GREEN, 2)); m_options->comboBlue->setCurrentIndex(setting->getInt(TANGENT_BLUE, 4)); //The comboboxes are connected to the TangentTiltPreview, so that gets automatically updated by them. if (setting->getInt(TANGENT_TYPE)== 0){ m_options->optionTilt->setChecked(true); m_options->sliderMixValue->setVisible(false); } else if (setting->getInt(TANGENT_TYPE)== 1) { m_options->optionDirection->setChecked(true); m_options->sliderMixValue->setVisible(false); } else if (setting->getInt(TANGENT_TYPE)== 2) { m_options->optionRotation->setChecked(true); m_options->sliderMixValue->setVisible(false); } else if (setting->getInt(TANGENT_TYPE)== 3) { m_options->optionMix->setChecked(true); m_options->sliderMixValue->setVisible(true); } m_canvasAngle = setting->getDouble("runtimeCanvasRotation", 0.0);//in degrees please. m_canvasAxisXMirrored = setting->getBool("runtimeCanvasMirroredX", false); m_canvasAxisYMirrored = setting->getBool("runtimeCanvasMirroredY", false); m_options->sliderElevationSensitivity->setValue(setting->getDouble(TANGENT_EV_SEN, 100)); m_options->sliderMixValue->setValue(setting->getDouble(TANGENT_MIX_VAL, 50)); } diff --git a/plugins/paintops/tangentnormal/kis_tangent_tilt_option.h b/plugins/paintops/tangentnormal/kis_tangent_tilt_option.h index 11d8805d3b..8598e7e82b 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_tilt_option.h +++ b/plugins/paintops/tangentnormal/kis_tangent_tilt_option.h @@ -1,68 +1,68 @@ /* This file is part of the KDE project * * Copyright (C) 2015 Wolthera van Hövell tot Westerflier * * 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_TANGENT_TILT_OPTION_H #define KIS_TANGENT_TILT_OPTION_H #include #include #include const QString TANGENT_RED = "Tangent/swizzleRed"; const QString TANGENT_GREEN = "Tangent/swizzleGreen"; const QString TANGENT_BLUE = "Tangent/swizzleBlue"; const QString TANGENT_TYPE = "Tangent/directionType"; const QString TANGENT_EV_SEN = "Tangent/elevationSensitivity"; const QString TANGENT_MIX_VAL = "Tangent/mixValue"; //const QString TANGENT_DIR_MIN = "Tangent/directionMinimum"; //const QString TANGENT_DIR_MAX = "Tangent/directionMaximum"; class KisPropertiesConfiguration; class KisTangentTiltOptionWidget; class KisTangentTiltOption: public KisPaintOpOption//not really// { public: KisTangentTiltOption(); ~KisTangentTiltOption(); /*These three give away which the index of the combobox for a given channel*/ int redChannel() const; int greenChannel() const; int blueChannel() const; int directionType() const; double elevationSensitivity() const; double mixValue() const; qreal m_canvasAngle; bool m_canvasAxisXMirrored; bool m_canvasAxisYMirrored; /*This assigns the right axis to the component, based on index and maximum value*/ void swizzleAssign(qreal const horizontal, qreal const vertical, qreal const depth, qreal *component, int index, qreal maxvalue); //takes the RGB values and will deform them depending on tilt. void apply(const KisPaintInformation& info, qreal *r, qreal *g, qreal *b); - void writeOptionSetting(KisPropertiesConfiguration* setting) const; - void readOptionSetting(const KisPropertiesConfiguration* setting); + void writeOptionSetting(KisPropertiesConfigurationSP setting) const; + void readOptionSetting(const KisPropertiesConfigurationSP setting); private: KisTangentTiltOptionWidget * m_options; }; #endif // KIS_TANGENT_TILT_OPTION_H diff --git a/plugins/tools/tool_transform2/kis_liquify_paint_helper.cpp b/plugins/tools/tool_transform2/kis_liquify_paint_helper.cpp index 6158c6c3c6..54329dedb2 100644 --- a/plugins/tools/tool_transform2/kis_liquify_paint_helper.cpp +++ b/plugins/tools/tool_transform2/kis_liquify_paint_helper.cpp @@ -1,139 +1,139 @@ /* * 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_liquify_paint_helper.h" #include "KoPointerEvent.h" #include #include "kis_painting_information_builder.h" #include "kis_liquify_transform_worker.h" #include #include "kis_coordinates_converter.h" #include "kis_liquify_paintop.h" #include "kis_liquify_properties.h" struct KisLiquifyPaintHelper::Private { Private(const KisCoordinatesConverter *_converter) : converter(_converter), infoBuilder(new KisConverterPaintingInformationBuilder(converter)), hasPaintedAtLeastOnce(false) { } KisPaintInformation previousPaintInfo; QScopedPointer paintOp; KisDistanceInformation currentDistance; const KisCoordinatesConverter *converter; QScopedPointer infoBuilder; QTime strokeTime; bool hasPaintedAtLeastOnce; KisDistanceInformation previousDistanceInfo; KisPaintOpUtils::PositionHistory lastOutlinePos; void updatePreviousPaintInfo(const KisPaintInformation &info); }; KisLiquifyPaintHelper::KisLiquifyPaintHelper(const KisCoordinatesConverter *converter) : m_d(new Private(converter)) { } KisLiquifyPaintHelper::~KisLiquifyPaintHelper() { } void KisLiquifyPaintHelper::Private::updatePreviousPaintInfo(const KisPaintInformation &info) { previousDistanceInfo = KisDistanceInformation( lastOutlinePos.pushThroughHistory(info.pos()), 0); previousPaintInfo = info; } -QPainterPath KisLiquifyPaintHelper::brushOutline(const KisLiquifyProperties &props) const +QPainterPath KisLiquifyPaintHelper::brushOutline(const KisLiquifyProperties &props) { KisPaintInformation::DistanceInformationRegistrar registrar = m_d->previousPaintInfo.registerDistanceInformation(&m_d->previousDistanceInfo); return KisLiquifyPaintop::brushOutline(props, m_d->previousPaintInfo); } void KisLiquifyPaintHelper::configurePaintOp(const KisLiquifyProperties &props, KisLiquifyTransformWorker *worker) { m_d->paintOp.reset(new KisLiquifyPaintop(props, worker)); } void KisLiquifyPaintHelper::startPaint(KoPointerEvent *event, const KoCanvasResourceManager *manager) { KIS_ASSERT_RECOVER_RETURN(m_d->paintOp); m_d->strokeTime.start(); KisPaintInformation pi = m_d->infoBuilder->startStroke(event, m_d->strokeTime.elapsed(), manager); m_d->updatePreviousPaintInfo(pi); m_d->hasPaintedAtLeastOnce = false; } void KisLiquifyPaintHelper::continuePaint(KoPointerEvent *event) { KIS_ASSERT_RECOVER_RETURN(m_d->paintOp); KisPaintInformation pi = m_d->infoBuilder->continueStroke(event, m_d->strokeTime.elapsed()); KisPaintOpUtils::paintLine(*m_d->paintOp.data(), m_d->previousPaintInfo, pi, &m_d->currentDistance, false, false); m_d->updatePreviousPaintInfo(pi); m_d->hasPaintedAtLeastOnce = true; } bool KisLiquifyPaintHelper::endPaint(KoPointerEvent *event) { KIS_ASSERT_RECOVER(m_d->paintOp) { return false; } if (!m_d->hasPaintedAtLeastOnce) { KisPaintInformation pi = m_d->infoBuilder->continueStroke(event, m_d->strokeTime.elapsed()); pi.paintAt(*m_d->paintOp.data(), &m_d->previousDistanceInfo); } m_d->paintOp.reset(); return !m_d->hasPaintedAtLeastOnce; } void KisLiquifyPaintHelper::hoverPaint(KoPointerEvent *event) { QPointF imagePoint = m_d->converter->documentToImage(event->pos()); KisPaintInformation pi = m_d->infoBuilder->hover(imagePoint, event); m_d->updatePreviousPaintInfo(pi); } diff --git a/plugins/tools/tool_transform2/kis_liquify_paint_helper.h b/plugins/tools/tool_transform2/kis_liquify_paint_helper.h index 76e937703f..9aa765d52f 100644 --- a/plugins/tools/tool_transform2/kis_liquify_paint_helper.h +++ b/plugins/tools/tool_transform2/kis_liquify_paint_helper.h @@ -1,53 +1,53 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LIQUIFY_PAINT_HELPER_H #define __KIS_LIQUIFY_PAINT_HELPER_H #include class KisLiquifyTransformWorker; class KisCoordinatesConverter; class KoPointerEvent; class KisLiquifyProperties; class QPainterPath; class KoCanvasResourceManager; class KisLiquifyPaintHelper { public: KisLiquifyPaintHelper(const KisCoordinatesConverter *converter); ~KisLiquifyPaintHelper(); void configurePaintOp(const KisLiquifyProperties &_props, KisLiquifyTransformWorker *worker); void startPaint(KoPointerEvent *event, const KoCanvasResourceManager *manager); void continuePaint(KoPointerEvent *event); bool endPaint(KoPointerEvent *event); void hoverPaint(KoPointerEvent *event); - QPainterPath brushOutline(const KisLiquifyProperties &props) const; + QPainterPath brushOutline(const KisLiquifyProperties &props); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_LIQUIFY_PAINT_HELPER_H */ diff --git a/plugins/tools/tool_transform2/kis_liquify_paintop.h b/plugins/tools/tool_transform2/kis_liquify_paintop.h index d57d05b272..905a2be37a 100644 --- a/plugins/tools/tool_transform2/kis_liquify_paintop.h +++ b/plugins/tools/tool_transform2/kis_liquify_paintop.h @@ -1,48 +1,47 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LIQUIFY_PAINTOP_H #define __KIS_LIQUIFY_PAINTOP_H #include class KisLiquifyTransformWorker; class KisPaintInformation; class KisSpacingInformation; class KisLiquifyProperties; class QPainterPath; class KisLiquifyPaintop { public: KisLiquifyPaintop(const KisLiquifyProperties &props, KisLiquifyTransformWorker *worker); ~KisLiquifyPaintop(); KisSpacingInformation paintAt(const KisPaintInformation &pi); - static QPainterPath brushOutline(const KisLiquifyProperties &props, - const KisPaintInformation &info); + static QPainterPath brushOutline(const KisLiquifyProperties &props, const KisPaintInformation &info); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_LIQUIFY_PAINTOP_H */ diff --git a/sdk/tests/qimage_based_test.h b/sdk/tests/qimage_based_test.h index 48d793ce41..19d5b660b0 100644 --- a/sdk/tests/qimage_based_test.h +++ b/sdk/tests/qimage_based_test.h @@ -1,316 +1,316 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __QIMAGE_BASED_TEST_H #define __QIMAGE_BASED_TEST_H #include "testutil.h" #include #include #include #include #include #include "KisDocument.h" #include "kis_shape_layer.h" #include "kis_undo_stores.h" #include "kis_image.h" #include "kis_selection.h" #include "kis_paint_layer.h" #include "kis_adjustment_layer.h" #include "kis_transparency_mask.h" #include "kis_clone_layer.h" #include "filter/kis_filter.h" #include "filter/kis_filter_registry.h" #include "commands/kis_selection_commands.h" namespace TestUtil { class QImageBasedTest { public: QImageBasedTest(const QString &directoryName) : m_directoryName(directoryName) { } // you need to declare your own test function // See KisProcessingTest for example protected: /** * Creates a complex image connected to a surrogate undo store */ KisImageSP createImage(KisSurrogateUndoStore *undoStore) { QImage sourceImage(fetchDataFileLazy("hakonepa.png")); QRect imageRect = QRect(QPoint(0,0), sourceImage.size()); QRect transpRect(50,50,300,300); QRect blurRect(66,66,300,300); QPoint blurShift(34,34); QPoint cloneShift(75,75); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "merge test"); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); - KisFilterConfiguration *configuration = filter->defaultConfiguration(0); + KisFilterConfigurationSP configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisAdjustmentLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0); blur1->internalSelection()->clear(); blur1->internalSelection()->pixelSelection()->select(blurRect); blur1->setX(blurShift.x()); blur1->setY(blurShift.y()); KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); paintLayer1->paintDevice()->convertFromQImage(sourceImage, 0, 0, 0); KisCloneLayerSP cloneLayer1 = new KisCloneLayer(paintLayer1, image, "clone1", OPACITY_OPAQUE_U8); cloneLayer1->setX(cloneShift.x()); cloneLayer1->setY(cloneShift.y()); image->addNode(cloneLayer1); image->addNode(blur1); image->addNode(paintLayer1); KisTransparencyMaskSP transparencyMask1 = new KisTransparencyMask(); transparencyMask1->setName("tmask1"); transparencyMask1->testingInitSelection(transpRect, paintLayer1); image->addNode(transparencyMask1, paintLayer1); return image; } /** * Creates a simple image with one empty layer and connects it to * a surrogate undo store */ KisImageSP createTrivialImage(KisSurrogateUndoStore *undoStore) { QRect imageRect = QRect(0, 0, 640, 441); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "merge test"); KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); image->addNode(paintLayer1); return image; } void addGlobalSelection(KisImageSP image) { QRect selectionRect(40,40,300,300); KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(0, image)); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); pixelSelection->select(selectionRect); KUndo2Command *cmd = new KisSetGlobalSelectionCommand(image, selection); image->undoAdapter()->addCommand(cmd); } void addShapeLayer(KisDocument *doc, KisImageSP image) { KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image.data(), "shape", OPACITY_OPAQUE_U8); image->addNode(shapeLayer); KoShapeFactoryBase *f1 = KoShapeRegistry::instance()->get("StarShape"); KoShapeFactoryBase *f2 = KoShapeRegistry::instance()->get("RectangleShape"); KoShape *shape1 = f1->createDefaultShape(); KoShape *shape2 = f2->createDefaultShape(); shape1->setPosition(QPointF(100,100)); shape2->setPosition(QPointF(200,200)); shapeLayer->addShape(shape1); shapeLayer->addShape(shape2); QApplication::processEvents(); } bool checkLayersInitial(KisImageWSP image, int baseFuzzyness = 0) { QString prefix = "initial_with_selection"; QString prefix2 = findNode(image->root(), "shape") ? "_with_shape" : ""; return checkLayers(image, prefix + prefix2, baseFuzzyness); } bool checkLayersInitialRootOnly(KisImageWSP image, int baseFuzzyness = 0) { QString prefix = "initial_with_selection"; QString prefix2 = findNode(image->root(), "shape") ? "_with_shape" : ""; return checkLayers(image, prefix + prefix2, baseFuzzyness, false); } /** * Checks the content of image's layers against the set of * QImages stored in @p prefix subfolder */ bool checkLayers(KisImageWSP image, const QString &prefix, int baseFuzzyness = 0, bool recursive = true) { QVector images; QVector names; fillNamesImages(image->root(), image->bounds(), images, names, recursive); bool valid = true; const int stackSize = images.size(); for(int i = 0; i < stackSize; i++) { if(!checkOneQImage(images[i], prefix, names[i], baseFuzzyness)) { valid = false; } } return valid; } /** * Checks the content of one image's layer against the QImage * stored in @p prefix subfolder */ bool checkOneLayer(KisImageWSP image, KisNodeSP node, const QString &prefix, int baseFuzzyness = 0) { QVector images; QVector names; fillNamesImages(node, image->bounds(), images, names); return checkOneQImage(images.first(), prefix, names.first(), baseFuzzyness); } // add default bounds param bool checkOneDevice(KisPaintDeviceSP device, const QString &prefix, const QString &name, int baseFuzzyness = 0) { QImage image = device->convertToQImage(0); return checkOneQImage(image, prefix, name, baseFuzzyness); } KisNodeSP findNode(KisNodeSP root, const QString &name) { return TestUtil::findNode(root, name); } private: bool checkOneQImage(const QImage &image, const QString &prefix, const QString &name, int baseFuzzyness) { QString realName = prefix + "_" + name + ".png"; QString expectedName = prefix + "_" + name + "_expected.png"; bool valid = true; QString fullPath = fetchDataFileLazy(m_directoryName + QDir::separator() + prefix + QDir::separator() + realName); if (fullPath.isEmpty()) { // Try without the testname subdirectory fullPath = fetchDataFileLazy(prefix + QDir::separator() + realName); } if (fullPath.isEmpty()) { // Try without the prefix subdirectory fullPath = fetchDataFileLazy(m_directoryName + QDir::separator() + realName); } QImage ref(fullPath); QPoint temp; int fuzzy = baseFuzzyness; { QStringList terms = name.split('_'); if(terms[0] == "root" || terms[0] == "blur1" || terms[0] == "shape") { fuzzy++; } } if(ref != image && !TestUtil::compareQImages(temp, ref, image, fuzzy)) { dbgKrita << "--- Wrong image:" << realName; valid = false; image.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + realName); ref.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + expectedName); } return valid; } void fillNamesImages(KisNodeSP node, const QRect &rc, QVector &images, QVector &names, bool recursive = true) { while (node) { if(node->paintDevice()) { names.append(node->name() + "_paintDevice"); images.append(node->paintDevice()-> convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height())); } if(node->original() && node->original() != node->paintDevice()) { names.append(node->name() + "_original"); images.append(node->original()-> convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height())); } if(node->projection() && node->projection() != node->paintDevice()) { names.append(node->name() + "_projection"); images.append(node->projection()-> convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height())); } if (recursive) { fillNamesImages(node->firstChild(), rc, images, names); } node = node->nextSibling(); } } private: QString m_directoryName; }; } #endif /* __QIMAGE_BASED_TEST_H */ diff --git a/sdk/tests/ui_manager_test.h b/sdk/tests/ui_manager_test.h index 66e5c89ffb..47cec974bc 100644 --- a/sdk/tests/ui_manager_test.h +++ b/sdk/tests/ui_manager_test.h @@ -1,181 +1,181 @@ /* * Copyright (c) 2012 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 __UI_MANAGER_TEST_H #define __UI_MANAGER_TEST_H #include "testutil.h" #include "qimage_based_test.h" - +#include #include #include "kis_resource_server_provider.h" #include "kis_canvas_resource_provider.h" #include "kis_filter_strategy.h" #include "kis_selection_manager.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "KisView.h" #include "KisPart.h" #include #include #include #include "KisMainWindow.h" #include "kis_selection_mask.h" namespace TestUtil { class UiManagerTest : public TestUtil::QImageBasedTest { public: UiManagerTest(bool useSelection, bool useShapeLayer, const QString &testName) : QImageBasedTest(testName) // "selection_manager_test" { undoStore = new KisSurrogateUndoStore(); image = createImage(undoStore); part = KisPart::instance(); doc = qobject_cast(part->createDocument()); doc->setCurrentImage(image); if(useSelection) addGlobalSelection(image); if(useShapeLayer) addShapeLayer(doc, image); image->initialRefreshGraph(); mainWindow = new KisMainWindow(); imageView = new KisView(doc, mainWindow->resourceManager(), mainWindow->actionCollection(), mainWindow); view = new KisViewManager(mainWindow, mainWindow->actionCollection()); KoPattern *newPattern = new KoPattern(fetchDataFileLazy("HR_SketchPaper_01.pat")); newPattern->load(); Q_ASSERT(newPattern->valid()); view->resourceProvider()->slotPatternActivated(newPattern); KoColor fgColor(Qt::black, image->colorSpace()); KoColor bgColor(Qt::white, image->colorSpace()); view->resourceProvider()->blockSignals(true); view->resourceProvider()->setBGColor(bgColor); view->resourceProvider()->setFGColor(fgColor); view->resourceProvider()->setOpacity(1.0); KisNodeSP paint1 = findNode(image->root(), "paint1"); Q_ASSERT(paint1); imageView->setViewManager(view); view->setCurrentView(imageView); view->nodeManager()->slotUiActivatedNode(paint1); selectionManager = view->selectionManager(); Q_ASSERT(selectionManager); actionManager = view->actionManager(); Q_ASSERT(actionManager); QVERIFY(checkLayersInitial()); } ~UiManagerTest() { /** * Here is a weird way of precessing pending events. * This is needed for the dummies facade could process * all the queued events telling it some nodes were * added/deleted */ QApplication::processEvents(); QTest::qSleep(500); QApplication::processEvents(); delete mainWindow; delete doc; /** * The event queue may have up to 200k events * by the time all the tests are finished. Removing * all of them may last forever, so clear them after * every single test is finished */ QApplication::removePostedEvents(0); } void checkUndo() { undoStore->undo(); image->waitForDone(); QVERIFY(checkLayersInitial()); } void checkDoubleUndo() { undoStore->undo(); undoStore->undo(); image->waitForDone(); QVERIFY(checkLayersInitial()); } void startConcurrentTask() { KisFilterStrategy * filter = new KisBoxFilterStrategy(); QSize initialSize = image->size(); image->scaleImage(2 * initialSize, image->xRes(), image->yRes(), filter); image->waitForDone(); image->scaleImage(initialSize, image->xRes(), image->yRes(), filter); } using QImageBasedTest::checkLayers; bool checkLayers(const QString &name) { return checkLayers(image, name); } using QImageBasedTest::checkLayersInitial; bool checkLayersInitial() { return checkLayersInitial(image); } bool checkLayersFuzzy(const QString &name) { return checkLayers(image, name, 1); } bool checkSelectionOnly(const QString &name) { KisNodeSP mask = dynamic_cast(image->root().data())->selectionMask(); return checkOneLayer(image, mask, name); } bool checkNoSelection() { KisNodeSP mask = dynamic_cast(image->root().data())->selectionMask(); return !mask && !image->globalSelection(); } KisImageSP image; KisSelectionManager *selectionManager; KisActionManager *actionManager; KisSurrogateUndoStore *undoStore; protected: KisView *imageView; KisViewManager *view; KisDocument *doc; KisPart *part; KisMainWindow *mainWindow; }; } #endif /* __UI_MANAGER_TEST_H */