diff --git a/krita/pics/tools/SVG/16/dark_krita_tool_smart_patch.svg b/krita/pics/tools/SVG/16/dark_krita_tool_smart_patch.svg
new file mode 100644
index 0000000000..749fb5a986
--- /dev/null
+++ b/krita/pics/tools/SVG/16/dark_krita_tool_smart_patch.svg
@@ -0,0 +1,102 @@
+
+
\ No newline at end of file
diff --git a/krita/pics/tools/SVG/16/light_krita_tool_smart_patch.svg b/krita/pics/tools/SVG/16/light_krita_tool_smart_patch.svg
new file mode 100644
index 0000000000..5371092ed9
--- /dev/null
+++ b/krita/pics/tools/SVG/16/light_krita_tool_smart_patch.svg
@@ -0,0 +1,102 @@
+
+
\ No newline at end of file
diff --git a/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc b/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
index f9574cd6a4..f440a8eeb1 100644
--- a/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
+++ b/krita/pics/tools/SVG/16/tools-svg-16-icons.qrc
@@ -1,80 +1,81 @@
dark_calligraphy.svg
dark_draw-text.svg
dark_format-fill-color.svg
dark_krita_draw_path.svg
dark_krita_tool_color_fill.svg
dark_krita_tool_color_picker.svg
dark_krita_tool_dyna.svg
dark_krita_tool_ellipse.svg
dark_krita_tool_freehand.svg
dark_krita_tool_freehandvector.svg
dark_krita_tool_gradient.svg
dark_krita_tool_grid.svg
dark_krita_tool_line.svg
dark_krita_tool_measure.svg
dark_krita_tool_move.svg
dark_krita_tool_multihand.svg
dark_krita_tool_polygon.svg
dark_krita_tool_rectangle.svg
dark_krita_tool_ruler_assistant.svg
dark_krita_tool_transform.svg
dark_pattern.svg
dark_polyline.svg
dark_select.svg
dark_tool_contiguous_selection.svg
dark_tool_crop.svg
dark_tool_elliptical_selection.svg
dark_tool_outline_selection.svg
dark_tool_pan.svg
dark_tool_path_selection.svg
dark_tool_perspectivegrid.svg
dark_tool_polygonal_selection.svg
dark_tool_rect_selection.svg
dark_tool_similar_selection.svg
dark_tool_zoom.svg
light_calligraphy.svg
light_draw-text.svg
light_format-fill-color.svg
light_krita_draw_path.svg
light_krita_tool_color_fill.svg
light_krita_tool_color_picker.svg
light_krita_tool_dyna.svg
light_krita_tool_ellipse.svg
light_krita_tool_freehand.svg
light_krita_tool_freehandvector.svg
light_krita_tool_gradient.svg
light_krita_tool_grid.svg
light_krita_tool_line.svg
light_krita_tool_measure.svg
light_krita_tool_move.svg
light_krita_tool_multihand.svg
light_krita_tool_polygon.svg
light_krita_tool_rectangle.svg
light_krita_tool_ruler_assistant.svg
light_krita_tool_transform.svg
light_pattern.svg
light_polyline.svg
light_select.svg
light_tool_contiguous_selection.svg
light_tool_crop.svg
light_tool_elliptical_selection.svg
light_tool_outline_selection.svg
light_tool_pan.svg
light_tool_path_selection.svg
light_tool_perspectivegrid.svg
light_tool_polygonal_selection.svg
light_tool_rect_selection.svg
light_tool_similar_selection.svg
light_tool_zoom.svg
dark_shape_handling.svg
dark_artistic_text.svg
light_artistic_text.svg
light_shape_handling.svg
dark_krita_tool_lazybrush.svg
light_krita_tool_lazybrush.svg
-
+ dark_krita_tool_smart_patch.svg
+ light_krita_tool_smart_patch.svg
diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt
index 4790fe5ba3..c86431986a 100644
--- a/libs/image/CMakeLists.txt
+++ b/libs/image/CMakeLists.txt
@@ -1,394 +1,395 @@
add_subdirectory( tests )
add_subdirectory( tiles3 )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/metadata
${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_CURRENT_SOURCE_DIR}/recorder
${CMAKE_SOURCE_DIR}/sdk/tests
)
include_directories(SYSTEM
${EIGEN3_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
if(FFTW3_FOUND)
include_directories(${FFTW3_INCLUDE_DIR})
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/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_marker_painter.cpp
kis_progress_updater.cpp
brushengine/kis_paint_information.cc
brushengine/kis_random_source.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_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
commands/kis_deselect_global_selection_command.cpp
commands/kis_image_change_layers_command.cpp
commands/kis_image_command.cpp
commands/kis_image_set_projection_color_space_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_layer_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/kis_set_global_selection_command.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
processing/kis_do_nothing_processing_visitor.cpp
processing/kis_simple_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
filter/kis_filter.cc
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/kis_colorize_mask.cpp
lazybrush/kis_colorize_stroke_strategy.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
kis_clone_info.cpp
kis_clone_layer.cpp
kis_colorspace_convert_visitor.cpp
kis_config_widget.cpp
kis_convolution_kernel.cc
kis_convolution_painter.cc
kis_gaussian_kernel.cpp
kis_cubic_curve.cpp
kis_default_bounds.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
kis_stroke_job_strategy.cpp
kis_stroke_strategy.cpp
kis_stroke.cpp
kis_strokes_queue.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
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
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_signal_compressor.cpp
kis_signal_compressor_with_param.cpp
kis_thread_safe_signal_compressor.cpp
kis_acyclic_signal_connector.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_command_utils.cpp
kis_layer_utils.cpp
kis_mask_projection_plane.cpp
kis_projection_leaf.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
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
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_algebra_2d.cpp
kis_transparency_mask.cc
+ kis_inpaint_mask.cpp
kis_undo_store.cpp
kis_undo_stores.cpp
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
metadata/kis_meta_data_entry.cc
metadata/kis_meta_data_filter.cc
metadata/kis_meta_data_filter_p.cc
metadata/kis_meta_data_filter_registry.cc
metadata/kis_meta_data_filter_registry_model.cc
metadata/kis_meta_data_io_backend.cc
metadata/kis_meta_data_merge_strategy.cc
metadata/kis_meta_data_merge_strategy_p.cc
metadata/kis_meta_data_merge_strategy_registry.cc
metadata/kis_meta_data_parser.cc
metadata/kis_meta_data_schema.cc
metadata/kis_meta_data_schema_registry.cc
metadata/kis_meta_data_store.cc
metadata/kis_meta_data_type_info.cc
metadata/kis_meta_data_validator.cc
metadata/kis_meta_data_value.cc
recorder/kis_action_recorder.cc
recorder/kis_macro.cc
recorder/kis_macro_player.cc
recorder/kis_node_query_path.cc
recorder/kis_play_info.cc
recorder/kis_recorded_action.cc
recorder/kis_recorded_action_factory_registry.cc
recorder/kis_recorded_action_load_context.cpp
recorder/kis_recorded_action_save_context.cpp
recorder/kis_recorded_filter_action.cpp
recorder/kis_recorded_fill_paint_action.cpp
recorder/kis_recorded_node_action.cc
recorder/kis_recorded_paint_action.cpp
recorder/kis_recorded_path_paint_action.cpp
recorder/kis_recorded_shape_paint_action.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
KisProofingConfiguration.cpp
)
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
kritaundo2
kritawidgetutils
Qt5::Concurrent
)
target_link_libraries(kritaimage PUBLIC ${Boost_SYSTEM_LIBRARY})
if(OPENEXR_FOUND)
target_link_libraries(kritaimage PUBLIC ${OPENEXR_LIBRARIES})
endif()
if(FFTW3_FOUND)
target_link_libraries(kritaimage PRIVATE ${FFTW3_LIBRARIES})
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})
########### install schemas #############
install( FILES
metadata/schemas/dc.schema
metadata/schemas/exif.schema
metadata/schemas/tiff.schema
metadata/schemas/mkn.schema
metadata/schemas/xmp.schema
metadata/schemas/xmpmm.schema
metadata/schemas/xmprights.schema
DESTINATION ${DATA_INSTALL_DIR}/krita/metadata/schemas)
diff --git a/libs/image/kis_inpaint_mask.cpp b/libs/image/kis_inpaint_mask.cpp
new file mode 100644
index 0000000000..28f66d533b
--- /dev/null
+++ b/libs/image/kis_inpaint_mask.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 Eugene Ingerman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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_inpaint_mask.h"
+
+#include "kis_debug.h"
+
+#include
+#include
+#include
+#include
+#include
+#include "kis_paint_device.h"
+#include "kis_painter.h"
+#include "kis_node_visitor.h"
+#include "kis_processing_visitor.h"
+
+
+KisInpaintMask::KisInpaintMask()
+ : KisTransparencyMask()
+{
+}
+
+KisInpaintMask::KisInpaintMask(const KisInpaintMask& rhs)
+ : KisTransparencyMask(rhs)
+{
+}
+
+KisInpaintMask::~KisInpaintMask()
+{
+}
+
+QRect KisInpaintMask::decorateRect(KisPaintDeviceSP &src,
+ KisPaintDeviceSP &dst,
+ const QRect & rc,
+ PositionToFilthy maskPos) const
+{
+ Q_UNUSED(maskPos);
+
+ if (src != dst) {
+ KisPainter::copyAreaOptimized(rc.topLeft(), src, dst, rc);
+ src->fill(rc, KoColor(Qt::darkMagenta, src->colorSpace()));
+ }
+
+ return rc;
+}
+
+QRect KisInpaintMask::extent() const
+{
+ return parent() ? parent()->extent() : QRect();
+}
+
+QRect KisInpaintMask::exactBounds() const
+{
+ return parent() ? parent()->exactBounds() : QRect();
+}
+
+QRect KisInpaintMask::changeRect(const QRect &rect, PositionToFilthy pos) const
+{
+ /**
+ * Selection on transparency masks have no special meaning:
+ * They do crop both: change and need area
+ */
+ return KisMask::changeRect(rect, pos);
+}
+
+QRect KisInpaintMask::needRect(const QRect &rect, PositionToFilthy pos) const
+{
+ /**
+ * Selection on transparency masks have no special meaning:
+ * They do crop both: change and need area
+ */
+ return KisMask::needRect(rect, pos);
+}
+
+QIcon KisInpaintMask::icon() const
+{
+ return KisIconUtils::loadIcon("transparencyMask");
+}
+
+bool KisInpaintMask::accept(KisNodeVisitor &v)
+{
+ return v.visit(this);
+}
+
+void KisInpaintMask::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
+{
+ return visitor.visit(this, undoAdapter);
+}
+
diff --git a/libs/image/kis_inpaint_mask.h b/libs/image/kis_inpaint_mask.h
new file mode 100644
index 0000000000..00cfe773a3
--- /dev/null
+++ b/libs/image/kis_inpaint_mask.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Eugene Ingerman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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_INPAINT_MASK_
+#define _KIS_INPAINT_MASK_
+
+#include "kis_types.h"
+#include "kis_transparency_mask.h"
+
+class QRect;
+
+/**
+ * A inpaint mask is a single channel mask that works with inpaint operation to denote area affected by inpaint operation.
+ *
+ */
+class KRITAIMAGE_EXPORT KisInpaintMask : public KisTransparencyMask
+{
+ Q_OBJECT
+
+public:
+
+ KisInpaintMask();
+ KisInpaintMask(const KisInpaintMask& rhs);
+ virtual ~KisInpaintMask();
+
+ KisNodeSP clone() const {
+ return KisNodeSP(new KisInpaintMask(*this));
+ }
+
+ QRect decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst,
+ const QRect & rc,
+ PositionToFilthy maskPos) const;
+ QIcon icon() const;
+ bool accept(KisNodeVisitor &v);
+ void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter);
+
+ QRect extent() const;
+ QRect exactBounds() const;
+
+ QRect changeRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const;
+ QRect needRect(const QRect &rect, PositionToFilthy pos = N_FILTHY) const;
+};
+
+#endif //_KIS_INPAINT_MASK_
diff --git a/libs/ui/kis_mask_manager.cc b/libs/ui/kis_mask_manager.cc
index 5a86188011..8540a72309 100644
--- a/libs/ui/kis_mask_manager.cc
+++ b/libs/ui/kis_mask_manager.cc
@@ -1,307 +1,324 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_mask_manager.h"
#include
#include
#include
#include
#include
#include
#include
#include "KisDocument.h"
#include "KisViewManager.h"
#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include "dialogs/kis_dlg_adjustment_layer.h"
#include "widgets/kis_mask_widgets.h"
#include
#include
#include
#include "dialogs/kis_dlg_adj_layer_props.h"
#include
#include
#include
#include
#include "kis_node_commands_adapter.h"
#include "commands/kis_selection_commands.h"
#include "kis_iterator_ng.h"
KisMaskManager::KisMaskManager(KisViewManager * view)
: m_view(view)
, m_imageView(0)
, m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
{
}
void KisMaskManager::setView(QPointerimageView)
{
m_imageView = imageView;
}
void KisMaskManager::setup(KActionCollection *actionCollection, KisActionManager *actionManager)
{
Q_UNUSED(actionCollection);
Q_UNUSED(actionManager);
}
void KisMaskManager::updateGUI()
{
// XXX: enable/disable menu items according to whether there's a mask selected currently
// XXX: disable the selection mask item if there's already a selection mask
// YYY: doesn't KisAction do that already?
}
KisMaskSP KisMaskManager::activeMask()
{
if (m_imageView) {
return m_imageView->currentMask();
}
return 0;
}
KisPaintDeviceSP KisMaskManager::activeDevice()
{
KisMaskSP mask = activeMask();
return mask ? mask->paintDevice() : 0;
}
void KisMaskManager::activateMask(KisMaskSP mask)
{
Q_UNUSED(mask);
}
void KisMaskManager::masksUpdated()
{
m_view->updateGUI();
}
void KisMaskManager::adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above)
{
Q_ASSERT(node);
Q_ASSERT(activeNode);
if (!avoidActiveNode && activeNode->allowAsChild(node)) {
parent = activeNode;
above = activeNode->lastChild();
} else if (activeNode->parent() && activeNode->parent()->allowAsChild(node)) {
parent = activeNode->parent();
above = activeNode;
} else {
KisNodeSP t = activeNode;
while ((t = t->nextSibling())) {
if (t->allowAsChild(node)) {
parent = t;
above = t->lastChild();
break;
}
}
if (!t) {
t = activeNode;
while ((t = t->prevSibling())) {
if (t->allowAsChild(node)) {
parent = t;
above = t->lastChild();
break;
}
}
}
if (!t && activeNode->parent()) {
adjustMaskPosition(node, activeNode->parent(), true, parent, above);
} else if (!t) {
KisImageWSP image = m_view->image();
KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
m_commandsAdapter->addNode(layer, activeNode, 0);
parent = layer;
above = 0;
}
}
}
void KisMaskManager::createMaskCommon(KisMaskSP mask, KisNodeSP activeNode, KisPaintDeviceSP copyFrom, const KUndo2MagicString& macroName, const QString &nodeType, const QString &nodeName, bool suppressSelection, bool avoidActiveNode, bool updateImage)
{
m_commandsAdapter->beginMacro(macroName);
KisNodeSP parent;
KisNodeSP above;
adjustMaskPosition(mask, activeNode, avoidActiveNode, parent, above);
KisLayerSP parentLayer = qobject_cast(parent.data());
Q_ASSERT(parentLayer);
if (!suppressSelection) {
if (copyFrom) {
mask->initSelection(copyFrom, parentLayer);
} else {
mask->initSelection(m_view->selection(), parentLayer);
}
}
//counting number of KisSelectionMask
QList masks = parentLayer->childNodes(QStringList(nodeType),KoProperties());
int number = masks.count() + 1;
mask->setName(nodeName + QString(" ") + QString::number(number));
m_commandsAdapter->addNode(mask, parentLayer, above, updateImage, updateImage);
m_commandsAdapter->endMacro();
masksUpdated();
}
void KisMaskManager::createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode)
{
KisSelectionMaskSP mask = new KisSelectionMask(m_view->image());
createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Selection Mask"), "KisSelectionMask", i18n("Selection"), false, avoidActiveNode, false);
mask->setActive(true);
}
void KisMaskManager::createTransparencyMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode)
{
KisMaskSP mask = new KisTransparencyMask();
createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Transparency Mask"), "KisTransparencyMask", i18n("Transparency Mask"), false, avoidActiveNode);
}
+void KisMaskManager::createInpaintMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode)
+{
+ KisMaskSP mask = new KisInpaintMask();
+ createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Inpaint Mask"), "KisInpaintMask", i18n("Inpaint Mask"), false, avoidActiveNode);
+}
+
+
void KisMaskManager::createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool avoidActiveNode)
{
KisFilterMaskSP mask = new KisFilterMask();
createMaskCommon(mask, activeNode, copyFrom, kundo2_i18n("Add Filter Mask"), "KisFilterMask", i18n("Filter Mask"), false, avoidActiveNode);
/**
* FIXME: We'll use layer's original for creation of a thumbnail.
* Actually, we can't use it's projection as newly created mask
* may be going to be inserted in the middle of the masks stack
*/
KisPaintDeviceSP originalDevice = mask->parent()->original();
KisDlgAdjustmentLayer dialog(mask, mask.data(), originalDevice,
mask->name(), i18n("New Filter Mask"),
m_view);
// If we are supposed to not disturb the user, don't start asking them about things.
if(quiet) {
KisFilterConfigurationSP filter = KisFilterRegistry::instance()->values().first()->defaultConfiguration();
if (filter) {
mask->setFilter(filter);
mask->setName(mask->name());
}
return;
}
if (dialog.exec() == QDialog::Accepted) {
KisFilterConfigurationSP filter = dialog.filterConfiguration();
if (filter) {
QString name = dialog.layerName();
mask->setFilter(filter);
mask->setName(name);
}
} else {
m_commandsAdapter->undoLastCommand();
}
}
+void KisMaskManager::createEffectsMask(KisNodeSP activeNode)
+{
+ KisFilterMaskSP mask = new KisFilterMask();
+ createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Effect Mask"), "KisEffectMask", i18n("Inpaint Mask"), false, false);
+ mask->setImage(m_view->image());
+}
+
+
void KisMaskManager::createColorizeMask(KisNodeSP activeNode)
{
KisColorizeMaskSP mask = new KisColorizeMask();
createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Colorize Mask"), "KisColorizeMask", i18n("Colorize Mask"), true, false);
mask->setImage(m_view->image());
mask->initializeCompositeOp();
delete mask->setColorSpace(mask->parent()->colorSpace());
}
+
void KisMaskManager::createTransformMask(KisNodeSP activeNode)
{
KisTransformMaskSP mask = new KisTransformMask();
createMaskCommon(mask, activeNode, 0, kundo2_i18n("Add Transform Mask"), "KisTransformMask", i18n("Transform Mask"), true, false);
}
void KisMaskManager::maskProperties()
{
if (!activeMask()) return;
if (activeMask()->inherits("KisFilterMask")) {
KisFilterMask *mask = static_cast(activeMask().data());
KisLayerSP layer = qobject_cast(mask->parent().data());
if (! layer)
return;
KisPaintDeviceSP dev = layer->original();
if (!dev) {
return;
}
KisDlgAdjLayerProps dlg(layer, mask, dev, m_view, mask->filter().data(), mask->name(), i18n("Filter Mask Properties"), m_view->mainWindow(), "dlgeffectmaskprops");
KisFilterConfigurationSP configBefore(mask->filter());
Q_ASSERT(configBefore);
QString xmlBefore = configBefore->toXML();
if (dlg.exec() == QDialog::Accepted) {
KisFilterConfigurationSP configAfter(dlg.filterConfiguration());
Q_ASSERT(configAfter);
QString xmlAfter = configAfter->toXML();
mask->setName(dlg.layerName());
if(xmlBefore != xmlAfter) {
KisChangeFilterCmd *cmd
= new KisChangeFilterCmd(mask,
configBefore->name(),
xmlBefore,
configAfter->name(),
xmlAfter,
false);
// FIXME: check whether is needed
cmd->redo();
m_view->undoAdapter()->addCommand(cmd);
m_view->document()->setModified(true);
}
}
else {
KisFilterConfigurationSP configAfter(dlg.filterConfiguration());
Q_ASSERT(configAfter);
QString xmlAfter = configAfter->toXML();
if(xmlBefore != xmlAfter) {
mask->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data()));
mask->setDirty();
}
}
} else {
// Not much to show for transparency or selection masks?
}
}
diff --git a/libs/ui/kis_mask_manager.h b/libs/ui/kis_mask_manager.h
index 58a16ae562..e72f43501f 100644
--- a/libs/ui/kis_mask_manager.h
+++ b/libs/ui/kis_mask_manager.h
@@ -1,100 +1,102 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_MASK_MANAGER
#define KIS_MASK_MANAGER
#include
#include
#include "kis_types.h"
#include "KisView.h"
class KisViewManager;
class KActionCollection;
class KisNodeCommandsAdapter;
class KisActionManager;
#include "kis_mask.h"
/**
* Handle the gui for manipulating masks.
*/
class KisMaskManager : public QObject
{
Q_OBJECT
public:
KisMaskManager(KisViewManager * view);
~KisMaskManager() {}
void setView(QPointerview);
private:
friend class KisNodeManager;
void setup(KActionCollection * actionCollection, KisActionManager *actionManager);
void updateGUI();
/**
* @return the paint device associated with the currently
* active mask, if there is one.
*/
KisPaintDeviceSP activeDevice();
/**
* @return the active mask, if there is one
*/
KisMaskSP activeMask();
/**
* Show the mask properties dialog
*/
void maskProperties();
/**
* called whenever the mask stack is updated to enable/disable all
* menu items
*/
void masksUpdated();
/**
* Activate a new mask. There can be only one mask active per
* view; and if the mask is active, it becomes the paint device.
*/
void activateMask(KisMaskSP mask);
void adjustMaskPosition(KisNodeSP node, KisNodeSP activeNode, bool avoidActiveNode, KisNodeSP &parent, KisNodeSP &above);
void createMaskCommon(KisMaskSP mask, KisNodeSP activeNode, KisPaintDeviceSP copyFrom, const KUndo2MagicString ¯oName, const QString &nodeType, const QString &nodeName, bool suppressSelection, bool avoidActiveNode, bool updateImage = true);
void createSelectionMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode);
void createFilterMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool quiet, bool avoidActiveNode);
void createColorizeMask(KisNodeSP activeNode);
+ void createEffectsMask(KisNodeSP activeNode);
void createTransformMask(KisNodeSP activeNode);
void createTransparencyMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode);
+ void createInpaintMask(KisNodeSP activeNode, KisPaintDeviceSP copyFrom, bool avoidActiveNode);
KisViewManager * m_view;
QPointerm_imageView;
KisNodeCommandsAdapter* m_commandsAdapter;
};
#endif // KIS_MASK_MANAGER
diff --git a/libs/ui/kis_node_manager.cpp b/libs/ui/kis_node_manager.cpp
index 0cd79fb48b..08e21caa9b 100644
--- a/libs/ui/kis_node_manager.cpp
+++ b/libs/ui/kis_node_manager.cpp
@@ -1,1333 +1,1336 @@
/*
* Copyright (C) 2007 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_node_manager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KisPart.h"
#include "canvas/kis_canvas2.h"
#include "kis_shape_controller.h"
#include "kis_canvas_resource_provider.h"
#include "KisViewManager.h"
#include "KisDocument.h"
#include "kis_mask_manager.h"
#include "kis_group_layer.h"
#include "kis_layer_manager.h"
#include "kis_selection_manager.h"
#include "kis_node_commands_adapter.h"
#include "kis_action.h"
#include "kis_action_manager.h"
#include "kis_processing_applicator.h"
#include "kis_sequential_iterator.h"
#include "kis_transaction.h"
#include "kis_node_selection_adapter.h"
#include "kis_node_insertion_adapter.h"
#include "kis_node_juggler_compressed.h"
#include "kis_clipboard.h"
#include "kis_node_dummies_graph.h"
#include "kis_mimedata.h"
#include "kis_layer_utils.h"
#include "krita_utils.h"
#include "processing/kis_mirror_processing_visitor.h"
#include "KisView.h"
struct KisNodeManager::Private {
Private(KisNodeManager *_q, KisViewManager *v)
: q(_q)
, view(v)
, imageView(0)
, layerManager(v)
, maskManager(v)
, commandsAdapter(v)
, nodeSelectionAdapter(new KisNodeSelectionAdapter(q))
, nodeInsertionAdapter(new KisNodeInsertionAdapter(q))
{
}
KisNodeManager * q;
KisViewManager * view;
QPointerimageView;
KisLayerManager layerManager;
KisMaskManager maskManager;
KisNodeCommandsAdapter commandsAdapter;
QScopedPointer nodeSelectionAdapter;
QScopedPointer nodeInsertionAdapter;
KisNodeList selectedNodes;
QPointer nodeJuggler;
KisNodeWSP previouslyActiveNode;
bool activateNodeImpl(KisNodeSP node);
QSignalMapper nodeCreationSignalMapper;
QSignalMapper nodeConversionSignalMapper;
void saveDeviceAsImage(KisPaintDeviceSP device,
const QString &defaultName,
const QRect &bounds,
qreal xRes,
qreal yRes,
quint8 opacity);
void mergeTransparencyMaskAsAlpha(bool writeToLayers);
KisNodeJugglerCompressed* lazyGetJuggler(const KUndo2MagicString &actionName);
};
bool KisNodeManager::Private::activateNodeImpl(KisNodeSP node)
{
Q_ASSERT(view);
Q_ASSERT(view->canvasBase());
Q_ASSERT(view->canvasBase()->globalShapeManager());
Q_ASSERT(imageView);
if (node && node == q->activeNode()) {
return false;
}
// Set the selection on the shape manager to the active layer
// and set call KoSelection::setActiveLayer( KoShapeLayer* layer )
// with the parent of the active layer.
KoSelection *selection = view->canvasBase()->globalShapeManager()->selection();
Q_ASSERT(selection);
selection->deselectAll();
if (!node) {
selection->setActiveLayer(0);
imageView->setCurrentNode(0);
maskManager.activateMask(0);
layerManager.activateLayer(0);
previouslyActiveNode = q->activeNode();
} else {
previouslyActiveNode = q->activeNode();
KoShape * shape = view->document()->shapeForNode(node);
KIS_ASSERT_RECOVER_RETURN_VALUE(shape, false);
selection->select(shape);
KoShapeLayer * shapeLayer = dynamic_cast(shape);
KIS_ASSERT_RECOVER_RETURN_VALUE(shapeLayer, false);
// shapeLayer->setGeometryProtected(node->userLocked());
// shapeLayer->setVisible(node->visible());
selection->setActiveLayer(shapeLayer);
imageView->setCurrentNode(node);
if (KisLayerSP layer = qobject_cast(node.data())) {
maskManager.activateMask(0);
layerManager.activateLayer(layer);
} else if (KisMaskSP mask = dynamic_cast(node.data())) {
maskManager.activateMask(mask);
// XXX_NODE: for now, masks cannot be nested.
layerManager.activateLayer(static_cast(node->parent().data()));
}
}
return true;
}
KisNodeManager::KisNodeManager(KisViewManager *view)
: m_d(new Private(this, view))
{
connect(&m_d->layerManager, SIGNAL(sigLayerActivated(KisLayerSP)), SIGNAL(sigLayerActivated(KisLayerSP)));
}
KisNodeManager::~KisNodeManager()
{
delete m_d;
}
void KisNodeManager::setView(QPointerimageView)
{
m_d->maskManager.setView(imageView);
m_d->layerManager.setView(imageView);
if (m_d->imageView) {
KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController());
Q_ASSERT(shapeController);
shapeController->disconnect(SIGNAL(sigActivateNode(KisNodeSP)), this);
m_d->imageView->image()->disconnect(this);
}
m_d->imageView = imageView;
if (m_d->imageView) {
KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController());
Q_ASSERT(shapeController);
connect(shapeController, SIGNAL(sigActivateNode(KisNodeSP)), SLOT(slotNonUiActivatedNode(KisNodeSP)));
connect(m_d->imageView->image(), SIGNAL(sigIsolatedModeChanged()),this, SLOT(slotUpdateIsolateModeAction()));
connect(m_d->imageView->image(), SIGNAL(sigRequestNodeReselection(KisNodeSP, const KisNodeList&)),this, SLOT(slotImageRequestNodeReselection(KisNodeSP, const KisNodeList&)));
m_d->imageView->resourceProvider()->slotNodeActivated(m_d->imageView->currentNode());
}
}
#define NEW_LAYER_ACTION(id, layerType) \
{ \
action = actionManager->createAction(id); \
m_d->nodeCreationSignalMapper.setMapping(action, layerType); \
connect(action, SIGNAL(triggered()), \
&m_d->nodeCreationSignalMapper, SLOT(map())); \
}
#define CONVERT_NODE_ACTION_2(id, layerType, exclude) \
{ \
action = actionManager->createAction(id); \
action->setExcludedNodeTypes(QStringList(exclude)); \
actionManager->addAction(id, action); \
m_d->nodeConversionSignalMapper.setMapping(action, layerType); \
connect(action, SIGNAL(triggered()), \
&m_d->nodeConversionSignalMapper, SLOT(map())); \
}
#define CONVERT_NODE_ACTION(id, layerType) \
CONVERT_NODE_ACTION_2(id, layerType, layerType)
void KisNodeManager::setup(KActionCollection * actionCollection, KisActionManager* actionManager)
{
m_d->layerManager.setup(actionManager);
m_d->maskManager.setup(actionCollection, actionManager);
KisAction * action = actionManager->createAction("mirrorNodeX");
connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeX()));
action = actionManager->createAction("mirrorNodeY");
connect(action, SIGNAL(triggered()), this, SLOT(mirrorNodeY()));
action = actionManager->createAction("activateNextLayer");
connect(action, SIGNAL(triggered()), this, SLOT(activateNextNode()));
action = actionManager->createAction("activatePreviousLayer");
connect(action, SIGNAL(triggered()), this, SLOT(activatePreviousNode()));
action = actionManager->createAction("switchToPreviouslyActiveNode");
connect(action, SIGNAL(triggered()), this, SLOT(switchToPreviouslyActiveNode()));
action = actionManager->createAction("save_node_as_image");
connect(action, SIGNAL(triggered()), this, SLOT(saveNodeAsImage()));
action = actionManager->createAction("duplicatelayer");
connect(action, SIGNAL(triggered()), this, SLOT(duplicateActiveNode()));
action = actionManager->createAction("copy_layer_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(copyLayersToClipboard()));
action = actionManager->createAction("cut_layer_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(cutLayersToClipboard()));
action = actionManager->createAction("paste_layer_from_clipboard");
connect(action, SIGNAL(triggered()), this, SLOT(pasteLayersFromClipboard()));
action = actionManager->createAction("create_quick_group");
connect(action, SIGNAL(triggered()), this, SLOT(createQuickGroup()));
action = actionManager->createAction("create_quick_clipping_group");
connect(action, SIGNAL(triggered()), this, SLOT(createQuickClippingGroup()));
action = actionManager->createAction("quick_ungroup");
connect(action, SIGNAL(triggered()), this, SLOT(quickUngroup()));
action = actionManager->createAction("select_all_layers");
connect(action, SIGNAL(triggered()), this, SLOT(selectAllNodes()));
action = actionManager->createAction("select_visible_layers");
connect(action, SIGNAL(triggered()), this, SLOT(selectVisibleNodes()));
action = actionManager->createAction("select_locked_layers");
connect(action, SIGNAL(triggered()), this, SLOT(selectLockedNodes()));
action = actionManager->createAction("select_invisible_layers");
connect(action, SIGNAL(triggered()), this, SLOT(selectInvisibleNodes()));
action = actionManager->createAction("select_unlocked_layers");
connect(action, SIGNAL(triggered()), this, SLOT(selectUnlockedNodes()));
action = actionManager->createAction("new_from_visible");
connect(action, SIGNAL(triggered()), this, SLOT(createFromVisible()));
NEW_LAYER_ACTION("add_new_paint_layer", "KisPaintLayer");
NEW_LAYER_ACTION("add_new_group_layer", "KisGroupLayer");
NEW_LAYER_ACTION("add_new_clone_layer", "KisCloneLayer");
NEW_LAYER_ACTION("add_new_shape_layer", "KisShapeLayer");
NEW_LAYER_ACTION("add_new_adjustment_layer", "KisAdjustmentLayer");
NEW_LAYER_ACTION("add_new_fill_layer", "KisGeneratorLayer");
NEW_LAYER_ACTION("add_new_file_layer", "KisFileLayer");
NEW_LAYER_ACTION("add_new_transparency_mask", "KisTransparencyMask");
NEW_LAYER_ACTION("add_new_filter_mask", "KisFilterMask");
NEW_LAYER_ACTION("add_new_colorize_mask", "KisColorizeMask");
NEW_LAYER_ACTION("add_new_transform_mask", "KisTransformMask");
NEW_LAYER_ACTION("add_new_selection_mask", "KisSelectionMask");
connect(&m_d->nodeCreationSignalMapper, SIGNAL(mapped(const QString &)),
this, SLOT(createNode(const QString &)));
CONVERT_NODE_ACTION("convert_to_paint_layer", "KisPaintLayer");
CONVERT_NODE_ACTION_2("convert_to_selection_mask", "KisSelectionMask", QStringList() << "KisSelectionMask" << "KisColorizeMask");
CONVERT_NODE_ACTION_2("convert_to_filter_mask", "KisFilterMask", QStringList() << "KisFilterMask" << "KisColorizeMask");
CONVERT_NODE_ACTION_2("convert_to_transparency_mask", "KisTransparencyMask", QStringList() << "KisTransparencyMask" << "KisColorizeMask");
CONVERT_NODE_ACTION("convert_to_animated", "animated");
connect(&m_d->nodeConversionSignalMapper, SIGNAL(mapped(const QString &)),
this, SLOT(convertNode(const QString &)));
action = actionManager->createAction("isolate_layer");
connect(action, SIGNAL(triggered(bool)), this, SLOT(toggleIsolateMode(bool)));
action = actionManager->createAction("split_alpha_into_mask");
connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaIntoMask()));
action = actionManager->createAction("split_alpha_write");
connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaWrite()));
// HINT: we can save even when the nodes are not editable
action = actionManager->createAction("split_alpha_save_merged");
connect(action, SIGNAL(triggered()), this, SLOT(slotSplitAlphaSaveMerged()));
connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(slotUpdateIsolateModeAction()));
connect(this, SIGNAL(sigNodeActivated(KisNodeSP)), SLOT(slotTryFinishIsolatedMode()));
}
void KisNodeManager::updateGUI()
{
// enable/disable all relevant actions
m_d->layerManager.updateGUI();
m_d->maskManager.updateGUI();
}
KisNodeSP KisNodeManager::activeNode()
{
if (m_d->imageView) {
return m_d->imageView->currentNode();
}
return 0;
}
KisLayerSP KisNodeManager::activeLayer()
{
return m_d->layerManager.activeLayer();
}
const KoColorSpace* KisNodeManager::activeColorSpace()
{
if (m_d->maskManager.activeDevice()) {
return m_d->maskManager.activeDevice()->colorSpace();
} else {
Q_ASSERT(m_d->layerManager.activeLayer());
if (m_d->layerManager.activeLayer()->parentLayer())
return m_d->layerManager.activeLayer()->parentLayer()->colorSpace();
else
return m_d->view->image()->colorSpace();
}
}
void KisNodeManager::moveNodeAt(KisNodeSP node, KisNodeSP parent, int index)
{
if (parent->allowAsChild(node)) {
if (node->inherits("KisSelectionMask") && parent->inherits("KisLayer")) {
KisSelectionMask *m = dynamic_cast(node.data());
KisLayer *l = qobject_cast(parent.data());
KisSelectionMaskSP selMask = l->selectionMask();
if (m && m->active() && l && l->selectionMask())
selMask->setActive(false);
}
m_d->commandsAdapter.moveNode(node, parent, index);
}
}
void KisNodeManager::moveNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
KUndo2MagicString actionName = kundo2_i18n("Move Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->moveNode(nodes, parent, aboveThis);
}
void KisNodeManager::copyNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
KUndo2MagicString actionName = kundo2_i18n("Copy Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->copyNode(nodes, parent, aboveThis);
}
void KisNodeManager::addNodesDirect(KisNodeList nodes, KisNodeSP parent, KisNodeSP aboveThis)
{
KUndo2MagicString actionName = kundo2_i18n("Add Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->addNode(nodes, parent, aboveThis);
}
void KisNodeManager::toggleIsolateActiveNode()
{
KisImageWSP image = m_d->view->image();
KisNodeSP activeNode = this->activeNode();
KIS_ASSERT_RECOVER_RETURN(activeNode);
if (activeNode == image->isolatedModeRoot()) {
toggleIsolateMode(false);
} else {
toggleIsolateMode(true);
}
}
void KisNodeManager::toggleIsolateMode(bool checked)
{
KisImageWSP image = m_d->view->image();
if (checked) {
KisNodeSP activeNode = this->activeNode();
// Transform and colorize masks don't have pixel data...
if (activeNode->inherits("KisTransformMask") ||
activeNode->inherits("KisColorizeMask")) return;
KIS_ASSERT_RECOVER_RETURN(activeNode);
if (!image->startIsolatedMode(activeNode)) {
KisAction *action = m_d->view->actionManager()->actionByName("isolate_layer");
action->setChecked(false);
}
} else {
image->stopIsolatedMode();
}
}
void KisNodeManager::slotUpdateIsolateModeAction()
{
KisAction *action = m_d->view->actionManager()->actionByName("isolate_layer");
Q_ASSERT(action);
KisNodeSP activeNode = this->activeNode();
KisNodeSP isolatedRootNode = m_d->view->image()->isolatedModeRoot();
action->setChecked(isolatedRootNode && isolatedRootNode == activeNode);
}
void KisNodeManager::slotTryFinishIsolatedMode()
{
KisNodeSP isolatedRootNode = m_d->view->image()->isolatedModeRoot();
if (!isolatedRootNode) return;
this->toggleIsolateMode(true);
}
void KisNodeManager::createNode(const QString & nodeType, bool quiet, KisPaintDeviceSP copyFrom)
{
KisNodeSP activeNode = this->activeNode();
if (!activeNode) {
activeNode = m_d->view->image()->root();
}
KIS_ASSERT_RECOVER_RETURN(activeNode);
if (activeNode->systemLocked()) {
return;
}
// XXX: make factories for this kind of stuff,
// with a registry
if (nodeType == "KisPaintLayer") {
m_d->layerManager.addLayer(activeNode);
} else if (nodeType == "KisGroupLayer") {
m_d->layerManager.addGroupLayer(activeNode);
} else if (nodeType == "KisAdjustmentLayer") {
m_d->layerManager.addAdjustmentLayer(activeNode);
} else if (nodeType == "KisGeneratorLayer") {
m_d->layerManager.addGeneratorLayer(activeNode);
} else if (nodeType == "KisShapeLayer") {
m_d->layerManager.addShapeLayer(activeNode);
} else if (nodeType == "KisCloneLayer") {
m_d->layerManager.addCloneLayer(activeNode);
} else if (nodeType == "KisTransparencyMask") {
m_d->maskManager.createTransparencyMask(activeNode, copyFrom, false);
} else if (nodeType == "KisFilterMask") {
m_d->maskManager.createFilterMask(activeNode, copyFrom, quiet, false);
} else if (nodeType == "KisColorizeMask") {
m_d->maskManager.createColorizeMask(activeNode);
} else if (nodeType == "KisTransformMask") {
m_d->maskManager.createTransformMask(activeNode);
} else if (nodeType == "KisSelectionMask") {
m_d->maskManager.createSelectionMask(activeNode, copyFrom, false);
} else if (nodeType == "KisFileLayer") {
m_d->layerManager.addFileLayer(activeNode);
+ } else if (nodeType == "KisInpaintMask") {
+ m_d->maskManager.createInpaintMask(activeNode, copyFrom, false);
+ //m_d->maskManager.createEffectsMask( activeNode );
}
}
void KisNodeManager::createFromVisible()
{
KisLayerUtils::newLayerFromVisible(m_d->view->image(), m_d->view->image()->root()->lastChild());
}
KisLayerSP KisNodeManager::createPaintLayer()
{
KisNodeSP activeNode = this->activeNode();
if (!activeNode) {
activeNode = m_d->view->image()->root();
}
return m_d->layerManager.addLayer(activeNode);
}
void KisNodeManager::convertNode(const QString &nodeType)
{
KisNodeSP activeNode = this->activeNode();
if (!activeNode) return;
if (nodeType == "KisPaintLayer") {
m_d->layerManager.convertNodeToPaintLayer(activeNode);
} else if (nodeType == "KisSelectionMask" ||
nodeType == "KisFilterMask" ||
nodeType == "KisTransparencyMask") {
KisPaintDeviceSP copyFrom = activeNode->paintDevice() ?
activeNode->paintDevice() : activeNode->projection();
m_d->commandsAdapter.beginMacro(kundo2_i18n("Convert to a Selection Mask"));
if (nodeType == "KisSelectionMask") {
m_d->maskManager.createSelectionMask(activeNode, copyFrom, true);
} else if (nodeType == "KisFilterMask") {
m_d->maskManager.createFilterMask(activeNode, copyFrom, false, true);
} else if (nodeType == "KisTransparencyMask") {
m_d->maskManager.createTransparencyMask(activeNode, copyFrom, true);
}
m_d->commandsAdapter.removeNode(activeNode);
m_d->commandsAdapter.endMacro();
} else {
warnKrita << "Unsupported node conversion type:" << nodeType;
}
}
void KisNodeManager::slotSomethingActivatedNodeImpl(KisNodeSP node)
{
KIS_ASSERT_RECOVER_RETURN(node != activeNode());
if (m_d->activateNodeImpl(node)) {
emit sigUiNeedChangeActiveNode(node);
emit sigNodeActivated(node);
nodesUpdated();
if (node) {
bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked();
if (toggled) {
m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine);
}
}
}
}
void KisNodeManager::slotNonUiActivatedNode(KisNodeSP node)
{
if (node == activeNode()) return;
slotSomethingActivatedNodeImpl(node);
if (node) {
bool toggled = m_d->view->actionCollection()->action("view_show_canvas_only")->isChecked();
if (toggled) {
m_d->view->showFloatingMessage( activeLayer()->name(), QIcon(), 1600, KisFloatingMessage::Medium, Qt::TextSingleLine);
}
}
}
void KisNodeManager::slotUiActivatedNode(KisNodeSP node)
{
if (node == activeNode()) return;
slotSomethingActivatedNodeImpl(node);
if (node) {
QStringList vectorTools = QStringList()
<< "InteractionTool"
<< "KarbonPatternTool"
<< "KarbonGradientTool"
<< "KarbonCalligraphyTool"
<< "CreateShapesTool"
<< "PathTool";
QStringList pixelTools = QStringList()
<< "KritaShape/KisToolBrush"
<< "KritaShape/KisToolDyna"
<< "KritaShape/KisToolMultiBrush"
<< "KritaFill/KisToolFill"
<< "KritaFill/KisToolGradient";
if (node->inherits("KisShapeLayer")) {
if (pixelTools.contains(KoToolManager::instance()->activeToolId())) {
KoToolManager::instance()->switchToolRequested("InteractionTool");
}
}
else {
if (vectorTools.contains(KoToolManager::instance()->activeToolId())) {
KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush");
}
}
}
}
void KisNodeManager::nodesUpdated()
{
KisNodeSP node = activeNode();
if (!node) return;
m_d->layerManager.layersUpdated();
m_d->maskManager.masksUpdated();
m_d->view->updateGUI();
m_d->view->selectionManager()->selectionChanged();
}
KisPaintDeviceSP KisNodeManager::activePaintDevice()
{
return m_d->maskManager.activeMask() ?
m_d->maskManager.activeDevice() :
m_d->layerManager.activeDevice();
}
void KisNodeManager::nodeProperties(KisNodeSP node)
{
if (selectedNodes().size() > 1 || node->inherits("KisLayer")) {
m_d->layerManager.layerProperties();
} else if (node->inherits("KisMask")) {
m_d->maskManager.maskProperties();
}
}
qint32 KisNodeManager::convertOpacityToInt(qreal opacity)
{
/**
* Scales opacity from the range 0...100
* to the integer range 0...255
*/
return qMin(255, int(opacity * 2.55 + 0.5));
}
void KisNodeManager::setNodeOpacity(KisNodeSP node, qint32 opacity,
bool finalChange)
{
if (!node) return;
if (node->opacity() == opacity) return;
if (!finalChange) {
node->setOpacity(opacity);
node->setDirty();
} else {
m_d->commandsAdapter.setOpacity(node, opacity);
}
}
void KisNodeManager::setNodeCompositeOp(KisNodeSP node,
const KoCompositeOp* compositeOp)
{
if (!node) return;
if (node->compositeOp() == compositeOp) return;
m_d->commandsAdapter.setCompositeOp(node, compositeOp);
}
void KisNodeManager::slotImageRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes)
{
if (activeNode) {
slotNonUiActivatedNode(activeNode);
}
if (!selectedNodes.isEmpty()) {
slotSetSelectedNodes(selectedNodes);
}
}
void KisNodeManager::slotSetSelectedNodes(const KisNodeList &nodes)
{
m_d->selectedNodes = nodes;
emit sigUiNeedChangeSelectedNodes(nodes);
}
KisNodeList KisNodeManager::selectedNodes()
{
return m_d->selectedNodes;
}
KisNodeSelectionAdapter* KisNodeManager::nodeSelectionAdapter() const
{
return m_d->nodeSelectionAdapter.data();
}
KisNodeInsertionAdapter* KisNodeManager::nodeInsertionAdapter() const
{
return m_d->nodeInsertionAdapter.data();
}
void KisNodeManager::nodeOpacityChanged(qreal opacity, bool finalChange)
{
KisNodeSP node = activeNode();
setNodeOpacity(node, convertOpacityToInt(opacity), finalChange);
}
void KisNodeManager::nodeCompositeOpChanged(const KoCompositeOp* op)
{
KisNodeSP node = activeNode();
setNodeCompositeOp(node, op);
}
void KisNodeManager::duplicateActiveNode()
{
KUndo2MagicString actionName = kundo2_i18n("Duplicate Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->duplicateNode(selectedNodes());
}
KisNodeJugglerCompressed* KisNodeManager::Private::lazyGetJuggler(const KUndo2MagicString &actionName)
{
KisImageWSP image = view->image();
if (!nodeJuggler ||
(nodeJuggler &&
!nodeJuggler->canMergeAction(actionName))) {
nodeJuggler = new KisNodeJugglerCompressed(actionName, image, q, 750);
nodeJuggler->setAutoDelete(true);
}
return nodeJuggler;
}
void KisNodeManager::raiseNode()
{
KUndo2MagicString actionName = kundo2_i18n("Raise Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->raiseNode(selectedNodes());
}
void KisNodeManager::lowerNode()
{
KUndo2MagicString actionName = kundo2_i18n("Lower Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->lowerNode(selectedNodes());
}
void KisNodeManager::removeSingleNode(KisNodeSP node)
{
if (!node || !node->parent()) {
return;
}
KisNodeList nodes;
nodes << node;
removeSelectedNodes(nodes);
}
void KisNodeManager::removeSelectedNodes(KisNodeList nodes)
{
KUndo2MagicString actionName = kundo2_i18n("Remove Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->removeNode(nodes);
}
void KisNodeManager::removeNode()
{
removeSelectedNodes(selectedNodes());
}
void KisNodeManager::mirrorNodeX()
{
KisNodeSP node = activeNode();
KUndo2MagicString commandName;
if (node->inherits("KisLayer")) {
commandName = kundo2_i18n("Mirror Layer X");
} else if (node->inherits("KisMask")) {
commandName = kundo2_i18n("Mirror Mask X");
}
mirrorNode(node, commandName, Qt::Horizontal);
}
void KisNodeManager::mirrorNodeY()
{
KisNodeSP node = activeNode();
KUndo2MagicString commandName;
if (node->inherits("KisLayer")) {
commandName = kundo2_i18n("Mirror Layer Y");
} else if (node->inherits("KisMask")) {
commandName = kundo2_i18n("Mirror Mask Y");
}
mirrorNode(node, commandName, Qt::Vertical);
}
inline bool checkForGlobalSelection(KisNodeSP node) {
return dynamic_cast(node.data()) && node->parent() && !node->parent()->parent();
}
void KisNodeManager::activateNextNode()
{
KisNodeSP activeNode = this->activeNode();
if (!activeNode) return;
KisNodeSP node = activeNode->nextSibling();
while (node && node->childCount() > 0) {
node = node->firstChild();
}
if (!node && activeNode->parent() && activeNode->parent()->parent()) {
node = activeNode->parent();
}
while(node && checkForGlobalSelection(node)) {
node = node->nextSibling();
}
if (node) {
slotNonUiActivatedNode(node);
}
}
void KisNodeManager::activatePreviousNode()
{
KisNodeSP activeNode = this->activeNode();
if (!activeNode) return;
KisNodeSP node;
if (activeNode->childCount() > 0) {
node = activeNode->lastChild();
}
else {
node = activeNode->prevSibling();
}
while (!node && activeNode->parent()) {
node = activeNode->parent()->prevSibling();
activeNode = activeNode->parent();
}
while(node && checkForGlobalSelection(node)) {
node = node->prevSibling();
}
if (node) {
slotNonUiActivatedNode(node);
}
}
void KisNodeManager::switchToPreviouslyActiveNode()
{
if (m_d->previouslyActiveNode && m_d->previouslyActiveNode->parent()) {
slotNonUiActivatedNode(m_d->previouslyActiveNode);
}
}
void KisNodeManager::mergeLayer()
{
m_d->layerManager.mergeLayer();
}
void KisNodeManager::rotate(double radians)
{
// XXX: implement rotation for masks as well
m_d->layerManager.rotateLayer(radians);
}
void KisNodeManager::rotate180()
{
rotate(M_PI);
}
void KisNodeManager::rotateLeft90()
{
rotate(-M_PI / 2);
}
void KisNodeManager::rotateRight90()
{
rotate(M_PI / 2);
}
void KisNodeManager::shear(double angleX, double angleY)
{
// XXX: implement shear for masks as well
m_d->layerManager.shearLayer(angleX, angleY);
}
void KisNodeManager::scale(double sx, double sy, KisFilterStrategy *filterStrategy)
{
KisNodeSP node = activeNode();
KIS_ASSERT_RECOVER_RETURN(node);
m_d->view->image()->scaleNode(node, sx, sy, filterStrategy);
nodesUpdated();
}
void KisNodeManager::mirrorNode(KisNodeSP node, const KUndo2MagicString& actionName, Qt::Orientation orientation)
{
KisImageSignalVector emitSignals;
emitSignals << ModifiedSignal;
KisProcessingApplicator applicator(m_d->view->image(), node,
KisProcessingApplicator::RECURSIVE,
emitSignals, actionName);
KisProcessingVisitorSP visitor =
new KisMirrorProcessingVisitor(m_d->view->image()->bounds(), orientation);
applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT);
applicator.end();
nodesUpdated();
}
void KisNodeManager::Private::saveDeviceAsImage(KisPaintDeviceSP device,
const QString &defaultName,
const QRect &bounds,
qreal xRes,
qreal yRes,
quint8 opacity)
{
KoFileDialog dialog(view->mainWindow(), KoFileDialog::SaveFile, "savenodeasimage");
dialog.setCaption(i18n("Export \"%1\"", defaultName));
dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Export));
QString filename = dialog.filename();
if (filename.isEmpty()) return;
QUrl url = QUrl::fromLocalFile(filename);
if (url.isEmpty()) return;
QString mimefilter = KisMimeDatabase::mimeTypeForFile(filename);;
QScopedPointer d(KisPart::instance()->createDocument());
KisImageSP dst = new KisImage(d->createUndoStore(),
bounds.width(),
bounds.height(),
device->compositionSourceColorSpace(),
defaultName);
dst->setResolution(xRes, yRes);
d->setCurrentImage(dst);
KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", opacity);
paintLayer->paintDevice()->makeCloneFrom(device, bounds);
dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0));
dst->initialRefreshGraph();
d->setOutputMimeType(mimefilter.toLatin1());
d->exportDocument(url);
}
void KisNodeManager::saveNodeAsImage()
{
KisNodeSP node = activeNode();
if (!node) {
warnKrita << "BUG: Save Node As Image was called without any node selected";
return;
}
KisImageWSP image = m_d->view->image();
QRect saveRect = image->bounds() | node->exactBounds();
KisPaintDeviceSP device = node->paintDevice();
if (!device) {
device = node->projection();
}
m_d->saveDeviceAsImage(device, node->name(),
saveRect,
image->xRes(), image->yRes(),
node->opacity());
}
void KisNodeManager::slotSplitAlphaIntoMask()
{
KisNodeSP node = activeNode();
// guaranteed by KisActionManager
KIS_ASSERT_RECOVER_RETURN(node->hasEditablePaintDevice());
KisPaintDeviceSP srcDevice = node->paintDevice();
const KoColorSpace *srcCS = srcDevice->colorSpace();
const QRect processRect =
srcDevice->exactBounds() |
srcDevice->defaultBounds()->bounds();
KisPaintDeviceSP selectionDevice =
new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
m_d->commandsAdapter.beginMacro(kundo2_i18n("Split Alpha into a Mask"));
KisTransaction transaction(kundo2_noi18n("__split_alpha_channel__"), srcDevice);
KisSequentialIterator srcIt(srcDevice, processRect);
KisSequentialIterator dstIt(selectionDevice, processRect);
do {
quint8 *srcPtr = srcIt.rawData();
quint8 *alpha8Ptr = dstIt.rawData();
*alpha8Ptr = srcCS->opacityU8(srcPtr);
srcCS->setOpacity(srcPtr, OPACITY_OPAQUE_U8, 1);
} while (srcIt.nextPixel() && dstIt.nextPixel());
m_d->commandsAdapter.addExtraCommand(transaction.endAndTake());
createNode("KisTransparencyMask", false, selectionDevice);
m_d->commandsAdapter.endMacro();
}
void KisNodeManager::Private::mergeTransparencyMaskAsAlpha(bool writeToLayers)
{
KisNodeSP node = q->activeNode();
KisNodeSP parentNode = node->parent();
// guaranteed by KisActionManager
KIS_ASSERT_RECOVER_RETURN(node->inherits("KisTransparencyMask"));
if (writeToLayers && !parentNode->hasEditablePaintDevice()) {
QMessageBox::information(view->mainWindow(),
i18nc("@title:window", "Layer %1 is not editable").arg(parentNode->name()),
i18n("Cannot write alpha channel of "
"the parent layer \"%1\".\n"
"The operation will be cancelled.").arg(parentNode->name()));
return;
}
KisPaintDeviceSP dstDevice;
if (writeToLayers) {
KIS_ASSERT_RECOVER_RETURN(parentNode->paintDevice());
dstDevice = parentNode->paintDevice();
} else {
KisPaintDeviceSP copyDevice = parentNode->paintDevice();
if (!copyDevice) {
copyDevice = parentNode->original();
}
dstDevice = new KisPaintDevice(*copyDevice);
}
const KoColorSpace *dstCS = dstDevice->colorSpace();
KisPaintDeviceSP selectionDevice = node->paintDevice();
KIS_ASSERT_RECOVER_RETURN(selectionDevice->colorSpace()->pixelSize() == 1);
const QRect processRect =
selectionDevice->exactBounds() |
dstDevice->exactBounds() |
selectionDevice->defaultBounds()->bounds();
QScopedPointer transaction;
if (writeToLayers) {
commandsAdapter.beginMacro(kundo2_i18n("Write Alpha into a Layer"));
transaction.reset(new KisTransaction(kundo2_noi18n("__write_alpha_channel__"), dstDevice));
}
KisSequentialIterator srcIt(selectionDevice, processRect);
KisSequentialIterator dstIt(dstDevice, processRect);
do {
quint8 *alpha8Ptr = srcIt.rawData();
quint8 *dstPtr = dstIt.rawData();
dstCS->setOpacity(dstPtr, *alpha8Ptr, 1);
} while (srcIt.nextPixel() && dstIt.nextPixel());
if (writeToLayers) {
commandsAdapter.addExtraCommand(transaction->endAndTake());
commandsAdapter.removeNode(node);
commandsAdapter.endMacro();
} else {
KisImageWSP image = view->image();
QRect saveRect = image->bounds();
saveDeviceAsImage(dstDevice, parentNode->name(),
saveRect,
image->xRes(), image->yRes(),
OPACITY_OPAQUE_U8);
}
}
void KisNodeManager::slotSplitAlphaWrite()
{
m_d->mergeTransparencyMaskAsAlpha(true);
}
void KisNodeManager::slotSplitAlphaSaveMerged()
{
m_d->mergeTransparencyMaskAsAlpha(false);
}
void KisNodeManager::cutLayersToClipboard()
{
KisNodeList nodes = this->selectedNodes();
KisNodeSP root = m_d->view->image()->root();
if (nodes.isEmpty()) return;
KisClipboard::instance()->setLayers(nodes, root, false);
KUndo2MagicString actionName = kundo2_i18n("Cut Nodes");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->removeNode(nodes);
}
void KisNodeManager::copyLayersToClipboard()
{
KisNodeList nodes = this->selectedNodes();
KisNodeSP root = m_d->view->image()->root();
KisClipboard::instance()->setLayers(nodes, root, true);
}
void KisNodeManager::pasteLayersFromClipboard()
{
const QMimeData *data = KisClipboard::instance()->layersMimeData();
if (!data) return;
KisNodeSP activeNode = this->activeNode();
KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController());
Q_ASSERT(shapeController);
KisDummiesFacadeBase *dummiesFacade = dynamic_cast(m_d->imageView->document()->shapeController());
Q_ASSERT(dummiesFacade);
const bool copyNode = false;
KisImageSP image = m_d->view->image();
KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode);
KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0;
KisMimeData::insertMimeLayers(data,
image,
shapeController,
parentDummy,
aboveThisDummy,
copyNode,
nodeInsertionAdapter());
}
void KisNodeManager::createQuickGroupImpl(KisNodeJugglerCompressed *juggler,
const QString &overrideGroupName,
KisNodeSP *newGroup,
KisNodeSP *newLastChild)
{
KisNodeSP active = activeNode();
if (!active) return;
KisImageSP image = m_d->view->image();
QString groupName = !overrideGroupName.isEmpty() ? overrideGroupName : image->nextLayerName();
KisGroupLayerSP group = new KisGroupLayer(image.data(), groupName, OPACITY_OPAQUE_U8);
KisNodeList nodes1;
nodes1 << group;
KisNodeList nodes2;
nodes2 = KisLayerUtils::sortMergableNodes(image->root(), selectedNodes());
KisLayerUtils::filterMergableNodes(nodes2);
if (KisLayerUtils::checkIsChildOf(active, nodes2)) {
active = nodes2.first();
}
KisNodeSP parent = active->parent();
KisNodeSP aboveThis = active;
juggler->addNode(nodes1, parent, aboveThis);
juggler->moveNode(nodes2, group, 0);
*newGroup = group;
*newLastChild = nodes2.last();
}
void KisNodeManager::createQuickGroup()
{
KUndo2MagicString actionName = kundo2_i18n("Quick Group");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
KisNodeSP parent;
KisNodeSP above;
createQuickGroupImpl(juggler, "", &parent, &above);
}
void KisNodeManager::createQuickClippingGroup()
{
KUndo2MagicString actionName = kundo2_i18n("Quick Clipping Group");
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
KisNodeSP parent;
KisNodeSP above;
KisImageSP image = m_d->view->image();
createQuickGroupImpl(juggler, image->nextLayerName(i18nc("default name for a clipping group layer", "Clipping Group")), &parent, &above);
KisPaintLayerSP maskLayer = new KisPaintLayer(image.data(), i18nc("default name for quick clip group mask layer", "Mask Layer"), OPACITY_OPAQUE_U8, image->colorSpace());
maskLayer->disableAlphaChannel(true);
juggler->addNode(KisNodeList() << maskLayer, parent, above);
}
void KisNodeManager::quickUngroup()
{
KisNodeSP active = activeNode();
if (!active) return;
KisNodeSP parent = active->parent();
KisNodeSP aboveThis = active;
KUndo2MagicString actionName = kundo2_i18n("Quick Ungroup");
if (parent && dynamic_cast(active.data())) {
KisNodeList nodes = active->childNodes(QStringList(), KoProperties());
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->moveNode(nodes, parent, active);
juggler->removeNode(KisNodeList() << active);
} else if (parent && parent->parent()) {
KisNodeSP grandParent = parent->parent();
KisNodeList allChildNodes = parent->childNodes(QStringList(), KoProperties());
KisNodeList allSelectedNodes = selectedNodes();
const bool removeParent = KritaUtils::compareListsUnordered(allChildNodes, allSelectedNodes);
KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName);
juggler->moveNode(allSelectedNodes, grandParent, parent);
if (removeParent) {
juggler->removeNode(KisNodeList() << parent);
}
}
}
void KisNodeManager::selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps)
{
KisImageSP image = m_d->view->image();
KisNodeList nodes = KisLayerUtils::findNodesWithProps(image->root(), props, true);
KisNodeList selectedNodes = this->selectedNodes();
if (KritaUtils::compareListsUnordered(nodes, selectedNodes)) {
nodes = KisLayerUtils::findNodesWithProps(image->root(), invertedProps, true);
}
if (!nodes.isEmpty()) {
slotImageRequestNodeReselection(nodes.last(), nodes);
}
}
void KisNodeManager::selectAllNodes()
{
KoProperties props;
selectLayersImpl(props, props);
}
void KisNodeManager::selectVisibleNodes()
{
KoProperties props;
props.setProperty("visible", true);
KoProperties invertedProps;
invertedProps.setProperty("visible", false);
selectLayersImpl(props, invertedProps);
}
void KisNodeManager::selectLockedNodes()
{
KoProperties props;
props.setProperty("locked", true);
KoProperties invertedProps;
invertedProps.setProperty("locked", false);
selectLayersImpl(props, invertedProps);
}
void KisNodeManager::selectInvisibleNodes()
{
KoProperties props;
props.setProperty("visible", false);
KoProperties invertedProps;
invertedProps.setProperty("visible", true);
selectLayersImpl(props, invertedProps);
}
void KisNodeManager::selectUnlockedNodes()
{
KoProperties props;
props.setProperty("locked", false);
KoProperties invertedProps;
invertedProps.setProperty("locked", true);
selectLayersImpl(props, invertedProps);
}
diff --git a/plugins/paintops/defaultpaintops/brush/tests/kis_clone_test.cpp b/plugins/paintops/defaultpaintops/brush/tests/kis_clone_test.cpp
index 9bd937ca73..33060ff932 100644
--- a/plugins/paintops/defaultpaintops/brush/tests/kis_clone_test.cpp
+++ b/plugins/paintops/defaultpaintops/brush/tests/kis_clone_test.cpp
@@ -1,1139 +1,1127 @@
/*
* Copyright (c) 2016 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* Inpaint using the PatchMatch Algorithm
*
* | PatchMatch : A Randomized Correspondence Algorithm for Structural Image Editing
* | by Connelly Barnes and Eli Shechtman and Adam Finkelstein and Dan B Goldman
* | ACM Transactions on Graphics (Proc. SIGGRAPH), vol.28, aug-2009
*
* Original author Xavier Philippeau
* Code adopted from: David Chatting https://github.com/davidchatting/PatchMatch
*/
#include
#include
#include
#include "kis_paint_device.h"
#include "kis_clone_test.h"
#include "kis_debug.h"
#include "kis_paint_device_debug_utils.h"
#include "kis_random_accessor_ng.h"
#include
#include
#include
#include
#include "KoColor.h"
#include "KoColorSpace.h"
#include "KoChannelInfo.h"
#include "KoMixColorsOp.h"
#include "KoColorModelStandardIds.h"
#include
#include
#include
#include
#include
#include
#include
#include
-#define isOdd(x) ((x) & 0x01)
const int MAX_DIST = 65535;
const quint8 MASK_SET = 0;
const quint8 MASK_CLEAR = 255;
class ImageView
{
protected:
quint8* m_data;
int m_imageWidth;
int m_imageHeight;
int m_pixelSize;
public:
void Init(quint8* _data, int _imageWidth, int _imageHeight, int _pixelSize)
{
m_data = _data;
m_imageWidth = _imageWidth;
m_imageHeight = _imageHeight;
m_pixelSize = _pixelSize;
}
ImageView() : m_data(nullptr)
{
m_imageHeight = m_imageWidth = m_pixelSize = 0;
}
ImageView(quint8* _data, int _imageWidth, int _imageHeight, int _pixelSize)
{
Init(_data, _imageWidth, _imageHeight, _pixelSize);
}
quint8* operator()(int x, int y) const
{
Q_ASSERT(m_data);
Q_ASSERT((x >= 0) && (x < m_imageWidth) && (y >= 0) && (y < m_imageHeight));
return (m_data + x * m_pixelSize + y * m_imageWidth * m_pixelSize);
}
ImageView& operator=(const ImageView& other)
{
if (this != &other) {
if (other.num_bytes() != num_bytes()) {
delete[] m_data;
m_data = nullptr; //to preserve invariance if next line throws exception
m_data = new quint8[other.num_bytes()];
}
std::copy(other.data(), other.data() + other.num_bytes(), m_data);
m_imageHeight = other.m_imageHeight;
m_imageWidth = other.m_imageWidth;
m_pixelSize = other.m_pixelSize;
}
return *this;
}
//move assignement operator
ImageView& operator=(ImageView&& other) noexcept
{
if (this != &other) {
delete[] m_data;
m_data = nullptr;
Init(other.data(), other.m_imageWidth, other.m_imageHeight, other.m_pixelSize);
other.m_data = nullptr;
}
return *this;
}
virtual ~ImageView() {} //this class doesn't own m_data, so it ain't going to delete it either.
quint8* data(void) const
{
return m_data;
}
inline int num_elements(void) const
{
return m_imageHeight * m_imageWidth;
}
inline int num_bytes(void) const
{
return m_imageHeight * m_imageWidth * m_pixelSize;
}
inline int pixel_size(void) const
{
return m_pixelSize;
}
void saveToDevice(KisPaintDeviceSP outDev)
{
QRect imSize(QPoint(0, 0), QSize(m_imageWidth, m_imageHeight));
Q_ASSERT(outDev->colorSpace()->pixelSize() == m_pixelSize);
outDev->writeBytes(m_data, imSize);
}
void DebugDump(const QString& fnamePrefix)
{
QRect imSize(QPoint(0, 0), QSize(m_imageWidth, m_imageHeight));
const KoColorSpace* cs = (m_pixelSize == 1) ?
KoColorSpaceRegistry::instance()->alpha8() : (m_pixelSize == 3) ? KoColorSpaceRegistry::instance()->colorSpace("RGB", "U8", "") :
KoColorSpaceRegistry::instance()->colorSpace("RGBA", "U8", "");
KisPaintDeviceSP dbout = new KisPaintDevice(cs);
saveToDevice(dbout);
KIS_DUMP_DEVICE_2(dbout, imSize, fnamePrefix, "/home/eugening/Projects/img");
}
};
class ImageData : public ImageView
{
public:
ImageData() : ImageView() {}
void Init(int _imageWidth, int _imageHeight, int _pixelSize)
{
m_data = new quint8[ _imageWidth * _imageHeight * _pixelSize ];
ImageView::Init(m_data, _imageWidth, _imageHeight, _pixelSize);
}
ImageData(int _imageWidth, int _imageHeight, int _pixelSize) : ImageView()
{
Init(_imageWidth, _imageHeight, _pixelSize);
}
void Init(KisPaintDeviceSP imageDev, const QRect& imageSize)
{
const KoColorSpace* cs = imageDev->colorSpace();
m_pixelSize = cs->pixelSize();
m_data = new quint8[ imageSize.width()*imageSize.height()*cs->pixelSize() ];
imageDev->readBytes(m_data, imageSize.x(), imageSize.y(), imageSize.width(), imageSize.height());
ImageView::Init(m_data, imageSize.width(), imageSize.height(), m_pixelSize);
}
ImageData(KisPaintDeviceSP imageDev, const QRect& imageSize) : ImageView()
{
Init(imageDev, imageSize);
}
virtual ~ImageData()
{
delete[] m_data; //ImageData owns m_data, so it has to delete it
}
};
-inline void alignRectBy2(qint32 &x, qint32 &y, qint32 &w, qint32 &h)
-{
- x -= isOdd(x);
- y -= isOdd(y);
- w += isOdd(x);
- w += isOdd(w);
- h += isOdd(y);
- h += isOdd(h);
-}
-
-
class MaskedImage : public KisShared
{
private:
QRect imageSize;
int nChannels;
const KoColorSpace* cs;
const KoColorSpace* csMask;
ImageData maskData;
ImageData imageData;
void cacheImageSize(KisPaintDeviceSP imageDev)
{
imageSize = imageDev->exactBounds();
}
void cacheImage(KisPaintDeviceSP imageDev)
{
Q_ASSERT(!imageSize.isEmpty() && imageSize.isValid());
cs = imageDev->colorSpace();
nChannels = cs->channelCount();
imageData.Init(imageDev, imageSize);
}
void cacheMask(KisPaintDeviceSP maskDev)
{
Q_ASSERT(!imageSize.isEmpty() && imageSize.isValid());
Q_ASSERT(maskDev->colorSpace()->pixelSize() == 1);
csMask = maskDev->colorSpace();
maskData.Init(maskDev, imageSize);
}
MaskedImage() {}
public:
void toPaintDevice(KisPaintDeviceSP imageDev)
{
imageData.saveToDevice(imageDev);
}
void DebugDump(const QString& name)
{
imageData.DebugDump(name);
}
void clearMask(void)
{
std::fill(maskData.data(), maskData.data() + maskData.num_bytes(), MASK_CLEAR);
}
void initialize(KisPaintDeviceSP _imageDev, KisPaintDeviceSP _maskDev)
{
cacheImageSize(_imageDev);
cacheImage(_imageDev);
cacheMask(_maskDev);
}
// void clone(const MaskeImageSP other)
// {
// return new MaskedImage(imageDev, maskDev);
// }
MaskedImage(KisPaintDeviceSP _imageDev, KisPaintDeviceSP _maskDev)
{
initialize(_imageDev, _maskDev);
}
void downsample2x(void)
{
int H = imageSize.height();
int W = imageSize.width();
int newW = W / 2, newH = H / 2;
KisPaintDeviceSP imageDev = new KisPaintDevice(cs);
KisPaintDeviceSP maskDev = new KisPaintDevice(csMask);
imageDev->writeBytes(imageData.data(), 0, 0, W, H);
maskDev->writeBytes(maskData.data(), 0, 0, W, H);
ImageData newImage(newW, newH, cs->pixelSize());
ImageData newMask(newW, newH, 1);
KoDummyUpdater updater;
KisTransformWorker worker(imageDev, 1. / 2., 1. / 2., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
&updater, KisFilterStrategyRegistry::instance()->value("Bicubic"));
worker.run();
KisTransformWorker workerMask(maskDev, 1. / 2., 1. / 2., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
&updater, KisFilterStrategyRegistry::instance()->value("Bicubic"));
workerMask.run();
imageDev->readBytes(newImage.data(), 0, 0, newW, newH);
maskDev->readBytes(newMask.data(), 0, 0, newW, newH);
imageData = std::move(newImage);
maskData = std::move(newMask);
for (int i = 0; i < imageData.num_elements(); ++i) {
quint8* maskPix = maskData.data() + i * maskData.pixel_size();
if (*maskPix == MASK_SET) {
for (int k = 0; k < imageData.pixel_size(); k++)
*(imageData.data() + i * imageData.pixel_size() + k) = 0;
} else {
*maskPix = MASK_CLEAR;
}
}
imageSize = QRect(0, 0, newW, newH);
// int nmasked = countMasked();
// printf("Masked: %d size: %dx%d\n", nmasked, newW, newH);
// maskData.DebugDump("maskData");
}
void upscale(int newW, int newH)
{
int H = imageSize.height();
int W = imageSize.width();
ImageData newImage(newW, newH, cs->pixelSize());
ImageData newMask(newW, newH, 1);
QVector colors(nChannels, 0.f);
QVector v(nChannels, 0.f);
for (int y = 0; y < newH; ++y) {
for (int x = 0; x < newW; ++x) {
// original pixel
int xs = (x * W) / newW;
int ys = (y * H) / newH;
// copy to new image
if (!isMasked(xs, ys)) {
std::copy(imageData(xs, ys), imageData(xs, ys) + imageData.pixel_size(), newImage(x, y));
*newMask(x, y) = MASK_CLEAR;
} else {
std::fill(newImage(x, y), newImage(x, y) + newImage.pixel_size(), 0);
*newMask(x, y) = MASK_SET;
}
}
}
imageData = std::move(newImage);
maskData = std::move(newMask);
imageSize = QRect(0, 0, newW, newH);
}
QRect size()
{
return imageSize;
}
KisSharedPtr copy(void)
{
KisSharedPtr clone = new MaskedImage();
clone->imageSize = this->imageSize;
clone->nChannels = this->nChannels;
clone->maskData = this->maskData;
clone->imageData = this->imageData;
clone->cs = this->cs;
clone->csMask = this->csMask;
return clone;
}
int countMasked(void)
{
int count = std::count_if(maskData.data(), maskData.data() + maskData.num_elements(), [](quint8 v) {
return v < MASK_CLEAR; //((MASK_SET + MASK_CLEAR / 2));
});
return count;
}
inline bool isMasked(int x, int y)
{
return (*maskData(x, y) < MASK_CLEAR); // ((MASK_SET + MASK_CLEAR) / 2));
}
//returns true if the patch contains a masked pixel
bool containsMasked(int x, int y, int S)
{
for (int dy = -S; dy <= S; ++dy) {
int ys = y + dy;
if (ys < 0 || ys >= imageSize.height())
continue;
for (int dx = -S; dx <= S; ++dx) {
int xs = x + dx;
if (xs < 0 || xs >= imageSize.width())
continue;
if (isMasked(xs, ys))
return true;
}
}
return false;
}
// const quint8* getImagePixel(int x, int y) {
// KisRandomConstAccessorSP it = imageDev->createRandomConstAccessorNG(x, y);
// return it->oldRawData(); //is this Ok to do?
// }
inline quint8 getImagePixelU8(int x, int y, int chan) const
{
return cs->scaleToU8(imageData(x, y), chan);
}
inline QVector getImagePixels(int x, int y) const
{
QVector v(cs->channelCount());
cs->normalisedChannelsValue(imageData(x, y), v);
return v;
}
inline quint8* getImagePixel(int x, int y)
{
return imageData(x, y);
}
inline void setImagePixels(int x, int y, QVector& value)
{
cs->fromNormalisedChannelsValue(imageData(x, y), value);
}
inline void mixColors(std::vector< quint8* > pixels, std::vector< float > w, float wsum, quint8* dst)
{
const KoMixColorsOp* mixOp = cs->mixColorsOp();
size_t n = w.size();
assert(pixels.size() == n);
std::vector< qint16 > weights;
weights.clear();
float dif = 0;
float scale = 255 / (wsum + 0.001);
for (auto& v : w) {
//compensated summation to increase accuracy
float v1 = v * scale + dif;
float v2 = std::round(v1);
dif = v1 - v2;
weights.push_back(v2);
}
mixOp->mixColors(pixels.data(), weights.data(), n, dst);
}
inline void setMask(int x, int y, quint8 v)
{
*(maskData(x, y)) = v;
}
inline int channelCount(void) const
{
return cs->channelCount();
}
float distance(int x, int y, const MaskedImage& other, int xo, int yo)
{
float dsq = 0;
quint32 nchannels = channelCount();
quint8* v1 = imageData(x, y);
quint8* v2 = other.imageData(xo, yo);
for (quint32 chan = 0; chan < nchannels; chan++) {
//It's very important not to lose precision in the next line
//TODO: This code only works for 8bpp data. Refactor to make it universal.
float v = (float)(*((quint8*)v1 + chan)) - (float)(*((quint8*)v2 + chan));
dsq += v * v;
}
return dsq;
}
};
typedef KisSharedPtr MaskedImageSP;
struct NNPixel {
int x;
int y;
int distance;
};
typedef boost::multi_array NNArray_type;
struct Vote_elem {
QVector channel_values;
float w;
};
typedef boost::multi_array Vote_type;
class NearestNeighborField : public KisShared
{
private:
template< typename T> T randomInt(T range)
{
return rand() % range;
}
//compute intial value of the distance term
void initialize(void)
{
for (int y = 0; y < imSize.height(); y++) {
for (int x = 0; x < imSize.width(); x++) {
field[x][y].distance = distance(x, y, field[x][y].x, field[x][y].y);
//if the distance is "infinity", try to find a better link
int iter = 0;
const int maxretry = 20;
while (field[x][y].distance == MAX_DIST && iter < maxretry) {
field[x][y].x = randomInt(imSize.width() + 1);
field[x][y].y = randomInt(imSize.height() + 1);
field[x][y].distance = distance(x, y, field[x][y].x, field[x][y].y);
iter++;
}
}
}
}
void init_similarity_curve(void)
{
float s_zero = 0.999;
float t_halfmax = 0.10;
float x = (s_zero - 0.5) * 2;
float invtanh = 0.5 * std::log((1. + x) / (1. - x));
float coef = invtanh / t_halfmax;
similarity.resize(MAX_DIST + 1);
for (int i = 0; i < (int)similarity.size(); i++) {
float t = (float)i / similarity.size();
similarity[i] = 0.5 - 0.5 * std::tanh(coef * (t - t_halfmax));
}
}
private:
int patchSize; //patch size
public:
MaskedImageSP input;
MaskedImageSP output;
QRect imSize;
NNArray_type field;
std::vector similarity;
quint32 nColors;
QList channels;
public:
NearestNeighborField(const MaskedImageSP _input, MaskedImageSP _output, int _patchsize) : patchSize(_patchsize), input(_input), output(_output)
{
imSize = input->size();
field.resize(boost::extents[imSize.width()][imSize.height()]);
init_similarity_curve();
nColors = input->channelCount(); //only color count, doesn't include alpha channels
}
void randomize(void)
{
for (int y = 0; y < imSize.height(); y++) {
for (int x = 0; x < imSize.width(); x++) {
field[x][y].x = randomInt(imSize.width() + 1);
field[x][y].y = randomInt(imSize.height() + 1);
field[x][y].distance = MAX_DIST;
}
}
initialize();
}
//initialize field from an existing (possibly smaller) nearest neighbor field
void initialize(const NearestNeighborField& nnf)
{
float xscale = imSize.width() / nnf.imSize.width();
float yscale = imSize.height() / nnf.imSize.height();
for (int y = 0; y < imSize.height(); y++) {
for (int x = 0; x < imSize.width(); x++) {
int xlow = std::min((int)(x / xscale), nnf.imSize.width() - 1);
int ylow = std::min((int)(y / yscale), nnf.imSize.height() - 1);
field[x][y].x = nnf.field[xlow][ylow].x * xscale;
field[x][y].y = nnf.field[xlow][ylow].y * yscale;
field[x][y].distance = MAX_DIST;
}
}
initialize();
}
//multi-pass NN-field minimization (see "PatchMatch" - page 4)
void minimize(int pass)
{
int min_x = 0;
int min_y = 0;
int max_x = imSize.width() - 1;
int max_y = imSize.height() - 1;
for (int i = 0; i < pass; i++) {
//scanline order
for (int y = min_y; y < max_y; y++)
for (int x = min_x; x <= max_x; x++)
if (field[x][y].distance > 0)
minimizeLink(x, y, 1);
//reverse scanline order
for (int y = max_y; y >= min_y; y--)
for (int x = max_x; x >= min_x; x--)
if (field[x][y].distance > 0)
minimizeLink(x, y, -1);
}
}
void minimizeLink(int x, int y, int dir)
{
int xp, yp, dp;
//Propagation Left/Right
if (x - dir > 0 && x - dir < imSize.width()) {
xp = field[x - dir][y].x + dir;
yp = field[x - dir][y].y;
dp = distance(x, y, xp, yp);
if (dp < field[x][y].distance) {
field[x][y].x = xp;
field[x][y].y = yp;
field[x][y].distance = dp;
}
}
//Propagation Up/Down
if (y - dir > 0 && y - dir < imSize.height()) {
xp = field[x][y - dir].x;
yp = field[x][y - dir].y + dir;
dp = distance(x, y, xp, yp);
if (dp < field[x][y].distance) {
field[x][y].x = xp;
field[x][y].y = yp;
field[x][y].distance = dp;
}
}
//Random search
int wi = std::max(output->size().width(), output->size().height());
int xpi = field[x][y].x;
int ypi = field[x][y].y;
while (wi > 0) {
xp = xpi + randomInt(2 * wi) - wi;
yp = ypi + randomInt(2 * wi) - wi;
xp = std::max(0, std::min(output->size().width() - 1, xp));
yp = std::max(0, std::min(output->size().height() - 1, yp));
dp = distance(x, y, xp, yp);
if (dp < field[x][y].distance) {
field[x][y].x = xp;
field[x][y].y = yp;
field[x][y].distance = dp;
}
wi /= 2;
}
}
//compute distance between two patches
int distance(int x, int y, int xp, int yp)
{
float distance = 0;
float wsum = 0;
float ssdmax = nColors * 255 * 255;
//for each pixel in the source patch
for (int dy = -patchSize; dy <= patchSize; dy++) {
for (int dx = -patchSize; dx <= patchSize; dx++) {
wsum += ssdmax;
int xks = x + dx;
int yks = y + dy;
if (xks < 0 || xks >= input->size().width()) {
distance += ssdmax;
continue;
}
if (yks < 0 || yks >= input->size().height()) {
distance += ssdmax;
continue;
}
//cannot use masked pixels as a valid source of information
if (input->isMasked(xks, yks)) {
distance += ssdmax;
continue;
}
//corresponding pixel in target patch
int xkt = xp + dx;
int ykt = yp + dy;
if (xkt < 0 || xkt >= output->size().width()) {
distance += ssdmax;
continue;
}
if (ykt < 0 || ykt >= output->size().height()) {
distance += ssdmax;
continue;
}
//cannot use masked pixels as a valid source of information
if (output->isMasked(xkt, ykt)) {
distance += ssdmax;
continue;
}
//SSD distance between pixels
float ssd = input->distance(xks, yks, *output, xkt, ykt);
//long ssd = input->distance(xks, yks, *input, xkt, ykt);
distance += ssd;
}
}
return (int)(MAX_DIST * (distance / wsum));
}
static MaskedImageSP ExpectationMaximization(KisSharedPtr TargetToSource, int level, int radius, QList& pyramid);
static void ExpectationStep(KisSharedPtr nnf, MaskedImageSP source, MaskedImageSP target, bool upscale);
void EM_Step(MaskedImageSP source, MaskedImageSP target, int R, bool upscaled);
};
typedef KisSharedPtr NearestNeighborFieldSP;
class Inpaint
{
private:
KisPaintDeviceSP devCache;
MaskedImageSP initial;
NearestNeighborFieldSP nnf_TargetToSource;
NearestNeighborFieldSP nnf_SourceToTarget;
int radius;
QList pyramid;
public:
Inpaint(KisPaintDeviceSP dev, KisPaintDeviceSP devMask, int _radius)
{
initial = new MaskedImage(dev, devMask);
radius = _radius;
devCache = dev;
}
MaskedImageSP patch(void);
MaskedImageSP patch_simple(void);
};
class TestClone : public TestUtil::QImageBasedTest
{
public:
TestClone() : QImageBasedTest("clonetest") {}
virtual ~TestClone() {}
void test();
void testPatchMatch();
private:
MaskedImageSP patchImage(KisPaintDeviceSP, KisPaintDeviceSP, int radius);
};
MaskedImageSP Inpaint::patch()
{
MaskedImageSP source = initial->copy();
pyramid.append(initial);
QRect size = source->size();
//std::cerr << "countMasked: " << source->countMasked() << "\n";
while ((size.width() > radius) && (size.height() > radius) && source->countMasked() > 0) {
//std::cerr << "countMasked: " << source->countMasked() << "\n";
source->downsample2x();
//source->DebugDump("Pyramid");
pyramid.append(source->copy());
size = source->size();
}
int maxlevel = pyramid.size();
//std::cerr << "MaxLevel: " << maxlevel << "\n";
// The initial target is the same as the smallest source.
// We consider that this target contains no masked pixels
MaskedImageSP target = source->copy();
target->clearMask();
//recursively building nearest neighbor field
for (int level = maxlevel - 1; level > 0; level--) {
source = pyramid.at(level);
if (level == maxlevel - 1) {
//random initial guess
nnf_TargetToSource = new NearestNeighborField(target, source, radius);
nnf_TargetToSource->randomize();
} else {
// then, we use the rebuilt (upscaled) target
// and reuse the previous NNF as initial guess
NearestNeighborFieldSP new_nnf_rev = new NearestNeighborField(target, source, radius);
new_nnf_rev->initialize(*nnf_TargetToSource);
nnf_TargetToSource = new_nnf_rev;
}
//Build an upscaled target by EM-like algorithm (see "PatchMatch" - page 6)
target = NearestNeighborField::ExpectationMaximization(nnf_TargetToSource, level, radius, pyramid);
//target->DebugDump( "target" );
}
return target;
}
//EM-Like algorithm (see "PatchMatch" - page 6)
//Returns a float sized target image
MaskedImageSP NearestNeighborField::ExpectationMaximization(NearestNeighborFieldSP nnf_TargetToSource, int level, int radius, QList& pyramid)
{
int iterEM = std::min(2 * level, 4);
int iterNNF = std::min(5, 1 + level);
MaskedImageSP source = nnf_TargetToSource->output;
MaskedImageSP target = nnf_TargetToSource->input;
MaskedImageSP newtarget = nullptr;
//EM loop
for (int emloop = 1; emloop <= iterEM; emloop++) {
//set the new target as current target
if (!newtarget.isNull()) {
nnf_TargetToSource->input = newtarget;
target = newtarget;
newtarget = nullptr;
}
for (int x = 0; x < target->size().width(); ++x) {
for (int y = 0; y < target->size().height(); ++y) {
if (!source->containsMasked(x, y, radius)) {
nnf_TargetToSource->field[x][y].x = x;
nnf_TargetToSource->field[x][y].y = y;
nnf_TargetToSource->field[x][y].distance = 0;
}
}
}
//minimize the NNF
nnf_TargetToSource->minimize(iterNNF);
//DebugSaver::instance()->debugDumpField("T2S", nnf_TargetToSource->field);
//Now we rebuild the target using best patches from source
MaskedImageSP newsource = nullptr;
bool upscaled = false;
// Instead of upsizing the final target, we build the last target from the next level source image
// So the final target is less blurry (see "Space-Time Video Completion" - page 5)
if (level >= 1 && (emloop == iterEM)) {
newsource = pyramid.at(level - 1);
QRect sz = newsource->size();
newtarget = target->copy();
newtarget->upscale(sz.width(), sz.height());
upscaled = true;
} else {
newsource = pyramid.at(level);
newtarget = target->copy();
upscaled = false;
}
//EM Step
//EM_Step(newsource, newtarget, radius, upscaled);
ExpectationStep(nnf_TargetToSource, newsource, newtarget, upscaled);
}
//DebugSaver::instance()->debugDumpField("T2S_Final", nnf_TargetToSource->field);
return newtarget;
}
void NearestNeighborField::ExpectationStep(NearestNeighborFieldSP nnf, MaskedImageSP source, MaskedImageSP target, bool upscale)
{
//int*** field = nnf->field;
int R = nnf->patchSize;
if (upscale)
R *= 2;
int H_nnf = nnf->input->size().height();
int W_nnf = nnf->input->size().width();
int H_target = target->size().height();
int W_target = target->size().width();
int H_source = source->size().height();
int W_source = source->size().width();
std::vector< quint8* > pixels;
std::vector< float > weights;
pixels.reserve(R * R);
weights.reserve(R * R);
for (int x = 0 ; x < W_target ; ++x) {
for (int y = 0 ; y < H_target; ++y) {
float wsum = 0;
pixels.clear();
weights.clear();
if (!source->containsMasked(x, y, R + 4) /*&& upscale*/) {
//speedup computation by copying parts that are not masked.
pixels.push_back(source->getImagePixel(x, y));
weights.push_back(1.f);
target->mixColors(pixels, weights, 1.f, target->getImagePixel(x, y));
} else {
for (int dx = -R ; dx <= R; ++dx) {
for (int dy = -R ; dy <= R ; ++dy) {
// xpt,ypt = center pixel of the target patch
int xpt = x + dx;
int ypt = y + dy;
int xst, yst;
float w;
if (!upscale) {
if (xpt < 0 || xpt >= W_nnf || ypt < 0 || ypt >= H_nnf)
continue;
xst = nnf->field[xpt][ypt].x;
yst = nnf->field[xpt][ypt].y;
float dp = nnf->field[xpt][ypt].distance;
// similarity measure between the two patches
w = nnf->similarity[dp];
} else {
if (xpt < 0 || (xpt / 2) >= W_nnf || ypt < 0 || (ypt / 2) >= H_nnf)
continue;
xst = 2 * nnf->field[xpt / 2][ypt / 2].x + (xpt % 2);
yst = 2 * nnf->field[xpt / 2][ypt / 2].y + (ypt % 2);
float dp = nnf->field[xpt / 2][ypt / 2].distance;
// similarity measure between the two patches
w = nnf->similarity[dp];
}
int xs = xst - dx;
int ys = yst - dy;
if (xs < 0 || xs >= W_source || ys < 0 || ys >= H_source)
continue;
if (source->isMasked(xs, ys))
continue;
pixels.push_back(source->getImagePixel(xs, ys));
weights.push_back(w);
wsum += w;
}
}
if (wsum < 1)
continue;
target->mixColors(pixels, weights, wsum, target->getImagePixel(x, y));
}
}
}
}
MaskedImageSP TestClone::patchImage(KisPaintDeviceSP dev, KisPaintDeviceSP devMask, int radius)
{
Inpaint inpaint(dev, devMask, radius);
//return inpaint.patch_simple();
return inpaint.patch();
}
void TestClone::testPatchMatch()
{
KisDocument *doc = KisPart::instance()->createDocument();
//doc->loadNativeFormat("/home/eugening/Projects/patch-inpainting/bungee.kra");
doc->loadNativeFormat("/home/eugening/Projects/patch-inpainting/Yosemite_Winter_crop.kra");
//doc->loadNativeFormat("/home/eugening/Projects/patch-inpainting/Yosemite_Winter.kra");
KisImageSP image = doc->image();
image->lock();
KisGroupLayerSP groupLayer = image->rootLayer();
QObjectList children = groupLayer->children();
KisNodeSP node = image->root()->firstChild();
KisPaintDeviceSP mainDev = node->paintDevice();
const KoColorSpace* mainCS = mainDev->colorSpace();
KisNodeSP maskNode = node->firstChild();
KisPaintDeviceSP maskDev = maskNode->paintDevice();
const KoColorSpace* maskCS = maskDev->colorSpace();
QRect rect = mainDev->exactBounds();
// KIS_DUMP_DEVICE_2(mainDev, rect, "maindev", "/home/eugening/Projects/img");
// KIS_DUMP_DEVICE_2(maskDev, rect, "maskdev", "/home/eugening/Projects/img");
MaskedImageSP output = patchImage(mainDev, maskDev, 4);
if (!output.isNull()) {
output->toPaintDevice(mainDev);
KIS_DUMP_DEVICE_2(mainDev, output->size(), "output", "/home/eugening/Projects/Out");
}
delete doc;
}
void TestClone::test(void)
{
KisSurrogateUndoStore *undoStore = new KisSurrogateUndoStore();
KisImageSP image = createImage(undoStore);
KisDocument *doc = KisPart::instance()->createDocument();
doc->setCurrentImage(image);
image->initialRefreshGraph();
KisLayerSP layer = new KisPaintLayer(image, "clone", OPACITY_OPAQUE_U8, image->colorSpace());
image->addNode(layer, image->root());
KisPaintDeviceSP dev = layer->paintDevice(); //chld->paintDevice(); //
KisPainter painter(dev);
delete doc;
}
void KisCloneOpTest::testClone()
{
TestClone t;
- DebugSaver::instance()->openDebugFile("/home/eugening/Projects/debug.h5");
+ //DebugSaver::instance()->openDebugFile("/home/eugening/Projects/debug.h5");
//t.test();
/*QBENCHMARK*/{
t.testPatchMatch();
}
}
void KisCloneOpTest::testProjection()
{
KisDocument *doc = KisPart::instance()->createDocument();
doc->loadNativeFormat("/home/eugening/Pictures/Krita_Test/Img_20M_3Layer.kra");
// KisPaintDeviceSP pd = nullptr;
doc->image()->refreshGraph();
// QBENCHMARK_ONCE{
// doc->image()->refreshGraph();
// }
// QBENCHMARK_ONCE{
// pd = doc->image()->projection();
// }
//KIS_DUMP_DEVICE_2(proj,proj->exactBounds(),"Img20M","/home/eugening/Projects/Img20M");
delete doc;
}
QTEST_MAIN(KisCloneOpTest)
//#if 1
//#include "hdf5.h"
//#include "hdf5_hl.h"
//#endif
//class DebugSaver {
// QString fname;
// hid_t file_id;
// int counter;
//public:
// static DebugSaver* instance();
// DebugSaver() : counter(0) {};
// ~DebugSaver() {
// if( file_id != -1 )
// H5Fclose(file_id);
// }
// void openDebugFile( QString fname ){
// file_id = H5Fcreate(fname.toStdString().c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// }
// template< typename T> void debugDumpField( QString dset, const T& field )
// {
// if( file_id == -1 )
// return;
// QString dset_name = QString("/") + QString::number(counter);
// hsize_t dims[] = {field.shape()[0], field.shape()[1], 3}; //x,y,distance
// H5LTmake_dataset(file_id, dset_name.toStdString().c_str(), 3, dims, H5T_NATIVE_INT, (void*)field.data());
// H5LTset_attribute_string (file_id, dset_name.toStdString().c_str(), "name", dset.toStdString().c_str());
// counter++;
// }
// template< typename T> void debugDumpHistogram(QString dset, const T& histogram)
// {
// if( file_id == -1 )
// return;
// QString dset_name = QString("/") + QString::number(counter);
// H5LTmake_dataset(file_id, dset_name.toStdString().c_str(), histogram.num_dimensions(), (const hsize_t*)histogram.shape(), H5T_NATIVE_FLOAT, (void*)histogram.data());
// H5LTset_attribute_string (file_id, dset_name.toStdString().c_str(), "name", dset.toStdString().c_str());
// counter++;
// }
//};
//Q_GLOBAL_STATIC(DebugSaver, s_instance)
//DebugSaver* DebugSaver::instance(){ return s_instance; }
diff --git a/plugins/tools/CMakeLists.txt b/plugins/tools/CMakeLists.txt
index 7d3381a403..3afdb4ebdc 100644
--- a/plugins/tools/CMakeLists.txt
+++ b/plugins/tools/CMakeLists.txt
@@ -1,11 +1,12 @@
add_subdirectory( basictools )
add_subdirectory( defaulttool )
add_subdirectory( selectiontools )
add_subdirectory( tool_crop )
add_subdirectory( tool_polygon )
add_subdirectory( tool_polyline )
add_subdirectory( tool_transform2 )
add_subdirectory( tool_dyna )
add_subdirectory( tool_text )
add_subdirectory( karbonplugins )
add_subdirectory( tool_lazybrush )
+add_subdirectory( tool_smart_patch )
diff --git a/plugins/tools/tool_smart_patch/CMakeLists.txt b/plugins/tools/tool_smart_patch/CMakeLists.txt
index 1d146a4960..e03e98ab36 100644
--- a/plugins/tools/tool_smart_patch/CMakeLists.txt
+++ b/plugins/tools/tool_smart_patch/CMakeLists.txt
@@ -1,16 +1,16 @@
-set(kritatoolsmartpatch_SOURCES
+set(kritatoolSmartPatch_SOURCES
tool_smartpatch.cpp
kis_tool_smart_patch.cpp
kis_tool_smart_patch_options_widget.cpp
)
-#ki18n_wrap_ui(kritatoolsmartpatch_SOURCES kis_tool_smart_patch_options_widget.ui)
+ki18n_wrap_ui(kritatoolSmartPatch_SOURCES kis_tool_smart_patch_options_widget.ui)
-add_library(kritatoolsmartpatch MODULE ${kritatoolsmartpatch_SOURCES})
+add_library(kritatoolSmartPatch MODULE ${kritatoolSmartPatch_SOURCES})
-generate_export_header(kritatoolsmartpatch BASE_NAME kritatoolsmartpatch)
+generate_export_header(kritatoolSmartPatch BASE_NAME kritatoolSmartPatch)
-target_link_libraries(kritatoolsmartpatch kritaui)
+target_link_libraries(kritatoolSmartPatch kritaui)
-install(TARGETS kritatoolsmartpatch DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
+install(TARGETS kritatoolSmartPatch DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/tools/tool_smart_patch/kis_tool_smart_patch.cpp b/plugins/tools/tool_smart_patch/kis_tool_smart_patch.cpp
index 82a05c394f..b00b327ffa 100644
--- a/plugins/tools/tool_smart_patch/kis_tool_smart_patch.cpp
+++ b/plugins/tools/tool_smart_patch/kis_tool_smart_patch.cpp
@@ -1,163 +1,173 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "kis_tool_lazy_brush.h"
+#include "kis_tool_smart_patch.h"
#include
#include
#include
#include
#include
#include
#include
#include "kis_canvas2.h"
#include "kis_cursor.h"
#include "kis_config.h"
#include "kundo2magicstring.h"
#include "KoProperties.h"
#include "kis_node_manager.h"
-#include "kis_tool_lazy_brush_options_widget.h"
+#include "kis_tool_smart_patch_options_widget.h"
-struct KisToolLazyBrush::Private
+struct KisToolSmartPatch::Private
{
bool activateMaskMode = false;
};
-KisToolLazyBrush::KisToolLazyBrush(KoCanvasBase * canvas)
+KisToolSmartPatch::KisToolSmartPatch(KoCanvasBase * canvas)
: KisToolFreehand(canvas,
KisCursor::load("tool_freehand_cursor.png", 5, 5),
- kundo2_i18n("Colorize Mask Key Stroke")),
+ kundo2_i18n("Smart Patch Stroke")),
m_d(new Private)
{
- setObjectName("tool_lazybrush");
+ setObjectName("tool_SmartPatch");
}
-KisToolLazyBrush::~KisToolLazyBrush()
+KisToolSmartPatch::~KisToolSmartPatch()
{
}
-void KisToolLazyBrush::activate(ToolActivation activation, const QSet &shapes)
+void KisToolSmartPatch::activate(ToolActivation activation, const QSet &shapes)
{
KisToolFreehand::activate(activation, shapes);
}
-void KisToolLazyBrush::deactivate()
+void KisToolSmartPatch::deactivate()
{
KisToolFreehand::deactivate();
}
-void KisToolLazyBrush::resetCursorStyle()
+void KisToolSmartPatch::resetCursorStyle()
{
KisToolFreehand::resetCursorStyle();
}
-bool KisToolLazyBrush::colorizeMaskActive() const
+bool KisToolSmartPatch::inpaintMaskActive() const
{
KisNodeSP node = currentNode();
- return node && node->inherits("KisColorizeMask");
+ return node && node->inherits("KisFilterMask");
}
-bool KisToolLazyBrush::canCreateColorizeMask() const
+bool KisToolSmartPatch::canCreateInpaintMask() const
{
KisNodeSP node = currentNode();
return node && node->inherits("KisLayer");
}
-void KisToolLazyBrush::activatePrimaryAction()
+void KisToolSmartPatch::activatePrimaryAction()
{
KisToolFreehand::activatePrimaryAction();
- if (!colorizeMaskActive() && canCreateColorizeMask()) {
- useCursor(KisCursor::handCursor());
+ if (!inpaintMaskActive() && canCreateInpaintMask()) {
+ //useCursor(KisCursor::handCursor());
m_d->activateMaskMode = true;
- setOutlineEnabled(false);
+ setOutlineEnabled(true);
}
}
-void KisToolLazyBrush::deactivatePrimaryAction()
+void KisToolSmartPatch::deactivatePrimaryAction()
{
if (m_d->activateMaskMode) {
m_d->activateMaskMode = false;
setOutlineEnabled(true);
resetCursorStyle();
}
KisToolFreehand::deactivatePrimaryAction();
}
-void KisToolLazyBrush::beginPrimaryAction(KoPointerEvent *event)
+void KisToolSmartPatch::beginPrimaryAction(KoPointerEvent *event)
{
if (m_d->activateMaskMode) {
KisNodeSP node = currentNode();
if (!node) return;
KoProperties properties;
properties.setProperty("visible", true);
- properties.setProperty("locked", false);
+ properties.setProperty("temporary", true);
+ properties.setProperty("smartpatch", true);
- QList masks = node->childNodes(QStringList("KisColorizeMask"), properties);
+ QList masks = node->childNodes(QStringList("KisInpaintMask"), properties);
if (!masks.isEmpty()) {
KisCanvas2 * kiscanvas = static_cast(canvas());
+
KisViewManager* viewManager = kiscanvas->viewManager();
viewManager->nodeManager()->slotNonUiActivatedNode(masks.first());
} else {
KisCanvas2 * kiscanvas = static_cast(canvas());
KisViewManager* viewManager = kiscanvas->viewManager();
- viewManager->nodeManager()->createNode("KisColorizeMask");
+ viewManager->nodeManager()->createNode("KisInpaintMask", true);
+ KisNodeSP node = currentNode();
+
+ if ( node ){
+ node->setProperty("visible", true);
+ node->setProperty("temporary", true);
+ node->setProperty("smartpatch", true);
+ }
+
}
} else {
KisToolFreehand::beginPrimaryAction(event);
}
}
-void KisToolLazyBrush::continuePrimaryAction(KoPointerEvent *event)
+void KisToolSmartPatch::continuePrimaryAction(KoPointerEvent *event)
{
if (m_d->activateMaskMode) return;
KisToolFreehand::continuePrimaryAction(event);
}
-void KisToolLazyBrush::endPrimaryAction(KoPointerEvent *event)
+void KisToolSmartPatch::endPrimaryAction(KoPointerEvent *event)
{
if (m_d->activateMaskMode) return;
KisToolFreehand::endPrimaryAction(event);
}
-QWidget * KisToolLazyBrush::createOptionWidget()
+QWidget * KisToolSmartPatch::createOptionWidget()
{
KisCanvas2 * kiscanvas = dynamic_cast(canvas());
- QWidget *optionsWidget = new KisToolLazyBrushOptionsWidget(kiscanvas->viewManager()->resourceProvider(), 0);
+ QWidget *optionsWidget = new KisToolSmartPatchOptionsWidget(kiscanvas->viewManager()->resourceProvider(), 0);
optionsWidget->setObjectName(toolId() + "option widget");
// // See https://bugs.kde.org/show_bug.cgi?id=316896
// QWidget *specialSpacer = new QWidget(optionsWidget);
// specialSpacer->setObjectName("SpecialSpacer");
// specialSpacer->setFixedSize(0, 0);
// optionsWidget->layout()->addWidget(specialSpacer);
return optionsWidget;
}
diff --git a/plugins/tools/tool_smart_patch/kis_tool_smart_patch.h b/plugins/tools/tool_smart_patch/kis_tool_smart_patch.h
index 0aaf46eb95..ebccd4f480 100644
--- a/plugins/tools/tool_smart_patch/kis_tool_smart_patch.h
+++ b/plugins/tools/tool_smart_patch/kis_tool_smart_patch.h
@@ -1,99 +1,99 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef KIS_TOOL_LAZY_BRUSH_H_
-#define KIS_TOOL_LAZY_BRUSH_H_
+#ifndef KIS_TOOL_SMART_PATCH_H_
+#define KIS_TOOL_SMART_PATCH_H_
#include
#include "kis_tool_freehand.h"
#include "KoToolFactoryBase.h"
#include
#include
#include
#include
#include
#include
class KActionCollection;
class KoCanvasBase;
-class KisToolLazyBrush : public KisToolFreehand
+class KisToolSmartPatch : public KisToolFreehand
{
Q_OBJECT
public:
- KisToolLazyBrush(KoCanvasBase * canvas);
- virtual ~KisToolLazyBrush();
+ KisToolSmartPatch(KoCanvasBase * canvas);
+ virtual ~KisToolSmartPatch();
QWidget * createOptionWidget();
void activatePrimaryAction();
void deactivatePrimaryAction();
void beginPrimaryAction(KoPointerEvent *event);
void continuePrimaryAction(KoPointerEvent *event);
void endPrimaryAction(KoPointerEvent *event);
protected Q_SLOTS:
void resetCursorStyle();
public Q_SLOTS:
virtual void activate(ToolActivation toolActivation, const QSet &shapes);
void deactivate();
Q_SIGNALS:
private:
- bool colorizeMaskActive() const;
- bool canCreateColorizeMask() const;
+ bool inpaintMaskActive() const;
+ bool canCreateInpaintMask() const;
private:
struct Private;
const QScopedPointer m_d;
};
-class KisToolLazyBrushFactory : public KoToolFactoryBase
+class KisToolSmartPatchFactory : public KoToolFactoryBase
{
public:
- KisToolLazyBrushFactory()
- : KoToolFactoryBase("KritaShape/KisToolLazyBrush") {
+ KisToolSmartPatchFactory()
+ : KoToolFactoryBase("KritaShape/KisToolSmartPatch") {
- setToolTip(i18n("Colorize Mask Editing Tool"));
+ setToolTip(i18n("Smart Patch Tool"));
// Temporarily
setSection(TOOL_TYPE_FILL);
- setIconName(koIconNameCStr("krita_tool_lazybrush"));
+ setIconName(koIconNameCStr("krita_tool_smart_patch"));
//setShortcut(QKeySequence(Qt::Key_Shift + Qt::Key_B));
- setPriority(3);
+ setPriority(4);
setActivationShapeId(KRITA_TOOL_ACTIVATION_ID);
}
- virtual ~KisToolLazyBrushFactory() {}
+ virtual ~KisToolSmartPatchFactory() {}
virtual KoToolBase * createTool(KoCanvasBase *canvas) {
- return new KisToolLazyBrush(canvas);
+ return new KisToolSmartPatch(canvas);
}
};
-#endif // KIS_TOOL_LAZY_BRUSH_H_
+#endif // KIS_TOOL_SMART_PATCH_H_
diff --git a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.cpp b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.cpp
index 98b731b447..ba78c29fb1 100644
--- a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.cpp
+++ b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.cpp
@@ -1,290 +1,290 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "kis_tool_lazy_brush_options_widget.h"
+#include "kis_tool_smart_patch_options_widget.h"
-#include "ui_kis_tool_lazy_brush_options_widget.h"
+#include "ui_kis_tool_smart_patch_options_widget.h"
#include
#include "KisPaletteModel.h"
#include "kis_config.h"
#include
#include "kis_canvas_resource_provider.h"
#include "kis_signal_auto_connection.h"
#include "lazybrush/kis_colorize_mask.h"
#include "kis_image.h"
#include "kis_signals_blocker.h"
#include "kis_signal_compressor.h"
#include "kis_layer_properties_icons.h"
-struct KisToolLazyBrushOptionsWidget::Private
+struct KisToolSmartPatchOptionsWidget::Private
{
Private()
: transparentColorIndex(-1),
baseNodeChangedCompressor(500, KisSignalCompressor::FIRST_ACTIVE)
{
}
- Ui_KisToolLazyBrushOptionsWidget *ui;
+ Ui_KisToolSmartPatchOptionsWidget *ui;
KisPaletteModel *colorModel;
KisCanvasResourceProvider *provider;
KisSignalAutoConnectionsStore providerSignals;
KisSignalAutoConnectionsStore maskSignals;
KisColorizeMaskSP activeMask;
KoColorSet colorSet;
int transparentColorIndex = -1;
KisSignalCompressor baseNodeChangedCompressor;
};
-KisToolLazyBrushOptionsWidget::KisToolLazyBrushOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent)
+KisToolSmartPatchOptionsWidget::KisToolSmartPatchOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent)
: QWidget(parent),
m_d(new Private)
{
- m_d->ui = new Ui_KisToolLazyBrushOptionsWidget();
+ m_d->ui = new Ui_KisToolSmartPatchOptionsWidget();
m_d->ui->setupUi(this);
m_d->colorModel = new KisPaletteModel(this);
m_d->ui->colorView->setPaletteModel(m_d->colorModel);
m_d->ui->colorView->setCrossedKeyword("transparent");
connect(m_d->ui->colorView, SIGNAL(clicked(QModelIndex)), this, SLOT(entrySelected(QModelIndex)));
connect(m_d->ui->btnTransparent, SIGNAL(toggled(bool)), this, SLOT(slotMakeTransparent(bool)));
connect(m_d->ui->btnRemove, SIGNAL(clicked()), this, SLOT(slotRemove()));
connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), m_d->ui->btnUpdate, SLOT(setDisabled(bool)));
connect(m_d->ui->btnUpdate, SIGNAL(clicked()), this, SLOT(slotUpdate()));
connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), this, SLOT(slotSetAutoUpdates(bool)));
connect(m_d->ui->chkShowKeyStrokes, SIGNAL(toggled(bool)), this, SLOT(slotSetShowKeyStrokes(bool)));
connect(m_d->ui->chkShowOutput, SIGNAL(toggled(bool)), this, SLOT(slotSetShowOutput(bool)));
connect(&m_d->baseNodeChangedCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateNodeProperties()));
m_d->provider = provider;
const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
m_d->colorSet.add(KoColorSetEntry(KoColor(Qt::red, cs), "color1"));
m_d->colorSet.add(KoColorSetEntry(KoColor(Qt::green, cs), "color2"));
m_d->colorSet.add(KoColorSetEntry(KoColor(Qt::blue, cs), "color3"));
m_d->colorModel->setColorSet(&m_d->colorSet);
}
-KisToolLazyBrushOptionsWidget::~KisToolLazyBrushOptionsWidget()
+KisToolSmartPatchOptionsWidget::~KisToolSmartPatchOptionsWidget()
{
}
-void KisToolLazyBrushOptionsWidget::showEvent(QShowEvent *event)
+void KisToolSmartPatchOptionsWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
m_d->providerSignals.addConnection(
m_d->provider, SIGNAL(sigNodeChanged(KisNodeSP)),
this, SLOT(slotCurrentNodeChanged(KisNodeSP)));
m_d->providerSignals.addConnection(
m_d->provider, SIGNAL(sigFGColorChanged(const KoColor&)),
this, SLOT(slotCurrentFgColorChanged(const KoColor&)));
slotCurrentNodeChanged(m_d->provider->currentNode());
slotCurrentFgColorChanged(m_d->provider->fgColor());
}
-void KisToolLazyBrushOptionsWidget::hideEvent(QHideEvent *event)
+void KisToolSmartPatchOptionsWidget::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
m_d->providerSignals.clear();
}
-void KisToolLazyBrushOptionsWidget::entrySelected(QModelIndex index)
+void KisToolSmartPatchOptionsWidget::entrySelected(QModelIndex index)
{
if (!index.isValid()) return;
const int i = m_d->colorModel->idFromIndex(index);
if (i >= 0 && i < m_d->colorSet.nColors()) {
KoColorSetEntry entry = m_d->colorSet.getColor(i);
m_d->provider->setFGColor(entry.color);
}
const bool transparentChecked = i >= 0 && i == m_d->transparentColorIndex;
KisSignalsBlocker b(m_d->ui->btnTransparent);
m_d->ui->btnTransparent->setChecked(transparentChecked);
}
-void KisToolLazyBrushOptionsWidget::slotCurrentFgColorChanged(const KoColor &color)
+void KisToolSmartPatchOptionsWidget::slotCurrentFgColorChanged(const KoColor &color)
{
int selectedIndex = -1;
for (int i = 0; i < m_d->colorSet.nColors(); i++) {
KoColorSetEntry entry = m_d->colorSet.getColor(i);
if (entry.color == color) {
selectedIndex = i;
break;
}
}
m_d->ui->btnRemove->setEnabled(selectedIndex >= 0);
m_d->ui->btnTransparent->setEnabled(selectedIndex >= 0);
if (selectedIndex < 0) {
KisSignalsBlocker b(m_d->ui->btnTransparent);
m_d->ui->btnTransparent->setChecked(false);
}
QModelIndex newIndex = m_d->colorModel->indexFromId(selectedIndex);
if (newIndex != m_d->ui->colorView->currentIndex()) {
m_d->ui->colorView->setCurrentIndex(newIndex);
}
}
-void KisToolLazyBrushOptionsWidget::slotColorLabelsChanged()
+void KisToolSmartPatchOptionsWidget::slotColorLabelsChanged()
{
m_d->colorSet.clear();
m_d->transparentColorIndex = -1;
if (m_d->activeMask) {
KisColorizeMask::KeyStrokeColors colors = m_d->activeMask->keyStrokesColors();
m_d->transparentColorIndex = colors.transparentIndex;
for (int i = 0; i < colors.colors.size(); i++) {
const QString name = i == m_d->transparentColorIndex ? "transparent" : "";
m_d->colorSet.add(KoColorSetEntry(colors.colors[i], name));
}
}
m_d->colorModel->setColorSet(&m_d->colorSet);
slotCurrentFgColorChanged(m_d->provider->fgColor());
}
-void KisToolLazyBrushOptionsWidget::slotUpdateNodeProperties()
+void KisToolSmartPatchOptionsWidget::slotUpdateNodeProperties()
{
KisSignalsBlocker b(m_d->ui->chkAutoUpdates,
m_d->ui->btnUpdate,
m_d->ui->chkShowKeyStrokes,
m_d->ui->chkShowOutput);
// not implemented yet!
//m_d->ui->chkAutoUpdates->setEnabled(m_d->activeMask);
m_d->ui->chkAutoUpdates->setEnabled(false);
bool value = false;
value = m_d->activeMask && !KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeNeedsUpdate, true).toBool();
m_d->ui->btnUpdate->setEnabled(m_d->activeMask && !m_d->ui->chkAutoUpdates->isChecked());
m_d->ui->btnUpdate->setChecked(value);
value = m_d->activeMask && KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool();
m_d->ui->chkShowKeyStrokes->setEnabled(m_d->activeMask);
m_d->ui->chkShowKeyStrokes->setChecked(value);
value = m_d->activeMask && KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeShowColoring, true).toBool();
m_d->ui->chkShowOutput->setEnabled(m_d->activeMask);
m_d->ui->chkShowOutput->setChecked(value);
}
-void KisToolLazyBrushOptionsWidget::slotCurrentNodeChanged(KisNodeSP node)
+void KisToolSmartPatchOptionsWidget::slotCurrentNodeChanged(KisNodeSP node)
{
m_d->maskSignals.clear();
KisColorizeMask *mask = dynamic_cast(node.data());
m_d->activeMask = mask;
if (m_d->activeMask) {
m_d->maskSignals.addConnection(
m_d->activeMask, SIGNAL(sigKeyStrokesListChanged()),
this, SLOT(slotColorLabelsChanged()));
m_d->maskSignals.addConnection(
m_d->provider->currentImage(), SIGNAL(sigNodeChanged(KisNodeSP)),
this, SLOT(slotUpdateNodeProperties()));
}
slotColorLabelsChanged();
slotUpdateNodeProperties();
m_d->ui->colorView->setEnabled(m_d->activeMask);
}
-void KisToolLazyBrushOptionsWidget::slotMakeTransparent(bool value)
+void KisToolSmartPatchOptionsWidget::slotMakeTransparent(bool value)
{
KIS_ASSERT_RECOVER_RETURN(m_d->activeMask);
QModelIndex index = m_d->ui->colorView->currentIndex();
if (!index.isValid()) return;
const int activeIndex = m_d->colorModel->idFromIndex(index);
KIS_ASSERT_RECOVER_RETURN(activeIndex >= 0);
KisColorizeMask::KeyStrokeColors colors;
for (int i = 0; i < m_d->colorSet.nColors(); i++) {
colors.colors << m_d->colorSet.getColor(i).color;
}
colors.transparentIndex = value ? activeIndex : -1;
m_d->activeMask->setKeyStrokesColors(colors);
}
-void KisToolLazyBrushOptionsWidget::slotRemove()
+void KisToolSmartPatchOptionsWidget::slotRemove()
{
KIS_ASSERT_RECOVER_RETURN(m_d->activeMask);
QModelIndex index = m_d->ui->colorView->currentIndex();
if (!index.isValid()) return;
const int activeIndex = m_d->colorModel->idFromIndex(index);
KIS_ASSERT_RECOVER_RETURN(activeIndex >= 0);
const KoColor color = m_d->colorSet.getColor(activeIndex).color;
m_d->activeMask->removeKeyStroke(color);
}
-void KisToolLazyBrushOptionsWidget::slotUpdate()
+void KisToolSmartPatchOptionsWidget::slotUpdate()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask);
KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeNeedsUpdate, false, m_d->provider->currentImage());
}
-void KisToolLazyBrushOptionsWidget::slotSetAutoUpdates(bool value)
+void KisToolSmartPatchOptionsWidget::slotSetAutoUpdates(bool value)
{
ENTER_FUNCTION() << ppVar(value);
}
-void KisToolLazyBrushOptionsWidget::slotSetShowKeyStrokes(bool value)
+void KisToolSmartPatchOptionsWidget::slotSetShowKeyStrokes(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask);
KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, value, m_d->provider->currentImage());
}
-void KisToolLazyBrushOptionsWidget::slotSetShowOutput(bool value)
+void KisToolSmartPatchOptionsWidget::slotSetShowOutput(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask);
KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeShowColoring, value, m_d->provider->currentImage());
}
diff --git a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.h b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.h
index 4ef1f96c35..3b3761d872 100644
--- a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.h
+++ b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.h
@@ -1,64 +1,64 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_TOOL_LAZY_BRUSH_OPTIONS_WIDGET_H
-#define __KIS_TOOL_LAZY_BRUSH_OPTIONS_WIDGET_H
+#ifndef __KIS_TOOL_SMART_PATCH_OPTIONS_WIDGET_H
+#define __KIS_TOOL_SMART_PATCH_OPTIONS_WIDGET_H
#include
#include
#include
#include "kis_types.h"
class KisCanvasResourceProvider;
class KoColor;
-class KisToolLazyBrushOptionsWidget : public QWidget
+class KisToolSmartPatchOptionsWidget : public QWidget
{
Q_OBJECT
public:
- KisToolLazyBrushOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent);
- ~KisToolLazyBrushOptionsWidget();
+ KisToolSmartPatchOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent);
+ ~KisToolSmartPatchOptionsWidget();
private Q_SLOTS:
void entrySelected(QModelIndex index);
void slotCurrentFgColorChanged(const KoColor &color);
void slotCurrentNodeChanged(KisNodeSP node);
void slotColorLabelsChanged();
void slotMakeTransparent(bool value);
void slotRemove();
void slotUpdate();
void slotSetAutoUpdates(bool value);
void slotSetShowKeyStrokes(bool value);
void slotSetShowOutput(bool value);
void slotUpdateNodeProperties();
protected:
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
private:
struct Private;
const QScopedPointer m_d;
};
-#endif /* __KIS_TOOL_LAZY_BRUSH_OPTIONS_WIDGET_H */
+#endif /* __KIS_TOOL_SMART_PATCH_OPTIONS_WIDGET_H */
diff --git a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.ui b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.ui
index c09421b1b6..35e025744e 100644
--- a/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.ui
+++ b/plugins/tools/tool_smart_patch/kis_tool_smart_patch_options_widget.ui
@@ -1,143 +1,143 @@
- KisToolLazyBrushOptionsWidget
-
+ KisToolSmartPatchOptionsWidget
+
0
0
233
264
2
2
2
2
2
-
-
Auto updates
-
Update
true
-
Edit key strokes
-
Show output
-
Qt::Vertical
QSizePolicy::Minimum
20
10
-
Key Strokes
true
0
0
0
-
0
16
-
-
Transparent
true
-
Remove
KisPaletteView
QTableView
diff --git a/plugins/tools/tool_smart_patch/kritatoolsmartpatch.json b/plugins/tools/tool_smart_patch/kritatoolsmartpatch.json
new file mode 100644
index 0000000000..11401c9ddc
--- /dev/null
+++ b/plugins/tools/tool_smart_patch/kritatoolsmartpatch.json
@@ -0,0 +1,9 @@
+{
+ "Id": "Inpaint Tool",
+ "Type": "Service",
+ "X-KDE-Library": "kritatoolsmartpatch",
+ "X-KDE-ServiceTypes": [
+ "Krita/Tool"
+ ],
+ "X-Krita-Version": "28"
+}
diff --git a/plugins/tools/tool_smart_patch/tool_smartpatch.cpp b/plugins/tools/tool_smart_patch/tool_smartpatch.cpp
index 5174cb20e2..7d5a939c4b 100644
--- a/plugins/tools/tool_smart_patch/tool_smartpatch.cpp
+++ b/plugins/tools/tool_smart_patch/tool_smartpatch.cpp
@@ -1,45 +1,45 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "tool_lazybrush.h"
+#include "tool_smartpatch.h"
#include
#include
#include
#include
#include
#include "kis_paint_device.h"
-#include "kis_tool_lazy_brush.h"
+#include "kis_tool_smart_patch.h"
-K_PLUGIN_FACTORY_WITH_JSON(DefaultToolsFactory, "kritatoollazybrush.json", registerPlugin();)
+K_PLUGIN_FACTORY_WITH_JSON(DefaultToolsFactory, "kritatoolsmartpatch.json", registerPlugin();)
-ToolLazyBrush::ToolLazyBrush(QObject *parent, const QVariantList &)
+ToolSmartPatch::ToolSmartPatch(QObject *parent, const QVariantList &)
: QObject(parent)
{
- KoToolRegistry::instance()->add(new KisToolLazyBrushFactory());
+ KoToolRegistry::instance()->add(new KisToolSmartPatchFactory());
}
-ToolLazyBrush::~ToolLazyBrush()
+ToolSmartPatch::~ToolSmartPatch()
{
}
-#include "tool_lazybrush.moc"
+#include "tool_smartpatch.moc"
diff --git a/plugins/tools/tool_smart_patch/tool_smartpatch.h b/plugins/tools/tool_smart_patch/tool_smartpatch.h
index fbadd0178a..1f3b7c4db6 100644
--- a/plugins/tools/tool_smart_patch/tool_smartpatch.h
+++ b/plugins/tools/tool_smart_patch/tool_smartpatch.h
@@ -1,34 +1,34 @@
/*
- * Copyright (c) 2016 Dmitry Kazakov
+ * Copyright (c) 2017 Eugene Ingerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef TOOL_LAZYBRUSH_H_
-#define TOOL_LAZYBRUSH_H_
+#ifndef TOOL_SMARTPATCH_H_
+#define TOOL_SMARTPATCH_H_
#include
#include
-class ToolLazyBrush : public QObject
+class ToolSmartPatch : public QObject
{
Q_OBJECT
public:
- ToolLazyBrush(QObject *parent, const QVariantList &);
- virtual ~ToolLazyBrush();
+ ToolSmartPatch(QObject *parent, const QVariantList &);
+ virtual ~ToolSmartPatch();
};
-#endif // TOOL_LAZYBRUSH_H_
+#endif // TOOL_SMARTPATCH_H_