diff --git a/3rdparty/ext_qt/0010-Fix-tablet-jitter-on-X11.patch b/3rdparty/ext_qt/0010-Fix-tablet-jitter-on-X11.patch index 16eac9379d..799c1eee3c 100644 --- a/3rdparty/ext_qt/0010-Fix-tablet-jitter-on-X11.patch +++ b/3rdparty/ext_qt/0010-Fix-tablet-jitter-on-X11.patch @@ -1,59 +1,68 @@ -From 999992ae79d1bc17bc4d7cbd49a8cd94cfce4e22 Mon Sep 17 00:00:00 2001 +From a05a69e789006bbf3fbfdd1998bc58af7b826b4b Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Sun, 10 Mar 2019 14:48:58 +0300 Subject: [PATCH] Fix tablet jitter on X11 We should get the correct stylus position from the valuators, not from the X11-provided global position. Global position is rounded to the nearest FP16 values, which is not enough for smooth painting. + +Change-Id: Ie701446b3586296bcb8fb09158f387ba6a7cbf07 --- - src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) + src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp -index 04ddd3c..8b79f2d 100644 +index 04ddd3c..20aca33 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1208,6 +1208,11 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD return handled; } +inline qreal scaleOneValuator(qreal normValue, qreal screenMin, qreal screenSize) +{ + return screenMin + normValue * screenSize; +} + void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData) { auto *ev = reinterpret_cast(event); -@@ -1221,6 +1226,8 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD +@@ -1221,6 +1226,15 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD double pressure = 0, rotation = 0, tangentialPressure = 0; int xTilt = 0, yTilt = 0; -+ const QRect screenArea = window->screen()->virtualGeometry(); ++ // Valuators' values are relative to the physical size of the current virtual ++ // screen. Therefore we cannot use QScreen/QWindow geometry and should use ++ // QPlatformWindow/QPlatformScreen instead. ++ QRect physicalScreenArea; ++ const QList siblings = window->screen()->handle()->virtualSiblings(); ++ for (const QPlatformScreen *screen : siblings) { ++ physicalScreenArea |= screen->geometry(); ++ } + for (QHash::iterator it = tabletData->valuatorInfo.begin(), ite = tabletData->valuatorInfo.end(); it != ite; ++it) { int valuator = it.key(); -@@ -1228,6 +1235,18 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD +@@ -1228,6 +1242,18 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal); double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal); switch (valuator) { + case QXcbAtom::AbsX: { -+ const qreal value = scaleOneValuator(normalizedValue, screenArea.x(), screenArea.width()); -+ global.rx() = value; -+ local.rx() = value - window->geometry().x(); ++ const qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.x(), physicalScreenArea.width()); ++ global.setX(value); ++ local.setX(value - window->handle()->geometry().x()); + break; + } + case QXcbAtom::AbsY: { -+ qreal value = scaleOneValuator(normalizedValue, screenArea.y(), screenArea.height()); -+ global.ry() = value; -+ local.ry() = value - window->geometry().y(); ++ qreal value = scaleOneValuator(normalizedValue, physicalScreenArea.y(), physicalScreenArea.height()); ++ global.setY(value); ++ local.setY(value - window->handle()->geometry().y()); + break; + } case QXcbAtom::AbsPressure: pressure = normalizedValue; break; -- 2.7.4 diff --git a/3rdparty/ext_qt/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch b/3rdparty/ext_qt/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch index 95c78d5263..e304f7fff1 100644 --- a/3rdparty/ext_qt/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch +++ b/3rdparty/ext_qt/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch @@ -1,27 +1,28 @@ -From 421860a79b6cab0ca67884314aadd9a2e2ece55f Mon Sep 17 00:00:00 2001 +From 8b82ab988807cd424e2e54b29dea4cde8e687fab Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov Date: Sun, 10 Mar 2019 14:51:28 +0300 Subject: [PATCH] Add an ID for recognition of UGEE tablets +Change-Id: I2228ee9d53aa23a2d2cd9970a363d8424e744093 --- src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp -index 8b79f2d..b8a83ba 100644 +index 20aca33..411366f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -240,6 +240,10 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) } else if (name.contains("uc-logic") && isTablet) { tabletData.pointerType = QTabletEvent::Pen; dbgType = QLatin1String("pen"); + } else if (name.contains("ugee")) { + isTablet = true; + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); } else { isTablet = false; } -- 2.7.4 diff --git a/3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch b/3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch similarity index 79% rename from 3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch rename to 3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch index 55c148f892..b5db94adc3 100644 --- a/3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch +++ b/3rdparty/ext_qt/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch @@ -1,38 +1,39 @@ -From 2365cd9067491214b4bc27b193813d9a5f527755 Mon Sep 17 00:00:00 2001 +From a36e3651fe79bbbdea44d78e11a97705687cffa9 Mon Sep 17 00:00:00 2001 From: Dmitry Kazakov -Date: Sun, 10 Mar 2019 19:41:33 +0300 -Subject: [PATCH] Synthesize Enter/LeaveEvent when QTabletEvent is accepted by - the receiver +Date: Mon, 11 Mar 2019 13:18:06 +0300 +Subject: [PATCH] Synthesize Enter/LeaveEvent for accepted QTabletEvent When the tablet event is accepted, then Qt doesn't synthesize a mouse event, it means that QApplicationPrivate::sendMouseEvent() will not be called, and, therefore, enter/leave events will not be dispatched. The patch looks a bit hackish. Ideally, the synthesize should happen in QGuiApplicationPrivate::processTabletEvent(), which takes the decision about synthesizing mouse events. But there is not enough information -on this level: neither qt_last_mouse_receiver nor the reciever widget +on this level: neither qt_last_mouse_receiver nor the receiver widget are known at this stage. + +Change-Id: Ifbad6284483ee282ad129db54606f5d0d9ddd633 --- src/widgets/kernel/qwidgetwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp -index 991a05f..cafb79e 100644 +index e9b749d..983ab77 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -1053,6 +1053,11 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) event->setAccepted(ev.isAccepted()); } + if (event->isAccepted() && widget != qt_last_mouse_receiver) { + QApplicationPrivate::dispatchEnterLeave(widget, qt_last_mouse_receiver, event->globalPos()); + qt_last_mouse_receiver = widget; + } + if (event->type() == QEvent::TabletRelease && event->buttons() == Qt::NoButton) qt_tablet_target = 0; } -- 2.7.4 diff --git a/3rdparty/ext_qt/CMakeLists.txt b/3rdparty/ext_qt/CMakeLists.txt index 0a48102107..603606a338 100644 --- a/3rdparty/ext_qt/CMakeLists.txt +++ b/3rdparty/ext_qt/CMakeLists.txt @@ -1,224 +1,224 @@ SET(EXTPREFIX_qt "${EXTPREFIX}") if (WIN32) list(APPEND _QT_conf -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtgraphicaleffects -skip qtlocation -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-qml-debug -no-ssl -no-libproxy -no-system-proxies -no-icu -no-mtdev -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard # -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg # -opensource -confirm-license # -release -platform win32-g++ -prefix ${EXTPREFIX_qt} QMAKE_LFLAGS_APP+=${SECURITY_EXE_LINKER_FLAGS} QMAKE_LFLAGS_SHLIB+=${SECURITY_SHARED_LINKER_FLAGS} QMAKE_LFLAGS_SONAME+=${SECURITY_SHARED_LINKER_FLAGS} ) if (QT_ENABLE_DEBUG_INFO) # Set the option to build Qt with debugging info enabled list(APPEND _QT_conf -force-debug-info) endif(QT_ENABLE_DEBUG_INFO) if (QT_ENABLE_DYNAMIC_OPENGL) list(APPEND _QT_conf -opengl dynamic -angle) else (QT_ENABLE_DYNAMIC_OPENGL) list(APPEND _QT_conf -opengl desktop -no-angle) endif (QT_ENABLE_DYNAMIC_OPENGL) ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5 99c2eb46e533371798b4ca2d1458e065 PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0001-disable-wintab.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0002-Don-t-request-the-MIME-image-every-time-Windows-asks.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0003-Hack-always-return-we-support-DIBV5.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0004-Fix-debug-on-openGL-ES.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0005-cumulative-patch-for-hdr.patch INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND /configure.bat ${_QT_conf} BUILD_COMMAND mingw32-make -j${SUBMAKE_JOBS} INSTALL_COMMAND mingw32-make -j${SUBMAKE_JOBS} install UPDATE_COMMAND "" # Use a short name to reduce the chance of exceeding path length limit SOURCE_DIR s BINARY_DIR b DEPENDS ext_patch ) elseif (NOT APPLE) ExternalProject_Add( ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5 99c2eb46e533371798b4ca2d1458e065 PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0010-Fix-tablet-jitter-on-X11.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0011-Add-an-ID-for-recognition-of-UGEE-tablets.patch - COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch + COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0013-Poison-Qt-s-headers-with-a-mark-about-presence-of-En.patch CMAKE_ARGS -DOPENSSL_LIBS='-L${EXTPREFIX_qt}/lib -lssl -lcrypto' CONFIGURE_COMMAND /configure -prefix ${EXTPREFIX_qt} -opensource -confirm-license -openssl-linked -verbose -nomake examples -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtgraphicaleffects -skip qtlocation -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebsockets -skip qtwebview -skip qtandroidextras -skip qtserialport -skip qtdatavis3d -skip qtvirtualkeyboard -skip qtspeech -skip qtsensors -skip qtgamepad -skip qtscxml -skip qtremoteobjects -skip qtxmlpatterns -skip qtnetworkauth -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtpurchasing -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard -skip qtmultimedia INSTALL_DIR ${EXTPREFIX_qt} BUILD_COMMAND $(MAKE) INSTALL_COMMAND $(MAKE) install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ) else( APPLE ) # XCODE_VERSION is set by CMake when using the Xcode generator, otherwise we need # to detect it manually here. if (NOT XCODE_VERSION) execute_process( COMMAND xcodebuild -version OUTPUT_VARIABLE xcodebuild_version OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_FILE /dev/null ) string(REGEX MATCH "Xcode ([0-9]+([.][0-9]+)*)" version_match ${xcodebuild_version}) if (version_match) message(STATUS "${EXTPREFIX_qt}:Identified Xcode Version: ${CMAKE_MATCH_1}") set(XCODE_VERSION ${CMAKE_MATCH_1}) else() # If detecting Xcode version failed, set a crazy high version so we default # to the newest. set(XCODE_VERSION 99) message(WARNING "${EXTPREFIX_qt}:Failed to detect the version of an installed copy of Xcode, falling back to highest supported version. Set XCODE_VERSION to override.") endif(version_match) endif(NOT XCODE_VERSION) # ------------------------------------------------------------------------------- # Verify the Xcode installation on Mac OS like Qt5.7 does/will # If not stop now, the system isn't configured correctly for Qt. # No reason to even proceed. # ------------------------------------------------------------------------------- set(XCSELECT_OUTPUT) find_program(XCSELECT_PROGRAM "xcode-select") if(XCSELECT_PROGRAM) message(STATUS "${EXTPREFIX_qt}:Found XCSELECT_PROGRAM as ${XCSELECT_PROGRAM}") set(XCSELECT_COMMAND ${XCSELECT_PROGRAM} "--print-path") execute_process( COMMAND ${XCSELECT_COMMAND} RESULT_VARIABLE XCSELECT_COMMAND_RESULT OUTPUT_VARIABLE XCSELECT_COMMAND_OUTPUT ERROR_FILE /dev/null ) if(NOT XCSELECT_COMMAND_RESULT) # returned 0, we're ok. string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" XCSELECT_COMMAND_OUTPUT ${XCSELECT_COMMAND_OUTPUT}) else() string(REPLACE ";" " " XCSELECT_COMMAND_STR "${XCSELECT_COMMAND}") # message(STATUS "${XCSELECT_COMMAND_STR}") message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} test failed with status ${XCSELECT_COMMAND_RESULT}") endif() else() message(FATAL_ERROR "${EXTPREFIX_qt}:${XCSELECT_PROGRAM} not found. No Xcode is selected. Use xcode-select -switch to choose an Xcode version") endif() # Belts and suspenders # Beyond all the Xcode and Qt version checking, the proof of the pudding # lies in the success/failure of this command: xcrun --find xcrun. # On failure a patch is necessary, otherwise we're ok # So hard check xcrun now... set(XCRUN_OUTPUT) find_program(XCRUN_PROGRAM "xcrun") if(XCRUN_PROGRAM) message(STATUS "${EXTPREFIX_qt}:Found XCRUN_PROGRAM as ${XCRUN_PROGRAM}") set(XCRUN_COMMAND ${XCRUN_PROGRAM} "--find xcrun") execute_process( COMMAND ${XCRUN_COMMAND} RESULT_VARIABLE XCRUN_COMMAND_RESULT OUTPUT_VARIABLE XCRUN_COMMAND_OUTPUT ERROR_FILE /dev/null ) if(NOT XCRUN_COMMAND_RESULT) # returned 0, we're ok. string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" XCRUN_COMMAND_OUTPUT ${XCRUN_COMMAND_OUTPUT}) else() string(REPLACE ";" " " XCRUN_COMMAND_STR "${XCRUN_COMMAND}") # message(STATUS "${XCRUN_COMMAND_STR}") message(STATUS "${EXTPREFIX_qt}:xcrun test failed with status ${XCRUN_COMMAND_RESULT}") endif() else() message(STATUS "${EXTPREFIX_qt}:xcrun not found -- ${XCRUN_PROGRAM}") endif() # # Now configure ext_qt accordingly # if ((XCRUN_COMMAND_RESULT) AND (NOT (XCODE_VERSION VERSION_LESS 8.0.0))) # Fix Xcode xcrun related issue. # NOTE: This should be fixed by Qt 5.7.1 see here: http://code.qt.io/cgit/qt/qtbase.git/commit/?h=dev&id=77a71c32c9d19b87f79b208929e71282e8d8b5d9 # NOTE: but no one's holding their breath. set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND}} -p1 -b -d /qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/mac_standardpaths_qtbug-61159.diff - COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch + COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0013-Poison-Qt-s-headers-with-a-mark-about-presence-of-En.patch #COMMAND ${PATCH_COMMAND} -p1 -b -d /qtbase/mkspecs/features/mac -i ${CMAKE_CURRENT_SOURCE_DIR}/mac-default.patch ) message(STATUS "${EXTPREFIX_qt}:Additional patches injected.") else() # No extra patches will be applied # NOTE: defaults for some untested scenarios like xcrun fails and xcode_version < 8. # NOTE: that is uncharted territory and (hopefully) a very unlikely scenario... - set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-when-QTabletEvent-is-acc.patch + set(ext_qt_PATCH_COMMAND ${PATCH_COMMAND} -p1 -d qtbase -i ${CMAKE_CURRENT_SOURCE_DIR}/0012-Synthesize-Enter-LeaveEvent-for-accepted-QTabletEven.patch ) endif() # Qt is big - try and parallelize if at all possible include(ProcessorCount) ProcessorCount(NUM_CORES) if(NOT NUM_CORES EQUAL 0) if (NUM_CORES GREATER 2) # be nice... MATH( EXPR NUM_CORES "${NUM_CORES} - 2" ) endif() set(PARALLEL_MAKE "make;-j${NUM_CORES}") message(STATUS "${EXTPREFIX_qt}:Parallelized make: ${PARALLEL_MAKE}") else() set(PARALLEL_MAKE "make") endif() ExternalProject_Add(ext_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} LOG_DOWNLOAD ON LOG_UPDATE ON LOG_CONFIGURE ON LOG_BUILD ON LOG_TEST ON LOG_INSTALL ON BUILD_IN_SOURCE ON URL https://download.qt.io/archive/qt/5.12/5.12.2/single/qt-everywhere-src-5.12.2.tar.xz URL_MD5=99c2eb46e533371798b4ca2d1458e065 CMAKE_ARGS -DOPENSSL_LIBS='-L${EXTPREFIX_qt}/lib -lssl -lcrypto' INSTALL_DIR ${EXTPREFIX_qt} CONFIGURE_COMMAND /configure -skip qt3d -skip qtactiveqt -skip qtcanvas3d -skip qtconnectivity -skip qtdoc -skip qtgraphicaleffects -skip qtlocation -skip qtsensors -skip qtserialport -skip qtwayland -skip qtwebchannel -skip qtwebsockets -skip qtwebview -skip qtxmlpatterns -no-sql-sqlite -skip qtcharts -skip qtdatavis3d -skip qtgamepad -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscxml -skip qtserialbus -skip qtspeech -skip qtvirtualkeyboard -nomake examples -nomake tools -no-compile-examples -no-dbus -no-iconv -no-qml-debug -no-libproxy -no-system-proxies -no-icu -no-mtdev -system-zlib -qt-pcre -opensource -confirm-license -openssl-linked -prefix ${EXTPREFIX_qt} BUILD_COMMAND ${PARALLEL_MAKE} INSTALL_COMMAND make install UPDATE_COMMAND "" BUILD_IN_SOURCE 1 ) endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 95eafb7470..5872ec1d94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,772 +1,772 @@ project(krita) message(STATUS "Using CMake version: ${CMAKE_VERSION}") cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) -set(MIN_QT_VERSION 5.10.0) +set(MIN_QT_VERSION 5.6.0) set(MIN_FRAMEWORKS_VERSION 5.18.0) if (POLICY CMP0002) cmake_policy(SET CMP0002 OLD) endif() if (POLICY CMP0017) cmake_policy(SET CMP0017 NEW) endif () if (POLICY CMP0022) cmake_policy(SET CMP0022 OLD) endif () if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() if (POLICY CMP0046) cmake_policy(SET CMP0046 OLD) endif () if (POLICY CMP0059) cmake_policy(SET CMP0059 OLD) endif() if (POLICY CMP0063) cmake_policy(SET CMP0063 OLD) endif() if (POLICY CMP0054) cmake_policy(SET CMP0054 OLD) endif() if (POLICY CMP0064) cmake_policy(SET CMP0064 OLD) endif() if (POLICY CMP0071) cmake_policy(SET CMP0071 OLD) endif() if (APPLE) set(APPLE_SUPPRESS_X11_WARNING TRUE) set(KDE_SKIP_RPATH_SETTINGS TRUE) set(CMAKE_MACOSX_RPATH 1) set(BUILD_WITH_INSTALL_RPATH 1) add_definitions(-mmacosx-version-min=10.11 -Wno-macro-redefined -Wno-deprecated-register) endif() if (CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9 AND NOT WIN32) add_definitions(-Wno-suggest-override) endif() ###################### ####################### ## Constants defines ## ####################### ###################### # define common versions of Krita applications, used to generate kritaversion.h # update these version for every release: set(KRITA_VERSION_STRING "4.2.0-pre-alpha") # Major version: 3 for 3.x, 4 for 4.x, etc. set(KRITA_STABLE_VERSION_MAJOR 4) # Minor version: 0 for 4.0, 1 for 4.1, etc. set(KRITA_STABLE_VERSION_MINOR 2) # Bugfix release version, or 0 for before the first stable release set(KRITA_VERSION_RELEASE 0) # the 4th digit, really only used for the Windows installer: # - [Pre-]Alpha: Starts from 0, increment 1 per release # - Beta: Starts from 50, increment 1 per release # - Stable: Set to 100, bump to 101 if emergency update is needed set(KRITA_VERSION_REVISION 0) set(KRITA_ALPHA 1) # uncomment only for Alpha #set(KRITA_BETA 1) # uncomment only for Beta #set(KRITA_RC 1) # uncomment only for RC set(KRITA_YEAR 2018) # update every year if(NOT DEFINED KRITA_ALPHA AND NOT DEFINED KRITA_BETA AND NOT DEFINED KRITA_RC) set(KRITA_STABLE 1) # do not edit endif() message(STATUS "Krita version: ${KRITA_VERSION_STRING}") # Define the generic version of the Krita libraries here # This makes it easy to advance it when the next Krita release comes. # 14 was the last GENERIC_KRITA_LIB_VERSION_MAJOR of the previous Krita series # (2.x) so we're starting with 15 in 3.x series, 16 in 4.x series if(KRITA_STABLE_VERSION_MAJOR EQUAL 4) math(EXPR GENERIC_KRITA_LIB_VERSION_MAJOR "${KRITA_STABLE_VERSION_MINOR} + 16") else() # let's make sure we won't forget to update the "16" message(FATAL_ERROR "Reminder: please update offset == 16 used to compute GENERIC_KRITA_LIB_VERSION_MAJOR to something bigger") endif() set(GENERIC_KRITA_LIB_VERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}.0.0") set(GENERIC_KRITA_LIB_SOVERSION "${GENERIC_KRITA_LIB_VERSION_MAJOR}") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") LIST (APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/kde_macro") # fetch git revision for the current build set(KRITA_GIT_SHA1_STRING "") set(KRITA_GIT_BRANCH_STRING "") include(GetGitRevisionDescription) get_git_head_hash(GIT_SHA1) get_git_branch(GIT_BRANCH) if(GIT_SHA1) string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1) set(KRITA_GIT_SHA1_STRING ${GIT_SHA1}) if(GIT_BRANCH) set(KRITA_GIT_BRANCH_STRING ${GIT_BRANCH}) else() set(KRITA_GIT_BRANCH_STRING "(detached HEAD)") endif() endif() # create test make targets enable_testing() # collect list of broken tests, empty here to start fresh with each cmake run set(KRITA_BROKEN_TESTS "" CACHE INTERNAL "KRITA_BROKEN_TESTS") ############ ############# ## Options ## ############# ############ include(FeatureSummary) if (WIN32) option(USE_DRMINGW "Support the Dr. Mingw crash handler (only on windows)" ON) add_feature_info("Dr. Mingw" USE_DRMINGW "Enable the Dr. Mingw crash handler") if (MINGW) option(USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags (mingw-w64)" ON) add_feature_info("Linker Security Flags" USE_MINGW_HARDENING_LINKER "Enable DEP (NX), ASLR and high-entropy ASLR linker flags") if (USE_MINGW_HARDENING_LINKER) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat -Wl,--disable-auto-image-base") if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # Enable high-entropy ASLR for 64-bit # The image base has to be >4GB for HEASLR to be enabled. # The values used here are kind of arbitrary. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x140000000") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--high-entropy-va -Wl,--image-base,0x180000000") endif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") else (USE_MINGW_HARDENING_LINKER) message(WARNING "Linker Security Flags not enabled!") endif (USE_MINGW_HARDENING_LINKER) endif (MINGW) endif () option(HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal." ON) configure_file(config-hide-safe-asserts.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hide-safe-asserts.h) add_feature_info("Hide Safe Asserts" HIDE_SAFE_ASSERTS "Don't show message box for \"safe\" asserts, just ignore them automatically and dump a message to the terminal.") option(USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking." ON) configure_file(config-hash-table-implementaion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hash-table-implementaion.h) add_feature_info("Lock free hash table" USE_LOCK_FREE_HASH_TABLE "Use lock free hash table instead of blocking.") option(FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true." OFF) add_feature_info("Foundation Build" FOUNDATION_BUILD "A Foundation build is a binary release build that can package some extra things like color themes. Linux distributions that build and install Krita into a default system location should not define this option to true.") option(KRITA_ENABLE_BROKEN_TESTS "Enable tests that are marked as broken" OFF) add_feature_info("Enable Broken Tests" KRITA_ENABLE_BROKEN_TESTS "Runs broken test when \"make test\" is invoked (use -DKRITA_ENABLE_BROKEN_TESTS=ON to enable).") option(HAVE_HDR "Enable HDR surface format selection. Available only on certain patched versions of Qt" OFF) configure_file(config-hdr.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-hdr.h) add_feature_info("Enable HDR" HAVE_HDR "Enable selection of HDR surface fort Krita window. Needs a particular patched version of Qt") option(LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode" ON) configure_file(config-limit-long-tests.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-limit-long-tests.h) add_feature_info("Limit long tests" LIMIT_LONG_TESTS "Run long running unittests in a limited quick mode") option(ENABLE_PYTHON_2 "Enables the compiler to look for Python 2.7 instead of Python 3. Some packaged scripts are not compatible with Python 2 and this should only be used if you really have to use 2.7." OFF) option(BUILD_KRITA_QT_DESIGNER_PLUGINS "Build Qt Designer plugins for Krita widgets" OFF) add_feature_info("Build Qt Designer plugins" BUILD_KRITA_QT_DESIGNER_PLUGINS "Builds Qt Designer plugins for Krita widgets (use -DBUILD_KRITA_QT_DESIGNER_PLUGINS=ON to enable).") include(MacroJPEG) ######################################################### ## Look for Python3 It is also searched by KF5, ## ## so we should request the correct version in advance ## ######################################################### function(TestCompileLinkPythonLibs OUTPUT_VARNAME) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${PYTHON_INCLUDE_PATH}) set(CMAKE_REQUIRED_LIBRARIES ${PYTHON_LIBRARIES}) if (MINGW) set(CMAKE_REQUIRED_DEFINITIONS -D_hypot=hypot) endif (MINGW) unset(${OUTPUT_VARNAME} CACHE) CHECK_CXX_SOURCE_COMPILES(" #include int main(int argc, char *argv[]) { Py_InitializeEx(0); }" ${OUTPUT_VARNAME}) endfunction() if(MINGW) if(ENABLE_PYTHON_2) message(FATAL_ERROR "Python 2.7 is not supported on Windows at the moment.") else(ENABLE_PYTHON_2) find_package(PythonInterp 3.6 EXACT) find_package(PythonLibs 3.6 EXACT) endif(ENABLE_PYTHON_2) if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) if(ENABLE_PYTHON_2) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonLibrary 3.6) endif(ENABLE_PYTHON_2) TestCompileLinkPythonLibs(CAN_USE_PYTHON_LIBS) if (NOT CAN_USE_PYTHON_LIBS) message(FATAL_ERROR "Compiling with Python library failed, please check whether the architecture is correct. Python will be disabled.") endif (NOT CAN_USE_PYTHON_LIBS) endif (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) else(MINGW) if(ENABLE_PYTHON_2) find_package(PythonInterp 2.7) find_package(PythonLibrary 2.7) else(ENABLE_PYTHON_2) find_package(PythonInterp 3.0) find_package(PythonLibrary 3.0) endif(ENABLE_PYTHON_2) endif(MINGW) ######################## ######################### ## Look for KDE and Qt ## ######################### ######################## find_package(ECM 5.22 REQUIRED NOMODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(ECMOptionalAddSubdirectory) include(ECMAddAppIcon) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(ECMMarkAsTest) include(ECMInstallIcons) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckFunctionExists) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) # do not reorder to be alphabetical: this is the order in which the frameworks # depend on each other. find_package(KF5 ${MIN_FRAMEWORKS_VERSION} REQUIRED COMPONENTS Config WidgetsAddons Completion CoreAddons GuiAddons I18n ItemModels ItemViews WindowSystem ) # KConfig deprecated authorizeKAction. In order to be warning free, # compile with the updated function when the dependency is new enough. # Remove this (and the uses of the define) when the minimum KF5 # version is >= 5.24.0. if (${KF5Config_VERSION} VERSION_LESS "5.24.0" ) message("Old KConfig (< 5.24.0) found.") add_definitions(-DKCONFIG_BEFORE_5_24) endif() find_package(Qt5 ${MIN_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Svg Test Concurrent Sql ) if (WIN32) option(USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt." ON) add_feature_info("Use Qt's Windows Tablet Support" USE_QT_TABLET_WINDOWS "Do not use Krita's forked Wintab and Windows Ink support on Windows, but leave everything to Qt.") configure_file(config_use_qt_tablet_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_use_qt_tablet_windows.h) endif () include (MacroAddFileDependencies) include (MacroBoolTo01) include (MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("Compiling Krita inside the source directory is not possible. Please refer to the build instruction https://community.kde.org/Krita#Build_Instructions") # Note: OPTIONAL_COMPONENTS does not seem to be reliable # (as of ECM 5.15.0, CMake 3.2) find_package(Qt5Multimedia ${MIN_QT_VERSION}) set_package_properties(Qt5Multimedia PROPERTIES DESCRIPTION "Qt multimedia integration" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide sound support for animations") macro_bool_to_01(Qt5Multimedia_FOUND HAVE_QT_MULTIMEDIA) configure_file(config-qtmultimedia.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-qtmultimedia.h ) if (NOT APPLE) find_package(Qt5Quick ${MIN_QT_VERSION}) set_package_properties(Qt5Quick PROPERTIES DESCRIPTION "QtQuick" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") macro_bool_to_01(Qt5Quick_FOUND HAVE_QT_QUICK) find_package(Qt5QuickWidgets ${MIN_QT_VERSION}) set_package_properties(Qt5QuickWidgets PROPERTIES DESCRIPTION "QtQuickWidgets" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used for the touch gui for Krita") endif() if (NOT WIN32 AND NOT APPLE) find_package(Qt5 ${MIN_QT_VERSION} REQUIRED X11Extras) find_package(Qt5DBus ${MIN_QT_VERSION}) set(HAVE_DBUS ${Qt5DBus_FOUND}) set_package_properties(Qt5DBus PROPERTIES DESCRIPTION "Qt DBUS integration" URL "http://www.qt.io/" TYPE OPTIONAL PURPOSE "Optionally used to provide a dbus api on Linux") find_package(KF5Crash ${MIN_FRAMEWORKS_VERSION}) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) set_package_properties(KF5Crash PROPERTIES DESCRIPTION "KDE's Crash Handler" URL "http://api.kde.org/frameworks-api/frameworks5-apidocs/kcrash/html/index.html" TYPE OPTIONAL PURPOSE "Optionally used to provide crash reporting on Linux") find_package(X11 REQUIRED COMPONENTS Xinput) set(HAVE_X11 TRUE) add_definitions(-DHAVE_X11) find_package(XCB COMPONENTS XCB ATOM) set(HAVE_XCB ${XCB_FOUND}) else() set(HAVE_DBUS FALSE) set(HAVE_X11 FALSE) set(HAVE_XCB FALSE) endif() add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_STRICT_ITERATORS -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING ) if (${Qt5_VERSION} VERSION_GREATER "5.8.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50900) elseif(${Qt5_VERSION} VERSION_GREATER "5.7.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50800) elseif(${Qt5_VERSION} VERSION_GREATER "5.6.0" ) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50700) else() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x50600) endif() add_definitions(-DTRANSLATION_DOMAIN=\"krita\") # # The reason for this mode is that the Debug mode disable inlining # if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") endif() option(KRITA_DEVS "For Krita developers. This modifies the DEBUG build type to use -O3 -g, while still enabling Q_ASSERT. This is necessary because the Qt5 cmake modules normally append QT_NO_DEBUG to any build type that is not labeled Debug") if (KRITA_DEVS) set(CMAKE_CXX_FLAGS_DEBUG "-O3 -g" CACHE STRING "" FORCE) endif() if(UNIX) set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m") endif() if(WIN32) if(MSVC) # C4522: 'class' : multiple assignment operators specified set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4522") endif() endif() # KDECompilerSettings adds the `--export-all-symbols` linker flag. # We don't really need it. if(MINGW) string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") string(REPLACE "-Wl,--export-all-symbols" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") endif(MINGW) # enable exceptions globally kde_enable_exceptions() set(KRITA_DEFAULT_TEST_DATA_DIR ${CMAKE_SOURCE_DIR}/sdk/tests/data/) macro(macro_add_unittest_definitions) add_definitions(-DFILES_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data/") add_definitions(-DFILES_OUTPUT_DIR="${CMAKE_CURRENT_BINARY_DIR}") add_definitions(-DFILES_DEFAULT_DATA_DIR="${KRITA_DEFAULT_TEST_DATA_DIR}") add_definitions(-DSYSTEM_RESOURCES_DATA_DIR="${CMAKE_SOURCE_DIR}/krita/data/") endmacro() # overcome some platform incompatibilities if(WIN32) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/winquirks) add_definitions(-D_USE_MATH_DEFINES) add_definitions(-DNOMINMAX) set(WIN32_PLATFORM_NET_LIBS ws2_32.lib netapi32.lib) endif() # set custom krita plugin installdir set(KRITA_PLUGIN_INSTALL_DIR ${LIB_INSTALL_DIR}/kritaplugins) ########################### ############################ ## Required dependencies ## ############################ ########################### find_package(PNG REQUIRED) if (APPLE) # this is not added correctly on OSX -- see http://forum.kde.org/viewtopic.php?f=139&t=101867&p=221242#p221242 include_directories(SYSTEM ${PNG_INCLUDE_DIR}) endif() add_definitions(-DBOOST_ALL_NO_LIB) find_package(Boost 1.55 REQUIRED COMPONENTS system) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) ## ## Test for GNU Scientific Library ## find_package(GSL) set_package_properties(GSL PROPERTIES URL "http://www.gnu.org/software/gsl" TYPE RECOMMENDED PURPOSE "Required by Krita's Transform tool.") macro_bool_to_01(GSL_FOUND HAVE_GSL) configure_file(config-gsl.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-gsl.h ) ########################### ############################ ## Optional dependencies ## ############################ ########################### find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Compression library" URL "http://www.zlib.net/" TYPE OPTIONAL PURPOSE "Optionally used by the G'Mic and the PSD plugins") macro_bool_to_01(ZLIB_FOUND HAVE_ZLIB) find_package(OpenEXR) set_package_properties(OpenEXR PROPERTIES DESCRIPTION "High dynamic-range (HDR) image file format" URL "http://www.openexr.com" TYPE OPTIONAL PURPOSE "Required by the Krita OpenEXR filter") macro_bool_to_01(OPENEXR_FOUND HAVE_OPENEXR) set(LINK_OPENEXR_LIB) if(OPENEXR_FOUND) include_directories(SYSTEM ${OPENEXR_INCLUDE_DIR}) set(LINK_OPENEXR_LIB ${OPENEXR_LIBRARIES}) add_definitions(${OPENEXR_DEFINITIONS}) endif() find_package(TIFF) set_package_properties(TIFF PROPERTIES DESCRIPTION "TIFF Library and Utilities" URL "http://www.remotesensing.org/libtiff" TYPE OPTIONAL PURPOSE "Required by the Krita TIFF filter") find_package(JPEG) set_package_properties(JPEG PROPERTIES DESCRIPTION "Free library for JPEG image compression. Note: libjpeg8 is NOT supported." URL "http://www.libjpeg-turbo.org" TYPE OPTIONAL PURPOSE "Required by the Krita JPEG filter") find_package(GIF) set_package_properties(GIF PROPERTIES DESCRIPTION "Library for loading and saving gif files." URL "http://giflib.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required by the Krita GIF filter") find_package(HEIF "1.3.0") set_package_properties(HEIF PROPERTIES DESCRIPTION "Library for loading and saving heif files." URL "https://github.com/strukturag/libheif" TYPE OPTIONAL PURPOSE "Required by the Krita HEIF filter") set(LIBRAW_MIN_VERSION "0.16") find_package(LibRaw ${LIBRAW_MIN_VERSION}) set_package_properties(LibRaw PROPERTIES DESCRIPTION "Library to decode RAW images" URL "http://www.libraw.org" TYPE OPTIONAL PURPOSE "Required to build the raw import plugin") find_package(FFTW3) set_package_properties(FFTW3 PROPERTIES DESCRIPTION "A fast, free C FFT library" URL "http://www.fftw.org/" TYPE OPTIONAL PURPOSE "Required by the Krita for fast convolution operators and some G'Mic features") macro_bool_to_01(FFTW3_FOUND HAVE_FFTW3) find_package(OCIO) set_package_properties(OCIO PROPERTIES DESCRIPTION "The OpenColorIO Library" URL "http://www.opencolorio.org" TYPE OPTIONAL PURPOSE "Required by the Krita LUT docker") macro_bool_to_01(OCIO_FOUND HAVE_OCIO) set_package_properties(PythonLibrary PROPERTIES DESCRIPTION "Python Library" URL "http://www.python.org" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYTHONLIBS_FOUND HAVE_PYTHONLIBS) find_package(SIP "4.19.13") set_package_properties(SIP PROPERTIES DESCRIPTION "Support for generating SIP Python bindings" URL "https://www.riverbankcomputing.com/software/sip/download" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(SIP_FOUND HAVE_SIP) find_package(PyQt5 "5.6.0") set_package_properties(PyQt5 PROPERTIES DESCRIPTION "Python bindings for Qt5." URL "https://www.riverbankcomputing.com/software/pyqt/download5" TYPE OPTIONAL PURPOSE "Required by the Krita PyQt plugin") macro_bool_to_01(PYQT5_FOUND HAVE_PYQT5) ## ## Look for OpenGL ## # TODO: see if there is a better check for QtGui being built with opengl support (and thus the QOpenGL* classes) if(Qt5Gui_OPENGL_IMPLEMENTATION) message(STATUS "Found QtGui OpenGL support") else() message(FATAL_ERROR "Did NOT find QtGui OpenGL support. Check your Qt configuration. You cannot build Krita without Qt OpenGL support.") endif() ## ## Test for eigen3 ## find_package(Eigen3 3.0 REQUIRED) set_package_properties(Eigen3 PROPERTIES DESCRIPTION "C++ template library for linear algebra" URL "http://eigen.tuxfamily.org" TYPE REQUIRED) ## ## Test for exiv2 ## find_package(LibExiv2 0.16 REQUIRED) ## ## Test for lcms ## find_package(LCMS2 2.4 REQUIRED) set_package_properties(LCMS2 PROPERTIES DESCRIPTION "LittleCMS Color management engine" URL "http://www.littlecms.com" TYPE REQUIRED PURPOSE "Will be used for color management and is necessary for Krita") if(LCMS2_FOUND) if(NOT ${LCMS2_VERSION} VERSION_LESS 2040 ) set(HAVE_LCMS24 TRUE) endif() set(HAVE_REQUIRED_LCMS_VERSION TRUE) set(HAVE_LCMS2 TRUE) endif() ## ## Test for Vc ## set(OLD_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) set(HAVE_VC FALSE) if (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") if(NOT MSVC) find_package(Vc 1.1.0) set_package_properties(Vc PROPERTIES DESCRIPTION "Portable, zero-overhead SIMD library for C++" URL "https://github.com/VcDevel/Vc" TYPE OPTIONAL PURPOSE "Required by the Krita for vectorization") macro_bool_to_01(Vc_FOUND HAVE_VC) endif() endif() configure_file(config-vc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-vc.h ) if(HAVE_VC) message(STATUS "Vc found!") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/vc") include (VcMacros) if(Vc_COMPILER_IS_CLANG) set(ADDITIONAL_VC_FLAGS "-Wabi -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() elseif (NOT MSVC) set(ADDITIONAL_VC_FLAGS "-Wabi -fabi-version=0 -ffp-contract=fast") if(NOT WIN32) set(ADDITIONAL_VC_FLAGS "${ADDITIONAL_VC_FLAGS} -fPIC") endif() endif() #Handle Vc master if(Vc_COMPILER_IS_GCC OR Vc_COMPILER_IS_CLANG) AddCompilerFlag("-std=c++11" _ok) if(NOT _ok) AddCompilerFlag("-std=c++0x" _ok) endif() endif() macro(ko_compile_for_all_implementations_no_scalar _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() macro(ko_compile_for_all_implementations _objs _src) vc_compile_for_all_implementations(${_objs} ${_src} FLAGS ${ADDITIONAL_VC_FLAGS} ONLY Scalar SSE2 SSSE3 SSE4_1 AVX AVX2+FMA+BMI2) endmacro() endif() set(CMAKE_MODULE_PATH ${OLD_CMAKE_MODULE_PATH} ) add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS}) ## ## Test endianness ## include (TestBigEndian) test_big_endian(CMAKE_WORDS_BIGENDIAN) ## ## Test for qt-poppler ## find_package(Poppler COMPONENTS Qt5) set_package_properties(Poppler PROPERTIES DESCRIPTION "A PDF rendering library" URL "http://poppler.freedesktop.org" TYPE OPTIONAL PURPOSE "Required by the Krita PDF filter.") ## ## Test for quazip ## find_package(QuaZip 0.6) set_package_properties(QuaZip PROPERTIES DESCRIPTION "A library for reading and writing zip files" URL "https://stachenov.github.io/quazip/" TYPE REQUIRED PURPOSE "Needed for reading and writing KRA and ORA files" ) ## ## Test for Atomics ## include(CheckAtomic) ############################ ############################# ## Add Krita helper macros ## ############################# ############################ include(MacroKritaAddBenchmark) #################### ##################### ## Define includes ## ##################### #################### # for config.h and includes (if any?) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/interfaces ) add_subdirectory(libs) add_subdirectory(plugins) add_subdirectory(benchmarks) add_subdirectory(krita) configure_file(KoConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/KoConfig.h ) configure_file(config_convolution.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_convolution.h) configure_file(config-ocio.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ocio.h ) check_function_exists(powf HAVE_POWF) configure_file(config-powf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-powf.h) if(WIN32) include(${CMAKE_CURRENT_LIST_DIR}/packaging/windows/installer/ConfigureInstallerNsis.cmake) endif() message("\nBroken tests:") foreach(tst ${KRITA_BROKEN_TESTS}) message(" * ${tst}") endforeach() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po OR EXISTS ${CMAKE_CURRENT_BINARY_DIR}/po ) find_package(KF5I18n CONFIG REQUIRED) ki18n_install(po) endif() diff --git a/libs/image/kis_types.h b/libs/image/kis_types.h index 19aeb25eb2..030b260d26 100644 --- a/libs/image/kis_types.h +++ b/libs/image/kis_types.h @@ -1,310 +1,313 @@ /* * 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 KisFileLayer; typedef KisSharedPtr KisFileLayerSP; typedef KisWeakSharedPtr KisFileLayerWSP; class KisSelection; typedef KisSharedPtr KisSelectionSP; typedef KisWeakSharedPtr KisSelectionWSP; class KisSelectionComponent; typedef KisSharedPtr KisSelectionComponentSP; 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; class KisReferenceImage; typedef QSharedPointer KisReferenceImageSP; typedef QWeakPointer KisReferenceImageWSP; // 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 QSharedPointer KisPaintOpPresetSP; typedef QWeakPointer KisPaintOpPresetWSP; template class KisPinnedSharedPtr; class KisPaintOpSettings; typedef KisPinnedSharedPtr KisPaintOpSettingsSP; template class KisRestrictedSharedPtr; typedef KisRestrictedSharedPtr KisPaintOpSettingsRestrictedSP; 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 KisPinnedSharedPtr KisFilterConfigurationSP; class KisPropertiesConfiguration; typedef KisPinnedSharedPtr KisPropertiesConfigurationSP; class KisLockedProperties; typedef KisSharedPtr KisLockedPropertiesSP; 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; class KisProofingConfiguration; typedef QSharedPointer KisProofingConfigurationSP; typedef QWeakPointer KisProofingConfigurationWSP; class KisLayerComposition; typedef QSharedPointer KisLayerCompositionSP; typedef QWeakPointer KisLayerCompositionWSP; +class KisMirrorAxis; +typedef KisSharedPtr KisMirrorAxisSP; +typedef KisWeakSharedPtr KisMirrorAxisWSP; #include #include #include #include #include #endif // KISTYPES_H_ diff --git a/libs/ui/canvas/kis_mirror_axis.cpp b/libs/ui/canvas/kis_mirror_axis.cpp index 39fc58b5dc..c226b64205 100644 --- a/libs/ui/canvas/kis_mirror_axis.cpp +++ b/libs/ui/canvas/kis_mirror_axis.cpp @@ -1,467 +1,466 @@ /* * Copyright (c) 2014 Arjen Hiemstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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_mirror_axis.h" #include "KoConfig.h" #include #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_canvas_resource_provider.h" #include "KisViewManager.h" #include "KisView.h" #include "kis_image.h" #include "canvas/kis_canvas_controller.h" #include "input/kis_input_manager.h" #include "kis_algebra_2d.h" #include #include #include class KisMirrorAxis::Private { public: Private(KisMirrorAxis* qq) : q(qq) , resourceProvider(0) , xActive(false) , yActive(false) , sideMargin(10.f) , minHandlePosition(10.f + 32.f) , horizontalContainsCursor(false) , verticalContainsCursor(false) , horizontalAxis(QLineF()) , verticalAxis(QLineF()) , config(KisMirrorAxisConfig()) { } void setAxisPosition(float x, float y); void recomputeVisibleAxes(QRect viewport); KisMirrorAxis* q; KisCanvasResourceProvider* resourceProvider; KisImageWSP image; QPixmap horizontalHandleIcon; QPixmap verticalHandleIcon; QPixmap horizontalIcon; QPixmap verticalIcon; QRectF horizontalHandle; QRectF verticalHandle; bool xActive; bool yActive; float sideMargin; float minHandlePosition; bool horizontalContainsCursor; bool verticalContainsCursor; QLineF horizontalAxis; QLineF verticalAxis; KisMirrorAxisConfig config; }; KisMirrorAxis::KisMirrorAxis(KisCanvasResourceProvider* provider, QPointerparent) : KisCanvasDecoration("mirror_axis", parent) , d(new Private(this)) { d->resourceProvider = provider; connect(d->resourceProvider, SIGNAL(mirrorModeChanged()), SLOT(mirrorModeChanged())); connect(d->resourceProvider, SIGNAL(moveMirrorVerticalCenter()), SLOT(moveVerticalAxisToCenter())); connect(d->resourceProvider, SIGNAL(moveMirrorHorizontalCenter()), SLOT(moveHorizontalAxisToCenter())); d->config.setMirrorHorizontal(d->resourceProvider->mirrorHorizontal()); d->config.setMirrorVertical(d->resourceProvider->mirrorVertical()); d->horizontalIcon = KisIconUtils::loadIcon("mirrorAxis-HorizontalMove").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("mirrorAxis-VerticalMove").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); d->image = parent->canvasBase()->image(); } KisMirrorAxis::~KisMirrorAxis() { - delete d; } float KisMirrorAxis::handleSize() const { return d->config.handleSize(); } void KisMirrorAxis::setHandleSize(float newSize) { if(d->config.handleSize() != newSize) { d->config.setHandleSize(newSize); - d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horyzontal").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horizontal").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("symmetry-vertical").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->minHandlePosition = d->sideMargin + newSize; emit handleSizeChanged(); emit sigConfigChanged(); } } void KisMirrorAxis::drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter* converter, KisCanvas2* canvas) { Q_UNUSED(updateArea); Q_UNUSED(converter); Q_UNUSED(canvas); if (!view()->isCurrent()) { return; } gc.save(); gc.setPen(QPen(QColor(0, 0, 0, 128), 1)); gc.setBrush(Qt::white); gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); QOpenGLContext *ctx = QOpenGLContext::currentContext(); bool hasMultisample = ((gc.paintEngine()->type() == QPaintEngine::OpenGL2) && (ctx->hasExtension("GL_ARB_multisample"))); // QPainter cannot anti-alias the edges of circles etc. when using OpenGL // So instead, use native OpenGL anti-aliasing when available. if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glEnable(GL_MULTISAMPLE); gc.endNativePainting(); } float halfHandleSize = d->config.handleSize() / 2; d->recomputeVisibleAxes(gc.viewport()); if(d->config.mirrorHorizontal() && !d->config.hideHorizontalDecoration()) { if (!d->horizontalAxis.isNull()) { // QPointF horizontalIndicatorCenter = d->horizontalAxis.unitVector().pointAt(15); // QRectF horizontalIndicator = QRectF(horizontalIndicatorCenter.x() - halfHandleSize, horizontalIndicatorCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); float horizontalHandlePosition = qBound(d->minHandlePosition, d->config.horizontalHandlePosition(), d->horizontalAxis.length() - d->minHandlePosition); QPointF horizontalHandleCenter = d->horizontalAxis.unitVector().pointAt(horizontalHandlePosition); d->horizontalHandle = QRectF(horizontalHandleCenter.x() - halfHandleSize, horizontalHandleCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->horizontalAxis); // gc.drawEllipse(horizontalIndicator); // gc.drawPixmap(horizontalIndicator.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); // don't draw the handles if we are locking the axis for movement if (!d->config.lockHorizontal()) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->horizontalHandle); gc.drawPixmap(d->horizontalHandle.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); } } else { d->horizontalHandle = QRectF(); } } if(d->config.mirrorVertical() && !d->config.hideVerticalDecoration()) { if (!d->verticalAxis.isNull()) { gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->verticalAxis); // QPointF verticalIndicatorCenter = d->verticalAxis.unitVector().pointAt(15); // QRectF verticalIndicator = QRectF(verticalIndicatorCenter.x() - halfHandleSize, verticalIndicatorCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); float verticalHandlePosition = qBound(d->minHandlePosition, d->config.verticalHandlePosition(), d->verticalAxis.length() - d->minHandlePosition); QPointF verticalHandleCenter = d->verticalAxis.unitVector().pointAt(verticalHandlePosition); d->verticalHandle = QRectF(verticalHandleCenter.x() - halfHandleSize, verticalHandleCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); // don't draw the handles if we are locking the axis for movement if (!d->config.lockVertical()) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->verticalHandle); gc.drawPixmap(d->verticalHandle.adjusted(5, 5, -5, -5).toRect(), d->verticalIcon); } } else { d->verticalHandle = QRectF(); } } if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glDisable(GL_MULTISAMPLE); gc.endNativePainting(); } gc.restore(); } bool KisMirrorAxis::eventFilter(QObject* target, QEvent* event) { if (!visible()) return false; QObject *expectedCanvasWidget = view() ? view()->canvasBase()->canvasWidget() : 0; if (!expectedCanvasWidget || target != expectedCanvasWidget) return false; if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::TabletPress) { QMouseEvent *me = dynamic_cast(event); QTabletEvent *te = dynamic_cast(event); QPoint pos = me ? me->pos() : (te ? te->pos() : QPoint(77,77)); if(d->config.mirrorHorizontal() && d->horizontalHandle.contains(pos) && !d->config.lockHorizontal() && !d->config.hideHorizontalDecoration() ) { d->xActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } if(d->config.mirrorVertical() && d->verticalHandle.contains(pos) && !d->config.lockVertical() && !d->config.hideVerticalDecoration()) { d->yActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } } if(event->type() == QEvent::MouseMove || event->type() == QEvent::TabletMove) { QMouseEvent *me = dynamic_cast(event); QTabletEvent *te = dynamic_cast(event); QPoint pos = me ? me->pos() : (te ? te->pos() : QPoint(77,77)); if(d->xActive) { float axisX = view()->viewConverter()->widgetToImage(pos).x(); d->setAxisPosition(axisX, d->config.axisPosition().y()); d->config.setHorizontalHandlePosition(KisAlgebra2D::dotProduct(pos - d->horizontalAxis.p1(), d->horizontalAxis.unitVector().p2() - d->horizontalAxis.p1())); emit sigConfigChanged(); event->accept(); return true; } if(d->yActive) { float axisY = view()->viewConverter()->widgetToImage(pos).y(); d->setAxisPosition(d->config.axisPosition().x(), axisY); d->config.setVerticalHandlePosition(KisAlgebra2D::dotProduct(pos - d->verticalAxis.p1(), d->verticalAxis.unitVector().p2() - d->verticalAxis.p1())); emit sigConfigChanged(); event->accept(); return true; } if(d->config.mirrorHorizontal() && !d->config.hideHorizontalDecoration()) { if(d->horizontalHandle.contains(pos) && !d->config.lockHorizontal()) { if(!d->horizontalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->horizontalContainsCursor = true; } } else if(d->horizontalContainsCursor) { QApplication::restoreOverrideCursor(); d->horizontalContainsCursor = false; } } if(d->config.mirrorVertical() && !d->config.hideVerticalDecoration()) { if(d->verticalHandle.contains(pos) && !d->config.lockVertical()) { if(!d->verticalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->verticalContainsCursor = true; } } else if(d->verticalContainsCursor) { QApplication::restoreOverrideCursor(); d->verticalContainsCursor = false; } } } if(event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TabletRelease) { if(d->xActive) { QApplication::restoreOverrideCursor(); d->xActive = false; event->accept(); return true; } if(d->yActive) { QApplication::restoreOverrideCursor(); d->yActive = false; event->accept(); return true; } } return QObject::eventFilter(target, event); } void KisMirrorAxis::mirrorModeChanged() { if (!view()->isCurrent()) { return; } d->config.setMirrorHorizontal(d->resourceProvider->mirrorHorizontal()); d->config.setMirrorVertical(d->resourceProvider->mirrorVertical()); d->config.setLockHorizontal(d->resourceProvider->mirrorHorizontalLock()); d->config.setLockVertical(d->resourceProvider->mirrorVerticalLock()); d->config.setHideHorizontalDecoration(d->resourceProvider->mirrorHorizontalHideDecorations()); d->config.setHideVerticalDecoration(d->resourceProvider->mirrorVerticalHideDecorations()); setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); emit sigConfigChanged(); } void KisMirrorAxis::setVisible(bool v) { KisCanvasDecoration::setVisible(v); KisInputManager *inputManager = view() ? view()->canvasBase()->globalInputManager() : 0; if (!inputManager) return; if (v) { inputManager->attachPriorityEventFilter(this); } else { inputManager->detachPriorityEventFilter(this); } } void KisMirrorAxis::setMirrorAxisConfig(const KisMirrorAxisConfig &config) { if (config != d->config) { KisSignalsBlocker blocker(d->resourceProvider); d->config = config; d->setAxisPosition(d->config.axisPosition().x(), d->config.axisPosition().y()); d->resourceProvider->setMirrorHorizontal(d->config.mirrorHorizontal()); d->resourceProvider->setMirrorVertical(d->config.mirrorVertical()); d->resourceProvider->setMirrorHorizontalLock(d->config.lockHorizontal()); d->resourceProvider->setMirrorVerticalLock(d->config.lockVertical()); d->resourceProvider->setMirrorHorizontal(d->config.mirrorHorizontal()); d->resourceProvider->setMirrorVertical(d->config.mirrorVertical()); d->resourceProvider->setMirrorHorizontalHideDecorations(d->config.hideHorizontalDecoration()); d->resourceProvider->setMirrorVerticalHideDecorations(d->config.hideVerticalDecoration()); } toggleMirrorActions(); setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); } const KisMirrorAxisConfig &KisMirrorAxis::mirrorAxisConfig() const { return d->config; } void KisMirrorAxis::toggleMirrorActions() { KActionCollection* collection = view()->viewManager()->actionCollection(); // first uncheck the action, then set according to config; // otherwise the connected KisHighlightedToolButton's highlight color is not // properly set collection->action("hmirror_action")->setChecked(false); collection->action("vmirror_action")->setChecked(false); if (d->config.mirrorHorizontal()) { collection->action("hmirror_action")->setChecked(d->config.mirrorHorizontal()); } if (d->config.mirrorVertical()) { collection->action("vmirror_action")->setChecked(d->config.mirrorVertical()); } collection->action("mirrorX-lock")->setChecked(d->config.lockHorizontal()); collection->action("mirrorY-lock")->setChecked(d->config.lockVertical()); collection->action("mirrorX-hideDecorations")->setChecked(d->config.hideHorizontalDecoration()); collection->action("mirrorY-hideDecorations")->setChecked(d->config.hideVerticalDecoration()); } void KisMirrorAxis::moveHorizontalAxisToCenter() { if (!view()->isCurrent()) { return; } d->setAxisPosition(d->image->width()/2, d->config.axisPosition().y()); emit sigConfigChanged(); } void KisMirrorAxis::moveVerticalAxisToCenter() { if (!view()->isCurrent()) { return; } d->setAxisPosition(d->config.axisPosition().x(), d->image->height()/2 ); emit sigConfigChanged(); } void KisMirrorAxis::Private::setAxisPosition(float x, float y) { QPointF newPosition = QPointF(x, y); config.setAxisPosition(newPosition); const QPointF relativePosition = KisAlgebra2D::absoluteToRelative(newPosition, image->bounds()); image->setMirrorAxesCenter(relativePosition); q->view()->canvasBase()->updateCanvas(); } void KisMirrorAxis::Private::recomputeVisibleAxes(QRect viewport) { KisCoordinatesConverter *converter = q->view()->viewConverter(); config.setAxisPosition(KisAlgebra2D::relativeToAbsolute(image->mirrorAxesCenter(), image->bounds())); QPointF samplePt1 = converter->imageToWidget(config.axisPosition()); QPointF samplePt2 = converter->imageToWidget(QPointF(config.axisPosition().x(), config.axisPosition().y() - 100)); horizontalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(horizontalAxis, viewport)) horizontalAxis = QLineF(); samplePt2 = converter->imageToWidget(QPointF(config.axisPosition().x() - 100, config.axisPosition().y())); verticalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(verticalAxis, viewport)) verticalAxis = QLineF(); } diff --git a/libs/ui/canvas/kis_mirror_axis.h b/libs/ui/canvas/kis_mirror_axis.h index 1176f0e737..fd2b78881c 100644 --- a/libs/ui/canvas/kis_mirror_axis.h +++ b/libs/ui/canvas/kis_mirror_axis.h @@ -1,64 +1,66 @@ /* * Copyright (c) 2014 Arjen Hiemstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef KISMIRRORAXIS_H #define KISMIRRORAXIS_H +#include + #include "kis_canvas_decoration.h" class KisView; class KisCanvasResourceProvider; class KisMirrorAxisConfig; class KisMirrorAxis : public KisCanvasDecoration { Q_OBJECT Q_PROPERTY(float handleSize READ handleSize WRITE setHandleSize NOTIFY handleSizeChanged) public: KisMirrorAxis(KisCanvasResourceProvider* provider, QPointer parent); ~KisMirrorAxis() override; float handleSize() const; void setHandleSize(float newSize); void setVisible(bool v) override; void setMirrorAxisConfig(const KisMirrorAxisConfig& config); const KisMirrorAxisConfig& mirrorAxisConfig() const; Q_SIGNALS: void handleSizeChanged(); void sigConfigChanged(); protected: void drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter* converter, KisCanvas2* canvas) override; bool eventFilter(QObject* target, QEvent* event) override; void toggleMirrorActions(); private: class Private; - Private * const d; + const QScopedPointer d; private Q_SLOTS: void mirrorModeChanged(); void moveHorizontalAxisToCenter(); void moveVerticalAxisToCenter(); }; #endif // KISMIRRORAXIS_H diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc index f75426d7da..a48e8ce96e 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -1,1651 +1,1655 @@ /* * preferencesdlg.cc - part of KImageShop * * Copyright (c) 1999 Michael Koch * Copyright (c) 2003-2011 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_dlg_preferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoID.h" #include #include #include #include #include #include #include #include "KisProofingConfiguration.h" #include "KoColorConversionTransformation.h" #include "kis_action_registry.h" #include #include #include "kis_clipboard.h" #include "widgets/kis_cmb_idlist.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "kis_action_registry.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_color_manager.h" #include "kis_config.h" #include "kis_cursor.h" #include "kis_image_config.h" #include "kis_preference_set_registry.h" #include "widgets/kis_cmb_idlist.h" #include #include "kis_file_name_requester.h" #include #include #include #include "slider_and_spin_box_sync.h" // for the performance update #include #include #include "input/config/kis_input_configuration_page.h" #include "input/wintab/drawpile_tablettester/tablettester.h" #ifdef Q_OS_WIN #include "config_use_qt_tablet_windows.h" # ifndef USE_QT_TABLET_WINDOWS # include # endif #endif struct BackupSuffixValidator : public QValidator { BackupSuffixValidator(QObject *parent) : QValidator(parent) , invalidCharacters(QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "/" << "\\" << ":" << ";" << " ") {} ~BackupSuffixValidator() override {} const QStringList invalidCharacters; State validate(QString &line, int &/*pos*/) const override { Q_FOREACH(const QString invalidChar, invalidCharacters) { if (line.contains(invalidChar)) { return Invalid; } } return Acceptable; } }; GeneralTab::GeneralTab(QWidget *_parent, const char *_name) : WdgGeneralSettings(_parent, _name) { KisConfig cfg(true); // // Cursor Tab // m_cmbCursorShape->addItem(i18n("No Cursor")); m_cmbCursorShape->addItem(i18n("Tool Icon")); m_cmbCursorShape->addItem(i18n("Arrow")); m_cmbCursorShape->addItem(i18n("Small Circle")); m_cmbCursorShape->addItem(i18n("Crosshair")); m_cmbCursorShape->addItem(i18n("Triangle Righthanded")); m_cmbCursorShape->addItem(i18n("Triangle Lefthanded")); m_cmbCursorShape->addItem(i18n("Black Pixel")); m_cmbCursorShape->addItem(i18n("White Pixel")); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle()); m_cmbOutlineShape->addItem(i18n("No Outline")); m_cmbOutlineShape->addItem(i18n("Circle Outline")); m_cmbOutlineShape->addItem(i18n("Preview Outline")); m_cmbOutlineShape->addItem(i18n("Tilt Outline")); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle()); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting()); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline()); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor()); cursorColorBtutton->setColor(cursorColor); // // Window Tab // m_cmbMDIType->setCurrentIndex(cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView)); m_backgroundimage->setText(cfg.getMDIBackgroundImage()); connect(m_bnFileName, SIGNAL(clicked()), SLOT(getBackgroundImage())); connect(clearBgImageButton, SIGNAL(clicked()), SLOT(clearBackgroundImage())); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor()); m_mdiColor->setColor(mdiColor); m_chkRubberBand->setChecked(cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); m_chkHiDPI->setChecked(kritarc.value("EnableHiDPI", true).toBool()); chkUsageLogging->setChecked(kritarc.value("LogUsage", true).toBool()); m_chkSingleApplication->setChecked(kritarc.value("EnableSingleApplication", true).toBool()); // // Tools tab // m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker()); cmbFlowMode->setCurrentIndex((int)!cfg.readEntry("useCreamyAlphaDarken", true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt()); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas()); chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste()); m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled()); m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag")); m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag")); m_cmbKineticScrollingGesture->addItem(i18n("On Middle-Click Drag")); //m_cmbKineticScrollingGesture->addItem(i18n("On Right Click Drag")); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture()); m_kineticScrollingSensitivitySlider->setRange(0, 100); m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity()); m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars()); // // File handling // int autosaveInterval = cfg.autoSaveInterval(); //convert to minutes m_autosaveSpinBox->setValue(autosaveInterval / 60); m_autosaveCheckBox->setChecked(autosaveInterval > 0); chkHideAutosaveFiles->setChecked(cfg.readEntry("autosavefileshidden", true)); m_chkCompressKra->setChecked(cfg.compressKra()); chkZip64->setChecked(cfg.useZip64()); m_backupFileCheckBox->setChecked(cfg.backupFile()); cmbBackupFileLocation->setCurrentIndex(cfg.readEntry("backupfilelocation", 0)); txtBackupFileSuffix->setText(cfg.readEntry("backupfilesuffix", "~")); QValidator *validator = new BackupSuffixValidator(txtBackupFileSuffix); txtBackupFileSuffix->setValidator(validator); intNumBackupFiles->setValue(cfg.readEntry("numberofbackupfiles", 1)); // // Miscellaneous // cmbStartupSession->addItem(i18n("Open default window")); cmbStartupSession->addItem(i18n("Load previous session")); cmbStartupSession->addItem(i18n("Show session manager")); cmbStartupSession->setCurrentIndex(cfg.sessionOnStartup()); chkSaveSessionOnQuit->setChecked(cfg.saveSessionOnQuit(false)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport()); m_undoStackSize->setValue(cfg.undoStackLimit()); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets()); chkShowRootLayer->setChecked(cfg.showRootLayer()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); bool dontUseNative = true; #ifdef Q_OS_UNIX if (qgetenv("XDG_CURRENT_DESKTOP") == "KDE") { dontUseNative = false; } #endif #ifdef Q_OS_WIN dontUseNative = false; #endif m_chkNativeFileDialog->setChecked(!group.readEntry("DontUseNativeFileDialog", dontUseNative)); intMaxBrushSize->setValue(cfg.readEntry("maximumBrushSize", 1000)); // // Resources // m_urlCacheDbLocation->setMode(KoFileDialog::OpenDirectory); m_urlCacheDbLocation->setConfigurationName("cachedb_location"); m_urlCacheDbLocation->setFileName(cfg.readEntry(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); m_urlResourceFolder->setMode(KoFileDialog::OpenDirectory); m_urlResourceFolder->setConfigurationName("resource_directory"); m_urlResourceFolder->setFileName(cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); } void GeneralTab::setDefault() { KisConfig cfg(true); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle(true)); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle(true)); chkShowRootLayer->setChecked(cfg.showRootLayer(true)); m_autosaveCheckBox->setChecked(cfg.autoSaveInterval(true) > 0); //convert to minutes m_autosaveSpinBox->setValue(cfg.autoSaveInterval(true) / 60); chkHideAutosaveFiles->setChecked(true); m_undoStackSize->setValue(cfg.undoStackLimit(true)); m_backupFileCheckBox->setChecked(cfg.backupFile(true)); cmbBackupFileLocation->setCurrentIndex(0); txtBackupFileSuffix->setText("~"); intNumBackupFiles->setValue(1); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting(true)); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline(true)); m_chkNativeFileDialog->setChecked(false); intMaxBrushSize->setValue(1000); m_cmbMDIType->setCurrentIndex((int)QMdiArea::TabbedView); m_chkRubberBand->setChecked(cfg.useOpenGL(true)); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets(true)); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor(true)); m_mdiColor->setColor(mdiColor); m_backgroundimage->setText(cfg.getMDIBackgroundImage(true)); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true)); m_chkCompressKra->setChecked(cfg.compressKra(true)); chkZip64->setChecked(cfg.useZip64(true)); m_chkHiDPI->setChecked(false); m_chkSingleApplication->setChecked(true); m_chkHiDPI->setChecked(true); chkUsageLogging->setChecked(true); m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true)); cmbFlowMode->setCurrentIndex(0); m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled(true)); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture(true)); m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity(true)); m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars(true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true)); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas(true)); chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste(true)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport(true)); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor(true)); cursorColorBtutton->setColor(cursorColor); m_urlCacheDbLocation->setFileName(cfg.readEntry(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); m_urlResourceFolder->setFileName(cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); } CursorStyle GeneralTab::cursorStyle() { return (CursorStyle)m_cmbCursorShape->currentIndex(); } OutlineStyle GeneralTab::outlineStyle() { return (OutlineStyle)m_cmbOutlineShape->currentIndex(); } KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const { return (KisConfig::SessionOnStartup)cmbStartupSession->currentIndex(); } bool GeneralTab::saveSessionOnQuit() const { return chkSaveSessionOnQuit->isChecked(); } bool GeneralTab::showRootLayer() { return chkShowRootLayer->isChecked(); } int GeneralTab::autoSaveInterval() { //convert to seconds return m_autosaveCheckBox->isChecked() ? m_autosaveSpinBox->value() * 60 : 0; } int GeneralTab::undoStackSize() { return m_undoStackSize->value(); } bool GeneralTab::showOutlineWhilePainting() { return m_showOutlinePainting->isChecked(); } int GeneralTab::mdiMode() { return m_cmbMDIType->currentIndex(); } int GeneralTab::favoritePresets() { return m_favoritePresetsSpinBox->value(); } bool GeneralTab::showCanvasMessages() { return m_chkCanvasMessages->isChecked(); } bool GeneralTab::compressKra() { return m_chkCompressKra->isChecked(); } bool GeneralTab::useZip64() { return chkZip64->isChecked(); } bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); } bool GeneralTab::kineticScrollingEnabled() { return m_groupBoxKineticScrollingSettings->isChecked(); } int GeneralTab::kineticScrollingGesture() { return m_cmbKineticScrollingGesture->currentIndex(); } int GeneralTab::kineticScrollingSensitivity() { return m_kineticScrollingSensitivitySlider->value(); } bool GeneralTab::kineticScrollingHiddenScrollbars() { return m_chkKineticScrollingHideScrollbars->isChecked(); } bool GeneralTab::switchSelectionCtrlAlt() { return m_chkSwitchSelectionCtrlAlt->isChecked(); } bool GeneralTab::convertToImageColorspaceOnImport() { return m_chkConvertOnImport->isChecked(); } void GeneralTab::getBackgroundImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BackgroundImages"); dialog.setCaption(i18n("Select a Background Image")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setImageFilters(); QString fn = dialog.filename(); // dialog box was canceled or somehow no file was selected if (fn.isEmpty()) { return; } QImage image(fn); if (image.isNull()) { QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("%1 is not a valid image file!", fn)); } else { m_backgroundimage->setText(fn); } } void GeneralTab::clearBackgroundImage() { // clearing the background image text will implicitly make the background color be used m_backgroundimage->setText(""); } #include "kactioncollection.h" #include "KisActionsSnapshot.h" ShortcutSettingsTab::ShortcutSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgShortcutSettings(this); l->addWidget(m_page, 0, 0); m_snapshot.reset(new KisActionsSnapshot); KActionCollection *collection = KisPart::instance()->currentMainwindow()->actionCollection(); Q_FOREACH (QAction *action, collection->actions()) { m_snapshot->addAction(action->objectName(), action); } QMap sortedCollections = m_snapshot->actionCollections(); for (auto it = sortedCollections.constBegin(); it != sortedCollections.constEnd(); ++it) { m_page->addCollection(it.value(), it.key()); } } ShortcutSettingsTab::~ShortcutSettingsTab() { } void ShortcutSettingsTab::setDefault() { m_page->allDefault(); } void ShortcutSettingsTab::saveChanges() { m_page->save(); KisActionRegistry::instance()->settingsPageSaved(); } void ShortcutSettingsTab::cancelChanges() { m_page->undo(); } ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); // XXX: Make sure only profiles that fit the specified color model // are shown in the profile combos QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgColorSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg(true); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile()); connect(m_page->chkUseSystemMonitorProfile, SIGNAL(toggled(bool)), this, SLOT(toggleAllowMonitorProfileSelection(bool))); m_page->cmbWorkingColorSpace->setIDList(KoColorSpaceRegistry::instance()->listKeys()); m_page->cmbWorkingColorSpace->setCurrent(cfg.workingColorSpace()); m_page->bnAddColorProfile->setIcon(KisIconUtils::loadIcon("document-open")); m_page->bnAddColorProfile->setToolTip( i18n("Open Color Profile") ); connect(m_page->bnAddColorProfile, SIGNAL(clicked()), SLOT(installProfile())); QFormLayout *monitorProfileGrid = new QFormLayout(m_page->monitorprofileholder); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QLabel *lbl = new QLabel(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileLabels << lbl; KisSqueezedComboBox *cmb = new KisSqueezedComboBox(); cmb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); monitorProfileGrid->addRow(lbl, cmb); m_monitorProfileWidgets << cmb; } refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation()); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization()); m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors()); KisImageConfig cfgImage(true); KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); m_page->sldAdaptationState->setMaximum(20); m_page->sldAdaptationState->setMinimum(0); m_page->sldAdaptationState->setValue((int)proofingConfig->adaptationState*20); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_pasteBehaviourGroup.addButton(m_page->radioPasteWeb, PASTE_ASSUME_WEB); m_pasteBehaviourGroup.addButton(m_page->radioPasteMonitor, PASTE_ASSUME_MONITOR); m_pasteBehaviourGroup.addButton(m_page->radioPasteAsk, PASTE_ASK); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour()); Q_ASSERT(button); if (button) { button->setChecked(true); } m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent()); toggleAllowMonitorProfileSelection(cfg.useSystemMonitorProfile()); } void ColorSettingsTab::installProfile() { KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocumentICC"); dialog.setCaption(i18n("Install Color Profiles")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setMimeTypeFilters(QStringList() << "application/vnd.iccprofile", "application/vnd.iccprofile"); QStringList profileNames = dialog.filenames(); KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); Q_ASSERT(iccEngine); QString saveLocation = KoResourcePaths::saveLocation("icc_profiles"); Q_FOREACH (const QString &profileName, profileNames) { if (!QFile::copy(profileName, saveLocation + QFileInfo(profileName).fileName())) { qWarning() << "Could not install profile!" << saveLocation + QFileInfo(profileName).fileName(); continue; } iccEngine->addProfile(saveLocation + QFileInfo(profileName).fileName()); } KisConfig cfg(true); refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } void ColorSettingsTab::toggleAllowMonitorProfileSelection(bool useSystemProfile) { KisConfig cfg(true); if (useSystemProfile) { QStringList devices = KisColorManager::instance()->devices(); if (devices.size() == QApplication::desktop()->screenCount()) { for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); QString monitorForScreen = cfg.monitorForScreen(i, devices[i]); Q_FOREACH (const QString &device, devices) { m_monitorProfileLabels[i]->setText(i18nc("The display/screen we got from Qt", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->addSqueezedItem(KisColorManager::instance()->deviceName(device), device); if (devices[i] == monitorForScreen) { m_monitorProfileWidgets[i]->setCurrentIndex(i); } } } } } else { refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } } void ColorSettingsTab::setDefault() { m_page->cmbWorkingColorSpace->setCurrent("RGBA"); refillMonitorProfiles(KoID("RGBA")); KisConfig cfg(true); KisImageConfig cfgImage(true); KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,proofingConfig->proofingDepth,proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_page->sldAdaptationState->setValue(0); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation(true)); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization(true)); m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors(true)); m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent(true)); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile(true)); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour(true)); Q_ASSERT(button); if (button) { button->setChecked(true); } } void ColorSettingsTab::refillMonitorProfiles(const KoID & colorSpaceId) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); } QMap profileList; Q_FOREACH(const KoColorProfile *profile, KoColorSpaceRegistry::instance()->profilesFor(colorSpaceId.id())) { profileList[profile->name()] = profile; } Q_FOREACH (const KoColorProfile *profile, profileList.values()) { //qDebug() << "Profile" << profile->name() << profile->isSuitableForDisplay() << csf->defaultProfile(); if (profile->isSuitableForDisplay()) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->addSqueezedItem(profile->name()); } } } for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileLabels[i]->setText(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->setCurrent(KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId.id())); } } //--------------------------------------------------------------------------------------------------- void TabletSettingsTab::setDefault() { KisCubicCurve curve; curve.fromString(DEFAULT_CURVE_STRING); m_page->pressureCurve->setCurve(curve); #ifdef Q_OS_WIN #ifndef USE_QT_TABLET_WINDOWS if (KisTabletSupportWin8::isAvailable()) { KisConfig cfg(true); m_page->radioWintab->setChecked(!cfg.useWin8PointerInput(true)); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput(true)); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); } #else m_page->grpTabletApi->setVisible(false); #endif #endif } TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgTabletSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg(true); KisCubicCurve curve; curve.fromString( cfg.pressureTabletCurve() ); m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); m_page->pressureCurve->setCurve(curve); #ifdef Q_OS_WIN #ifndef USE_QT_TABLET_WINDOWS if (KisTabletSupportWin8::isAvailable()) { m_page->radioWintab->setChecked(!cfg.useWin8PointerInput()); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput()); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); m_page->grpTabletApi->setVisible(false); } #else m_page->grpTabletApi->setVisible(false); #endif #else m_page->grpTabletApi->setVisible(false); #endif connect(m_page->btnTabletTest, SIGNAL(clicked()), SLOT(slotTabletTest())); } void TabletSettingsTab::slotTabletTest() { TabletTestDialog tabletTestDialog(this); tabletTestDialog.exec(); } //--------------------------------------------------------------------------------------------------- #include "kis_acyclic_signal_connector.h" int getTotalRAM() { return KisImageConfig(true).totalRAM(); } int PerformanceTab::realTilesRAM() { return intMemoryLimit->value() - intPoolLimit->value(); } PerformanceTab::PerformanceTab(QWidget *parent, const char *name) : WdgPerformanceSettings(parent, name) { KisImageConfig cfg(true); const double totalRAM = cfg.totalRAM(); lblTotalMemory->setText(KFormat().formatByteSize(totalRAM * 1024 * 1024, 0, KFormat::IECBinaryDialect, KFormat::UnitMegaByte)); sliderMemoryLimit->setSuffix(i18n(" %")); sliderMemoryLimit->setRange(1, 100, 2); sliderMemoryLimit->setSingleStep(0.01); sliderPoolLimit->setSuffix(i18n(" %")); sliderPoolLimit->setRange(0, 20, 2); sliderMemoryLimit->setSingleStep(0.01); sliderUndoLimit->setSuffix(i18n(" %")); sliderUndoLimit->setRange(0, 50, 2); sliderMemoryLimit->setSingleStep(0.01); intMemoryLimit->setMinimumWidth(80); intPoolLimit->setMinimumWidth(80); intUndoLimit->setMinimumWidth(80); SliderAndSpinBoxSync *sync1 = new SliderAndSpinBoxSync(sliderMemoryLimit, intMemoryLimit, getTotalRAM); sync1->slotParentValueChanged(); m_syncs << sync1; SliderAndSpinBoxSync *sync2 = new SliderAndSpinBoxSync(sliderPoolLimit, intPoolLimit, std::bind(&KisIntParseSpinBox::value, intMemoryLimit)); connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync2, SLOT(slotParentValueChanged())); sync2->slotParentValueChanged(); m_syncs << sync2; SliderAndSpinBoxSync *sync3 = new SliderAndSpinBoxSync(sliderUndoLimit, intUndoLimit, std::bind(&PerformanceTab::realTilesRAM, this)); connect(intPoolLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged())); sync3->slotParentValueChanged(); m_syncs << sync3; sliderSwapSize->setSuffix(i18n(" GiB")); sliderSwapSize->setRange(1, 64); intSwapSize->setRange(1, 64); KisAcyclicSignalConnector *swapSizeConnector = new KisAcyclicSignalConnector(this); swapSizeConnector->connectForwardInt(sliderSwapSize, SIGNAL(valueChanged(int)), intSwapSize, SLOT(setValue(int))); swapSizeConnector->connectBackwardInt(intSwapSize, SIGNAL(valueChanged(int)), sliderSwapSize, SLOT(setValue(int))); lblSwapFileLocation->setText(cfg.swapDir()); connect(bnSwapFile, SIGNAL(clicked()), SLOT(selectSwapDir())); sliderThreadsLimit->setRange(1, QThread::idealThreadCount()); sliderFrameClonesLimit->setRange(1, QThread::idealThreadCount()); sliderFpsLimit->setRange(20, 100); sliderFpsLimit->setSuffix(i18n(" fps")); connect(sliderThreadsLimit, SIGNAL(valueChanged(int)), SLOT(slotThreadsLimitChanged(int))); connect(sliderFrameClonesLimit, SIGNAL(valueChanged(int)), SLOT(slotFrameClonesLimitChanged(int))); intCachedFramesSizeLimit->setRange(1, 10000); intCachedFramesSizeLimit->setSuffix(i18n(" px")); intCachedFramesSizeLimit->setSingleStep(1); intCachedFramesSizeLimit->setPageStep(1000); intRegionOfInterestMargin->setRange(1, 100); intRegionOfInterestMargin->setSuffix(i18n(" %")); intRegionOfInterestMargin->setSingleStep(1); intRegionOfInterestMargin->setPageStep(10); connect(chkCachedFramesSizeLimit, SIGNAL(toggled(bool)), intCachedFramesSizeLimit, SLOT(setEnabled(bool))); connect(chkUseRegionOfInterest, SIGNAL(toggled(bool)), intRegionOfInterestMargin, SLOT(setEnabled(bool))); load(false); } PerformanceTab::~PerformanceTab() { qDeleteAll(m_syncs); } void PerformanceTab::load(bool requestDefault) { KisImageConfig cfg(true); sliderMemoryLimit->setValue(cfg.memoryHardLimitPercent(requestDefault)); sliderPoolLimit->setValue(cfg.memoryPoolLimitPercent(requestDefault)); sliderUndoLimit->setValue(cfg.memorySoftLimitPercent(requestDefault)); chkPerformanceLogging->setChecked(cfg.enablePerfLog(requestDefault)); chkProgressReporting->setChecked(cfg.enableProgressReporting(requestDefault)); sliderSwapSize->setValue(cfg.maxSwapSize(requestDefault) / 1024); lblSwapFileLocation->setText(cfg.swapDir(requestDefault)); m_lastUsedThreadsLimit = cfg.maxNumberOfThreads(requestDefault); m_lastUsedClonesLimit = cfg.frameRenderingClones(requestDefault); sliderThreadsLimit->setValue(m_lastUsedThreadsLimit); sliderFrameClonesLimit->setValue(m_lastUsedClonesLimit); sliderFpsLimit->setValue(cfg.fpsLimit(requestDefault)); { KisConfig cfg2(true); chkOpenGLFramerateLogging->setChecked(cfg2.enableOpenGLFramerateLogging(requestDefault)); chkBrushSpeedLogging->setChecked(cfg2.enableBrushSpeedLogging(requestDefault)); chkDisableVectorOptimizations->setChecked(cfg2.enableAmdVectorizationWorkaround(requestDefault)); chkBackgroundCacheGeneration->setChecked(cfg2.calculateAnimationCacheInBackground(requestDefault)); } if (cfg.useOnDiskAnimationCacheSwapping(requestDefault)) { optOnDisk->setChecked(true); } else { optInMemory->setChecked(true); } chkCachedFramesSizeLimit->setChecked(cfg.useAnimationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setValue(cfg.animationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setEnabled(chkCachedFramesSizeLimit->isChecked()); chkUseRegionOfInterest->setChecked(cfg.useAnimationCacheRegionOfInterest(requestDefault)); intRegionOfInterestMargin->setValue(cfg.animationCacheRegionOfInterestMargin(requestDefault) * 100.0); intRegionOfInterestMargin->setEnabled(chkUseRegionOfInterest->isChecked()); } void PerformanceTab::save() { KisImageConfig cfg(false); cfg.setMemoryHardLimitPercent(sliderMemoryLimit->value()); cfg.setMemorySoftLimitPercent(sliderUndoLimit->value()); cfg.setMemoryPoolLimitPercent(sliderPoolLimit->value()); cfg.setEnablePerfLog(chkPerformanceLogging->isChecked()); cfg.setEnableProgressReporting(chkProgressReporting->isChecked()); cfg.setMaxSwapSize(sliderSwapSize->value() * 1024); cfg.setSwapDir(lblSwapFileLocation->text()); cfg.setMaxNumberOfThreads(sliderThreadsLimit->value()); cfg.setFrameRenderingClones(sliderFrameClonesLimit->value()); cfg.setFpsLimit(sliderFpsLimit->value()); { KisConfig cfg2(true); cfg2.setEnableOpenGLFramerateLogging(chkOpenGLFramerateLogging->isChecked()); cfg2.setEnableBrushSpeedLogging(chkBrushSpeedLogging->isChecked()); cfg2.setEnableAmdVectorizationWorkaround(chkDisableVectorOptimizations->isChecked()); cfg2.setCalculateAnimationCacheInBackground(chkBackgroundCacheGeneration->isChecked()); } cfg.setUseOnDiskAnimationCacheSwapping(optOnDisk->isChecked()); cfg.setUseAnimationCacheFrameSizeLimit(chkCachedFramesSizeLimit->isChecked()); cfg.setAnimationCacheFrameSizeLimit(intCachedFramesSizeLimit->value()); cfg.setUseAnimationCacheRegionOfInterest(chkUseRegionOfInterest->isChecked()); cfg.setAnimationCacheRegionOfInterestMargin(intRegionOfInterestMargin->value() / 100.0); } void PerformanceTab::selectSwapDir() { KisImageConfig cfg(true); QString swapDir = cfg.swapDir(); swapDir = QFileDialog::getExistingDirectory(0, i18nc("@title:window", "Select a swap directory"), swapDir); if (swapDir.isEmpty()) { return; } lblSwapFileLocation->setText(swapDir); } void PerformanceTab::slotThreadsLimitChanged(int value) { KisSignalsBlocker b(sliderFrameClonesLimit); sliderFrameClonesLimit->setValue(qMin(m_lastUsedClonesLimit, value)); m_lastUsedThreadsLimit = value; } void PerformanceTab::slotFrameClonesLimitChanged(int value) { KisSignalsBlocker b(sliderThreadsLimit); sliderThreadsLimit->setValue(qMax(m_lastUsedThreadsLimit, value)); m_lastUsedClonesLimit = value; } //--------------------------------------------------------------------------------------------------- #include "KoColor.h" #include "opengl/KisOpenGLModeProber.h" #include "opengl/KisScreenInformationAdapter.h" #include #include -QString colorSpaceString(QSurfaceFormat::ColorSpace cs, int depth) +QString colorSpaceString(KisSurfaceColorSpace cs, int depth) { const QString csString = #ifdef HAVE_HDR - cs == QSurfaceFormat::bt2020PQColorSpace ? "Rec. 2020 PQ" : - cs == QSurfaceFormat::scRGBColorSpace ? "Rec. 709 Linear" : + cs == KisSurfaceColorSpace::bt2020PQColorSpace ? "Rec. 2020 PQ" : + cs == KisSurfaceColorSpace::scRGBColorSpace ? "Rec. 709 Linear" : #endif - cs == QSurfaceFormat::sRGBColorSpace ? "sRGB" : - cs == QSurfaceFormat::DefaultColorSpace ? "sRGB" : + cs == KisSurfaceColorSpace::sRGBColorSpace ? "sRGB" : + cs == KisSurfaceColorSpace::DefaultColorSpace ? "sRGB" : "Unknown Color Space"; return QString("%1 (%2 bit)").arg(csString).arg(depth); } int formatToIndex(KisConfig::RootSurfaceFormat fmt) { return fmt == KisConfig::BT2020_PQ ? 1 : fmt == KisConfig::BT709_G10 ? 2 : 0; } KisConfig::RootSurfaceFormat indexToFormat(int value) { return value == 1 ? KisConfig::BT2020_PQ : value == 2 ? KisConfig::BT709_G10 : KisConfig::BT709_G22; } DisplaySettingsTab::DisplaySettingsTab(QWidget *parent, const char *name) : WdgDisplaySettings(parent, name) { KisConfig cfg(true); const QString rendererOpenGLText = i18nc("canvas renderer", "OpenGL"); #ifdef Q_OS_WIN const QString rendererOpenGLESText = i18nc("canvas renderer", "Direct3D 11 via ANGLE"); #else const QString rendererOpenGLESText = i18nc("canvas renderer", "OpenGL ES"); #endif lblCurrentRenderer->setText(KisOpenGL::hasOpenGLES() ? rendererOpenGLESText : rendererOpenGLText); cmbPreferredRenderer->clear(); QString qtPreferredRendererText; if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererOpenGLES) { qtPreferredRendererText = rendererOpenGLESText; } else { qtPreferredRendererText = rendererOpenGLText; } cmbPreferredRenderer->addItem(i18nc("canvas renderer", "Auto (%1)", qtPreferredRendererText), KisOpenGL::RendererAuto); cmbPreferredRenderer->setCurrentIndex(0); if (KisOpenGL::getSupportedOpenGLRenderers() & KisOpenGL::RendererDesktopGL) { cmbPreferredRenderer->addItem(rendererOpenGLText, KisOpenGL::RendererDesktopGL); if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererDesktopGL) { cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1); } } #ifdef Q_OS_WIN if (KisOpenGL::getSupportedOpenGLRenderers() & KisOpenGL::RendererOpenGLES) { cmbPreferredRenderer->addItem(rendererOpenGLESText, KisOpenGL::RendererOpenGLES); if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererOpenGLES) { cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1); } } #endif if (!(KisOpenGL::getSupportedOpenGLRenderers() & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererOpenGLES))) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL()); chkUseTextureBuffer->setEnabled(cfg.useOpenGL()); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer()); chkDisableVsync->setVisible(cfg.showAdvancedOpenGLSettings()); chkDisableVsync->setEnabled(cfg.useOpenGL()); chkDisableVsync->setChecked(cfg.disableVSync()); cmbFilterMode->setEnabled(cfg.useOpenGL()); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode()); // Don't show the high quality filtering mode if it's not available if (!KisOpenGL::supportsLoD()) { cmbFilterMode->removeItem(3); } } lblCurrentDisplayFormat->setText(""); lblCurrentRootSurfaceFormat->setText(""); lblHDRWarning->setText(""); - cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(QSurfaceFormat::sRGBColorSpace, 8)); + cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::sRGBColorSpace, 8)); #ifdef HAVE_HDR - cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(QSurfaceFormat::bt2020PQColorSpace, 10)); - cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(QSurfaceFormat::scRGBColorSpace, 16)); + cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::bt2020PQColorSpace, 10)); + cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::scRGBColorSpace, 16)); #endif cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22)); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); QOpenGLContext *context = QOpenGLContext::currentContext(); if (!context) { context = QOpenGLContext::globalShareContext(); } if (context) { QScreen *screen = QGuiApplication::screenAt(rect().center()); KisScreenInformationAdapter adapter(context); if (screen && adapter.isValid()) { KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen); if (info.isValid()) { QStringList toolTip; toolTip << i18n("Display Id: %1", info.screen->name()); toolTip << i18n("Display Name: %1 %2", info.screen->manufacturer(), info.screen->model()); toolTip << i18n("Min Luminance: %1", info.minLuminance); toolTip << i18n("Max Luminance: %1", info.maxLuminance); toolTip << i18n("Max Full Frame Luminance: %1", info.maxFullFrameLuminance); toolTip << i18n("Red Primary: %1, %2", info.redPrimary[0], info.redPrimary[1]); toolTip << i18n("Green Primary: %1, %2", info.greenPrimary[0], info.greenPrimary[1]); toolTip << i18n("Blue Primary: %1, %2", info.bluePrimary[0], info.bluePrimary[1]); toolTip << i18n("White Point: %1, %2", info.whitePoint[0], info.whitePoint[1]); lblCurrentDisplayFormat->setToolTip(toolTip.join('\n')); lblCurrentDisplayFormat->setText(colorSpaceString(info.colorSpace, info.bitsPerColor)); } else { lblCurrentDisplayFormat->setToolTip(""); lblCurrentDisplayFormat->setText(i18n("Unknown")); } } else { lblCurrentDisplayFormat->setToolTip(""); lblCurrentDisplayFormat->setText(i18n("Unknown")); qWarning() << "Failed to fetch display info:" << adapter.errorString(); } const QSurfaceFormat currentFormat = KisOpenGLModeProber::instance()->surfaceformatInUse(); - lblCurrentRootSurfaceFormat->setText(colorSpaceString(currentFormat.colorSpace(), currentFormat.redBufferSize())); +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + KisSurfaceColorSpace colorSpace = currentFormat.colorSpace(); +#else + KisSurfaceColorSpace colorSpace = KisSurfaceColorSpace::DefaultColorSpace; +#endif + lblCurrentRootSurfaceFormat->setText(colorSpaceString(colorSpace, currentFormat.redBufferSize())); cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(cfg.rootSurfaceFormat())); - connect(cmbPreferedRootSurfaceFormat, SIGNAL(currentIndexChanged(int)), SLOT(slotPreferredSurfaceFormatChanged(int))); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); } #ifndef HAVE_HDR grpHDRSettings->setVisible(false); #endif const QStringList openglWarnings = KisOpenGL::getOpenGLWarnings(); if (openglWarnings.isEmpty()) { lblOpenGLWarnings->setVisible(false); } else { QString text(" "); text.append(i18n("Warning(s):")); text.append("
    "); Q_FOREACH (const QString &warning, openglWarnings) { text.append("
  • "); text.append(warning.toHtmlEscaped()); text.append("
  • "); } text.append("
"); lblOpenGLWarnings->setText(text); lblOpenGLWarnings->setVisible(true); } if (qApp->applicationName() == "kritasketch" || qApp->applicationName() == "kritagemini") { grpOpenGL->setVisible(false); grpOpenGL->setMaximumHeight(0); } KisImageConfig imageCfg(false); KoColor c; c.fromQColor(imageCfg.selectionOverlayMaskColor()); c.setOpacity(1.0); btnSelectionOverlayColor->setColor(c); sldSelectionOverlayOpacity->setRange(0.0, 1.0, 2); sldSelectionOverlayOpacity->setSingleStep(0.05); sldSelectionOverlayOpacity->setValue(imageCfg.selectionOverlayMaskColor().alphaF()); intCheckSize->setValue(cfg.checkSize()); chkMoving->setChecked(cfg.scrollCheckers()); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1()); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2()); colorChecks2->setColor(ck2); KoColor cb(KoColorSpaceRegistry::instance()->rgb8()); cb.fromQColor(cfg.canvasBorderColor()); canvasBorder->setColor(cb); hideScrollbars->setChecked(cfg.hideScrollbars()); chkCurveAntialiasing->setChecked(cfg.antialiasCurves()); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline()); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor()); chkHidePopups->setChecked(cfg.hidePopups()); connect(grpOpenGL, SIGNAL(toggled(bool)), SLOT(slotUseOpenGLToggled(bool))); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor()); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold() * 100); } void DisplaySettingsTab::setDefault() { KisConfig cfg(true); cmbPreferredRenderer->setCurrentIndex(0); if (!(KisOpenGL::getSupportedOpenGLRenderers() & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererOpenGLES))) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL(true)); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer(true)); chkUseTextureBuffer->setEnabled(true); chkDisableVsync->setEnabled(true); chkDisableVsync->setChecked(cfg.disableVSync(true)); cmbFilterMode->setEnabled(true); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode(true)); } chkMoving->setChecked(cfg.scrollCheckers(true)); intCheckSize->setValue(cfg.checkSize(true)); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1(true)); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2(true)); colorChecks2->setColor(ck2); KoColor cvb(KoColorSpaceRegistry::instance()->rgb8()); cvb.fromQColor(cfg.canvasBorderColor(true)); canvasBorder->setColor(cvb); hideScrollbars->setChecked(cfg.hideScrollbars(true)); chkCurveAntialiasing->setChecked(cfg.antialiasCurves(true)); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline(true)); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor(true)); chkHidePopups->setChecked(cfg.hidePopups(true)); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor(true)); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold(true) * 100); cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22)); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); } void DisplaySettingsTab::slotUseOpenGLToggled(bool isChecked) { chkUseTextureBuffer->setEnabled(isChecked); chkDisableVsync->setEnabled(isChecked); cmbFilterMode->setEnabled(isChecked); } void DisplaySettingsTab::slotPreferredSurfaceFormatChanged(int index) { Q_UNUSED(index); QOpenGLContext *context = QOpenGLContext::currentContext(); if (context) { QScreen *screen = QGuiApplication::screenAt(rect().center()); KisScreenInformationAdapter adapter(context); if (adapter.isValid()) { KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen); if (info.isValid()) { if (cmbPreferedRootSurfaceFormat->currentIndex() != formatToIndex(KisConfig::BT709_G22) && - info.colorSpace == QSurfaceFormat::sRGBColorSpace) { + info.colorSpace == KisSurfaceColorSpace::sRGBColorSpace) { lblHDRWarning->setText(i18n("WARNING: current display doesn't support HDR rendering")); } else { lblHDRWarning->setText(""); } } } } } //--------------------------------------------------------------------------------------------------- FullscreenSettingsTab::FullscreenSettingsTab(QWidget* parent) : WdgFullscreenSettingsBase(parent) { KisConfig cfg(true); chkDockers->setChecked(cfg.hideDockersFullscreen()); chkMenu->setChecked(cfg.hideMenuFullscreen()); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen()); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen()); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen()); chkToolbar->setChecked(cfg.hideToolbarFullscreen()); } void FullscreenSettingsTab::setDefault() { KisConfig cfg(true); chkDockers->setChecked(cfg.hideDockersFullscreen(true)); chkMenu->setChecked(cfg.hideMenuFullscreen(true)); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen(true)); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen(true)); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen(true)); chkToolbar->setChecked(cfg.hideToolbarFullscreen(true)); } //--------------------------------------------------------------------------------------------------- KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name) : KPageDialog(parent) { Q_UNUSED(name); setWindowTitle(i18n("Configure Krita")); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); setFaceType(KPageDialog::Tree); // General KoVBox *vbox = new KoVBox(); KPageWidgetItem *page = new KPageWidgetItem(vbox, i18n("General")); page->setObjectName("general"); page->setHeader(i18n("General")); page->setIcon(KisIconUtils::loadIcon("go-home")); m_pages << page; addPage(page); m_general = new GeneralTab(vbox); // Shortcuts vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Keyboard Shortcuts")); page->setObjectName("shortcuts"); page->setHeader(i18n("Shortcuts")); page->setIcon(KisIconUtils::loadIcon("document-export")); m_pages << page; addPage(page); m_shortcutSettings = new ShortcutSettingsTab(vbox); connect(this, SIGNAL(accepted()), m_shortcutSettings, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_shortcutSettings, SLOT(cancelChanges())); // Canvas input settings m_inputConfiguration = new KisInputConfigurationPage(); page = addPage(m_inputConfiguration, i18n("Canvas Input Settings")); page->setHeader(i18n("Canvas Input")); page->setObjectName("canvasinput"); page->setIcon(KisIconUtils::loadIcon("configure")); m_pages << page; // Display vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Display")); page->setObjectName("display"); page->setHeader(i18n("Display")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-display")); m_pages << page; addPage(page); m_displaySettings = new DisplaySettingsTab(vbox); // Color vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Color Management")); page->setObjectName("colormanagement"); page->setHeader(i18n("Color")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-color")); m_pages << page; addPage(page); m_colorSettings = new ColorSettingsTab(vbox); // Performance vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Performance")); page->setObjectName("performance"); page->setHeader(i18n("Performance")); page->setIcon(KisIconUtils::loadIcon("applications-system")); m_pages << page; addPage(page); m_performanceSettings = new PerformanceTab(vbox); // Tablet vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Tablet settings")); page->setObjectName("tablet"); page->setHeader(i18n("Tablet")); page->setIcon(KisIconUtils::loadIcon("document-edit")); m_pages << page; addPage(page); m_tabletSettings = new TabletSettingsTab(vbox); // full-screen mode vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Canvas-only settings")); page->setObjectName("canvasonly"); page->setHeader(i18n("Canvas-only")); page->setIcon(KisIconUtils::loadIcon("folder-pictures")); m_pages << page; addPage(page); m_fullscreenSettings = new FullscreenSettingsTab(vbox); // Author profiles m_authorPage = new KoConfigAuthorPage(); page = addPage(m_authorPage, i18nc("@title:tab Author page", "Author" )); page->setObjectName("author"); page->setHeader(i18n("Author")); page->setIcon(KisIconUtils::loadIcon("im-user")); m_pages << page; QPushButton *restoreDefaultsButton = button(QDialogButtonBox::RestoreDefaults); restoreDefaultsButton->setText(i18nc("@action:button", "Restore Defaults")); connect(this, SIGNAL(accepted()), m_inputConfiguration, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_inputConfiguration, SLOT(revertChanges())); KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance(); Q_FOREACH (KisAbstractPreferenceSetFactory *preferenceSetFactory, preferenceSetRegistry->values()) { KisPreferenceSet* preferenceSet = preferenceSetFactory->createPreferenceSet(); vbox = new KoVBox(); page = new KPageWidgetItem(vbox, preferenceSet->name()); page->setHeader(preferenceSet->header()); page->setIcon(preferenceSet->icon()); addPage(page); preferenceSet->setParent(vbox); preferenceSet->loadPreferences(); connect(restoreDefaultsButton, SIGNAL(clicked(bool)), preferenceSet, SLOT(loadDefaultPreferences()), Qt::UniqueConnection); connect(this, SIGNAL(accepted()), preferenceSet, SLOT(savePreferences()), Qt::UniqueConnection); } connect(restoreDefaultsButton, SIGNAL(clicked(bool)), this, SLOT(slotDefault())); KisConfig cfg(true); QString currentPageName = cfg.readEntry("KisDlgPreferences/CurrentPage"); Q_FOREACH(KPageWidgetItem *page, m_pages) { if (page->objectName() == currentPageName) { setCurrentPage(page); break; } } } KisDlgPreferences::~KisDlgPreferences() { KisConfig cfg(true); cfg.writeEntry("KisDlgPreferences/CurrentPage", currentPage()->objectName()); } void KisDlgPreferences::showEvent(QShowEvent *event){ KPageDialog::showEvent(event); button(QDialogButtonBox::Cancel)->setAutoDefault(false); button(QDialogButtonBox::Ok)->setAutoDefault(false); button(QDialogButtonBox::RestoreDefaults)->setAutoDefault(false); button(QDialogButtonBox::Cancel)->setDefault(false); button(QDialogButtonBox::Ok)->setDefault(false); button(QDialogButtonBox::RestoreDefaults)->setDefault(false); } void KisDlgPreferences::slotDefault() { if (currentPage()->objectName() == "general") { m_general->setDefault(); } else if (currentPage()->objectName() == "shortcuts") { m_shortcutSettings->setDefault(); } else if (currentPage()->objectName() == "display") { m_displaySettings->setDefault(); } else if (currentPage()->objectName() == "colormanagement") { m_colorSettings->setDefault(); } else if (currentPage()->objectName() == "performance") { m_performanceSettings->load(true); } else if (currentPage()->objectName() == "tablet") { m_tabletSettings->setDefault(); } else if (currentPage()->objectName() == "canvasonly") { m_fullscreenSettings->setDefault(); } else if (currentPage()->objectName() == "canvasinput") { m_inputConfiguration->setDefaults(); } } bool KisDlgPreferences::editPreferences() { KisDlgPreferences* dialog; dialog = new KisDlgPreferences(); bool baccept = (dialog->exec() == Accepted); if (baccept) { // General settings KisConfig cfg(false); cfg.setNewCursorStyle(dialog->m_general->cursorStyle()); cfg.setNewOutlineStyle(dialog->m_general->outlineStyle()); cfg.setShowRootLayer(dialog->m_general->showRootLayer()); cfg.setShowOutlineWhilePainting(dialog->m_general->showOutlineWhilePainting()); cfg.setForceAlwaysFullSizedOutline(!dialog->m_general->m_changeBrushOutline->isChecked()); cfg.setSessionOnStartup(dialog->m_general->sessionOnStartup()); cfg.setSaveSessionOnQuit(dialog->m_general->saveSessionOnQuit()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); group.writeEntry("DontUseNativeFileDialog", !dialog->m_general->m_chkNativeFileDialog->isChecked()); cfg.writeEntry("maximumBrushSize", dialog->m_general->intMaxBrushSize->value()); cfg.writeEntry("mdi_viewmode", dialog->m_general->mdiMode()); cfg.setMDIBackgroundColor(dialog->m_general->m_mdiColor->color().toQColor()); cfg.setMDIBackgroundImage(dialog->m_general->m_backgroundimage->text()); cfg.setAutoSaveInterval(dialog->m_general->autoSaveInterval()); cfg.writeEntry("autosavefileshidden", dialog->m_general->chkHideAutosaveFiles->isChecked()); cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); cfg.writeEntry("backupfilelocation", dialog->m_general->cmbBackupFileLocation->currentIndex()); cfg.writeEntry("backupfilesuffix", dialog->m_general->txtBackupFileSuffix->text()); cfg.writeEntry("numberofbackupfiles", dialog->m_general->intNumBackupFiles->value()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); cfg.setUseZip64(dialog->m_general->useZip64()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("EnableHiDPI", dialog->m_general->m_chkHiDPI->isChecked()); kritarc.setValue("EnableSingleApplication", dialog->m_general->m_chkSingleApplication->isChecked()); kritarc.setValue("LogUsage", dialog->m_general->chkUsageLogging->isChecked()); cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker()); cfg.writeEntry("useCreamyAlphaDarken", (bool)!dialog->m_general->cmbFlowMode->currentIndex()); cfg.setKineticScrollingEnabled(dialog->m_general->kineticScrollingEnabled()); cfg.setKineticScrollingGesture(dialog->m_general->kineticScrollingGesture()); cfg.setKineticScrollingSensitivity(dialog->m_general->kineticScrollingSensitivity()); cfg.setKineticScrollingHideScrollbars(dialog->m_general->kineticScrollingHiddenScrollbars()); cfg.setSwitchSelectionCtrlAlt(dialog->m_general->switchSelectionCtrlAlt()); cfg.setDisableTouchOnCanvas(!dialog->m_general->chkEnableTouch->isChecked()); cfg.setActivateTransformToolAfterPaste(dialog->m_general->chkEnableTranformToolAfterPaste->isChecked()); cfg.setConvertToImageColorspaceOnImport(dialog->m_general->convertToImageColorspaceOnImport()); cfg.setUndoStackLimit(dialog->m_general->undoStackSize()); cfg.setFavoritePresets(dialog->m_general->favoritePresets()); cfg.writeEntry(KisResourceCacheDb::dbLocationKey, dialog->m_general->m_urlCacheDbLocation->fileName()); cfg.writeEntry(KisResourceLocator::resourceLocationKey, dialog->m_general->m_urlResourceFolder->fileName()); // Color settings cfg.setUseSystemMonitorProfile(dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()) { int currentIndex = dialog->m_colorSettings->m_monitorProfileWidgets[i]->currentIndex(); QString monitorid = dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemData(currentIndex).toString(); cfg.setMonitorForScreen(i, monitorid); } else { cfg.setMonitorProfile(i, dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemHighlighted(), dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); } } cfg.setWorkingColorSpace(dialog->m_colorSettings->m_page->cmbWorkingColorSpace->currentItem().id()); KisImageConfig cfgImage(false); cfgImage.setDefaultProofingConfig(dialog->m_colorSettings->m_page->proofingSpaceSelector->currentColorSpace(), dialog->m_colorSettings->m_page->cmbProofingIntent->currentIndex(), dialog->m_colorSettings->m_page->ckbProofBlackPoint->isChecked(), dialog->m_colorSettings->m_page->gamutAlarm->color(), (double)dialog->m_colorSettings->m_page->sldAdaptationState->value()/20); cfg.setUseBlackPointCompensation(dialog->m_colorSettings->m_page->chkBlackpoint->isChecked()); cfg.setAllowLCMSOptimization(dialog->m_colorSettings->m_page->chkAllowLCMSOptimization->isChecked()); cfg.setForcePaletteColors(dialog->m_colorSettings->m_page->chkForcePaletteColor->isChecked()); cfg.setPasteBehaviour(dialog->m_colorSettings->m_pasteBehaviourGroup.checkedId()); cfg.setRenderIntent(dialog->m_colorSettings->m_page->cmbMonitorIntent->currentIndex()); // Tablet settings cfg.setPressureTabletCurve( dialog->m_tabletSettings->m_page->pressureCurve->curve().toString() ); #ifdef Q_OS_WIN #ifndef USE_QT_TABLET_WINDOWS if (KisTabletSupportWin8::isAvailable()) { cfg.setUseWin8PointerInput(dialog->m_tabletSettings->m_page->radioWin8PointerInput->isChecked()); } #endif #endif dialog->m_performanceSettings->save(); { KisOpenGL::OpenGLRenderer renderer = static_cast( dialog->m_displaySettings->cmbPreferredRenderer->itemData( dialog->m_displaySettings->cmbPreferredRenderer->currentIndex()).toInt()); KisOpenGL::setUserPreferredOpenGLRendererConfig(renderer); } if (!cfg.useOpenGL() && dialog->m_displaySettings->grpOpenGL->isChecked()) cfg.setCanvasState("TRY_OPENGL"); cfg.setUseOpenGL(dialog->m_displaySettings->grpOpenGL->isChecked()); cfg.setUseOpenGLTextureBuffer(dialog->m_displaySettings->chkUseTextureBuffer->isChecked()); cfg.setOpenGLFilteringMode(dialog->m_displaySettings->cmbFilterMode->currentIndex()); cfg.setDisableVSync(dialog->m_displaySettings->chkDisableVsync->isChecked()); cfg.setRootSurfaceFormat(&kritarc, indexToFormat(dialog->m_displaySettings->cmbPreferedRootSurfaceFormat->currentIndex())); cfg.setCheckSize(dialog->m_displaySettings->intCheckSize->value()); cfg.setScrollingCheckers(dialog->m_displaySettings->chkMoving->isChecked()); cfg.setCheckersColor1(dialog->m_displaySettings->colorChecks1->color().toQColor()); cfg.setCheckersColor2(dialog->m_displaySettings->colorChecks2->color().toQColor()); cfg.setCanvasBorderColor(dialog->m_displaySettings->canvasBorder->color().toQColor()); cfg.setHideScrollbars(dialog->m_displaySettings->hideScrollbars->isChecked()); KoColor c = dialog->m_displaySettings->btnSelectionOverlayColor->color(); c.setOpacity(dialog->m_displaySettings->sldSelectionOverlayOpacity->value()); cfgImage.setSelectionOverlayMaskColor(c.toQColor()); cfg.setAntialiasCurves(dialog->m_displaySettings->chkCurveAntialiasing->isChecked()); cfg.setAntialiasSelectionOutline(dialog->m_displaySettings->chkSelectionOutlineAntialiasing->isChecked()); cfg.setShowSingleChannelAsColor(dialog->m_displaySettings->chkChannelsAsColor->isChecked()); cfg.setHidePopups(dialog->m_displaySettings->chkHidePopups->isChecked()); cfg.setHideDockersFullscreen(dialog->m_fullscreenSettings->chkDockers->checkState()); cfg.setHideMenuFullscreen(dialog->m_fullscreenSettings->chkMenu->checkState()); cfg.setHideScrollbarsFullscreen(dialog->m_fullscreenSettings->chkScrollbars->checkState()); cfg.setHideStatusbarFullscreen(dialog->m_fullscreenSettings->chkStatusbar->checkState()); cfg.setHideTitlebarFullscreen(dialog->m_fullscreenSettings->chkTitlebar->checkState()); cfg.setHideToolbarFullscreen(dialog->m_fullscreenSettings->chkToolbar->checkState()); cfg.setCursorMainColor(dialog->m_general->cursorColorBtutton->color().toQColor()); cfg.setPixelGridColor(dialog->m_displaySettings->pixelGridColorButton->color().toQColor()); cfg.setPixelGridDrawingThreshold(dialog->m_displaySettings->pixelGridDrawingThresholdBox->value() / 100); dialog->m_authorPage->apply(); } delete dialog; return baccept; } diff --git a/libs/ui/kis_mirror_manager.cpp b/libs/ui/kis_mirror_manager.cpp index a54c4b8bda..4ab4808643 100644 --- a/libs/ui/kis_mirror_manager.cpp +++ b/libs/ui/kis_mirror_manager.cpp @@ -1,132 +1,140 @@ /* * Copyright (c) 2009 Cyrille Berger * 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_mirror_manager.h" #include "KisViewManager.h" #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_mirror_axis.h" #include #include #include - -class KisMirrorManager::Private -{ -public: - Private() - : mirrorAxisDecoration(nullptr) - {} - - KisMirrorAxis* mirrorAxisDecoration; -}; +#include KisMirrorManager::KisMirrorManager(KisViewManager* view) : QObject(view) - , d(new Private()) , m_imageView(0) { } KisMirrorManager::~KisMirrorManager() { } void KisMirrorManager::setup(KActionCollection * collection) { m_mirrorCanvas = new KToggleAction(i18n("Mirror View"), this); m_mirrorCanvas->setChecked(false); m_mirrorCanvas->setIcon(KisIconUtils::loadIcon("mirror-view")); collection->addAction("mirror_canvas", m_mirrorCanvas); collection->setDefaultShortcut(m_mirrorCanvas, QKeySequence(Qt::Key_M)); updateAction(); } void KisMirrorManager::setView(QPointer imageView) { if (m_imageView) { m_mirrorCanvas->disconnect(); m_imageView->document()->disconnect(); - d->mirrorAxisDecoration->disconnect(); - d->mirrorAxisDecoration = nullptr; + KisMirrorAxisSP canvasDecoration = this->decoration(); + if (canvasDecoration) { + canvasDecoration->disconnect(); + } } m_imageView = imageView; if (m_imageView) { connect(m_mirrorCanvas, SIGNAL(toggled(bool)), dynamic_cast(m_imageView->canvasController()), SLOT(mirrorCanvas(bool))); connect(m_imageView->document(), SIGNAL(sigMirrorAxisConfigChanged()), this, SLOT(slotDocumentConfigChanged()), Qt::UniqueConnection); - KisMirrorAxis* decoration; - if (m_imageView->canvasBase() && m_imageView->canvasBase()->decoration("mirror_axis")) { - decoration = dynamic_cast(m_imageView->canvasBase()->decoration("mirror_axis").data()); - } else { - decoration = new KisMirrorAxis(m_imageView->viewManager()->canvasResourceProvider(), m_imageView); + KisMirrorAxisSP canvasDecoration = this->decoration(); + if (!canvasDecoration) { + KisMirrorAxis* decoration = new KisMirrorAxis(m_imageView->viewManager()->canvasResourceProvider(), m_imageView); connect(decoration, SIGNAL(sigConfigChanged()), this, SLOT(slotMirrorAxisConfigChanged()), Qt::UniqueConnection); m_imageView->canvasBase()->addDecoration(decoration); + } else { + connect(canvasDecoration.data(), SIGNAL(sigConfigChanged()), this, SLOT(slotMirrorAxisConfigChanged()), Qt::UniqueConnection); } - d->mirrorAxisDecoration = decoration; setDecorationConfig(); } updateAction(); } void KisMirrorManager::updateAction() { if (m_imageView) { m_mirrorCanvas->setEnabled(true); m_mirrorCanvas->setChecked(m_imageView->canvasIsMirrored()); } else { m_mirrorCanvas->setEnabled(false); m_mirrorCanvas->setChecked(false); } } void KisMirrorManager::slotDocumentConfigChanged() { setDecorationConfig(); } void KisMirrorManager::slotMirrorAxisConfigChanged() { if (m_imageView && m_imageView->document()) { KisSignalsBlocker blocker(m_imageView->document()); - m_imageView->document()->setMirrorAxisConfig(d->mirrorAxisDecoration->mirrorAxisConfig()); + + KisMirrorAxisSP canvasDecoration = this->decoration(); + if (canvasDecoration) { + m_imageView->document()->setMirrorAxisConfig(canvasDecoration->mirrorAxisConfig()); + } + } +} + +KisMirrorAxisSP KisMirrorManager::decoration() const +{ + if (m_imageView) { + return qobject_cast(m_imageView->canvasBase()->decoration("mirror_axis").data()); + } else { + return 0; } } void KisMirrorManager::setDecorationConfig() { if (m_imageView && m_imageView->document()) { KisMirrorAxisConfig config = m_imageView->document()->mirrorAxisConfig(); - d->mirrorAxisDecoration->setMirrorAxisConfig(config); + + KisMirrorAxisSP canvasDecoration = this->decoration(); + if (canvasDecoration) { + canvasDecoration->setMirrorAxisConfig(config); + } } } diff --git a/libs/ui/kis_mirror_manager.h b/libs/ui/kis_mirror_manager.h index e95f8b11e0..6a59da8b1c 100644 --- a/libs/ui/kis_mirror_manager.h +++ b/libs/ui/kis_mirror_manager.h @@ -1,60 +1,57 @@ /* * Copyright (c) 2009 Cyrille Berger * 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. */ #ifndef KIS_MIRROR_MANAGER_H #define KIS_MIRROR_MANAGER_H #include #include -#include +#include #include "KisView.h" class KisViewManager; class KActionCollection; class KisMirrorAxis; class KisMirrorAxisConfig; class KisMirrorManager : public QObject { Q_OBJECT public: KisMirrorManager(KisViewManager* view); ~KisMirrorManager() override; void setup(KActionCollection* collection); - void setView(QPointer imageView); private Q_SLOTS: void updateAction(); void slotDocumentConfigChanged(); void slotMirrorAxisConfigChanged(); private: - class Private; - const QScopedPointer d; - QPointer m_imageView; QAction *m_mirrorCanvas; void setDecorationConfig(); + KisMirrorAxisSP decoration() const; }; -#endif // KIS__MANAGER_H +#endif // KIS_MIRROR_MANAGER_H diff --git a/libs/ui/opengl/KisOpenGLModeProber.cpp b/libs/ui/opengl/KisOpenGLModeProber.cpp index 6f89e04c18..c23d9a63f2 100644 --- a/libs/ui/opengl/KisOpenGLModeProber.cpp +++ b/libs/ui/opengl/KisOpenGLModeProber.cpp @@ -1,253 +1,262 @@ /* * Copyright (c) 2017 Alvin Wong * Copyright (c) 2019 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 "KisOpenGLModeProber.h" #include #include #include #include #include #include Q_GLOBAL_STATIC(KisOpenGLModeProber, s_instance) KisOpenGLModeProber::KisOpenGLModeProber() { } KisOpenGLModeProber::~KisOpenGLModeProber() { } KisOpenGLModeProber *KisOpenGLModeProber::instance() { return s_instance; } bool KisOpenGLModeProber::useHDRMode() const { return isFormatHDR(QSurfaceFormat::defaultFormat()); } QSurfaceFormat KisOpenGLModeProber::surfaceformatInUse() const { // TODO: use information provided by KisOpenGL instead QOpenGLContext *sharedContext = QOpenGLContext::globalShareContext(); QSurfaceFormat format = sharedContext ? sharedContext->format() : QSurfaceFormat::defaultFormat(); return format; } const KoColorProfile *KisOpenGLModeProber::rootSurfaceColorProfile() const { - const QSurfaceFormat::ColorSpace surfaceColorSpace = surfaceformatInUse().colorSpace(); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->p709SRGBProfile(); - if (surfaceColorSpace == QSurfaceFormat::sRGBColorSpace) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + + const KisSurfaceColorSpace surfaceColorSpace = surfaceformatInUse().colorSpace(); + if (surfaceColorSpace == KisSurfaceColorSpace::sRGBColorSpace) { // use the default one! #ifdef HAVE_HDR - } else if (surfaceColorSpace == QSurfaceFormat::scRGBColorSpace) { + } else if (surfaceColorSpace == KisSurfaceColorSpace::scRGBColorSpace) { profile = KoColorSpaceRegistry::instance()->p709G10Profile(); - } else if (surfaceColorSpace == QSurfaceFormat::bt2020PQColorSpace) { + } else if (surfaceColorSpace == KisSurfaceColorSpace::bt2020PQColorSpace) { profile = KoColorSpaceRegistry::instance()->p2020PQProfile(); #endif } +#endif + return profile; } namespace { struct AppAttributeSetter { AppAttributeSetter(Qt::ApplicationAttribute attribute, bool useOpenGLES) : m_attribute(attribute), m_oldValue(QCoreApplication::testAttribute(attribute)) { QCoreApplication::setAttribute(attribute, useOpenGLES); } ~AppAttributeSetter() { QCoreApplication::setAttribute(m_attribute, m_oldValue); } private: Qt::ApplicationAttribute m_attribute; bool m_oldValue = false; }; struct SurfaceFormatSetter { SurfaceFormatSetter(const QSurfaceFormat &format) : m_oldFormat(QSurfaceFormat::defaultFormat()) { QSurfaceFormat::setDefaultFormat(format); } ~SurfaceFormatSetter() { QSurfaceFormat::setDefaultFormat(m_oldFormat); } private: QSurfaceFormat m_oldFormat; }; } boost::optional KisOpenGLModeProber::probeFormat(const QSurfaceFormat &format, bool adjustGlobalState) { QScopedPointer sharedContextSetter; QScopedPointer glSetter; QScopedPointer glesSetter; QScopedPointer formatSetter; QScopedPointer application; if (adjustGlobalState) { sharedContextSetter.reset(new AppAttributeSetter(Qt::AA_ShareOpenGLContexts, false)); if (format.renderableType() != QSurfaceFormat::DefaultRenderableType) { glSetter.reset(new AppAttributeSetter(Qt::AA_UseDesktopOpenGL, format.renderableType() != QSurfaceFormat::OpenGLES)); glesSetter.reset(new AppAttributeSetter(Qt::AA_UseOpenGLES, format.renderableType() == QSurfaceFormat::OpenGLES)); } formatSetter.reset(new SurfaceFormatSetter(format)); int argc = 1; QByteArray data("krita"); char *argv = data.data(); application.reset(new QApplication(argc, &argv)); } QWindow surface; surface.setFormat(format); surface.setSurfaceType(QSurface::OpenGLSurface); surface.create(); QOpenGLContext context; context.setFormat(format); if (!context.create()) { dbgOpenGL << "OpenGL context cannot be created"; return boost::none; } if (!context.isValid()) { dbgOpenGL << "OpenGL context is not valid while checking Qt's OpenGL status"; return boost::none; } if (!context.makeCurrent(&surface)) { dbgOpenGL << "OpenGL context cannot be made current"; return boost::none; } +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) if (!fuzzyCompareColorSpaces(context.format().colorSpace(), format.colorSpace())) { dbgOpenGL << "Failed to create an OpenGL context with requested color space. Requested:" << format.colorSpace() << "Actual:" << context.format().colorSpace(); return boost::none; } +#endif return Result(context); } -bool KisOpenGLModeProber::fuzzyCompareColorSpaces(const QSurfaceFormat::ColorSpace &lhs, const QSurfaceFormat::ColorSpace &rhs) +bool KisOpenGLModeProber::fuzzyCompareColorSpaces(const KisSurfaceColorSpace &lhs, const KisSurfaceColorSpace &rhs) { return lhs == rhs || - ((lhs == QSurfaceFormat::DefaultColorSpace || - lhs == QSurfaceFormat::sRGBColorSpace) && - (rhs == QSurfaceFormat::DefaultColorSpace || - rhs == QSurfaceFormat::sRGBColorSpace)); + ((lhs == KisSurfaceColorSpace::DefaultColorSpace || + lhs == KisSurfaceColorSpace::sRGBColorSpace) && + (rhs == KisSurfaceColorSpace::DefaultColorSpace || + rhs == KisSurfaceColorSpace::sRGBColorSpace)); } void KisOpenGLModeProber::initSurfaceFormatFromConfig(KisConfig::RootSurfaceFormat config, QSurfaceFormat *format) { #ifdef HAVE_HDR if (config == KisConfig::BT2020_PQ) { format->setRedBufferSize(10); format->setGreenBufferSize(10); format->setBlueBufferSize(10); format->setAlphaBufferSize(2); - format->setColorSpace(QSurfaceFormat::bt2020PQColorSpace); + format->setColorSpace(KisSurfaceColorSpace::bt2020PQColorSpace); } else if (config == KisConfig::BT709_G10) { format->setRedBufferSize(16); format->setGreenBufferSize(16); format->setBlueBufferSize(16); format->setAlphaBufferSize(16); - format->setColorSpace(QSurfaceFormat::scRGBColorSpace); + format->setColorSpace(KisSurfaceColorSpace::scRGBColorSpace); } else #else if (config == KisConfig::BT2020_PQ) { qWarning() << "WARNING: Bt.2020 PQ surface type is not supoprted by this build of Krita"; } else if (config == KisConfig::BT709_G10) { qWarning() << "WARNING: scRGB surface type is not supoprted by this build of Krita"; } #endif { format->setRedBufferSize(8); format->setGreenBufferSize(8); format->setBlueBufferSize(8); format->setAlphaBufferSize(8); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // TODO: check if we can use real sRGB space here - format->setColorSpace(QSurfaceFormat::DefaultColorSpace); + format->setColorSpace(KisSurfaceColorSpace::DefaultColorSpace); +#endif } } bool KisOpenGLModeProber::isFormatHDR(const QSurfaceFormat &format) { #ifdef HAVE_HDR bool isBt2020PQ = - format.colorSpace() == QSurfaceFormat::bt2020PQColorSpace && + format.colorSpace() == KisSurfaceColorSpace::bt2020PQColorSpace && format.redBufferSize() == 10 && format.greenBufferSize() == 10 && format.blueBufferSize() == 10 && format.alphaBufferSize() == 2; bool isBt709G10 = - format.colorSpace() == QSurfaceFormat::scRGBColorSpace && + format.colorSpace() == KisSurfaceColorSpace::scRGBColorSpace && format.redBufferSize() == 16 && format.greenBufferSize() == 16 && format.blueBufferSize() == 16 && format.alphaBufferSize() == 16; return isBt2020PQ || isBt709G10; #else return false; #endif } KisOpenGLModeProber::Result::Result(QOpenGLContext &context) { if (!context.isValid()) { return; } QOpenGLFunctions *funcs = context.functions(); // funcs is ready to be used m_rendererString = QString(reinterpret_cast(funcs->glGetString(GL_RENDERER))); m_driverVersionString = QString(reinterpret_cast(funcs->glGetString(GL_VERSION))); m_vendorString = QString(reinterpret_cast(funcs->glGetString(GL_VENDOR))); m_shadingLanguageString = QString(reinterpret_cast(funcs->glGetString(GL_SHADING_LANGUAGE_VERSION))); m_glMajorVersion = context.format().majorVersion(); m_glMinorVersion = context.format().minorVersion(); m_supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions); m_isOpenGLES = context.isOpenGLES(); m_format = context.format(); } diff --git a/libs/ui/opengl/KisOpenGLModeProber.h b/libs/ui/opengl/KisOpenGLModeProber.h index 1968cb519b..4763d01aa4 100644 --- a/libs/ui/opengl/KisOpenGLModeProber.h +++ b/libs/ui/opengl/KisOpenGLModeProber.h @@ -1,145 +1,146 @@ /* * Copyright (c) 2017 Alvin Wong * Copyright (c) 2019 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 KISOPENGLMODEPROBER_H #define KISOPENGLMODEPROBER_H #include "kritaui_export.h" #include "kis_config.h" #include +#include "KisSurfaceColorSpace.h" #include class KoColorProfile; class KRITAUI_EXPORT KisOpenGLModeProber { public: class Result; public: KisOpenGLModeProber(); ~KisOpenGLModeProber(); static KisOpenGLModeProber* instance(); bool useHDRMode() const; QSurfaceFormat surfaceformatInUse() const; const KoColorProfile *rootSurfaceColorProfile() const; boost::optional probeFormat(const QSurfaceFormat &format, bool adjustGlobalState = true); - static bool fuzzyCompareColorSpaces(const QSurfaceFormat::ColorSpace &lhs, - const QSurfaceFormat::ColorSpace &rhs); + static bool fuzzyCompareColorSpaces(const KisSurfaceColorSpace &lhs, + const KisSurfaceColorSpace &rhs); public: static void initSurfaceFormatFromConfig(KisConfig::RootSurfaceFormat config, QSurfaceFormat *format); static bool isFormatHDR(const QSurfaceFormat &format); }; class KisOpenGLModeProber::Result { public: Result(QOpenGLContext &context); int glMajorVersion() const { return m_glMajorVersion; } int glMinorVersion() const { return m_glMinorVersion; } bool supportsDeprecatedFunctions() const { return m_supportsDeprecatedFunctions; } bool isOpenGLES() const { return m_isOpenGLES; } QString rendererString() const { return m_rendererString; } QString driverVersionString() const { return m_driverVersionString; } bool isSupportedVersion() const { return #ifdef Q_OS_OSX ((m_glMajorVersion * 100 + m_glMinorVersion) >= 302) #else (m_glMajorVersion >= 3 && (m_supportsDeprecatedFunctions || m_isOpenGLES)) || ((m_glMajorVersion * 100 + m_glMinorVersion) == 201) #endif ; } bool supportsLoD() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 300; } bool hasOpenGL3() const { return (m_glMajorVersion * 100 + m_glMinorVersion) >= 302; } bool supportsFenceSync() const { return m_glMajorVersion >= 3; } #ifdef Q_OS_WIN // This is only for detecting whether ANGLE is being used. // For detecting generic OpenGL ES please check isOpenGLES bool isUsingAngle() const { return m_rendererString.startsWith("ANGLE", Qt::CaseInsensitive); } #endif QString shadingLanguageString() const { return m_shadingLanguageString; } QString vendorString() const { return m_vendorString; } QSurfaceFormat format() const { return m_format; } private: int m_glMajorVersion = 0; int m_glMinorVersion = 0; bool m_supportsDeprecatedFunctions = false; bool m_isOpenGLES = false; QString m_rendererString; QString m_driverVersionString; QString m_vendorString; QString m_shadingLanguageString; QSurfaceFormat m_format; }; #endif // KISOPENGLMODEPROBER_H diff --git a/libs/ui/opengl/KisScreenInformationAdapter.cpp b/libs/ui/opengl/KisScreenInformationAdapter.cpp index d40ab8ccd8..a7435cd419 100644 --- a/libs/ui/opengl/KisScreenInformationAdapter.cpp +++ b/libs/ui/opengl/KisScreenInformationAdapter.cpp @@ -1,306 +1,306 @@ /* * Copyright (c) 2019 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 "KisScreenInformationAdapter.h" #include "kis_debug.h" #include #include #include #include #ifdef Q_OS_WIN #if (QT_VERSION == QT_VERSION_CHECK(5, 11, 2)) #include #elif (QT_VERSION == QT_VERSION_CHECK(5, 12, 0)) #include #elif (QT_VERSION == QT_VERSION_CHECK(5, 12, 1)) #include #elif (QT_VERSION == QT_VERSION_CHECK(5, 12, 2)) #include #elif (QT_VERSION == QT_VERSION_CHECK(5, 13, 0)) #include #endif #include #include #include #include "EGL/egl.h" #include "EGL/eglext.h" #endif namespace { struct EGLException { EGLException() {} EGLException(const QString &what) : m_what(what) {} QString what() const { return m_what; } private: QString m_what; }; template void getProcAddressSafe(QOpenGLContext *context, const char *funcName, FuncType &func) { func = reinterpret_cast(context->getProcAddress(funcName)); if (!func) { throw EGLException(QString("failed to fetch function %1").arg(funcName)); } } #ifdef Q_OS_WIN typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name); #endif } struct KisScreenInformationAdapter::Private { void initialize(QOpenGLContext *context); QOpenGLContext *context; QString errorString; #ifdef Q_OS_WIN Microsoft::WRL::ComPtr dxgiAdapter; #endif }; KisScreenInformationAdapter::KisScreenInformationAdapter(QOpenGLContext *context) : m_d(new Private) { m_d->initialize(context); } KisScreenInformationAdapter::~KisScreenInformationAdapter() { } void KisScreenInformationAdapter::Private::initialize(QOpenGLContext *newContext) { context = newContext; errorString.clear(); try { #ifdef Q_OS_WIN if (!context->isOpenGLES()) { throw EGLException("the context is not OpenGL ES"); } PFNEGLQUERYSTRINGPROC queryString = nullptr; getProcAddressSafe(context, "eglQueryString", queryString); const char* client_extensions = queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); const QList extensions = QByteArray(client_extensions).split(' '); if (!extensions.contains("EGL_ANGLE_platform_angle_d3d") || !extensions.contains("EGL_ANGLE_device_creation_d3d11")) { throw EGLException("the context is not Angle + D3D11"); } PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT = nullptr; PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT = nullptr; getProcAddressSafe(context, "eglQueryDisplayAttribEXT", queryDisplayAttribEXT); getProcAddressSafe(context, "eglQueryDeviceAttribEXT", queryDeviceAttribEXT); QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); EGLDisplay display = reinterpret_cast(nativeInterface->nativeResourceForContext("egldisplay", context)); if (!display) { throw EGLException( QString("couldn't request EGLDisplay handle, display = 0x%1").arg(uintptr_t(display), 0, 16)); } EGLAttrib value = 0; EGLBoolean result = false; result = queryDisplayAttribEXT(display, EGL_DEVICE_EXT, &value); if (!result || value == EGL_NONE) { throw EGLException( QString("couldn't request EGLDeviceEXT handle, result = 0x%1, value = 0x%2") .arg(result, 0, 16).arg(value, 0, 16)); } EGLDeviceEXT device = reinterpret_cast(value); result = queryDeviceAttribEXT(device, EGL_D3D11_DEVICE_ANGLE, &value); if (!result || value == EGL_NONE) { throw EGLException( QString("couldn't request ID3D11Device pointer, result = 0x%1, value = 0x%2") .arg(result, 0, 16).arg(value, 0, 16)); } ID3D11Device *deviceD3D = reinterpret_cast(value); { HRESULT result = 0; Microsoft::WRL::ComPtr dxgiDevice; result = deviceD3D->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); if (FAILED(result)) { throw EGLException( QString("couldn't request IDXGIDevice pointer, result = 0x%1").arg(result, 0, 16)); } Microsoft::WRL::ComPtr dxgiAdapter; result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter1), (void**)&dxgiAdapter); if (FAILED(result)) { throw EGLException( QString("couldn't request IDXGIAdapter1 pointer, result = 0x%1").arg(result, 0, 16)); } this->dxgiAdapter = dxgiAdapter; } #else throw EGLException("current platform doesn't support fetching display information"); #endif } catch (EGLException &e) { this->context = 0; this->errorString = e.what(); #ifdef Q_OS_WIN this->dxgiAdapter.Reset(); #endif } } bool KisScreenInformationAdapter::isValid() const { #ifdef Q_OS_WIN return m_d->context && m_d->dxgiAdapter; #else return false; #endif } QString KisScreenInformationAdapter::errorString() const { return m_d->errorString; } KisScreenInformationAdapter::ScreenInfo KisScreenInformationAdapter::infoForScreen(QScreen *screen) const { ScreenInfo info; #ifdef Q_OS_WIN QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); HMONITOR monitor = reinterpret_cast(nativeInterface->nativeResourceForScreen("handle", screen)); if (!monitor) { qWarning("%s: failed to get HMONITOR handle for screen: screen = 0x%X, monitor = 0x%X", __PRETTY_FUNCTION__, screen, monitor); } UINT i = 0; Microsoft::WRL::ComPtr currentOutput; while (m_d->dxgiAdapter->EnumOutputs(i, ¤tOutput) != DXGI_ERROR_NOT_FOUND) { HRESULT result = 0; Microsoft::WRL::ComPtr output6; result = currentOutput.As(&output6); if (output6) { DXGI_OUTPUT_DESC1 desc; result = output6->GetDesc1(&desc); if (desc.Monitor == monitor) { info.screen = screen; info.bitsPerColor = desc.BitsPerColor; info.redPrimary[0] = desc.RedPrimary[0]; info.redPrimary[1] = desc.RedPrimary[1]; info.greenPrimary[0] = desc.GreenPrimary[0]; info.greenPrimary[1] = desc.GreenPrimary[1]; info.bluePrimary[0] = desc.BluePrimary[0]; info.bluePrimary[1] = desc.BluePrimary[1]; info.whitePoint[0] = desc.WhitePoint[0]; info.whitePoint[1] = desc.WhitePoint[1]; info.minLuminance = desc.MinLuminance; info.maxLuminance = desc.MaxLuminance; info.maxFullFrameLuminance = desc.MaxFullFrameLuminance; - info.colorSpace = QSurfaceFormat::DefaultColorSpace; + info.colorSpace = KisSurfaceColorSpace::DefaultColorSpace; if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709) { - info.colorSpace = QSurfaceFormat::sRGBColorSpace; + info.colorSpace = KisSurfaceColorSpace::sRGBColorSpace; } else if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709) { #ifdef HAVE_HDR - info.colorSpace = QSurfaceFormat::scRGBColorSpace; + info.colorSpace = KisSurfaceColorSpace::scRGBColorSpace; #else qWarning("WARNING: scRGB display color space is not supported by Qt's build"); #endif } else if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { #ifdef HAVE_HDR - info.colorSpace = QSurfaceFormat::bt2020PQColorSpace; + info.colorSpace = KisSurfaceColorSpace::bt2020PQColorSpace; #else qWarning("WARNING: bt2020-pq display color space is not supported by Qt's build"); #endif } else { qWarning("WARNING: unknown display color space! 0x%X", desc.ColorSpace); } break; } } i++; } #endif Q_UNUSED(screen); return info; } QDebug operator<<(QDebug dbg, const KisScreenInformationAdapter::ScreenInfo &info) { QDebugStateSaver saver(dbg); if (info.isValid()) { dbg.nospace() << "ScreenInfo(" << "screen " << info.screen << ", bitsPerColor " << info.bitsPerColor << ", colorSpace " << info.colorSpace << ", redPrimary " << "(" << info.redPrimary[0] << ", " << info.redPrimary[1] << ")" << ", greenPrimary " << "(" << info.greenPrimary[0] << ", " << info.greenPrimary[1] << ")" << ", bluePrimary " << "(" << info.bluePrimary[0] << ", " << info.bluePrimary[1] << ")" << ", whitePoint " << "(" << info.whitePoint[0] << ", " << info.whitePoint[1] << ")" << ", minLuminance " << info.minLuminance << ", maxLuminance " << info.maxLuminance << ", maxFullFrameLuminance " << info.maxFullFrameLuminance << ')'; } else { dbg.nospace() << "ScreenInfo()"; } return dbg; } diff --git a/libs/ui/opengl/KisScreenInformationAdapter.h b/libs/ui/opengl/KisScreenInformationAdapter.h index fc4bf20e93..54d98f1066 100644 --- a/libs/ui/opengl/KisScreenInformationAdapter.h +++ b/libs/ui/opengl/KisScreenInformationAdapter.h @@ -1,66 +1,67 @@ /* * Copyright (c) 2019 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 KISSCREENINFORMATIONADAPTER_H #define KISSCREENINFORMATIONADAPTER_H #include "kritaui_export.h" #include #include +#include "KisSurfaceColorSpace.h" class QScreen; class QOpenGLContext; class KRITAUI_EXPORT KisScreenInformationAdapter { public: struct ScreenInfo { QScreen *screen = 0; int bitsPerColor = 0; - QSurfaceFormat::ColorSpace colorSpace = QSurfaceFormat::DefaultColorSpace; + KisSurfaceColorSpace colorSpace = KisSurfaceColorSpace::DefaultColorSpace; qreal redPrimary[2] = {0, 0}; qreal greenPrimary[2] = {0, 0}; qreal bluePrimary[2] = {0, 0}; qreal whitePoint[2] = {0, 0}; qreal minLuminance = 0; qreal maxLuminance = 0; qreal maxFullFrameLuminance = 0; bool isValid() const { return screen; } }; public: KisScreenInformationAdapter(QOpenGLContext *context); ~KisScreenInformationAdapter(); bool isValid() const; QString errorString() const; ScreenInfo infoForScreen(QScreen *screen) const; private: struct Private; const QScopedPointer m_d; }; QDebug operator<<(QDebug, const KisScreenInformationAdapter::ScreenInfo &); #endif // KISSCREENINFORMATIONADAPTER_H diff --git a/libs/ui/opengl/KisSurfaceColorSpace.h b/libs/ui/opengl/KisSurfaceColorSpace.h new file mode 100644 index 0000000000..7c587c3d7e --- /dev/null +++ b/libs/ui/opengl/KisSurfaceColorSpace.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 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 KISSURFACECOLORSPACE_H +#define KISSURFACECOLORSPACE_H + +#include + +/** + * This file is a simple workaround for building our surface format + * selection code on Qt older than 5.10, which doesn't have this feature + * + * TODO: remove this file when we drop support for Qt 5.9 LTS + */ + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + +using KisSurfaceColorSpace = QSurfaceFormat::ColorSpace; + +#else + +enum KisSurfaceColorSpace { + DefaultColorSpace, + sRGBColorSpace +}; + +#endif + +#endif // KISSURFACECOLORSPACE_H diff --git a/libs/ui/opengl/kis_opengl.cpp b/libs/ui/opengl/kis_opengl.cpp index 6e0f9b5578..07cf6b940b 100644 --- a/libs/ui/opengl/kis_opengl.cpp +++ b/libs/ui/opengl/kis_opengl.cpp @@ -1,734 +1,741 @@ /* * Copyright (c) 2007 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "opengl/kis_opengl.h" #include "opengl/kis_opengl_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisOpenGLModeProber.h" #include #include #include "kis_assert.h" #include #include #ifndef GL_RENDERER # define GL_RENDERER 0x1F01 #endif using namespace KisOpenGLPrivate; namespace { // config option, set manually by main() bool g_isDebugSynchronous = false; bool g_sanityDefaultFormatIsSet = false; boost::optional openGLCheckResult; bool g_needsFenceWorkaround = false; bool g_needsPixmapCacheWorkaround = false; QString g_surfaceFormatDetectionLog; QString g_debugText("OpenGL Info\n **OpenGL not initialized**"); QVector g_openglWarningStrings; KisOpenGL::OpenGLRenderers g_supportedRenderers; KisOpenGL::OpenGLRenderer g_rendererPreferredByQt; void overrideSupportedRenderers(KisOpenGL::OpenGLRenderers supportedRenderers, KisOpenGL::OpenGLRenderer preferredByQt) { g_supportedRenderers = supportedRenderers; g_rendererPreferredByQt = preferredByQt; } void openglOnMessageLogged(const QOpenGLDebugMessage& debugMessage) { qDebug() << "OpenGL:" << debugMessage; } } KisOpenGLPrivate::OpenGLCheckResult::OpenGLCheckResult(QOpenGLContext &context) { if (!context.isValid()) { return; } QOpenGLFunctions *funcs = context.functions(); // funcs is ready to be used m_rendererString = QString(reinterpret_cast(funcs->glGetString(GL_RENDERER))); m_driverVersionString = QString(reinterpret_cast(funcs->glGetString(GL_VERSION))); m_glMajorVersion = context.format().majorVersion(); m_glMinorVersion = context.format().minorVersion(); m_supportsDeprecatedFunctions = (context.format().options() & QSurfaceFormat::DeprecatedFunctions); m_isOpenGLES = context.isOpenGLES(); } void KisOpenGLPrivate::appendOpenGLWarningString(KLocalizedString warning) { g_openglWarningStrings << warning; } void KisOpenGLPrivate::overrideOpenGLWarningString(QVector warnings) { g_openglWarningStrings = warnings; } void KisOpenGL::initialize() { if (openGLCheckResult) return; KIS_SAFE_ASSERT_RECOVER_NOOP(g_sanityDefaultFormatIsSet); openGLCheckResult = KisOpenGLModeProber::instance()->probeFormat(QSurfaceFormat::defaultFormat(), false); g_debugText.clear(); QDebug debugOut(&g_debugText); debugOut << "OpenGL Info\n"; debugOut << "\n Vendor: " << openGLCheckResult->vendorString(); debugOut << "\n Renderer: " << openGLCheckResult->rendererString(); debugOut << "\n Version: " << openGLCheckResult->driverVersionString(); debugOut << "\n Shading language: " << openGLCheckResult->shadingLanguageString(); debugOut << "\n Requested format: " << QSurfaceFormat::defaultFormat(); debugOut << "\n Current format: " << openGLCheckResult->format(); debugOut.nospace(); debugOut << "\n Version: " << openGLCheckResult->glMajorVersion() << "." << openGLCheckResult->glMinorVersion(); debugOut.resetFormat(); debugOut << "\n Supports deprecated functions" << openGLCheckResult->supportsDeprecatedFunctions(); debugOut << "\n is OpenGL ES:" << openGLCheckResult->isOpenGLES(); debugOut << "\n\nQPA OpenGL Detection Info"; debugOut << "\n supportsDesktopGL:" << bool(g_supportedRenderers & RendererDesktopGL); #ifdef Q_OS_WIN debugOut << "\n supportsAngleD3D11:" << bool(g_supportedRenderers & RendererOpenGLES); debugOut << "\n isQtPreferAngle:" << bool(g_rendererPreferredByQt == RendererOpenGLES); #else debugOut << "\n supportsOpenGLES:" << bool(g_supportedRenderers & RendererOpenGLES); debugOut << "\n isQtPreferOpenGLES:" << bool(g_rendererPreferredByQt == RendererOpenGLES); #endif debugOut << "\n== log ==\n"; debugOut.noquote(); debugOut << g_surfaceFormatDetectionLog; debugOut.resetFormat(); debugOut << "\n== end log =="; dbgOpenGL.noquote().nospace() << g_debugText; KisUsageLogger::write(g_debugText); // Check if we have a bugged driver that needs fence workaround bool isOnX11 = false; #ifdef HAVE_X11 isOnX11 = true; #endif KisConfig cfg(true); if ((isOnX11 && openGLCheckResult->rendererString().startsWith("AMD")) || cfg.forceOpenGLFenceWorkaround()) { g_needsFenceWorkaround = true; } /** * NVidia + Qt's openGL don't play well together and one cannot * draw a pixmap on a widget more than once in one rendering cycle. * * It can be workarounded by drawing strictly via QPixmapCache and * only when the pixmap size in bigger than doubled size of the * display framebuffer. That is for 8-bit HD display, you should have * a cache bigger than 16 MiB. Don't ask me why. (DK) * * See bug: https://bugs.kde.org/show_bug.cgi?id=361709 * * TODO: check if this workaround is still needed after merging * Qt5+openGL3 branch. */ if (openGLCheckResult->vendorString().toUpper().contains("NVIDIA")) { g_needsPixmapCacheWorkaround = true; const QRect screenSize = QApplication::desktop()->screenGeometry(); const int minCacheSize = 20 * 1024; const int cacheSize = 2048 + 2 * 4 * screenSize.width() * screenSize.height() / 1024; //KiB QPixmapCache::setCacheLimit(qMax(minCacheSize, cacheSize)); } } void KisOpenGL::initializeContext(QOpenGLContext *ctx) { KisConfig cfg(true); initialize(); const bool isDebugEnabled = ctx->format().testOption(QSurfaceFormat::DebugContext); dbgUI << "OpenGL: Opening new context"; if (isDebugEnabled) { // Passing ctx for ownership management only, not specifying context. // QOpenGLDebugLogger only function on the current active context. // FIXME: Do we need to make sure ctx is the active context? QOpenGLDebugLogger* openglLogger = new QOpenGLDebugLogger(ctx); if (openglLogger->initialize()) { qDebug() << "QOpenGLDebugLogger is initialized. Check whether you get a message below."; QObject::connect(openglLogger, &QOpenGLDebugLogger::messageLogged, &openglOnMessageLogged); openglLogger->startLogging(g_isDebugSynchronous ? QOpenGLDebugLogger::SynchronousLogging : QOpenGLDebugLogger::AsynchronousLogging); openglLogger->logMessage(QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("QOpenGLDebugLogger is logging."))); } else { qDebug() << "QOpenGLDebugLogger cannot be initialized."; delete openglLogger; } } // Double check we were given the version we requested QSurfaceFormat format = ctx->format(); QOpenGLFunctions *f = ctx->functions(); f->initializeOpenGLFunctions(); QFile log(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/krita-opengl.txt"); log.open(QFile::WriteOnly); QString vendor((const char*)f->glGetString(GL_VENDOR)); log.write(vendor.toLatin1()); log.write(", "); log.write(openGLCheckResult->rendererString().toLatin1()); log.write(", "); QString version((const char*)f->glGetString(GL_VERSION)); log.write(version.toLatin1()); log.close(); } const QString &KisOpenGL::getDebugText() { initialize(); return g_debugText; } QStringList KisOpenGL::getOpenGLWarnings() { QStringList strings; Q_FOREACH (const KLocalizedString &item, g_openglWarningStrings) { strings << item.toString(); } return strings; } // XXX Temporary function to allow LoD on OpenGL3 without triggering // all of the other 3.2 functionality, can be removed once we move to Qt5.7 bool KisOpenGL::supportsLoD() { initialize(); return openGLCheckResult->supportsLoD(); } bool KisOpenGL::hasOpenGL3() { initialize(); return openGLCheckResult->hasOpenGL3(); } bool KisOpenGL::hasOpenGLES() { initialize(); return openGLCheckResult->isOpenGLES(); } bool KisOpenGL::supportsFenceSync() { initialize(); return openGLCheckResult->supportsFenceSync(); } bool KisOpenGL::needsFenceWorkaround() { initialize(); return g_needsFenceWorkaround; } bool KisOpenGL::needsPixmapCacheWorkaround() { initialize(); return g_needsPixmapCacheWorkaround; } void KisOpenGL::testingInitializeDefaultSurfaceFormat() { setDefaultSurfaceFormat(selectSurfaceFormat(KisOpenGL::RendererAuto, KisConfig::BT709_G22, false)); } void KisOpenGL::setDebugSynchronous(bool value) { g_isDebugSynchronous = value; } KisOpenGL::OpenGLRenderer KisOpenGL::getCurrentOpenGLRenderer() { const QSurfaceFormat::RenderableType renderer = QSurfaceFormat::defaultFormat().renderableType(); return renderer == QSurfaceFormat::OpenGLES ? RendererOpenGLES : renderer == QSurfaceFormat::OpenGL ? RendererDesktopGL : RendererAuto; } KisOpenGL::OpenGLRenderer KisOpenGL::getQtPreferredOpenGLRenderer() { return g_rendererPreferredByQt; } KisOpenGL::OpenGLRenderers KisOpenGL::getSupportedOpenGLRenderers() { return g_supportedRenderers; } KisOpenGL::OpenGLRenderer KisOpenGL::getUserPreferredOpenGLRendererConfig() { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); return convertConfigToOpenGLRenderer(kritarc.value("OpenGLRenderer", "auto").toString()); } void KisOpenGL::setUserPreferredOpenGLRendererConfig(KisOpenGL::OpenGLRenderer renderer) { const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("OpenGLRenderer", KisOpenGL::convertOpenGLRendererToConfig(renderer)); } QString KisOpenGL::convertOpenGLRendererToConfig(KisOpenGL::OpenGLRenderer renderer) { switch (renderer) { case RendererDesktopGL: return QStringLiteral("desktop"); case RendererOpenGLES: return QStringLiteral("angle"); default: return QStringLiteral("auto"); } } KisOpenGL::OpenGLRenderer KisOpenGL::convertConfigToOpenGLRenderer(QString renderer) { if (renderer == "desktop") { return RendererDesktopGL; } else if (renderer == "angle") { return RendererOpenGLES; } else { return RendererAuto; } } namespace { QSurfaceFormat generateSurfaceFormat(QSurfaceFormat::RenderableType renderer, KisConfig::RootSurfaceFormat rootSurfaceFormat, bool debugContext) { QSurfaceFormat format; #ifdef Q_OS_OSX format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); #else // XXX This can be removed once we move to Qt5.7 format.setVersion(3, 0); format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setOptions(QSurfaceFormat::DeprecatedFunctions); #endif format.setDepthBufferSize(24); format.setStencilBufferSize(8); KisOpenGLModeProber::initSurfaceFormatFromConfig(rootSurfaceFormat, &format); format.setRenderableType(renderer); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); format.setSwapInterval(0); // Disable vertical refresh syncing if (debugContext) { format.setOption(QSurfaceFormat::DebugContext, true); } return format; } bool isOpenGLRendererBlacklisted(const QString &rendererString, const QString &driverVersionString, QVector *warningMessage) { bool isBlacklisted = false; // Special blacklisting of OpenGL/ANGLE is tracked on: // https://phabricator.kde.org/T7411 // HACK: Specifically detect for Intel driver build number // See https://www.intel.com/content/www/us/en/support/articles/000005654/graphics-drivers.html if (rendererString.startsWith("Intel")) { KLocalizedString knownBadIntelWarning = ki18n("The Intel graphics driver in use is known to have issues with OpenGL."); KLocalizedString grossIntelWarning = ki18n( "Intel graphics drivers tend to have issues with OpenGL so ANGLE will be used by default. " "You may manually switch to OpenGL but it is not guaranteed to work properly." ); QRegularExpression regex("\\b\\d{2}\\.\\d{2}\\.\\d{2}\\.(\\d{4})\\b"); QRegularExpressionMatch match = regex.match(driverVersionString); if (match.hasMatch()) { int driverBuild = match.captured(1).toInt(); if (driverBuild > 4636 && driverBuild < 4729) { // Make ANGLE the preferred renderer for Intel driver versions // between build 4636 and 4729 (exclusive) due to an UI offset bug. // See https://communities.intel.com/thread/116003 // (Build 4636 is known to work from some test results) qDebug() << "Detected Intel driver build between 4636 and 4729, making ANGLE the preferred renderer"; isBlacklisted = true; *warningMessage << knownBadIntelWarning; } else if (driverBuild == 4358) { // There are several reports on a bug where the canvas is not being // updated properly which has debug info pointing to this build. qDebug() << "Detected Intel driver build 4358, making ANGLE the preferred renderer"; isBlacklisted = true; *warningMessage << knownBadIntelWarning; } else { // Intel tends to randomly break OpenGL in some of their new driver // builds, therefore we just shouldn't use OpenGL by default to // reduce bug report noises. qDebug() << "Detected Intel driver, making ANGLE the preferred renderer"; isBlacklisted = true; *warningMessage << grossIntelWarning; } } } return isBlacklisted; } boost::optional orderPreference(bool lhs, bool rhs) { if (lhs == rhs) return boost::none; if (lhs && !rhs) return true; if (!lhs && rhs) return false; return false; } #define ORDER_BY(lhs, rhs) if (auto res = orderPreference((lhs), (rhs))) { return *res; } class FormatPositionLess { public: FormatPositionLess() { } bool operator()(const QSurfaceFormat &lhs, const QSurfaceFormat &rhs) const { - KIS_SAFE_ASSERT_RECOVER_NOOP(m_preferredColorSpace != QSurfaceFormat::DefaultColorSpace); + KIS_SAFE_ASSERT_RECOVER_NOOP(m_preferredColorSpace != KisSurfaceColorSpace::DefaultColorSpace); ORDER_BY(isPreferredColorSpace(lhs.colorSpace()), isPreferredColorSpace(rhs.colorSpace())); if (doPreferHDR()) { ORDER_BY(isHDRFormat(lhs), isHDRFormat(rhs)); } else { ORDER_BY(!isHDRFormat(lhs), !isHDRFormat(rhs)); } if (m_preferredRendererByUser != QSurfaceFormat::DefaultRenderableType) { ORDER_BY(lhs.renderableType() == m_preferredRendererByUser, rhs.renderableType() == m_preferredRendererByUser); } ORDER_BY(!isBlacklisted(lhs), !isBlacklisted(rhs)); if (doPreferHDR() && m_preferredRendererByHDR != QSurfaceFormat::DefaultRenderableType) { ORDER_BY(lhs.renderableType() == m_preferredRendererByHDR, rhs.renderableType() == m_preferredRendererByHDR); } KIS_SAFE_ASSERT_RECOVER_NOOP(m_preferredRendererByQt != QSurfaceFormat::DefaultRenderableType); ORDER_BY(lhs.renderableType() == m_preferredRendererByQt, rhs.renderableType() == m_preferredRendererByQt); return false; } public: - void setPreferredColorSpace(const QSurfaceFormat::ColorSpace &preferredColorSpace) { + void setPreferredColorSpace(const KisSurfaceColorSpace &preferredColorSpace) { m_preferredColorSpace = preferredColorSpace; } void setPreferredRendererByQt(const QSurfaceFormat::RenderableType &preferredRendererByQt) { m_preferredRendererByQt = preferredRendererByQt; } void setPreferredRendererByUser(const QSurfaceFormat::RenderableType &preferredRendererByUser) { m_preferredRendererByUser = preferredRendererByUser; } void setPreferredRendererByHDR(const QSurfaceFormat::RenderableType &preferredRendererByHDR) { m_preferredRendererByHDR = preferredRendererByHDR; } void setOpenGLBlacklisted(bool openGLBlacklisted) { m_openGLBlacklisted = openGLBlacklisted; } void setOpenGLESBlacklisted(bool openGLESBlacklisted) { m_openGLESBlacklisted = openGLESBlacklisted; } - QSurfaceFormat::ColorSpace preferredColorSpace() const { + KisSurfaceColorSpace preferredColorSpace() const { return m_preferredColorSpace; } QSurfaceFormat::RenderableType preferredRendererByUser() const { return m_preferredRendererByUser; } private: bool isHDRFormat(const QSurfaceFormat &f) const { #ifdef HAVE_HDR - return f.colorSpace() == QSurfaceFormat::bt2020PQColorSpace || - f.colorSpace() == QSurfaceFormat::scRGBColorSpace; + return f.colorSpace() == KisSurfaceColorSpace::bt2020PQColorSpace || + f.colorSpace() == KisSurfaceColorSpace::scRGBColorSpace; #else Q_UNUSED(f); return false; #endif } bool isBlacklisted(const QSurfaceFormat &f) const { KIS_SAFE_ASSERT_RECOVER_NOOP(f.renderableType() == QSurfaceFormat::OpenGL || f.renderableType() == QSurfaceFormat::OpenGLES); return (f.renderableType() == QSurfaceFormat::OpenGL && m_openGLBlacklisted) || (f.renderableType() == QSurfaceFormat::OpenGLES && m_openGLESBlacklisted); } bool doPreferHDR() const { #ifdef HAVE_HDR - return m_preferredColorSpace == QSurfaceFormat::bt2020PQColorSpace || - m_preferredColorSpace == QSurfaceFormat::scRGBColorSpace; + return m_preferredColorSpace == KisSurfaceColorSpace::bt2020PQColorSpace || + m_preferredColorSpace == KisSurfaceColorSpace::scRGBColorSpace; #else return false; #endif } - bool isPreferredColorSpace(const QSurfaceFormat::ColorSpace cs) const { + bool isPreferredColorSpace(const KisSurfaceColorSpace cs) const { return KisOpenGLModeProber::fuzzyCompareColorSpaces(m_preferredColorSpace, cs); return false; } private: - QSurfaceFormat::ColorSpace m_preferredColorSpace = QSurfaceFormat::DefaultColorSpace; + KisSurfaceColorSpace m_preferredColorSpace = KisSurfaceColorSpace::DefaultColorSpace; QSurfaceFormat::RenderableType m_preferredRendererByQt = QSurfaceFormat::OpenGL; QSurfaceFormat::RenderableType m_preferredRendererByUser = QSurfaceFormat::DefaultRenderableType; QSurfaceFormat::RenderableType m_preferredRendererByHDR = QSurfaceFormat::DefaultRenderableType; bool m_openGLBlacklisted = false; bool m_openGLESBlacklisted = false; }; struct DetectionDebug : public QDebug { DetectionDebug(QString *string) : QDebug(string), m_string(string), m_originalSize(string->size()) {} ~DetectionDebug() { dbgOpenGL << m_string->right(m_string->size() - m_originalSize); *this << endl; } QString *m_string; int m_originalSize; }; } #define dbgDetection() DetectionDebug(&g_surfaceFormatDetectionLog) QSurfaceFormat KisOpenGL::selectSurfaceFormat(KisOpenGL::OpenGLRenderer preferredRenderer, KisConfig::RootSurfaceFormat preferredRootSurfaceFormat, bool enableDebug) { QVector warningMessages; using Info = boost::optional; QVector renderers({QSurfaceFormat::OpenGLES, QSurfaceFormat::OpenGL}); #ifdef HAVE_HDR QVector formatSymbols({KisConfig::BT709_G22, KisConfig::BT709_G10, KisConfig::BT2020_PQ}); #else QVector formatSymbols({KisConfig::BT709_G22}); #endif QVector preferredFormats; Q_FOREACH (const QSurfaceFormat::RenderableType renderer, renderers) { Q_FOREACH (const KisConfig::RootSurfaceFormat formatSymbol, formatSymbols) { preferredFormats << generateSurfaceFormat(renderer, formatSymbol, enableDebug); } } QSurfaceFormat defaultFormat = generateSurfaceFormat(QSurfaceFormat::DefaultRenderableType, KisConfig::BT709_G22, false); Info info = KisOpenGLModeProber::instance()->probeFormat(defaultFormat); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(info, QSurfaceFormat()); FormatPositionLess compareOp; compareOp.setPreferredRendererByQt(info->isOpenGLES() ? QSurfaceFormat::OpenGLES : QSurfaceFormat::OpenGL); #ifdef HAVE_HDR compareOp.setPreferredColorSpace( - preferredRootSurfaceFormat == KisConfig::BT709_G22 ? QSurfaceFormat::sRGBColorSpace : - preferredRootSurfaceFormat == KisConfig::BT709_G10 ? QSurfaceFormat::scRGBColorSpace : - QSurfaceFormat::bt2020PQColorSpace); + preferredRootSurfaceFormat == KisConfig::BT709_G22 ? KisSurfaceColorSpace::sRGBColorSpace : + preferredRootSurfaceFormat == KisConfig::BT709_G10 ? KisSurfaceColorSpace::scRGBColorSpace : + KisSurfaceColorSpace::bt2020PQColorSpace); #else Q_UNUSED(preferredRootSurfaceFormat); - compareOp.setPreferredColorSpace(QSurfaceFormat::sRGBColorSpace); + compareOp.setPreferredColorSpace(KisSurfaceColorSpace::sRGBColorSpace); #endif #ifdef Q_OS_WIN compareOp.setPreferredRendererByHDR(QSurfaceFormat::OpenGLES); #endif compareOp.setPreferredRendererByUser(preferredRenderer == KisOpenGL::RendererDesktopGL ? QSurfaceFormat::OpenGL : preferredRenderer == KisOpenGL::RendererOpenGLES ? QSurfaceFormat::OpenGLES : QSurfaceFormat::DefaultRenderableType); compareOp.setOpenGLESBlacklisted(false); // We cannot blacklist ES drivers atm OpenGLRenderers supportedRenderers = RendererNone; OpenGLRenderer preferredByQt = info->isOpenGLES() ? RendererOpenGLES : RendererDesktopGL; if (!info->isOpenGLES()) { compareOp.setOpenGLBlacklisted(isOpenGLRendererBlacklisted(info->rendererString(), info->driverVersionString(), &warningMessages)); supportedRenderers |= RendererDesktopGL; info = KisOpenGLModeProber::instance()-> probeFormat(generateSurfaceFormat(QSurfaceFormat::OpenGLES, KisConfig::BT709_G22, false)); if (info) { supportedRenderers |= RendererOpenGLES; } } else { supportedRenderers |= RendererOpenGLES; info = KisOpenGLModeProber::instance()-> probeFormat(generateSurfaceFormat(QSurfaceFormat::OpenGL, KisConfig::BT709_G22, false)); if (!info || info->isOpenGLES()) { compareOp.setOpenGLBlacklisted(true); } else { compareOp.setOpenGLBlacklisted(isOpenGLRendererBlacklisted(info->rendererString(), info->driverVersionString(), &warningMessages)); supportedRenderers |= RendererDesktopGL; } } std::stable_sort(preferredFormats.begin(), preferredFormats.end(), compareOp); dbgDetection() << "Supported renderers:" << supportedRenderers; dbgDetection() << "Surface format preference list:"; Q_FOREACH (const QSurfaceFormat &format, preferredFormats) { dbgDetection() << "*" << format; dbgDetection() << " " << format.renderableType(); } QSurfaceFormat resultFormat = defaultFormat; Q_FOREACH (const QSurfaceFormat &format, preferredFormats) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) dbgDetection() <<"Probing format..." << format.colorSpace() << format.renderableType(); - +#else + dbgDetection() <<"Probing format..." << format.renderableType(); +#endif Info info = KisOpenGLModeProber::instance()->probeFormat(format); if (info && info->isSupportedVersion()) { #ifdef Q_OS_WIN // HACK: Block ANGLE with Direct3D9 // Direct3D9 does not give OpenGL ES 3.0 // Some versions of ANGLE returns OpenGL version 3.0 incorrectly if (info->isUsingAngle() && info->rendererString().contains("Direct3D9", Qt::CaseInsensitive)) { dbgDetection() << "Skipping Direct3D 9 Angle implementation, it shouldn't have happened."; continue; } #endif dbgDetection() << "Found format:" << format; dbgDetection() << " " << format.renderableType(); resultFormat = format; break; } } { const bool colorSpaceIsCorrect = +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) KisOpenGLModeProber::fuzzyCompareColorSpaces(compareOp.preferredColorSpace(), resultFormat.colorSpace()); +#else + true; +#endif const bool rendererIsCorrect = compareOp.preferredRendererByUser() == QSurfaceFormat::DefaultRenderableType || compareOp.preferredRendererByUser() == resultFormat.renderableType(); if (!rendererIsCorrect && colorSpaceIsCorrect) { warningMessages << ki18n("Preferred renderer doesn't support requested surface format. Another renderer has been selected."); } else if (!colorSpaceIsCorrect) { warningMessages << ki18n("Preferred output format is not supported by available renderers"); } } overrideSupportedRenderers(supportedRenderers, preferredByQt); overrideOpenGLWarningString(warningMessages); return resultFormat; } void KisOpenGL::setDefaultSurfaceFormat(const QSurfaceFormat &format) { KIS_SAFE_ASSERT_RECOVER_NOOP(!g_sanityDefaultFormatIsSet); g_sanityDefaultFormatIsSet = true; QSurfaceFormat::setDefaultFormat(format); } bool KisOpenGL::hasOpenGL() { return openGLCheckResult->isSupportedVersion(); } diff --git a/packaging/linux/appimage/build-image.sh b/packaging/linux/appimage/build-image.sh index 25760f529a..7922e6f377 100755 --- a/packaging/linux/appimage/build-image.sh +++ b/packaging/linux/appimage/build-image.sh @@ -1,102 +1,106 @@ #!/bin/bash # Halt on errors and be verbose about what we are doing -set -e +#set -e set -x # Read in our parameters export BUILD_PREFIX=$1 export KRITA_SOURCES=$2 # Save some frequently referenced locations in variables for ease of use / updating export APPDIR=$BUILD_PREFIX/krita.appdir export PLUGINS=$APPDIR/usr/lib/kritaplugins/ # qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. # That's not always the case, so make sure it is export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # We want to use $prefix/deps/usr/ for all our dependencies export DEPS_INSTALL_PREFIX=$BUILD_PREFIX/deps/usr/ export DOWNLOADS_DIR=$BUILD_PREFIX/downloads/ # Setup variables needed to help everything find what we built export LD_LIBRARY_PATH=$DEPS_INSTALL_PREFIX/lib/:$DEPS_INSTALL_PREFIX/lib/x86_64-linux-gnu/:$APPDIR/usr/lib/:$LD_LIBRARY_PATH export PATH=$DEPS_INSTALL_PREFIX/bin/:$PATH export PKG_CONFIG_PATH=$DEPS_INSTALL_PREFIX/share/pkgconfig/:$DEPS_INSTALL_PREFIX/lib/pkgconfig/:/usr/lib/pkgconfig/:$PKG_CONFIG_PATH export CMAKE_PREFIX_PATH=$DEPS_INSTALL_PREFIX:$CMAKE_PREFIX_PATH export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip/:$DEPS_INSTALL_PREFIX/lib/python3.5/site-packages/:$DEPS_INSTALL_PREFIX/lib/python3.5/ export PYTHONHOME=$DEPS_INSTALL_PREFIX # Switch over to our build prefix cd $BUILD_PREFIX # # Now we can get the process started! # # Step 0: place the translations where ki18n and Qt look for them if [ -d $APPDIR/usr/share/locale ] ; then mv $APPDIR/usr/share/locale $APPDIR/usr/share/krita fi # Step 1: Copy over all the resources provided by dependencies that we need cp -r $DEPS_INSTALL_PREFIX/share/locale $APPDIR/usr/share/krita cp -r $DEPS_INSTALL_PREFIX/share/kf5 $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/share/mime $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/lib/python3.5 $APPDIR/usr/lib cp -r $DEPS_INSTALL_PREFIX/sip $APPDIR/usr/lib/ cp -r $DEPS_INSTALL_PREFIX/translations $APPDIR/usr/ # Step 2: Relocate x64 binaries from the architecture specific directory as required for Appimages mv $APPDIR/usr/lib/x86_64-linux-gnu/* $APPDIR/usr/lib rm -rf $APPDIR/usr/lib/x86_64-linux-gnu/ # Step 3: Update the rpath in the various plugins we have to make sure they'll be loadable in an Appimage context for lib in $PLUGINS/*.so*; do patchelf --set-rpath '$ORIGIN/..' $lib; done for lib in $APPDIR/usr/lib/python3.5/site-packages/PyQt5/*.so*; do patchelf --set-rpath '$ORIGIN/../..' $lib; done for lib in $APPDIR/usr/lib/python3.5/lib-dynload/*.so*; do patchelf --set-rpath '$ORIGIN/../..' $lib; done patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/sketch/libkritasketchplugin.so patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so -patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/sip/sip.so +patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/sip/sip.so # Step 5: Find out what version of Krita we built and give the Appimage a proper name cd $BUILD_PREFIX/krita-build + KRITA_VERSION=$(grep "#define KRITA_VERSION_STRING" libs/version/kritaversion.h | cut -d '"' -f 2) # Also find out the revision of Git we built # Then use that to generate a combined name we'll distribute cd $KRITA_SOURCES if [[ -d .git ]]; then GIT_REVISION=$(git rev-parse --short HEAD) VERSION=$KRITA_VERSION-$GIT_REVISION else VERSION=$KRITA_VERSION fi # Return to our build root cd $BUILD_PREFIX + # Step 4: Build the image!!! linuxdeployqt $APPDIR/usr/share/applications/org.kde.krita.desktop \ -executable=$APPDIR/usr/bin/krita \ -qmldir=$DEPS_INSTALL_PREFIX/qml \ -verbose=2 \ -bundle-non-qt-libs \ -extra-plugins=$PLUGINS,$APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so,$APPDIR/usr/lib//qml/org/krita/sketch/libkritasketchplugin.so,$APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so \ -appimage - + # Generate a new name for the Appimage file and rename it accordingly APPIMAGE=krita-"$VERSION"-x86_64.appimage + mv Krita*x86_64.AppImage $APPIMAGE + diff --git a/packaging/macos/Makefile b/packaging/macos/Makefile deleted file mode 100644 index bd0d783de6..0000000000 --- a/packaging/macos/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -# -# Build file for creating DMG files. -# -# The DMG packager looks for a template.dmg.bz2 for using as its -# DMG template. If it doesn't find one, it generates a clean one. -# -# If you create a DMG template, you should make one containing all -# the files listed in $(SOURCE_FILES) below, and arrange everything to suit -# your style. The contents of the files themselves does not matter, so -# they can be empty (they will be overwritten later). -# -# Remko Tronçon -# http://el-tramo.be/about -# Licensed under the MIT License. See COPYING for details. - - -################################################################################ -# Customizable variables -################################################################################ - -NAME ?= krita -VERSION ?= 4.0.0-prealpha - -SOURCE_DIR ?= /Users/boud/master -SOURCE_FILES ?= krita.app - -TEMPLATE_DMG ?= template.dmg - - -################################################################################ -# DMG building. No editing should be needed beyond this point. -################################################################################ - -MASTER_DMG=$(NAME)-$(VERSION).dmg -WC_DMG=wc.dmg -WC_DIR=wc - -.PHONY: all -all: $(MASTER_DMG) - -$(TEMPLATE_DMG): $(TEMPLATE_DMG).bz2 - bunzip2 -k $< - -$(TEMPLATE_DMG).bz2: - @echo - @echo --------------------- Generating empty template -------------------- - mkdir template - hdiutil create -fs HFSX -layout SPUD -size 250m "$(TEMPLATE_DMG)" -srcfolder template -format UDRW -volname "$(NAME)" -quiet - rmdir template - bzip2 "$(TEMPLATE_DMG)" - @echo - -$(WC_DMG): $(TEMPLATE_DMG) - cp $< $@ - -$(MASTER_DMG): $(WC_DMG) $(addprefix $(SOURCE_DIR)/,$(SOURCE_FILES)) - @echo - @echo --------------------- Creating Disk Image -------------------- - mkdir -p $(WC_DIR) - hdiutil attach "$(WC_DMG)" -noautoopen -quiet -mountpoint "$(WC_DIR)" - for i in $(SOURCE_FILES); do \ - rm -rf "$(WC_DIR)/$$i"; \ - ditto -rsrc "$(SOURCE_DIR)/$$i" "$(WC_DIR)/$$i"; \ - done - #rm -f "$@" - #hdiutil create -srcfolder "$(WC_DIR)" -format UDZO -imagekey zlib-level=9 "$@" -volname "$(NAME) $(VERSION)" -scrub -quiet - WC_DEV=`hdiutil info | grep "$(WC_DIR)" | grep "Apple_HFS" | awk '{print $$1}'` && \ - hdiutil detach $$WC_DEV -quiet -force - rm -f "$(MASTER_DMG)" - hdiutil convert "$(WC_DMG)" -quiet -format UDZO -imagekey zlib-level=9 -o "$@" - rm -rf $(WC_DIR) - @echo - -.PHONY: clean -clean: - -rm -rf $(TEMPLATE_DMG) $(MASTER_DMG) $(WC_DMG) diff --git a/packaging/macos/b.sh b/packaging/macos/b.sh deleted file mode 100755 index c9d3abcfaa..0000000000 --- a/packaging/macos/b.sh +++ /dev/null @@ -1,53 +0,0 @@ -export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.11 -export MACOSX_DEPLOYMENT_TARGET=10.11 -export SDKROOT=/Applications/Xcode.app/Contents/developer/Platforms/MacOSX.platform/developer/SDKs/MacOSX10.13.sdk - -# Be verbose -set -x -# Exit on error -set -e -/usr/bin/make ext_zlib -/usr/bin/make ext_giflib -/usr/bin/make ext_png -/usr/bin/make ext_lcms2 -/usr/bin/make ext_jpeg -/usr/bin/make ext_openssl -/usr/bin/make ext_qt - -export PATH=/Applications/CMake.app/Contents/bin/:/Users/boud/bin:/Users/boud/dev/deps/bin:/Users/boud/dev/deps/lib:/Users/boud/dev/i/bin:/Users/boud/i/lib:$PATH -export LIBRARY_PATH=/Users/boud/dev/deps/lib:/Users/boud/dev/i/lib:$LIBRARY_PATH -export C_INCLUDE_PATH=/Users/boud/dev/deps/include:/Users/boud/dev/i/include:$C_INCLUDE_PATH -export CPLUS_INCLUDE_PATH=/Users/boud/dev/deps/include:/Users/boud/dev/i/include:$CPLUS_INCLUDE_PATH -#export KRITA_PLUGIN_PATH=/Users/boud/dev/i/ -export PKG_CONFIG_PATH=/Users/boud/dev/deps/lib/pkgconfig:/Users/boud/dev/deps/share/pkgconfig:$PKG_CONFIG_PATH - -/usr/bin/make ext_python -/usr/bin/make ext_boost -/usr/bin/make ext_eigen3 -/usr/bin/make ext_exiv2 -/usr/bin/make ext_fftw3 -/usr/bin/make ext_ilmbase -/usr/bin/make ext_ocio -/usr/bin/make ext_openexr -install_name_tool -add_rpath /Users/boud/dev/deps/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./b44ExpLogTable -install_name_tool -add_rpath /Users/boud/dev/deps/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./dwaLookups -/usr/bin/make ext_openexr -/usr/bin/make ext_tiff -/usr/bin/make ext_vc -/usr/bin/make ext_libraw -/usr/bin/make ext_gettext -/usr/bin/make ext_kcrash -/usr/bin/make ext_gsl -/usr/bin/make ext_freetype -/usr/bin/make ext_fontconfig -install_name_tool -add_rpath /Users/boud/dev/deps/lib ./ext_fontconfig/ext_fontconfig-prefix/src/ext_fontconfig-build/fc-cache/.libs/fc-cache -/usr/bin/make ext_fontconfig -/usr/bin/make ext_poppler - -export DEPS_INSTALL_PREFIX=/Users/boud/dev/deps -export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip:$DEPS_INSTALL_PREFIX/lib/python3.5/site-packages:$DEPS_INSTALL_PREFIX/lib/python3.5 -export PYTHONHOME=$DEPS_INSTALL_PREFIX - -/usr/bin/make ext_sip -/usr/bin/make ext_pyqt - diff --git a/packaging/macos/build-deps.sh b/packaging/macos/build-deps.sh deleted file mode 100755 index 4264f69994..0000000000 --- a/packaging/macos/build-deps.sh +++ /dev/null @@ -1,19 +0,0 @@ -cmake --build . --config RelWithDebInfo --target ext_boost -cmake --build . --config RelWithDebInfo --target ext_eigen3 -cmake --build . --config RelWithDebInfo --target ext_exiv2 -cmake --build . --config RelWithDebInfo --target ext_fftw3 -cmake --build . --config RelWithDebInfo --target ext_ilmbase -cmake --build . --config RelWithDebInfo --target ext_jpeg -cmake --build . --config RelWithDebInfo --target ext_lcms2 -cmake --build . --config RelWithDebInfo --target ext_ocio -cmake --build . --config RelWithDebInfo --target ext_openexr -install_name_tool -add_rpath /Users/boud/dev/i/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./b44ExpLogTable -install_name_tool -add_rpath /Users/boud/dev/i/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./dwaLookups -cmake --build . --config RelWithDebInfo --target ext_openexr -cmake --build . --config RelWithDebInfo --target ext_png -cmake --build . --config RelWithDebInfo --target ext_tiff -cmake --build . --config RelWithDebInfo --target ext_vc -cmake --build . --config RelWithDebInfo --target ext_libraw -cmake --build . --config RelWithDebInfo --target ext_giflib -cmake --build . --config RelWithDebInfo --target ext_kwindowsystem -cmake --build . --config RelWithDebInfo --target ext_gsl diff --git a/packaging/macos/build-release.sh b/packaging/macos/build-release.sh deleted file mode 100755 index a9bfe0f780..0000000000 --- a/packaging/macos/build-release.sh +++ /dev/null @@ -1,13 +0,0 @@ -export MACOSX_DEPLOYMENT_TARGET=10.11 -cmake ../krita-4.0.3 \ - -DCMAKE_INSTALL_PREFIX=/Users/boud/dev/i-krita-4.0.3 \ - -DCMAKE_PREFIX_PATH=/Users/boud/dev/deps \ - -DDEFINE_NO_DEPRECATED=1 -DBUILD_TESTING=OFF \ - -DKDE4_BUILD_TESTS=OFF \ - -DPACKAGERS_BUILD=ON \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DBUNDLE_INSTALL_DIR=$HOME/dev/i/bin \ - -DFOUNDATION_BUILD=ON \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -make -j4 install -../deploy5.sh diff --git a/packaging/macos/configure.sh b/packaging/macos/configure.sh deleted file mode 100755 index 6fb42875c1..0000000000 --- a/packaging/macos/configure.sh +++ /dev/null @@ -1,31 +0,0 @@ -export MACOSX_DEPLOYMENT_TARGET=10.11 -export SDKROOT=/Applications/Xcode.app/Contents/developer/Platforms/MacOSX.platform/developer/SDKs/MacOSX10.13.sdk - -./configure \ - -skip qt3d \ - -skip qtactiveqt \ - -skip qtcanvas3d \ - -skip qtconnectivity \ - -skip qtdeclarative \ - -skip qtdoc \ - -skip qtenginio \ - -skip qtgraphicaleffects \ - -skip qtlocation \ - -skip qtmultimedia \ - -skip qtsensors \ - -skip qtserialport \ - -skip qtwayland \ - -skip qtwebchannel \ - -skip qtwebengine \ - -skip qtwebsockets \ - -skip qtxmlpatterns \ - -opensource -confirm-license -release \ - -no-qml-debug -no-mtdev -no-journald \ - -openssl-linked -no-libproxy \ - -no-pulseaudio -no-alsa -no-nis \ - -no-cups -no-tslib -no-pch \ - -no-dbus -no-gstreamer -no-system-proxies \ - -no-openssl -no-libproxy -no-pulseaudio \ - -nomake examples \ - -prefix /Users/boud/dev/deps - -sdk macosx10.13 diff --git a/packaging/macos/deploy.sh b/packaging/macos/deploy.sh deleted file mode 100755 index 12002ea932..0000000000 --- a/packaging/macos/deploy.sh +++ /dev/null @@ -1,32 +0,0 @@ -set -e # stop on errors -set -x # be verbose -/Users/boud/dev/fixrpath.sh $1 -rm -rf ~/dev/krita.app/ -rm -rf ~/dev/krita.dmg -cp -r ~/dev/i-$1/bin/krita.app ~/dev -cp -r ~/dev/i-$1/share/* ~/dev/krita.app/Contents/Resources -cp -r ~/dev/deps/translations ~/dev/krita.app/Contents/Resources -cd ~/dev/krita.app/Contents -ln -s Resources share -mkdir -p ~/dev/krita.app/Contents/Library/QuickLook -cp -r ~/dev/i-$1/lib/plugins/kritaquicklook.qlgenerator ~/dev/krita.app/Contents/Library/QuickLook - -~/dev/deps/bin/macdeployqt ~/dev/krita.app \ - -verbose=0 \ - -executable=/Users/boud/dev/krita.app/Contents/MacOS/krita \ - -libpath=/Users/boud/dev/i-$1/lib:/Users/boud/dev/deps/lib \ - -qmldir=/Users/boud/dev/deps/qml \ - -extra-plugins=/Users/boud/dev/i-$1/lib/kritaplugins/ \ - -extra-plugins=/Users/boud/dev/i-$1/lib/plugins/ \ - -extra-plugins=/Users/boud/dev/i-$1/plugins/ \ - -extra-plugins=/Users/boud/dev/deps/plugins - -#cp -r /Users/boud/dev/i-$1/lib/qml Resources -#cp -r /Users/boud/dev/deps/lib/python3.5 Frameworks/ -#cp -r /Users/boud/dev/i-$1/lib/krita-python-libs Frameworks/ -# XXX: fix rpath for krita.so -#cp -r /Users/boud/dev/deps/sip Frameworks/ - -install_name_tool -delete_rpath @loader_path/../../../../lib ~/dev/krita.app/Contents/MacOS/krita -rm -rf /Users/boud/dev/krita.app/Contents/PlugIns/kf5/org.kde.kwindowsystem.platforms -codesign -s "Boudewijn Rempt" --deep --continue --timestamp ~/dev/krita.app diff --git a/packaging/macos/deploy5.sh b/packaging/macos/deploy5.sh deleted file mode 100755 index c734dbd5b2..0000000000 --- a/packaging/macos/deploy5.sh +++ /dev/null @@ -1,31 +0,0 @@ -set -e # stop on errors -set -x # be verbose -/Users/boud/dev/fixrpath.sh -rm -rf ~/dev/krita.app/ -rm -rf ~/dev/krita.dmg -cp -r ~/dev/i/bin/krita.app ~/dev -cp -r ~/dev/i/share/* ~/dev/krita.app/Contents/Resources -cp -r ~/dev/deps/translations ~/dev/krita.app/Contents/Resources -cd ~/dev/krita.app/Contents -ln -s Resources share -mkdir -p ~/dev/krita.app/Contents/Library/QuickLook -cp -r ~/dev/i/lib/plugins/kritaquicklook.qlgenerator ~/dev/krita.app/Contents/Library/QuickLook - -~/dev/deps/bin/macdeployqt ~/dev/krita.app \ - -verbose=0 \ - -executable=/Users/boud/dev/krita.app/Contents/MacOS/krita \ - -qmldir=/Users/boud/dev/deps/qml \ - -extra-plugins=/Users/boud/dev/i/lib/kritaplugins/ \ - -extra-plugins=/Users/boud/dev/i/lib/plugins/ \ - -extra-plugins=/Users/boud/dev/i/plugins/ \ - -extra-plugins=/Users/boud/dev/deps/plugins - -cp -r /Users/boud/dev/i/lib/qml Resources -cp -r /Users/boud/dev/deps/lib/python3.5 Frameworks/ -cp -r /Users/boud/dev/i/lib/krita-python-libs Frameworks/ -# XXX: fix rpath for krita.so -cp -r /Users/boud/dev/deps/sip Frameworks/ - - -#install_name_tool -delete_rpath @loader_path/../../../../lib ~/dev/krita.app/Contents/MacOS/krita - diff --git a/packaging/macos/env.sh b/packaging/macos/env.sh deleted file mode 100644 index 915f495d57..0000000000 --- a/packaging/macos/env.sh +++ /dev/null @@ -1,24 +0,0 @@ -export PATH=/Applications/CMake.app/Contents/bin/:/Users/boud/bin:/Users/boud/dev/deps/bin:/Users/boud/dev/deps/lib:/Users/boud/dev/i-krita/bin:/Users/boud/i/lib:$PATH -export LIBRARY_PATH=/Users/boud/dev/deps/lib:/Users/boud/dev/i-krita/lib:$LIBRARY_PATH -export C_INCLUDE_PATH=/Users/boud/dev/deps/include:/Users/boud/dev/i-krita/include:$C_INCLUDE_PATH -export CPLUS_INCLUDE_PATH=/Users/boud/dev/deps/include:/Users/boud/dev/i-krita/include:$CPLUS_INCLUDE_PATH -#export KRITA_PLUGIN_PATH=/Users/boud/dev/i-krita/ -export PKG_CONFIG_PATH=/Users/boud/dev/deps/lib/pkgconfig:/Users/boud/dev/deps/share/pkgconfig:$PKG_CONFIG_PATH - -alias ls='ls -AFG' - -prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; } - -# This will make the debug output prettier -export KDE_COLOR_DEBUG=1 -export QTEST_COLORED=1 - -# We only support from 10.11 up -export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.11 -export MACOSX_DEPLOYMENT_TARGET=10.11 -export SDKROOT=/Applications/Xcode.app/Contents/developer/Platforms/MacOSX.platform/developer/SDKs/MacOSX10.1.sdk - -# Python -#export DEPS_INSTALL_PREFIX=/Users/boud/dev/deps -#export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip:$DEPS_INSTALL_PREFIX/lib/python3.5/site-packages:$DEPS_INSTALL_PREFIX/lib/python3.5 -#export PYTHONHOME=$DEPS_INSTALL_PREFIX diff --git a/packaging/macos/fixrpath.sh b/packaging/macos/fixrpath.sh deleted file mode 100755 index 57be6f13c0..0000000000 --- a/packaging/macos/fixrpath.sh +++ /dev/null @@ -1,10 +0,0 @@ -install_name_tool -add_rpath /Users/boud/dev/i-$1/lib ~/dev/i-$1/bin/krita.app/Contents/MacOS/krita -install_name_tool -add_rpath /Users/boud/dev/deps/lib ~/dev/i-$1/bin/krita.app/Contents/MacOS/krita -install_name_tool -change libboost_system.dylib @rpath/libboost_system.dylib /Users/boud/dev/i-$1/bin/krita.app/Contents/MacOS/krita - - -FILES="$(find /Users/boud/dev/i-$1/lib/ -name '*so' -o -name '*dylib')" -for FILE in $FILES ; do - echo $FILE - install_name_tool -change libboost_system.dylib @rpath/libboost_system.dylib $FILE -done diff --git a/packaging/macos/macdeploy-qt.diff b/packaging/macos/macdeploy-qt.diff deleted file mode 100644 index 92794936a6..0000000000 --- a/packaging/macos/macdeploy-qt.diff +++ /dev/null @@ -1,127 +0,0 @@ -diff --git a/src/macdeployqt/macdeployqt/main.cpp b/src/macdeployqt/macdeployqt/main.cpp -index 81639f2..a7b28d1 100644 ---- a/src/macdeployqt/macdeployqt/main.cpp -+++ b/src/macdeployqt/macdeployqt/main.cpp -@@ -57,6 +57,7 @@ int main(int argc, char **argv) - qDebug() << " -always-overwrite : Copy files even if the target file exists"; - qDebug() << " -codesign= : Run codesign with the given identity on all executables"; - qDebug() << " -appstore-compliant: Skip deployment of components that use private API"; -+ qDebug() << " -extra-plugins= : Deploy plugins from given extra directory"; - qDebug() << ""; - qDebug() << "macdeployqt takes an application bundle as input and makes it"; - qDebug() << "self-contained by copying in the Qt frameworks and plugins that"; -@@ -96,6 +97,7 @@ int main(int argc, char **argv) - extern bool runCodesign; - extern QString codesignIdentiy; - extern bool appstoreCompliant; -+ QStringList extraPluginDirectories; - - for (int i = 2; i < argc; ++i) { - QByteArray argument = QByteArray(argv[i]); -@@ -151,6 +153,13 @@ int main(int argc, char **argv) - } else if (argument == QByteArray("-appstore-compliant")) { - LogDebug() << "Argument found:" << argument; - appstoreCompliant = true; -+ } else if (argument.startsWith(QByteArray("-extra-plugins"))) { -+ LogDebug() << "Argument found:" << argument; -+ int index = argument.indexOf('='); -+ if (index == -1) -+ LogError() << "Missing extra plugins directory"; -+ else -+ extraPluginDirectories << argument.mid(index+1); - } else if (argument.startsWith("-")) { - LogError() << "Unknown argument" << argument << "\n"; - return 1; -@@ -178,10 +187,13 @@ int main(int argc, char **argv) - deploymentInfo.deployedFrameworks = deploymentInfo.deployedFrameworks.toSet().toList(); - } - -- if (plugins && !deploymentInfo.qtPath.isEmpty()) { -+ if ((plugins && !deploymentInfo.qtPath.isEmpty()) || !extraPluginDirectories.isEmpty()) { - deploymentInfo.pluginPath = deploymentInfo.qtPath + "/plugins"; - LogNormal(); -- deployPlugins(appBundlePath, deploymentInfo, useDebugLibs); -+ if (plugins && !deploymentInfo.qtPath.isEmpty()) -+ deployPlugins(appBundlePath, deploymentInfo, useDebugLibs); -+ if (!extraPluginDirectories.isEmpty()) -+ deployExtraPlugins(appBundlePath, deploymentInfo, useDebugLibs, extraPluginDirectories); - createQtConf(appBundlePath); - } - -diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp -index d20b219..4a9aa1f 100644 ---- a/src/macdeployqt/shared/shared.cpp -+++ b/src/macdeployqt/shared/shared.cpp -@@ -1020,6 +1020,43 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl - } - } - -+void deployExtraPlugins(const ApplicationBundleInfo &appBundleInfo, -+ const QString pluginDestinationPath, DeploymentInfo deploymentInfo, bool useDebugLibs, const QStringList &extraPluginDirectories) -+{ -+ foreach (const QString &extraPluginDir, extraPluginDirectories) { -+ LogNormal() << "Deploying plugins from" << extraPluginDir; -+ -+ // search for dylib and so files, both work as plugins on mac os -+ QDir dir(extraPluginDir); -+ dir.setFilter(QDir::Files); -+ dir.setNameFilters(QStringList() << "*.dylib" << "*.so"); -+ QDirIterator dirIterator(dir, QDirIterator::Subdirectories); -+ QStringList pluginList; -+ while (dirIterator.hasNext()) { -+ dirIterator.next(); -+ if (!QFileInfo(dirIterator.filePath()).isFile()) -+ continue; -+ pluginList.append(dir.relativeFilePath(dirIterator.filePath())); -+ } -+ -+ // deploy all found plugins -+ foreach (const QString &plugin, pluginList) { -+ QString sourcePath = extraPluginDir + "/" + plugin; -+ const QString destinationPath = pluginDestinationPath + "/" + extraPluginDir.split("/", QString::SkipEmptyParts).last() + "/" + plugin; -+ QDir dir; -+ dir.mkpath(QFileInfo(destinationPath).path()); -+ -+ if (copyFilePrintStatus(sourcePath, destinationPath)) { -+ runStrip(destinationPath); -+ -+ QList frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs); -+ deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath); -+ -+ } -+ } -+ } -+} -+ - void createQtConf(const QString &appBundlePath) - { - // Set Plugins and imports paths. These are relative to App.app/Contents. -@@ -1061,6 +1098,16 @@ void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, - deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo, useDebugLibs); - } - -+void deployExtraPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs, const QStringList &extraPluginDirectories) -+{ -+ ApplicationBundleInfo applicationBundle; -+ applicationBundle.path = appBundlePath; -+ applicationBundle.binaryPath = findAppBinary(appBundlePath); -+ -+ const QString pluginDestinationPath = appBundlePath + "/" + "Contents/PlugIns"; -+ deployExtraPlugins(applicationBundle, pluginDestinationPath, deploymentInfo, useDebugLibs, extraPluginDirectories); -+} -+ - void deployQmlImport(const QString &appBundlePath, const QSet &rpaths, const QString &importSourcePath, const QString &importName) - { - QString importDestinationPath = appBundlePath + "/Contents/Resources/qml/" + importName; -diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h -index ea678c2..f10efd3 100644 ---- a/src/macdeployqt/shared/shared.h -+++ b/src/macdeployqt/shared/shared.h -@@ -100,6 +100,7 @@ DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringLis - DeploymentInfo deployQtFrameworks(QList frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath); - void createQtConf(const QString &appBundlePath); - void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs); -+void deployExtraPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs, const QStringList &extraPluginDirectories); - bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs); - void changeIdentification(const QString &id, const QString &binaryPath); - void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath); diff --git a/packaging/macos/notes.txt b/packaging/macos/notes.txt deleted file mode 100644 index a2875ce713..0000000000 --- a/packaging/macos/notes.txt +++ /dev/null @@ -1,50 +0,0 @@ -OSX Build Notes - -Setup: - -~/dev/b: build location for all dependencies (run cmake ../krita/3rdparty in /dev/b) -~/dev/d: download location for all dependencies -~/dev/i: install location for all dependencies -~/dev/build: manual build location -~/dev/krita: source checkout - -deploy.sh: for creating the krita.app bundle - -cmake command to configure krita: - -cmake ../krita \ - -DCMAKE_PREFIX_PATH=$HOME/dev/i \ - -DCMAKE_LIBRARY_PATH=$HOME/dev/i/lib \ - -Wno-dev \ - -DCMAKE_INSTALL_PREFIX=$HOME/dev/i \ - -DBUILD_TESTING=OFF \ - -DDEFINE_NO_DEPRECATED=1 \ - -DBUILD_doc=FALSE \ - -DBUNDLE_INSTALL_DIR=$HOME/dev/i/bin - - -cmake command to configure the ext projects - -cmake ../krita/3rdparty/ -DCMAKE_INSTALL_PREFIX=$HOME/dev/i/ -DEXTERNALS_DOWNLOAD_DIR=$HOME/dev/d/ -DINSTALL_ROOT=$HOME/dev/i/ - -cmake line for qt creator - --DBUILD_TESTING=OFF -DKDE4_BUILD_TESTS=OFF -DDEFINE_NO_DEPRECATED=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=$HOME/dev/i -DCMAKE_INCLUDE_PATH=$HOME/dev/i/include -DQT_QMAKE_EXECUTABLE=$HOME/dev/i/bin/qmake -DCMAKE_PREFIX_PATH=$HOME/dev/i - -rm -rf ~/krita.app/ -rm -rf ~/krita.dmg -cp -r ~/dev/i/bin/krita.app ~ -cp -r ~/dev/i/share ~/krita.app/Contents/ -macdeployqt ~/krita.app \ - -verbose=1 \ - -extra-plugins=$HOME/dev/i/lib/kritaplugins/ \ - -extra-plugins=$HOME/dev/i/lib/kf5/ \ - -extra-plugins=$HOME/dev/i/lib/plugins/ \ - -extra-plugins=$HOME/dev/i/plugins/ \ - -dmg -mkdir ~/krita.app/Contents/PlugIns/kritaplugins -mv ~/krita.app/Contents/PlugIns/*so ~/krita.app/Contents/PlugIns/kritaplugins - -To make open_exr build, manual step after it fails because dwalookups cannot find Half: -install_name_tool -add_rpath /Users/boud/dev/i/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./b44ExpLogTable -install_name_tool -add_rpath /Users/boud/dev/i/lib /Users/boud/dev/b/ext_openexr/ext_openexr-prefix/src/ext_openexr-build/IlmImf/./dwaLookups diff --git a/packaging/macos/osxdeploy.sh b/packaging/macos/osxdeploy.sh index a366bd478b..29b460ef0c 100755 --- a/packaging/macos/osxdeploy.sh +++ b/packaging/macos/osxdeploy.sh @@ -1,367 +1,432 @@ #!/usr/bin/env sh # Krita tool to create dmg from installed source # Copies all files to a folder to be converted into the final dmg # Background image must be set for it to deploy correcly # osxdeploy.sh automates the creation of the release DMG. It needs an image # either png or jpg as first argument as it will use the image to set # the background of the DMG. # Necessary files can be downloaded from https://drive.google.com/drive/folders/15cUhCou7ya9ktjfhbzRaL7_IpntzxG4j?usp=sharing # A short explanation of what it does: # - Creates a copy of "krita-template" folder (this containes Terms of use # and Applications) into kritadmg folder. # Application folder symlink can be created with applescript but Terms of use contents cannot, # also working like this allows to add other files to dmg if needed. # Place the folder in ${BUILDROOT} # - Copies krita.app contents to kritadmg folder # - Copies i/share to Contents/Resources excluding unnecesary files # - Copies translations, qml and quicklook PlugIns # - Copies i/plugins and i/lib/plugins to Contents/PlugIns # - Runs macdeployqt: macdeployqt is not built by default in ext_qt # build by: # cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src # make sub-macdeployqt-all # make sub-macdeployqt-install_subtargets # make install # the script changes dir to installation/bin to run macdeployqt as it can be buggy # if not runned from the same folder as the binary is on. # - Fix rpath from krita bin # - Find missing libraries from plugins and copy to Framworks or plugins. # This uses oTool iterative to find all unique libraries, then it searches each # library fond in folder, and if not found attempts to copy contents # to the appropiate folder, either Frameworks (if frameworks is in namefile, or # library has plugin isnot in path), or plugin if otherwise. # - Builds DMG # Building DMG creates a new dmg with the contents of # mounts the dmg and sets the style for dmg. # unmount # Compress resulting dmg into krita_nightly-.dmg # deletes temporary files. DMG_title="krita" #if changed krita.temp.dmg must be deleted manually if test -z ${BUILDROOT}; then echo "ERROR: BUILDROOT env not set!" echo "\t Must point to the root of the buildfiles as stated in 3rdparty Readme" echo "exiting..." exit fi # There is some duplication between build and deploy scripts # a config env file could would be a nice idea. KIS_INSTALL_DIR=${BUILDROOT}/i KIS_BUILD_DIR=${BUILDROOT}/kisbuild # only used for getting git sha number KRITA_DMG=${BUILDROOT}/kritadmg KRITA_DMG_TEMPLATE=${BUILDROOT}/kritadmg-template # flags for OSX environment # We only support from 10.11 up export MACOSX_DEPLOYMENT_TARGET=10.11 export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.11 print_usage () { - echo "USAGE: osxdeploy.sh [pkg]" + echo "USAGE: osxdeploy.sh [-s=] " + echo "\t -s Code sign identity for codesign" echo "\t osxdeploy needs an input image to add to the dmg background \t image recomended size is at least 950x500\n" } if test ${#} -eq 0; then echo "ERROR: no option given" print_usage exit 1 fi -if [[ -f ${1} ]]; then - DMG_validBG=0 - echo "attempting to check background is valid jpg or png..." - BG_FORMAT=$(sips --getProperty format ${1} | awk '{printf $2}') - - if [[ "png" = ${BG_FORMAT} || "jpeg" = ${BG_FORMAT} ]];then - echo "valid image file" - DMG_background=${1} - DMG_validBG=1 +for arg in "${@}"; do + if [[ -f ${arg} ]]; then + DMG_validBG=0 + echo "attempting to check background is valid jpg or png..." + BG_FORMAT=$(sips --getProperty format ${arg} | awk '{printf $2}') + + if [[ "png" = ${BG_FORMAT} || "jpeg" = ${BG_FORMAT} ]];then + echo "valid image file" + DMG_background=${arg} + DMG_validBG=1 + fi fi -fi + # If string starts with -sign + if [[ ${arg} = -s=* ]]; then + CODE_SIGNATURE="${arg#*=}" + fi + + if [[ ${arg} = "-h" || ${arg} = "--help" ]]; then + print_usage + exit + fi +done if [[ ${DMG_validBG} -eq 0 ]]; then echo "No jpg or png valid file detected!!" echo "exiting" exit fi +if [[ -z "${CODE_SIGNATURE}" ]]; then + echo "WARNING: No signature provided, Code will not be signed" +else + printf 'Code will be signed with "%s"\n' "${CODE_SIGNATURE}" +fi + # Helper functions countArgs () { echo "${#}" } stringContains () { echo "$(grep "${2}" <<< "${1}")" } add_lib_to_list() { local llist=${2} if test -z "$(grep ${1##*/} <<< ${llist})" ; then local llist="${llist} ${1##*/} " fi echo ${llist} } # Find all @rpath and Absolute to buildroot path libs # Add to libs_used # converts absolute buildroot path to @rpath find_needed_libs () { echo "Analizing libraries with oTool..." >&2 local libs_used="" # input lib_lists founded for libFile in $(find ${KRITA_DMG}/krita.app/Contents -name "*.so" -or -name "*.dylib"); do oToolResult=$(otool -L ${libFile} | awk '{print $1}') resultArray=(${oToolResult}) # convert to array echo "${libFile##*Contents/}" >&2 for lib in ${resultArray[@]:1}; do if test "${lib:0:1}" = "@"; then local libs_used=$(add_lib_to_list ${lib} "${libs_used}") fi if test "${lib:0:${#BUILDROOT}}" = "${BUILDROOT}"; then install_name_tool -id ${lib##*/} "${libFile}" install_name_tool -change ${lib} "@rpath/${lib##*/}" "${libFile}" local libs_used=$(add_lib_to_list ${lib} "${libs_used}") fi done done echo ${libs_used} # return updated list } find_missing_libs (){ echo "Searching for missing libs on deployment folders…" >&2 local libs_missing="" for lib in ${@}; do if test -z "$(find ${KRITA_DMG}/krita.app/Contents/ -name ${lib})"; then echo "Adding ${lib} to missing libraries." >&2 libs_missing="${libs_missing} ${lib}" fi done echo ${libs_missing} } copy_missing_libs () { for lib in ${@}; do result=$(find "${BUILDROOT}/i" -name "${lib}") if test $(countArgs ${result}) -eq 1; then echo ${result} if [ "$(stringContains "${result}" "plugin")" ]; then echo "copying ${lib} to plugins dir" cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/PlugIns/ else echo "copying ${lib} to Frameworks dir" cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/Frameworks/ fi else echo "${lib} might be a missing framework" if [ "$(stringContains "${result}" "framework")" ]; then echo "copying framework ${BUILDROOT}/i/lib/${lib}.framework to dmg" - cp -pvr ${BUILDROOT}/i/lib/${lib}.framework ${KRITA_DMG}/krita.app/Contents/Frameworks/ + # TODO rsync only included ${lib} Resources Versions + rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/${lib} ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ + rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Resources ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ + rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Versions ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ fi fi done } krita_findmissinglibs() { echo "Starting search for missing libraries" neededLibs=$(find_needed_libs) echo "\nDone!" missingLibs=$(find_missing_libs ${neededLibs}) if test $(countArgs ${missingLibs}) -gt 0; then echo "Found missing libs!" echo "${missingLibs}\n" copy_missing_libs ${missingLibs} else echo "No missing libraries found." fi echo "Done!" } krita_deploy () { # fix_boost_rpath cd ${BUILDROOT} # Update files in krita.app + echo "Deleting previous kritadmg run..." rm -rf ./krita.dmg ${KRITA_DMG} # Copy new builtFiles + echo "Preparing ${KRITA_DMG} for deployment..." + echo "Copying krita.app..." rsync -riul ${KRITA_DMG_TEMPLATE}/ ${KRITA_DMG} - rsync -priul ${KIS_INSTALL_DIR}/bin/krita.app ${KRITA_DMG} + rsync -prul ${KIS_INSTALL_DIR}/bin/krita.app ${KRITA_DMG} + + mkdir -p ${KRITA_DMG}/krita.app/Contents/PlugIns + mkdir -p ${KRITA_DMG}/krita.app/Contents/Frameworks echo "Copying share..." # Deletes old copies of translation and qml to be recreated cd ${KIS_INSTALL_DIR}/share/ - rsync -priul --delete ./ \ + rsync -prul --delete ./ \ --exclude krita_SRCS.icns \ --exclude aclocal \ --exclude doc \ --exclude ECM \ --exclude eigen3 \ --exclude emacs \ --exclude gettext \ --exclude gettext-0.19.8 \ --exclude info \ --exclude kf5 \ --exclude kservices5 \ --exclude man \ --exclude ocio \ --exclude pkgconfig \ --exclude mime \ --exclude translations \ --exclude qml \ ${KRITA_DMG}/krita.app/Contents/Resources cd ${BUILDROOT} echo "Copying translations..." - rsync -priul ${KIS_INSTALL_DIR}/translations/ \ + rsync -prul ${KIS_INSTALL_DIR}/translations/ \ ${KRITA_DMG}/krita.app/Contents/Resources/translations echo "Copying kritaquicklook..." mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/QuickLook - rsync -priul ${KIS_INSTALL_DIR}/plugins/kritaquicklook.qlgenerator ${KRITA_DMG}/krita.app/Contents/Library/QuickLook + rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklook.qlgenerator ${KRITA_DMG}/krita.app/Contents/Library/QuickLook cd ${KRITA_DMG}/krita.app/Contents ln -shF Resources share echo "Copying qml..." - rsync -priul ${KIS_INSTALL_DIR}/qml Resources/qml + rsync -prul ${KIS_INSTALL_DIR}/qml Resources/qml echo "Copying plugins..." - mkdir -p ${KRITA_DMG}/krita.app/Contents/PlugIns # exclude kritaquicklook.qlgenerator/ cd ${KIS_INSTALL_DIR}/plugins/ - rsync -priul --delete --delete-excluded ./ \ + rsync -prul --delete --delete-excluded ./ \ --exclude kritaquicklook.qlgenerator \ ${KRITA_DMG}/krita.app/Contents/PlugIns cd ${BUILDROOT} - rsync -priul ${KIS_INSTALL_DIR}/lib/kritaplugins/ ${KRITA_DMG}/krita.app/Contents/PlugIns + rsync -prul ${KIS_INSTALL_DIR}/lib/kritaplugins/ ${KRITA_DMG}/krita.app/Contents/PlugIns # rsync -prul /Volumes/Osiris/programs/krita-master/i/lib/libkrita* Frameworks/ # activate for python enabled Krita # echo "Copying python..." # cp -r ${KIS_INSTALL_DIR}/lib/python3.5 Frameworks/ # cp -r ${KIS_INSTALL_DIR}/lib/krita-python-libs Frameworks/ # XXX: fix rpath for krita.so # echo "Copying sip..." # rsync -Prvul ${KIS_INSTALL_DIR}/sip Frameworks/ # To avoid errors macdeployqt must be run from bin location # ext_qt will not build macdeployqt by default so it must be build manually # cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src # make sub-macdeployqt-all # make sub-macdeployqt-install_subtargets # make install - echo "Preparing ${KRITA_DMG} for deployment..." echo "Running macdeployqt..." cd ${KIS_INSTALL_DIR}/bin ./macdeployqt ${KRITA_DMG}/krita.app \ -verbose=0 \ -executable=${KRITA_DMG}/krita.app/Contents/MacOS/krita \ -libpath=${KIS_INSTALL_DIR}/lib \ -qmldir=${KIS_INSTALL_DIR}/qml \ # -extra-plugins=${KIS_INSTALL_DIR}/lib/kritaplugins \ # -extra-plugins=${KIS_INSTALL_DIR}/lib/plugins \ # -extra-plugins=${KIS_INSTALL_DIR}/plugins cd ${BUILDROOT} echo "macdeployqt done!" install_name_tool -delete_rpath @loader_path/../../../../lib ${KRITA_DMG}/krita.app/Contents/MacOS/krita rm -rf ${KRITA_DMG}/krita.app/Contents/PlugIns/kf5/org.kde.kwindowsystem.platforms # repair krita for plugins krita_findmissinglibs } +# Code sign must be done as recommended by apple "sign code inside out in individual stages" +signBundle() { + # helper to define function only once + batch_codesign() { + xargs -P4 -I FILE codesign -f -s "${CODE_SIGNATURE}" FILE + } + cd ${KRITA_DMG} + + # sign Frameworks and libs + cd ${KRITA_DMG}/krita.app/Contents/Frameworks + # remove debug version as both versions cant be signed. + rm ${KRITA_DMG}/krita.app/Contents/Frameworks/QtScript.framework/Versions/Current/QtScript_debug + find . -type d -name "*.framework" | xargs printf "%s/Versions/Current\n" | batch_codesign + find . -type f -name "*.dylib" -or -name "*.so" | batch_codesign + + # Sign all other files in Framework (needed) + # there are many files in pyton do we need to sign them? TODO + # find krita-python-libs -type f | batch_codesign + # find python -type f | batch_codesign + + # Sing only libraries and plugins + cd ${KRITA_DMG}/krita.app/Contents/PlugIns + find . -type f -name "*.dylib" -or -name "*.so" | batch_codesign + + cd ${KRITA_DMG}/krita.app/Contents/Library/QuickLook + printf "kritaquicklook.qlgenerator" | batch_codesign + + cd ${KRITA_DMG}/krita.app/Contents/Resources + find . -type f -name "*.dylib" -or -name "*.so" | batch_codesign + + + #Finally sign krita and krita.app + printf "${KRITA_DMG}/krita.app/Contents/MacOS/krita" | batch_codesign + printf "${KRITA_DMG}/krita.app" | batch_codesign +} + createDMG () { echo "Starting creation of dmg..." cd ${BUILDROOT} DMG_size=500 ## Build dmg from folder # create dmg on local system # usage of -fsargs minimze gaps at front of filesystem (reduce size) hdiutil create -srcfolder "${KRITA_DMG}" -volname "${DMG_title}" -fs HFS+ \ -fsargs "-c c=64,a=16,e=16" -format UDRW -size ${DMG_size}m krita.temp.dmg # Next line is only useful if we have a dmg as a template! # previous hdiutil must be uncommented # cp krita-template.dmg krita.dmg device=$(hdiutil attach -readwrite -noverify -noautoopen "krita.temp.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}') # rsync -priul --delete ${KRITA_DMG}/krita.app "/Volumes/${DMG_title}" # Set style for dmg if [[ ! -d "/Volumes/${DMG_title}/.background" ]]; then mkdir "/Volumes/${DMG_title}/.background" fi cp ${BUILDROOT}/${DMG_background} "/Volumes/${DMG_title}/.background/" ## Apple script to set style echo ' tell application "Finder" tell disk "'${DMG_title}'" open set current view of container window to icon view set toolbar visible of container window to false set statusbar visible of container window to false set the bounds of container window to {186, 156, 956, 592} set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 80 set background picture of theViewOptions to file ".background:'${DMG_background}'" set position of item "'krita.app'" of container window to {279, 272} set position of item "Applications" of container window to {597, 272} set position of item "Terms of Use" of container window to {597, 110} update without registering applications delay 1 close end tell end tell ' | osascript chmod -Rf go-w "/Volumes/${DMG_title}" # ensure all writting operations to dmg are over sync hdiutil detach $device hdiutil convert "krita.temp.dmg" -format UDZO -imagekey -zlib-level=9 -o krita-out.dmg # Add git version number GIT_SHA=$(grep "#define KRITA_GIT_SHA1_STRING" ${KIS_BUILD_DIR}/libs/version/kritagitversion.h | awk '{gsub(/"/, "", $3); printf $3}') mv krita-out.dmg krita-nightly_${GIT_SHA}.dmg echo "moved krita-out.dmg to krita-nightly_${GIT_SHA}.dmg" rm krita.temp.dmg echo "dmg done!" } # Run deploy command, instalation is assumed to exist in BUILDROOT/i krita_deploy +# Code sign krita.app +if [[ -n "${CODE_SIGNATURE}" ]]; then + signBundle +fi # Create DMG from files insiede ${KRITA_DMG} folder createDMG diff --git a/packaging/macos/run-cmake-3rdparty.sh b/packaging/macos/run-cmake-3rdparty.sh deleted file mode 100755 index a1a958e9b1..0000000000 --- a/packaging/macos/run-cmake-3rdparty.sh +++ /dev/null @@ -1,10 +0,0 @@ -export MACOSX_DEPLOYMENT_TARGET=10.11 -export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.11 -export MACOSX_DEPLOYMENT_TARGET=10.11 -export SDKROOT=/Applications/Xcode.app/Contents/developer/Platforms/MacOSX.platform/developer/SDKs/MacOSX10.13.sdk - -/Applications/CMake.app/Contents/bin/cmake ../krita/3rdparty/ \ - -DCMAKE_INSTALL_PREFIX=/Users/boud/dev/deps \ - -DINSTALL_ROOT=/Users/boud/dev/deps \ - -DEXTERNALS_DOWNLOAD_DIR=/Users/boud/Downloads \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 diff --git a/packaging/macos/run-cmake-gmic-qt.sh b/packaging/macos/run-cmake-gmic-qt.sh deleted file mode 100755 index 84a05f6893..0000000000 --- a/packaging/macos/run-cmake-gmic-qt.sh +++ /dev/null @@ -1,7 +0,0 @@ -export MACOSX_DEPLOYMENT_TARGET=10.11 -cmake ../gmic-qt \ - -DGMIC_QT_HOST=krita \ - -DCMAKE_INSTALL_PREFIX=/Users/boud/dev/i \ - -DCMAKE_PREFIX_PATH=/Users/boud/dev/deps \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 diff --git a/packaging/macos/run-cmake-krita.sh b/packaging/macos/run-cmake-krita.sh deleted file mode 100755 index 53d2e01c86..0000000000 --- a/packaging/macos/run-cmake-krita.sh +++ /dev/null @@ -1,17 +0,0 @@ -export MACOSX_DEPLOYMENT_TARGET=10.11 -export DEPS_INSTALL_PREFIX=/Users/boud/dev/deps -export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip:$DEPS_INSTALL_PREFIX/lib/python3.5/site-packages:$DEPS_INSTALL_PREFIX/lib/python3.5 -export PYTHONHOME=$DEPS_INSTALL_PREFIX -cmake ../$1 \ - -DCMAKE_INSTALL_PREFIX=/Users/boud/dev/i-$1 \ - -DCMAKE_PREFIX_PATH=/Users/boud/dev/deps \ - -DDEFINE_NO_DEPRECATED=0 \ - -DBUILD_TESTING=OFF \ - -DFOUNDATION_BUILD=ON \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DBUNDLE_INSTALL_DIR=$HOME/dev/i-$1/bin \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 \ - -DHIDE_SAFE_ASSERTS=ON \ - -DBUILD_TESTING=FALSE \ - -DPYQT_SIP_DIR_OVERRIDE=$DEPS_INSTALL_PREFIX/share/sip/ \ - -DHAVE_MEMORY_LEAK_TRACKER=FALSE diff --git a/plugins/dockers/lut/lutdocker_dock.cpp b/plugins/dockers/lut/lutdocker_dock.cpp index e3856144dd..e905dc7105 100644 --- a/plugins/dockers/lut/lutdocker_dock.cpp +++ b/plugins/dockers/lut/lutdocker_dock.cpp @@ -1,674 +1,683 @@ /* * 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 #include "kis_icon_utils.h" #include #include #include #include #include #include #include #include #include #include "kis_signals_blocker.h" #include "krita_utils.h" #include "ocio_display_filter.h" #include "black_white_point_chooser.h" #include "KisOcioConfiguration.h" #include 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) { 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(true); m_chkUseOcio->setChecked(cfg.useOcio()); connect(m_chkUseOcio, SIGNAL(toggled(bool)), SLOT(updateDisplaySettings())); connect(m_colorManagement, SIGNAL(currentIndexChanged(int)), SLOT(slotColorManagementModeChanged())); m_bnSelectConfigurationFile->setToolTip(i18n("Select custom configuration file.")); connect(m_bnSelectConfigurationFile,SIGNAL(clicked()), SLOT(selectOcioConfiguration())); KisOcioConfiguration ocioOptions = cfg.ocioConfiguration(); m_txtConfigurationPath->setText(ocioOptions.configurationPath); m_txtLut->setText(ocioOptions.lutPath); 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())); resetOcioConfiguration(); } LutDockerDock::~LutDockerDock() { } void LutDockerDock::setCanvas(KoCanvasBase* _canvas) { if (m_canvas) { m_canvas->disconnect(this); } setEnabled(_canvas != 0); if (KisCanvas2* canvas = dynamic_cast(_canvas)) { m_canvas = canvas; if (m_canvas) { if (!m_canvas->displayFilter()) { resetOcioConfiguration(); updateDisplaySettings(); } else { m_displayFilter = m_canvas->displayFilter(); OcioDisplayFilter *displayFilter = qobject_cast(m_displayFilter.data()); Q_ASSERT(displayFilter); m_ocioConfig = displayFilter->config; KisSignalsBlocker exposureBlocker(m_exposureDoubleWidget); m_exposureDoubleWidget->setValue(displayFilter->exposure); KisSignalsBlocker gammaBlocker(m_gammaDoubleWidget); m_gammaDoubleWidget->setValue(displayFilter->gamma); KisSignalsBlocker componentsBlocker(m_cmbComponents); m_cmbComponents->setCurrentIndex((int)displayFilter->swizzle); KisSignalsBlocker bwBlocker(m_bwPointChooser); m_bwPointChooser->setBlackPoint(displayFilter->blackPoint); m_bwPointChooser->setWhitePoint(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::unsetCanvas() { m_canvas = 0; setEnabled(false); m_displayFilter = QSharedPointer(0); } 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 { if (!m_chkUseOcio->isChecked() || !m_ocioConfig) return false; const bool externalColorManagementEnabled = m_colorManagement->currentIndex() != (int)KisOcioConfiguration::INTERNAL; + +#ifdef HAVE_HDR +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + KisSurfaceColorSpace currentColorSpace = KisOpenGLModeProber::instance()->surfaceformatInUse().colorSpace(); +#else + KisSurfaceColorSpace currentColorSpace = KisSurfaceColorSpace::DefaultColorSpace; +#endif +#endif + const bool exposureManagementEnabled = externalColorManagementEnabled #ifdef HAVE_HDR - || KisOpenGLModeProber::instance()->surfaceformatInUse().colorSpace() == QSurfaceFormat::scRGBColorSpace + || currentColorSpace == KisSurfaceColorSpace::scRGBColorSpace #endif ; return exposureManagementEnabled; } qreal LutDockerDock::currentExposure() const { if (!m_displayFilter) return 0.0; OcioDisplayFilter *displayFilter = qobject_cast(m_displayFilter.data()); return canChangeExposureAndGamma() ? 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; OcioDisplayFilter *displayFilter = qobject_cast(m_displayFilter.data()); return canChangeExposureAndGamma() ? 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()->canvasResourceProvider()->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()->canvasResourceProvider()->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) KisOcioConfiguration::INTERNAL); } const bool ocioEnabled = m_chkUseOcio->isChecked(); m_colorManagement->setEnabled(ocioEnabled && canDoExternalColorCorrection); const bool externalColorManagementEnabled = m_colorManagement->currentIndex() != (int)KisOcioConfiguration::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); const bool exposureManagementEnabled = canChangeExposureAndGamma(); m_exposureDoubleWidget->setEnabled(exposureManagementEnabled); m_gammaDoubleWidget->setEnabled(exposureManagementEnabled); m_lblExposure->setEnabled(exposureManagementEnabled); m_lblGamma->setEnabled(exposureManagementEnabled); QString exposureToolTip; if (!exposureManagementEnabled) { exposureToolTip = i18nc("@info:tooltip", "Exposure and Gamma corrections are disabled in Internal mode. Switch to OCIO mode to use them"); } m_exposureDoubleWidget->setToolTip(exposureToolTip); m_gammaDoubleWidget->setToolTip(exposureToolTip); m_lblExposure->setToolTip(exposureToolTip); m_lblGamma->setToolTip(exposureToolTip); bool enableConfigPath = m_colorManagement->currentIndex() == (int) KisOcioConfiguration::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) { KIS_SAFE_ASSERT_RECOVER_NOOP(!m_canvas->displayFilter() || m_canvas->displayFilter() == m_displayFilter); if (!m_displayFilter) { m_displayFilter = m_canvas->displayFilter() ? m_canvas->displayFilter() : QSharedPointer(new OcioDisplayFilter(this)); } OcioDisplayFilter *displayFilter = qobject_cast(m_displayFilter.data()); displayFilter->config = m_ocioConfig; displayFilter->inputColorSpaceName = m_ocioConfig->getColorSpaceNameByIndex(m_cmbInputColorSpace->currentIndex()); displayFilter->displayDevice = m_ocioConfig->getDisplay(m_cmbDisplayDevice->currentIndex()); displayFilter->view = m_ocioConfig->getView(displayFilter->displayDevice, m_cmbView->currentIndex()); displayFilter->look = m_ocioConfig->getLookNameByIndex(m_cmbLook->currentIndex()); displayFilter->gamma = m_gammaDoubleWidget->isEnabled() ? m_gammaDoubleWidget->value() : 1.0; displayFilter->exposure = m_exposureDoubleWidget->isEnabled() ? m_exposureDoubleWidget->value() : 0.0; displayFilter->swizzle = (OCIO_CHANNEL_SWIZZLE)m_cmbComponents->currentIndex(); displayFilter->blackPoint = m_bwPointChooser->blackPoint(); displayFilter->whitePoint = m_bwPointChooser->whitePoint(); displayFilter->forceInternalColorManagement = m_colorManagement->currentIndex() == (int)KisOcioConfiguration::INTERNAL; displayFilter->setLockCurrentColorVisualRepresentation(m_btnConvertCurrentColor->isChecked()); displayFilter->updateProcessor(); m_canvas->setDisplayFilter(m_displayFilter); } else { m_canvas->setDisplayFilter(QSharedPointer(0)); } m_canvas->updateCanvas(); } void LutDockerDock::writeControls() { KisOcioConfiguration ocioOptions; ocioOptions.mode = (KisOcioConfiguration::Mode)m_colorManagement->currentIndex(); ocioOptions.configurationPath = m_txtConfigurationPath->text(); ocioOptions.lutPath = m_txtLut->text(); ocioOptions.inputColorSpace = m_cmbInputColorSpace->itemHighlighted(); ocioOptions.displayDevice = m_cmbDisplayDevice->itemHighlighted(); ocioOptions.displayView = m_cmbView->itemHighlighted(); ocioOptions.look = m_cmbLook->itemHighlighted(); KisConfig cfg(false); cfg.setUseOcio(m_chkUseOcio->isChecked()); cfg.setOcioConfiguration(ocioOptions); 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); writeControls(); resetOcioConfiguration(); } } void LutDockerDock::resetOcioConfiguration() { KisConfig cfg(true); KisOcioConfiguration ocioOptions = cfg.ocioConfiguration(); m_ocioConfig.reset(); try { if (ocioOptions.mode == KisOcioConfiguration::INTERNAL) { m_ocioConfig = defaultRawProfile(); } else if (ocioOptions.mode == KisOcioConfiguration::OCIO_ENVIRONMENT) { m_ocioConfig = OCIO::Config::CreateFromEnv(); } else if (ocioOptions.mode == KisOcioConfiguration::OCIO_CONFIG) { QString configFile = ocioOptions.configurationPath; 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()->canvasResourceProvider()) return; if (!m_canvas->viewManager()->image()) return; KIS_ASSERT_RECOVER_RETURN(m_ocioConfig); KisConfig cfg(true); KisOcioConfiguration ocioOptions = cfg.ocioConfiguration(); { // Color Management Mode KisSignalsBlocker modeBlocker(m_colorManagement); m_colorManagement->setCurrentIndex((int) ocioOptions.mode); } { // Exposure KisSignalsBlocker exposureBlocker(m_exposureDoubleWidget); m_exposureDoubleWidget->setValue(m_canvas->viewManager()->canvasResourceProvider()->HDRExposure()); } { // Gamma KisSignalsBlocker gammaBlocker(m_gammaDoubleWidget); m_gammaDoubleWidget->setValue(m_canvas->viewManager()->canvasResourceProvider()->HDRGamma()); } { // Components const KoColorSpace *cs = m_canvas->viewManager()->image()->colorSpace(); QStringList itemsList; itemsList << i18n("Luminance"); itemsList << i18n("All Channels"); Q_FOREACH (KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(cs->channels())) { itemsList << channel->name(); } if (m_cmbComponents->originalTexts() != itemsList) { KisSignalsBlocker componentsBlocker(m_cmbComponents); m_cmbComponents->resetOriginalTexts(itemsList); m_cmbComponents->setCurrentIndex(1); // All Channels... } } { // Input Color Space QStringList itemsList; 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); itemsList << QString::fromUtf8(colorSpace->getName()); } KisSignalsBlocker inputCSBlocker(m_cmbInputColorSpace); if (itemsList != m_cmbInputColorSpace->originalTexts()) { m_cmbInputColorSpace->resetOriginalTexts(itemsList); } m_cmbInputColorSpace->setCurrent(ocioOptions.inputColorSpace); } { // Display Device QStringList itemsList; int numDisplays = m_ocioConfig->getNumDisplays(); for (int i = 0; i < numDisplays; ++i) { itemsList << QString::fromUtf8(m_ocioConfig->getDisplay(i)); } KisSignalsBlocker displayDeviceLocker(m_cmbDisplayDevice); if (itemsList != m_cmbDisplayDevice->originalTexts()) { m_cmbDisplayDevice->resetOriginalTexts(itemsList); } m_cmbDisplayDevice->setCurrent(ocioOptions.displayDevice); } { // Lock Current Color KisSignalsBlocker locker(m_btnConvertCurrentColor); m_btnConvertCurrentColor->setChecked(cfg.ocioLockColorVisualRepresentation()); } refillViewCombobox(); { QStringList itemsList; int numLooks = m_ocioConfig->getNumLooks(); for (int k = 0; k < numLooks; k++) { itemsList << QString::fromUtf8(m_ocioConfig->getLookNameByIndex(k)); } itemsList << i18nc("Item to indicate no look transform being selected","None"); KisSignalsBlocker LookComboLocker(m_cmbLook); if (itemsList != m_cmbLook->originalTexts()) { m_cmbLook->resetOriginalTexts(itemsList); } m_cmbLook->setCurrent(ocioOptions.look); } 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))); } KisConfig cfg(true); KisOcioConfiguration ocioOptions = cfg.ocioConfiguration(); m_cmbView->setCurrent(ocioOptions.displayView); } 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); writeControls(); updateDisplaySettings(); } } void LutDockerDock::clearLut() { m_txtLut->clear(); updateDisplaySettings(); } diff --git a/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.cpp b/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.cpp index 3a5238df11..ad19466b6e 100644 --- a/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.cpp +++ b/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.cpp @@ -1,158 +1,158 @@ /* * Copyright (c) 2019 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 "KisClickableGLImageWidget.h" #include #include #include "kis_algebra_2d.h" #include KisClickableGLImageWidget::KisClickableGLImageWidget(QWidget *parent) : KisGLImageWidget(parent) { } -KisClickableGLImageWidget::KisClickableGLImageWidget(QSurfaceFormat::ColorSpace colorSpace, QWidget *parent) +KisClickableGLImageWidget::KisClickableGLImageWidget(KisSurfaceColorSpace colorSpace, QWidget *parent) : KisGLImageWidget(colorSpace, parent) { } KisClickableGLImageWidget::~KisClickableGLImageWidget() { } void KisClickableGLImageWidget::setHandlePaintingStrategy(HandlePaintingStrategy *strategy) { m_handleStrategy.reset(strategy); } void KisClickableGLImageWidget::setUseHandleOpacity(bool value) { m_useHandleOpacity = value; update(); } QPointF KisClickableGLImageWidget::normalizedPos() const { return m_normalizedClickPoint; } void KisClickableGLImageWidget::setNormalizedPos(const QPointF &pos, bool update) { m_normalizedClickPoint = KisAlgebra2D::clampPoint(pos, QRectF(0,0,1.0,1.0)); if (update) { this->update(); } } void KisClickableGLImageWidget::paintEvent(QPaintEvent *event) { KisGLImageWidget::paintEvent(event); if (m_handleStrategy) { QPainter p(this); m_handleStrategy->drawHandle(&p, m_normalizedClickPoint, rect(), m_useHandleOpacity); } } void KisClickableGLImageWidget::mousePressEvent(QMouseEvent *event) { KisGLImageWidget::mousePressEvent(event); if (!event->isAccepted()) { event->accept(); m_normalizedClickPoint = normalizePoint(event->localPos()); emit selected(m_normalizedClickPoint); if (m_handleStrategy) { update(); } } } void KisClickableGLImageWidget::mouseReleaseEvent(QMouseEvent *event) { KisGLImageWidget::mouseReleaseEvent(event); if (!event->isAccepted()) { event->accept(); m_normalizedClickPoint = normalizePoint(event->localPos()); emit selected(m_normalizedClickPoint); if (m_handleStrategy) { update(); } } } void KisClickableGLImageWidget::mouseMoveEvent(QMouseEvent *event) { KisGLImageWidget::mouseMoveEvent(event); if (!event->isAccepted()) { event->accept(); m_normalizedClickPoint = normalizePoint(event->localPos()); emit selected(m_normalizedClickPoint); if (m_handleStrategy) { update(); } } } QPointF KisClickableGLImageWidget::normalizePoint(const QPointF &pos) const { const QPointF croppedPoint = KisAlgebra2D::clampPoint(pos, rect()); return QPointF(croppedPoint.x() / width(), croppedPoint.y() / height()); } namespace { QPen outerHandlePen(bool useOpacity) { // opacity works inexpectedly in HDR mode, so let the user switch it off return QPen(QColor(0, 0, 0, useOpacity ? 180 : 255), 0); } QPen innerHandlePen(bool useOpacity) { // opacity works inexpectedly in HDR mode, so let the user switch it off return QPen(QColor(255, 255, 255, useOpacity ? 180 : 255), 0); } } void KisClickableGLImageWidget::VerticalLineHandleStrategy::drawHandle(QPainter *p, const QPointF &normalizedPoint, const QRect &rect, bool useOpacity) { const QPointF pos = KisAlgebra2D::relativeToAbsolute(normalizedPoint, rect); const int x = std::floor(pos.x()); p->setPen(outerHandlePen(useOpacity)); p->drawLine(x, rect.top(), x, rect.bottom()); p->setPen(innerHandlePen(useOpacity)); p->drawLine(x + 1, rect.top(), x + 1, rect.bottom()); } void KisClickableGLImageWidget::CircularHandleStrategy::drawHandle(QPainter *p, const QPointF &normalizedPoint, const QRect &rect, bool useOpacity) { const QPointF pos = KisAlgebra2D::relativeToAbsolute(normalizedPoint, rect); p->setRenderHint(QPainter::Antialiasing); p->setPen(outerHandlePen(useOpacity)); p->drawEllipse(pos, 5, 5); p->setPen(innerHandlePen(useOpacity)); p->drawEllipse(pos, 4, 4); } diff --git a/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.h b/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.h index 3fcb621955..95facdc498 100644 --- a/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.h +++ b/plugins/dockers/smallcolorselector/KisClickableGLImageWidget.h @@ -1,73 +1,73 @@ /* * Copyright (c) 2019 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 KISCLICKABLEGLIMAGEWIDGET_H #define KISCLICKABLEGLIMAGEWIDGET_H #include #include class KisClickableGLImageWidget : public KisGLImageWidget { Q_OBJECT public: struct HandlePaintingStrategy { virtual void drawHandle(QPainter *p, const QPointF &normalizedPoint, const QRect &rect, bool useOpacity) = 0; virtual ~HandlePaintingStrategy() {} }; struct VerticalLineHandleStrategy : public HandlePaintingStrategy { void drawHandle(QPainter *p, const QPointF &normalizedPoint, const QRect &rect, bool useOpacity) override; }; struct CircularHandleStrategy : public HandlePaintingStrategy { void drawHandle(QPainter *p, const QPointF &normalizedPoint, const QRect &rect, bool useOpacity) override; }; public: KisClickableGLImageWidget(QWidget *parent = nullptr); - KisClickableGLImageWidget(QSurfaceFormat::ColorSpace colorSpace, + KisClickableGLImageWidget(KisSurfaceColorSpace colorSpace, QWidget *parent = nullptr); ~KisClickableGLImageWidget(); void setHandlePaintingStrategy(HandlePaintingStrategy *strategy); void setUseHandleOpacity(bool value); QPointF normalizedPos() const; void setNormalizedPos(const QPointF &pos, bool update = true); void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; Q_SIGNALS: void selected(const QPointF &normalizedPos); private: QPointF normalizePoint(const QPointF &pos) const; private: QPointF m_normalizedClickPoint; QScopedPointer m_handleStrategy; bool m_useHandleOpacity = true; }; #endif // KISCLICKABLEGLIMAGEWIDGET_H diff --git a/plugins/dockers/smallcolorselector/KisGLImageWidget.cpp b/plugins/dockers/smallcolorselector/KisGLImageWidget.cpp index 9706e40157..22c9ff95ab 100644 --- a/plugins/dockers/smallcolorselector/KisGLImageWidget.cpp +++ b/plugins/dockers/smallcolorselector/KisGLImageWidget.cpp @@ -1,281 +1,281 @@ /* * Copyright (c) 2019 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 "KisGLImageWidget.h" #include #include #include #include "kis_debug.h" #include #include #include "KisGLImageF16.h" namespace { inline void rectToVertices(QVector3D* vertices, const QRectF &rc) { vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f); vertices[1] = QVector3D(rc.left(), rc.top(), 0.f); vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f); vertices[3] = QVector3D(rc.left(), rc.top(), 0.f); vertices[4] = QVector3D(rc.right(), rc.top(), 0.f); vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f); } inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc) { texCoords[0] = QVector2D(rc.left(), rc.bottom()); texCoords[1] = QVector2D(rc.left(), rc.top()); texCoords[2] = QVector2D(rc.right(), rc.bottom()); texCoords[3] = QVector2D(rc.left(), rc.top()); texCoords[4] = QVector2D(rc.right(), rc.top()); texCoords[5] = QVector2D(rc.right(), rc.bottom()); } } KisGLImageWidget::KisGLImageWidget(QWidget *parent) - : KisGLImageWidget(QSurfaceFormat::sRGBColorSpace, parent) + : KisGLImageWidget(KisSurfaceColorSpace::sRGBColorSpace, parent) { } -KisGLImageWidget::KisGLImageWidget(QSurfaceFormat::ColorSpace colorSpace, +KisGLImageWidget::KisGLImageWidget(KisSurfaceColorSpace colorSpace, QWidget *parent) : QOpenGLWidget(parent), m_texture(QOpenGLTexture::Target2D) { setTextureFormat(GL_RGBA16F); #ifdef HAVE_HDR setTextureColorSpace(colorSpace); #endif setUpdateBehavior(QOpenGLWidget::NoPartialUpdate); } KisGLImageWidget::~KisGLImageWidget() { // force releasing the reourses on destruction slotOpenGLContextDestroyed(); } void KisGLImageWidget::initializeGL() { initializeOpenGLFunctions(); connect(context(), SIGNAL(aboutToBeDestroyed()), SLOT(slotOpenGLContextDestroyed())); m_shader.reset(new QOpenGLShaderProgram); QFile vertexShaderFile(QString(":/") + "kis_gl_image_widget.vert"); vertexShaderFile.open(QIODevice::ReadOnly); QString vertSource = vertexShaderFile.readAll(); QFile fragShaderFile(QString(":/") + "kis_gl_image_widget.frag"); fragShaderFile.open(QIODevice::ReadOnly); QString fragSource = fragShaderFile.readAll(); if (context()->isOpenGLES()) { const char *versionHelper = "#define USE_OPENGLES\n"; vertSource.prepend(versionHelper); fragSource.prepend(versionHelper); const char *versionDefinition = "#version 100\n"; vertSource.prepend(versionDefinition); fragSource.prepend(versionDefinition); } else { const char *versionDefinition = KisOpenGL::supportsLoD() ? "#version 130\n" : "#version 120\n"; vertSource.prepend(versionDefinition); fragSource.prepend(versionDefinition); } if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertSource)) { qDebug() << "Could not add vertex code"; return; } if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) { qDebug() << "Could not add fragment code"; return; } if (!m_shader->link()) { qDebug() << "Could not link"; return; } if (!m_shader->bind()) { qDebug() << "Could not bind"; return; } m_shader->release(); m_vao.create(); m_vao.bind(); m_verticesBuffer.create(); updateVerticesBuffer(this->rect()); QVector textureVertices(6); rectToTexCoords(textureVertices.data(), QRect(0.0, 0.0, 1.0, 1.0)); m_textureVerticesBuffer.create(); m_textureVerticesBuffer.bind(); m_textureVerticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); m_textureVerticesBuffer.allocate(2 * 3 * sizeof(QVector2D)); m_verticesBuffer.write(0, textureVertices.data(), m_textureVerticesBuffer.size()); m_textureVerticesBuffer.release(); m_vao.release(); if (!m_sourceImage.isNull()) { loadImage(m_sourceImage); } } void KisGLImageWidget::slotOpenGLContextDestroyed() { this->makeCurrent(); m_shader.reset(); m_texture.destroy(); m_verticesBuffer.destroy(); m_textureVerticesBuffer.destroy(); m_vao.destroy(); m_havePendingTextureUpdate = false; this->doneCurrent(); } void KisGLImageWidget::updateVerticesBuffer(const QRect &rect) { if (!m_vao.isCreated() || !m_verticesBuffer.isCreated()) return; QVector vertices(6); rectToVertices(vertices.data(), rect); m_verticesBuffer.bind(); m_verticesBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); m_verticesBuffer.allocate(2 * 3 * sizeof(QVector3D)); m_verticesBuffer.write(0, vertices.data(), m_verticesBuffer.size()); m_verticesBuffer.release(); } void KisGLImageWidget::paintGL() { const QColor bgColor = palette().background().color(); // TODO: fix conversion to the destination surface space //glClearColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF(), 1.0f); glClearColor(0.3, 0.2, 0.8, 1.0f); glClear(GL_COLOR_BUFFER_BIT); if (m_havePendingTextureUpdate) { m_havePendingTextureUpdate = false; if (!m_texture.isCreated() || m_sourceImage.width() != m_texture.width() || m_sourceImage.height() != m_texture.height()) { if (m_texture.isCreated()) { m_texture.destroy(); } m_texture.setFormat(QOpenGLTexture::RGBA16F); m_texture.setSize(m_sourceImage.width(), m_sourceImage.height()); m_texture.allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::Float16); m_texture.setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); m_texture.setMagnificationFilter(QOpenGLTexture::Linear); m_texture.setWrapMode(QOpenGLTexture::ClampToEdge); } m_texture.setData(QOpenGLTexture::RGBA, QOpenGLTexture::Float16, m_sourceImage.constData()); } if (!m_texture.isCreated()) return; m_vao.bind(); m_shader->bind(); { QMatrix4x4 projectionMatrix; projectionMatrix.setToIdentity(); projectionMatrix.ortho(0, width(), height(), 0, -1, 1); QMatrix4x4 viewProjectionMatrix; // use a QTransform to scale, translate, rotate your view QTransform transform; // TODO: noop! viewProjectionMatrix = projectionMatrix * QMatrix4x4(transform); m_shader->setUniformValue("viewProjectionMatrix", viewProjectionMatrix); } m_shader->enableAttributeArray("vertexPosition"); m_verticesBuffer.bind(); m_shader->setAttributeBuffer("vertexPosition", GL_FLOAT, 0, 3); m_shader->enableAttributeArray("texturePosition"); m_textureVerticesBuffer.bind(); m_shader->setAttributeBuffer("texturePosition", GL_FLOAT, 0, 2); glActiveTexture(GL_TEXTURE0); m_texture.bind(); // draw 2 triangles = 6 vertices starting at offset 0 in the buffer glDrawArrays(GL_TRIANGLES, 0, 6); m_verticesBuffer.release(); m_textureVerticesBuffer.release(); m_texture.release(); m_shader->release(); m_vao.release(); } void KisGLImageWidget::loadImage(const KisGLImageF16 &image) { if (m_sourceImage != image) { m_sourceImage = image; } m_havePendingTextureUpdate = true; updateGeometry(); update(); } void KisGLImageWidget::paintEvent(QPaintEvent *event) { QOpenGLWidget::paintEvent(event); } void KisGLImageWidget::resizeEvent(QResizeEvent *event) { updateVerticesBuffer(QRect(QPoint(),event->size())); QOpenGLWidget::resizeEvent(event); } QSize KisGLImageWidget::sizeHint() const { return m_sourceImage.size(); } diff --git a/plugins/dockers/smallcolorselector/KisGLImageWidget.h b/plugins/dockers/smallcolorselector/KisGLImageWidget.h index 391642aa88..0e495c33ae 100644 --- a/plugins/dockers/smallcolorselector/KisGLImageWidget.h +++ b/plugins/dockers/smallcolorselector/KisGLImageWidget.h @@ -1,72 +1,73 @@ /* * Copyright (c) 2019 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 KISGLIMAGEWIDGET_H #define KISGLIMAGEWIDGET_H #include #include #include #include #include #include #include #include +#include class KisGLImageWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: KisGLImageWidget(QWidget *parent = nullptr); - KisGLImageWidget(QSurfaceFormat::ColorSpace colorSpace, + KisGLImageWidget(KisSurfaceColorSpace colorSpace, QWidget *parent = nullptr); ~KisGLImageWidget(); void initializeGL(); void paintGL(); void loadImage(const KisGLImageF16 &image); void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; QSize sizeHint() const; public Q_SLOTS: private Q_SLOTS: void slotOpenGLContextDestroyed(); private: void updateVerticesBuffer(const QRect &rect); private: KisGLImageF16 m_sourceImage; QScopedPointer m_shader; QOpenGLVertexArrayObject m_vao; QOpenGLBuffer m_verticesBuffer; QOpenGLBuffer m_textureVerticesBuffer; QOpenGLTexture m_texture; bool m_havePendingTextureUpdate = false; }; #endif // KISGLIMAGEWIDGET_H diff --git a/plugins/dockers/smallcolorselector/kis_small_color_widget.cc b/plugins/dockers/smallcolorselector/kis_small_color_widget.cc index 5c9bf3cce1..0f9d586bea 100644 --- a/plugins/dockers/smallcolorselector/kis_small_color_widget.cc +++ b/plugins/dockers/smallcolorselector/kis_small_color_widget.cc @@ -1,516 +1,516 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_small_color_widget.h" #include #include "kis_slider_spin_box.h" #include #include "kis_signal_compressor.h" #include #include #include #include "kis_debug.h" #include "kis_assert.h" #include #include "KisGLImageF16.h" #include "KisGLImageWidget.h" #include "KisClickableGLImageWidget.h" #include "kis_display_color_converter.h" #include "kis_signal_auto_connection.h" #include "kis_signal_compressor_with_param.h" #include #include #include "kis_fixed_paint_device.h" #include struct KisSmallColorWidget::Private { qreal hue; // 0 ... 1.0 qreal value; // 0 ... 1.0 qreal saturation; // 0 ... 1.0 bool updateAllowed; KisClickableGLImageWidget *hueWidget; KisClickableGLImageWidget *valueWidget; KisSignalCompressor *repaintCompressor; KisSignalCompressor *resizeUpdateCompressor; KisSignalCompressor *valueSliderUpdateCompressor; KisSignalCompressor *colorChangedSignalCompressor; KisSignalCompressorWithParam *dynamicRangeCompressor; int huePreferredHeight = 32; KisSliderSpinBox *dynamicRange = 0; qreal currentRelativeDynamicRange = 1.0; KisDisplayColorConverter *displayColorConverter = KisDisplayColorConverter::dumbConverterInstance(); KisSignalAutoConnectionsStore colorConverterConnections; bool hasHDR = false; bool hasHardwareHDR = false; qreal effectiveRelativeDynamicRange() const { return hasHDR ? currentRelativeDynamicRange : 1.0; } const KoColorSpace *outputColorSpace() { return KoColorSpaceRegistry::instance()-> colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), displayColorConverter->openGLCanvasSurfaceProfile()); } const KoColorSpace *generationColorSpace() { const KoColorSpace *result = displayColorConverter->paintingColorSpace(); if (!result || result->colorModelId() != RGBAColorModelID) { result = outputColorSpace(); } else if (result->colorDepthId() != Float32BitsColorDepthID) { result = KoColorSpaceRegistry::instance()-> colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), result->profile()); } // PQ color space we deliniearize into linear one if (result->colorModelId() == RGBAColorModelID && result->profile()->uniqueId() == KoColorSpaceRegistry::instance()->p2020PQProfile()->uniqueId()) { result = KoColorSpaceRegistry::instance()-> colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), KoColorSpaceRegistry::instance()->p2020G10Profile()); } return result; } }; KisSmallColorWidget::KisSmallColorWidget(QWidget* parent) : QWidget(parent), d(new Private) { d->hue = 0.0; d->value = 0; d->saturation = 0; d->updateAllowed = true; d->repaintCompressor = new KisSignalCompressor(20, KisSignalCompressor::FIRST_ACTIVE, this); connect(d->repaintCompressor, SIGNAL(timeout()), SLOT(update())); d->resizeUpdateCompressor = new KisSignalCompressor(200, KisSignalCompressor::FIRST_ACTIVE, this); connect(d->resizeUpdateCompressor, SIGNAL(timeout()), SLOT(slotUpdatePalettes())); d->valueSliderUpdateCompressor = new KisSignalCompressor(100, KisSignalCompressor::FIRST_ACTIVE, this); connect(d->valueSliderUpdateCompressor, SIGNAL(timeout()), SLOT(updateSVPalette())); d->colorChangedSignalCompressor = new KisSignalCompressor(20, KisSignalCompressor::FIRST_ACTIVE, this); connect(d->colorChangedSignalCompressor, SIGNAL(timeout()), SLOT(slotTellColorChanged())); { using namespace std::placeholders; std::function callback( std::bind(&KisSmallColorWidget::updateDynamicRange, this, _1)); d->dynamicRangeCompressor = new KisSignalCompressorWithParam(50, callback); } - const QSurfaceFormat::ColorSpace colorSpace = QSurfaceFormat::DefaultColorSpace; + const KisSurfaceColorSpace colorSpace = KisSurfaceColorSpace::DefaultColorSpace; d->hueWidget = new KisClickableGLImageWidget(colorSpace, this); d->hueWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->hueWidget->setHandlePaintingStrategy(new KisClickableGLImageWidget::VerticalLineHandleStrategy); connect(d->hueWidget, SIGNAL(selected(const QPointF&)), SLOT(slotHueSliderChanged(const QPointF&))); d->valueWidget = new KisClickableGLImageWidget(colorSpace, this); d->valueWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); d->valueWidget->setHandlePaintingStrategy(new KisClickableGLImageWidget::CircularHandleStrategy); connect(d->valueWidget, SIGNAL(selected(const QPointF&)), SLOT(slotValueSliderChanged(const QPointF&))); d->hasHardwareHDR = KisOpenGLModeProber::instance()->useHDRMode(); if (d->hasHardwareHDR) { d->dynamicRange = new KisSliderSpinBox(this); d->dynamicRange->setRange(80, 10000); d->dynamicRange->setExponentRatio(3.0); d->dynamicRange->setSingleStep(1); d->dynamicRange->setPageStep(100); d->dynamicRange->setSuffix("cd/m²"); d->dynamicRange->setValue(80.0 * d->currentRelativeDynamicRange); connect(d->dynamicRange, SIGNAL(valueChanged(int)), SLOT(slotInitiateUpdateDynamicRange(int))); } QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(d->hueWidget, 0); layout->addWidget(d->valueWidget, 1); if (d->dynamicRange) { layout->addSpacing(16); layout->addWidget(d->dynamicRange, 0); } setLayout(layout); slotUpdatePalettes(); } KisSmallColorWidget::~KisSmallColorWidget() { delete d; } void KisSmallColorWidget::setHue(qreal h) { h = qBound(0.0, h, 1.0); d->hue = h; d->colorChangedSignalCompressor->start(); d->valueSliderUpdateCompressor->start(); d->repaintCompressor->start(); } void KisSmallColorWidget::setHSV(qreal h, qreal s, qreal v, bool notifyChanged) { h = qBound(0.0, h, 1.0); s = qBound(0.0, s, 1.0); v = qBound(0.0, v, 1.0); bool newH = !qFuzzyCompare(d->hue, h); d->hue = h; d->value = v; d->saturation = s; // TODO: remove and make acyclic! if (notifyChanged) { d->colorChangedSignalCompressor->start(); } if(newH) { d->valueSliderUpdateCompressor->start(); } d->repaintCompressor->start(); } void KisSmallColorWidget::setColor(const KoColor &color) { if (!d->updateAllowed) return; KIS_SAFE_ASSERT_RECOVER(!d->dynamicRange || d->hasHDR == d->dynamicRange->isEnabled()) { slotDisplayConfigurationChanged(); } KIS_SAFE_ASSERT_RECOVER_RETURN(!d->hasHDR || d->hasHardwareHDR); const KoColorSpace *cs = d->generationColorSpace(); KIS_SAFE_ASSERT_RECOVER_RETURN(cs); KoColor newColor(color); newColor.convertTo(cs); QVector channels(4); cs->normalisedChannelsValue(newColor.data(), channels); float r, g, b; if (cs->colorDepthId() == Integer8BitsColorDepthID) { r = channels[2]; g = channels[1]; b = channels[0]; } else { r = channels[0]; g = channels[1]; b = channels[2]; } if (d->hasHDR) { qreal rangeCoeff = d->effectiveRelativeDynamicRange(); if (rangeCoeff < r || rangeCoeff < g || rangeCoeff < b) { rangeCoeff = std::max({r, g, b}) * 1.10f; const int newMaxLuminance = qRound(80.0 * rangeCoeff); updateDynamicRange(newMaxLuminance); d->dynamicRange->setValue(newMaxLuminance); } r /= rangeCoeff; g /= rangeCoeff; b /= rangeCoeff; } else { r = qBound(0.0f, r, 1.0f); g = qBound(0.0f, g, 1.0f); b = qBound(0.0f, b, 1.0f); } float denormHue, saturation, value; RGBToHSV(r, g, b, &denormHue, &saturation, &value); d->hueWidget->setNormalizedPos(QPointF(denormHue / 360.0, 0.0)); d->valueWidget->setNormalizedPos(QPointF(saturation, 1.0 - value)); setHSV(denormHue / 360.0, saturation, value, false); } void KisSmallColorWidget::slotUpdatePalettes() { updateHuePalette(); updateSVPalette(); } namespace { struct FillHPolicy { static inline void getRGB(qreal hue, float xPortionCoeff, float yPortionCoeff, int x, int y, float *r, float *g, float *b) { HSVToRGB(xPortionCoeff * x * 360.0f, 1.0, 1.0, r, g, b); } }; struct FillSVPolicy { static inline void getRGB(qreal hue, float xPortionCoeff, float yPortionCoeff, int x, int y, float *r, float *g, float *b) { HSVToRGB(hue * 360.0, xPortionCoeff * x, 1.0 - yPortionCoeff * y, r, g, b); } }; } template void KisSmallColorWidget::uploadPaletteData(KisGLImageWidget *widget, const QSize &size) { if (size.isEmpty()) return; KisGLImageF16 image(size); const float xPortionCoeff = 1.0 / image.width(); const float yPortionCoeff = 1.0 / image.height(); const float rangeCoeff = d->effectiveRelativeDynamicRange(); const KoColorSpace *generationColorSpace = d->generationColorSpace(); if (d->displayColorConverter->canSkipDisplayConversion(generationColorSpace)) { half *pixelPtr = image.data(); for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { Imf::Rgba &pxl = reinterpret_cast(*pixelPtr); float r, g, b; FillPolicy::getRGB(d->hue, xPortionCoeff, yPortionCoeff, x, y, &r, &g, &b); pxl.r = r * rangeCoeff; pxl.g = g * rangeCoeff; pxl.b = b * rangeCoeff; pxl.a = 1.0; pixelPtr += 4; } } } else { KIS_SAFE_ASSERT_RECOVER_RETURN(d->displayColorConverter); KisFixedPaintDeviceSP device = new KisFixedPaintDevice(generationColorSpace); device->setRect(QRect(QPoint(), image.size())); device->reallocateBufferWithoutInitialization(); float *devicePtr = reinterpret_cast(device->data()); for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { FillPolicy::getRGB(d->hue, xPortionCoeff, yPortionCoeff, x, y, devicePtr, devicePtr + 1, devicePtr + 2); devicePtr[0] *= rangeCoeff; devicePtr[1] *= rangeCoeff; devicePtr[2] *= rangeCoeff; devicePtr[3] = 1.0; devicePtr += 4; } } d->displayColorConverter->applyDisplayFilteringF32(device, Float32BitsColorDepthID); half *imagePtr = image.data(); devicePtr = reinterpret_cast(device->data()); for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { imagePtr[0] = devicePtr[0]; imagePtr[1] = devicePtr[1]; imagePtr[2] = devicePtr[2]; imagePtr[3] = devicePtr[3]; devicePtr += 4; imagePtr += 4; } } } widget->loadImage(image); } void KisSmallColorWidget::updateHuePalette() { uploadPaletteData(d->hueWidget, QSize(d->hueWidget->width(), d->huePreferredHeight)); } void KisSmallColorWidget::updateSVPalette() { const int maxSize = 256; QSize newSize = d->valueWidget->size(); newSize.rwidth() = qMin(maxSize, newSize.width()); newSize.rheight() = qMin(maxSize, newSize.height()); uploadPaletteData(d->valueWidget, newSize); } void KisSmallColorWidget::slotHueSliderChanged(const QPointF &pos) { const qreal newHue = pos.x(); if (!qFuzzyCompare(newHue, d->hue)) { setHue(newHue); } } void KisSmallColorWidget::slotValueSliderChanged(const QPointF &pos) { const qreal newSaturation = pos.x(); const qreal newValue = 1.0 - pos.y(); if (!qFuzzyCompare(newSaturation, d->saturation) || !qFuzzyCompare(newValue, d->value)) { setHSV(d->hue, newSaturation, newValue); } } void KisSmallColorWidget::slotInitiateUpdateDynamicRange(int maxLuminance) { d->dynamicRangeCompressor->start(maxLuminance); } void KisSmallColorWidget::updateDynamicRange(int maxLuminance) { const qreal oldRange = d->currentRelativeDynamicRange; const qreal newRange = qreal(maxLuminance) / 80.0; if (qFuzzyCompare(oldRange, newRange)) return; float r, g, b; float denormHue = d->hue * 360.0; float saturation = d->saturation; float value = d->value; HSVToRGB(denormHue, saturation, value, &r, &g, &b); const qreal transformCoeff = oldRange / newRange; r = qBound(0.0, r * transformCoeff, 1.0); g = qBound(0.0, g * transformCoeff, 1.0); b = qBound(0.0, b * transformCoeff, 1.0); RGBToHSV(r, g, b, &denormHue, &saturation, &value); d->currentRelativeDynamicRange = newRange; slotUpdatePalettes(); setHSV(denormHue / 360.0, saturation, value, false); d->hueWidget->setNormalizedPos(QPointF(denormHue / 360.0, 0)); d->valueWidget->setNormalizedPos(QPointF(saturation, 1.0 - value)); } void KisSmallColorWidget::setDisplayColorConverter(KisDisplayColorConverter *converter) { d->colorConverterConnections.clear(); if (!converter) { converter = KisDisplayColorConverter::dumbConverterInstance(); } d->displayColorConverter = converter; if (d->displayColorConverter) { d->colorConverterConnections.addConnection( d->displayColorConverter, SIGNAL(displayConfigurationChanged()), this, SLOT(slotDisplayConfigurationChanged())); } slotDisplayConfigurationChanged(); } void KisSmallColorWidget::slotDisplayConfigurationChanged() { d->hasHDR = false; if (d->hasHardwareHDR) { const KoColorSpace *cs = d->displayColorConverter->paintingColorSpace(); d->hasHDR = cs->colorModelId() == RGBAColorModelID && (cs->colorDepthId() == Float16BitsColorDepthID || cs->colorDepthId() == Float32BitsColorDepthID || cs->colorDepthId() == Float64BitsColorDepthID || cs->profile()->uniqueId() == KoColorSpaceRegistry::instance()->p2020PQProfile()->uniqueId()); } if (d->dynamicRange) { d->dynamicRange->setEnabled(d->hasHDR); } d->hueWidget->setUseHandleOpacity(!d->hasHDR); d->valueWidget->setUseHandleOpacity(!d->hasHDR); slotUpdatePalettes(); // TODO: also set the currently selected color again } void KisSmallColorWidget::slotTellColorChanged() { d->updateAllowed = false; float r, g, b; HSVToRGB(d->hue * 360.0, d->saturation, d->value, &r, &g, &b); if (d->hasHDR) { const float rangeCoeff = d->effectiveRelativeDynamicRange(); r *= rangeCoeff; g *= rangeCoeff; b *= rangeCoeff; } const KoColorSpace *cs = d->generationColorSpace(); KIS_SAFE_ASSERT_RECOVER_RETURN(cs); QVector values(4); if (cs->colorDepthId() == Integer8BitsColorDepthID) { values[0] = b; values[1] = g; values[2] = r; values[3] = 1.0f; } else { values[0] = r; values[1] = g; values[2] = b; values[3] = 1.0f; } KoColor c(cs); cs->fromNormalisedChannelsValue(c.data(), values); emit colorChanged(c); d->updateAllowed = true; } void KisSmallColorWidget::resizeEvent(QResizeEvent * event) { QWidget::resizeEvent(event); update(); d->resizeUpdateCompressor->start(); }