diff --git a/cmake/modules/FindLibMyPaint.cmake b/cmake/modules/FindLibMyPaint.cmake
index e5f2a3a77f..cd2736dc4c 100644
--- a/cmake/modules/FindLibMyPaint.cmake
+++ b/cmake/modules/FindLibMyPaint.cmake
@@ -1,19 +1,27 @@
#For finding LibMyPaint library in the system
include(LibFindMacros)
libfind_pkg_check_modules(MYPAINT_PKGCONF libmypaint)
find_path(LIBMYPAINT_INCLUDE_DIR
- NAMES libmypaint/mypaint-brush.h
- HINTS ${MYPAINT_PKGCONF_INCLUDE_DIRS} ${MYPAINT_PKGCONF_INCLUDEDIR}
+ NAMES mypaint-config.h
+ /usr/include
+ /usr/local/include
+ /sw/include
+ /opt/local/include
+ ${MYPAINT_PKGCONF_INCLUDE_DIRS}
+ ${MYPAINT_PKGCONF_INCLUDEDIR}
PATH_SUFFIXES libmypaint
)
find_library(LIBMYPAINT_LIBRARY
NAMES libmypaint mypaint
HINTS ${MYPAINT_PKGCONF_LIBRARY_DIRS} ${MYPAINT_PKGCONF_LIBDIR}
DOC "Libraries to link against for mypaint brush engine Support"
)
+string(REGEX MATCH "(.*)/libmypaint.so" LIBMYPAINT_LIBRARIES ${LIBMYPAINT_LIBRARY})
+
+set(LIBMYPAINT_LIBRARIES ${CMAKE_MATCH_1})
set(LIBMYPAINT_FOUND ${MYPAINT_PKGCONF_FOUND})
set(LIBMYPAINT_VERSION ${MYPAINT_PKGCONF_VERSION})
diff --git a/krita/pics/paintops/mypaintbrush.png b/krita/pics/paintops/mypaintbrush.png
new file mode 100644
index 0000000000..af5f166d19
Binary files /dev/null and b/krita/pics/paintops/mypaintbrush.png differ
diff --git a/krita/pics/paintops/paintops-icons.qrc b/krita/pics/paintops/paintops-icons.qrc
index 535ed480f5..968c88f82b 100644
--- a/krita/pics/paintops/paintops-icons.qrc
+++ b/krita/pics/paintops/paintops-icons.qrc
@@ -1,37 +1,38 @@
dark_bristlebrush.svg
dark_clonebrush.svg
dark_colorsmudge.svg
dark_curvebrush.svg
dark_deformbrush.svg
dark_dynabrush.svg
dark_filterbrush.svg
dark_gridbrush.svg
dark_hatchingbrush.svg
dark_particlebrush.svg
dark_pixelbrush.svg
dark_quickbrush.svg
dark_shapebrush.svg
dark_sketchbrush.svg
dark_spraybrush.svg
dark_tangentnormal.svg
light_bristlebrush.svg
light_clonebrush.svg
light_colorsmudge.svg
light_curvebrush.svg
light_deformbrush.svg
light_dynabrush.svg
light_filterbrush.svg
light_gridbrush.svg
light_hatchingbrush.svg
light_particlebrush.svg
light_pixelbrush.svg
light_quickbrush.svg
light_shapebrush.svg
light_sketchbrush.svg
light_spraybrush.svg
light_tangentnormal.svg
+ mypaintbrush.png
diff --git a/libs/global/KisUsageLogger.cpp b/libs/global/KisUsageLogger.cpp
index 46ef05ce0d..d62ad5d71f 100644
--- a/libs/global/KisUsageLogger.cpp
+++ b/libs/global/KisUsageLogger.cpp
@@ -1,253 +1,253 @@
/*
* Copyright (c) 2019 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 "KisUsageLogger.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_GLOBAL_STATIC(KisUsageLogger, s_instance)
const QString KisUsageLogger::s_sectionHeader("================================================================================\n");
struct KisUsageLogger::Private {
bool active {false};
QFile logFile;
QFile sysInfoFile;
};
KisUsageLogger::KisUsageLogger()
: d(new Private)
{
d->logFile.setFileName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita.log");
d->sysInfoFile.setFileName(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/krita-sysinfo.log");
rotateLog();
d->logFile.open(QFile::Append | QFile::Text);
d->sysInfoFile.open(QFile::WriteOnly | QFile::Text);
}
KisUsageLogger::~KisUsageLogger()
{
if (d->active) {
close();
}
}
void KisUsageLogger::initialize()
{
s_instance->d->active = true;
QString systemInfo = basicSystemInfo();
s_instance->d->sysInfoFile.write(systemInfo.toUtf8());
}
QString KisUsageLogger::basicSystemInfo()
{
QString systemInfo;
// NOTE: This is intentionally not translated!
// Krita version info
systemInfo.append("Krita\n");
systemInfo.append("\n Version: ").append(KritaVersionWrapper::versionString(true));
systemInfo.append("\n Languages: ").append(KLocalizedString::languages().join(", "));
systemInfo.append("\n Hidpi: ").append(QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) ? "true" : "false");
systemInfo.append("\n\n");
systemInfo.append("Qt\n");
systemInfo.append("\n Version (compiled): ").append(QT_VERSION_STR);
systemInfo.append("\n Version (loaded): ").append(qVersion());
systemInfo.append("\n\n");
// OS information
systemInfo.append("OS Information\n");
systemInfo.append("\n Build ABI: ").append(QSysInfo::buildAbi());
systemInfo.append("\n Build CPU: ").append(QSysInfo::buildCpuArchitecture());
systemInfo.append("\n CPU: ").append(QSysInfo::currentCpuArchitecture());
systemInfo.append("\n Kernel Type: ").append(QSysInfo::kernelType());
systemInfo.append("\n Kernel Version: ").append(QSysInfo::kernelVersion());
systemInfo.append("\n Pretty Productname: ").append(QSysInfo::prettyProductName());
systemInfo.append("\n Product Type: ").append(QSysInfo::productType());
systemInfo.append("\n Product Version: ").append(QSysInfo::productVersion());
#ifdef Q_OS_LINUX
systemInfo.append("\n Desktop: ").append(qgetenv("XDG_CURRENT_DESKTOP"));
#endif
systemInfo.append("\n\n");
return systemInfo;
}
void KisUsageLogger::close()
{
log("CLOSING SESSION");
s_instance->d->active = false;
s_instance->d->logFile.flush();
s_instance->d->logFile.close();
s_instance->d->sysInfoFile.flush();
s_instance->d->sysInfoFile.close();
}
void KisUsageLogger::log(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->logFile.isOpen()) return;
s_instance->d->logFile.write(QDateTime::currentDateTime().toString(Qt::RFC2822Date).toUtf8());
s_instance->d->logFile.write(": ");
write(message);
}
void KisUsageLogger::write(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->logFile.isOpen()) return;
s_instance->d->logFile.write(message.toUtf8());
s_instance->d->logFile.write("\n");
s_instance->d->logFile.flush();
}
void KisUsageLogger::writeSysInfo(const QString &message)
{
if (!s_instance->d->active) return;
if (!s_instance->d->sysInfoFile.isOpen()) return;
s_instance->d->sysInfoFile.write(message.toUtf8());
s_instance->d->sysInfoFile.write("\n");
s_instance->d->sysInfoFile.flush();
}
void KisUsageLogger::writeHeader()
{
- Q_ASSERT(s_instance->d->sysInfoFile.isOpen());
+// Q_ASSERT(s_instance->d->sysInfoFile.isOpen());
s_instance->d->logFile.write(s_sectionHeader.toUtf8());
QString sessionHeader = QString("SESSION: %1. Executing %2\n\n")
.arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date))
.arg(qApp->arguments().join(' '));
s_instance->d->logFile.write(sessionHeader.toUtf8());
QString KritaAndQtVersion;
KritaAndQtVersion.append("Krita Version: ").append(KritaVersionWrapper::versionString(true))
.append(", Qt version compiled: ").append(QT_VERSION_STR)
.append(", loaded: ").append(qVersion())
.append(". Process ID: ")
.append(QString::number(qApp->applicationPid())).append("\n");
KritaAndQtVersion.append("-- -- -- -- -- -- -- --\n");
s_instance->d->logFile.write(KritaAndQtVersion.toUtf8());
s_instance->d->logFile.flush();
}
QString KisUsageLogger::screenInformation()
{
QList screens = qApp->screens();
QString info;
info.append("Display Information");
info.append("\nNumber of screens: ").append(QString::number(screens.size()));
for (int i = 0; i < screens.size(); ++i ) {
QScreen *screen = screens[i];
info.append("\n\tScreen: ").append(QString::number(i));
info.append("\n\t\tName: ").append(screen->name());
info.append("\n\t\tDepth: ").append(QString::number(screen->depth()));
info.append("\n\t\tScale: ").append(QString::number(screen->devicePixelRatio()));
info.append("\n\t\tResolution in pixels: ").append(QString::number(screen->geometry().width()))
.append("x")
.append(QString::number(screen->geometry().height()));
info.append("\n\t\tManufacturer: ").append(screen->manufacturer());
info.append("\n\t\tModel: ").append(screen->model());
info.append("\n\t\tRefresh Rate: ").append(QString::number(screen->refreshRate()));
}
info.append("\n");
return info;
}
void KisUsageLogger::rotateLog()
{
if (d->logFile.exists()) {
{
// Check for CLOSING SESSION
d->logFile.open(QFile::ReadOnly);
QString log = QString::fromUtf8(d->logFile.readAll());
if (!log.split(s_sectionHeader).last().contains("CLOSING SESSION")) {
log.append("\nKRITA DID NOT CLOSE CORRECTLY\n");
QString crashLog = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/kritacrash.log");
if (QFileInfo(crashLog).exists()) {
QFile f(crashLog);
f.open(QFile::ReadOnly);
QString crashes = QString::fromUtf8(f.readAll());
f.close();
QStringList crashlist = crashes.split("-------------------");
log.append(QString("\nThere were %1 crashes in total in the crash log.\n").arg(crashlist.size()));
if (crashes.size() > 0) {
log.append(crashlist.last());
}
}
d->logFile.close();
d->logFile.open(QFile::WriteOnly);
d->logFile.write(log.toUtf8());
}
d->logFile.flush();
d->logFile.close();
}
{
// Rotate
d->logFile.open(QFile::ReadOnly);
QString log = QString::fromUtf8(d->logFile.readAll());
int sectionCount = log.count(s_sectionHeader);
int nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
while(sectionCount >= s_maxLogs) {
log = log.remove(0, log.indexOf(s_sectionHeader, nextSectionIndex));
nextSectionIndex = log.indexOf(s_sectionHeader, s_sectionHeader.length());
sectionCount = log.count(s_sectionHeader);
}
d->logFile.close();
d->logFile.open(QFile::WriteOnly);
d->logFile.write(log.toUtf8());
d->logFile.flush();
d->logFile.close();
}
}
}
diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt
index 810dee2f16..510e1844a4 100644
--- a/libs/image/CMakeLists.txt
+++ b/libs/image/CMakeLists.txt
@@ -1,387 +1,396 @@
add_subdirectory( tests )
add_subdirectory( tiles3 )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty
${CMAKE_CURRENT_SOURCE_DIR}/brushengine
${CMAKE_CURRENT_SOURCE_DIR}/commands
${CMAKE_CURRENT_SOURCE_DIR}/commands_new
${CMAKE_CURRENT_SOURCE_DIR}/filter
${CMAKE_CURRENT_SOURCE_DIR}/floodfill
${CMAKE_CURRENT_SOURCE_DIR}/generator
${CMAKE_CURRENT_SOURCE_DIR}/layerstyles
${CMAKE_CURRENT_SOURCE_DIR}/processing
${CMAKE_SOURCE_DIR}/sdk/tests
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
)
if(FFTW3_FOUND)
include_directories(${FFTW3_INCLUDE_DIR})
endif()
+if(LIBMYPAINT_FOUND)
+ include_directories(${LIBMYPAINT_INCLUDE_DIR})
+ link_directories(${LIBMYPAINT_LIBRARIES})
+endif()
+
if(HAVE_VC)
include_directories(SYSTEM ${Vc_INCLUDE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})
ko_compile_for_all_implementations(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp)
else()
set(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp)
endif()
set(kritaimage_LIB_SRCS
tiles3/kis_tile.cc
tiles3/kis_tile_data.cc
tiles3/kis_tile_data_store.cc
tiles3/kis_tile_data_pooler.cc
tiles3/kis_tiled_data_manager.cc
tiles3/KisTiledExtentManager.cpp
tiles3/kis_memento_manager.cc
tiles3/kis_hline_iterator.cpp
tiles3/kis_vline_iterator.cpp
tiles3/kis_random_accessor.cc
tiles3/swap/kis_abstract_compression.cpp
tiles3/swap/kis_lzf_compression.cpp
tiles3/swap/kis_abstract_tile_compressor.cpp
tiles3/swap/kis_legacy_tile_compressor.cpp
tiles3/swap/kis_tile_compressor_2.cpp
tiles3/swap/kis_chunk_allocator.cpp
tiles3/swap/kis_memory_window.cpp
tiles3/swap/kis_swapped_data_store.cpp
tiles3/swap/kis_tile_data_swapper.cpp
kis_distance_information.cpp
kis_painter.cc
kis_painter_blt_multi_fixed.cpp
kis_marker_painter.cpp
KisPrecisePaintDeviceWrapper.cpp
kis_progress_updater.cpp
brushengine/kis_paint_information.cc
brushengine/kis_random_source.cpp
brushengine/KisPerStrokeRandomSource.cpp
brushengine/kis_stroke_random_source.cpp
brushengine/kis_paintop.cc
brushengine/kis_paintop_factory.cpp
brushengine/kis_paintop_preset.cpp
brushengine/kis_paintop_registry.cc
brushengine/kis_paintop_settings.cpp
brushengine/kis_paintop_settings_update_proxy.cpp
brushengine/kis_paintop_utils.cpp
brushengine/kis_no_size_paintop_settings.cpp
brushengine/kis_locked_properties.cc
brushengine/kis_locked_properties_proxy.cpp
brushengine/kis_locked_properties_server.cpp
brushengine/kis_paintop_config_widget.cpp
brushengine/kis_uniform_paintop_property.cpp
brushengine/kis_combo_based_paintop_property.cpp
brushengine/kis_slider_based_paintop_property.cpp
brushengine/kis_standard_uniform_properties_factory.cpp
brushengine/KisStrokeSpeedMeasurer.cpp
brushengine/KisPaintopSettingsIds.cpp
commands/kis_deselect_global_selection_command.cpp
commands/KisDeselectActiveSelectionCommand.cpp
commands/kis_image_change_layers_command.cpp
commands/kis_image_change_visibility_command.cpp
commands/kis_image_command.cpp
commands/kis_image_layer_add_command.cpp
commands/kis_image_layer_move_command.cpp
commands/kis_image_layer_remove_command.cpp
commands/kis_image_layer_remove_command_impl.cpp
commands/kis_image_lock_command.cpp
commands/kis_node_command.cpp
commands/kis_node_compositeop_command.cpp
commands/kis_node_opacity_command.cpp
commands/kis_node_property_list_command.cpp
commands/kis_reselect_global_selection_command.cpp
commands/KisReselectActiveSelectionCommand.cpp
commands/kis_set_global_selection_command.cpp
commands/KisNodeRenameCommand.cpp
commands_new/kis_saved_commands.cpp
commands_new/kis_processing_command.cpp
commands_new/kis_image_resize_command.cpp
commands_new/kis_image_set_resolution_command.cpp
commands_new/kis_node_move_command2.cpp
commands_new/kis_set_layer_style_command.cpp
commands_new/kis_selection_move_command2.cpp
commands_new/kis_update_command.cpp
commands_new/kis_switch_current_time_command.cpp
commands_new/kis_change_projection_color_command.cpp
commands_new/kis_activate_selection_mask_command.cpp
commands_new/kis_transaction_based_command.cpp
commands_new/KisHoldUIUpdatesCommand.cpp
commands_new/KisChangeChannelFlagsCommand.cpp
commands_new/KisChangeChannelLockFlagsCommand.cpp
commands_new/KisMergeLabeledLayersCommand.cpp
processing/kis_do_nothing_processing_visitor.cpp
processing/kis_simple_processing_visitor.cpp
processing/kis_convert_color_space_processing_visitor.cpp
processing/kis_assign_profile_processing_visitor.cpp
processing/kis_crop_processing_visitor.cpp
processing/kis_crop_selections_processing_visitor.cpp
processing/kis_transform_processing_visitor.cpp
processing/kis_mirror_processing_visitor.cpp
processing/KisSelectionBasedProcessingHelper.cpp
filter/kis_filter.cc
filter/kis_filter_category_ids.cpp
filter/kis_filter_configuration.cc
filter/kis_color_transformation_configuration.cc
filter/kis_filter_registry.cc
filter/kis_color_transformation_filter.cc
generator/kis_generator.cpp
generator/kis_generator_layer.cpp
generator/kis_generator_registry.cpp
floodfill/kis_fill_interval_map.cpp
floodfill/kis_scanline_fill.cpp
lazybrush/kis_min_cut_worker.cpp
lazybrush/kis_lazy_fill_tools.cpp
lazybrush/kis_multiway_cut.cpp
lazybrush/KisWatershedWorker.cpp
lazybrush/kis_colorize_mask.cpp
lazybrush/kis_colorize_stroke_strategy.cpp
KisDelayedUpdateNodeInterface.cpp
KisCroppedOriginalLayerInterface.cpp
KisDecoratedNodeInterface.cpp
kis_adjustment_layer.cc
kis_selection_based_layer.cpp
kis_node_filter_interface.cpp
kis_base_accessor.cpp
kis_base_node.cpp
kis_base_processor.cpp
kis_bookmarked_configuration_manager.cc
KisBusyWaitBroker.cpp
KisSafeBlockingQueueConnectionProxy.cpp
kis_node_uuid_info.cpp
kis_clone_layer.cpp
kis_config_widget.cpp
kis_convolution_kernel.cc
kis_convolution_painter.cc
kis_gaussian_kernel.cpp
kis_edge_detection_kernel.cpp
kis_cubic_curve.cpp
kis_default_bounds.cpp
kis_default_bounds_node_wrapper.cpp
kis_default_bounds_base.cpp
kis_effect_mask.cc
kis_fast_math.cpp
kis_fill_painter.cc
kis_filter_mask.cpp
kis_filter_strategy.cc
kis_transform_mask.cpp
kis_transform_mask_params_interface.cpp
kis_recalculate_transform_mask_job.cpp
kis_recalculate_generator_layer_job.cpp
kis_transform_mask_params_factory_registry.cpp
kis_safe_transform.cpp
kis_gradient_painter.cc
kis_gradient_shape_strategy.cpp
kis_cached_gradient_shape_strategy.cpp
kis_polygonal_gradient_shape_strategy.cpp
kis_iterator_ng.cpp
kis_async_merger.cpp
kis_merge_walker.cc
kis_updater_context.cpp
kis_update_job_item.cpp
kis_stroke_strategy_undo_command_based.cpp
kis_simple_stroke_strategy.cpp
KisRunnableBasedStrokeStrategy.cpp
KisRunnableStrokeJobDataBase.cpp
KisRunnableStrokeJobData.cpp
KisRunnableStrokeJobsInterface.cpp
KisFakeRunnableStrokeJobsExecutor.cpp
kis_stroke_job_strategy.cpp
kis_stroke_strategy.cpp
kis_stroke.cpp
kis_strokes_queue.cpp
KisStrokesQueueMutatedJobInterface.cpp
kis_simple_update_queue.cpp
kis_update_scheduler.cpp
kis_queues_progress_updater.cpp
kis_composite_progress_proxy.cpp
kis_sync_lod_cache_stroke_strategy.cpp
kis_lod_capable_layer_offset.cpp
kis_update_time_monitor.cpp
KisImageConfigNotifier.cpp
kis_group_layer.cc
kis_count_visitor.cpp
kis_histogram.cc
kis_image_interfaces.cpp
kis_image_animation_interface.cpp
kis_time_range.cpp
kis_node_graph_listener.cpp
kis_image.cc
kis_image_signal_router.cpp
KisImageSignals.cpp
kis_image_config.cpp
kis_projection_updates_filter.cpp
kis_suspend_projection_updates_stroke_strategy.cpp
kis_regenerate_frame_stroke_strategy.cpp
kis_switch_time_stroke_strategy.cpp
kis_crop_saved_extra_data.cpp
kis_timed_signal_threshold.cpp
kis_layer.cc
kis_indirect_painting_support.cpp
kis_abstract_projection_plane.cpp
kis_layer_projection_plane.cpp
kis_layer_utils.cpp
kis_mask_projection_plane.cpp
kis_projection_leaf.cpp
KisSafeNodeProjectionStore.cpp
kis_mask.cc
kis_base_mask_generator.cpp
kis_rect_mask_generator.cpp
kis_circle_mask_generator.cpp
kis_gauss_circle_mask_generator.cpp
kis_gauss_rect_mask_generator.cpp
${__per_arch_circle_mask_generator_objs}
kis_curve_circle_mask_generator.cpp
kis_curve_rect_mask_generator.cpp
kis_math_toolbox.cpp
kis_memory_statistics_server.cpp
kis_name_server.cpp
kis_node.cpp
kis_node_facade.cpp
kis_node_progress_proxy.cpp
kis_busy_progress_indicator.cpp
kis_node_visitor.cpp
kis_paint_device.cc
kis_paint_device_debug_utils.cpp
kis_fixed_paint_device.cpp
KisOptimizedByteArray.cpp
kis_paint_layer.cc
kis_perspective_math.cpp
kis_pixel_selection.cpp
kis_processing_information.cpp
kis_properties_configuration.cc
kis_random_accessor_ng.cpp
kis_random_generator.cc
kis_random_sub_accessor.cpp
kis_wrapped_random_accessor.cpp
kis_selection.cc
KisSelectionUpdateCompressor.cpp
kis_selection_mask.cpp
kis_update_outline_job.cpp
kis_update_selection_job.cpp
kis_serializable_configuration.cc
kis_transaction_data.cpp
kis_transform_worker.cc
kis_perspectivetransform_worker.cpp
bsplines/kis_bspline_1d.cpp
bsplines/kis_bspline_2d.cpp
bsplines/kis_nu_bspline_2d.cpp
kis_warptransform_worker.cc
kis_cage_transform_worker.cpp
kis_liquify_transform_worker.cpp
kis_green_coordinates_math.cpp
kis_transparency_mask.cc
kis_undo_adapter.cpp
kis_macro_based_undo_store.cpp
kis_surrogate_undo_adapter.cpp
kis_legacy_undo_adapter.cpp
kis_post_execution_undo_adapter.cpp
kis_processing_visitor.cpp
kis_processing_applicator.cpp
krita_utils.cpp
kis_outline_generator.cpp
kis_layer_composition.cpp
kis_selection_filters.cpp
KisProofingConfiguration.h
KisRecycleProjectionsJob.cpp
kis_keyframe.cpp
kis_keyframe_channel.cpp
kis_keyframe_commands.cpp
kis_scalar_keyframe_channel.cpp
kis_raster_keyframe_channel.cpp
kis_onion_skin_compositor.cpp
kis_onion_skin_cache.cpp
kis_idle_watcher.cpp
kis_psd_layer_style.cpp
kis_layer_properties_icons.cpp
layerstyles/kis_multiple_projection.cpp
layerstyles/kis_layer_style_filter.cpp
layerstyles/kis_layer_style_filter_environment.cpp
layerstyles/kis_layer_style_filter_projection_plane.cpp
layerstyles/kis_layer_style_projection_plane.cpp
layerstyles/kis_ls_drop_shadow_filter.cpp
layerstyles/kis_ls_satin_filter.cpp
layerstyles/kis_ls_stroke_filter.cpp
layerstyles/kis_ls_bevel_emboss_filter.cpp
layerstyles/kis_ls_overlay_filter.cpp
layerstyles/kis_ls_utils.cpp
layerstyles/gimp_bump_map.cpp
layerstyles/KisLayerStyleKnockoutBlower.cpp
KisProofingConfiguration.cpp
kis_node_query_path.cc
)
set(einspline_SRCS
3rdparty/einspline/bspline_create.cpp
3rdparty/einspline/bspline_data.cpp
3rdparty/einspline/multi_bspline_create.cpp
3rdparty/einspline/nubasis.cpp
3rdparty/einspline/nubspline_create.cpp
3rdparty/einspline/nugrid.cpp
)
add_library(kritaimage SHARED ${kritaimage_LIB_SRCS} ${einspline_SRCS})
generate_export_header(kritaimage BASE_NAME kritaimage)
target_link_libraries(kritaimage
PUBLIC
kritaversion
kritawidgets
kritaglobal
kritapsd
kritaodf
kritapigment
kritacommand
kritawidgetutils
kritametadata
Qt5::Concurrent
)
target_link_libraries(kritaimage PUBLIC ${Boost_SYSTEM_LIBRARY})
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
target_link_libraries(kritaimage PUBLIC atomic)
endif()
endif()
if(OPENEXR_FOUND)
target_link_libraries(kritaimage PUBLIC ${OPENEXR_LIBRARIES})
endif()
if(FFTW3_FOUND)
target_link_libraries(kritaimage PRIVATE ${FFTW3_LIBRARIES})
endif()
+if(LIBMYPAINT_FOUND)
+ target_link_libraries(kritaimage PUBLIC mypaint)
+endif()
+
if(HAVE_VC)
target_link_libraries(kritaimage PUBLIC ${Vc_LIBRARIES})
endif()
if (NOT GSL_FOUND)
message (WARNING "KRITA WARNING! No GNU Scientific Library was found! Krita's Shaped Gradients might be non-normalized! Please install GSL library.")
else ()
target_link_libraries(kritaimage PRIVATE ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES})
endif ()
target_include_directories(kritaimage
PUBLIC
$
$
$
$
$
)
set_target_properties(kritaimage PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
)
install(TARGETS kritaimage ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/image/brushengine/kis_paintop_preset.cpp b/libs/image/brushengine/kis_paintop_preset.cpp
index 59d3f0aa2c..c78e645cc5 100644
--- a/libs/image/brushengine/kis_paintop_preset.cpp
+++ b/libs/image/brushengine/kis_paintop_preset.cpp
@@ -1,425 +1,452 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2008
* Copyright (C) Sven Langkamp , (C) 2009
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_paintop_registry.h"
#include "kis_painter.h"
#include
#include "kis_paint_device.h"
#include "kis_image.h"
#include "kis_paintop_settings_update_proxy.h"
#include
#include
+#include
struct Q_DECL_HIDDEN KisPaintOpPreset::Private {
Private()
: settings(0),
dirtyPreset(false)
{
}
KisPaintOpSettingsSP settings;
bool dirtyPreset;
QScopedPointer updateProxy;
};
KisPaintOpPreset::KisPaintOpPreset()
: KoResource(QString())
, m_d(new Private)
{
}
KisPaintOpPreset::KisPaintOpPreset(const QString & fileName)
: KoResource(fileName)
, m_d(new Private)
{
}
KisPaintOpPreset::~KisPaintOpPreset()
{
delete m_d;
}
KisPaintOpPresetSP KisPaintOpPreset::clone() const
{
KisPaintOpPresetSP preset(new KisPaintOpPreset());
if (settings()) {
preset->setSettings(settings()); // the settings are cloned inside!
}
preset->setDirty(isDirty());
// only valid if we could clone the settings
preset->setValid(settings());
preset->setPaintOp(paintOp());
preset->setName(name());
preset->setImage(image());
preset->settings()->setPreset(KisPaintOpPresetWSP(preset));
Q_ASSERT(preset->valid());
return preset;
}
void KisPaintOpPreset::setDirty(bool value)
{
m_d->dirtyPreset = value;
}
bool KisPaintOpPreset::isDirty() const
{
return m_d->dirtyPreset;
}
void KisPaintOpPreset::setPaintOp(const KoID & paintOp)
{
Q_ASSERT(m_d->settings);
m_d->settings->setProperty("paintop", paintOp.id());
}
KoID KisPaintOpPreset::paintOp() const
{
Q_ASSERT(m_d->settings);
return KoID(m_d->settings->getString("paintop"));
}
void KisPaintOpPreset::setOptionsWidget(KisPaintOpConfigWidget* widget)
{
if (m_d->settings) {
m_d->settings->setOptionsWidget(widget);
if (widget) {
widget->setConfigurationSafe(m_d->settings);
}
}
}
void KisPaintOpPreset::setSettings(KisPaintOpSettingsSP settings)
{
Q_ASSERT(settings);
Q_ASSERT(!settings->getString("paintop", QString()).isEmpty());
DirtyStateSaver dirtyStateSaver(this);
KisPaintOpConfigWidget *oldOptionsWidget = 0;
if (m_d->settings) {
oldOptionsWidget = m_d->settings->optionsWidget();
m_d->settings->setOptionsWidget(0);
m_d->settings->setPreset(0);
m_d->settings = 0;
}
if (settings) {
m_d->settings = settings->clone();
m_d->settings->setPreset(KisPaintOpPresetWSP(this));
if (oldOptionsWidget) {
oldOptionsWidget->setConfigurationSafe(m_d->settings);
m_d->settings->setOptionsWidget(oldOptionsWidget);
}
}
setValid(m_d->settings);
if (m_d->updateProxy) {
m_d->updateProxy->notifyUniformPropertiesChanged();
m_d->updateProxy->notifySettingsChanged();
}
}
KisPaintOpSettingsSP KisPaintOpPreset::settings() const
{
Q_ASSERT(m_d->settings);
Q_ASSERT(!m_d->settings->getString("paintop", QString()).isEmpty());
return m_d->settings;
}
bool KisPaintOpPreset::load()
{
dbgImage << "Load preset " << filename();
setValid(false);
if (filename().isEmpty()) {
return false;
}
QIODevice *dev = 0;
QByteArray ba;
if (filename().startsWith("bundle://")) {
QString bn = filename().mid(9);
int pos = bn.lastIndexOf(":");
QString fn = bn.right(bn.size() - pos - 1);
bn = bn.left(pos);
QScopedPointer resourceStore(KoStore::createStore(bn, KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip));
if (!resourceStore || resourceStore->bad()) {
warnKrita << "Could not open store on bundle" << bn;
return false;
}
if (resourceStore->isOpen()) resourceStore->close();
if (!resourceStore->open(fn)) {
warnKrita << "Could not open preset" << fn << "in bundle" << bn;
return false;
}
ba = resourceStore->device()->readAll();
dev = new QBuffer(&ba);
resourceStore->close();
}
else {
dev = new QFile(filename());
if (dev->size() == 0)
{
delete dev;
return false;
}
if (!dev->open(QIODevice::ReadOnly)) {
warnKrita << "Can't open file " << filename();
delete dev;
return false;
}
}
- bool res = loadFromDevice(dev);
+ bool res = false;
+ if(filename().endsWith(".myb")) {
+ // res = loadMYB(dev);
+ }
+ else {
+ res = loadFromDevice(dev);
+ }
delete dev;
setValid(res);
setDirty(false);
return res;
}
bool KisPaintOpPreset::loadFromDevice(QIODevice *dev)
{
QImageReader reader(dev, "PNG");
QString version = reader.text("version");
QString preset = reader.text("preset");
dbgImage << version;
if (version != "2.2") {
return false;
}
QImage img;
if (!reader.read(&img)) {
dbgImage << "Fail to decode PNG";
return false;
}
//Workaround for broken presets
//Presets was saved with nested cdata section
preset.replace("");
preset.replace("]]>", "");
QDomDocument doc;
if (!doc.setContent(preset)) {
return false;
}
fromXML(doc.documentElement());
if (!m_d->settings) {
return false;
}
setValid(true);
setImage(img);
return true;
}
+bool KisPaintOpPreset::loadMYB(QIODevice *dev) {
+
+ QString pngFilePath = filename();
+ pngFilePath = pngFilePath.remove(filename().size()-4, 4);
+ pngFilePath = pngFilePath + "_prev.png";
+ QIODevice *imgDev = new QFile(pngFilePath);
+
+ QImageReader reader(imgDev, "PNG");
+
+ QImage img;
+ if (!reader.read(&img)) {
+ dbgImage << "Fail to decode PNG";
+ return false;
+ }
+
+ setValid(true);
+ setImage(img);
+ return true;
+}
+
bool KisPaintOpPreset::save()
{
if (filename().isEmpty())
return false;
QString paintopid = m_d->settings->getString("paintop", QString());
if (paintopid.isEmpty())
return false;
QFile f(filename());
f.open(QFile::WriteOnly);
return saveToDevice(&f);
}
void KisPaintOpPreset::toXML(QDomDocument& doc, QDomElement& elt) const
{
QString paintopid = m_d->settings->getString("paintop", QString());
elt.setAttribute("paintopid", paintopid);
elt.setAttribute("name", name());
// sanitize the settings
bool hasTexture = m_d->settings->getBool("Texture/Pattern/Enabled");
if (!hasTexture) {
Q_FOREACH (const QString & key, m_d->settings->getProperties().keys()) {
if (key.startsWith("Texture") && key != "Texture/Pattern/Enabled") {
m_d->settings->removeProperty(key);
}
}
}
m_d->settings->toXML(doc, elt);
}
void KisPaintOpPreset::fromXML(const QDomElement& presetElt)
{
setName(presetElt.attribute("name"));
QString paintopid = presetElt.attribute("paintopid");
if (paintopid.isEmpty()) {
dbgImage << "No paintopid attribute";
setValid(false);
return;
}
if (KisPaintOpRegistry::instance()->get(paintopid) == 0) {
dbgImage << "No paintop " << paintopid;
setValid(false);
return;
}
KoID id(paintopid, QString());
KisPaintOpSettingsSP settings = KisPaintOpRegistry::instance()->settings(id);
if (!settings) {
setValid(false);
warnKrita << "Could not load settings for preset" << paintopid;
return;
}
settings->fromXML(presetElt);
// sanitize the settings
bool hasTexture = settings->getBool("Texture/Pattern/Enabled");
if (!hasTexture) {
Q_FOREACH (const QString & key, settings->getProperties().keys()) {
if (key.startsWith("Texture") && key != "Texture/Pattern/Enabled") {
settings->removeProperty(key);
}
}
}
setSettings(settings);
}
bool KisPaintOpPreset::saveToDevice(QIODevice *dev) const
{
QImageWriter writer(dev, "PNG");
QDomDocument doc;
QDomElement root = doc.createElement("Preset");
toXML(doc, root);
doc.appendChild(root);
writer.setText("version", "2.2");
writer.setText("preset", doc.toString());
QImage img;
if (image().isNull()) {
img = QImage(1, 1, QImage::Format_RGB32);
} else {
img = image();
}
m_d->dirtyPreset = false;
KoResource::saveToDevice(dev);
return writer.write(img);
}
KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxy() const
{
if (!m_d->updateProxy) {
m_d->updateProxy.reset(new KisPaintopSettingsUpdateProxy());
}
return m_d->updateProxy.data();
}
KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxyNoCreate() const
{
return m_d->updateProxy.data();
}
QList KisPaintOpPreset::uniformProperties()
{
return m_d->settings->uniformProperties(m_d->settings);
}
bool KisPaintOpPreset::hasMaskingPreset() const
{
return m_d->settings && m_d->settings->hasMaskingSettings();
}
KisPaintOpPresetSP KisPaintOpPreset::createMaskingPreset() const
{
KisPaintOpPresetSP result;
if (m_d->settings && m_d->settings->hasMaskingSettings()) {
result = new KisPaintOpPreset();
result->setSettings(m_d->settings->createMaskingSettings());
if (!result->valid()) {
result.clear();
}
}
return result;
}
KisPaintOpPreset::UpdatedPostponer::UpdatedPostponer(KisPaintOpPreset *preset)
: m_updateProxy(preset->updateProxyNoCreate())
{
if (m_updateProxy) {
m_updateProxy->postponeSettingsChanges();
}
}
KisPaintOpPreset::UpdatedPostponer::~UpdatedPostponer()
{
if (m_updateProxy) {
m_updateProxy->unpostponeSettingsChanges();
}
}
diff --git a/libs/image/brushengine/kis_paintop_preset.h b/libs/image/brushengine/kis_paintop_preset.h
index 3cfbd9c40a..b87abc7d1d 100644
--- a/libs/image/brushengine/kis_paintop_preset.h
+++ b/libs/image/brushengine/kis_paintop_preset.h
@@ -1,154 +1,156 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2008
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KIS_PAINTOP_PRESET_H
#define KIS_PAINTOP_PRESET_H
#include
#include "KoID.h"
#include "kis_types.h"
#include "kis_shared.h"
#include "kritaimage_export.h"
#include
class KisPaintopSettingsUpdateProxy;
class KisPaintOpConfigWidget;
/**
* A KisPaintOpPreset contains a particular set of settings
* associated with a paintop, like brush, paintopsettings.
* A new property in this class is to make it dirty. That means the
* user can now temporarily save any tweaks in the Preset throughout
* the session. The Dirty Preset setting/unsetting is handled by KisPaintOpPresetSettings
*/
class KRITAIMAGE_EXPORT KisPaintOpPreset : public KoResource, public KisShared
{
public:
KisPaintOpPreset();
KisPaintOpPreset(const QString& filename);
~KisPaintOpPreset() override;
KisPaintOpPresetSP clone() const;
/// set the id of the paintop plugin
void setPaintOp(const KoID & paintOp);
/// return the id of the paintop plugin
KoID paintOp() const;
/// replace the current settings object with the specified settings
void setSettings(KisPaintOpSettingsSP settings);
void setOriginalSettings(KisPaintOpSettingsSP originalSettings);
/// return the settings that define this paintop preset
KisPaintOpSettingsSP settings() const;
KisPaintOpSettingsSP originalSettings() const;
bool load() override;
bool loadFromDevice(QIODevice *dev) override;
bool save() override;
bool saveToDevice(QIODevice* dev) const override;
void toXML(QDomDocument& doc, QDomElement& elt) const;
void fromXML(const QDomElement& elt);
+ bool loadMYB(QIODevice* dev);
+
bool removable() const {
return true;
}
QString defaultFileExtension() const override {
return ".kpp";
}
/// Mark the preset as modified but not saved
void setDirty(bool value);
/// @return true if the preset has been modified, but not saved
bool isDirty() const;
/**
* Never use manual save/restore calls to
* isPresetDirty()/setPresetDirty()! They will lead to
* hard-to-tack-down bugs when the dirty state will not be
* restored on jumps like 'return', 'break' or exception.
*/
class KRITAIMAGE_EXPORT DirtyStateSaver {
public:
DirtyStateSaver(KisPaintOpPreset *preset)
: m_preset(preset), m_isDirty(preset->isDirty())
{
}
~DirtyStateSaver() {
m_preset->setDirty(m_isDirty);
}
private:
KisPaintOpPreset *m_preset;
bool m_isDirty;
};
/**
* @brief The UpdatedPostponer class
* @see KisPaintopSettingsUpdateProxy::postponeSettingsChanges()
*/
class KRITAIMAGE_EXPORT UpdatedPostponer{
public:
UpdatedPostponer(KisPaintOpPreset *preset);
~UpdatedPostponer();
private:
KisPaintopSettingsUpdateProxy *m_updateProxy;
};
void setOptionsWidget(KisPaintOpConfigWidget *widget);
KisPaintopSettingsUpdateProxy* updateProxy() const;
KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const;
QList uniformProperties();
/**
* @return true if this preset demands a secondary masked brush running
* alongside it
*/
bool hasMaskingPreset() const;
/**
* @return a newly created preset of the masked brush that should be run
* alongside the current brush
*/
KisPaintOpPresetSP createMaskingPreset() const;
private:
struct Private;
Private * const m_d;
};
Q_DECLARE_METATYPE(KisPaintOpPresetSP)
#endif
diff --git a/libs/ui/KisResourceServerProvider.cpp b/libs/ui/KisResourceServerProvider.cpp
index 5360352ce8..602fe77054 100644
--- a/libs/ui/KisResourceServerProvider.cpp
+++ b/libs/ui/KisResourceServerProvider.cpp
@@ -1,120 +1,120 @@
/*
* kis_resourceserver.cc - part of KImageShop
*
* Copyright (c) 1999 Matthias Elter
* Copyright (c) 2003 Patrick Julien
* Copyright (c) 2005 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 "KisResourceServerProvider.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_GLOBAL_STATIC(KisResourceServerProvider, s_instance)
typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer;
typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter;
KisResourceServerProvider::KisResourceServerProvider()
{
KisBrushServer *brushServer = KisBrushServer::instance();
- m_paintOpPresetServer = new KisPaintOpPresetResourceServer("kis_paintoppresets", "*.kpp");
+ m_paintOpPresetServer = new KisPaintOpPresetResourceServer("kis_paintoppresets", "*.kpp:*.myb");
m_paintOpPresetServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_paintOpPresetServer->fileNames(), m_paintOpPresetServer->blackListedFiles()));
m_workspaceServer = new KoResourceServerSimpleConstruction("kis_workspaces", "*.kws");
m_workspaceServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_workspaceServer->fileNames(), m_workspaceServer->blackListedFiles()));
m_windowLayoutServer = new KoResourceServerSimpleConstruction("kis_windowlayouts", "*.kwl");
m_windowLayoutServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_windowLayoutServer->fileNames(), m_windowLayoutServer->blackListedFiles()));
m_sessionServer = new KoResourceServerSimpleConstruction("kis_sessions", "*.ksn");
m_sessionServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_sessionServer->fileNames(), m_sessionServer->blackListedFiles()));
m_layerStyleCollectionServer = new KoResourceServerSimpleConstruction("psd_layer_style_collections", "*.asl");
m_layerStyleCollectionServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_layerStyleCollectionServer->fileNames(), m_layerStyleCollectionServer->blackListedFiles()));
connect(this, SIGNAL(notifyBrushBlacklistCleanup()),
brushServer, SLOT(slotRemoveBlacklistedResources()));
}
KisResourceServerProvider::~KisResourceServerProvider()
{
delete m_paintOpPresetServer;
delete m_workspaceServer;
delete m_sessionServer;
delete m_windowLayoutServer;
delete m_layerStyleCollectionServer;
}
KisResourceServerProvider* KisResourceServerProvider::instance()
{
return s_instance;
}
KisPaintOpPresetResourceServer* KisResourceServerProvider::paintOpPresetServer()
{
return m_paintOpPresetServer;
}
KoResourceServer< KisWorkspaceResource >* KisResourceServerProvider::workspaceServer()
{
return m_workspaceServer;
}
KoResourceServer< KisWindowLayoutResource >* KisResourceServerProvider::windowLayoutServer()
{
return m_windowLayoutServer;
}
KoResourceServer< KisSessionResource >* KisResourceServerProvider::sessionServer()
{
return m_sessionServer;
}
KoResourceServer *KisResourceServerProvider::layerStyleCollectionServer()
{
return m_layerStyleCollectionServer;
}
void KisResourceServerProvider::brushBlacklistCleanup()
{
emit notifyBrushBlacklistCleanup();
}
diff --git a/libs/widgetutils/KoResourcePaths.cpp b/libs/widgetutils/KoResourcePaths.cpp
index 7cc3b4a3c5..ae27975a1b 100644
--- a/libs/widgetutils/KoResourcePaths.cpp
+++ b/libs/widgetutils/KoResourcePaths.cpp
@@ -1,602 +1,606 @@
/*
* Copyright (c) 2015 Boudewijn Rempt
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "KoResourcePaths.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_debug.h"
Q_GLOBAL_STATIC(KoResourcePaths, s_instance)
static QString cleanup(const QString &path)
{
return QDir::cleanPath(path);
}
static QStringList cleanup(const QStringList &pathList)
{
QStringList cleanedPathList;
Q_FOREACH(const QString &path, pathList) {
cleanedPathList << cleanup(path);
}
return cleanedPathList;
}
static QString cleanupDirs(const QString &path)
{
return QDir::cleanPath(path) + QDir::separator();
}
static QStringList cleanupDirs(const QStringList &pathList)
{
QStringList cleanedPathList;
Q_FOREACH(const QString &path, pathList) {
cleanedPathList << cleanupDirs(path);
}
return cleanedPathList;
}
void appendResources(QStringList *dst, const QStringList &src, bool eliminateDuplicates)
{
Q_FOREACH (const QString &resource, src) {
QString realPath = QDir::cleanPath(resource);
if (!eliminateDuplicates || !dst->contains(realPath)) {
*dst << realPath;
}
}
}
#ifdef Q_OS_WIN
static const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
#else
static const Qt::CaseSensitivity cs = Qt::CaseSensitive;
#endif
#ifdef Q_OS_MACOS
#include
#include
#include
#endif
QString getInstallationPrefix() {
#ifdef Q_OS_MACOS
QString appPath = qApp->applicationDirPath();
dbgResources << "1" << appPath;
appPath.chop(QString("MacOS/").length());
dbgResources << "2" << appPath;
bool makeInstall = QDir(appPath + "/../../../share/kritaplugins").exists();
bool inBundle = QDir(appPath + "/Resources/kritaplugins").exists();
dbgResources << "3. After make install" << makeInstall;
dbgResources << "4. In Bundle" << inBundle;
QString bundlePath;
if (inBundle) {
bundlePath = appPath + "/";
}
else if (makeInstall) {
appPath.chop(QString("Contents/").length());
bundlePath = appPath + "/../../";
}
else {
qFatal("Cannot calculate the bundle path from the app path");
}
dbgResources << ">>>>>>>>>>>" << bundlePath;
return bundlePath;
#else
#ifdef Q_OS_QWIN
QDir appdir(qApp->applicationDirPath());
// Corrects for mismatched case errors in path (qtdeclarative fails to load)
wchar_t buffer[1024];
QString absolute = appdir.absolutePath();
DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
rv = ::GetLongPathName(buffer, buffer, 1024);
QString correctedPath((QChar *)buffer);
appdir.setPath(correctedPath);
appdir.cdUp();
return appdir.canonicalPath();
#else
#ifdef Q_OS_ANDROID
// qApp->applicationDirPath() isn't writable and android system won't allow
// any files other than libraries
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/";
#else
return qApp->applicationDirPath() + "/../";
#endif
#endif
#endif
}
class Q_DECL_HIDDEN KoResourcePaths::Private {
public:
QMap absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
QMap relatives; // Same with relative paths
QMutex relativesMutex;
QMutex absolutesMutex;
QStringList aliases(const QString &type)
{
QStringList r;
QStringList a;
relativesMutex.lock();
if (relatives.contains(type)) {
r += relatives[type];
}
relativesMutex.unlock();
dbgResources << "\trelatives" << r;
absolutesMutex.lock();
if (absolutes.contains(type)) {
a += absolutes[type];
}
dbgResources << "\tabsolutes" << a;
absolutesMutex.unlock();
return r + a;
}
QStandardPaths::StandardLocation mapTypeToQStandardPaths(const QString &type)
{
if (type == "tmp") {
return QStandardPaths::TempLocation;
}
else if (type == "appdata") {
return QStandardPaths::AppDataLocation;
}
else if (type == "data") {
return QStandardPaths::AppDataLocation;
}
else if (type == "cache") {
return QStandardPaths::CacheLocation;
}
else if (type == "locale") {
return QStandardPaths::AppDataLocation;
}
else {
return QStandardPaths::AppDataLocation;
}
}
};
KoResourcePaths::KoResourcePaths()
: d(new Private)
{
}
KoResourcePaths::~KoResourcePaths()
{
}
QString KoResourcePaths::getApplicationRoot()
{
return getInstallationPrefix();
}
void KoResourcePaths::addResourceType(const char *type, const char *basetype,
const QString &relativeName, bool priority)
{
s_instance->addResourceTypeInternal(QString::fromLatin1(type), QString::fromLatin1(basetype), relativeName, priority);
}
void KoResourcePaths::addResourceDir(const char *type, const QString &dir, bool priority)
{
s_instance->addResourceDirInternal(QString::fromLatin1(type), dir, priority);
}
QString KoResourcePaths::findResource(const char *type, const QString &fileName)
{
return cleanup(s_instance->findResourceInternal(QString::fromLatin1(type), fileName));
}
QStringList KoResourcePaths::findDirs(const char *type)
{
return cleanupDirs(s_instance->findDirsInternal(QString::fromLatin1(type)));
}
QStringList KoResourcePaths::findAllResources(const char *type,
const QString &filter,
SearchOptions options)
{
return cleanup(s_instance->findAllResourcesInternal(QString::fromLatin1(type), filter, options));
}
QStringList KoResourcePaths::resourceDirs(const char *type)
{
return cleanupDirs(s_instance->resourceDirsInternal(QString::fromLatin1(type)));
}
QString KoResourcePaths::saveLocation(const char *type, const QString &suffix, bool create)
{
return cleanupDirs(s_instance->saveLocationInternal(QString::fromLatin1(type), suffix, create));
}
QString KoResourcePaths::locate(const char *type, const QString &filename)
{
return cleanup(s_instance->locateInternal(QString::fromLatin1(type), filename));
}
QString KoResourcePaths::locateLocal(const char *type, const QString &filename, bool createDir)
{
return cleanup(s_instance->locateLocalInternal(QString::fromLatin1(type), filename, createDir));
}
void KoResourcePaths::addResourceTypeInternal(const QString &type, const QString &basetype,
const QString &relativename,
bool priority)
{
Q_UNUSED(basetype);
if (relativename.isEmpty()) return;
QString copy = relativename;
Q_ASSERT(basetype == "data");
if (!copy.endsWith(QLatin1Char('/'))) {
copy += QLatin1Char('/');
}
d->relativesMutex.lock();
QStringList &rels = d->relatives[type]; // find or insert
if (!rels.contains(copy, cs)) {
if (priority) {
rels.prepend(copy);
} else {
rels.append(copy);
}
}
d->relativesMutex.unlock();
dbgResources << "addResourceType: type" << type << "basetype" << basetype << "relativename" << relativename << "priority" << priority << d->relatives[type];
}
void KoResourcePaths::addResourceDirInternal(const QString &type, const QString &absdir, bool priority)
{
if (absdir.isEmpty() || type.isEmpty()) return;
// find or insert entry in the map
QString copy = absdir;
if (copy.at(copy.length() - 1) != QLatin1Char('/')) {
copy += QLatin1Char('/');
}
d->absolutesMutex.lock();
QStringList &paths = d->absolutes[type];
if (!paths.contains(copy, cs)) {
if (priority) {
paths.prepend(copy);
} else {
paths.append(copy);
}
}
d->absolutesMutex.unlock();
dbgResources << "addResourceDir: type" << type << "absdir" << absdir << "priority" << priority << d->absolutes[type];
}
QString KoResourcePaths::findResourceInternal(const QString &type, const QString &fileName)
{
QStringList aliases = d->aliases(type);
dbgResources<< "aliases" << aliases << getApplicationRoot();
QString resource = QStandardPaths::locate(QStandardPaths::AppDataLocation, fileName, QStandardPaths::LocateFile);
if (resource.isEmpty()) {
Q_FOREACH (const QString &alias, aliases) {
resource = QStandardPaths::locate(d->mapTypeToQStandardPaths(type), alias + '/' + fileName, QStandardPaths::LocateFile);
dbgResources << "\t1" << resource;
if (QFile::exists(resource)) {
continue;
}
}
}
if (resource.isEmpty() || !QFile::exists(resource)) {
QString approot = getApplicationRoot();
Q_FOREACH (const QString &alias, aliases) {
resource = approot + "/share/" + alias + '/' + fileName;
dbgResources << "\t2" << resource;
if (QFile::exists(resource)) {
continue;
}
}
}
if (resource.isEmpty() || !QFile::exists(resource)) {
QString approot = getApplicationRoot();
Q_FOREACH (const QString &alias, aliases) {
resource = approot + "/share/krita/" + alias + '/' + fileName;
dbgResources << "\t3" << resource;
if (QFile::exists(resource)) {
continue;
}
}
}
if (resource.isEmpty() || !QFile::exists(resource)) {
QString extraResourceDirs = qgetenv("EXTRA_RESOURCE_DIRS");
if (!extraResourceDirs.isEmpty()) {
Q_FOREACH(const QString &extraResourceDir, extraResourceDirs.split(':', QString::SkipEmptyParts)) {
if (aliases.isEmpty()) {
resource = extraResourceDir + '/' + fileName;
dbgResources<< "\t4" << resource;
if (QFile::exists(resource)) {
continue;
}
}
else {
Q_FOREACH (const QString &alias, aliases) {
resource = extraResourceDir + '/' + alias + '/' + fileName;
dbgResources<< "\t4" << resource;
if (QFile::exists(resource)) {
continue;
}
}
}
}
}
}
dbgResources<< "findResource: type" << type << "filename" << fileName << "resource" << resource;
Q_ASSERT(!resource.isEmpty());
return resource;
}
QStringList filesInDir(const QString &startdir, const QString & filter, bool recursive)
{
dbgResources << "filesInDir: startdir" << startdir << "filter" << filter << "recursive" << recursive;
QStringList result;
// First the entries in this path
QStringList nameFilters;
nameFilters << filter;
const QStringList fileNames = QDir(startdir).entryList(nameFilters, QDir::Files | QDir::CaseSensitive, QDir::Name);
dbgResources << "\tFound:" << fileNames.size() << ":" << fileNames;
Q_FOREACH (const QString &fileName, fileNames) {
QString file = startdir + '/' + fileName;
result << file;
}
// And then everything underneath, if recursive is specified
if (recursive) {
const QStringList entries = QDir(startdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
Q_FOREACH (const QString &subdir, entries) {
dbgResources << "\tGoing to look in subdir" << subdir << "of" << startdir;
result << filesInDir(startdir + '/' + subdir, filter, recursive);
}
}
return result;
}
QStringList KoResourcePaths::findDirsInternal(const QString &type)
{
QStringList aliases = d->aliases(type);
dbgResources << type << aliases << d->mapTypeToQStandardPaths(type);
QStringList dirs;
QStringList standardDirs =
QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), "", QStandardPaths::LocateDirectory);
appendResources(&dirs, standardDirs, true);
Q_FOREACH (const QString &alias, aliases) {
QStringList aliasDirs =
QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias + '/', QStandardPaths::LocateDirectory);
appendResources(&dirs, aliasDirs, true);
#ifdef Q_OS_MACOS
dbgResources << "MAC:" << getApplicationRoot();
QStringList bundlePaths;
bundlePaths << getApplicationRoot() + "/share/krita/" + alias;
bundlePaths << getApplicationRoot() + "/../share/krita/" + alias;
dbgResources << "bundlePaths" << bundlePaths;
appendResources(&dirs, bundlePaths, true);
Q_ASSERT(!dirs.isEmpty());
#endif
QStringList fallbackPaths;
fallbackPaths << getApplicationRoot() + "/share/" + alias;
fallbackPaths << getApplicationRoot() + "/share/krita/" + alias;
appendResources(&dirs, fallbackPaths, true);
}
dbgResources << "findDirs: type" << type << "resource" << dirs;
return dirs;
}
QStringList KoResourcePaths::findAllResourcesInternal(const QString &type,
const QString &_filter,
SearchOptions options) const
{
dbgResources << "=====================================================";
dbgResources << type << _filter << QStandardPaths::standardLocations(d->mapTypeToQStandardPaths(type));
bool recursive = options & KoResourcePaths::Recursive;
dbgResources << "findAllResources: type" << type << "filter" << _filter << "recursive" << recursive;
QStringList aliases = d->aliases(type);
QString filter = _filter;
// In cases where the filter is like "color-schemes/*.colors" instead of "*.kpp", used with unregistered resource types
if (filter.indexOf('*') > 0) {
aliases << filter.split('*').first();
filter = '*' + filter.split('*')[1];
dbgResources << "Split up alias" << aliases << "filter" << filter;
}
QStringList resources;
if (aliases.isEmpty()) {
QStringList standardResources =
QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type),
filter, QStandardPaths::LocateFile);
dbgResources << "standardResources" << standardResources;
appendResources(&resources, standardResources, true);
dbgResources << "1" << resources;
}
QString extraResourceDirs = qgetenv("EXTRA_RESOURCE_DIRS");
dbgResources << "extraResourceDirs" << extraResourceDirs;
if (!extraResourceDirs.isEmpty()) {
Q_FOREACH(const QString &extraResourceDir, extraResourceDirs.split(':', QString::SkipEmptyParts)) {
if (aliases.isEmpty()) {
appendResources(&resources, filesInDir(extraResourceDir + '/' + type, filter, recursive), true);
}
else {
Q_FOREACH (const QString &alias, aliases) {
appendResources(&resources, filesInDir(extraResourceDir + '/' + alias + '/', filter, recursive), true);
}
}
}
}
dbgResources << "\tresources from qstandardpaths:" << resources.size();
Q_FOREACH (const QString &alias, aliases) {
dbgResources << "\t\talias:" << alias;
QStringList dirs;
QFileInfo dirInfo(alias);
if (dirInfo.exists() && dirInfo.isDir() && dirInfo.isAbsolute()) {
dirs << alias;
} else {
dirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory)
<< getInstallationPrefix() + "share/" + alias + "/"
<< getInstallationPrefix() + "share/krita/" + alias + "/";
}
+ if(_filter.endsWith("*.myb")) {
+ dirs << "/usr/share" << "/home";
+ }
+
Q_FOREACH (const QString &dir, dirs) {
appendResources(&resources,
filesInDir(dir, filter, recursive),
true);
}
}
dbgResources << "\tresources also from aliases:" << resources.size();
// if the original filter is "input/*", we only want share/input/* and share/krita/input/* here, but not
// share/*. therefore, use _filter here instead of filter which was split into alias and "*".
QFileInfo fi(_filter);
QStringList prefixResources;
prefixResources << filesInDir(getInstallationPrefix() + "share/" + fi.path(), fi.fileName(), false);
prefixResources << filesInDir(getInstallationPrefix() + "share/krita/" + fi.path(), fi.fileName(), false);
appendResources(&resources, prefixResources, true);
dbgResources << "\tresources from installation:" << resources.size();
dbgResources << "=====================================================";
return resources;
}
QStringList KoResourcePaths::resourceDirsInternal(const QString &type)
{
QStringList resourceDirs;
QStringList aliases = d->aliases(type);
Q_FOREACH (const QString &alias, aliases) {
QStringList aliasDirs;
aliasDirs << QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
aliasDirs << getInstallationPrefix() + "share/" + alias + "/"
<< QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
aliasDirs << getInstallationPrefix() + "share/krita/" + alias + "/"
<< QStandardPaths::locateAll(d->mapTypeToQStandardPaths(type), alias, QStandardPaths::LocateDirectory);
appendResources(&resourceDirs, aliasDirs, true);
}
dbgResources << "resourceDirs: type" << type << resourceDirs;
return resourceDirs;
}
QString KoResourcePaths::saveLocationInternal(const QString &type, const QString &suffix, bool create)
{
QStringList aliases = d->aliases(type);
QString path;
if (aliases.size() > 0) {
path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type)) + '/' + aliases.first();
}
else {
path = QStandardPaths::writableLocation(d->mapTypeToQStandardPaths(type));
if (!path.endsWith("krita")) {
path += "/krita";
}
if (!suffix.isEmpty()) {
path += "/" + suffix;
}
}
QDir d(path);
if (!d.exists() && create) {
d.mkpath(path);
}
dbgResources << "saveLocation: type" << type << "suffix" << suffix << "create" << create << "path" << path;
return path;
}
QString KoResourcePaths::locateInternal(const QString &type, const QString &filename)
{
QStringList aliases = d->aliases(type);
QStringList locations;
if (aliases.isEmpty()) {
locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type), filename, QStandardPaths::LocateFile);
}
Q_FOREACH (const QString &alias, aliases) {
locations << QStandardPaths::locate(d->mapTypeToQStandardPaths(type),
(alias.endsWith('/') ? alias : alias + '/') + filename, QStandardPaths::LocateFile);
}
dbgResources << "locate: type" << type << "filename" << filename << "locations" << locations;
if (locations.size() > 0) {
return locations.first();
}
else {
return "";
}
}
QString KoResourcePaths::locateLocalInternal(const QString &type, const QString &filename, bool createDir)
{
QString path = saveLocationInternal(type, "", createDir);
dbgResources << "locateLocal: type" << type << "filename" << filename << "CreateDir" << createDir << "path" << path;
return path + '/' + filename;
}
diff --git a/plugins/paintops/CMakeLists.txt b/plugins/paintops/CMakeLists.txt
index cf3377e38b..174718a820 100644
--- a/plugins/paintops/CMakeLists.txt
+++ b/plugins/paintops/CMakeLists.txt
@@ -1,18 +1,19 @@
include_directories(libpaintop)
add_subdirectory( libpaintop )
add_subdirectory( defaultpresets )
add_subdirectory( defaultpaintops )
add_subdirectory( hairy )
add_subdirectory( deform )
add_subdirectory( curvebrush )
add_subdirectory( spray )
add_subdirectory( filterop )
add_subdirectory( experiment )
add_subdirectory( particle )
add_subdirectory( gridbrush )
add_subdirectory( hatching)
add_subdirectory( sketch )
add_subdirectory( colorsmudge )
add_subdirectory( roundmarker )
add_subdirectory( tangentnormal )
+add_subdirectory( mypaint )
diff --git a/plugins/paintops/mypaint/CMakeLists.txt b/plugins/paintops/mypaint/CMakeLists.txt
new file mode 100644
index 0000000000..1eb44dd485
--- /dev/null
+++ b/plugins/paintops/mypaint/CMakeLists.txt
@@ -0,0 +1,27 @@
+if(LIBMYPAINT_FOUND)
+ include_directories(${LIBMYPAINT_INCLUDE_DIR})
+ link_directories(${LIBMYPAINT_LIBRARIES})
+endif()
+
+set(kritamypaintop_SOURCES
+ my_paintop_plugin.cpp
+ kis_my_paintop.cpp
+ #kis_myop_option.cpp
+ kis_my_paintop_settings.cpp
+ kis_my_paintop_settings_widget.cpp
+)
+
+#ki18n_wrap_ui(kritasketchpaintop_SOURCES wdgsketchoptions.ui )
+
+add_library(kritamypaintop MODULE ${kritamypaintop_SOURCES})
+
+target_link_libraries(kritamypaintop kritalibpaintop mypaint)
+
+install(TARGETS kritamypaintop DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
+
+
+########### install files ###############
+
+install( FILES krita-mypaint.png DESTINATION ${DATA_INSTALL_DIR}/krita/images)
+
+
diff --git a/plugins/paintops/mypaint/kis_my_paintop.cpp b/plugins/paintops/mypaint/kis_my_paintop.cpp
new file mode 100644
index 0000000000..af39938737
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop.cpp
@@ -0,0 +1,32 @@
+#include "kis_my_paintop.h"
+
+#include "kis_paintop.h"
+#include "kis_spacing_information.h"
+#include "kis_my_paintop_settings.h"
+#include
+#include
+
+#include
+
+
+KisMyPaintOp::KisMyPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image)
+ : KisPaintOp (painter) {
+
+ MyPaintBrush *brush = mypaint_brush_new();
+}
+
+KisMyPaintOp::~KisMyPaintOp() {
+
+}
+
+KisSpacingInformation KisMyPaintOp::paintAt(const KisPaintInformation& info) {
+
+ KisSpacingInformation spacingInfo;
+ return spacingInfo;
+}
+
+KisSpacingInformation KisMyPaintOp::updateSpacingImpl(const KisPaintInformation &info) const
+{
+ KisSpacingInformation spacingInfo;
+ return spacingInfo;
+}
diff --git a/plugins/paintops/mypaint/kis_my_paintop.h b/plugins/paintops/mypaint/kis_my_paintop.h
new file mode 100644
index 0000000000..c76d72fec5
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop.h
@@ -0,0 +1,40 @@
+#ifndef KIS_MY_PAINTOP_H_
+#define KIS_MY_PAINTOP_H_
+
+#include
+#include
+
+//#include "kis_spray_paintop_settings.h"
+//#include "kis_brush_option.h"
+// #include
+// #include
+// #include
+// #include
+// #include
+
+class KisPainter;
+
+
+class KisMyPaintOp : public KisPaintOp
+{
+
+public:
+
+ KisMyPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image);
+ ~KisMyPaintOp() override;
+
+protected:
+
+ KisSpacingInformation paintAt(const KisPaintInformation& info) override;
+
+ KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override;
+
+ //KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override;
+
+private:
+ //KisSpacingInformation computeSpacing(const KisPaintInformation &info, qreal lodScale) const;
+
+private:
+};
+
+#endif // KIS_MY_PAINTOP_H_
diff --git a/plugins/paintops/mypaint/kis_my_paintop_settings.cpp b/plugins/paintops/mypaint/kis_my_paintop_settings.cpp
new file mode 100644
index 0000000000..cedcbbfeff
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop_settings.cpp
@@ -0,0 +1,200 @@
+#include
+
+#include
+#include
+
+#include "kis_my_paintop_settings.h"
+///#include "kis_sprayop_option.h"
+
+struct KisMyPaintOpSettings::Private
+{
+ QList uniformProperties;
+};
+
+
+KisMyPaintOpSettings::KisMyPaintOpSettings()
+ : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION |
+ KisCurrentOutlineFetcher::ROTATION_OPTION),
+ m_d(new Private)
+{
+}
+
+KisMyPaintOpSettings::~KisMyPaintOpSettings()
+{
+}
+
+void KisMyPaintOpSettings::setPaintOpSize(qreal value)
+{
+// KisMyOptionProperties option;
+// option.readOptionSetting(this);
+// option.diameter = value;
+// option.writeOptionSetting(this);
+}
+
+qreal KisMyPaintOpSettings::paintOpSize() const
+{
+
+// KisSprayOptionProperties option;
+// option.readOptionSetting(this);
+//
+// return option.diameter;
+ return 2;
+}
+
+bool KisMyPaintOpSettings::paintIncremental()
+{
+ return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP;
+}
+
+
+QPainterPath KisMyPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom)
+{
+ QPainterPath path;
+// if (mode.isVisible) {
+// qreal width = getInt(SPRAY_DIAMETER);
+// qreal height = getInt(SPRAY_DIAMETER) * getDouble(SPRAY_ASPECT);
+// path = ellipseOutline(width, height, getDouble(SPRAY_SCALE), getDouble(SPRAY_ROTATION));
+
+// path = outlineFetcher()->fetchOutline(info, this, path, mode, alignForZoom);
+
+// if (mode.forceFullSize) {
+// QPainterPath tiltLine =
+// makeTiltIndicator(info, QPointF(0.0, 0.0), width * 0.5, 3.0);
+// path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, alignForZoom, 1.0, 0.0, true, 0, 0));
+// }
+// }
+ return path;
+}
+
+#include
+#include "kis_paintop_preset.h"
+#include "kis_paintop_settings_update_proxy.h"
+#include "kis_standard_uniform_properties_factory.h"
+
+
+QList KisMyPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings)
+{
+ QList props =
+ listWeakToStrong(m_d->uniformProperties);
+
+// if (props.isEmpty()) {
+// {
+// KisDoubleSliderBasedPaintOpPropertyCallback *prop =
+// new KisDoubleSliderBasedPaintOpPropertyCallback(
+// KisDoubleSliderBasedPaintOpPropertyCallback::Double,
+// "spacing",
+// i18n("Spacing"),
+// settings, 0);
+
+// prop->setRange(0.01, 10);
+// prop->setSingleStep(0.01);
+// prop->setExponentRatio(3.0);
+
+// prop->setReadCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+
+// prop->setValue(option.spacing);
+// });
+// prop->setWriteCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// option.spacing = prop->value().toReal();
+// option.writeOptionSetting(prop->settings().data());
+// });
+
+// QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+// prop->requestReadValue();
+// props << toQShared(prop);
+// }
+// {
+// KisIntSliderBasedPaintOpPropertyCallback *prop =
+// new KisIntSliderBasedPaintOpPropertyCallback(
+// KisIntSliderBasedPaintOpPropertyCallback::Int,
+// "spray_particlecount",
+// i18n("Particle Count"),
+// settings, 0);
+
+// prop->setRange(0, 1000);
+// prop->setExponentRatio(3);
+
+// prop->setReadCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+
+// prop->setValue(int(option.particleCount));
+// });
+// prop->setWriteCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// option.particleCount = prop->value().toInt();
+// option.writeOptionSetting(prop->settings().data());
+// });
+// prop->setIsVisibleCallback(
+// [](const KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// return !option.useDensity;
+// });
+
+// QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+// prop->requestReadValue();
+// props << toQShared(prop);
+// }
+// {
+// KisDoubleSliderBasedPaintOpPropertyCallback *prop =
+// new KisDoubleSliderBasedPaintOpPropertyCallback(
+// KisDoubleSliderBasedPaintOpPropertyCallback::Double,
+// "spray_density",
+// i18n("Density"),
+// settings, 0);
+
+// prop->setRange(0.1, 100);
+// prop->setSingleStep(0.01);
+// prop->setDecimals(2);
+// prop->setExponentRatio(3);
+// prop->setSuffix(i18n("%"));
+
+// prop->setReadCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// prop->setValue(option.coverage);
+// });
+// prop->setWriteCallback(
+// [](KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// option.coverage = prop->value().toReal();
+// option.writeOptionSetting(prop->settings().data());
+// });
+// prop->setIsVisibleCallback(
+// [](const KisUniformPaintOpProperty *prop) {
+// KisSprayOptionProperties option;
+// option.readOptionSetting(prop->settings().data());
+// return option.useDensity;
+// });
+
+// QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
+// prop->requestReadValue();
+// props << toQShared(prop);
+// }
+// }
+// {
+// using namespace KisStandardUniformPropertiesFactory;
+
+// Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) {
+// if (prop->id() == opacity.id() ||
+// prop->id() == size.id()) {
+
+// props.prepend(prop);
+// }
+// }
+// }
+
+ return props;
+}
diff --git a/plugins/paintops/mypaint/kis_my_paintop_settings.h b/plugins/paintops/mypaint/kis_my_paintop_settings.h
new file mode 100644
index 0000000000..b7ab6cff07
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop_settings.h
@@ -0,0 +1,44 @@
+#ifndef KIS_MY_PAINTOP_SETTINGS_H_
+#define KIS_MY_PAINTOP_SETTINGS_H_
+
+#include
+
+#include
+#include
+
+#include
+#include "kis_my_paintop_settings_widget.h"
+
+
+class KisMyPaintOpSettings : public KisOutlineGenerationPolicy
+{
+public:
+ KisMyPaintOpSettings();
+ ~KisMyPaintOpSettings() override;
+
+ void setPaintOpSize(qreal value) override;
+ qreal paintOpSize() const override;
+
+ QPainterPath brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom) override;
+
+ QString modelName() const override {
+ return "airbrush";
+ }
+
+ bool paintIncremental() override;
+
+protected:
+
+ QList uniformProperties(KisPaintOpSettingsSP settings) override;
+
+private:
+ Q_DISABLE_COPY(KisMyPaintOpSettings)
+
+ struct Private;
+ const QScopedPointer m_d;
+
+};
+
+typedef KisSharedPtr KisMyPaintOpSettingsSP;
+
+#endif
diff --git a/plugins/paintops/mypaint/kis_my_paintop_settings_widget.cpp b/plugins/paintops/mypaint/kis_my_paintop_settings_widget.cpp
new file mode 100644
index 0000000000..eff36b52d1
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop_settings_widget.cpp
@@ -0,0 +1,33 @@
+#include "kis_my_paintop_settings_widget.h"
+
+#include "kis_my_paintop_settings.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+KisMyPaintOpSettingsWidget:: KisMyPaintOpSettingsWidget(QWidget* parent)
+ : KisPaintOpSettingsWidget(parent)
+{
+}
+
+KisMyPaintOpSettingsWidget::~ KisMyPaintOpSettingsWidget()
+{
+}
+
+KisPropertiesConfigurationSP KisMyPaintOpSettingsWidget::configuration() const
+{
+ KisMyPaintOpSettings* config = new KisMyPaintOpSettings();
+ config->setOptionsWidget(const_cast(this));
+ config->setProperty("paintop", "mypaintbrush"); // XXX: make this a const id string
+ writeConfiguration(config);
+ return config;
+}
diff --git a/plugins/paintops/mypaint/kis_my_paintop_settings_widget.h b/plugins/paintops/mypaint/kis_my_paintop_settings_widget.h
new file mode 100644
index 0000000000..96bccbcb1d
--- /dev/null
+++ b/plugins/paintops/mypaint/kis_my_paintop_settings_widget.h
@@ -0,0 +1,18 @@
+#ifndef KIS_MYPAINTOP_SETTINGS_WIDGET_H_
+#define KIS_MYPAINTOP_SETTINGS_WIDGET_H_
+
+#include
+
+class KisMyPaintOpSettingsWidget : public KisPaintOpSettingsWidget
+{
+ Q_OBJECT
+
+public:
+ KisMyPaintOpSettingsWidget(QWidget* parent = 0);
+ ~KisMyPaintOpSettingsWidget() override;
+
+ KisPropertiesConfigurationSP configuration() const override;
+
+};
+
+#endif
diff --git a/plugins/paintops/mypaint/krita-mypaint.png b/plugins/paintops/mypaint/krita-mypaint.png
new file mode 100644
index 0000000000..8e0a1b77c7
Binary files /dev/null and b/plugins/paintops/mypaint/krita-mypaint.png differ
diff --git a/plugins/paintops/mypaint/kritamypaintop.json b/plugins/paintops/mypaint/kritamypaintop.json
new file mode 100644
index 0000000000..e5355b9358
--- /dev/null
+++ b/plugins/paintops/mypaint/kritamypaintop.json
@@ -0,0 +1,9 @@
+{
+ "Id": "MyPaint Brush",
+ "Type": "Service",
+ "X-KDE-Library": "kritamypaintop",
+ "X-KDE-ServiceTypes": [
+ "Krita/Paintop"
+ ],
+ "X-Krita-Version": "28"
+}
diff --git a/plugins/paintops/mypaint/my_paintop_plugin.cpp b/plugins/paintops/mypaint/my_paintop_plugin.cpp
new file mode 100644
index 0000000000..1ab93c33dc
--- /dev/null
+++ b/plugins/paintops/mypaint/my_paintop_plugin.cpp
@@ -0,0 +1,32 @@
+#include "my_paintop_plugin.h"
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include "kis_my_paintop.h"
+#include "kis_my_paintop_settings.h"
+#include "kis_my_paintop_settings_widget.h"
+#include "kis_simple_paintop_factory.h"
+
+#include "kis_global.h"
+
+K_PLUGIN_FACTORY_WITH_JSON(MyPaintOpPluginFactory, "kritamypaintop.json", registerPlugin();)
+
+
+MyPaintOpPlugin::MyPaintOpPlugin(QObject *parent, const QVariantList &)
+ : QObject(parent)
+{
+ KisPaintOpRegistry *r = KisPaintOpRegistry::instance();
+ r->add(new KisSimplePaintOpFactory("mypaintbrush", i18n("MyPaint"), KisPaintOpFactory::categoryStable() , "krita-mypaint.png", QString(), QStringList(), 6));
+
+}
+
+MyPaintOpPlugin::~MyPaintOpPlugin()
+{
+}
+
+#include "my_paintop_plugin.moc"
diff --git a/plugins/paintops/mypaint/my_paintop_plugin.h b/plugins/paintops/mypaint/my_paintop_plugin.h
new file mode 100644
index 0000000000..2cef13a477
--- /dev/null
+++ b/plugins/paintops/mypaint/my_paintop_plugin.h
@@ -0,0 +1,18 @@
+#ifndef MY_PAINTOP_PLUGIN_H_
+#define MY_PAINTOP_PLUGIN_H_
+
+#include
+#include
+
+/**
+ * A plugin wrapper that adds the paintop factories to the paintop registry.
+ */
+class MyPaintOpPlugin : public QObject
+{
+ Q_OBJECT
+public:
+ MyPaintOpPlugin(QObject *parent, const QVariantList &);
+ ~MyPaintOpPlugin() override;
+};
+
+#endif // MY_PAINTOP_PLUGIN_H_