diff --git a/krita/krita4.xmlgui b/krita/krita4.xmlgui index 907ebfe326..7c29c0e666 100644 --- a/krita/krita4.xmlgui +++ b/krita/krita4.xmlgui @@ -1,386 +1,379 @@ &File &Edit Fill Special &View &Canvas &Snap To &Image &Rotate &Layer New &Import/Export Import &Convert &Select &Group &Transform &Rotate S&plit S&plit Alpha &Select Filte&r &Tools Scripts - - Macros - - - - - Setti&ngs &Help File Brushes and Stuff diff --git a/krita/kritamenu.action b/krita/kritamenu.action index 151a10df76..22e8e1e24d 100644 --- a/krita/kritamenu.action +++ b/krita/kritamenu.action @@ -1,1822 +1,1770 @@ File document-new &New Create new document New 0 0 Ctrl+N false document-open &Open... Open an existing document Open 0 0 Ctrl+O false document-open-recent Open &Recent Open a document which was recently opened Open Recent 1 0 false document-save &Save Save Save 1 0 Ctrl+S false document-save-as Save &As... Save document under a new name Save As 1 0 Ctrl+Shift+S false Sessions... Open session manager Sessions 0 0 false document-import Open ex&isting Document as Untitled Document... Open existing Document as Untitled Document Open existing Document as Untitled Document 0 0 false document-export E&xport... Export Export 1 0 false application-pdf &Export as PDF... Export as PDF Export as PDF 1 0 false Import animation frames... Import animation frames Import animation frames 1 0 false &Render Animation... Render Animation to GIF, Image Sequence or Video Render Animation 1000 0 false &Render Image Sequence Again Render Animation to Image Sequence Again Render Animation 1000 0 false Save Incremental &Version Save Incremental Version Save Incremental Version 1 0 Ctrl+Alt+S false Save Incremental &Backup Save Incremental Backup Save Incremental Backup 1 0 F4 false &Create Template From Image... Create Template From Image Create Template From Image 1 0 false Create Copy &From Current Image Create Copy From Current Image Create Copy From Current Image 1 0 false document-print &Print... Print document Print 1 0 Ctrl+P false document-print-preview Print Previe&w Show a print preview of document Print Preview 1 0 false configure &Document Information Document Information Document Information 1 0 false &Close All Close All Close All 1 0 Ctrl+Shift+W false C&lose Close Close 1 0 false &Quit Quit application Quit 0 0 Ctrl+Q false Edit edit-undo Undo Undo last action Undo 1 0 Ctrl+Z false edit-redo Redo Redo last undone action Redo 1 0 Ctrl+Shift+Z false edit-cut Cu&t Cut selection to clipboard Cut 0 0 Ctrl+X false edit-copy &Copy Copy selection to clipboard Copy 0 0 Ctrl+C false C&opy (sharp) Copy (sharp) Copy (sharp) 100000000 0 false Cut (&sharp) Cut (sharp) Cut (sharp) 100000000 0 false Copy &merged Copy merged Copy merged 100000000 0 Ctrl+Shift+C false edit-paste &Paste Paste clipboard content Paste 0 0 Ctrl+V false Paste at Cursor Paste at cursor Paste at cursor 0 0 Ctrl+Alt+V false Paste into &New Image Paste into New Image Paste into New Image 0 0 Ctrl+Shift+N false edit-clear C&lear Clear Clear 1 0 Del false &Fill with Foreground Color Fill with Foreground Color Fill with Foreground Color 10000 1 Shift+Backspace false Fill &with Background Color Fill with Background Color Fill with Background Color 10000 1 Backspace false F&ill with Pattern Fill with Pattern Fill with Pattern 10000 1 false Fill Special Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) Fill with Foreground Color (Opacity) 10000 1 Ctrl+Shift+Backspace false Fill with Background Color (Opacity) Fill with Background Color (Opacity) Fill with Background Color (Opacity) 10000 1 Ctrl+Backspace false Fill with Pattern (Opacity) Fill with Pattern (Opacity) Fill with Pattern (Opacity) 10000 1 false Stro&ke selected shapes Stroke selected shapes Stroke selected shapes 1000000000 0 false Stroke Selec&tion... Stroke selection Stroke selection 10000000000 0 false Delete keyframe Delete keyframe Delete keyframe 100000 0 false Window window-new &New Window New Window New Window 0 0 false N&ext Next Next 10 0 false Previous Previous Previous false View &Show Canvas Only Show just the canvas or the whole window Show Canvas Only 0 0 Tab true view-fullscreen F&ull Screen Mode Display the window in full screen Full Screen Mode 0 0 Ctrl+Shift+F true &Wrap Around Mode Wrap Around Mode Wrap Around Mode 1 0 W true &Instant Preview Mode Instant Preview Mode Instant Preview Mode 1 0 Shift+L true Soft Proofing Turns on Soft Proofing Turns on Soft Proofing Ctrl+Y true Out of Gamut Warnings Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on. Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on. Ctrl+Shift+Y true mirror-view Mirror View Mirror View Mirror View M false zoom-original &Reset zoom Reset zoom Reset zoom 1 0 Ctrl+0 false zoom-in Zoom &In Zoom In 0 0 Ctrl++ false zoom-out Zoom &Out Zoom Out 0 0 Ctrl+- false rotate-canvas-right Rotate &Canvas Right Rotate Canvas Right Rotate Canvas Right 1 0 Ctrl+] false rotate-canvas-left Rotate Canvas &Left Rotate Canvas Left Rotate Canvas Left 1 0 Ctrl+[ false rotation-reset Reset Canvas Rotation Reset Canvas Rotation Reset Canvas Rotation 1 0 false Show &Rulers The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p> Show Rulers Show Rulers 1 0 true Rulers Track Pointer The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown Rulers Track Pointer Rulers Track Pointer 1 0 true Show Guides Show or hide guides Show Guides 1 0 true Lock Guides Lock or unlock guides Lock Guides 1 0 true Snap to Guides Snap cursor to guides position Snap to Guides 1 0 true Show Status &Bar Show or hide the status bar Show Status Bar 0 0 true Show Pixel Grid Show Pixel Grid Show Pixel Grid 1000 0 true view-grid Show &Grid Show Grid Show Grid 1000 0 Ctrl+Shift+' true Snap To Grid Snap To Grid Snap To Grid 1000 Ctrl+Shift+; true Show Snap Options Popup Show Snap Options Popup Show Snap Options Popup 1000 Shift+s false Snap Orthogonal Snap Orthogonal Snap Orthogonal 1000 true Snap Node Snap Node Snap Node 1000 true Snap Extension Snap Extension Snap Extension 1000 true Snap Intersection Snap Intersection Snap Intersection 1000 true Snap Bounding Box Snap Bounding Box Snap Bounding Box 1000 true Snap Image Bounds Snap Image Bounds Snap Image Bounds 1000 true Snap Image Center Snap Image Center Snap Image Center 1000 true S&how Painting Assistants Show Painting Assistants Show Painting Assistants 1000 0 true Show &Assistant Previews Show Assistant Previews Show Assistant Previews 1000 0 true S&how Reference Images Show Reference Images Show Reference Images 1000 0 true Image document-properties &Properties... Properties Properties 1000 0 false format-stroke-color &Image Background Color and Transparency... Change the background color of the image Image Background Color and Transparency 1000 0 false &Convert Image Color Space... Convert Image Color Space Convert Image Color Space 1000 0 false trim-to-image &Trim to Image Size Trim to Image Size Trim to Image Size 1 0 false Trim to Current &Layer Trim to Current Layer Trim to Current Layer 100000 0 false Trim to S&election Trim to Selection Trim to Selection 100000000 0 false &Rotate Image... Rotate Image Rotate Image 1000 0 false object-rotate-right Rotate &Image 90° to the Right Rotate Image 90° to the Right Rotate Image 90° to the Right 1000 0 false object-rotate-left Rotate Image &90° to the Left Rotate Image 90° to the Left Rotate Image 90° to the Left 1000 0 false Rotate Image &180° Rotate Image 180° Rotate Image 180° 1000 0 false &Shear Image... Shear Image Shear Image 1000 0 false symmetry-horizontal &Mirror Image Horizontally Mirror Image Horizontally Mirror Image Horizontally 1000 0 false symmetry-vertical Mirror Image &Vertically Mirror Image Vertically Mirror Image Vertically 1000 0 false Scale Image To &New Size... Scale Image To New Size Scale Image To New Size 1000 0 Ctrl+Alt+I false &Offset Image... Offset Image Offset Image 1000 0 false R&esize Canvas... Resize Canvas Resize Canvas 1000 0 Ctrl+Alt+C false Im&age Split Image Split Image Split 1000 0 false Separate Ima&ge... Separate Image Separate Image 1000 0 false Select edit-select-all Select &All Select All Select All 0 0 Ctrl+A false edit-select-all &Deselect Deselect Deselect 1100000000 0 Ctrl+Shift+A false &Reselect Reselect Reselect 0 0 Ctrl+Shift+D false &Invert Selection Invert Selection Invert Selection 10000 0 Ctrl+I false &Convert to Vector Selection Convert to Vector Selection Convert to Vector Selection 10000000000 0 false Convert Shapes to &Vector Selection Convert Shapes to Vector Selection Convert Shapes to Vector Selection 1000000000 0 false &Feather Selection... Feather Selection Feather Selection 10000000000 100 Shift+F6 false Dis&play Selection Display Selection Display Selection 1000 0 Ctrl+H true Sca&le... Scale Scale 100000000 100 false S&elect from Color Range... Select from Color Range Select from Color Range 10000 100 false Select &Opaque Select Opaque Select Opaque 10000 100 false &Grow Selection... Grow Selection Grow Selection 10000000000 100 false S&hrink Selection... Shrink Selection Shrink Selection 10000000000 100 false &Border Selection... Border Selection Border Selection 10000000000 100 false S&mooth Smooth Smooth 10000000000 100 false Filter &Apply Filter Again Apply Filter Again Apply Filter Again 0 0 Ctrl+F false Adjust Adjust Adjust false Artistic Artistic Artistic false Blur Blur Blur false Colors Colors Colors false Edge Detection Edge Detection Edge Detection false Enhance Enhance Enhance false Emboss Emboss Emboss false Map Map Map false Other Other Other false gmic Start G'MIC-Qt Start G'Mic-Qt Start G'Mic-Qt false gmic Re-apply the last G'MIC filter Apply the last G'Mic-Qt action again Apply the last G'Mic-Qt action again false - - Tools - - media-record - &Start recording macro - - Start recording macro - Start recording macro - 1000 - 0 - - false - - - - media-playback-stop - Stop &recording macro - - Stop recording macro - Stop recording macro - 1000 - 0 - - false - - - - media-playback-start - &Open and play... - - Open and play - Open and play - 0 - 0 - - false - - - - document-edit - Open &and edit... - - Open and edit - Open and edit - 0 - 0 - - false - - - - Settings configure &Configure Krita... Configure Krita Configure Krita 0 0 false &Manage Resources... Manage Resources Manage Resources 0 0 false preferences-desktop-locale Switch Application &Language... Switch Application Language Switch Application Language false &Show Dockers Show Dockers Show Dockers 0 0 true configure Configure Tool&bars... Configure Toolbars Configure Toolbars 0 0 false Dockers Dockers Dockers false &Themes Themes Themes false im-user Active Author Profile Active Author Profile Active Author Profile configure-shortcuts Configure S&hortcuts... Configure Shortcuts Configure Shortcuts 0 0 false &Window Window Window false Help help-contents Krita &Handbook Krita Handbook Krita Handbook F1 false tools-report-bug &Report Bug... Report Bug Report Bug false calligrakrita &About Krita About Krita About Krita false kde About &KDE About KDE About KDE false Brushes and Stuff &Gradients Gradients Gradients false &Patterns Patterns Patterns false &Color Color Color false &Painter's Tools Painter's Tools Painter's Tools false Brush composite Brush composite Brush composite false Brush option slider 1 Brush option slider 1 Brush option slider 1 false Brush option slider 2 Brush option slider 2 Brush option slider 2 false Brush option slider 3 Brush option slider 3 Brush option slider 3 false Mirror Mirror Mirror false Layouts Select layout false Workspaces Workspaces Workspaces false diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt index d20f437daa..f72d83badf 100644 --- a/libs/image/CMakeLists.txt +++ b/libs/image/CMakeLists.txt @@ -1,402 +1,387 @@ 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} ) 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/KisTiledExtentManager.cpp tiles3/kis_memento_manager.cc tiles3/kis_hline_iterator.cpp tiles3/kis_vline_iterator.cpp tiles3/kis_random_accessor.cc tiles3/swap/kis_abstract_compression.cpp tiles3/swap/kis_lzf_compression.cpp tiles3/swap/kis_abstract_tile_compressor.cpp tiles3/swap/kis_legacy_tile_compressor.cpp tiles3/swap/kis_tile_compressor_2.cpp tiles3/swap/kis_chunk_allocator.cpp tiles3/swap/kis_memory_window.cpp tiles3/swap/kis_swapped_data_store.cpp tiles3/swap/kis_tile_data_swapper.cpp kis_distance_information.cpp kis_painter.cc kis_painter_blt_multi_fixed.cpp kis_marker_painter.cpp KisPrecisePaintDeviceWrapper.cpp kis_progress_updater.cpp brushengine/kis_paint_information.cc brushengine/kis_random_source.cpp brushengine/KisPerStrokeRandomSource.cpp brushengine/kis_stroke_random_source.cpp brushengine/kis_paintop.cc brushengine/kis_paintop_factory.cpp brushengine/kis_paintop_preset.cpp brushengine/kis_paintop_registry.cc brushengine/kis_paintop_settings.cpp brushengine/kis_paintop_settings_update_proxy.cpp brushengine/kis_paintop_utils.cpp brushengine/kis_no_size_paintop_settings.cpp brushengine/kis_locked_properties.cc brushengine/kis_locked_properties_proxy.cpp brushengine/kis_locked_properties_server.cpp brushengine/kis_paintop_config_widget.cpp brushengine/kis_uniform_paintop_property.cpp brushengine/kis_combo_based_paintop_property.cpp brushengine/kis_slider_based_paintop_property.cpp brushengine/kis_standard_uniform_properties_factory.cpp brushengine/KisStrokeSpeedMeasurer.cpp brushengine/KisPaintopSettingsIds.cpp commands/kis_deselect_global_selection_command.cpp commands/kis_image_change_layers_command.cpp commands/kis_image_change_visibility_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_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/KisWatershedWorker.cpp lazybrush/kis_colorize_mask.cpp lazybrush/kis_colorize_stroke_strategy.cpp KisDelayedUpdateNodeInterface.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_node_uuid_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_edge_detection_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 KisRunnableBasedStrokeStrategy.cpp KisRunnableStrokeJobData.cpp KisRunnableStrokeJobsInterface.cpp KisFakeRunnableStrokeJobsExecutor.cpp kis_stroke_job_strategy.cpp kis_stroke_strategy.cpp kis_stroke.cpp kis_strokes_queue.cpp KisStrokesQueueMutatedJobInterface.cpp kis_simple_update_queue.cpp kis_update_scheduler.cpp kis_queues_progress_updater.cpp kis_composite_progress_proxy.cpp kis_sync_lod_cache_stroke_strategy.cpp kis_lod_capable_layer_offset.cpp kis_update_time_monitor.cpp KisUpdateSchedulerConfigNotifier.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_timed_signal_threshold.cpp kis_layer.cc kis_indirect_painting_support.cpp kis_abstract_projection_plane.cpp kis_layer_projection_plane.cpp kis_layer_utils.cpp kis_mask_projection_plane.cpp kis_projection_leaf.cpp kis_mask.cc kis_base_mask_generator.cpp kis_rect_mask_generator.cpp kis_circle_mask_generator.cpp kis_gauss_circle_mask_generator.cpp kis_gauss_rect_mask_generator.cpp ${__per_arch_circle_mask_generator_objs} kis_curve_circle_mask_generator.cpp kis_curve_rect_mask_generator.cpp kis_math_toolbox.cpp kis_memory_statistics_server.cpp kis_name_server.cpp kis_node.cpp kis_node_facade.cpp kis_node_progress_proxy.cpp kis_busy_progress_indicator.cpp kis_node_visitor.cpp kis_paint_device.cc kis_paint_device_debug_utils.cpp kis_fixed_paint_device.cpp KisOptimizedByteArray.cpp kis_paint_layer.cc kis_perspective_math.cpp kis_pixel_selection.cpp kis_processing_information.cpp kis_properties_configuration.cc kis_random_accessor_ng.cpp kis_random_generator.cc kis_random_sub_accessor.cpp kis_wrapped_random_accessor.cpp kis_selection.cc kis_selection_mask.cpp kis_update_outline_job.cpp kis_update_selection_job.cpp kis_serializable_configuration.cc kis_transaction_data.cpp kis_transform_worker.cc kis_perspectivetransform_worker.cpp bsplines/kis_bspline_1d.cpp bsplines/kis_bspline_2d.cpp bsplines/kis_nu_bspline_2d.cpp kis_warptransform_worker.cc kis_cage_transform_worker.cpp kis_liquify_transform_worker.cpp kis_green_coordinates_math.cpp kis_transparency_mask.cc kis_undo_adapter.cpp kis_macro_based_undo_store.cpp kis_surrogate_undo_adapter.cpp kis_legacy_undo_adapter.cpp kis_post_execution_undo_adapter.cpp kis_processing_visitor.cpp kis_processing_applicator.cpp krita_utils.cpp kis_outline_generator.cpp kis_layer_composition.cpp kis_selection_filters.cpp KisProofingConfiguration.h 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 + + kis_node_query_path.cc ) set(einspline_SRCS 3rdparty/einspline/bspline_create.cpp 3rdparty/einspline/bspline_data.cpp 3rdparty/einspline/multi_bspline_create.cpp 3rdparty/einspline/nubasis.cpp 3rdparty/einspline/nubspline_create.cpp 3rdparty/einspline/nugrid.cpp ) add_library(kritaimage SHARED ${kritaimage_LIB_SRCS} ${einspline_SRCS}) generate_export_header(kritaimage BASE_NAME kritaimage) target_link_libraries(kritaimage PUBLIC kritaversion kritawidgets kritaglobal kritapsd kritaodf kritapigment kritacommand kritawidgetutils 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/TODO b/libs/image/TODO deleted file mode 100644 index 6698919416..0000000000 --- a/libs/image/TODO +++ /dev/null @@ -1,5 +0,0 @@ -because KoUpdater was moved to komvc, Krita/Image now -depends on komvc again -- this is not right, since it -makes it impossible to use krita/image outside a calligra -mvc application framework, so KoUpdater must be moved out -again. diff --git a/libs/image/brushengine/kis_paintop_settings.h b/libs/image/brushengine/kis_paintop_settings.h index d820f5bcce..14c39bbf89 100644 --- a/libs/image/brushengine/kis_paintop_settings.h +++ b/libs/image/brushengine/kis_paintop_settings.h @@ -1,351 +1,351 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_SETTINGS_H_ #define KIS_PAINTOP_SETTINGS_H_ #include "kis_types.h" #include "kritaimage_export.h" #include #include #include "kis_properties_configuration.h" #include #include class KisPaintOpConfigWidget; class KisPaintopSettingsUpdateProxy; /** * Configuration property used to control whether airbrushing is enabled. */ const QString AIRBRUSH_ENABLED = "PaintOpSettings/isAirbrushing"; /** * Configuration property used to control airbrushing rate. The value should be in dabs per second. */ const QString AIRBRUSH_RATE = "PaintOpSettings/rate"; /** * Configuration property used to control whether airbrushing is configured to ignore distance-based * spacing. */ const QString AIRBRUSH_IGNORE_SPACING = "PaintOpSettings/ignoreSpacing"; /** * Configuration property used to control whether the spacing settings can be updated between * painted dabs. */ const QString SPACING_USE_UPDATES = "PaintOpSettings/updateSpacingBetweenDabs"; /** * This class is used to cache the settings for a paintop * between two creations. There is one KisPaintOpSettings per input device (mouse, tablet, * etc...). * - * The settings may be stored in a preset or a recorded brush stroke. Note that if your + * The settings may be stored in a preset. Note that if your * paintop's settings subclass has data that is not stored as a property, that data is not * saved and restored. * * The object also contains a pointer to its parent KisPaintOpPreset object.This is to control the DirtyPreset * property of KisPaintOpPreset. Whenever the settings are changed/modified from the original -- the preset is * set to dirty. */ class KRITAIMAGE_EXPORT KisPaintOpSettings : public KisPropertiesConfiguration { public: KisPaintOpSettings(); ~KisPaintOpSettings() override; KisPaintOpSettings(const KisPaintOpSettings &rhs); /** * */ void setOptionsWidget(KisPaintOpConfigWidget* widget); /** * This function is called by a tool when the mouse is pressed. It's useful if * the paintop needs mouse interaction for instance in the case of the clone op. * If the tool is supposed to ignore the event, the paint op should return false * and if the tool is supposed to use the event, return true. */ virtual bool mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode); /** * Clone the current settings object. Override this if your settings instance doesn't * store everything as properties. */ virtual KisPaintOpSettingsSP clone() const; /** * Removes all the settings from the object while keeping the paintop id, * which is loaded to the object by the factory */ void resetSettings(const QStringList &preserveProperties = QStringList()); /** * @return the node the paintop is working on. */ KisNodeSP node() const; /** * Call this function when the paint op is selected or the tool is activated */ virtual void activate(); /** * XXX: Remove this after 2.0, when the paint operation (incremental/non incremental) will * be completely handled in the paintop, not in the tool. This is a filthy hack to move * the option to the right place, at least. * @return true if we paint incrementally, false if we paint like Photoshop. By default, paintops * do not support non-incremental. */ virtual bool paintIncremental() { return true; } /** * @return the composite op it to which the indirect painting device * should be initialized to. This is used by clone op to reset * the composite op to COMPOSITE_COPY */ virtual QString indirectPaintingCompositeOp() const; /** * Whether this paintop wants to deposit paint even when not moving, i.e. the tool needs to * activate its timer. If this is true, painting updates need to be generated at regular * intervals even in the absence of input device events, e.g. when the cursor is not moving. * * The default implementation checks the property AIRBRUSH_ENABLED, defaulting to false if the * property is not found. This should be suitable for most paintops. */ virtual bool isAirbrushing() const; /** * Indicates the minimum time interval that might be needed between airbrush dabs, in * milliseconds. A lower value means painting updates need to happen more frequently. This value * should be ignored if isAirbrushing() is false. * * The default implementation uses the property AIRBRUSH_RATE, defaulting to an interval of * one second if the property is not found. This should be suitable for most paintops. */ virtual qreal airbrushInterval() const; /** * Indicates whether this configuration allows spacing information to be updated between painted * dabs during a stroke. */ virtual bool useSpacingUpdates() const; /** * Indicates if the tool should call paintOp->doAsynchronousUpdate() inbetween * paintAt() calls to do the asynchronous rendering */ virtual bool needsAsynchronousUpdates() const; /** * This structure defines the current mode for painting an outline. */ struct OutlineMode { bool isVisible = false; bool forceCircle = false; bool showTiltDecoration = false; bool forceFullSize = false; }; /** * Returns the brush outline in pixel coordinates. Tool is responsible for conversion into view coordinates. * Outline mode has to be passed to the paintop which builds the outline as some paintops have to paint outline * always like clone paintop indicating the duplicate position */ virtual QPainterPath brushOutline(const KisPaintInformation &info, const OutlineMode &mode); /** * Helpers for drawing the brush outline */ static QPainterPath ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation); /** * Helper for drawing a triangle representing the tilt of the stylus. * * @param start is the offset from the brush's outline's bounding box * @param lengthScale is used for deciding the size of the triangle. * Brush diameter or width are common choices for this. * @param angle is the angle between the two sides of the triangle. */ static QPainterPath makeTiltIndicator(KisPaintInformation const& info, QPointF const& start, qreal lengthScale, qreal angle); /** * Set paintop opacity directly in the properties */ void setPaintOpOpacity(qreal value); /** * Set paintop flow directly in the properties */ void setPaintOpFlow(qreal value); /** * Set paintop composite mode directly in the properties */ void setPaintOpCompositeOp(const QString &value); /** * @return opacity saved in the properties */ qreal paintOpOpacity(); /** * @return flow saved in the properties */ qreal paintOpFlow(); /** * @return composite mode saved in the properties */ QString paintOpCompositeOp(); /** * Set paintop size directly in the properties */ virtual void setPaintOpSize(qreal value) = 0; /** * @return size saved in the properties */ virtual qreal paintOpSize() const = 0; void setEraserMode(bool value); bool eraserMode(); qreal savedEraserSize() const; void setSavedEraserSize(qreal value); qreal savedBrushSize() const; void setSavedBrushSize(qreal value); qreal savedEraserOpacity() const; void setSavedEraserOpacity(qreal value); qreal savedBrushOpacity() const; void setSavedBrushOpacity(qreal value); QString effectivePaintOpCompositeOp(); void setPreset(KisPaintOpPresetWSP preset); KisPaintOpPresetWSP preset() const; /** * @return filename of the 3D brush model, empty if no brush is set */ virtual QString modelName() const; /** * Set filename of 3D brush model. By default no brush is set */ void setModelName(const QString & modelName); /// Check if the settings are valid, setting might be invalid through missing brushes etc /// Overwrite if the settings of a paintop can be invalid /// @return state of the settings, default implementation is true virtual bool isValid() const; /// Check if the settings are loadable, that might the case if we can fallback to something /// Overwrite if the settings can do some kind of fallback /// @return loadable state of the settings, by default implementation return the same as isValid() virtual bool isLoadable(); /** * These methods are populating properties with runtime * information about canvas rotation/mirroring. This information * is set directly by KisToolFreehand. Later the data is accessed * by the pressure options to make a final decision. */ void setCanvasRotation(qreal angle); void setCanvasMirroring(bool xAxisMirrored, bool yAxisMirrored); /** * Overrides the method in KisPropertiesCofiguration to allow * onPropertyChanged() callback */ void setProperty(const QString & name, const QVariant & value) override; virtual QList uniformProperties(KisPaintOpSettingsSP settings); static bool isLodUserAllowed(const KisPropertiesConfigurationSP config); static void setLodUserAllowed(KisPropertiesConfigurationSP config, bool value); virtual bool lodSizeThresholdSupported() const; qreal lodSizeThreshold() const; void setLodSizeThreshold(qreal value); /** * @return the option widget of the paintop (can be 0 is no option widgets is set) */ KisPaintOpConfigWidget* optionsWidget() const; /** * This function is called to set random offsets to the brush whenever the mouse is clicked. It is * specific to when the pattern option is set. * */ virtual void setRandomOffset(const KisPaintInformation &paintInformation); /** * @return true if this preset demands a secondary masked brush running * alongside it */ bool hasMaskingSettings() const; /** * @return a newly created settings object representing a preset of the masking * brush that should be run alongside the current brush */ KisPaintOpSettingsSP createMaskingSettings() const; /** * @return a composite op id of the masked brush rendering algorithm. * * Please take into account that the brush itself always paints in alpha- * darken mode, but the final result is combined with this composite op. */ QString maskingBrushCompositeOp() const; protected: /** * The callback is called every time when a property changes */ virtual void onPropertyChanged(); private: struct Private; const QScopedPointer d; }; #endif diff --git a/libs/image/kis_image.cc b/libs/image/kis_image.cc index 51be3f46df..fa5415f891 100644 --- a/libs/image/kis_image.cc +++ b/libs/image/kis_image.cc @@ -1,1778 +1,1769 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_image.h" #include // WORDS_BIGENDIAN #include #include #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoColor.h" #include "KoColorProfile.h" #include #include "KisProofingConfiguration.h" -#include "recorder/kis_action_recorder.h" #include "kis_adjustment_layer.h" #include "kis_annotation.h" #include "kis_change_profile_visitor.h" #include "kis_colorspace_convert_visitor.h" #include "kis_count_visitor.h" #include "kis_filter_strategy.h" #include "kis_group_layer.h" #include "commands/kis_image_commands.h" #include "kis_layer.h" #include "kis_meta_data_merge_strategy_registry.h" #include "kis_name_server.h" #include "kis_paint_layer.h" #include "kis_projection_leaf.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_transaction.h" #include "kis_meta_data_merge_strategy.h" #include "kis_memory_statistics_server.h" #include "kis_image_config.h" #include "kis_update_scheduler.h" #include "kis_image_signal_router.h" #include "kis_image_animation_interface.h" #include "kis_stroke_strategy.h" #include "kis_simple_stroke_strategy.h" #include "kis_image_barrier_locker.h" #include "kis_undo_stores.h" #include "kis_legacy_undo_adapter.h" #include "kis_post_execution_undo_adapter.h" #include "kis_transform_worker.h" #include "kis_processing_applicator.h" #include "processing/kis_crop_processing_visitor.h" #include "processing/kis_crop_selections_processing_visitor.h" #include "processing/kis_transform_processing_visitor.h" #include "commands_new/kis_image_resize_command.h" #include "commands_new/kis_image_set_resolution_command.h" #include "commands_new/kis_activate_selection_mask_command.h" #include "kis_composite_progress_proxy.h" #include "kis_layer_composition.h" #include "kis_wrapped_rect.h" #include "kis_crop_saved_extra_data.h" #include "kis_layer_utils.h" #include "kis_lod_transform.h" #include "kis_suspend_projection_updates_stroke_strategy.h" #include "kis_sync_lod_cache_stroke_strategy.h" #include "kis_projection_updates_filter.h" #include "kis_layer_projection_plane.h" #include "kis_update_time_monitor.h" #include "kis_image_barrier_locker.h" #include #include #include "kis_time_range.h" // #define SANITY_CHECKS #ifdef SANITY_CHECKS #define SANITY_CHECK_LOCKED(name) \ if (!locked()) warnKrita() << "Locking policy failed:" << name \ << "has been called without the image" \ "being locked"; #else #define SANITY_CHECK_LOCKED(name) #endif struct KisImageSPStaticRegistrar { KisImageSPStaticRegistrar() { qRegisterMetaType("KisImageSP"); } }; static KisImageSPStaticRegistrar __registrar; class KisImage::KisImagePrivate { public: KisImagePrivate(KisImage *_q, qint32 w, qint32 h, const KoColorSpace *c, KisUndoStore *undo, KisImageAnimationInterface *_animationInterface) : q(_q) , lockedForReadOnly(false) , width(w) , height(h) , colorSpace(c ? c : KoColorSpaceRegistry::instance()->rgb8()) , nserver(1) , undoStore(undo ? undo : new KisDumbUndoStore()) , legacyUndoAdapter(undoStore.data(), _q) , postExecutionUndoAdapter(undoStore.data(), _q) - , recorder(_q) , signalRouter(_q) , animationInterface(_animationInterface) , scheduler(_q, _q) , axesCenter(QPointF(0.5, 0.5)) { { KisImageConfig cfg; if (cfg.enableProgressReporting()) { scheduler.setProgressProxy(&compositeProgressProxy); } // Each of these lambdas defines a new factory function. scheduler.setLod0ToNStrokeStrategyFactory( [=](bool forgettable) { return KisLodSyncPair( new KisSyncLodCacheStrokeStrategy(KisImageWSP(q), forgettable), KisSyncLodCacheStrokeStrategy::createJobsData(KisImageWSP(q))); }); scheduler.setSuspendUpdatesStrokeStrategyFactory( [=]() { return KisSuspendResumePair( new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), true), KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP(q))); }); scheduler.setResumeUpdatesStrokeStrategyFactory( [=]() { return KisSuspendResumePair( new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), false), KisSuspendProjectionUpdatesStrokeStrategy::createResumeJobsData(KisImageWSP(q))); }); } connect(q, SIGNAL(sigImageModified()), KisMemoryStatisticsServer::instance(), SLOT(notifyImageChanged())); } ~KisImagePrivate() { /** * Stop animation interface. It may use the rootLayer. */ delete animationInterface; /** * First delete the nodes, while strokes * and undo are still alive */ rootLayer.clear(); } KisImage *q; quint32 lockCount = 0; bool lockedForReadOnly; qint32 width; qint32 height; double xres = 1.0; double yres = 1.0; const KoColorSpace * colorSpace; KisProofingConfigurationSP proofingConfig; KisSelectionSP deselectedGlobalSelection; KisGroupLayerSP rootLayer; // The layers are contained in here QList compositions; KisNodeSP isolatedRootNode; bool wrapAroundModePermitted = false; KisNameServer nserver; QScopedPointer undoStore; KisLegacyUndoAdapter legacyUndoAdapter; KisPostExecutionUndoAdapter postExecutionUndoAdapter; - KisActionRecorder recorder; - vKisAnnotationSP annotations; QAtomicInt disableUIUpdateSignals; KisProjectionUpdatesFilterSP projectionUpdatesFilter; KisImageSignalRouter signalRouter; KisImageAnimationInterface *animationInterface; KisUpdateScheduler scheduler; QAtomicInt disableDirtyRequests; KisCompositeProgressProxy compositeProgressProxy; bool blockLevelOfDetail = false; QPointF axesCenter; bool tryCancelCurrentStrokeAsync(); void notifyProjectionUpdatedInPatches(const QRect &rc); }; KisImage::KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace, const QString& name) : QObject(0) , KisShared() , m_d(new KisImagePrivate(this, width, height, colorSpace, undoStore, new KisImageAnimationInterface(this))) { // make sure KisImage belongs to the GUI thread moveToThread(qApp->thread()); connect(this, SIGNAL(sigInternalStopIsolatedModeRequested()), SLOT(stopIsolatedMode())); setObjectName(name); setRootLayer(new KisGroupLayer(this, "root", OPACITY_OPAQUE_U8)); } KisImage::~KisImage() { dbgImage << "deleting kisimage" << objectName(); /** * Request the tools to end currently running strokes */ waitForDone(); delete m_d; disconnect(); // in case Qt gets confused } KisImage *KisImage::clone(bool exactCopy) { return new KisImage(*this, 0, exactCopy); } KisImage::KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy) : KisNodeFacade(), KisNodeGraphListener(), KisShared(), m_d(new KisImagePrivate(this, rhs.width(), rhs.height(), rhs.colorSpace(), undoStore ? undoStore : new KisDumbUndoStore(), new KisImageAnimationInterface(*rhs.animationInterface(), this))) { // make sure KisImage belongs to the GUI thread moveToThread(qApp->thread()); connect(this, SIGNAL(sigInternalStopIsolatedModeRequested()), SLOT(stopIsolatedMode())); setObjectName(rhs.objectName()); m_d->xres = rhs.m_d->xres; m_d->yres = rhs.m_d->yres; if (rhs.m_d->proofingConfig) { m_d->proofingConfig = toQShared(new KisProofingConfiguration(*rhs.m_d->proofingConfig)); } KisNodeSP newRoot = rhs.root()->clone(); newRoot->setGraphListener(this); newRoot->setImage(this); m_d->rootLayer = dynamic_cast(newRoot.data()); setRoot(newRoot); if (exactCopy || rhs.m_d->isolatedRootNode) { QQueue linearizedNodes; KisLayerUtils::recursiveApplyNodes(rhs.root(), [&linearizedNodes](KisNodeSP node) { linearizedNodes.enqueue(node); }); KisLayerUtils::recursiveApplyNodes(newRoot, [&linearizedNodes, exactCopy, &rhs, this](KisNodeSP node) { KisNodeSP refNode = linearizedNodes.dequeue(); if (exactCopy) { node->setUuid(refNode->uuid()); } if (rhs.m_d->isolatedRootNode && rhs.m_d->isolatedRootNode == refNode) { m_d->isolatedRootNode = node; } }); } Q_FOREACH (KisLayerCompositionSP comp, rhs.m_d->compositions) { m_d->compositions << toQShared(new KisLayerComposition(*comp, this)); } rhs.m_d->nserver = KisNameServer(rhs.m_d->nserver); vKisAnnotationSP newAnnotations; Q_FOREACH (KisAnnotationSP annotation, rhs.m_d->annotations) { newAnnotations << annotation->clone(); } m_d->annotations = newAnnotations; KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->projectionUpdatesFilter); KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableUIUpdateSignals); KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableDirtyRequests); m_d->blockLevelOfDetail = rhs.m_d->blockLevelOfDetail; } void KisImage::aboutToAddANode(KisNode *parent, int index) { KisNodeGraphListener::aboutToAddANode(parent, index); SANITY_CHECK_LOCKED("aboutToAddANode"); } void KisImage::nodeHasBeenAdded(KisNode *parent, int index) { KisNodeGraphListener::nodeHasBeenAdded(parent, index); SANITY_CHECK_LOCKED("nodeHasBeenAdded"); m_d->signalRouter.emitNodeHasBeenAdded(parent, index); KisNodeSP newNode = parent->at(index); if (!dynamic_cast(newNode.data())) { emit sigInternalStopIsolatedModeRequested(); } } void KisImage::aboutToRemoveANode(KisNode *parent, int index) { KisNodeSP deletedNode = parent->at(index); if (!dynamic_cast(deletedNode.data())) { emit sigInternalStopIsolatedModeRequested(); } KisNodeGraphListener::aboutToRemoveANode(parent, index); SANITY_CHECK_LOCKED("aboutToRemoveANode"); m_d->signalRouter.emitAboutToRemoveANode(parent, index); } void KisImage::nodeChanged(KisNode* node) { KisNodeGraphListener::nodeChanged(node); requestStrokeEnd(); m_d->signalRouter.emitNodeChanged(node); } void KisImage::invalidateAllFrames() { invalidateFrames(KisTimeRange::infinite(0), QRect()); } KisSelectionSP KisImage::globalSelection() const { KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask(); if (selectionMask) { return selectionMask->selection(); } else { return 0; } } void KisImage::setGlobalSelection(KisSelectionSP globalSelection) { KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask(); if (!globalSelection) { if (selectionMask) { removeNode(selectionMask); } } else { if (!selectionMask) { selectionMask = new KisSelectionMask(this); selectionMask->initSelection(m_d->rootLayer); addNode(selectionMask); // If we do not set the selection now, the setActive call coming next // can be very, very expensive, depending on the size of the image. selectionMask->setSelection(globalSelection); selectionMask->setActive(true); } else { selectionMask->setSelection(globalSelection); } Q_ASSERT(m_d->rootLayer->childCount() > 0); Q_ASSERT(m_d->rootLayer->selectionMask()); } m_d->deselectedGlobalSelection = 0; m_d->legacyUndoAdapter.emitSelectionChanged(); } void KisImage::deselectGlobalSelection() { KisSelectionSP savedSelection = globalSelection(); setGlobalSelection(0); m_d->deselectedGlobalSelection = savedSelection; } bool KisImage::canReselectGlobalSelection() { return m_d->deselectedGlobalSelection; } void KisImage::reselectGlobalSelection() { if(m_d->deselectedGlobalSelection) { setGlobalSelection(m_d->deselectedGlobalSelection); } } QString KisImage::nextLayerName(const QString &_baseName) const { QString baseName = _baseName; if (m_d->nserver.currentSeed() == 0) { m_d->nserver.number(); return i18n("background"); } if (baseName.isEmpty()) { baseName = i18n("Layer"); } return QString("%1 %2").arg(baseName).arg(m_d->nserver.number()); } void KisImage::rollBackLayerName() { m_d->nserver.rollback(); } KisCompositeProgressProxy* KisImage::compositeProgressProxy() { return &m_d->compositeProgressProxy; } bool KisImage::locked() const { return m_d->lockCount != 0; } void KisImage::barrierLock(bool readOnly) { if (!locked()) { requestStrokeEnd(); m_d->scheduler.barrierLock(); m_d->lockedForReadOnly = readOnly; } else { m_d->lockedForReadOnly &= readOnly; } m_d->lockCount++; } bool KisImage::tryBarrierLock(bool readOnly) { bool result = true; if (!locked()) { result = m_d->scheduler.tryBarrierLock(); m_d->lockedForReadOnly = readOnly; } if (result) { m_d->lockCount++; m_d->lockedForReadOnly &= readOnly; } return result; } bool KisImage::isIdle(bool allowLocked) { return (allowLocked || !locked()) && m_d->scheduler.isIdle(); } void KisImage::lock() { if (!locked()) { requestStrokeEnd(); m_d->scheduler.lock(); } m_d->lockCount++; m_d->lockedForReadOnly = false; } void KisImage::unlock() { Q_ASSERT(locked()); if (locked()) { m_d->lockCount--; if (m_d->lockCount == 0) { m_d->scheduler.unlock(!m_d->lockedForReadOnly); } } } void KisImage::blockUpdates() { m_d->scheduler.blockUpdates(); } void KisImage::unblockUpdates() { m_d->scheduler.unblockUpdates(); } void KisImage::setSize(const QSize& size) { m_d->width = size.width(); m_d->height = size.height(); } void KisImage::resizeImageImpl(const QRect& newRect, bool cropLayers) { if (newRect == bounds() && !cropLayers) return; KUndo2MagicString actionName = cropLayers ? kundo2_i18n("Crop Image") : kundo2_i18n("Resize Image"); KisImageSignalVector emitSignals; emitSignals << ComplexSizeChangedSignal(newRect, newRect.size()); emitSignals << ModifiedSignal; KisCropSavedExtraData *extraData = new KisCropSavedExtraData(cropLayers ? KisCropSavedExtraData::CROP_IMAGE : KisCropSavedExtraData::RESIZE_IMAGE, newRect); KisProcessingApplicator applicator(this, m_d->rootLayer, KisProcessingApplicator::RECURSIVE | KisProcessingApplicator::NO_UI_UPDATES, emitSignals, actionName, extraData); if (cropLayers || !newRect.topLeft().isNull()) { KisProcessingVisitorSP visitor = new KisCropProcessingVisitor(newRect, cropLayers, true); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); } applicator.applyCommand(new KisImageResizeCommand(this, newRect.size())); applicator.end(); } void KisImage::resizeImage(const QRect& newRect) { resizeImageImpl(newRect, false); } void KisImage::cropImage(const QRect& newRect) { resizeImageImpl(newRect, true); } void KisImage::cropNode(KisNodeSP node, const QRect& newRect) { bool isLayer = qobject_cast(node.data()); KUndo2MagicString actionName = isLayer ? kundo2_i18n("Crop Layer") : kundo2_i18n("Crop Mask"); KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisCropSavedExtraData *extraData = new KisCropSavedExtraData(KisCropSavedExtraData::CROP_LAYER, newRect, node); KisProcessingApplicator applicator(this, node, KisProcessingApplicator::RECURSIVE, emitSignals, actionName, extraData); KisProcessingVisitorSP visitor = new KisCropProcessingVisitor(newRect, true, false); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } void KisImage::scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy) { bool resolutionChanged = xres != xRes() && yres != yRes(); bool sizeChanged = size != this->size(); if (!resolutionChanged && !sizeChanged) return; KisImageSignalVector emitSignals; if (resolutionChanged) emitSignals << ResolutionChangedSignal; if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), size); emitSignals << ModifiedSignal; KUndo2MagicString actionName = sizeChanged ? kundo2_i18n("Scale Image") : kundo2_i18n("Change Image Resolution"); KisProcessingApplicator::ProcessingFlags signalFlags = (resolutionChanged || sizeChanged) ? KisProcessingApplicator::NO_UI_UPDATES : KisProcessingApplicator::NONE; KisProcessingApplicator applicator(this, m_d->rootLayer, KisProcessingApplicator::RECURSIVE | signalFlags, emitSignals, actionName); qreal sx = qreal(size.width()) / this->size().width(); qreal sy = qreal(size.height()) / this->size().height(); QTransform shapesCorrection; if (resolutionChanged) { shapesCorrection = QTransform::fromScale(xRes() / xres, yRes() / yres); } KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(sx, sy, 0, 0, QPointF(), 0, 0, 0, filterStrategy, shapesCorrection); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (resolutionChanged) { KUndo2Command *parent = new KisResetShapesCommand(m_d->rootLayer); new KisImageSetResolutionCommand(this, xres, yres, parent); applicator.applyCommand(parent); } if (sizeChanged) { applicator.applyCommand(new KisImageResizeCommand(this, size)); } applicator.end(); } void KisImage::scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy) { KUndo2MagicString actionName(kundo2_i18n("Scale Layer")); KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(this, node, KisProcessingApplicator::RECURSIVE, emitSignals, actionName); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(scaleX, scaleY, 0, 0, QPointF(), 0, 0, 0, filterStrategy); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } void KisImage::rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double radians) { QPointF offset; QSize newSize; { KisTransformWorker worker(0, 1.0, 1.0, 0, 0, 0, 0, radians, 0, 0, 0, 0); QTransform transform = worker.transform(); if (resizeImage) { QRect newRect = transform.mapRect(bounds()); newSize = newRect.size(); offset = -newRect.topLeft(); } else { QPointF origin = QRectF(rootNode->exactBounds()).center(); newSize = size(); offset = -(transform.map(origin) - origin); } } bool sizeChanged = resizeImage && (newSize.width() != width() || newSize.height() != height()); // These signals will be emitted after processing is done KisImageSignalVector emitSignals; if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), newSize); emitSignals << ModifiedSignal; // These flags determine whether updates are transferred to the UI during processing KisProcessingApplicator::ProcessingFlags signalFlags = sizeChanged ? KisProcessingApplicator::NO_UI_UPDATES : KisProcessingApplicator::NONE; KisProcessingApplicator applicator(this, rootNode, KisProcessingApplicator::RECURSIVE | signalFlags, emitSignals, actionName); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bicubic"); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(1.0, 1.0, 0.0, 0.0, QPointF(), radians, offset.x(), offset.y(), filter); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (sizeChanged) { applicator.applyCommand(new KisImageResizeCommand(this, newSize)); } applicator.end(); } void KisImage::rotateImage(double radians) { rotateImpl(kundo2_i18n("Rotate Image"), root(), true, radians); } void KisImage::rotateNode(KisNodeSP node, double radians) { if (node->inherits("KisMask")) { rotateImpl(kundo2_i18n("Rotate Mask"), node, false, radians); } else { rotateImpl(kundo2_i18n("Rotate Layer"), node, false, radians); } } void KisImage::shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double angleX, double angleY, const QPointF &origin) { //angleX, angleY are in degrees const qreal pi = 3.1415926535897932385; const qreal deg2rad = pi / 180.0; qreal tanX = tan(angleX * deg2rad); qreal tanY = tan(angleY * deg2rad); QPointF offset; QSize newSize; { KisTransformWorker worker(0, 1.0, 1.0, tanX, tanY, origin.x(), origin.y(), 0, 0, 0, 0, 0); QRect newRect = worker.transform().mapRect(bounds()); newSize = newRect.size(); if (resizeImage) offset = -newRect.topLeft(); } if (newSize == size()) return; KisImageSignalVector emitSignals; if (resizeImage) emitSignals << ComplexSizeChangedSignal(bounds(), newSize); emitSignals << ModifiedSignal; KisProcessingApplicator::ProcessingFlags signalFlags = KisProcessingApplicator::RECURSIVE; if (resizeImage) signalFlags |= KisProcessingApplicator::NO_UI_UPDATES; KisProcessingApplicator applicator(this, rootNode, signalFlags, emitSignals, actionName); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bilinear"); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(1.0, 1.0, tanX, tanY, origin, 0, offset.x(), offset.y(), filter); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (resizeImage) { applicator.applyCommand(new KisImageResizeCommand(this, newSize)); } applicator.end(); } void KisImage::shearNode(KisNodeSP node, double angleX, double angleY) { QPointF shearOrigin = QRectF(bounds()).center(); if (node->inherits("KisMask")) { shearImpl(kundo2_i18n("Shear Mask"), node, false, angleX, angleY, shearOrigin); } else { shearImpl(kundo2_i18n("Shear Layer"), node, false, angleX, angleY, shearOrigin); } } void KisImage::shear(double angleX, double angleY) { shearImpl(kundo2_i18n("Shear Image"), m_d->rootLayer, true, angleX, angleY, QPointF()); } void KisImage::convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { if (!dstColorSpace) return; const KoColorSpace *srcColorSpace = m_d->colorSpace; undoAdapter()->beginMacro(kundo2_i18n("Convert Image Color Space")); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), true)); undoAdapter()->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace)); KisColorSpaceConvertVisitor visitor(this, srcColorSpace, dstColorSpace, renderingIntent, conversionFlags); m_d->rootLayer->accept(visitor); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), false)); undoAdapter()->endMacro(); setModified(); } bool KisImage::assignImageProfile(const KoColorProfile *profile) { if (!profile) return false; const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile); const KoColorSpace *srcCs = colorSpace(); if (!dstCs) return false; m_d->colorSpace = dstCs; KisChangeProfileVisitor visitor(srcCs, dstCs); bool retval = m_d->rootLayer->accept(visitor); m_d->signalRouter.emitNotification(ProfileChangedSignal); return retval; } void KisImage::convertProjectionColorSpace(const KoColorSpace *dstColorSpace) { if (*m_d->colorSpace == *dstColorSpace) return; undoAdapter()->beginMacro(kundo2_i18n("Convert Projection Color Space")); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), true)); undoAdapter()->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace)); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), false)); undoAdapter()->endMacro(); setModified(); } void KisImage::setProjectionColorSpace(const KoColorSpace * colorSpace) { m_d->colorSpace = colorSpace; m_d->rootLayer->resetCache(); m_d->signalRouter.emitNotification(ColorSpaceChangedSignal); } const KoColorSpace * KisImage::colorSpace() const { return m_d->colorSpace; } const KoColorProfile * KisImage::profile() const { return colorSpace()->profile(); } double KisImage::xRes() const { return m_d->xres; } double KisImage::yRes() const { return m_d->yres; } void KisImage::setResolution(double xres, double yres) { m_d->xres = xres; m_d->yres = yres; m_d->signalRouter.emitNotification(ResolutionChangedSignal); } QPointF KisImage::documentToPixel(const QPointF &documentCoord) const { return QPointF(documentCoord.x() * xRes(), documentCoord.y() * yRes()); } QPoint KisImage::documentToImagePixelFloored(const QPointF &documentCoord) const { QPointF pixelCoord = documentToPixel(documentCoord); return QPoint(qFloor(pixelCoord.x()), qFloor(pixelCoord.y())); } QRectF KisImage::documentToPixel(const QRectF &documentRect) const { return QRectF(documentToPixel(documentRect.topLeft()), documentToPixel(documentRect.bottomRight())); } QPointF KisImage::pixelToDocument(const QPointF &pixelCoord) const { return QPointF(pixelCoord.x() / xRes(), pixelCoord.y() / yRes()); } QPointF KisImage::pixelToDocument(const QPoint &pixelCoord) const { return QPointF((pixelCoord.x() + 0.5) / xRes(), (pixelCoord.y() + 0.5) / yRes()); } QRectF KisImage::pixelToDocument(const QRectF &pixelCoord) const { return QRectF(pixelToDocument(pixelCoord.topLeft()), pixelToDocument(pixelCoord.bottomRight())); } qint32 KisImage::width() const { return m_d->width; } qint32 KisImage::height() const { return m_d->height; } KisGroupLayerSP KisImage::rootLayer() const { Q_ASSERT(m_d->rootLayer); return m_d->rootLayer; } KisPaintDeviceSP KisImage::projection() const { if (m_d->isolatedRootNode) { return m_d->isolatedRootNode->projection(); } Q_ASSERT(m_d->rootLayer); KisPaintDeviceSP projection = m_d->rootLayer->projection(); Q_ASSERT(projection); return projection; } qint32 KisImage::nlayers() const { QStringList list; list << "KisLayer"; KisCountVisitor visitor(list, KoProperties()); m_d->rootLayer->accept(visitor); return visitor.count(); } qint32 KisImage::nHiddenLayers() const { QStringList list; list << "KisLayer"; KoProperties properties; properties.setProperty("visible", false); KisCountVisitor visitor(list, properties); m_d->rootLayer->accept(visitor); return visitor.count(); } void KisImage::flatten() { KisLayerUtils::flattenImage(this); } void KisImage::mergeMultipleLayers(QList mergedNodes, KisNodeSP putAfter) { if (!KisLayerUtils::tryMergeSelectionMasks(this, mergedNodes, putAfter)) { KisLayerUtils::mergeMultipleLayers(this, mergedNodes, putAfter); } } void KisImage::mergeDown(KisLayerSP layer, const KisMetaData::MergeStrategy* strategy) { KisLayerUtils::mergeDown(this, layer, strategy); } void KisImage::flattenLayer(KisLayerSP layer) { KisLayerUtils::flattenLayer(this, layer); } void KisImage::setModified() { m_d->signalRouter.emitNotification(ModifiedSignal); } QImage KisImage::convertToQImage(QRect imageRect, const KoColorProfile * profile) { qint32 x; qint32 y; qint32 w; qint32 h; imageRect.getRect(&x, &y, &w, &h); return convertToQImage(x, y, w, h, profile); } QImage KisImage::convertToQImage(qint32 x, qint32 y, qint32 w, qint32 h, const KoColorProfile * profile) { KisPaintDeviceSP dev = projection(); if (!dev) return QImage(); QImage image = dev->convertToQImage(const_cast(profile), x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); return image; } QImage KisImage::convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile) { if (scaledImageSize.isEmpty()) { return QImage(); } KisPaintDeviceSP dev = new KisPaintDevice(colorSpace()); KisPainter gc; gc.copyAreaOptimized(QPoint(0, 0), projection(), dev, bounds()); gc.end(); double scaleX = qreal(scaledImageSize.width()) / width(); double scaleY = qreal(scaledImageSize.height()) / height(); QPointer updater = new KoDummyUpdater(); KisTransformWorker worker(dev, scaleX, scaleY, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, updater, KisFilterStrategyRegistry::instance()->value("Bicubic")); worker.run(); delete updater; return dev->convertToQImage(profile); } void KisImage::notifyLayersChanged() { m_d->signalRouter.emitNotification(LayersChangedSignal); } QRect KisImage::bounds() const { return QRect(0, 0, width(), height()); } QRect KisImage::effectiveLodBounds() const { QRect boundRect = bounds(); const int lod = currentLevelOfDetail(); if (lod > 0) { KisLodTransform t(lod); boundRect = t.map(boundRect); } return boundRect; } KisPostExecutionUndoAdapter* KisImage::postExecutionUndoAdapter() const { const int lod = currentLevelOfDetail(); return lod > 0 ? m_d->scheduler.lodNPostExecutionUndoAdapter() : &m_d->postExecutionUndoAdapter; } void KisImage::setUndoStore(KisUndoStore *undoStore) { m_d->legacyUndoAdapter.setUndoStore(undoStore); m_d->postExecutionUndoAdapter.setUndoStore(undoStore); m_d->undoStore.reset(undoStore); } KisUndoStore* KisImage::undoStore() { return m_d->undoStore.data(); } KisUndoAdapter* KisImage::undoAdapter() const { return &m_d->legacyUndoAdapter; } -KisActionRecorder* KisImage::actionRecorder() const -{ - return &m_d->recorder; -} - void KisImage::setDefaultProjectionColor(const KoColor &color) { KIS_ASSERT_RECOVER_RETURN(m_d->rootLayer); m_d->rootLayer->setDefaultProjectionColor(color); } KoColor KisImage::defaultProjectionColor() const { KIS_ASSERT_RECOVER(m_d->rootLayer) { return KoColor(Qt::transparent, m_d->colorSpace); } return m_d->rootLayer->defaultProjectionColor(); } void KisImage::setRootLayer(KisGroupLayerSP rootLayer) { emit sigInternalStopIsolatedModeRequested(); KoColor defaultProjectionColor(Qt::transparent, m_d->colorSpace); if (m_d->rootLayer) { m_d->rootLayer->setGraphListener(0); m_d->rootLayer->disconnect(); KisPaintDeviceSP original = m_d->rootLayer->original(); defaultProjectionColor = original->defaultPixel(); } m_d->rootLayer = rootLayer; m_d->rootLayer->disconnect(); m_d->rootLayer->setGraphListener(this); m_d->rootLayer->setImage(this); KisPaintDeviceSP newOriginal = m_d->rootLayer->original(); newOriginal->setDefaultPixel(defaultProjectionColor); setRoot(m_d->rootLayer.data()); } void KisImage::addAnnotation(KisAnnotationSP annotation) { // Find the icc annotation, if there is one vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == annotation->type()) { *it = annotation; return; } ++it; } m_d->annotations.push_back(annotation); } KisAnnotationSP KisImage::annotation(const QString& type) { vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == type) { return *it; } ++it; } return KisAnnotationSP(0); } void KisImage::removeAnnotation(const QString& type) { vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == type) { m_d->annotations.erase(it); return; } ++it; } } vKisAnnotationSP_it KisImage::beginAnnotations() { return m_d->annotations.begin(); } vKisAnnotationSP_it KisImage::endAnnotations() { return m_d->annotations.end(); } void KisImage::notifyAboutToBeDeleted() { emit sigAboutToBeDeleted(); } KisImageSignalRouter* KisImage::signalRouter() { return &m_d->signalRouter; } void KisImage::waitForDone() { requestStrokeEnd(); m_d->scheduler.waitForDone(); } KisStrokeId KisImage::startStroke(KisStrokeStrategy *strokeStrategy) { /** * Ask open strokes to end gracefully. All the strokes clients * (including the one calling this method right now) will get * a notification that they should probably end their strokes. * However this is purely their choice whether to end a stroke * or not. */ if (strokeStrategy->requestsOtherStrokesToEnd()) { requestStrokeEnd(); } /** * Some of the strokes can cancel their work with undoing all the * changes they did to the paint devices. The problem is that undo * stack will know nothing about it. Therefore, just notify it * explicitly */ if (strokeStrategy->clearsRedoOnStart()) { m_d->undoStore->purgeRedoState(); } return m_d->scheduler.startStroke(strokeStrategy); } void KisImage::KisImagePrivate::notifyProjectionUpdatedInPatches(const QRect &rc) { KisImageConfig imageConfig; int patchWidth = imageConfig.updatePatchWidth(); int patchHeight = imageConfig.updatePatchHeight(); for (int y = 0; y < rc.height(); y += patchHeight) { for (int x = 0; x < rc.width(); x += patchWidth) { QRect patchRect(x, y, patchWidth, patchHeight); patchRect &= rc; QtConcurrent::run(std::bind(&KisImage::notifyProjectionUpdated, q, patchRect)); } } } bool KisImage::startIsolatedMode(KisNodeSP node) { struct StartIsolatedModeStroke : public KisSimpleStrokeStrategy { StartIsolatedModeStroke(KisNodeSP node, KisImageSP image) : KisSimpleStrokeStrategy("start-isolated-mode", kundo2_noi18n("start-isolated-mode")), m_node(node), m_image(image) { this->enableJob(JOB_INIT, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); setClearsRedoOnStart(false); } void initStrokeCallback() { // pass-though node don't have any projection prepared, so we should // explicitly regenerate it before activating isolated mode. m_node->projectionLeaf()->explicitlyRegeneratePassThroughProjection(); m_image->m_d->isolatedRootNode = m_node; emit m_image->sigIsolatedModeChanged(); // the GUI uses our thread to do the color space conversion so we // need to emit this signal in multiple threads m_image->m_d->notifyProjectionUpdatedInPatches(m_image->bounds()); m_image->invalidateAllFrames(); } private: KisNodeSP m_node; KisImageSP m_image; }; KisStrokeId id = startStroke(new StartIsolatedModeStroke(node, this)); endStroke(id); return true; } void KisImage::stopIsolatedMode() { if (!m_d->isolatedRootNode) return; struct StopIsolatedModeStroke : public KisSimpleStrokeStrategy { StopIsolatedModeStroke(KisImageSP image) : KisSimpleStrokeStrategy("stop-isolated-mode", kundo2_noi18n("stop-isolated-mode")), m_image(image) { this->enableJob(JOB_INIT); setClearsRedoOnStart(false); } void initStrokeCallback() { if (!m_image->m_d->isolatedRootNode) return; //KisNodeSP oldRootNode = m_image->m_d->isolatedRootNode; m_image->m_d->isolatedRootNode = 0; emit m_image->sigIsolatedModeChanged(); // the GUI uses our thread to do the color space conversion so we // need to emit this signal in multiple threads m_image->m_d->notifyProjectionUpdatedInPatches(m_image->bounds()); m_image->invalidateAllFrames(); // TODO: Substitute notifyProjectionUpdated() with this code // when update optimization is implemented // // QRect updateRect = bounds() | oldRootNode->extent(); // oldRootNode->setDirty(updateRect); } private: KisImageSP m_image; }; KisStrokeId id = startStroke(new StopIsolatedModeStroke(this)); endStroke(id); } KisNodeSP KisImage::isolatedModeRoot() const { return m_d->isolatedRootNode; } void KisImage::addJob(KisStrokeId id, KisStrokeJobData *data) { KisUpdateTimeMonitor::instance()->reportJobStarted(data); m_d->scheduler.addJob(id, data); } void KisImage::endStroke(KisStrokeId id) { m_d->scheduler.endStroke(id); } bool KisImage::cancelStroke(KisStrokeId id) { return m_d->scheduler.cancelStroke(id); } bool KisImage::KisImagePrivate::tryCancelCurrentStrokeAsync() { return scheduler.tryCancelCurrentStrokeAsync(); } void KisImage::requestUndoDuringStroke() { emit sigUndoDuringStrokeRequested(); } void KisImage::requestStrokeCancellation() { if (!m_d->tryCancelCurrentStrokeAsync()) { emit sigStrokeCancellationRequested(); } } UndoResult KisImage::tryUndoUnfinishedLod0Stroke() { return m_d->scheduler.tryUndoLastStrokeAsync(); } void KisImage::requestStrokeEnd() { emit sigStrokeEndRequested(); emit sigStrokeEndRequestedActiveNodeFiltered(); } void KisImage::requestStrokeEndActiveNode() { emit sigStrokeEndRequested(); } void KisImage::refreshGraph(KisNodeSP root) { refreshGraph(root, bounds(), bounds()); } void KisImage::refreshGraph(KisNodeSP root, const QRect &rc, const QRect &cropRect) { if (!root) root = m_d->rootLayer; m_d->animationInterface->notifyNodeChanged(root.data(), rc, true); m_d->scheduler.fullRefresh(root, rc, cropRect); } void KisImage::initialRefreshGraph() { /** * NOTE: Tricky part. We set crop rect to null, so the clones * will not rely on precalculated projections of their sources */ refreshGraphAsync(0, bounds(), QRect()); waitForDone(); } void KisImage::refreshGraphAsync(KisNodeSP root) { refreshGraphAsync(root, bounds(), bounds()); } void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc) { refreshGraphAsync(root, rc, bounds()); } void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) { if (!root) root = m_d->rootLayer; m_d->animationInterface->notifyNodeChanged(root.data(), rc, true); m_d->scheduler.fullRefreshAsync(root, rc, cropRect); } void KisImage::requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect) { KIS_ASSERT_RECOVER_RETURN(pseudoFilthy); m_d->animationInterface->notifyNodeChanged(pseudoFilthy.data(), rc, false); m_d->scheduler.updateProjectionNoFilthy(pseudoFilthy, rc, cropRect); } void KisImage::addSpontaneousJob(KisSpontaneousJob *spontaneousJob) { m_d->scheduler.addSpontaneousJob(spontaneousJob); } void KisImage::setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) { // update filters are *not* recursive! KIS_ASSERT_RECOVER_NOOP(!filter || !m_d->projectionUpdatesFilter); m_d->projectionUpdatesFilter = filter; } KisProjectionUpdatesFilterSP KisImage::projectionUpdatesFilter() const { return m_d->projectionUpdatesFilter; } void KisImage::disableDirtyRequests() { setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP(new KisDropAllProjectionUpdatesFilter())); } void KisImage::enableDirtyRequests() { setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP()); } void KisImage::disableUIUpdates() { m_d->disableUIUpdateSignals.ref(); } void KisImage::enableUIUpdates() { m_d->disableUIUpdateSignals.deref(); } void KisImage::notifyProjectionUpdated(const QRect &rc) { KisUpdateTimeMonitor::instance()->reportUpdateFinished(rc); if (!m_d->disableUIUpdateSignals) { int lod = currentLevelOfDetail(); QRect dirtyRect = !lod ? rc : KisLodTransform::upscaledRect(rc, lod); if (dirtyRect.isEmpty()) return; emit sigImageUpdated(dirtyRect); } } void KisImage::setWorkingThreadsLimit(int value) { m_d->scheduler.setThreadsLimit(value); } int KisImage::workingThreadsLimit() const { return m_d->scheduler.threadsLimit(); } void KisImage::notifySelectionChanged() { /** * The selection is calculated asynchromously, so it is not * handled by disableUIUpdates() and other special signals of * KisImageSignalRouter */ m_d->legacyUndoAdapter.emitSelectionChanged(); /** * Editing of selection masks doesn't necessary produce a * setDirty() call, so in the end of the stroke we need to request * direct update of the UI's cache. */ if (m_d->isolatedRootNode && dynamic_cast(m_d->isolatedRootNode.data())) { notifyProjectionUpdated(bounds()); } } void KisImage::requestProjectionUpdateImpl(KisNode *node, const QVector &rects, const QRect &cropRect) { if (rects.isEmpty()) return; m_d->scheduler.updateProjection(node, rects, cropRect); } void KisImage::requestProjectionUpdate(KisNode *node, const QVector &rects, bool resetAnimationCache) { if (m_d->projectionUpdatesFilter && m_d->projectionUpdatesFilter->filter(this, node, rects, resetAnimationCache)) { return; } if (resetAnimationCache) { m_d->animationInterface->notifyNodeChanged(node, rects, false); } /** * Here we use 'permitted' instead of 'active' intentively, * because the updates may come after the actual stroke has been * finished. And having some more updates for the stroke not * supporting the wrap-around mode will not make much harm. */ if (m_d->wrapAroundModePermitted) { QVector allSplitRects; const QRect boundRect = effectiveLodBounds(); Q_FOREACH (const QRect &rc, rects) { KisWrappedRect splitRect(rc, boundRect); allSplitRects.append(splitRect); } requestProjectionUpdateImpl(node, allSplitRects, boundRect); } else { requestProjectionUpdateImpl(node, rects, bounds()); } KisNodeGraphListener::requestProjectionUpdate(node, rects, resetAnimationCache); } void KisImage::invalidateFrames(const KisTimeRange &range, const QRect &rect) { m_d->animationInterface->invalidateFrames(range, rect); } void KisImage::requestTimeSwitch(int time) { m_d->animationInterface->requestTimeSwitchNonGUI(time); } QList KisImage::compositions() { return m_d->compositions; } void KisImage::addComposition(KisLayerCompositionSP composition) { m_d->compositions.append(composition); } void KisImage::removeComposition(KisLayerCompositionSP composition) { m_d->compositions.removeAll(composition); } bool checkMasksNeedConversion(KisNodeSP root, const QRect &bounds) { KisSelectionMask *mask = dynamic_cast(root.data()); if (mask && (!bounds.contains(mask->paintDevice()->exactBounds()) || mask->selection()->hasShapeSelection())) { return true; } KisNodeSP node = root->firstChild(); while (node) { if (checkMasksNeedConversion(node, bounds)) { return true; } node = node->nextSibling(); } return false; } void KisImage::setWrapAroundModePermitted(bool value) { if (m_d->wrapAroundModePermitted != value) { requestStrokeEnd(); } m_d->wrapAroundModePermitted = value; if (m_d->wrapAroundModePermitted && checkMasksNeedConversion(root(), bounds())) { KisProcessingApplicator applicator(this, root(), KisProcessingApplicator::RECURSIVE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Crop Selections")); KisProcessingVisitorSP visitor = new KisCropSelectionsProcessingVisitor(bounds()); applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } } bool KisImage::wrapAroundModePermitted() const { return m_d->wrapAroundModePermitted; } bool KisImage::wrapAroundModeActive() const { return m_d->wrapAroundModePermitted && m_d->scheduler.wrapAroundModeSupported(); } void KisImage::setDesiredLevelOfDetail(int lod) { if (m_d->blockLevelOfDetail) { qWarning() << "WARNING: KisImage::setDesiredLevelOfDetail()" << "was called while LoD functionality was being blocked!"; return; } m_d->scheduler.setDesiredLevelOfDetail(lod); } int KisImage::currentLevelOfDetail() const { if (m_d->blockLevelOfDetail) { return 0; } return m_d->scheduler.currentLevelOfDetail(); } void KisImage::setLevelOfDetailBlocked(bool value) { KisImageBarrierLockerRaw l(this); if (value && !m_d->blockLevelOfDetail) { m_d->scheduler.setDesiredLevelOfDetail(0); } m_d->blockLevelOfDetail = value; } void KisImage::explicitRegenerateLevelOfDetail() { if (!m_d->blockLevelOfDetail) { m_d->scheduler.explicitRegenerateLevelOfDetail(); } } bool KisImage::levelOfDetailBlocked() const { return m_d->blockLevelOfDetail; } void KisImage::notifyNodeCollpasedChanged() { emit sigNodeCollapsedChanged(); } KisImageAnimationInterface* KisImage::animationInterface() const { return m_d->animationInterface; } void KisImage::setProofingConfiguration(KisProofingConfigurationSP proofingConfig) { m_d->proofingConfig = proofingConfig; emit sigProofingConfigChanged(); } KisProofingConfigurationSP KisImage::proofingConfiguration() const { if (m_d->proofingConfig) { return m_d->proofingConfig; } return KisProofingConfigurationSP(); } QPointF KisImage::mirrorAxesCenter() const { return m_d->axesCenter; } void KisImage::setMirrorAxesCenter(const QPointF &value) const { m_d->axesCenter = value; } diff --git a/libs/image/kis_image.h b/libs/image/kis_image.h index 240ffbc2d7..fcea5fd28a 100644 --- a/libs/image/kis_image.h +++ b/libs/image/kis_image.h @@ -1,1109 +1,1103 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_IMAGE_H_ #define KIS_IMAGE_H_ #include #include #include #include #include #include #include #include "kis_paint_device.h" // msvc cannot handle forward declarations, so include kis_paint_device here #include "kis_types.h" #include "kis_shared.h" #include "kis_node_graph_listener.h" #include "kis_node_facade.h" #include "kis_image_interfaces.h" #include "kis_strokes_queue_undo_result.h" #include class KisDocument; class KoColorSpace; class KoColor; class KisCompositeProgressProxy; -class KisActionRecorder; class KisUndoStore; class KisUndoAdapter; class KisImageSignalRouter; class KisPostExecutionUndoAdapter; class KisFilterStrategy; class KoColorProfile; class KisLayerComposition; class KisSpontaneousJob; class KisImageAnimationInterface; class KUndo2MagicString; class KisProofingConfiguration; namespace KisMetaData { class MergeStrategy; } /** * This is the image class, it contains a tree of KisLayer stack and * meta information about the image. And it also provides some * functions to manipulate the whole image. */ class KRITAIMAGE_EXPORT KisImage : public QObject, public KisStrokesFacade, public KisStrokeUndoFacade, public KisUpdatesFacade, public KisProjectionUpdateListener, public KisNodeFacade, public KisNodeGraphListener, public KisShared { Q_OBJECT public: /// @param colorSpace can be null. in that case it will be initialised to a default color space. KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace *colorSpace, const QString& name); ~KisImage() override; public: // KisNodeGraphListener implementation void aboutToAddANode(KisNode *parent, int index) override; void nodeHasBeenAdded(KisNode *parent, int index) override; void aboutToRemoveANode(KisNode *parent, int index) override; void nodeChanged(KisNode * node) override; void invalidateAllFrames() override; void notifySelectionChanged() override; void requestProjectionUpdate(KisNode *node, const QVector &rects, bool resetAnimationCache) override; void invalidateFrames(const KisTimeRange &range, const QRect &rect) override; void requestTimeSwitch(int time) override; public: // KisProjectionUpdateListener implementation void notifyProjectionUpdated(const QRect &rc) override; public: /** * Set the number of threads used by the image's working threads */ void setWorkingThreadsLimit(int value); /** * Return the number of threads available to the image's working threads */ int workingThreadsLimit() const; /** * Makes a copy of the image with all the layers. If possible, shallow * copies of the layers are made. * * \p exactCopy shows if the copied image should look *exactly* the same as * the other one (according to it's .kra xml representation). It means that * the layers will have the same UUID keys and, therefore, you are not * expected to use the copied image anywhere except for saving. Don't use * this option if you plan to work with the copied image later. */ KisImage *clone(bool exactCopy = false); /** * Render the projection onto a QImage. */ QImage convertToQImage(qint32 x1, qint32 y1, qint32 width, qint32 height, const KoColorProfile * profile); /** * Render the projection onto a QImage. * (this is an overloaded function) */ QImage convertToQImage(QRect imageRect, const KoColorProfile * profile); /** * Render a thumbnail of the projection onto a QImage. */ QImage convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile); /** * [low-level] Lock the image without waiting for all the internal job queues are processed * * WARNING: Don't use it unless you really know what you are doing! Use barrierLock() instead! * * Waits for all the **currently running** internal jobs to complete and locks the image * for writing. Please note that this function does **not** wait for all the internal * queues to process, so there might be some non-finished actions pending. It means that * you just postpone these actions until you unlock() the image back. Until then, then image * might easily be frozen in some inconsistent state. * * The only sane usage for this function is to lock the image for **emergency** * processing, when some internal action or scheduler got hung up, and you just want * to fetch some data from the image without races. * * In all other cases, please use barrierLock() instead! */ void lock(); /** * Unlocks the image and starts/resumes all the pending internal jobs. If the image * has been locked for a non-readOnly access, then all the internal caches of the image * (e.g. lod-planes) are reset and regeneration jobs are scheduled. */ void unlock(); /** * @return return true if the image is in a locked state, i.e. all the internal * jobs are blocked from execution by calling wither lock() or barrierLock(). * * When the image is locked, the user can do some modifications to the image * contents safely without a perspective having race conditions with internal * image jobs. */ bool locked() const; /** * @return the global selection object or 0 if there is none. The * global selection is always read-write. */ KisSelectionSP globalSelection() const; /** * Retrieve the next automatic layername (XXX: fix to add option to return Mask X) */ QString nextLayerName(const QString &baseName = "") const; /** * Set the automatic layer name counter one back. */ void rollBackLayerName(); /** * @brief start asynchronous operation on resizing the image * * The method will resize the image to fit the new size without * dropping any pixel data. The GUI will get correct * notification with old and new sizes, so it adjust canvas origin * accordingly and avoid jumping of the canvas on screen * * @param newRect the rectangle of the image which will be visible * after operation is completed * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after ths call. */ void resizeImage(const QRect& newRect); /** * @brief start asynchronous operation on cropping the image * * The method will **drop** all the image data outside \p newRect * and resize the image to fit the new size. The GUI will get correct * notification with old and new sizes, so it adjust canvas origin * accordingly and avoid jumping of the canvas on screen * * @param newRect the rectangle of the image which will be cut-out * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after ths call. */ void cropImage(const QRect& newRect); /** * @brief start asynchronous operation on cropping a subtree of nodes starting at \p node * * The method will **drop** all the layer data outside \p newRect. Neither * image nor a layer will be moved anywhere * * @param newRect the rectangle of the layer which will be cut-out * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after ths call. */ void cropNode(KisNodeSP node, const QRect& newRect); /** * @brief start asynchronous operation on scaling the image * @param size new image size in pixels * @param xres new image x-resolution pixels-per-pt * @param yres new image y-resolution pixels-per-pt * @param filterStrategy filtering strategy * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after ths call. */ void scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy); /** * @brief start asynchronous operation on scaling a subtree of nodes starting at \p node * @param node node to scale * @param scaleX, @param scaleY scale coefficient to be applied to the node * @param filterStrategy filtering strategy * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the image having new size * right after ths call. */ void scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy); /** * @brief start asynchronous operation on rotating the image * * The image is resized to fit the rotated rectangle * * @param radians rotation angle in radians * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void rotateImage(double radians); /** * @brief start asynchronous operation on rotating a subtree of nodes starting at \p node * * The image is not resized! * * @param node the root of the subtree to rotate * @param radians rotation angle in radians * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void rotateNode(KisNodeSP node, double radians); /** * @brief start asynchronous operation on shearing the image * * The image is resized to fit the sheared polygon * * @param angleX, @param angleY are given in degrees. * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void shear(double angleX, double angleY); /** * @brief start asynchronous operation on shearing a subtree of nodes starting at \p node * * The image is not resized! * * @param node the root of the subtree to rotate * @param angleX, @param angleY are given in degrees. * * Please note that the actual operation starts asynchronously in * a background, so you cannot expect the operation being completed * right after the call */ void shearNode(KisNodeSP node, double angleX, double angleY); /** * Convert the image and all its layers to the dstColorSpace */ void convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Set the color space of the projection (and the root layer) * to dstColorSpace. No conversion is done for other layers, * their colorspace can differ. * NOTE: Note conversion is done, only regeneration, so no rendering * intent needed */ void convertProjectionColorSpace(const KoColorSpace *dstColorSpace); // Get the profile associated with this image const KoColorProfile * profile() const; /** * Set the profile of the image to the new profile and do the same for * all layers that have the same colorspace and profile of the image. * It doesn't do any pixel conversion. * * This is essential if you have loaded an image that didn't * have an embedded profile to which you want to attach the right profile. * * This does not create an undo action; only call it when creating or * loading an image. * * @returns false if the profile could not be assigned */ bool assignImageProfile(const KoColorProfile *profile); /** * Returns the current undo adapter. You can add new commands to the * undo stack using the adapter. This adapter is used for a backward * compatibility for old commands created before strokes. It blocks * all the porcessing at the scheduler, waits until it's finished * and executes commands exclusively. */ KisUndoAdapter* undoAdapter() const; /** * This adapter is used by the strokes system. The commands are added * to it *after* redo() is done (in the scheduler context). They are * wrapped into a special command and added to the undo stack. redo() * in not called. */ KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const override; /** * Replace current undo store with the new one. The old store * will be deleted. * This method is used by KisDocument for dropping all the commands * during file loading. */ void setUndoStore(KisUndoStore *undoStore); /** * Return current undo store of the image */ KisUndoStore* undoStore(); - /** - * @return the action recorder associated with this image - */ - KisActionRecorder* actionRecorder() const; - /** * Tell the image it's modified; this emits the sigImageModified * signal. This happens when the image needs to be saved */ void setModified(); /** * The default colorspace of this image: new layers will have this * colorspace and the projection will have this colorspace. */ const KoColorSpace * colorSpace() const; /** * X resolution in pixels per pt */ double xRes() const; /** * Y resolution in pixels per pt */ double yRes() const; /** * Set the resolution in pixels per pt. */ void setResolution(double xres, double yres); /** * Convert a document coordinate to a pixel coordinate. * * @param documentCoord PostScript Pt coordinate to convert. */ QPointF documentToPixel(const QPointF &documentCoord) const; /** * Convert a document coordinate to an integer pixel coordinate rounded down. * * @param documentCoord PostScript Pt coordinate to convert. */ QPoint documentToImagePixelFloored(const QPointF &documentCoord) const; /** * Convert a document rectangle to a pixel rectangle. * * @param documentRect PostScript Pt rectangle to convert. */ QRectF documentToPixel(const QRectF &documentRect) const; /** * Convert a pixel coordinate to a document coordinate. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPointF &pixelCoord) const; /** * Convert an integer pixel coordinate to a document coordinate. * The document coordinate is at the centre of the pixel. * * @param pixelCoord pixel coordinate to convert. */ QPointF pixelToDocument(const QPoint &pixelCoord) const; /** * Convert a document rectangle to an integer pixel rectangle. * * @param pixelCoord pixel coordinate to convert. */ QRectF pixelToDocument(const QRectF &pixelCoord) const; /** * Return the width of the image */ qint32 width() const; /** * Return the height of the image */ qint32 height() const; /** * Return the size of the image */ QSize size() const { return QSize(width(), height()); } /** * @return the root node of the image node graph */ KisGroupLayerSP rootLayer() const; /** * Return the projection; that is, the complete, composited * representation of this image. */ KisPaintDeviceSP projection() const; /** * Return the number of layers (not other nodes) that are in this * image. */ qint32 nlayers() const; /** * Return the number of layers (not other node types) that are in * this image and that are hidden. */ qint32 nHiddenLayers() const; /** * Merge all visible layers and discard hidden ones. */ void flatten(); /** * Merge the specified layer with the layer * below this layer, remove the specified layer. */ void mergeDown(KisLayerSP l, const KisMetaData::MergeStrategy* strategy); /** * flatten the layer: that is, the projection becomes the layer * and all subnodes are removed. If this is not a paint layer, it will morph * into a paint layer. */ void flattenLayer(KisLayerSP layer); /** * Merges layers in \p mergedLayers and creates a new layer above * \p putAfter */ void mergeMultipleLayers(QList mergedLayers, KisNodeSP putAfter); /// @return the exact bounds of the image in pixel coordinates. QRect bounds() const; /** * Returns the actual bounds of the image, taking LevelOfDetail * into account. This value is used as a bounds() value of * KisDefaultBounds object. */ QRect effectiveLodBounds() const; /// use if the layers have changed _completely_ (eg. when flattening) void notifyLayersChanged(); /** * Sets the default color of the root layer projection. All the layers * will be merged on top of this very color */ void setDefaultProjectionColor(const KoColor &color); /** * \see setDefaultProjectionColor() */ KoColor defaultProjectionColor() const; void setRootLayer(KisGroupLayerSP rootLayer); /** * Add an annotation for this image. This can be anything: Gamma, EXIF, etc. * Note that the "icc" annotation is reserved for the color strategies. * If the annotation already exists, overwrite it with this one. */ void addAnnotation(KisAnnotationSP annotation); /** get the annotation with the given type, can return 0 */ KisAnnotationSP annotation(const QString& type); /** delete the annotation, if the image contains it */ void removeAnnotation(const QString& type); /** * Start of an iteration over the annotations of this image (including the ICC Profile) */ vKisAnnotationSP_it beginAnnotations(); /** end of an iteration over the annotations of this image */ vKisAnnotationSP_it endAnnotations(); /** * Called before the image is delted and sends the sigAboutToBeDeleted signal */ void notifyAboutToBeDeleted(); KisImageSignalRouter* signalRouter(); /** * Returns whether we can reselect current global selection * * \see reselectGlobalSelection() */ bool canReselectGlobalSelection(); /** * Returns the layer compositions for the image */ QList compositions(); /** * Adds a new layer composition, will be saved with the image */ void addComposition(KisLayerCompositionSP composition); /** * Remove the layer compostion */ void removeComposition(KisLayerCompositionSP composition); /** * Permit or deny the wrap-around mode for all the paint devices * of the image. Note that permitting the wraparound mode will not * necessarily activate it right now. To be activated the wrap * around mode should be 1) permitted; 2) supported by the * currently running stroke. */ void setWrapAroundModePermitted(bool value); /** * \return whether the wrap-around mode is permitted for this * image. If the wrap around mode is permitted and the * currently running stroke supports it, the mode will be * activated for all paint devices of the image. * * \see setWrapAroundMode */ bool wrapAroundModePermitted() const; /** * \return whether the wraparound mode is activated for all the * devices of the image. The mode is activated when both * factors are true: the user permitted it and the stroke * supports it */ bool wrapAroundModeActive() const; /** * \return current level of detail which is used when processing the image. * Current working zoom = 2 ^ (- currentLevelOfDetail()). Default value is * null, which means we work on the original image. */ int currentLevelOfDetail() const; /** * Notify KisImage which level of detail should be used in the * lod-mode. Setting the mode does not guarantee the LOD to be * used. It will be activated only when the stokes supports it. */ void setDesiredLevelOfDetail(int lod); /** * Relative position of the mirror axis center * 0,0 - topleft corner of the image * 1,1 - bottomright corner of the image */ QPointF mirrorAxesCenter() const; /** * Sets the relative position of the axes center * \see mirrorAxesCenter() for details */ void setMirrorAxesCenter(const QPointF &value) const; public Q_SLOTS: /** * Explicitly start regeneration of LoD planes of all the devices * in the image. This call should be performed when the user is idle, * just to make the quality of image updates better. */ void explicitRegenerateLevelOfDetail(); public: /** * Blocks usage of level of detail functionality. After this method * has been called, no new strokes will use LoD. */ void setLevelOfDetailBlocked(bool value); /** * \see setLevelOfDetailBlocked() */ bool levelOfDetailBlocked() const; /** * Notifies that the node collapsed state has changed */ void notifyNodeCollpasedChanged(); KisImageAnimationInterface *animationInterface() const; /** * @brief setProofingConfiguration, this sets the image's proofing configuration, and signals * the proofingConfiguration has changed. * @param proofingConfig - the kis proofing config that will be used instead. */ void setProofingConfiguration(KisProofingConfigurationSP proofingConfig); /** * @brief proofingConfiguration * @return the proofing configuration of the image. */ KisProofingConfigurationSP proofingConfiguration() const; public Q_SLOTS: bool startIsolatedMode(KisNodeSP node); void stopIsolatedMode(); public: KisNodeSP isolatedModeRoot() const; Q_SIGNALS: /** * Emitted whenever an action has caused the image to be * recomposited. * * @param rc The rect that has been recomposited. */ void sigImageUpdated(const QRect &); /** Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk. */ void sigImageModified(); /** * The signal is emitted when the size of the image is changed. * \p oldStillPoint and \p newStillPoint give the receiver the * hint about how the new and old rect of the image correspond to * each other. They specify the point of the image around which * the conversion was done. This point will stay still on the * user's screen. That is the \p newStillPoint of the new image * will be painted at the same screen position, where \p * oldStillPoint of the old image was painted. * * \param oldStillPoint is a still point represented in *old* * image coordinates * * \param newStillPoint is a still point represented in *new* * image coordinates */ void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint); void sigProfileChanged(const KoColorProfile * profile); void sigColorSpaceChanged(const KoColorSpace* cs); void sigResolutionChanged(double xRes, double yRes); void sigRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes); /** * Inform the model that a node was changed */ void sigNodeChanged(KisNodeSP node); /** * Inform that the image is going to be deleted */ void sigAboutToBeDeleted(); /** * The signal is emitted right after a node has been connected * to the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. If you need * information about the parent/siblings of the node connect * with Qt::DirectConnection, get needed information and then * emit another Qt::AutoConnection signal to pass this information * to your thread. See details of the implementation * in KisDummiesfacadeBase. */ void sigNodeAddedAsync(KisNodeSP node); /** * This signal is emitted right before a node is going to removed * from the graph of the nodes. * * WARNING: you must not request any graph-related information * about the node being run in a not-scheduler thread. * * \see comment in sigNodeAddedAsync() */ void sigRemoveNodeAsync(KisNodeSP node); /** * Emitted when the root node of the image has changed. * It happens, e.g. when we flatten the image. When * this happens the receiver should reload information * about the image */ void sigLayersChangedAsync(); /** * Emitted when the UI has requested the undo of the last stroke's * operation. The point is, we cannot deal with the internals of * the stroke without its creator knowing about it (which most * probably cause a crash), so we just forward this request from * the UI to the creator of the stroke. * * If your tool supports undoing part of its work, just listen to * this signal and undo when it comes */ void sigUndoDuringStrokeRequested(); /** * Emitted when the UI has requested the cancellation of * the stroke. The point is, we cannot cancel the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports cancelling of its work in the middle * of operation, just listen to this signal and cancel * the stroke when it comes */ void sigStrokeCancellationRequested(); /** * Emitted when the image decides that the stroke should better * be ended. The point is, we cannot just end the stroke * without its creator knowing about it (which most probably * cause a crash), so we just forward this request from the UI * to the creator of the stroke. * * If your tool supports long strokes that may involve multiple * mouse actions in one stroke, just listen to this signal and * end the stroke when it comes. */ void sigStrokeEndRequested(); /** * Same as sigStrokeEndRequested() but is not emitted when the active node * is changed. */ void sigStrokeEndRequestedActiveNodeFiltered(); /** * Emitted when the isolated mode status has changed. * * Can be used by the receivers to catch a fact of forcefully * stopping the isolated mode by the image when some complex * action was requested */ void sigIsolatedModeChanged(); /** * Emitted when one or more nodes changed the collapsed state * */ void sigNodeCollapsedChanged(); /** * Emitted when the proofing configuration of the image is being changed. * */ void sigProofingConfigChanged(); /** * Internal signal for asynchronously requesting isolated mode to stop. Don't use it * outside KisImage, use sigIsolatedModeChanged() instead. */ void sigInternalStopIsolatedModeRequested(); public Q_SLOTS: KisCompositeProgressProxy* compositeProgressProxy(); bool isIdle(bool allowLocked = false); /** * @brief Wait until all the queued background jobs are completed and lock the image. * * KisImage object has a local scheduler that executes long-running image * rendering/modifying jobs (we call them "strokes") in a background. Basically, * one should either access the image from the scope of such jobs (strokes) or * just lock the image before using. * * Calling barrierLock() will wait until all the queued operations are finished * and lock the image, so you can start accessing it in a safe way. * * @p readOnly tells the image if the caller is going to modify the image during * holding the lock. Locking with non-readOnly access will reset all * the internal caches of the image (lod-planes) when the lock status * will be lifted. */ void barrierLock(bool readOnly = false); /** * @brief Tries to lock the image without waiting for the jobs to finish * * Same as barrierLock(), but doesn't block execution of the calling thread * until all the background jobs are finished. Instead, in case of presence of * unfinished jobs in the queue, it just returns false * * @return whether the lock has been acquired * @see barrierLock */ bool tryBarrierLock(bool readOnly = false); /** * Wait for all the internal image jobs to complete and return without locking * the image. This function is handly for tests or other synchronous actions, * when one needs to wait for the result of his actions. */ void waitForDone(); KisStrokeId startStroke(KisStrokeStrategy *strokeStrategy) override; void addJob(KisStrokeId id, KisStrokeJobData *data) override; void endStroke(KisStrokeId id) override; bool cancelStroke(KisStrokeId id) override; /** * @brief blockUpdates block updating the image projection */ void blockUpdates() override; /** * @brief unblockUpdates unblock updating the image project. This * only restarts the scheduler and does not schedule a full refresh. */ void unblockUpdates() override; /** * Disables notification of the UI about the changes in the image. * This feature is used by KisProcessingApplicator. It is needed * when we change the size of the image. In this case, the whole * image will be reloaded into UI by sigSizeChanged(), so there is * no need to inform the UI about individual dirty rects. */ void disableUIUpdates() override; /** * \see disableUIUpdates */ void enableUIUpdates() override; /** * Disables the processing of all the setDirty() requests that * come to the image. The incoming requests are effectively * *dropped*. * * This feature is used by KisProcessingApplicator. For many cases * it provides its own updates interface, which recalculates the * whole subtree of nodes. But while we change any particular * node, it can ask for an update itself. This method is a way of * blocking such intermediate (and excessive) requests. * * NOTE: this is a convenience function for setProjectionUpdatesFilter() * that installs a predefined filter that eats everything. Please * note that these calls are *not* recursive */ void disableDirtyRequests() override; /** * \see disableDirtyRequests() */ void enableDirtyRequests() override; /** * Installs a filter object that will filter all the incoming projection update * requests. If the filter return true, the incoming update is dropped. * * NOTE: you cannot set filters recursively! */ void setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) override; /** * \see setProjectionUpdatesFilter() */ KisProjectionUpdatesFilterSP projectionUpdatesFilter() const override; void refreshGraphAsync(KisNodeSP root = KisNodeSP()) override; void refreshGraphAsync(KisNodeSP root, const QRect &rc) override; void refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) override; /** * Triggers synchronous recomposition of the projection */ void refreshGraph(KisNodeSP root = KisNodeSP()); void refreshGraph(KisNodeSP root, const QRect& rc, const QRect &cropRect); void initialRefreshGraph(); /** * Initiate a stack regeneration skipping the recalculation of the * filthy node's projection. * * Works exactly as pseudoFilthy->setDirty() with the only * exception that pseudoFilthy::updateProjection() will not be * called. That is used by KisRecalculateTransformMaskJob to avoid * cyclic dependencies. */ void requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect); /** * Adds a spontaneous job to the updates queue. * * A spontaneous job may do some trivial tasks in the background, * like updating the outline of selection or purging unused tiles * from the existing paint devices. */ void addSpontaneousJob(KisSpontaneousJob *spontaneousJob); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks the current stroke should undo its last * action, for example, when the user presses Ctrl+Z while some * stroke is active. * * If the creator of the stroke supports undoing of intermediate * actions, it will be notified about this request and can undo * its last action. */ void requestUndoDuringStroke(); /** * This method is called by the UI (*not* by the creator of the * stroke) when it thinks current stroke should be cancelled. If * there is a running stroke that has already been detached from * its creator (ended or cancelled), it will be forcefully * cancelled and reverted. If there is an open stroke present, and * if its creator supports cancelling, it will be notified about * the request and the stroke will be cancelled */ void requestStrokeCancellation(); /** * This method requests the last stroke executed on the image to become undone. * If the stroke is not ended, or if all the Lod0 strokes are completed, the method * returns UNDO_FAIL. If the last Lod0 is going to be finished soon, then UNDO_WAIT * is returned and the caller should just wait for its completion and call global undo * instead. UNDO_OK means one unfinished stroke has been undone. */ UndoResult tryUndoUnfinishedLod0Stroke(); /** * This method is called when image or some other part of Krita * (*not* the creator of the stroke) decides that the stroke * should be ended. If the creator of the stroke supports it, it * will be notified and the stroke will be cancelled */ void requestStrokeEnd(); /** * Same as requestStrokeEnd() but is called by view manager when * the current node is changed. Use to dintinguish * sigStrokeEndRequested() and * sigStrokeEndRequestedActiveNodeFiltered() which are used by * KisNodeJugglerCompressed */ void requestStrokeEndActiveNode(); private: KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy); KisImage& operator=(const KisImage& rhs); void emitSizeChanged(); void resizeImageImpl(const QRect& newRect, bool cropLayers); void rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double radians); void shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double angleX, double angleY, const QPointF &origin); void safeRemoveTwoNodes(KisNodeSP node1, KisNodeSP node2); void refreshHiddenArea(KisNodeSP rootNode, const QRect &preparedArea); void requestProjectionUpdateImpl(KisNode *node, const QVector &rects, const QRect &cropRect); friend class KisImageResizeCommand; void setSize(const QSize& size); friend class KisImageSetProjectionColorSpaceCommand; void setProjectionColorSpace(const KoColorSpace * colorSpace); friend class KisDeselectGlobalSelectionCommand; friend class KisReselectGlobalSelectionCommand; friend class KisSetGlobalSelectionCommand; friend class KisImageTest; friend class Document; // For libkis /** * Replaces the current global selection with globalSelection. If * \p globalSelection is empty, removes the selection object, so that * \ref globalSelection() will return 0 after that. */ void setGlobalSelection(KisSelectionSP globalSelection); /** * Deselects current global selection. * \ref globalSelection() will return 0 after that. */ void deselectGlobalSelection(); /** * Reselects current deselected selection * * \see deselectGlobalSelection() */ void reselectGlobalSelection(); private: class KisImagePrivate; KisImagePrivate * m_d; }; #endif // KIS_IMAGE_H_ diff --git a/libs/image/kis_image_animation_interface.cpp b/libs/image/kis_image_animation_interface.cpp index d2ab2857b2..cd97f3dbdf 100644 --- a/libs/image/kis_image_animation_interface.cpp +++ b/libs/image/kis_image_animation_interface.cpp @@ -1,431 +1,426 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_image_animation_interface.h" #include #include "kis_global.h" #include "kis_image.h" #include "kis_regenerate_frame_stroke_strategy.h" #include "kis_switch_time_stroke_strategy.h" #include "kis_keyframe_channel.h" #include "kis_time_range.h" #include "kis_post_execution_undo_adapter.h" #include "commands_new/kis_switch_current_time_command.h" #include "kis_layer_utils.h" struct KisImageAnimationInterface::Private { Private() : image(0), externalFrameActive(false), frameInvalidationBlocked(false), cachedLastFrameValue(-1), audioChannelMuted(false), audioChannelVolume(0.5), m_currentTime(0), m_currentUITime(0) { } Private(const Private &rhs, KisImage *newImage) : image(newImage), externalFrameActive(false), frameInvalidationBlocked(false), fullClipRange(rhs.fullClipRange), playbackRange(rhs.playbackRange), framerate(rhs.framerate), cachedLastFrameValue(-1), audioChannelFileName(rhs.audioChannelFileName), audioChannelMuted(rhs.audioChannelMuted), audioChannelVolume(rhs.audioChannelVolume), m_currentTime(rhs.m_currentTime), m_currentUITime(rhs.m_currentUITime) { } KisImage *image; bool externalFrameActive; bool frameInvalidationBlocked; KisTimeRange fullClipRange; KisTimeRange playbackRange; int framerate; int cachedLastFrameValue; QString audioChannelFileName; bool audioChannelMuted; qreal audioChannelVolume; KisSwitchTimeStrokeStrategy::SharedTokenWSP switchToken; inline int currentTime() const { return m_currentTime; } inline int currentUITime() const { return m_currentUITime; } inline void setCurrentTime(int value) { m_currentTime = value; } inline void setCurrentUITime(int value) { m_currentUITime = value; } private: int m_currentTime; int m_currentUITime; }; KisImageAnimationInterface::KisImageAnimationInterface(KisImage *image) : QObject(image), m_d(new Private) { m_d->image = image; m_d->framerate = 24; m_d->fullClipRange = KisTimeRange::fromTime(0, 100); connect(this, SIGNAL(sigInternalRequestTimeSwitch(int, bool)), SLOT(switchCurrentTimeAsync(int, bool))); } KisImageAnimationInterface::KisImageAnimationInterface(const KisImageAnimationInterface &rhs, KisImage *newImage) : m_d(new Private(*rhs.m_d, newImage)) { connect(this, SIGNAL(sigInternalRequestTimeSwitch(int, bool)), SLOT(switchCurrentTimeAsync(int, bool))); } KisImageAnimationInterface::~KisImageAnimationInterface() { } bool KisImageAnimationInterface::hasAnimation() const { bool hasAnimation = false; KisLayerUtils::recursiveApplyNodes( m_d->image->root(), [&hasAnimation](KisNodeSP node) { hasAnimation |= node->isAnimated(); }); return hasAnimation; } int KisImageAnimationInterface::currentTime() const { return m_d->currentTime(); } int KisImageAnimationInterface::currentUITime() const { return m_d->currentUITime(); } const KisTimeRange& KisImageAnimationInterface::fullClipRange() const { return m_d->fullClipRange; } void KisImageAnimationInterface::setFullClipRange(const KisTimeRange range) { KIS_SAFE_ASSERT_RECOVER_RETURN(!range.isInfinite()); m_d->fullClipRange = range; emit sigFullClipRangeChanged(); } void KisImageAnimationInterface::setFullClipRangeStartTime(int column) { KisTimeRange newRange(column, m_d->fullClipRange.end(), false); setFullClipRange(newRange); } void KisImageAnimationInterface::setFullClipRangeEndTime(int column) { KisTimeRange newRange(m_d->fullClipRange.start(), column, false); setFullClipRange(newRange); } const KisTimeRange& KisImageAnimationInterface::playbackRange() const { return m_d->playbackRange.isValid() ? m_d->playbackRange : m_d->fullClipRange; } void KisImageAnimationInterface::setPlaybackRange(const KisTimeRange range) { KIS_SAFE_ASSERT_RECOVER_RETURN(!range.isInfinite()); m_d->playbackRange = range; emit sigPlaybackRangeChanged(); } int KisImageAnimationInterface::framerate() const { return m_d->framerate; } QString KisImageAnimationInterface::audioChannelFileName() const { return m_d->audioChannelFileName; } void KisImageAnimationInterface::setAudioChannelFileName(const QString &fileName) { QFileInfo info(fileName); KIS_SAFE_ASSERT_RECOVER_NOOP(fileName.isEmpty() || info.isAbsolute()); m_d->audioChannelFileName = fileName.isEmpty() ? fileName : info.absoluteFilePath(); emit sigAudioChannelChanged(); } bool KisImageAnimationInterface::isAudioMuted() const { return m_d->audioChannelMuted; } void KisImageAnimationInterface::setAudioMuted(bool value) { m_d->audioChannelMuted = value; emit sigAudioChannelChanged(); } qreal KisImageAnimationInterface::audioVolume() const { return m_d->audioChannelVolume; } void KisImageAnimationInterface::setAudioVolume(qreal value) { m_d->audioChannelVolume = value; emit sigAudioVolumeChanged(); } void KisImageAnimationInterface::setFramerate(int fps) { m_d->framerate = fps; emit sigFramerateChanged(); } KisImageWSP KisImageAnimationInterface::image() const { return m_d->image; } bool KisImageAnimationInterface::externalFrameActive() const { return m_d->externalFrameActive; } void KisImageAnimationInterface::requestTimeSwitchWithUndo(int time) { if (currentUITime() == time) return; requestTimeSwitchNonGUI(time, true); } void KisImageAnimationInterface::setDefaultProjectionColor(const KoColor &color) { int savedTime = 0; saveAndResetCurrentTime(currentTime(), &savedTime); m_d->image->setDefaultProjectionColor(color); restoreCurrentTime(&savedTime); } void KisImageAnimationInterface::requestTimeSwitchNonGUI(int time, bool useUndo) { emit sigInternalRequestTimeSwitch(time, useUndo); } void KisImageAnimationInterface::explicitlySetCurrentTime(int frameId) { m_d->setCurrentTime(frameId); } void KisImageAnimationInterface::switchCurrentTimeAsync(int frameId, bool useUndo) { if (currentUITime() == frameId) return; KisTimeRange range = KisTimeRange::infinite(0); KisTimeRange::calculateTimeRangeRecursive(m_d->image->root(), currentUITime(), range, true); const bool needsRegeneration = !range.contains(frameId); KisSwitchTimeStrokeStrategy::SharedTokenSP token = m_d->switchToken.toStrongRef(); if (!token || !token->tryResetDestinationTime(frameId, needsRegeneration)) { { KisPostExecutionUndoAdapter *undoAdapter = useUndo ? m_d->image->postExecutionUndoAdapter() : 0; KisSwitchTimeStrokeStrategy *strategy = new KisSwitchTimeStrokeStrategy(frameId, needsRegeneration, this, undoAdapter); m_d->switchToken = strategy->token(); KisStrokeId stroke = m_d->image->startStroke(strategy); m_d->image->endStroke(stroke); } if (needsRegeneration) { KisStrokeStrategy *strategy = new KisRegenerateFrameStrokeStrategy(this); KisStrokeId strokeId = m_d->image->startStroke(strategy); m_d->image->endStroke(strokeId); } } m_d->setCurrentUITime(frameId); emit sigUiTimeChanged(frameId); } void KisImageAnimationInterface::requestFrameRegeneration(int frameId, const QRegion &dirtyRegion) { KisStrokeStrategy *strategy = new KisRegenerateFrameStrokeStrategy(frameId, dirtyRegion, this); QList jobs = KisRegenerateFrameStrokeStrategy::createJobsData(m_d->image); KisStrokeId stroke = m_d->image->startStroke(strategy); Q_FOREACH (KisStrokeJobData* job, jobs) { m_d->image->addJob(stroke, job); } m_d->image->endStroke(stroke); } void KisImageAnimationInterface::saveAndResetCurrentTime(int frameId, int *savedValue) { m_d->externalFrameActive = true; *savedValue = m_d->currentTime(); m_d->setCurrentTime(frameId); } void KisImageAnimationInterface::restoreCurrentTime(int *savedValue) { m_d->setCurrentTime(*savedValue); m_d->externalFrameActive = false; } void KisImageAnimationInterface::notifyFrameReady() { emit sigFrameReady(m_d->currentTime()); } void KisImageAnimationInterface::notifyFrameCancelled() { emit sigFrameCancelled(); } KisUpdatesFacade* KisImageAnimationInterface::updatesFacade() const { return m_d->image; } void KisImageAnimationInterface::notifyNodeChanged(const KisNode *node, const QRect &rect, bool recursive) { notifyNodeChanged(node, QVector({rect}), recursive); } void KisImageAnimationInterface::notifyNodeChanged(const KisNode *node, const QVector &rects, bool recursive) { if (externalFrameActive() || m_d->frameInvalidationBlocked) return; if (node->inherits("KisSelectionMask")) return; - KisKeyframeChannel *channel = - node->getKeyframeChannel(KisKeyframeChannel::Content.id()); + const int currentTime = m_d->currentTime(); KisTimeRange invalidateRange; if (recursive) { - KisTimeRange::calculateTimeRangeRecursive(node, currentTime(), invalidateRange, false); - } else if (channel) { - const int currentTime = m_d->currentTime(); - invalidateRange = channel->affectedFrames(currentTime); + KisTimeRange::calculateTimeRangeRecursive(node, currentTime, invalidateRange, false); } else { - invalidateRange = KisTimeRange::infinite(0); + invalidateRange = KisTimeRange::calculateNodeAffectedFrames(node, currentTime); } - // we compress the updated rect (atm, no one uses it anyway) QRect unitedRect; Q_FOREACH (const QRect &rc, rects) { unitedRect |= rc; } invalidateFrames(invalidateRange, unitedRect); } void KisImageAnimationInterface::invalidateFrames(const KisTimeRange &range, const QRect &rect) { m_d->cachedLastFrameValue = -1; emit sigFramesChanged(range, rect); } void KisImageAnimationInterface::blockFrameInvalidation(bool value) { m_d->frameInvalidationBlocked = value; } int findLastKeyframeTimeRecursive(KisNodeSP node) { int time = 0; KisKeyframeChannel *channel; Q_FOREACH (channel, node->keyframeChannels()) { KisKeyframeSP keyframe = channel->lastKeyframe(); if (keyframe) { time = std::max(time, keyframe->time()); } } KisNodeSP child = node->firstChild(); while (child) { time = std::max(time, findLastKeyframeTimeRecursive(child)); child = child->nextSibling(); } return time; } int KisImageAnimationInterface::totalLength() { if (m_d->cachedLastFrameValue < 0) { m_d->cachedLastFrameValue = findLastKeyframeTimeRecursive(m_d->image->root()); } int lastKey = m_d->cachedLastFrameValue; lastKey = std::max(lastKey, m_d->fullClipRange.end()); lastKey = std::max(lastKey, m_d->currentUITime()); return lastKey + 1; } diff --git a/libs/image/recorder/kis_node_query_path.cc b/libs/image/kis_node_query_path.cc similarity index 100% rename from libs/image/recorder/kis_node_query_path.cc rename to libs/image/kis_node_query_path.cc diff --git a/libs/image/recorder/kis_node_query_path.h b/libs/image/kis_node_query_path.h similarity index 100% rename from libs/image/recorder/kis_node_query_path.h rename to libs/image/kis_node_query_path.h diff --git a/libs/image/kis_spontaneous_job.h b/libs/image/kis_spontaneous_job.h index 6a4194062d..033eac24e6 100644 --- a/libs/image/kis_spontaneous_job.h +++ b/libs/image/kis_spontaneous_job.h @@ -1,48 +1,48 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_SPONTANEOUS_JOB_H #define __KIS_SPONTANEOUS_JOB_H #include "kis_runnable.h" /** * This class represents a simple update just that should be * executed by the updates system from time to time, without - * any recording or undo support. Just some useful update that + * any undo support. Just some useful update that * can be run concurrently with other types updates. */ class KRITAIMAGE_EXPORT KisSpontaneousJob : public KisRunnable { public: virtual bool overrides(const KisSpontaneousJob *otherJob) = 0; virtual int levelOfDetail() const = 0; bool isExclusive() const { return m_isExclusive; } protected: void setExclusive(bool value) { m_isExclusive = value; } private: bool m_isExclusive = false; }; #endif /* __KIS_SPONTANEOUS_JOB_H */ diff --git a/libs/image/kis_time_range.cpp b/libs/image/kis_time_range.cpp index 85c918e961..363e970bc4 100644 --- a/libs/image/kis_time_range.cpp +++ b/libs/image/kis_time_range.cpp @@ -1,100 +1,144 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_time_range.h" #include #include "kis_keyframe_channel.h" #include "kis_node.h" struct KisTimeRangeStaticRegistrar { KisTimeRangeStaticRegistrar() { qRegisterMetaType("KisTimeRange"); } }; static KisTimeRangeStaticRegistrar __registrar; QDebug operator<<(QDebug dbg, const KisTimeRange &r) { dbg.nospace() << "KisTimeRange(" << r.start() << ", " << r.end() << ")"; return dbg.space(); } void KisTimeRange::calculateTimeRangeRecursive(const KisNode *node, int time, KisTimeRange &range, bool exclusive) { if (!node->visible()) return; - Q_FOREACH (const KisKeyframeChannel *channel, node->keyframeChannels()) { - if (exclusive) { - // Intersection - range &= channel->identicalFrames(time); - } else { - // Union - range |= channel->affectedFrames(time); - } + + if (exclusive) { + // Intersection + range &= calculateNodeIdenticalFrames(node, time); + } else { + // Union + range |= calculateNodeAffectedFrames(node, time); } KisNodeSP child = node->firstChild(); while (child) { calculateTimeRangeRecursive(child, time, range, exclusive); child = child->nextSibling(); } } +KisTimeRange KisTimeRange::calculateNodeIdenticalFrames(const KisNode *node, int time) +{ + KisTimeRange range = KisTimeRange::infinite(0); + + const QMap channels = + node->keyframeChannels(); + + if (channels.isEmpty() || + !channels.contains(KisKeyframeChannel::Content.id())) { + + return range; + } + + Q_FOREACH (const KisKeyframeChannel *channel, channels) { + // Intersection + range &= channel->identicalFrames(time); + } + + return range; +} + +KisTimeRange KisTimeRange::calculateNodeAffectedFrames(const KisNode *node, int time) +{ + KisTimeRange range; + + if (!node->visible()) return range; + + const QMap channels = + node->keyframeChannels(); + + if (channels.isEmpty() || + !channels.contains(KisKeyframeChannel::Content.id())) { + + range = KisTimeRange::infinite(0); + return range; + } + + Q_FOREACH (const KisKeyframeChannel *channel, channels) { + // Union + range |= channel->affectedFrames(time); + } + + return range; +} + namespace KisDomUtils { void saveValue(QDomElement *parent, const QString &tag, const KisTimeRange &range) { QDomDocument doc = parent->ownerDocument(); QDomElement e = doc.createElement(tag); parent->appendChild(e); e.setAttribute("type", "timerange"); if (range.isValid()) { e.setAttribute("from", toString(range.start())); if (!range.isInfinite()) { e.setAttribute("to", toString(range.end())); } } } bool loadValue(const QDomElement &parent, const QString &tag, KisTimeRange *range) { QDomElement e; if (!findOnlyElement(parent, tag, &e)) return false; if (!Private::checkType(e, "timerange")) return false; int start = toInt(e.attribute("from", "-1")); int end = toInt(e.attribute("to", "-1")); if (start == -1) { range = new KisTimeRange(); } else if (end == -1) { *range = KisTimeRange::infinite(start); } else { *range = KisTimeRange::fromTime(start, end); } return true; } } diff --git a/libs/image/kis_time_range.h b/libs/image/kis_time_range.h index 0b1489d256..a6af4eab50 100644 --- a/libs/image/kis_time_range.h +++ b/libs/image/kis_time_range.h @@ -1,150 +1,152 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TIME_RANGE_H #define __KIS_TIME_RANGE_H #include "kritaimage_export.h" #include #include #include #include #include "kis_types.h" #include class KRITAIMAGE_EXPORT KisTimeRange : public boost::equality_comparable { public: inline KisTimeRange() : m_start(0), m_end(-1) { } inline KisTimeRange(int start, int duration) : m_start(start), m_end(start + duration - 1) { } inline KisTimeRange(int start, int end, bool) : m_start(start), m_end(end) { } bool operator==(const KisTimeRange &rhs) const { return rhs.m_start == m_start && rhs.m_end == m_end; } KisTimeRange& operator|=(const KisTimeRange &rhs) { if (!isValid()) { m_start = rhs.start(); } else if (rhs.isValid()) { m_start = std::min(m_start, rhs.start()); } if (rhs.isInfinite() || isInfinite()) { m_end = std::numeric_limits::min(); } else if (!isValid()) { m_end = rhs.m_end; } else { m_end = std::max(m_end, rhs.m_end); } return *this; } KisTimeRange& operator&=(const KisTimeRange &rhs) { if (!isValid()) { return *this; } else if (!rhs.isValid()) { m_start = rhs.start(); m_end = rhs.m_end; return *this; } else { m_start = std::max(m_start, rhs.start()); } if (isInfinite()) { m_end = rhs.m_end; } else if (!rhs.isInfinite()) { m_end = std::min(m_end, rhs.m_end); } return *this; } inline int start() const { return m_start; } inline int end() const { return m_end; } inline int duration() const { return m_end >= m_start ? m_end - m_start + 1 : 0; } inline bool isInfinite() const { return m_end == std::numeric_limits::min(); } inline bool isValid() const { return (m_end >= m_start) || (m_end == std::numeric_limits::min() && m_start >= 0); } inline bool contains(int time) const { if (m_end == std::numeric_limits::min()) { return m_start <= time; } return m_start <= time && time <= m_end; } static inline KisTimeRange fromTime(int start, int end) { return KisTimeRange(start, end, true); } static inline KisTimeRange infinite(int start) { return KisTimeRange(start, std::numeric_limits::min(), true); } static void calculateTimeRangeRecursive(const KisNode *node, int time, KisTimeRange &range, bool exclusive); + static KisTimeRange calculateNodeIdenticalFrames(const KisNode *node, int time); + static KisTimeRange calculateNodeAffectedFrames(const KisNode *node, int time); private: int m_start; int m_end; }; namespace KisDomUtils { void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const KisTimeRange &range); bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, KisTimeRange *range); } Q_DECLARE_METATYPE(KisTimeRange); KRITAIMAGE_EXPORT QDebug operator<<(QDebug dbg, const KisTimeRange &r); #endif /* __KIS_TIME_RANGE_H */ diff --git a/libs/image/kis_vec.h b/libs/image/kis_vec.h index f7c34750a8..624e031ff8 100644 --- a/libs/image/kis_vec.h +++ b/libs/image/kis_vec.h @@ -1,61 +1,46 @@ /* * kis_vec.h - part of KImageShop * * Copyright (c) 1999 Matthias Elter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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_vec_h__ #define __kis_vec_h__ #include #include #include typedef Eigen::Matrix KisVector2D; -typedef Eigen::Matrix KisVector3D; inline KisVector2D toKisVector2D(const QPointF& p) { return KisVector2D(p.x(), p.y()); } inline KisVector2D toKisVector2D(const QPoint& p) { return KisVector2D(p.x(), p.y()); } template inline QPointF toQPointF(const ExpressionType& expr) { return QPointF(expr.x(), expr.y()); } -template -inline QVector2D toQVector2D(const ExpressionType& expr){ - return QVector2D(expr.x(), expr.y()); -} - -inline KisVector2D nullKisVector2D() -{ - KisVector2D v; - v(0) = 0.0; - v(1) = 0.0; - return v; -} - - #endif diff --git a/libs/image/recorder/kis_action_recorder.cc b/libs/image/recorder/kis_action_recorder.cc deleted file mode 100644 index a0cf36bca3..0000000000 --- a/libs/image/recorder/kis_action_recorder.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "recorder/kis_action_recorder.h" - -#include "recorder/kis_recorded_action.h" - -KisActionRecorder::KisActionRecorder(QObject* parent) - : QObject(parent) -{ - -} - -KisActionRecorder::~KisActionRecorder() -{ -} - -void KisActionRecorder::addAction(const KisRecordedAction& action, const KisRecordedAction* before) -{ - Q_UNUSED(before); - emit(addedAction(action)); -} - diff --git a/libs/image/recorder/kis_action_recorder.h b/libs/image/recorder/kis_action_recorder.h deleted file mode 100644 index c4fbba629f..0000000000 --- a/libs/image/recorder/kis_action_recorder.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_ACTION_RECORDER_H_ -#define _KIS_ACTION_RECORDER_H_ - -#include -#include "kritaimage_export.h" - -class KisRecordedAction; - -/** - * This class allows other \ref KisMacro to connect to it - * to get the action that are currently created. - */ -class KRITAIMAGE_EXPORT KisActionRecorder : public QObject -{ - Q_OBJECT -public: - KisActionRecorder(QObject* parent = 0); - ~KisActionRecorder() override; - -public Q_SLOTS: - - void addAction(const KisRecordedAction& action, const KisRecordedAction* before = 0); - -Q_SIGNALS: - /** - * This signal is emitted each time an action is added to this recorder. - */ - void addedAction(const KisRecordedAction& action); -}; - -#endif diff --git a/libs/image/recorder/kis_macro.cc b/libs/image/recorder/kis_macro.cc deleted file mode 100644 index 84e0ee3554..0000000000 --- a/libs/image/recorder/kis_macro.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_macro.h" -#include - -#include -#include - -#include "kis_image.h" -#include "recorder/kis_recorded_action.h" -#include "recorder/kis_recorded_action_factory_registry.h" -#include "kis_undo_adapter.h" -#include "kis_play_info.h" -#include "kis_node_query_path.h" -#include - -struct Q_DECL_HIDDEN KisMacro::Private { - QList actions; -}; - -KisMacro::KisMacro(QObject* parent) : QObject(parent), d(new Private) -{ -} - -KisMacro::KisMacro(const QList& actions) : d(new Private) -{ - appendActions(actions); -} - -KisMacro::~KisMacro() -{ - qDeleteAll(d->actions); - delete d; -} - - -void KisMacro::appendActions(const QList& actions) -{ - Q_FOREACH (KisRecordedAction* action, actions) { - addAction(*action); - } -} - -void KisMacro::removeActions(const QList& actions) -{ - Q_FOREACH (KisRecordedAction* action, actions) { - d->actions.removeAll(action); - } - qDeleteAll(actions); -} - -void KisMacro::addAction(const KisRecordedAction& action, const KisRecordedAction* before) -{ - if (before == 0) { - KisRecordedAction* a = action.clone(); - Q_ASSERT(a); - d->actions.append(a); - } else { - d->actions.insert(d->actions.indexOf(const_cast(before)), action.clone()); - } -} - -void KisMacro::moveAction(const KisRecordedAction* action, const KisRecordedAction* before) -{ - KisRecordedAction* _action = d->actions.takeAt(d->actions.indexOf(const_cast(action))); - if (before == 0) { - Q_ASSERT(_action); - d->actions.append(_action); - } else { - d->actions.insert(d->actions.indexOf(const_cast(before)), _action); - } -} - -void KisMacro::fromXML(const QDomElement& docElem, const KisRecordedActionLoadContext* loadContext) -{ - d->actions.clear(); - QDomNode node = docElem.firstChild(); - while (!node.isNull()) { - QDomElement elt = node.toElement(); // try to convert the node to an element. - if (!elt.isNull() && elt.tagName() == "RecordedAction") { - QString id = elt.attribute("id", ""); - if (!id.isNull()) { - dbgImage << "Reconstruct : " << id << endl; // the node really is an element. - KisRecordedActionFactory* raf = KisRecordedActionFactoryRegistry::instance()->get(id); - if (raf) { - KisRecordedAction* a = raf->fromXML(elt, loadContext); - Q_ASSERT(a); - d->actions.append(a); // TODO should use addAction - } else { - dbgImage << "Unknown action : " << id << endl; - } - } else { - dbgImage << "Invalid recorded action: null id"; - } - } else { - dbgImage << "Unknown element " << elt.tagName() << (elt.tagName() == "RecordedAction"); - } - node = node.nextSibling(); - } -} - -void KisMacro::toXML(QDomDocument& doc, QDomElement& e, KisRecordedActionSaveContext* saveContext) const -{ - for (QList::iterator it = d->actions.begin(); - it != d->actions.end(); ++it) { - QDomElement eAct = doc.createElement("RecordedAction"); - (*it)->toXML(doc, eAct, saveContext); - e.appendChild(eAct); - } -} - -const QList& KisMacro::actions() const -{ - return d->actions; -} - diff --git a/libs/image/recorder/kis_macro.h b/libs/image/recorder/kis_macro.h deleted file mode 100644 index 3f904abd4c..0000000000 --- a/libs/image/recorder/kis_macro.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_MACRO_H_ -#define _KIS_MACRO_H_ - -#include -#include -#include - -#include "kis_serializable_configuration.h" -#include "kis_types.h" - -class KisRecordedAction; -class KisRecordedActionLoadContext; -class KisRecordedActionSaveContext; - -/** - * This is the base class for macro in Krita. It's basically a list of recorded action,KisRecordedAction - * that can be stored as XML, played, and edited. - */ -class KRITAIMAGE_EXPORT KisMacro : public QObject -{ - Q_OBJECT -public: - KisMacro(QObject* parent = 0); - KisMacro(const QList& _actions); - ~KisMacro() override; -public: - /** - * Append a list of actions, and make clone of them. - */ - void appendActions(const QList& actions); - /** - * Remove the list of actions. Actions are deleted. - */ - void removeActions(const QList& actions); - /** - * Move the action before an other one. - * @param before if null, the action is moved to the end - */ - void moveAction(const KisRecordedAction* action, const KisRecordedAction* before); -public: // serialization functions - - virtual void fromXML(const QDomElement&, const KisRecordedActionLoadContext* loadContext); - virtual void toXML(QDomDocument& doc, QDomElement& e, KisRecordedActionSaveContext* saveContext) const; - const QList& actions() const; -public Q_SLOTS: - /** - * add a single action, and make a clone of it. - * @param before if non null, the action will be added before that action, - * otherwise, if null, the action will be added at the end. - */ - virtual void addAction(const KisRecordedAction& action, const KisRecordedAction* before = 0); -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/image/recorder/kis_macro_player.cc b/libs/image/recorder/kis_macro_player.cc deleted file mode 100644 index 7490b93e8d..0000000000 --- a/libs/image/recorder/kis_macro_player.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2007,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_macro_player.h" - -#include - -#include -#include - -#include "kis_image.h" -#include "kis_debug.h" -#include "kis_macro.h" -#include "kis_node_query_path.h" -#include "kis_play_info.h" -#include "kis_recorded_action.h" -#include "kis_undo_adapter.h" -#include "kundo2magicstring.h" - - -struct Q_DECL_HIDDEN KisMacroPlayer::Private -{ - Private(const KisPlayInfo& _info) : info(_info), updater(0) {} - bool paused; - KisMacro* macro; - KisPlayInfo info; - KoUpdater* updater; -}; - -KisMacroPlayer::KisMacroPlayer(KisMacro* _macro, const KisPlayInfo& info, KoUpdater * updater, QObject* _parent ) : QThread(_parent), d(new Private(info)) -{ - d->macro = _macro; - d->updater = updater; -} - -KisMacroPlayer::~KisMacroPlayer() -{ - delete d; -} - -void KisMacroPlayer::pause() -{ - d->paused = true; -} - -void KisMacroPlayer::resume() -{ - d->paused = false; -} - -void KisMacroPlayer::run() -{ - d->paused = false; - QList actions = d->macro->actions(); - - if (actions.size() < 1) { - return; - } - - dbgImage << "Start playing macro with " << actions.size() << " actions"; - if (d->info.undoAdapter()) { - d->info.undoAdapter()->beginMacro(kundo2_i18n("Play macro")); - } - - KoProgressUpdater* progressUpdater = 0; - if(d->updater) { - progressUpdater = new KoProgressUpdater(d->updater); - progressUpdater->start(actions.size(), i18n("Playing back macro")); - } - - for (QList::iterator it = actions.begin(); it != actions.end(); ++it) { - if (*it) { - dbgImage << "Play action : " << (*it)->name(); - KoUpdater* updater = 0; - if(progressUpdater) { - updater = progressUpdater->startSubtask(); - } - (*it)->play(d->info, updater); - } - if(progressUpdater && progressUpdater->interrupted()) { - break; - } - } - - if (d->info.undoAdapter()) { - d->info.undoAdapter()->endMacro(); - if(progressUpdater && progressUpdater->interrupted()) { - d->info.undoAdapter()->undoLastCommand(); - } - } - -} - diff --git a/libs/image/recorder/kis_macro_player.h b/libs/image/recorder/kis_macro_player.h deleted file mode 100644 index c58cafc064..0000000000 --- a/libs/image/recorder/kis_macro_player.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_MACRO_PLAYER_H_ -#define _KIS_MACRO_PLAYER_H_ - -#include - -#include -#include - -class KisMacro; -class KisPlayInfo; -class KoUpdater; - -/** - * This class play a macro inside a thread. - */ -class KRITAIMAGE_EXPORT KisMacroPlayer : public QThread { - Q_OBJECT -public: - KisMacroPlayer(KisMacro* _macro, const KisPlayInfo& info, KoUpdater * updater = 0, QObject* _parent = 0); - ~KisMacroPlayer() override; -public Q_SLOTS: - void pause(); - void resume(); -protected: - void run() override; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/image/recorder/kis_play_info.cc b/libs/image/recorder/kis_play_info.cc deleted file mode 100644 index a0d40d8aad..0000000000 --- a/libs/image/recorder/kis_play_info.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2009,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_play_info.h" - -#include "kis_image.h" -#include "kis_node.h" -#include - -struct Q_DECL_HIDDEN KisPlayInfo::Private { - KisImageWSP image; - KisNodeSP currentNode; -}; - -KisPlayInfo::KisPlayInfo(KisImageWSP image, KisNodeSP currentNode) - : d(new Private) -{ - d->image = image; - d->currentNode = currentNode; -} - -KisPlayInfo::KisPlayInfo(const KisPlayInfo& _rhs) : d(new Private(*_rhs.d)) -{ -} - -KisPlayInfo& KisPlayInfo::operator=(const KisPlayInfo& _rhs) -{ - *d = *_rhs.d; - return *this; -} - -KisPlayInfo::~KisPlayInfo() -{ - delete d; -} - -KisUndoAdapter* KisPlayInfo::undoAdapter() const -{ - return d->image->undoAdapter(); -} - -KisImageWSP KisPlayInfo::image() const -{ - return d->image; -} - -KisNodeSP KisPlayInfo::currentNode() const -{ - return d->currentNode; -} diff --git a/libs/image/recorder/kis_play_info.h b/libs/image/recorder/kis_play_info.h deleted file mode 100644 index 9f54df938e..0000000000 --- a/libs/image/recorder/kis_play_info.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_PLAY_INFO_H_ -#define _KIS_PLAY_INFO_H_ - -#include -#include - -class KisUndoAdapter; - -class KRITAIMAGE_EXPORT KisPlayInfo -{ -public: - KisPlayInfo(KisImageWSP image, KisNodeSP currentNodes); - KisPlayInfo(const KisPlayInfo& _rhs); - KisPlayInfo& operator=(const KisPlayInfo& _rhs); - ~KisPlayInfo(); - KisUndoAdapter* undoAdapter() const; - KisImageWSP image() const; - KisNodeSP currentNode() const; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_action.cc b/libs/image/recorder/kis_recorded_action.cc deleted file mode 100644 index 5b5ae388c5..0000000000 --- a/libs/image/recorder/kis_recorded_action.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action.h" -#include -#include -#include - -#include -#include -#include -#include -#include - -struct Q_DECL_HIDDEN KisRecordedAction::Private { - QString name; - QString id; -}; - -KisRecordedAction::KisRecordedAction(const QString& id, const QString& name) : d(new Private()) -{ - d->name = name; - d->id = id; -} - -KisRecordedAction::KisRecordedAction(const KisRecordedAction& rhs) : d(new Private(*rhs.d)) -{ - -} - -KisRecordedAction::~KisRecordedAction() -{ - delete d; -} - -const QString& KisRecordedAction::id() const -{ - return d->id; -} - -const QString& KisRecordedAction::name() const -{ - return d->name; -} - -void KisRecordedAction::setName(const QString& name) -{ - d->name = name; -} - -void KisRecordedAction::toXML(QDomDocument& , QDomElement& elt, KisRecordedActionSaveContext* ) const -{ - elt.setAttribute("name", name()); - elt.setAttribute("id", id()); -} - -struct Q_DECL_HIDDEN KisRecordedActionFactory::Private { - QString id; -}; - -KisRecordedActionFactory::KisRecordedActionFactory(QString id) : d(new Private) -{ - d->id = id; -} - -KisRecordedActionFactory::~KisRecordedActionFactory() -{ - delete d; -} - -QString KisRecordedActionFactory::id() const -{ - return d->id; -} - -QString KisRecordedActionFactory::name() const -{ - return QString(); -} diff --git a/libs/image/recorder/kis_recorded_action.h b/libs/image/recorder/kis_recorded_action.h deleted file mode 100644 index 6285be090b..0000000000 --- a/libs/image/recorder/kis_recorded_action.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_H_ -#define _KIS_RECORDED_ACTION_H_ - -class QDomDocument; -class QDomElement; -class QString; -class KisPlayInfo; -class KisRecordedActionLoadContext; -class KisRecordedActionSaveContext; -class KoUpdater; - -#include -#include -#include - -/** - * This class represent an action. - */ -class KRITAIMAGE_EXPORT KisRecordedAction -{ -public: - KisRecordedAction(const QString& id, const QString& name); - KisRecordedAction(const KisRecordedAction&); - virtual ~KisRecordedAction(); - /** - * Play the action. - */ - virtual void play(const KisPlayInfo& _info, KoUpdater* _updater = 0) const = 0; - /** - * Clone this action. - */ - virtual KisRecordedAction* clone() const = 0; - virtual void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const; -public: - const QString& id() const; - const QString& name() const; - void setName(const QString& name); -private: - struct Private; - Private* const d; -}; - -/** - * This class is used to create recorded action. - */ -class KRITAIMAGE_EXPORT KisRecordedActionFactory -{ -public: - KisRecordedActionFactory(QString id); - virtual ~KisRecordedActionFactory(); - virtual KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) = 0; - QString id() const; - QString name() const; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_action_factory_registry.cc b/libs/image/recorder/kis_recorded_action_factory_registry.cc deleted file mode 100644 index b1d17cc41c..0000000000 --- a/libs/image/recorder/kis_recorded_action_factory_registry.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_factory_registry.h" -#include "kis_recorded_filter_action.h" -#include "kis_recorded_path_paint_action.h" -#include "kis_recorded_shape_paint_action.h" -#include "kis_recorded_fill_paint_action.h" - -#include -#include - -Q_GLOBAL_STATIC(KisRecordedActionFactoryRegistry, s_instance) - - -KisRecordedActionFactoryRegistry* KisRecordedActionFactoryRegistry::instance() -{ - return s_instance; -} - - -KisRecordedActionFactoryRegistry::KisRecordedActionFactoryRegistry() -{ - add(new KisRecordedFilterActionFactory); - add(new KisRecordedPathPaintActionFactory); - add(new KisRecordedShapePaintActionFactory); - add(new KisRecordedFillPaintActionFactory); -} - -KisRecordedActionFactoryRegistry::~KisRecordedActionFactoryRegistry() -{ - Q_FOREACH (const QString &id, keys()) { - delete get(id); - } - dbgRegistry << "deleting KisRecordedActionFactoryRegistry"; -} diff --git a/libs/image/recorder/kis_recorded_action_factory_registry.h b/libs/image/recorder/kis_recorded_action_factory_registry.h deleted file mode 100644 index b678417220..0000000000 --- a/libs/image/recorder/kis_recorded_action_factory_registry.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_FACTORY_REGISTRY_H_ -#define _KIS_RECORDED_ACTION_FACTORY_REGISTRY_H_ - -#include - -class KisRecordedActionFactory; - -#include - -class KRITAIMAGE_EXPORT KisRecordedActionFactoryRegistry : public KoGenericRegistry -{ -public: - KisRecordedActionFactoryRegistry(); - ~KisRecordedActionFactoryRegistry() override; - static KisRecordedActionFactoryRegistry* instance(); -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_action_load_context.cpp b/libs/image/recorder/kis_recorded_action_load_context.cpp deleted file mode 100644 index cb1dc1f43d..0000000000 --- a/libs/image/recorder/kis_recorded_action_load_context.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_load_context.h" - - -KisRecordedActionLoadContext::~KisRecordedActionLoadContext() -{ -} diff --git a/libs/image/recorder/kis_recorded_action_load_context.h b/libs/image/recorder/kis_recorded_action_load_context.h deleted file mode 100644 index 940fc3123b..0000000000 --- a/libs/image/recorder/kis_recorded_action_load_context.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_LOAD_CONTEXT_H_ -#define _KIS_RECORDED_ACTION_LOAD_CONTEXT_H_ - -#include "kritaimage_export.h" - -class KoAbstractGradient; -class KoPattern; -class QString; - -class KRITAIMAGE_EXPORT KisRecordedActionLoadContext { - public: - virtual ~KisRecordedActionLoadContext(); - virtual KoAbstractGradient* gradient(const QString& name) const = 0; - virtual KoPattern* pattern(const QString& name) const = 0; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_action_save_context.cpp b/libs/image/recorder/kis_recorded_action_save_context.cpp deleted file mode 100644 index 9230072cc7..0000000000 --- a/libs/image/recorder/kis_recorded_action_save_context.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_save_context.h" - -KisRecordedActionSaveContext::~KisRecordedActionSaveContext() -{ -} diff --git a/libs/image/recorder/kis_recorded_action_save_context.h b/libs/image/recorder/kis_recorded_action_save_context.h deleted file mode 100644 index c52ecf5ce3..0000000000 --- a/libs/image/recorder/kis_recorded_action_save_context.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_SAVE_CONTEXT_H_ -#define _KIS_RECORDED_ACTION_SAVE_CONTEXT_H_ - -#include "kritaimage_export.h" - -class KoAbstractGradient; -class KoPattern; - -class KRITAIMAGE_EXPORT KisRecordedActionSaveContext { - public: - virtual ~KisRecordedActionSaveContext(); - virtual void saveGradient(const KoAbstractGradient* gradient) = 0; - virtual void savePattern(const KoPattern* pattern) = 0; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_fill_paint_action.cpp b/libs/image/recorder/kis_recorded_fill_paint_action.cpp deleted file mode 100644 index 5a26bad2a4..0000000000 --- a/libs/image/recorder/kis_recorded_fill_paint_action.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_fill_paint_action.h" - -#include - -#include - -#include "kis_image.h" -#include -#include "kis_node.h" -#include "kis_node_query_path.h" -#include -#include "kis_play_info.h" - -struct Q_DECL_HIDDEN KisRecordedFillPaintAction::Private { - Private(const KisNodeQueryPath& _projectionPath) : projectionPath(_projectionPath) {} - QPoint pt; - KisNodeQueryPath projectionPath; -}; - -KisRecordedFillPaintAction::KisRecordedFillPaintAction( - const KisNodeQueryPath& path, - const QPoint& pt, - const KisNodeQueryPath& projectionPath) - : KisRecordedPaintAction("FillPaintAction", i18n("Fill"), path, 0) - , d(new Private(projectionPath)) -{ - d->pt = pt; -} - -KisRecordedFillPaintAction::KisRecordedFillPaintAction(const KisRecordedFillPaintAction& rhs) : KisRecordedPaintAction(rhs), d(new Private(*rhs.d)) -{ - -} - -KisRecordedFillPaintAction::~KisRecordedFillPaintAction() -{ - delete d; -} - -void KisRecordedFillPaintAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const -{ - KisRecordedPaintAction::toXML(doc, elt, context); - elt.setAttribute("x", d->pt.x()); - elt.setAttribute("y", d->pt.y()); - elt.setAttribute("projectionPath", d->projectionPath.toString()); -} - -KisRecordedAction* KisRecordedFillPaintAction::clone() const -{ - return new KisRecordedFillPaintAction(*this); -} - -KisPainter* KisRecordedFillPaintAction::createPainter(KisPaintDeviceSP device) const -{ - return new KisFillPainter(device); -} - -void KisRecordedFillPaintAction::playPaint(const KisPlayInfo& info, KisPainter* _painter) const -{ - QList nodes = d->projectionPath.queryNodes(info.image(), info.currentNode()); - KisPaintDeviceSP projection = 0; - if (!nodes.isEmpty()) - { - projection = nodes[0]->projection(); - } - KisFillPainter* painter = static_cast(_painter); - painter->setWidth(info.image()->width()); - painter->setHeight(info.image()->height()); - if (fillStyle() == KisPainter::FillStylePattern) - { - painter->fillPattern(d->pt.x(), d->pt.y(), projection); - } else { - painter->fillColor(d->pt.x(), d->pt.y(), projection); - } -} - -KisRecordedFillPaintActionFactory::KisRecordedFillPaintActionFactory() : - KisRecordedPaintActionFactory("FillPaintAction") -{ -} - -KisRecordedFillPaintActionFactory::~KisRecordedFillPaintActionFactory() -{ - -} - -KisRecordedAction* KisRecordedFillPaintActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext* context) -{ - KisNodeQueryPath pathnode = nodeQueryPathFromXML(elt); - KisNodeQueryPath projectionPathnode = KisNodeQueryPath::fromString(elt.attribute("projectionPath")); - - int x = elt.attribute("x", "0").toInt(); - int y = elt.attribute("y", "0").toInt(); - - KisRecordedFillPaintAction* rplpa = new KisRecordedFillPaintAction(pathnode, QPoint(x,y), projectionPathnode); - - setupPaintAction(rplpa, elt, context); - return rplpa; -} diff --git a/libs/image/recorder/kis_recorded_fill_paint_action.h b/libs/image/recorder/kis_recorded_fill_paint_action.h deleted file mode 100644 index 4a7fd3f00d..0000000000 --- a/libs/image/recorder/kis_recorded_fill_paint_action.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_FILL_PAINT_ACTION_H_ -#define _KIS_RECORDED_FILL_PAINT_ACTION_H_ - -#include "recorder/kis_recorded_action.h" -#include "recorder/kis_recorded_paint_action.h" -#include "kis_types.h" - -#include - -/** - * This class will record the painting of a bezier curve. - */ -class KRITAIMAGE_EXPORT KisRecordedFillPaintAction : public KisRecordedPaintAction -{ -public: - - KisRecordedFillPaintAction(const KisNodeQueryPath& path, const QPoint& pt, const KisNodeQueryPath& projectionPath); - - KisRecordedFillPaintAction(const KisRecordedFillPaintAction&); - - ~KisRecordedFillPaintAction() override; - - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; - - KisRecordedAction* clone() const override; - -protected: - - KisPainter* createPainter(KisPaintDeviceSP device) const override; - void playPaint(const KisPlayInfo& info, KisPainter* painter) const override; - -private: - - struct Private; - Private* const d; -}; - - -class KisRecordedFillPaintActionFactory : public KisRecordedPaintActionFactory -{ -public: - KisRecordedFillPaintActionFactory(); - ~KisRecordedFillPaintActionFactory() override; - KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) override; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_filter_action.cpp b/libs/image/recorder/kis_recorded_filter_action.cpp deleted file mode 100644 index 5052a43f11..0000000000 --- a/libs/image/recorder/kis_recorded_filter_action.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "recorder/kis_recorded_filter_action.h" -#include -#include - - -#include "kis_image.h" -#include "filter/kis_filter.h" -#include "filter/kis_filter_configuration.h" -#include "filter/kis_filter_registry.h" -#include "kis_layer.h" -#include "kis_node.h" -#include "kis_selection.h" -#include "kis_transaction.h" -#include "kis_undo_adapter.h" -#include "kis_selection_mask.h" -#include "kis_config_widget.h" -#include "kis_node_query_path.h" -#include "kis_play_info.h" - -struct Q_DECL_HIDDEN KisRecordedFilterAction::Private { - Private() - : filterConfiguration(0) - { - - } - - const KisFilter* filter; - QRect rect; - - KisFilterConfigurationSP configuration() { - if (!filterConfiguration) { - filterConfiguration = filter->defaultConfiguration(); - if (filterConfiguration) { - filterConfiguration->fromXML(configstr); - } - } - return filterConfiguration; - } - - void setConfiguration(KisFilterConfigurationSP conf) { - filterConfiguration = conf; - configstr = conf->toXML(); - } - - void setConfig(const QString& cfg) { - filterConfiguration = 0; - configstr = cfg; - } - - const QString& config() { - return configstr; - } - -private: - QString configstr; - KisFilterConfigurationSP filterConfiguration; -}; - -KisRecordedFilterAction::KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfigurationSP fc) : KisRecordedNodeAction("FilterAction", name, path), d(new Private) -{ - Q_ASSERT(filter); - d->filter = filter; - if (fc) { - d->setConfig(fc->toXML()); - } -} - -KisRecordedFilterAction::KisRecordedFilterAction(const KisRecordedFilterAction& rhs) : KisRecordedNodeAction(rhs), d(new Private(*rhs.d)) -{ -} - -KisRecordedFilterAction::~KisRecordedFilterAction() -{ - delete d; -} - -void KisRecordedFilterAction::play(KisNodeSP node, const KisPlayInfo& _info, KoUpdater* _updater) const -{ - KisFilterConfigurationSP kfc = d->configuration(); - KisPaintDeviceSP dev = node->paintDevice(); - KisLayerSP layer = qobject_cast(node.data()); - QRect r1 = dev->extent(); - KisTransaction transaction(kundo2_i18n("Filter: \"%1\"", d->filter->name()), dev); - - KisImageWSP image = _info.image(); - r1 = r1.intersected(image->bounds()); - if (layer && layer->selection()) { - r1 = r1.intersected(layer->selection()->selectedExactRect()); - } - - d->filter->process(dev, dev, layer->selection(), r1, kfc, _updater); - node->setDirty(r1); - - transaction.commit(_info.undoAdapter()); -} - -void KisRecordedFilterAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const -{ - KisRecordedAction::toXML(doc, elt, context); - elt.setAttribute("filter", d->filter->id()); - // Save configuration - KisFilterConfigurationSP kfc = d->configuration(); - if (kfc) { - QDomElement filterConfigElt = doc.createElement("Params"); - kfc->toXML(doc, filterConfigElt); - elt.appendChild(filterConfigElt); - } -} - -KisRecordedAction* KisRecordedFilterAction::clone() const -{ - return new KisRecordedFilterAction(*this); -} - -const KisFilter* KisRecordedFilterAction::filter() const -{ - return d->filter; -} - -const KisFilterConfigurationSP KisRecordedFilterAction::filterConfiguration() const -{ - return d->configuration(); -} - -void KisRecordedFilterAction::setFilterConfiguration(KisFilterConfigurationSP config) -{ - d->setConfiguration(config); -} - - -KisRecordedFilterActionFactory::KisRecordedFilterActionFactory() : - KisRecordedActionFactory("FilterAction") -{ -} - -KisRecordedFilterActionFactory::~KisRecordedFilterActionFactory() -{ - -} - -KisRecordedAction* KisRecordedFilterActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) -{ - QString name = elt.attribute("name"); - KisNodeQueryPath pathnode = KisNodeQueryPath::fromString(elt.attribute("path")); - const KisFilterSP filter = KisFilterRegistry::instance()->get(elt.attribute("filter")); - if (filter) { - KisFilterConfigurationSP config = filter->defaultConfiguration(); - QDomElement paramsElt = elt.firstChildElement("Params"); - if (config && !paramsElt.isNull()) { - config->fromXML(paramsElt); - } - KisRecordedFilterAction* rfa = new KisRecordedFilterAction(name, pathnode, filter, config); - return rfa; - } else { - return 0; - } -} diff --git a/libs/image/recorder/kis_recorded_filter_action.h b/libs/image/recorder/kis_recorded_filter_action.h deleted file mode 100644 index c568117ace..0000000000 --- a/libs/image/recorder/kis_recorded_filter_action.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_FILTER_ACTION_H_ -#define _KIS_RECORDED_FILTER_ACTION_H_ - -#include "recorder/kis_recorded_node_action.h" - -#include - -class QString; -class KisFilterConfiguration; - -/** - * Action representing a filter. - */ -class KRITAIMAGE_EXPORT KisRecordedFilterAction : public KisRecordedNodeAction -{ -public: - /** - * @param config the filter configuration, the ownership of config remains in the caller. - */ - KisRecordedFilterAction(QString name, const KisNodeQueryPath& path, const KisFilter* filter, const KisFilterConfigurationSP config); - KisRecordedFilterAction(const KisRecordedFilterAction&); - ~KisRecordedFilterAction() override; - using KisRecordedNodeAction::play; - void play(KisNodeSP node, const KisPlayInfo& _info, KoUpdater* _updater = 0) const override; - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; - KisRecordedAction* clone() const override; - const KisFilter* filter() const; - const KisFilterConfigurationSP filterConfiguration() const; - /** - * Set the configuration, and takes the ownership of the config object. - */ - void setFilterConfiguration(KisFilterConfigurationSP config); -private: - struct Private; - Private* const d; -}; - -class KisRecordedFilterActionFactory : public KisRecordedActionFactory -{ -public: - KisRecordedFilterActionFactory(); - ~KisRecordedFilterActionFactory() override; - KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) override; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_node_action.cc b/libs/image/recorder/kis_recorded_node_action.cc deleted file mode 100644 index 2529cc519c..0000000000 --- a/libs/image/recorder/kis_recorded_node_action.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_node_action.h" - -#include -#include -#include - -#include "kis_node_query_path.h" -#include "kis_play_info.h" -#include "kis_image.h" -#include "kis_paint_device.h" -#include - -struct Q_DECL_HIDDEN KisRecordedNodeAction::Private -{ - Private(const KisNodeQueryPath& _path) : path(_path) {} - KisNodeQueryPath path; -}; - -KisRecordedNodeAction::KisRecordedNodeAction(const QString& id, const QString& name, const KisNodeQueryPath& path) : KisRecordedAction(id, name), d(new Private(path)) -{ -} - -KisRecordedNodeAction::KisRecordedNodeAction(const KisRecordedNodeAction& _rhs) : KisRecordedAction(_rhs), d(new Private(*_rhs.d)) -{ -} - -KisRecordedNodeAction::~KisRecordedNodeAction() -{ - delete d; -} - -void KisRecordedNodeAction::play(const KisPlayInfo& _info, KoUpdater* _updater) const -{ - QList nodes = nodeQueryPath().queryNodes(_info.image(), _info.currentNode()); - KoProgressUpdater updater(_updater); - updater.start(nodes.size(), i18n("Applying action to all selected nodes")); - Q_FOREACH (KisNodeSP node, nodes) - { - play(node, _info, updater.startSubtask()); - } -} - -const KisNodeQueryPath& KisRecordedNodeAction::nodeQueryPath() const -{ - return d->path; -} - -void KisRecordedNodeAction::setNodeQueryPath(const KisNodeQueryPath& nqp) -{ - d->path = nqp; -} - -void KisRecordedNodeAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const -{ - Q_UNUSED(doc) - elt.setAttribute("path", d->path.toString()); -} diff --git a/libs/image/recorder/kis_recorded_node_action.h b/libs/image/recorder/kis_recorded_node_action.h deleted file mode 100644 index e9a4884b0d..0000000000 --- a/libs/image/recorder/kis_recorded_node_action.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_NODE_ACTION_H_ -#define _KIS_RECORDED_NODE_ACTION_H_ - -#include "kis_recorded_action.h" -class KisNodeQueryPath; - -/** - * Used for action that applys on nodes that are - */ -class KRITAIMAGE_EXPORT KisRecordedNodeAction : public KisRecordedAction -{ -public: - KisRecordedNodeAction(const QString& id, const QString& name, const KisNodeQueryPath& path); - KisRecordedNodeAction(const KisRecordedNodeAction& _rhs); - ~KisRecordedNodeAction() override; - /** - * Play the action on one node - */ - virtual void play(KisNodeSP node, const KisPlayInfo&, KoUpdater* _updater) const = 0; - /** - * Play the action on all the nodes returned by the nodeQueryPath - */ - void play(const KisPlayInfo& _info, KoUpdater* _updater) const override; - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; -public: - const KisNodeQueryPath& nodeQueryPath() const; - void setNodeQueryPath(const KisNodeQueryPath&); -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_paint_action.cpp b/libs/image/recorder/kis_recorded_paint_action.cpp deleted file mode 100644 index 5f04f12294..0000000000 --- a/libs/image/recorder/kis_recorded_paint_action.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (c) 2007,2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include //MSVC requires that Vc come first -#include "recorder/kis_recorded_paint_action.h" - -#include -#include - -#include -#include -#include -#include - -#include "kis_node.h" -#include "kis_mask_generator.h" -#include "kis_painter.h" -#include -#include "kis_paintop_registry.h" -#include "kis_transaction.h" -#include "kis_undo_adapter.h" -#include -#include -#include "kis_paint_device.h" -#include "kis_image.h" -#include "kis_layer.h" -#include "kis_play_info.h" -#include "kis_node_query_path.h" -#include -// Recorder -#include "kis_recorded_action_factory_registry.h" -#include "kis_recorded_action_load_context.h" -#include "kis_recorded_action_save_context.h" -#include -#include -#include -#include -#include - - -struct Q_DECL_HIDDEN KisRecordedPaintAction::Private { - KisPaintOpPresetSP paintOpPreset; - KoColor foregroundColor; - KoColor backgroundColor; - qreal opacity; ///< opacity in the range 0.0 -> 100.0 - bool paintIncremental; - QString compositeOp; - KisPainter::StrokeStyle strokeStyle; - KisPainter::FillStyle fillStyle; - const KoPattern* pattern; - const KoAbstractGradient* gradient; - KisFilterConfigurationSP generator; -}; - -KisRecordedPaintAction::KisRecordedPaintAction(const QString & id, - const QString & name, - const KisNodeQueryPath& path, - const KisPaintOpPresetSP paintOpPreset) - : KisRecordedNodeAction(id, name, path) - , d(new Private) -{ - if (paintOpPreset) - { - d->paintOpPreset = paintOpPreset; - } - d->opacity = 1.0; - d->paintIncremental = true; - d->compositeOp = COMPOSITE_OVER; - d->strokeStyle = KisPainter::StrokeStyleBrush; - d->fillStyle = KisPainter::FillStyleNone; - d->pattern = 0; - d->gradient = 0; -} - -KisRecordedPaintAction::KisRecordedPaintAction(const KisRecordedPaintAction& rhs) : KisRecordedNodeAction(rhs), d(new Private(*rhs.d)) -{ - -} - -KisRecordedPaintAction::~KisRecordedPaintAction() -{ - delete d; -} - -void KisRecordedPaintAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const -{ - KisRecordedAction::toXML(doc, elt, context); - - // Paint op presset - if (d->paintOpPreset) - { - QDomElement paintopPressetElt = doc.createElement("PaintopPreset"); - d->paintOpPreset->toXML(doc, paintopPressetElt); - elt.appendChild(paintopPressetElt); - } - - // ForegroundColor - QDomElement foregroundColorElt = doc.createElement("ForegroundColor"); - d->foregroundColor.toXML(doc, foregroundColorElt); - elt.appendChild(foregroundColorElt); - - // BackgroundColor - QDomElement backgroundColorElt = doc.createElement("BackgroundColor"); - d->backgroundColor.toXML(doc, backgroundColorElt); - elt.appendChild(backgroundColorElt); - - // Opacity - elt.setAttribute("opacity", KisDomUtils::toString(d->opacity)); - - // paintIncremental - elt.setAttribute("paintIncremental", d->paintIncremental); - - // compositeOp - elt.setAttribute("compositeOp", d->compositeOp); - - // Save stroke style - switch(d->strokeStyle) - { - case KisPainter::StrokeStyleNone: - elt.setAttribute("strokeStyle", "None"); - break; - case KisPainter::StrokeStyleBrush: - elt.setAttribute("strokeStyle", "Brush"); - break; - } - // Save fill style - switch(d->fillStyle) - { - case KisPainter::FillStyleNone: - elt.setAttribute("fillStyle", "None"); - break; - case KisPainter::FillStyleForegroundColor: - elt.setAttribute("fillStyle", "PaintColor"); - break; - case KisPainter::FillStyleBackgroundColor: - elt.setAttribute("fillStyle", "AlternativeColor"); - break; - case KisPainter::FillStylePattern: - elt.setAttribute("fillStyle", "Pattern"); - context->savePattern(d->pattern); - elt.setAttribute("pattern", d->pattern->name()); - break; - case KisPainter::FillStyleGradient: - elt.setAttribute("fillStyle", "Gradient"); - context->saveGradient(d->gradient); - elt.setAttribute("gradient", d->gradient->name()); - break; - case KisPainter::FillStyleStrokes: - elt.setAttribute("fillStyle", "Strokes"); - break; - case KisPainter::FillStyleGenerator: - elt.setAttribute("fillStyle", "Generator"); - if (d->generator) - { - elt.setAttribute("generator", d->generator->name()); - QDomElement filterConfigElt = doc.createElement("Generator"); - d->generator->toXML(doc, filterConfigElt); - elt.appendChild(filterConfigElt); - } - break; - } -} - -KisPaintOpPresetSP KisRecordedPaintAction::paintOpPreset() const -{ - return d->paintOpPreset; -} - -void KisRecordedPaintAction::setPaintOpPreset(KisPaintOpPresetSP preset) -{ - d->paintOpPreset = preset; -} - -qreal KisRecordedPaintAction::opacity() const -{ - return d->opacity; -} - -void KisRecordedPaintAction::setOpacity(qreal opacity) -{ - d->opacity = opacity; -} - -KoColor KisRecordedPaintAction::paintColor() const -{ - return d->foregroundColor; -} - -void KisRecordedPaintAction::setPaintColor(const KoColor& color) -{ - d->foregroundColor = color; -} - -KoColor KisRecordedPaintAction::backgroundColor() const -{ - return d->backgroundColor; -} - -void KisRecordedPaintAction::setBackgroundColor(const KoColor& color) -{ - d->backgroundColor = color; -} - -QString KisRecordedPaintAction::compositeOp() -{ - return d->compositeOp; -} - -void KisRecordedPaintAction::setCompositeOp(const QString& id) -{ - d->compositeOp = id; -} - -void KisRecordedPaintAction::setPaintIncremental(bool v) -{ - d->paintIncremental = v; -} - -void KisRecordedPaintAction::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) -{ - d->strokeStyle = strokeStyle; -} - -void KisRecordedPaintAction::setFillStyle(KisPainter::FillStyle fillStyle) -{ - d->fillStyle = fillStyle; -} - -KisPainter::FillStyle KisRecordedPaintAction::fillStyle() const -{ - return d->fillStyle; -} - -void KisRecordedPaintAction::setPattern(const KoPattern* pattern) -{ - d->pattern = pattern; -} - -void KisRecordedPaintAction::setGradient(const KoAbstractGradient* gradient) -{ - d->gradient = gradient; -} - -void KisRecordedPaintAction::setGenerator(const KisFilterConfigurationSP generator) -{ - d->generator = generator; -} - -void KisRecordedPaintAction::play(KisNodeSP node, const KisPlayInfo& info, KoUpdater* _updater) const -{ - dbgUI << "Play recorded paint action on node : " << node->name() ; - KisTransaction transaction(node->paintDevice()); - - KisPaintDeviceSP target = 0; - if (d->paintIncremental) { - target = node->paintDevice(); - } else { - target = node->paintDevice()->createCompositionSourceDevice(); - } - - KisPainter* painter = createPainter(target); - painter->setProgress(_updater); - - if (d->paintIncremental) { - painter->setCompositeOp(d->compositeOp); - painter->setOpacity(d->opacity * 255); - } else { - painter->setCompositeOp(node->paintDevice()->colorSpace()->compositeOp(COMPOSITE_ALPHA_DARKEN)); - painter->setOpacity(OPACITY_OPAQUE_U8); - - } - - painter->setPaintColor(d->foregroundColor); - painter->setBackgroundColor(d->backgroundColor); - - painter->setStrokeStyle(d->strokeStyle); - painter->setFillStyle(d->fillStyle); - painter->setPattern(d->pattern); - painter->setGradient(d->gradient); - painter->setGenerator(d->generator); - - if (d->paintOpPreset) { - painter->setPaintOpPreset(d->paintOpPreset, node, info.image()); - } - - playPaint(info, painter); - - if (!d->paintIncremental) { - KisPainter painter2(node->paintDevice()); - painter2.setCompositeOp(d->compositeOp); - painter2.setOpacity(d->opacity * 255); - - QVector dirtyRects = painter->takeDirtyRegion(); - Q_FOREACH (const QRect &rc, dirtyRects) { - painter2.bitBlt(rc.topLeft(), target, rc); - } - - node->setDirty(painter2.takeDirtyRegion()); - } else { - node->setDirty(painter->takeDirtyRegion()); - } - delete painter; - - transaction.commit(info.undoAdapter()); -} - -KisPainter* KisRecordedPaintAction::createPainter(KisPaintDeviceSP device) const -{ - return new KisPainter(device); -} - -void KisRecordedPaintActionFactory::setupPaintAction(KisRecordedPaintAction* action, const QDomElement& elt, const KisRecordedActionLoadContext* context) -{ - QString name = elt.attribute("name"); - - qreal opacity = opacityFromXML(elt); - dbgKrita << ppVar(opacity); - bool paintIncremental = paintIncrementalFromXML(elt); - - QString compositeOp = compositeOpFromXML(elt); - // Decode colors - - KoColor bC = backgroundColorFromXML(elt); - KoColor fC = paintColorFromXML(elt); - - action->setName(name); - action->setBackgroundColor(bC); - action->setPaintColor(fC); - action->setOpacity(opacity); - action->setPaintIncremental(paintIncremental); - action->setCompositeOp(compositeOp); - - - // Load stroke style - QString strokeAttr = elt.attribute("strokeStyle", "None"); - if (strokeAttr == "Brush" ) - { - action->setStrokeStyle(KisPainter::StrokeStyleBrush); - } else { // "None" - action->setStrokeStyle(KisPainter::StrokeStyleNone); - } - // Save fill style - QString fillAttr = elt.attribute("fillStyle", "None"); - if (fillAttr == "PaintColor") - { - action->setFillStyle(KisPainter::FillStyleForegroundColor); - } else if(fillAttr == "AlternativeColor") - { - action->setFillStyle(KisPainter::FillStyleBackgroundColor); - } else if(fillAttr == "Pattern") - { - const KoPattern* pattern = context->pattern(elt.attribute("pattern")); - if (pattern) - { - action->setFillStyle(KisPainter::FillStylePattern); - action->setPattern(pattern); - } else { - action->setFillStyle(KisPainter::FillStyleNone); - } - } else if(fillAttr == "Gradient") - { - const KoAbstractGradient* gradient = context->gradient(elt.attribute("gradient")); - if (gradient) - { - action->setFillStyle(KisPainter::FillStyleGradient); - action->setGradient(gradient); - } else { - action->setFillStyle(KisPainter::FillStyleNone); - } - } else if(fillAttr == "Strokes") - { - action->setFillStyle(KisPainter::FillStyleStrokes); - } else if(fillAttr == "Generator") - { - KisGeneratorSP g = KisGeneratorRegistry::instance()->value(elt.attribute("generator")); - KisFilterConfigurationSP config = 0; - if (g) - { - config = g->defaultConfiguration(); - QDomElement paramsElt = elt.firstChildElement("Generator"); - if (config && !paramsElt.isNull()) { - config->fromXML(paramsElt); - } - } - if(config) - { - action->setFillStyle(KisPainter::FillStyleGenerator); - action->setGenerator(config); - } else { - action->setFillStyle(KisPainter::FillStyleNone); - } - } -} - -KisPaintOpPresetSP KisRecordedPaintActionFactory::paintOpPresetFromXML(const QDomElement& elt) -{ - - QDomElement settingsElt = elt.firstChildElement("PaintopPreset"); - if (!settingsElt.isNull()) { - KisPaintOpPresetSP settings = new KisPaintOpPreset; - settings->fromXML(settingsElt); - return settings; - } else { - errImage << "No found"; - return 0; - } -} - -KoColor KisRecordedPaintActionFactory::paintColorFromXML(const QDomElement& elt) -{ - return colorFromXML(elt, "ForegroundColor"); -} - -KoColor KisRecordedPaintActionFactory::backgroundColorFromXML(const QDomElement& elt) -{ - return colorFromXML(elt, "BackgroundColor"); -} - -KoColor KisRecordedPaintActionFactory::colorFromXML(const QDomElement& elt, const QString& elementName) -{ - QDomElement colorElt = elt.firstChildElement(elementName); - KoColor bC; - - if (!colorElt.isNull()) { - bC = KoColor::fromXML(colorElt.firstChildElement(), Integer8BitsColorDepthID.id()); - bC.setOpacity(quint8(255)); - dbgImage << elementName << " color : " << bC.toQColor(); - } else { - dbgImage << "Warning: no <" << elementName << " /> found"; - } - return bC; -} - -qreal KisRecordedPaintActionFactory::opacityFromXML(const QDomElement& elt) -{ - return KisDomUtils::toDouble(elt.attribute("opacity", "1.0")); -} - -bool KisRecordedPaintActionFactory::paintIncrementalFromXML(const QDomElement& elt) -{ - return KisDomUtils::toInt(elt.attribute("paintIncremental", "1")); -} - -QString KisRecordedPaintActionFactory::compositeOpFromXML(const QDomElement& elt) -{ - return elt.attribute("compositeOp", COMPOSITE_OVER); -} - -KisNodeQueryPath KisRecordedPaintActionFactory::nodeQueryPathFromXML(const QDomElement& elt) -{ - return KisNodeQueryPath::fromString(elt.attribute("path")); -} diff --git a/libs/image/recorder/kis_recorded_paint_action.h b/libs/image/recorder/kis_recorded_paint_action.h deleted file mode 100644 index 68b33119bb..0000000000 --- a/libs/image/recorder/kis_recorded_paint_action.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2007,2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_PAINT_ACTION_H_ -#define _KIS_RECORDED_PAINT_ACTION_H_ - -#include "recorder/kis_recorded_node_action.h" -#include "kis_types.h" -#include "kis_painter.h" - -class KisPainter; -class KoColor; - -#include - -/** - * Base class for paint action. - */ -class KRITAIMAGE_EXPORT KisRecordedPaintAction : public KisRecordedNodeAction -{ -public: - - KisRecordedPaintAction(const QString & id, - const QString & name, - const KisNodeQueryPath& path, - KisPaintOpPresetSP paintOpPreset); - - KisRecordedPaintAction(const KisRecordedPaintAction&); - - ~KisRecordedPaintAction() override; - - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; - - using KisRecordedNodeAction::play; - void play(KisNodeSP node, const KisPlayInfo& info, KoUpdater* _updater = 0) const override; - -protected: - /** - * This function will create a painter for the given device. The default - * implementation creates a KisPainter, subclass can reimplement it if - * they want to use one of the subclass of KisPainter. - */ - virtual KisPainter* createPainter(KisPaintDeviceSP device) const; - /** - * Reimplement this function in a subclass to play the painting. - */ - virtual void playPaint(const KisPlayInfo&, KisPainter* painter) const = 0; - -public: - KisPaintOpPresetSP paintOpPreset() const; - void setPaintOpPreset(KisPaintOpPresetSP preset); - /** - * @return the opacity in the range 0.0->1.0 - */ - qreal opacity() const; - void setOpacity(qreal ); - KoColor paintColor() const; - void setPaintColor(const KoColor& color); - KoColor backgroundColor() const; - void setBackgroundColor(const KoColor& color); - QString compositeOp(); - void setCompositeOp(const QString& ); - void setPaintIncremental(bool ); - void setStrokeStyle(KisPainter::StrokeStyle ); - void setFillStyle(KisPainter::FillStyle ); - KisPainter::FillStyle fillStyle() const; - void setPattern(const KoPattern* ); - void setGradient(const KoAbstractGradient* gradient); - void setGenerator(const KisFilterConfigurationSP generator); -private: - - struct Private; - Private* const d; -}; - -class KisRecordedPaintActionFactory : public KisRecordedActionFactory -{ -public: - KisRecordedPaintActionFactory(const QString & id) : KisRecordedActionFactory(id) {} - ~KisRecordedPaintActionFactory() override {} -protected: - - void setupPaintAction(KisRecordedPaintAction* action, const QDomElement& elt, const KisRecordedActionLoadContext*); - KisPaintOpPresetSP paintOpPresetFromXML(const QDomElement& elt); - KoColor paintColorFromXML(const QDomElement& elt); - KoColor backgroundColorFromXML(const QDomElement& elt); - KoColor colorFromXML(const QDomElement& elt, const QString& elementName); - qreal opacityFromXML(const QDomElement& elt); - bool paintIncrementalFromXML(const QDomElement& elt); - QString compositeOpFromXML(const QDomElement& elt); - KisNodeQueryPath nodeQueryPathFromXML(const QDomElement& elt); -}; - - -#endif diff --git a/libs/image/recorder/kis_recorded_path_paint_action.cpp b/libs/image/recorder/kis_recorded_path_paint_action.cpp deleted file mode 100644 index a4951a5194..0000000000 --- a/libs/image/recorder/kis_recorded_path_paint_action.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include //MSVC requires that Vc come first -#include "recorder/kis_recorded_path_paint_action.h" -#include -#include - -#include -#include -#include -#include "kis_node.h" -#include "kis_mask_generator.h" -#include "kis_painter.h" -#include -#include "kis_paintop_registry.h" -#include "recorder/kis_recorded_action_factory_registry.h" -#include "kis_transaction.h" -#include "kis_undo_adapter.h" -#include -#include -#include "kis_paint_device.h" -#include "kis_image.h" -#include "kis_layer.h" -#include "kis_node_query_path.h" -#include - -struct Q_DECL_HIDDEN KisRecordedPathPaintAction::Private { - struct BezierCurveSlice { - enum Type { - Point, - Line, - Curve - }; - Type type; - KisPaintInformation point1; - QPointF control1; - QPointF control2; - KisPaintInformation point2; - }; - - Private(const KisDistanceInitInfo &startDistInfo) : - startDistInfo(startDistInfo) {} - - QList curveSlices; - - // Information about distance and spacing at the start of the action. - KisDistanceInitInfo startDistInfo; -}; - -KisRecordedPathPaintAction::KisRecordedPathPaintAction( - const KisNodeQueryPath& path, - const KisPaintOpPresetSP preset, - const KisDistanceInitInfo& startDistInfo) - : KisRecordedPaintAction("PathPaintAction", i18n("Path"), path, preset) - , d(new Private(startDistInfo)) -{ -} - -KisRecordedPathPaintAction::KisRecordedPathPaintAction(const KisRecordedPathPaintAction& rhs) : KisRecordedPaintAction(rhs), d(new Private(*rhs.d)) -{ - -} - -KisRecordedPathPaintAction::~KisRecordedPathPaintAction() -{ - delete d; -} - -KisDistanceInitInfo KisRecordedPathPaintAction::getInitDistInfo() const -{ - return d->startDistInfo; -} - -void KisRecordedPathPaintAction::setInitDistInfo(const KisDistanceInitInfo &startDistInfo) -{ - d->startDistInfo = startDistInfo; -} - -void KisRecordedPathPaintAction::addPoint(const KisPaintInformation& info) -{ - Private::BezierCurveSlice slice; - slice.type = Private::BezierCurveSlice::Point; - slice.point1 = info; - d->curveSlices.append(slice); -} - -void KisRecordedPathPaintAction::addLine(const KisPaintInformation& point1, const KisPaintInformation& point2) -{ - Private::BezierCurveSlice slice; - slice.type = Private::BezierCurveSlice::Line; - slice.point1 = point1; - slice.point2 = point2; - d->curveSlices.append(slice); -} - -void KisRecordedPathPaintAction::addPolyLine(const QList& points) -{ - QPointF previousPoint = points[0]; - for(int i = 1; i < points.size(); ++i) { - QPointF pt = points[i]; - addLine(KisPaintInformation(previousPoint), KisPaintInformation(pt)); - previousPoint = pt; - } -} - - -void KisRecordedPathPaintAction::addCurve(const KisPaintInformation& point1, - const QPointF& control1, - const QPointF& control2, - const KisPaintInformation& point2) -{ - Private::BezierCurveSlice slice; - slice.type = Private::BezierCurveSlice::Curve; - slice.point1 = point1; - slice.control1 = control1; - slice.control2 = control2; - slice.point2 = point2; - d->curveSlices.append(slice); -} - -void KisRecordedPathPaintAction::playPaint(const KisPlayInfo&, KisPainter* painter) const -{ - dbgImage << "play path paint action with " << d->curveSlices.size() << " slices"; - if (d->curveSlices.size() <= 0) return; - - KisDistanceInformation savedDist = d->startDistInfo.makeDistInfo(); - - Q_FOREACH (const Private::BezierCurveSlice &slice, d->curveSlices) - { - switch(slice.type) - { - case Private::BezierCurveSlice::Point: - painter->paintAt(slice.point1, &savedDist); - break; - case Private::BezierCurveSlice::Line: - painter->paintLine(slice.point1, slice.point2, &savedDist); - break; - case Private::BezierCurveSlice::Curve: - painter->paintBezierCurve(slice.point1, slice.control1, slice.control2, slice.point2, &savedDist); - break; - } - } -} - -void KisRecordedPathPaintAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const -{ - KisRecordedPaintAction::toXML(doc, elt, context); - QDomElement waypointsElt = doc.createElement("Slices"); - Q_FOREACH (const Private::BezierCurveSlice & slice, d->curveSlices) { - switch(slice.type) - { - case Private::BezierCurveSlice::Point: - { - QDomElement infoElt = doc.createElement("Point"); - slice.point1.toXML(doc, infoElt); - - waypointsElt.appendChild(infoElt); - break; - } - case Private::BezierCurveSlice::Line: - { - QDomElement infoElt = doc.createElement("Line"); - // Point1 - QDomElement point1Elt = doc.createElement("Point1"); - slice.point1.toXML(doc, point1Elt); - infoElt.appendChild(point1Elt); - // Point2 - QDomElement point2Elt = doc.createElement("Point2"); - slice.point2.toXML(doc, point2Elt); - infoElt.appendChild(point2Elt); - - waypointsElt.appendChild(infoElt); - break; - } - case Private::BezierCurveSlice::Curve: - { - QDomElement infoElt = doc.createElement("Curve"); - // Point1 - QDomElement point1Elt = doc.createElement("Point1"); - slice.point1.toXML(doc, point1Elt); - infoElt.appendChild(point1Elt); - // Control1 - QDomElement control1Elt = doc.createElement("Control1"); - control1Elt.setAttribute("x", KisDomUtils::toString(slice.control1.x())); - control1Elt.setAttribute("y", KisDomUtils::toString(slice.control1.y())); - infoElt.appendChild(control1Elt); - // Control2 - QDomElement control2Elt = doc.createElement("Control2"); - control2Elt.setAttribute("x", KisDomUtils::toString(slice.control2.x())); - control2Elt.setAttribute("y", KisDomUtils::toString(slice.control2.y())); - infoElt.appendChild(control2Elt); - // Point2 - QDomElement point2Elt = doc.createElement("Point2"); - slice.point2.toXML(doc, point2Elt); - infoElt.appendChild(point2Elt); - - waypointsElt.appendChild(infoElt); - } - } - } - elt.appendChild(waypointsElt); - - QDomElement initDistElt = doc.createElement("StartDistInfo"); - d->startDistInfo.toXML(doc, initDistElt); - elt.appendChild(initDistElt); -} - -KisRecordedAction* KisRecordedPathPaintAction::clone() const -{ - return new KisRecordedPathPaintAction(*this); -} - - -KisRecordedPathPaintActionFactory::KisRecordedPathPaintActionFactory() : - KisRecordedPaintActionFactory("PathPaintAction") -{ -} - -KisRecordedPathPaintActionFactory::~KisRecordedPathPaintActionFactory() -{ - -} - -KisRecordedAction* KisRecordedPathPaintActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext* context) -{ - KisNodeQueryPath pathnode = nodeQueryPathFromXML(elt); - - // Decode pressets - KisPaintOpPresetSP paintOpPreset = paintOpPresetFromXML(elt); - - KisRecordedPathPaintAction* rplpa = new KisRecordedPathPaintAction(pathnode, paintOpPreset, - KisDistanceInitInfo()); - - setupPaintAction(rplpa, elt, context); - - QDomElement wpElt = elt.firstChildElement("Slices"); - if (!wpElt.isNull()) { - QDomNode nWp = wpElt.firstChild(); - while (!nWp.isNull()) { - QDomElement eWp = nWp.toElement(); - if (!eWp.isNull()) { - if( eWp.tagName() == "Point") { - rplpa->addPoint(KisPaintInformation::fromXML(eWp)); - } else if(eWp.tagName() == "Line") { - rplpa->addLine(KisPaintInformation::fromXML(eWp.firstChildElement("Point1")), - KisPaintInformation::fromXML(eWp.firstChildElement("Point2"))); - } else if( eWp.tagName() == "Curve") { - QDomElement control1Elt = eWp.firstChildElement("Control1"); - QDomElement control2Elt = eWp.firstChildElement("Control2"); - rplpa->addCurve(KisPaintInformation::fromXML(eWp.firstChildElement("Point1")), - QPointF(KisDomUtils::toDouble(control1Elt.attribute("x", "0.0")), - KisDomUtils::toDouble(control1Elt.attribute("y", "0.0"))), - QPointF(KisDomUtils::toDouble(control2Elt.attribute("x", "0.0")), - KisDomUtils::toDouble(control2Elt.attribute("y", "0.0"))), - KisPaintInformation::fromXML(eWp.firstChildElement("Point2"))); - } else { - dbgImage << "Unsupported <" << eWp.tagName() << " /> element"; - } - } - nWp = nWp.nextSibling(); - } - } else { - dbgImage << "Warning: no found"; - } - - QDomElement initDistInfoElt = elt.firstChildElement("StartDistInfo"); - if (!initDistInfoElt.isNull()) { - rplpa->setInitDistInfo(KisDistanceInitInfo::fromXML(initDistInfoElt)); - } else { - dbgImage << "Warning: no found"; - } - - return rplpa; -} - - diff --git a/libs/image/recorder/kis_recorded_path_paint_action.h b/libs/image/recorder/kis_recorded_path_paint_action.h deleted file mode 100644 index 607eb47ccc..0000000000 --- a/libs/image/recorder/kis_recorded_path_paint_action.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_PATH_PAINT_ACTIONS_H_ -#define _KIS_RECORDED_PATH_PAINT_ACTIONS_H_ - -#include "recorder/kis_recorded_action.h" -#include "recorder/kis_recorded_paint_action.h" -#include "kis_types.h" - -class KisPaintInformation; -class KisPainter; -class KisDistanceInitInfo; - -#include - -/** - * This class will record the painting of a bezier curve. - */ -class KRITAIMAGE_EXPORT KisRecordedPathPaintAction : public KisRecordedPaintAction -{ - -public: - - /** - * @param startDist - Provides initial information related to distance and spacing, which can - * have an effect on how the path is painted. - */ - KisRecordedPathPaintAction(const KisNodeQueryPath& path, - const KisPaintOpPresetSP paintOpPreset, - const KisDistanceInitInfo& startDistInfo); - - KisRecordedPathPaintAction(const KisRecordedPathPaintAction&); - - ~KisRecordedPathPaintAction() override; - - KisDistanceInitInfo getInitDistInfo() const; - - void setInitDistInfo(const KisDistanceInitInfo &startDistInfo); - - void addPoint(const KisPaintInformation& info); - void addLine(const KisPaintInformation& point1, const KisPaintInformation& point2); - void addPolyLine(const QList& points); - void addCurve(const KisPaintInformation& point1, - const QPointF& control1, - const QPointF& control2, - const KisPaintInformation& point2); - - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; - - KisRecordedAction* clone() const override; - -protected: - - void playPaint(const KisPlayInfo& info, KisPainter* painter) const override; - -private: - - struct Private; - Private* const d; -}; - - -class KisRecordedPathPaintActionFactory : public KisRecordedPaintActionFactory -{ -public: - KisRecordedPathPaintActionFactory(); - ~KisRecordedPathPaintActionFactory() override; - KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) override; -}; - -#endif diff --git a/libs/image/recorder/kis_recorded_shape_paint_action.cpp b/libs/image/recorder/kis_recorded_shape_paint_action.cpp deleted file mode 100644 index ea48b426d8..0000000000 --- a/libs/image/recorder/kis_recorded_shape_paint_action.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include //MSVC requires that Vc come first - -#include "recorder/kis_recorded_shape_paint_action.h" - -#include -#include - -#include -#include -#include -#include "kis_node.h" -#include "kis_mask_generator.h" -#include "kis_painter.h" -#include -#include "kis_paintop_registry.h" -#include "recorder/kis_recorded_action_factory_registry.h" -#include "kis_transaction.h" -#include "kis_undo_adapter.h" -#include -#include -#include "kis_paint_device.h" -#include "kis_image.h" -#include "kis_layer.h" -#include "kis_node_query_path.h" -#include - -struct Q_DECL_HIDDEN KisRecordedShapePaintAction::Private { - Shape shape; - QRectF rectangle; -}; - -QString selectName(KisRecordedShapePaintAction::Shape s) -{ - switch(s) - { - case KisRecordedShapePaintAction::Ellipse: - return i18n("Ellipse"); - case KisRecordedShapePaintAction::Rectangle: - return i18n("Rectangle"); - } - return QString(); -} - -KisRecordedShapePaintAction::KisRecordedShapePaintAction( - const KisNodeQueryPath& path, - const KisPaintOpPresetSP preset, - Shape shape, - const QRectF& rect) - : KisRecordedPaintAction("ShapePaintAction", selectName(shape), path, preset) - , d(new Private) -{ - d->shape = shape; - d->rectangle = rect; -} - -KisRecordedShapePaintAction::KisRecordedShapePaintAction(const KisRecordedShapePaintAction& rhs) : KisRecordedPaintAction(rhs), d(new Private(*rhs.d)) -{ - -} - -KisRecordedShapePaintAction::~KisRecordedShapePaintAction() -{ - delete d; -} - -void KisRecordedShapePaintAction::playPaint(const KisPlayInfo&, KisPainter* painter) const -{ - switch(d->shape) - { - case Ellipse: - painter->paintEllipse(d->rectangle); - break; - case Rectangle: - painter->paintRect(d->rectangle); - break; - } -} - -void KisRecordedShapePaintAction::toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* context) const -{ - KisRecordedPaintAction::toXML(doc, elt, context); - QDomElement rectangleElt = doc.createElement("Rectangle"); - rectangleElt.setAttribute("x", KisDomUtils::toString(d->rectangle.x())); - rectangleElt.setAttribute("y", KisDomUtils::toString(d->rectangle.y())); - rectangleElt.setAttribute("width", KisDomUtils::toString(d->rectangle.width())); - rectangleElt.setAttribute("height", KisDomUtils::toString(d->rectangle.height())); - elt.appendChild(rectangleElt); - switch(d->shape) - { - case Ellipse: - elt.setAttribute("shape", "Ellipse"); - break; - case Rectangle: - elt.setAttribute("shape", "Rectangle"); - break; - } -} - -KisRecordedAction* KisRecordedShapePaintAction::clone() const -{ - return new KisRecordedShapePaintAction(*this); -} - - -KisRecordedShapePaintActionFactory::KisRecordedShapePaintActionFactory() : - KisRecordedPaintActionFactory("ShapePaintAction") -{ -} - -KisRecordedShapePaintActionFactory::~KisRecordedShapePaintActionFactory() -{ - -} - -KisRecordedAction* KisRecordedShapePaintActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext* context) -{ - KisNodeQueryPath pathnode = nodeQueryPathFromXML(elt); - - // Decode pressets - KisPaintOpPresetSP paintOpPreset = paintOpPresetFromXML(elt); - - QDomElement ellipseElt = elt.firstChildElement("Rectangle"); - qreal x, y, width, height; - if (!ellipseElt.isNull()) { - x = KisDomUtils::toDouble(ellipseElt.attribute("x", "0.0")); - y = KisDomUtils::toDouble(ellipseElt.attribute("y", "0.0")); - width = KisDomUtils::toDouble(ellipseElt.attribute("width", "0.0")); - height = KisDomUtils::toDouble(ellipseElt.attribute("height", "0.0")); - } - else { - x = 0; - y = 0; - width = 0; - height = 0; - dbgImage << "Warning: no found"; - } - - KisRecordedShapePaintAction::Shape shape = KisRecordedShapePaintAction::Ellipse; - QString shapeStr = elt.attribute("shape", "Ellipse"); - if (shapeStr == "Ellipse") - { - shape = KisRecordedShapePaintAction::Ellipse; - } else { // shapeStr == "Rectangle" - shape = KisRecordedShapePaintAction::Rectangle; - } - - KisRecordedShapePaintAction* rplpa = new KisRecordedShapePaintAction(pathnode, paintOpPreset, shape, QRectF(x, y, width, height)); - - setupPaintAction(rplpa, elt, context); - return rplpa; -} diff --git a/libs/image/recorder/kis_recorded_shape_paint_action.h b/libs/image/recorder/kis_recorded_shape_paint_action.h deleted file mode 100644 index cc190ed8d0..0000000000 --- a/libs/image/recorder/kis_recorded_shape_paint_action.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ELLIPSE_PAINT_ACTION_H_ -#define _KIS_RECORDED_ELLIPSE_PAINT_ACTION_H_ - -#include "recorder/kis_recorded_action.h" -#include "recorder/kis_recorded_paint_action.h" -#include "kis_types.h" - -#include - -/** - * This class will record the painting of a bezier curve. - */ -class KRITAIMAGE_EXPORT KisRecordedShapePaintAction : public KisRecordedPaintAction -{ -public: - enum Shape { - Ellipse, - Rectangle - }; -public: - - KisRecordedShapePaintAction(const KisNodeQueryPath& path, - const KisPaintOpPresetSP paintOpPreset, - Shape shape, - const QRectF& rect); - - KisRecordedShapePaintAction(const KisRecordedShapePaintAction&); - - ~KisRecordedShapePaintAction() override; - - void toXML(QDomDocument& doc, QDomElement& elt, KisRecordedActionSaveContext* ) const override; - - KisRecordedAction* clone() const override; - -protected: - - void playPaint(const KisPlayInfo& info, KisPainter* painter) const override; - -private: - - struct Private; - Private* const d; -}; - - -class KisRecordedShapePaintActionFactory : public KisRecordedPaintActionFactory -{ -public: - KisRecordedShapePaintActionFactory(); - ~KisRecordedShapePaintActionFactory() override; - KisRecordedAction* fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) override; -}; - -#endif diff --git a/libs/image/tests/CMakeLists.txt b/libs/image/tests/CMakeLists.txt index 979f93f1dd..aff2df122c 100644 --- a/libs/image/tests/CMakeLists.txt +++ b/libs/image/tests/CMakeLists.txt @@ -1,248 +1,244 @@ # cmake in some versions for some not yet known reasons fails to run automoc # on random targets (changing target names already has an effect) # As temporary workaround skipping build of tests on these versions for now # See https://mail.kde.org/pipermail/kde-buildsystem/2015-June/010819.html # extend range of affected cmake versions as needed if(NOT ${CMAKE_VERSION} VERSION_LESS 3.1.3 AND NOT ${CMAKE_VERSION} VERSION_GREATER 3.2.3) message(WARNING "Skipping krita/image/tests, CMake in at least versions 3.1.3 - 3.2.3 seems to have a problem with automoc. \n(FRIENDLY REMINDER: PLEASE DON'T BREAK THE TESTS!)") set (HAVE_FAILING_CMAKE TRUE) else() set (HAVE_FAILING_CMAKE FALSE) endif() include_directories( ${CMAKE_SOURCE_DIR}/libs/image/metadata ${CMAKE_BINARY_DIR}/libs/image/ ${CMAKE_SOURCE_DIR}/libs/image/ ${CMAKE_SOURCE_DIR}/libs/image/brushengine ${CMAKE_SOURCE_DIR}/libs/image/tiles3 ${CMAKE_SOURCE_DIR}/libs/image/tiles3/swap ${CMAKE_SOURCE_DIR}/sdk/tests ) include_Directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ) if(HAVE_VC) include_directories(${Vc_INCLUDE_DIR}) endif() include(ECMAddTests) include(KritaAddBrokenUnitTest) macro_add_unittest_definitions() set(KisRandomGeneratorDemoSources kis_random_generator_demo.cpp kimageframe.cpp) ki18n_wrap_ui(KisRandomGeneratorDemoSources kis_random_generator_demo.ui) add_executable(KisRandomGeneratorDemo ${KisRandomGeneratorDemoSources}) target_link_libraries(KisRandomGeneratorDemo kritaimage) ecm_mark_as_test(KisRandomGeneratorDemo) ecm_add_tests( kis_base_node_test.cpp kis_fast_math_test.cpp kis_node_test.cpp kis_node_facade_test.cpp kis_fixed_paint_device_test.cpp kis_layer_test.cpp kis_effect_mask_test.cpp kis_iterator_test.cpp kis_painter_test.cpp kis_selection_test.cpp kis_count_visitor_test.cpp kis_projection_test.cpp kis_properties_configuration_test.cpp kis_transaction_test.cpp kis_pixel_selection_test.cpp kis_group_layer_test.cpp kis_paint_layer_test.cpp kis_adjustment_layer_test.cpp kis_annotation_test.cpp kis_change_profile_visitor_test.cpp kis_clone_layer_test.cpp kis_colorspace_convert_visitor_test.cpp kis_convolution_painter_test.cpp kis_crop_processing_visitor_test.cpp kis_processing_applicator_test.cpp kis_datamanager_test.cpp kis_fill_painter_test.cpp kis_filter_configuration_test.cpp kis_filter_test.cpp kis_filter_processing_information_test.cpp kis_filter_registry_test.cpp kis_filter_strategy_test.cpp kis_gradient_painter_test.cpp kis_image_commands_test.cpp kis_image_test.cpp kis_image_signal_router_test.cpp kis_iterators_ng_test.cpp kis_iterator_benchmark.cpp kis_updater_context_test.cpp kis_simple_update_queue_test.cpp kis_stroke_test.cpp kis_simple_stroke_strategy_test.cpp kis_stroke_strategy_undo_command_based_test.cpp kis_strokes_queue_test.cpp - kis_macro_test.cpp kis_mask_test.cpp kis_math_toolbox_test.cpp kis_name_server_test.cpp kis_node_commands_test.cpp kis_node_graph_listener_test.cpp kis_node_visitor_test.cpp kis_paint_information_test.cpp kis_distance_information_test.cpp kis_paintop_test.cpp kis_pattern_test.cpp - kis_recorded_action_factory_registry_test.cpp - kis_recorded_action_test.cpp - kis_recorded_filter_action_test.cpp kis_selection_mask_test.cpp kis_shared_ptr_test.cpp kis_bsplines_test.cpp kis_warp_transform_worker_test.cpp kis_liquify_transform_worker_test.cpp kis_transparency_mask_test.cpp kis_types_test.cpp kis_vec_test.cpp kis_filter_config_widget_test.cpp kis_mask_generator_test.cpp kis_cubic_curve_test.cpp - kis_node_query_path_test.cpp kis_fixed_point_maths_test.cpp + kis_node_query_path_test.cpp kis_filter_weights_buffer_test.cpp kis_filter_weights_applicator_test.cpp kis_fill_interval_test.cpp kis_fill_interval_map_test.cpp kis_scanline_fill_test.cpp kis_psd_layer_style_test.cpp kis_layer_style_projection_plane_test.cpp kis_lod_capable_layer_offset_test.cpp kis_algebra_2d_test.cpp kis_marker_painter_test.cpp kis_lazy_brush_test.cpp kis_colorize_mask_test.cpp kis_mask_similarity_test.cpp KisMaskGeneratorBenchmark.cpp NAME_PREFIX "krita-image-" LINK_LIBRARIES kritaimage Qt5::Test) ecm_add_test(kis_layer_style_filter_environment_test.cpp TEST_NAME kritaimage-layer_style_filter_environment_test LINK_LIBRARIES ${KDE4_KDEUI_LIBS} kritaimage Qt5::Test) ecm_add_test(kis_asl_parser_test.cpp TEST_NAME kritalibpsd-asl_parser_test LINK_LIBRARIES kritapsd kritapigment kritawidgetutils kritacommand Qt5::Xml Qt5::Test) ecm_add_test(KisPerStrokeRandomSourceTest.cpp TEST_NAME KisPerStrokeRandomSourceTest LINK_LIBRARIES kritaimage Qt5::Test) ecm_add_test(KisWatershedWorkerTest.cpp TEST_NAME KisWatershedWorkerTest LINK_LIBRARIES kritaimage Qt5::Test) # ecm_add_test(kis_dom_utils_test.cpp # TEST_NAME krita-image-DomUtils-Test # LINK_LIBRARIES kritaimage Qt5::Test) # kisdoc dep # kis_transform_worker_test.cpp # TEST_NAME krita-image-KisTransformWorkerTest #LINK_LIBRARIES kritaimage Qt5::Test) # kisdoc # kis_perspective_transform_worker_test.cpp # TEST_NAME krita-image-KisPerspectiveTransformWorkerTest #LINK_LIBRARIES kritaimage Qt5::Test) # kis_cs_conversion_test.cpp # TEST_NAME krita-image-KisCsConversionTest # LINK_LIBRARIES kritaimage Qt5::Test) # kisdoc # kis_processings_test.cpp # TEST_NAME krita-image-KisProcessingsTest #LINK_LIBRARIES kritaimage Qt5::Test) # image/tests cannot use stuff that needs kisdocument # kis_projection_leaf_test.cpp # TEST_NAME kritaimage-projection_leaf_test # LINK_LIBRARIES kritaimage Qt5::Test) if (NOT HAVE_FAILING_CMAKE) krita_add_broken_unit_test(kis_paint_device_test.cpp TEST_NAME krita-image-KisPaintDeviceTest LINK_LIBRARIES kritaimage kritaodf Qt5::Test) else() message(WARNING "Skipping KisPaintDeviceTest!!!!!!!!!!!!!!") endif() if (NOT HAVE_FAILING_CMAKE) krita_add_broken_unit_test(kis_filter_mask_test.cpp TEST_NAME krita-image-KisFilterMaskTest LINK_LIBRARIES kritaimage Qt5::Test) else() message(WARNING "Skipping KisFilterMaskTest!!!!!!!!!!!!!!") endif() krita_add_broken_unit_test(kis_transform_mask_test.cpp TEST_NAME krita-image-KisTransformMaskTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_histogram_test.cpp TEST_NAME krita-image-KisHistogramTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_walkers_test.cpp TEST_NAME krita-image-KisWalkersTest LINK_LIBRARIES kritaimage Qt5::Test) #krita_add_broken_unit_test(kis_async_merger_test.cpp # TEST_NAME krita-image-KisAsyncMergerTest # LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_update_scheduler_test.cpp TEST_NAME krita-image-KisUpdateSchedulerTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_queues_progress_updater_test.cpp TEST_NAME krita-image-KisQueuesProgressUpdaterTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_cage_transform_worker_test.cpp TEST_NAME krita-image-KisCageTransformWorkerTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_meta_data_test.cpp TEST_NAME krita-image-KisMetaDataTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_random_generator_test.cpp TEST_NAME krita-image-KisRandomGeneratorTest LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_keyframing_test.cpp TEST_NAME krita-image-Keyframing-Test LINK_LIBRARIES kritaimage Qt5::Test) krita_add_broken_unit_test(kis_image_animation_interface_test.cpp TEST_NAME krita-image-ImageAnimationInterface-Test LINK_LIBRARIES ${KDE4_KDEUI_LIBS} kritaimage Qt5::Test) krita_add_broken_unit_test(kis_onion_skin_compositor_test.cpp TEST_NAME krita-image-OnionSkinCompositor-Test LINK_LIBRARIES ${KDE4_KDEUI_LIBS} kritaimage Qt5::Test) krita_add_broken_unit_test(kis_layer_styles_test.cpp TEST_NAME krita-image-LayerStylesTest LINK_LIBRARIES kritaimage Qt5::Test) diff --git a/libs/image/tests/kis_macro_test.cpp b/libs/image/tests/kis_macro_test.cpp deleted file mode 100644 index b921304a09..0000000000 --- a/libs/image/tests/kis_macro_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_macro_test.h" - -#include -#include "recorder/kis_macro.h" -#include -#include -#include "kis_image.h" - -#include "recorder/kis_recorded_action.h" -#include - -class TestAction : public KisRecordedAction -{ -public: - - TestAction(const QString & id, const QString & name) - : KisRecordedAction(id, name) { - } - - void play(const KisPlayInfo&, KoUpdater*) const override { - } - - KisRecordedAction* clone() const override { - return new TestAction(id(), name()); - } - -}; - - -void KisMacroTest::testCreation() -{ - QList actions; - TestAction tc("bla", "bla"); - actions << &tc; - - const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); - KisImageSP image = new KisImage(0, 512, 512, cs, "test"); - - KisMacro a; - KisMacro b(actions); -} - - -QTEST_MAIN(KisMacroTest) diff --git a/libs/image/tests/kis_macro_test.h b/libs/image/tests/kis_macro_test.h deleted file mode 100644 index 8c8099195d..0000000000 --- a/libs/image/tests/kis_macro_test.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef KIS_MACRO_TEST_H -#define KIS_MACRO_TEST_H - -#include - -class KisMacroTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - - void testCreation(); - -}; - -#endif diff --git a/libs/image/tests/kis_node_query_path_test.cpp b/libs/image/tests/kis_node_query_path_test.cpp index 6a77305b28..a694526048 100644 --- a/libs/image/tests/kis_node_query_path_test.cpp +++ b/libs/image/tests/kis_node_query_path_test.cpp @@ -1,100 +1,100 @@ /* * Copyright (c) 2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_node_query_path_test.h" #include -#include "recorder/kis_node_query_path.h" +#include "kis_node_query_path.h" #include #include #include #include #include KisNodeQueryPathTest::KisNodeQueryPathTest() { image = new KisImage(0, 100, 100, KoColorSpaceRegistry::instance()->rgb8(), ""); current = new KisGroupLayer(image, "", OPACITY_OPAQUE_U8); child1 = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8); child2 = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8); image->addNode(child1, current); image->addNode(child2, current); parent = new KisGroupLayer(image, "", OPACITY_OPAQUE_U8); brother1 = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8); brother2 = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8); image->addNode(brother1, parent); image->addNode(current, parent); image->addNode(brother2, parent); image->addNode(parent, image->rootLayer()); } #define TESTS(name, relativeStr, absoluteStr1, absoluteStr2, node) \ void KisNodeQueryPathTest::test##name##LayerFromRelativeString() \ { \ KisNodeQueryPath path = KisNodeQueryPath::fromString(relativeStr); \ QCOMPARE(path.toString(), QString(relativeStr)); \ QList nodes = path.queryNodes(image, current); \ QCOMPARE(nodes.size(), 1); \ QCOMPARE(nodes[0], node); \ } \ \ void KisNodeQueryPathTest::test##name##LayerFromAbsoluteString() \ { \ { \ KisNodeQueryPath path = KisNodeQueryPath::fromString(absoluteStr1); \ QCOMPARE(path.toString(), QString(absoluteStr1)); \ QList nodes = path.queryNodes(image, current); \ QCOMPARE(nodes.size(), 1); \ QCOMPARE(nodes[0], node); \ } \ { \ KisNodeQueryPath path = KisNodeQueryPath::fromString(absoluteStr2); \ QCOMPARE(path.toString(), QString(absoluteStr2)); \ QList nodes = path.queryNodes(image, current); \ QCOMPARE(nodes.size(), 1); \ QCOMPARE(nodes[0], node); \ } \ } \ \ void KisNodeQueryPathTest::test##name##LayerFromAbsolutePath() \ { \ KisNodeQueryPath path = KisNodeQueryPath::absolutePath(node); \ QCOMPARE(path.toString(), QString(absoluteStr1)); \ QList nodes = path.queryNodes(image, current); \ QCOMPARE(nodes.size(), 1); \ QCOMPARE(nodes[0], node); \ } TESTS(Current, ".", "/0/1", "/*/1", current) TESTS(Child1, "0", "/0/1/0", "/*/1/0", child1) TESTS(Child2, "1", "/0/1/1", "/*/1/1", child2) TESTS(Brother1, "../0", "/0/0", "/*/0", brother1) TESTS(Brother2, "../2", "/0/2", "/*/2", brother2) TESTS(Parent, "..", "/0", "/*", parent) TESTS(Root, "../..", "/", "/", KisNodeSP(image->rootLayer())) void KisNodeQueryPathTest::testPathCompression() { KisNodeQueryPath path = KisNodeQueryPath::fromString("1/../3/../5"); QCOMPARE(path.toString(), QString("5")); KisNodeQueryPath path2 = KisNodeQueryPath::fromString("/*/.."); QCOMPARE(path2.toString(), QString("/")); } QTEST_MAIN(KisNodeQueryPathTest) diff --git a/libs/image/tests/kis_recorded_action_factory_registry_test.cpp b/libs/image/tests/kis_recorded_action_factory_registry_test.cpp deleted file mode 100644 index b6192ef6e2..0000000000 --- a/libs/image/tests/kis_recorded_action_factory_registry_test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_factory_registry_test.h" - -#include -#include "recorder/kis_recorded_action_factory_registry.h" - -void KisRecordedActionFactoryRegistryTest::testCreation() -{ - KisRecordedActionFactoryRegistry test; -} - - -QTEST_MAIN(KisRecordedActionFactoryRegistryTest) diff --git a/libs/image/tests/kis_recorded_action_factory_registry_test.h b/libs/image/tests/kis_recorded_action_factory_registry_test.h deleted file mode 100644 index 1f76a93212..0000000000 --- a/libs/image/tests/kis_recorded_action_factory_registry_test.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef KIS_RECORDED_ACTION_FACTORY_REGISTRY_TEST_H -#define KIS_RECORDED_ACTION_FACTORY_REGISTRY_TEST_H - -#include - -class KisRecordedActionFactoryRegistryTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - - void testCreation(); - -}; - -#endif diff --git a/libs/image/tests/kis_recorded_action_test.cpp b/libs/image/tests/kis_recorded_action_test.cpp deleted file mode 100644 index 5481427f56..0000000000 --- a/libs/image/tests/kis_recorded_action_test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_test.h" - -#include -#include -#include "recorder/kis_recorded_action.h" -#include - -class TestAction : public KisRecordedAction -{ -public: - - TestAction(const QString & id, const QString & name) - : KisRecordedAction(id, name) { - } - - void play(const KisPlayInfo&, KoUpdater*) const override { - } - - KisRecordedAction* clone() const override { - return new TestAction(id(), name()); - } - -}; - - -void KisRecordedActionTest::testCreation() -{ - TestAction tc("bla", "bla"); -} - - -QTEST_MAIN(KisRecordedActionTest) diff --git a/libs/image/tests/kis_recorded_action_test.h b/libs/image/tests/kis_recorded_action_test.h deleted file mode 100644 index cc20fa40f4..0000000000 --- a/libs/image/tests/kis_recorded_action_test.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef KIS_RECORDED_ACTION_TEST_H -#define KIS_RECORDED_ACTION_TEST_H - -#include - -class KisRecordedActionTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - - void testCreation(); - -}; - -#endif diff --git a/libs/image/tests/kis_recorded_filter_action_test.cpp b/libs/image/tests/kis_recorded_filter_action_test.cpp deleted file mode 100644 index 94677fcb8b..0000000000 --- a/libs/image/tests/kis_recorded_filter_action_test.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_filter_action_test.h" - -#include -#include "recorder/kis_recorded_filter_action.h" -#include -#include -#include "kis_paint_layer.h" -#include "filter/kis_filter.h" -#include "filter/kis_filter_configuration.h" -#include "filter/kis_filter_registry.h" -#include "kis_image.h" -#include "kis_paint_device.h" -#include - -void KisRecordedFilterActionTest::testCreation() -{ - const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); - KisFilterSP f = KisFilterRegistry::instance()->value("invert"); - KisFilterConfigurationSP kfc = f->defaultConfiguration(); - KisImageSP image = new KisImage(0, 10, 10, cs, "merge test"); - KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); - - KisRecordedFilterAction test("invert", KisNodeQueryPath::absolutePath(layer), f, kfc); -} - - -QTEST_MAIN(KisRecordedFilterActionTest) diff --git a/libs/image/tests/kis_recorded_filter_action_test.h b/libs/image/tests/kis_recorded_filter_action_test.h deleted file mode 100644 index f517964e67..0000000000 --- a/libs/image/tests/kis_recorded_filter_action_test.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef KIS_RECORDED_FILTER_ACTION_TEST_H -#define KIS_RECORDED_FILTER_ACTION_TEST_H - -#include - -class KisRecordedFilterActionTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - - void testCreation(); - -}; - -#endif diff --git a/libs/image/tests/kis_vec_test.cpp b/libs/image/tests/kis_vec_test.cpp index 8dfc4b3d74..588059c3d0 100644 --- a/libs/image/tests/kis_vec_test.cpp +++ b/libs/image/tests/kis_vec_test.cpp @@ -1,47 +1,32 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_vec_test.h" #include #include "kis_vec.h" void KisVecTest::testCreation() { KisVector2D v2d = KisVector2D::Zero(); QVERIFY(v2d.x() == 0.0); QVERIFY(v2d.y() == 0.0); - - KisVector3D v3d = KisVector3D::Zero(); - QVERIFY(v3d.x() == 0.0); - QVERIFY(v3d.y() == 0.0); - QVERIFY(v3d.z() == 0.0); -} - - -void KisVecTest::testVec2D() -{ -} - - -void KisVecTest::testVec3D() -{ } QTEST_MAIN(KisVecTest) diff --git a/libs/image/tests/kis_vec_test.h b/libs/image/tests/kis_vec_test.h index 714e14582b..19f0388122 100644 --- a/libs/image/tests/kis_vec_test.h +++ b/libs/image/tests/kis_vec_test.h @@ -1,35 +1,33 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_VEC_TEST_H #define KIS_VEC_TEST_H #include class KisVecTest : public QObject { Q_OBJECT private Q_SLOTS: void testCreation(); - void testVec2D(); - void testVec3D(); }; #endif diff --git a/libs/koplugin/KisMimeDatabase.cpp b/libs/koplugin/KisMimeDatabase.cpp index 6fcf7f874f..10fb99289c 100644 --- a/libs/koplugin/KisMimeDatabase.cpp +++ b/libs/koplugin/KisMimeDatabase.cpp @@ -1,292 +1,287 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisMimeDatabase.h" #include #include #include #include #include QList KisMimeDatabase::s_mimeDatabase; QString KisMimeDatabase::mimeTypeForFile(const QString &file, bool checkExistingFiles) { fillMimeData(); QFileInfo fi(file); QString suffix = fi.suffix().toLower(); Q_FOREACH(const KisMimeDatabase::KisMimeType &mimeType, s_mimeDatabase) { if (mimeType.suffixes.contains(suffix)) { debugPlugin << "mimeTypeForFile(). KisMimeDatabase returned" << mimeType.mimeType << "for" << file; return mimeType.mimeType; } } QMimeDatabase db; QMimeType mime; if (checkExistingFiles && fi.size() > 0) { mime = db.mimeTypeForFile(file, QMimeDatabase::MatchContent); if (mime.name() != "application/octet-stream" && mime.name() != "application/zip") { debugPlugin << "mimeTypeForFile(). QMimeDatabase returned" << mime.name() << "for" << file; return mime.name(); } } mime = db.mimeTypeForFile(file); if (mime.name() != "application/octet-stream") { debugPlugin << "mimeTypeForFile(). QMimeDatabase returned" << mime.name() << "for" << file; return mime.name(); } return ""; } QString KisMimeDatabase::mimeTypeForSuffix(const QString &suffix) { fillMimeData(); QMimeDatabase db; QString s = suffix.toLower(); Q_FOREACH(const KisMimeDatabase::KisMimeType &mimeType, s_mimeDatabase) { if (mimeType.suffixes.contains(s)) { debugPlugin << "mimeTypeForSuffix(). KisMimeDatabase returned" << mimeType.mimeType << "for" << s; return mimeType.mimeType; } } // make the file look like a file so Qt would recognize it s = "file." + s; return mimeTypeForFile(s); } QString KisMimeDatabase::mimeTypeForData(const QByteArray ba) { QMimeDatabase db; QMimeType mtp = db.mimeTypeForData(ba); debugPlugin << "mimeTypeForData(). QMimeDatabase returned" << mtp.name(); return mtp.name(); } QString KisMimeDatabase::descriptionForMimeType(const QString &mimeType) { fillMimeData(); Q_FOREACH(const KisMimeDatabase::KisMimeType &m, s_mimeDatabase) { if (m.mimeType == mimeType) { debugPlugin << "descriptionForMimeType. KisMimeDatabase returned" << m.description << "for" << mimeType; return m.description; } } QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeType); if (mime.name() != "application/octet-stream") { debugPlugin << "descriptionForMimeType. QMimeDatabase returned" << mime.comment() << "for" << mimeType; return mime.comment(); } return mimeType; } QStringList KisMimeDatabase::suffixesForMimeType(const QString &mimeType) { fillMimeData(); Q_FOREACH(const KisMimeDatabase::KisMimeType &m, s_mimeDatabase) { if (m.mimeType == mimeType) { debugPlugin << "suffixesForMimeType. KisMimeDatabase returned" << m.suffixes; return m.suffixes; } } QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeType); if (mime.name() != "application/octet-stream" && !mime.suffixes().isEmpty()) { QString preferredSuffix = mime.preferredSuffix(); if (mimeType == "image/x-tga") { preferredSuffix = "tga"; } if (mimeType == "image/jpeg") { preferredSuffix = "jpg"; } QStringList suffixes = mime.suffixes(); if (preferredSuffix != suffixes.first()) { suffixes.removeAll(preferredSuffix); suffixes.prepend(preferredSuffix); } debugPlugin << "suffixesForMimeType. QMimeDatabase returned" << suffixes; return suffixes; } return QStringList(); } QString KisMimeDatabase::iconNameForMimeType(const QString &mimeType) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeType); debugPlugin << "iconNameForMimeType" << mime.iconName(); return mime.iconName(); } void KisMimeDatabase::fillMimeData() { // This should come from the import/export plugins, but the json files aren't translated, // which is bad for the description field if (s_mimeDatabase.isEmpty()) { KisMimeType mimeType; mimeType.mimeType = "image/x-gimp-brush"; mimeType.description = i18nc("description of a file type", "Gimp Brush"); mimeType.suffixes = QStringList() << "gbr" << "vbr"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-gimp-brush-animated"; mimeType.description = i18nc("description of a file type", "Gimp Image Hose Brush"); mimeType.suffixes = QStringList() << "gih"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-adobe-brushlibrary"; mimeType.description = i18nc("description of a file type", "Adobe Brush Library"); mimeType.suffixes = QStringList() << "abr"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-paintoppreset"; mimeType.description = i18nc("description of a file type", "Krita Brush Preset"); mimeType.suffixes = QStringList() << "kpp"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-assistant"; mimeType.description = i18nc("description of a file type", "Krita Assistant"); mimeType.suffixes = QStringList() << "paintingassistant"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-r32"; mimeType.description = i18nc("description of a file type", "R32 Heightmap"); mimeType.suffixes = QStringList() << "r32"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-r16"; mimeType.description = i18nc("description of a file type", "R16 Heightmap"); mimeType.suffixes = QStringList() << "r16"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-r8"; mimeType.description = i18nc("description of a file type", "R8 Heightmap"); mimeType.suffixes = QStringList() << "r8"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-spriter"; mimeType.description = i18nc("description of a file type", "Spriter SCML"); mimeType.suffixes = QStringList() << "scml"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-svm"; mimeType.description = i18nc("description of a file type", "Starview Metafile"); mimeType.suffixes = QStringList() << "svm"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/openraster"; mimeType.description = i18nc("description of a file type", "OpenRaster Image"); mimeType.suffixes = QStringList() << "ora"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-photoshop-style-library"; mimeType.description = i18nc("description of a file type", "Photoshop Layer Style Library"); mimeType.suffixes = QStringList() << "asl"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-gimp-color-palette"; mimeType.description = i18nc("description of a file type", "Color Palette"); mimeType.suffixes = QStringList() << "gpl" << "pal" << "act" << "aco" << "colors" << "xml" << "sbz"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-opencolorio-configuration"; mimeType.description = i18nc("description of a file type", "OpenColorIO Configuration"); mimeType.suffixes = QStringList() << "ocio"; s_mimeDatabase << mimeType; - mimeType.mimeType = "application/x-krita-recorded-macro"; - mimeType.description = i18nc("description of a file type", "Krita Recorded Action"); - mimeType.suffixes = QStringList() << "krarec"; - s_mimeDatabase << mimeType; - mimeType.mimeType = "application/x-gimp-gradient"; mimeType.description = i18nc("description of a file type", "GIMP Gradients"); mimeType.suffixes = QStringList() << "ggr"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-gimp-pattern"; mimeType.description = i18nc("description of a file type", "GIMP Patterns"); mimeType.suffixes = QStringList() << "pat"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-karbon-gradient"; mimeType.description = i18nc("description of a file type", "Karbon Gradients"); mimeType.suffixes = QStringList() << "kgr"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-bundle"; mimeType.description = i18nc("description of a file type", "Krita Resource Bundle"); mimeType.suffixes = QStringList() << "bundle"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-workspace"; mimeType.description = i18nc("description of a file type", "Krita Workspace"); mimeType.suffixes = QStringList() << "kws"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-taskset"; mimeType.description = i18nc("description of a file type", "Krita Taskset"); mimeType.suffixes = QStringList() << "kts"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-krita-reference-images"; mimeType.description = i18nc("description of a file type", "Krita Reference Image Collection"); mimeType.suffixes = QStringList() << "krf"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-krita-raw"; mimeType.description = i18nc("description of a file type", "Camera Raw Files"); mimeType.suffixes = QStringList() << "bay" << "bmq" << "cr2" << "crw" << "cs1" << "dc2" << "dcr" << "dng" << "erf" << "fff" << "hdr" << "k25" << "kdc" << "mdc" << "mos" << "mrw" << "nef" << "orf" << "pef" << "pxn" << "raf" << "raw" << "rdc" << "sr2" << "srf" << "x3f" << "arw" << "3fr" << "cine" << "ia" << "kc2" << "mef" << "nrw" << "qtk" << "rw2" << "sti" << "rwl" << "srw"; s_mimeDatabase << mimeType; mimeType.mimeType = "application/x-extension-exr"; mimeType.description = i18nc("description of a file type", "OpenEXR (Extended)"); mimeType.suffixes = QStringList() << "exr"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/x-psb"; mimeType.description = i18nc("description of a file type", "Photoshop Image (Large)"); mimeType.suffixes = QStringList() << "psb"; s_mimeDatabase << mimeType; mimeType.mimeType = "image/heic"; mimeType.description = i18nc("description of a file type", "HEIC/HEIF Image"); mimeType.suffixes = QStringList() << "heic" << "heif"; s_mimeDatabase << mimeType; debugPlugin << "Filled mimedatabase with" << s_mimeDatabase.count() << "special mimetypes"; } } diff --git a/libs/pigment/KoColorSpaceRegistry.h b/libs/pigment/KoColorSpaceRegistry.h index 89abd8c935..8db1fe2054 100644 --- a/libs/pigment/KoColorSpaceRegistry.h +++ b/libs/pigment/KoColorSpaceRegistry.h @@ -1,361 +1,360 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004,2010 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACEREGISTRY_H #define KOCOLORSPACEREGISTRY_H #include #include #include #include "kritapigment_export.h" #include #include #include class KoColorProfile; class KoColorConversionSystem; class KoColorConversionCache; class KoColorConversionTransformation; /** * The registry for colorspaces and profiles. * This class contains: * - a registry of colorspace instantiated with specific profiles. * - a registry of singleton colorspace factories. * - a registry of icc profiles * * Locking policy details: * * Basically, we have two levels of locks in the registry: * 1) (outer level) is Private::registrylock, which controls the structures * of the color space registry itself * 2) (inner level) is KoColorProfileStorage::Private::lock controls * the structures related to profiles. * * The locks can be taken individually, but if you are going to take both * of them, you should always follow the order 1) registry; 2) profiles. * Otherwise you'll get a deadlock. * * To avoid recursive deadlocks, all the dependent classes * (KoColorConversionSystem and KoColorSpaceFactory) now do not use the direct * links to the registry. Instead, they use special private interfaces that * skip recursive locking and ensure we take a lock twice. */ class KRITAPIGMENT_EXPORT KoColorSpaceRegistry { public: KoColorSpaceRegistry(); enum ColorSpaceListVisibility { OnlyUserVisible = 1, ///< Only user visible color space AllColorSpaces = 4 ///< All color space even those not visible to the user }; enum ColorSpaceListProfilesSelection { OnlyDefaultProfile = 1, ///< Only add the default profile AllProfiles = 4 ///< Add all profiles }; /** * Return an instance of the KoColorSpaceRegistry * Creates an instance if that has never happened before and returns the singleton instance. */ static KoColorSpaceRegistry * instance(); virtual ~KoColorSpaceRegistry(); public: /** * add a color space to the registry * @param item the color space factory to add */ void add(KoColorSpaceFactory* item); /** * Remove a color space factory from the registry. Note that it is the * responsibility of the caller to ensure that the colorspaces are not * used anymore. */ void remove(KoColorSpaceFactory* item); /** * Add a profile to the profile map but do not add it to the * color conversion system yet. * @param profile the new profile to be registered. */ void addProfileToMap(KoColorProfile *p); /** * register the profile with the color space registry * @param profile the new profile to be registered so it can be combined with * colorspaces. */ void addProfile(KoColorProfile* profile); void addProfile(const KoColorProfile* profile); // TODO why ? void removeProfile(KoColorProfile* profile); /** * Create an alias to a profile with a different name. Then @ref profileByName * will return the profile @p to when passed @p name as a parameter. */ void addProfileAlias(const QString& name, const QString& to); /** * @return the profile alias, or name if not aliased */ QString profileAlias(const QString& name) const; /** * create a profile of the specified type. */ const KoColorProfile *createColorProfile(const QString & colorModelId, const QString & colorDepthId, const QByteArray& rawData); /** * Return a profile by its given name, or 0 if none registered. * @return a profile by its given name, or 0 if none registered. * @param name the product name as set on the profile. * @see addProfile() * @see KoColorProfile::productName() */ const KoColorProfile * profileByName(const QString & name) const ; /** * Returns a profile by its unique id stored/calculated in the header. * The first call to this function might take long, because the map is * created on the first use only (atm used by SVG only) * @param id unique ProfileID of the profile (MD5 sum of its header) * @return the profile or 0 if not found */ const KoColorProfile *profileByUniqueId(const QByteArray &id) const; bool profileIsCompatible(const KoColorProfile* profile, const QString &colorSpaceId); /** * Return the list of profiles for a colorspace with the argument id. * Profiles will not work with any color space, you can query which profiles * that are registered with this registry can be used in combination with the * argument factory. * @param colorSpaceId the colorspace-id with which all the returned profiles will work. * @return a list of profiles for the factory */ QList profilesFor(const QString& csID) const; QString defaultProfileForColorSpace(const QString &colorSpaceId) const; /** * This function is called by the color space to create a color conversion * between two color space. This function search in the graph of transformations * the best possible path between the two color space. */ KoColorConversionTransformation* createColorConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * This function creates two transformations, one from the color space and one to the * color space. The destination color space is picked from a list of color space, such * as the conversion between the two color space is of the best quality. * * The typical use case of this function is for KoColorTransformationFactory which * doesn't support all color spaces, so unsupported color space have to find an * acceptable conversion in order to use that KoColorTransformationFactory. * * @param colorSpace the source color space * @param possibilities a list of color space among which we need to find the best * conversion * @param fromCS the conversion from the source color space will be affected to this * variable * @param toCS the revert conversion to the source color space will be affected to this * variable */ void createColorConverters(const KoColorSpace* colorSpace, const QList< QPair >& possibilities, KoColorConversionTransformation*& fromCS, KoColorConversionTransformation*& toCS) const; /** * Return a colorspace that works with the parameter profile. * @param colorSpaceId the ID string of the colorspace that you want to have returned * @param profile the profile be combined with the colorspace * @return the wanted colorspace, or 0 when the cs and profile can not be combined. */ const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId, const KoColorProfile *profile); /** * Return a colorspace that works with the parameter profile. * @param profileName the name of the KoColorProfile to be combined with the colorspace * @return the wanted colorspace, or 0 when the cs and profile can not be combined. */ const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId, const QString &profileName); const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId); /** * Return the id of the colorspace that have the defined colorModelId with colorDepthId. * @param colorModelId id of the color model * @param colorDepthId id of the color depth * @return the id of the wanted colorspace, or "" if no colorspace correspond to those ids */ QString colorSpaceId(const QString & colorModelId, const QString & colorDepthId) const; /** * It's a convenient function that behave like the above. * Return the id of the colorspace that have the defined colorModelId with colorDepthId. * @param colorModelId id of the color model * @param colorDepthId id of the color depth * @return the id of the wanted colorspace, or "" if no colorspace correspond to those ids */ QString colorSpaceId(const KoID& colorModelId, const KoID& colorDepthId) const; /** * @return a the identifiant of the color model for the given color space id. * * This function is a compatibility function used to get the color space from * all kra files. */ KoID colorSpaceColorModelId(const QString & _colorSpaceId) const; /** * @return a the identifiant of the color depth for the given color space id. * * This function is a compatibility function used to get the color space from * all kra files. */ KoID colorSpaceColorDepthId(const QString & _colorSpaceId) const; /** * Convenience methods to get the often used alpha colorspaces */ const KoColorSpace *alpha8(); const KoColorSpace *alpha16(); #include #ifdef HAVE_OPENEXR const KoColorSpace *alpha16f(); #endif const KoColorSpace *alpha32f(); /** * Convenience method to get an RGBA 8bit colorspace. If a profile is not specified, * an sRGB profile will be used. * @param profileName the name of an RGB color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb8(const QString &profileName = QString()); /** * Convenience method to get an RGBA 8bit colorspace with the given profile. * @param profile an RGB profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb8(const KoColorProfile * profile); /** * Convenience method to get an RGBA 16bit colorspace. If a profile is not specified, * an sRGB profile will be used. * @param profileName the name of an RGB color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb16(const QString &profileName = QString()); /** * Convenience method to get an RGBA 16bit colorspace with the given profile. * @param profile an RGB profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * rgb16(const KoColorProfile * profile); /** * Convenience method to get an Lab 16bit colorspace. If a profile is not specified, * an Lab profile with a D50 whitepoint will be used. * @param profileName the name of an Lab color profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * lab16(const QString &profileName = QString()); /** * Convenience method to get an Lab 16bit colorspace with the given profile. * @param profile an Lab profile * @return the wanted colorspace, or 0 if the color space and profile can not be combined. */ const KoColorSpace * lab16(const KoColorProfile * profile); /** * @return the list of available color models */ QList colorModelsList(ColorSpaceListVisibility option) const; /** * @return the list of available color models for the given colorModelId */ QList colorDepthList(const KoID& colorModelId, ColorSpaceListVisibility option) const; /** * @return the list of available color models for the given colorModelId */ QList colorDepthList(const QString & colorModelId, ColorSpaceListVisibility option) const; /** * @return the cache of color conversion transformation to be use by KoColorSpace */ KoColorConversionCache* colorConversionCache() const; /** * @return a permanent colorspace owned by the registry, of the same type and profile * as the one given in argument */ const KoColorSpace* permanentColorspace(const KoColorSpace* _colorSpace); /** * This function return a list of all the keys in KoID format by using the name() method * on the objects stored in the registry. */ QList listKeys() const; private: friend class KisCsConversionTest; friend class KisIteratorTest; friend class KisPainterTest; friend class KisCrashFilterTest; friend class KoColorSpacesBenchmark; friend class TestKoColorSpaceSanity; - friend class KisActionRecorderTest; friend class TestColorConversionSystem; friend class FriendOfColorSpaceRegistry; /** * @return a list with an instance of all color space with their default profile. */ QList allColorSpaces(ColorSpaceListVisibility visibility, ColorSpaceListProfilesSelection pSelection); /** * @return the color conversion system use by the registry and the color * spaces to create color conversion transformation. * * WARNING: conversion system is guared by the registry locks, don't * use it anywhere other than unttests! */ const KoColorConversionSystem* colorConversionSystem() const; private: KoColorSpaceRegistry(const KoColorSpaceRegistry&); KoColorSpaceRegistry operator=(const KoColorSpaceRegistry&); void init(); private: struct Private; Private * const d; }; #endif // KOCOLORSPACEREGISTRY_H diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 38b6e288e8..fe7af22802 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,599 +1,588 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ${EXIV2_INCLUDE_DIR} ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) find_library(APPKIT_LIBRARY AppKit) endif () set(kritaui_LIB_SRCS canvas/kis_canvas_widget_base.cpp canvas/kis_canvas2.cpp canvas/kis_canvas_updates_compressor.cpp canvas/kis_canvas_controller.cpp canvas/kis_paintop_transformation_connector.cpp canvas/kis_display_color_converter.cpp canvas/kis_display_filter.cpp canvas/kis_exposure_gamma_correction_interface.cpp canvas/kis_tool_proxy.cpp canvas/kis_canvas_decoration.cc canvas/kis_coordinates_converter.cpp canvas/kis_grid_manager.cpp canvas/kis_grid_decoration.cpp canvas/kis_grid_config.cpp canvas/kis_prescaled_projection.cpp canvas/kis_qpainter_canvas.cpp canvas/kis_projection_backend.cpp canvas/kis_update_info.cpp canvas/kis_image_patch.cpp canvas/kis_image_pyramid.cpp canvas/kis_infinity_manager.cpp canvas/kis_change_guides_command.cpp canvas/kis_guides_decoration.cpp canvas/kis_guides_manager.cpp canvas/kis_guides_config.cpp canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp canvas/KisSnapPointStrategy.cpp dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_generator_layer.cpp dialogs/kis_dlg_file_layer.cpp dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_stroke_selection_properties.cpp dialogs/kis_dlg_image_properties.cc dialogs/kis_dlg_layer_properties.cc dialogs/kis_dlg_preferences.cc dialogs/slider_and_spin_box_sync.cpp dialogs/kis_dlg_blacklist_cleanup.cpp dialogs/kis_dlg_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp dialogs/kis_dlg_internal_color_selector.cpp dialogs/KisSessionManagerDialog.cpp dialogs/KisNewWindowLayoutDialog.cpp flake/kis_node_dummies_graph.cpp flake/kis_dummies_facade_base.cpp flake/kis_dummies_facade.cpp flake/kis_node_shapes_graph.cpp flake/kis_node_shape.cpp flake/kis_shape_controller.cpp flake/kis_shape_layer.cc flake/kis_shape_layer_canvas.cpp flake/kis_shape_selection.cpp flake/kis_shape_selection_canvas.cpp flake/kis_shape_selection_model.cpp flake/kis_take_all_shapes_command.cpp brushhud/kis_uniform_paintop_property_widget.cpp brushhud/kis_brush_hud.cpp brushhud/kis_round_hud_button.cpp brushhud/kis_dlg_brush_hud_config.cpp brushhud/kis_brush_hud_properties_list.cpp brushhud/kis_brush_hud_properties_config.cpp kis_aspect_ratio_locker.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc KisPaintopPropertiesBase.cpp kis_canvas_resource_provider.cpp kis_derived_resources.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc kis_config_notifier.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_cursor.cc kis_cursor_cache.cpp kis_custom_pattern.cc kis_file_layer.cpp kis_change_file_layer_command.h kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc kis_histogram_view.cc KisImageBarrierLockerWithFeedback.cpp kis_image_manager.cc kis_image_view_converter.cpp kis_import_catcher.cc kis_layer_manager.cc kis_mask_manager.cc kis_mimedata.cpp kis_node_commands_adapter.cpp kis_node_manager.cpp kis_node_juggler_compressed.cpp kis_node_selection_adapter.cpp kis_node_insertion_adapter.cpp kis_node_model.cpp kis_node_filter_proxy_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_painting_assistant.cc kis_painting_assistants_decoration.cpp KisDecorationsManager.cpp kis_paintop_box.cc kis_paintop_option.cpp kis_paintop_options_model.cpp kis_paintop_settings_widget.cpp kis_popup_palette.cpp kis_png_converter.cpp kis_preference_set_registry.cpp KisResourceServerProvider.cpp KisResourceBundleServerProvider.cpp KisSelectedShapesProxy.cpp kis_selection_decoration.cc kis_selection_manager.cc kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp KisActionPlugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_stopgradient_editor.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp opengl/kis_opengl.cpp opengl/kis_opengl_canvas2.cpp opengl/kis_opengl_canvas_debugger.cpp opengl/kis_opengl_image_textures.cpp opengl/kis_texture_tile.cpp opengl/kis_opengl_shader_loader.cpp opengl/kis_texture_tile_info_pool.cpp opengl/KisOpenGLUpdateInfoBuilder.cpp kis_fps_decoration.cpp - recorder/kis_node_query_path_editor.cc - recorder/kis_recorded_action_creator.cc - recorder/kis_recorded_action_creator_factory.cc - recorder/kis_recorded_action_creator_factory_registry.cc - recorder/kis_recorded_action_editor_factory.cc - recorder/kis_recorded_action_editor_factory_registry.cc - recorder/kis_recorded_filter_action_editor.cc - recorder/kis_recorded_filter_action_creator.cpp - recorder/kis_recorded_paint_action_editor.cc tool/kis_selection_tool_helper.cpp tool/kis_selection_tool_config_widget_helper.cpp tool/kis_rectangle_constraint_widget.cpp tool/kis_shape_tool_helper.cpp tool/kis_tool.cc tool/kis_delegated_tool_policies.cpp tool/kis_tool_freehand.cc tool/kis_speed_smoother.cpp tool/kis_painting_information_builder.cpp tool/kis_stabilized_events_sampler.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp - tool/kis_recording_adapter.cpp tool/kis_tool_paint.cc tool/kis_tool_shape.cc tool/kis_tool_ellipse_base.cpp tool/kis_tool_rectangle_base.cpp tool/kis_tool_polyline_base.cpp tool/kis_tool_utils.cpp tool/kis_resources_snapshot.cpp tool/kis_smoothing_options.cpp tool/KisStabilizerDelayedPaintHelper.cpp tool/KisStrokeSpeedMonitor.cpp tool/strokes/freehand_stroke.cpp tool/strokes/KisStrokeEfficiencyMeasurer.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp tool/strokes/KisFreehandStrokeInfo.cpp tool/strokes/KisMaskedFreehandStrokePainter.cpp tool/strokes/KisMaskingBrushRenderer.cpp tool/strokes/KisMaskingBrushCompositeOpFactory.cpp widgets/kis_cmb_composite.cc widgets/kis_cmb_contour.cpp widgets/kis_cmb_gradient.cpp widgets/kis_paintop_list_widget.cpp widgets/kis_cmb_idlist.cc widgets/kis_color_space_selector.cc widgets/kis_advanced_color_space_selector.cc widgets/kis_cie_tongue_widget.cpp widgets/kis_tone_curve_widget.cpp widgets/kis_curve_widget.cpp widgets/kis_custom_image_widget.cc widgets/kis_image_from_clipboard_widget.cpp widgets/kis_double_widget.cc widgets/kis_filter_selector_widget.cc widgets/kis_gradient_chooser.cc widgets/kis_iconwidget.cc widgets/kis_mask_widgets.cpp widgets/kis_meta_data_merge_strategy_chooser_widget.cc widgets/kis_multi_bool_filter_widget.cc widgets/kis_multi_double_filter_widget.cc widgets/kis_multi_integer_filter_widget.cc widgets/kis_multipliers_double_slider_spinbox.cpp widgets/kis_paintop_presets_popup.cpp widgets/kis_tool_options_popup.cpp widgets/kis_paintop_presets_chooser_popup.cpp widgets/kis_paintop_presets_save.cpp widgets/kis_paintop_preset_icon_library.cpp widgets/kis_pattern_chooser.cc widgets/kis_popup_button.cc widgets/kis_preset_chooser.cpp widgets/kis_progress_widget.cpp widgets/kis_selection_options.cc widgets/kis_scratch_pad.cpp widgets/kis_scratch_pad_event_filter.cpp widgets/kis_preset_selector_strip.cpp widgets/kis_slider_spin_box.cpp widgets/KisSelectionPropertySlider.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.cpp widgets/kis_categorized_list_view.cpp widgets/kis_widget_chooser.cpp widgets/kis_tool_button.cpp widgets/kis_floating_message.cpp widgets/kis_lod_availability_widget.cpp widgets/kis_color_label_selector_widget.cpp widgets/kis_color_filter_combo.cpp widgets/kis_elided_label.cpp widgets/kis_stopgradient_slider_widget.cpp widgets/kis_spinbox_color_selector.cpp widgets/kis_screen_color_picker.cpp widgets/kis_preset_live_preview_view.cpp widgets/KoDualColorButton.cpp widgets/kis_color_input.cpp widgets/kis_color_button.cpp widgets/KisVisualColorSelector.cpp widgets/KisVisualColorSelectorShape.cpp widgets/KisVisualEllipticalSelectorShape.cpp widgets/KisVisualRectangleSelectorShape.cpp widgets/KisVisualTriangleSelectorShape.cpp widgets/KoStrokeConfigWidget.cpp widgets/KoFillConfigWidget.cpp utils/kis_document_aware_spin_box_unit_manager.cpp input/kis_input_manager.cpp input/kis_input_manager_p.cpp input/kis_extended_modifiers_mapper.cpp input/kis_abstract_input_action.cpp input/kis_tool_invocation_action.cpp input/kis_pan_action.cpp input/kis_alternate_invocation_action.cpp input/kis_rotate_canvas_action.cpp input/kis_zoom_action.cpp input/kis_change_frame_action.cpp input/kis_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_native_gesture_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp input/KisQtWidgetsTweaker.cpp input/KisInputActionGroup.cpp operations/kis_operation.cpp operations/kis_operation_configuration.cpp operations/kis_operation_registry.cpp operations/kis_operation_ui_factory.cpp operations/kis_operation_ui_widget.cpp operations/kis_filter_selection_operation.cpp actions/kis_selection_action_factories.cpp actions/KisPasteActionFactory.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.cpp kis_transaction_based_command.cpp kis_gui_context_command.cpp kis_gui_context_command_p.cpp input/kis_tablet_debugger.cpp input/kis_input_profile_manager.cpp input/kis_input_profile.cpp input/kis_shortcut_configuration.cpp input/config/kis_input_configuration_page.cpp input/config/kis_edit_profiles_dialog.cpp input/config/kis_input_profile_model.cpp input/config/kis_input_configuration_page_item.cpp input/config/kis_action_shortcuts_model.cpp input/config/kis_input_type_delegate.cpp input/config/kis_input_mode_delegate.cpp input/config/kis_input_button.cpp input/config/kis_input_editor_delegate.cpp input/config/kis_mouse_input_editor.cpp input/config/kis_wheel_input_editor.cpp input/config/kis_key_input_editor.cpp processing/fill_processing_visitor.cpp kis_asl_layer_style_serializer.cpp kis_psd_layer_style_resource.cpp canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisCloneDocumentStroke.cpp KisNodeDelegate.cpp kis_node_view_visibility_delegate.cpp KisNodeToolTip.cpp KisNodeView.cpp kis_node_view_color_scheme.cpp KisImportExportFilter.cpp KisFilterEntry.cpp KisImportExportManager.cpp KisImportExportUtils.cpp kis_async_action_feedback.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoActionsUpdateManager.cpp KisView.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisPaletteModel.cpp kis_palette_delegate.cpp kis_palette_view.cpp KisColorsetChooser.cpp KisSaveGroupVisitor.cpp KisWindowLayoutResource.cpp KisWindowLayoutManager.cpp KisSessionResource.cpp KisReferenceImagesDecoration.cpp KisReferenceImage.cpp flake/KisReferenceImagesLayer.cpp flake/KisReferenceImagesLayer.h ) if(WIN32) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp qtlockedfile/qtlockedfile_win.cpp input/wintab/kis_tablet_support_win8.cpp opengl/kis_opengl_win.cpp ) endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp KisAsyncAnimationRendererBase.cpp KisAsyncAnimationCacheRenderer.cpp KisAsyncAnimationFramesSavingRenderer.cpp dialogs/KisAsyncAnimationRenderDialogBase.cpp dialogs/KisAsyncAnimationCacheRenderDialog.cpp dialogs/KisAsyncAnimationFramesSaveDialog.cpp canvas/kis_animation_player.cpp kis_animation_importer.cpp KisSyncedAudioPlayback.cpp KisFrameDataSerializer.cpp KisFrameCacheStore.cpp KisFrameCacheSwapper.cpp KisAbstractFrameCacheSwapper.cpp KisInMemoryFrameCacheSwapper.cpp input/wintab/drawpile_tablettester/tablettester.cpp input/wintab/drawpile_tablettester/tablettest.cpp ) if(UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/kis_tablet_event.cpp input/wintab/kis_tablet_support.cpp qtlockedfile/qtlockedfile_unix.cpp ) if(NOT APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/qxcbconnection_xi2.cpp input/wintab/qxcbconnection.cpp input/wintab/kis_xi2_event_filter.cpp ) endif() endif() if(APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} osx.mm ) endif() ki18n_wrap_ui(kritaui_LIB_SRCS widgets/KoFillConfigWidget.ui widgets/KoStrokeConfigWidget.ui forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggenerators.ui forms/wdgbookmarkedconfigurationseditor.ui forms/wdgapplyprofile.ui forms/wdgcustompattern.ui forms/wdglayerproperties.ui forms/wdgcolorsettings.ui forms/wdgtabletsettings.ui forms/wdgcolorspaceselector.ui forms/wdgcolorspaceselectoradvanced.ui forms/wdgdisplaysettings.ui forms/kis_previewwidgetbase.ui forms/kis_matrix_widget.ui forms/wdgselectionoptions.ui forms/wdggeometryoptions.ui forms/wdgnewimage.ui forms/wdgimageproperties.ui forms/wdgmaskfromselection.ui forms/wdgmasksource.ui forms/wdgfilterdialog.ui forms/wdgmetadatamergestrategychooser.ui forms/wdgpaintoppresets.ui forms/wdgpaintopsettings.ui forms/wdgdlggeneratorlayer.ui forms/wdgdlgfilelayer.ui forms/wdgfilterselector.ui forms/wdgfilternodecreation.ui - forms/wdgpaintactioneditor.ui forms/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgsavebrushpreset.ui forms/wdgpreseticonlibrary.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui forms/wdgstopgradienteditor.ui forms/wdgsessionmanager.ui forms/wdgnewwindowlayout.ui brushhud/kis_dlg_brush_hud_config.ui forms/wdgdlginternalcolorselector.ui dialogs/kis_delayed_save_dialog.ui input/config/kis_input_configuration_page.ui input/config/kis_edit_profiles_dialog.ui input/config/kis_input_configuration_page_item.ui input/config/kis_mouse_input_editor.ui input/config/kis_wheel_input_editor.ui input/config/kis_key_input_editor.ui layerstyles/wdgBevelAndEmboss.ui layerstyles/wdgblendingoptions.ui layerstyles/WdgColorOverlay.ui layerstyles/wdgContour.ui layerstyles/wdgdropshadow.ui layerstyles/WdgGradientOverlay.ui layerstyles/wdgInnerGlow.ui layerstyles/wdglayerstyles.ui layerstyles/WdgPatternOverlay.ui layerstyles/WdgSatin.ui layerstyles/WdgStroke.ui layerstyles/wdgstylesselector.ui layerstyles/wdgTexture.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui input/wintab/drawpile_tablettester/tablettest.ui ) QT5_WRAP_CPP(kritaui_HEADERS_MOC KisNodePropertyAction_p.h) add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} ) generate_export_header(kritaui BASE_NAME kritaui) target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} ${EXIV2_LIBRARIES} ) if (HAVE_QT_MULTIMEDIA) target_link_libraries(kritaui Qt5::Multimedia) endif() if (HAVE_KIO) target_link_libraries(kritaui KF5::KIOCore) endif() if (NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) target_link_libraries(kritaui ${APPKIT_LIBRARY}) endif () target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_include_directories(kritaui PUBLIC $ $ $ $ $ $ $ ) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () diff --git a/libs/ui/forms/wdgpaintactioneditor.ui b/libs/ui/forms/wdgpaintactioneditor.ui deleted file mode 100644 index deac79f578..0000000000 --- a/libs/ui/forms/wdgpaintactioneditor.ui +++ /dev/null @@ -1,207 +0,0 @@ - - - WdgPaintActionEditor - - - - 0 - 0 - 405 - 376 - - - - - - - - - - 0 - - - - Options - - - - - - Paint color: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Background color: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Vertical - - - - 236 - 147 - - - - - - - - Opacity: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - 0 - - - 100 - - - true - - - - - - - - 0 - 0 - - - - ... - - - - - - - - 0 - 0 - - - - ... - - - - - - - - Current preset - - - - - - Paint op: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - - 0 - 4 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - Preset Collection - - - - - - - 4 - 4 - - - - - - - - - - - - - KisColorButton - QPushButton -
kis_color_button.h
-
- - KisIntParseSpinBox - QSpinBox -
kis_int_parse_spin_box.h
-
- - KisPresetChooser - QWidget -
widgets/kis_preset_chooser.h
- 1 -
- - KisNodeQueryPathEditor - QWidget -
recorder/kis_node_query_path_editor.h
- 1 -
-
- - -
diff --git a/libs/ui/kis_layer_manager.cc b/libs/ui/kis_layer_manager.cc index 2c7ad7af0b..df57ec03ca 100644 --- a/libs/ui/kis_layer_manager.cc +++ b/libs/ui/kis_layer_manager.cc @@ -1,955 +1,955 @@ /* * Copyright (C) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisImportExportManager.h" #include "kis_config.h" #include "kis_cursor.h" #include "dialogs/kis_dlg_adj_layer_props.h" #include "dialogs/kis_dlg_adjustment_layer.h" #include "dialogs/kis_dlg_layer_properties.h" #include "dialogs/kis_dlg_generator_layer.h" #include "dialogs/kis_dlg_file_layer.h" #include "dialogs/kis_dlg_layer_style.h" #include "KisDocument.h" #include "kis_filter_manager.h" #include "kis_node_visitor.h" #include "kis_paint_layer.h" #include "commands/kis_image_commands.h" #include "commands/kis_node_commands.h" #include "kis_change_file_layer_command.h" #include "kis_canvas_resource_provider.h" #include "kis_selection_manager.h" #include "kis_statusbar.h" #include "KisViewManager.h" #include "kis_zoom_manager.h" #include "canvas/kis_canvas2.h" #include "widgets/kis_meta_data_merge_strategy_chooser_widget.h" #include "widgets/kis_wdg_generator.h" #include "kis_progress_widget.h" #include "kis_node_commands_adapter.h" #include "kis_node_manager.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisPart.h" #include "kis_raster_keyframe_channel.h" #include "kis_signal_compressor_with_param.h" #include "kis_abstract_projection_plane.h" #include "commands_new/kis_set_layer_style_command.h" #include "kis_post_execution_undo_adapter.h" #include "kis_selection_mask.h" #include "kis_layer_utils.h" #include "lazybrush/kis_colorize_mask.h" #include "KisSaveGroupVisitor.h" KisLayerManager::KisLayerManager(KisViewManager * view) : m_view(view) , m_imageView(0) , m_imageFlatten(0) , m_imageMergeLayer(0) , m_groupLayersSave(0) , m_imageResizeToLayer(0) , m_flattenLayer(0) , m_rasterizeLayer(0) , m_commandsAdapter(new KisNodeCommandsAdapter(m_view)) , m_layerStyle(0) { } KisLayerManager::~KisLayerManager() { delete m_commandsAdapter; } void KisLayerManager::setView(QPointerview) { m_imageView = view; } KisLayerSP KisLayerManager::activeLayer() { if (m_imageView) { return m_imageView->currentLayer(); } return 0; } KisPaintDeviceSP KisLayerManager::activeDevice() { if (activeLayer()) { return activeLayer()->paintDevice(); } return 0; } void KisLayerManager::activateLayer(KisLayerSP layer) { if (m_imageView) { emit sigLayerActivated(layer); layersUpdated(); if (layer) { m_view->resourceProvider()->slotNodeActivated(layer.data()); } } } void KisLayerManager::setup(KisActionManager* actionManager) { m_imageFlatten = actionManager->createAction("flatten_image"); connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage())); m_imageMergeLayer = actionManager->createAction("merge_layer"); connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer())); m_flattenLayer = actionManager->createAction("flatten_layer"); connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer())); m_rasterizeLayer = actionManager->createAction("rasterize_layer"); connect(m_rasterizeLayer, SIGNAL(triggered()), this, SLOT(rasterizeLayer())); m_groupLayersSave = actionManager->createAction("save_groups_as_images"); connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers())); m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated"); connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated())); m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer"); connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer())); KisAction *action = actionManager->createAction("trim_to_image"); connect(action, SIGNAL(triggered()), this, SLOT(trimToImage())); m_layerStyle = actionManager->createAction("layer_style"); connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle())); } void KisLayerManager::updateGUI() { KisImageSP image = m_view->image(); KisLayerSP layer = activeLayer(); const bool isGroupLayer = layer && layer->inherits("KisGroupLayer"); m_imageMergeLayer->setText( isGroupLayer ? i18nc("@action:inmenu", "Merge Group") : i18nc("@action:inmenu", "Merge with Layer Below")); m_flattenLayer->setVisible(!isGroupLayer); if (m_view->statusBar()) m_view->statusBar()->setProfile(image); } void KisLayerManager::imageResizeToActiveLayer() { KisLayerSP layer; KisImageWSP image = m_view->image(); if (image && (layer = activeLayer())) { QRect cropRect = layer->projection()->nonDefaultPixelArea(); if (!cropRect.isEmpty()) { image->cropImage(cropRect); } else { m_view->showFloatingMessage( i18nc("floating message in layer manager", "Layer is empty "), QIcon(), 2000, KisFloatingMessage::Low); } } } void KisLayerManager::trimToImage() { KisImageWSP image = m_view->image(); if (image) { image->cropImage(image->bounds()); } } void KisLayerManager::layerProperties() { if (!m_view) return; if (!m_view->document()) return; KisLayerSP layer = activeLayer(); if (!layer) return; QList selectedNodes = m_view->nodeManager()->selectedNodes(); const bool multipleLayersSelected = selectedNodes.size() > 1; KisAdjustmentLayerSP alayer = KisAdjustmentLayerSP(dynamic_cast(layer.data())); KisGeneratorLayerSP glayer = KisGeneratorLayerSP(dynamic_cast(layer.data())); KisFileLayerSP flayer = KisFileLayerSP(dynamic_cast(layer.data())); if (alayer && !multipleLayersSelected) { KisPaintDeviceSP dev = alayer->projection(); KisDlgAdjLayerProps dlg(alayer, alayer.data(), dev, m_view, alayer->filter().data(), alayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops"); dlg.resize(dlg.minimumSizeHint()); KisFilterConfigurationSP configBefore(alayer->filter()); KIS_ASSERT_RECOVER_RETURN(configBefore); QString xmlBefore = configBefore->toXML(); if (dlg.exec() == QDialog::Accepted) { alayer->setName(dlg.layerName()); KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(alayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, false); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } else { KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { alayer->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data())); alayer->setDirty(); } } } else if (glayer && !multipleLayersSelected) { KisDlgGeneratorLayer dlg(glayer->name(), m_view, m_view->mainWindow()); dlg.setCaption(i18n("Fill Layer Properties")); KisFilterConfigurationSP configBefore(glayer->filter()); Q_ASSERT(configBefore); QString xmlBefore = configBefore->toXML(); dlg.setConfiguration(configBefore.data()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { glayer->setName(dlg.layerName()); KisFilterConfigurationSP configAfter(dlg.configuration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(glayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, true); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } } else if (flayer && !multipleLayersSelected){ QString basePath = QFileInfo(m_view->document()->url().toLocalFile()).absolutePath(); QString fileNameOld = flayer->fileName(); KisFileLayer::ScalingMethod scalingMethodOld = flayer->scalingMethod(); KisDlgFileLayer dlg(basePath, flayer->name(), m_view->mainWindow()); dlg.setCaption(i18n("File Layer Properties")); dlg.setFileName(fileNameOld); dlg.setScalingMethod(scalingMethodOld); if (dlg.exec() == QDialog::Accepted) { const QString fileNameNew = dlg.fileName(); KisFileLayer::ScalingMethod scalingMethodNew = dlg.scaleToImageResolution(); if(fileNameNew.isEmpty()){ QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); return; } flayer->setName(dlg.layerName()); if (fileNameOld!= fileNameNew || scalingMethodOld != scalingMethodNew) { KisChangeFileLayerCmd *cmd = new KisChangeFileLayerCmd(flayer, basePath, fileNameOld, scalingMethodOld, basePath, fileNameNew, scalingMethodNew); m_view->undoAdapter()->addCommand(cmd); } } } else { // If layer == normal painting layer, vector layer, or group layer QList selectedNodes = m_view->nodeManager()->selectedNodes(); KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view); dialog->resize(dialog->minimumSizeHint()); dialog->setAttribute(Qt::WA_DeleteOnClose); Qt::WindowFlags flags = dialog->windowFlags(); dialog->setWindowFlags(flags | Qt::WindowStaysOnTopHint | Qt::Dialog); dialog->show(); } } void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source) { KisImageWSP image = m_view->image(); if (!image) return; KisLayer *srcLayer = qobject_cast(source.data()); if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) { image->flattenLayer(srcLayer); return; } KisPaintDeviceSP srcDevice = source->paintDevice() ? source->projection() : source->original(); bool putBehind = false; QString newCompositeOp = source->compositeOpId(); KisColorizeMask *colorizeMask = dynamic_cast(source.data()); if (colorizeMask) { srcDevice = colorizeMask->coloringProjection(); putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND; if (putBehind) { newCompositeOp = COMPOSITE_OVER; } } if (!srcDevice) return; KisPaintDeviceSP clone; if (*srcDevice->colorSpace() != *srcDevice->compositionSourceColorSpace()) { clone = new KisPaintDevice(srcDevice->compositionSourceColorSpace()); QRect rc(srcDevice->extent()); KisPainter::copyAreaOptimized(rc.topLeft(), srcDevice, clone, rc); } else { clone = new KisPaintDevice(*srcDevice); } KisLayerSP layer = new KisPaintLayer(image, source->name(), source->opacity(), clone); layer->setCompositeOpId(newCompositeOp); KisNodeSP parent = source->parent(); - KisNodeSP above = source; + KisNodeSP above = source->prevSibling(); while (parent && !parent->allowAsChild(layer)) { - above = above->parent(); + above = above ? above->parent() : source->parent(); parent = above ? above->parent() : 0; } if (putBehind && above == source->parent()) { above = above->prevSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a Paint Layer")); - m_commandsAdapter->addNode(layer, parent, above); m_commandsAdapter->removeNode(source); + m_commandsAdapter->addNode(layer, parent, above); m_commandsAdapter->endMacro(); } void KisLayerManager::convertGroupToAnimated() { KisGroupLayerSP group = dynamic_cast(activeLayer().data()); if (group.isNull()) return; KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8); animatedLayer->enableAnimation(); KisRasterKeyframeChannel *contentChannel = dynamic_cast( animatedLayer->getKeyframeChannel(KisKeyframeChannel::Content.id(), true)); KIS_ASSERT_RECOVER_RETURN(contentChannel); KisNodeSP child = group->firstChild(); int time = 0; while (child) { contentChannel->importFrame(time, child->projection(), NULL); time++; child = child->nextSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer")); m_commandsAdapter->addNode(animatedLayer, group->parent(), group); m_commandsAdapter->removeNode(group); m_commandsAdapter->endMacro(); } void KisLayerManager::convertLayerToFileLayer(KisNodeSP source) { KisImageSP image = m_view->image(); if (!image) return; QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); KoDialog dlg; QWidget *page = new QWidget(&dlg); dlg.setMainWidget(page); QBoxLayout *layout = new QVBoxLayout(page); dlg.setWindowTitle(i18n("Save layers to...")); QLabel *lbl = new QLabel(i18n("Choose the location where the layer will be saved to. The new file layer will then reference this location.")); lbl->setWordWrap(true); layout->addWidget(lbl); KisFileNameRequester *urlRequester = new KisFileNameRequester(page); urlRequester->setMode(KoFileDialog::SaveFile); urlRequester->setMimeTypeFilters(listMimeFilter); urlRequester->setFileName(m_view->document()->url().toLocalFile()); if (m_view->document()->url().isLocalFile()) { QFileInfo location = QFileInfo(m_view->document()->url().toLocalFile()).baseName(); location.setFile(location.dir(), location.baseName()+"_"+ source->name()+".kra"); urlRequester->setFileName(location.absoluteFilePath()); } else { const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".kra"); urlRequester->setFileName(proposedFileName); } layout->addWidget(urlRequester); if (!dlg.exec()) return; QString path = urlRequester->fileName(); if (path.isEmpty()) return; QFileInfo f(path); QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName()); if (mimeType.isEmpty()) { mimeType = "image/png"; } QScopedPointer doc(KisPart::instance()->createDocument()); QRect bounds = source->exactBounds(); KisImageSP dst = new KisImage(doc->createUndoStore(), image->width(), image->height(), image->projection()->compositionSourceColorSpace(), source->name()); dst->setResolution(image->xRes(), image->yRes()); doc->setFileBatchMode(false); doc->setCurrentImage(dst); KisNodeSP node = source->clone(); dst->addNode(node); dst->initialRefreshGraph(); dst->cropImage(bounds); dst->waitForDone(); bool r = doc->exportDocumentSync(QUrl::fromLocalFile(path), mimeType.toLatin1()); if (!r) { qDebug()<< "Path:"<errorMessage(); } else { QString basePath = QFileInfo(m_view->document()->url().toLocalFile()).absolutePath(); QString relativePath = QDir(basePath).relativeFilePath(path); KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, source->name(), OPACITY_OPAQUE_U8); fileLayer->setX(bounds.x()); fileLayer->setY(bounds.y()); KisNodeSP dstParent = source->parent(); KisNodeSP dstAboveThis = source->prevSibling(); m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer")); m_commandsAdapter->removeNode(source); m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis); m_commandsAdapter->endMacro(); } doc->closeUrl(false); } void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above) { Q_ASSERT(activeNode); parent = activeNode; above = parent->lastChild(); while (parent && (!parent->allowAsChild(node) || parent->userLocked())) { above = parent; parent = parent->parent(); } if (!parent) { warnKrita << "KisLayerManager::adjustLayerPosition:" << "No node accepted newly created node"; parent = m_view->image()->root(); above = parent->lastChild(); } } void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisLayerSP layer, bool updateImage) { KisNodeSP parent; KisNodeSP above; adjustLayerPosition(layer, activeNode, parent, above); KisGroupLayer *group = dynamic_cast(parent.data()); const bool parentForceUpdate = group && !group->projectionIsValid(); updateImage |= parentForceUpdate; m_commandsAdapter->addNode(layer, parent, above, updateImage, updateImage); } KisLayerSP KisLayerManager::addLayer(KisNodeSP activeNode) { KisLayerSP layer = KisLayerUtils::constructDefaultLayer(m_view->image()); addLayerCommon(activeNode, layer, false); return layer; } void KisLayerManager::addGroupLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisGroupLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8), false); } void KisLayerManager::addCloneLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisCloneLayer(activeLayer(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8)); } void KisLayerManager::addShapeLayer(KisNodeSP activeNode) { if (!m_view) return; if (!m_view->document()) return; KisImageWSP image = m_view->image(); KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8); addLayerCommon(activeNode, layer, false); } void KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisSelectionSP selection = m_view->selection(); KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection); image->refreshGraph(); KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original()); KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(), i18n("New Filter Layer"), m_view); dlg.resize(dlg.minimumSizeHint()); // ensure that the device may be free'd by the dialog // when it is not needed anymore previewDevice = 0; if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) { // XXX: add messagebox warning if there's no filter set! m_commandsAdapter->undoLastCommand(); } else { adjl->setName(dlg.layerName()); } } KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name, KisFilterConfigurationSP filter, KisSelectionSP selection) { KisImageWSP image = m_view->image(); KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter, selection); addLayerCommon(activeNode, layer); return layer; } void KisLayerManager::addGeneratorLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisDlgGeneratorLayer dlg(image->nextLayerName(), m_view, m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { KisSelectionSP selection = m_view->selection(); KisFilterConfigurationSP generator = dlg.configuration(); QString name = dlg.layerName(); addLayerCommon(activeNode, new KisGeneratorLayer(image, name, generator, selection)); } } void KisLayerManager::flattenImage() { KisImageSP image = m_view->image(); if (!m_view->blockUntilOperationsFinished(image)) return; if (image) { bool doIt = true; if (image->nHiddenLayers() > 0) { int answer = QMessageBox::warning(m_view->mainWindow(), i18nc("@title:window", "Flatten Image"), i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer != QMessageBox::Yes) { doIt = false; } } if (doIt) { image->flatten(); } } } inline bool isSelectionMask(KisNodeSP node) { return dynamic_cast(node.data()); } bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image) { bool result = false; KisNodeSP prevNode = currentNode->prevSibling(); if (isSelectionMask(currentNode) && prevNode && isSelectionMask(prevNode)) { QList mergedNodes; mergedNodes.append(currentNode); mergedNodes.append(prevNode); image->mergeMultipleLayers(mergedNodes, currentNode); result = true; } return result; } bool tryFlattenGroupLayer(KisNodeSP currentNode, KisImageSP image) { bool result = false; if (currentNode->inherits("KisGroupLayer")) { KisGroupLayer *layer = qobject_cast(currentNode.data()); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(layer, false); image->flattenLayer(layer); result = true; } return result; } void KisLayerManager::mergeLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; if (!m_view->blockUntilOperationsFinished(image)) return; QList selectedNodes = m_view->nodeManager()->selectedNodes(); if (selectedNodes.size() > 1) { image->mergeMultipleLayers(selectedNodes, m_view->activeNode()); } else if (tryMergeSelectionMasks(m_view->activeNode(), image)) { // already done! } else if (tryFlattenGroupLayer(m_view->activeNode(), image)) { // already done! } else { if (!layer->prevSibling()) return; KisLayer *prevLayer = qobject_cast(layer->prevSibling().data()); if (!prevLayer) return; if (prevLayer->userLocked()) { m_view->showFloatingMessage( i18nc("floating message in layer manager", "Layer is locked "), QIcon(), 2000, KisFloatingMessage::Low); } else if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) { image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); } else { const KisMetaData::MergeStrategy* strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow()); if (!strategy) return; image->mergeDown(layer, strategy); } } m_view->updateGUI(); } void KisLayerManager::flattenLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; if (!m_view->blockUntilOperationsFinished(image)) return; convertNodeToPaintLayer(layer); m_view->updateGUI(); } void KisLayerManager::rasterizeLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; if (!m_view->blockUntilOperationsFinished(image)) return; KisPaintLayerSP paintLayer = new KisPaintLayer(image, layer->name(), layer->opacity()); KisPainter gc(paintLayer->paintDevice()); QRect rc = layer->projection()->exactBounds(); gc.bitBlt(rc.topLeft(), layer->projection(), rc); m_commandsAdapter->beginMacro(kundo2_i18n("Rasterize Layer")); m_commandsAdapter->addNode(paintLayer.data(), layer->parent().data(), layer.data()); int childCount = layer->childCount(); for (int i = 0; i < childCount; i++) { m_commandsAdapter->moveNode(layer->firstChild(), paintLayer, paintLayer->lastChild()); } m_commandsAdapter->removeNode(layer); m_commandsAdapter->endMacro(); updateGUI(); } void KisLayerManager::layersUpdated() { KisLayerSP layer = activeLayer(); if (!layer) return; m_view->updateGUI(); } void KisLayerManager::saveGroupLayers() { QStringList listMimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); KoDialog dlg; QWidget *page = new QWidget(&dlg); dlg.setMainWidget(page); QBoxLayout *layout = new QVBoxLayout(page); KisFileNameRequester *urlRequester = new KisFileNameRequester(page); urlRequester->setMode(KoFileDialog::SaveFile); if (m_view->document()->url().isLocalFile()) { urlRequester->setStartDir(QFileInfo(m_view->document()->url().toLocalFile()).absolutePath()); } urlRequester->setMimeTypeFilters(listMimeFilter); urlRequester->setFileName(m_view->document()->url().toLocalFile()); layout->addWidget(urlRequester); QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page); chkInvisible->setChecked(false); layout->addWidget(chkInvisible); QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page); chkDepth->setChecked(true); layout->addWidget(chkDepth); if (!dlg.exec()) return; QString path = urlRequester->fileName(); if (path.isEmpty()) return; QFileInfo f(path); QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName(), false); if (mimeType.isEmpty()) { mimeType = "image/png"; } QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first(); QString basename = f.baseName(); KisImageSP image = m_view->image(); if (!image) return; KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType); image->rootLayer()->accept(v); } bool KisLayerManager::activeLayerHasSelection() { return (activeLayer()->selection() != 0); } void KisLayerManager::addFileLayer(KisNodeSP activeNode) { QString basePath; QUrl url = m_view->document()->url(); if (url.isLocalFile()) { basePath = QFileInfo(url.toLocalFile()).absolutePath(); } KisImageWSP image = m_view->image(); KisDlgFileLayer dlg(basePath, image->nextLayerName(), m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { QString name = dlg.layerName(); QString fileName = dlg.fileName(); if(fileName.isEmpty()){ QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); return; } KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution(); addLayerCommon(activeNode, new KisFileLayer(image, basePath, fileName, scalingMethod, name, OPACITY_OPAQUE_U8)); } } void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg) { KisSetLayerStyleCommand::updateLayerStyle(layer, dlg->style()->clone()); } void KisLayerManager::layerStyle() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; if (!m_view->blockUntilOperationsFinished(image)) return; KisPSDLayerStyleSP oldStyle; if (layer->layerStyle()) { oldStyle = layer->layerStyle()->clone(); } else { oldStyle = toQShared(new KisPSDLayerStyle()); } KisDlgLayerStyle dlg(oldStyle->clone(), m_view->resourceProvider()); std::function updateCall(std::bind(updateLayerStyles, layer, &dlg)); SignalToFunctionProxy proxy(updateCall); connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start())); if (dlg.exec() == QDialog::Accepted) { KisPSDLayerStyleSP newStyle = dlg.style(); KUndo2CommandSP command = toQShared( new KisSetLayerStyleCommand(layer, oldStyle, newStyle)); image->postExecutionUndoAdapter()->addCommand(command); } } diff --git a/libs/ui/kis_node_manager.cpp b/libs/ui/kis_node_manager.cpp index 9a55a667ba..9aec153105 100644 --- a/libs/ui/kis_node_manager.cpp +++ b/libs/ui/kis_node_manager.cpp @@ -1,1502 +1,1502 @@ /* * 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 #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 "kis_shape_layer.h" #include "processing/kis_mirror_processing_visitor.h" #include "KisView.h" #include 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; KisAction *showInTimeline; 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); //if (!shape) return false; KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(shape, false); selection->select(shape); KoShapeLayer * shapeLayer = dynamic_cast(shape); //if (!shapeLayer) return false; KIS_SAFE_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("save_vector_node_to_svg"); connect(action, SIGNAL(triggered()), this, SLOT(saveVectorLayerAsImage())); action->setActivationFlags(KisAction::ACTIVE_SHAPE_LAYER); 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())); action = actionManager->createAction("show_in_timeline"); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), this, SLOT(slotShowHideTimeline(bool))); m_d->showInTimeline = action; 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"); CONVERT_NODE_ACTION_2("convert_layer_to_file_layer", "KisFileLayer", QStringList()<< "KisFileLayer" << "KisCloneLayer"); 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("toggle_layer_visibility"); connect(action, SIGNAL(triggered()), this, SLOT(toggleVisibility())); action = actionManager->createAction("toggle_layer_lock"); connect(action, SIGNAL(triggered()), this, SLOT(toggleLock())); action = actionManager->createAction("toggle_layer_inherit_alpha"); connect(action, SIGNAL(triggered()), this, SLOT(toggleInheritAlpha())); action = actionManager->createAction("toggle_layer_alpha_lock"); connect(action, SIGNAL(triggered()), this, SLOT(toggleAlphaLock())); 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()); if (m && m->active() && l && l->selectionMask()) { l->selectionMask()->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) { if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) { return; } KisNodeSP activeNode = this->activeNode(); if (!activeNode) { activeNode = m_d->view->image()->root(); } KIS_ASSERT_RECOVER_RETURN(activeNode); // XXX: make factories for this kind of stuff, // with a registry if (nodeType == "KisPaintLayer") { m_d->layerManager.addLayer(activeNode); } else if (nodeType == "KisGroupLayer") { m_d->layerManager.addGroupLayer(activeNode); } else if (nodeType == "KisAdjustmentLayer") { m_d->layerManager.addAdjustmentLayer(activeNode); } else if (nodeType == "KisGeneratorLayer") { m_d->layerManager.addGeneratorLayer(activeNode); } else if (nodeType == "KisShapeLayer") { m_d->layerManager.addShapeLayer(activeNode); } else if (nodeType == "KisCloneLayer") { m_d->layerManager.addCloneLayer(activeNode); } else if (nodeType == "KisTransparencyMask") { m_d->maskManager.createTransparencyMask(activeNode, copyFrom, false); } else if (nodeType == "KisFilterMask") { m_d->maskManager.createFilterMask(activeNode, copyFrom, quiet, false); } else if (nodeType == "KisColorizeMask") { m_d->maskManager.createColorizeMask(activeNode); } else if (nodeType == "KisTransformMask") { m_d->maskManager.createTransformMask(activeNode); } else if (nodeType == "KisSelectionMask") { m_d->maskManager.createSelectionMask(activeNode, copyFrom, false); } else if (nodeType == "KisFileLayer") { m_d->layerManager.addFileLayer(activeNode); } } void KisNodeManager::createFromVisible() { KisLayerUtils::newLayerFromVisible(m_d->view->image(), m_d->view->image()->root()->lastChild()); } void KisNodeManager::slotShowHideTimeline(bool value) { Q_FOREACH (KisNodeSP node, selectedNodes()) { node->setUseInTimeline(value); } } 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 if (nodeType == "KisFileLayer") { m_d->layerManager.convertLayerToFileLayer(activeNode); } 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; // the node must still be in the graph, some asynchronous // signals may easily break this requirement - KIS_SAFE_ASSERT_RECOVER_RETURN(node->graphListener()); + KIS_SAFE_ASSERT_RECOVER_RETURN(!node || node->graphListener()); 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; // the node must still be in the graph, some asynchronous // signals may easily break this requirement - KIS_SAFE_ASSERT_RECOVER_RETURN(node->graphListener()); + KIS_SAFE_ASSERT_RECOVER_RETURN(!node || node->graphListener()); 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(); { KisSignalsBlocker b(m_d->showInTimeline); m_d->showInTimeline->setChecked(node->useInTimeline()); } } 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")) || 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(); } bool KisNodeManager::isNodeHidden(KisNodeSP node, bool isGlobalSelectionHidden) { if (dynamic_cast(node.data())) { return true; } if (isGlobalSelectionHidden && dynamic_cast(node.data()) && (!node->parent() || !node->parent()->parent())) { return true; } return false; } 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->isEnded() || !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); } 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 && isNodeHidden(node, true)) { 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 && isNodeHidden(node, true)) { node = node->prevSibling(); } if (node) { slotNonUiActivatedNode(node); } } void KisNodeManager::switchToPreviouslyActiveNode() { if (m_d->previouslyActiveNode && m_d->previouslyActiveNode->parent()) { slotNonUiActivatedNode(m_d->previouslyActiveNode); } } void KisNodeManager::rotate(double radians) { if(!m_d->view->image()) return; KisNodeSP node = activeNode(); if (!node) return; if (!m_d->view->blockUntilOperationsFinished(m_d->view->image())) return; m_d->view->image()->rotateNode(node, 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) { if (!m_d->view->image()) return; KisNodeSP node = activeNode(); if (!node) return; if(!m_d->view->blockUntilOperationsFinished(m_d->view->image())) return; m_d->view->image()->shearNode(node, 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(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export)); QString filename = dialog.filename(); if (filename.isEmpty()) return; QUrl url = QUrl::fromLocalFile(filename); if (url.isEmpty()) return; QString mimefilter = KisMimeDatabase::mimeTypeForFile(filename, false); QScopedPointer doc(KisPart::instance()->createDocument()); KisImageSP dst = new KisImage(doc->createUndoStore(), bounds.width(), bounds.height(), device->compositionSourceColorSpace(), defaultName); dst->setResolution(xRes, yRes); doc->setCurrentImage(dst); KisPaintLayer* paintLayer = new KisPaintLayer(dst, "paint device", opacity); paintLayer->paintDevice()->makeCloneFrom(device, bounds); dst->addNode(paintLayer, dst->rootLayer(), KisLayerSP(0)); dst->initialRefreshGraph(); doc->exportDocumentSync(url, mimefilter.toLatin1()); } 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()); } #include "SvgWriter.h" void KisNodeManager::saveVectorLayerAsImage() { KisShapeLayerSP shapeLayer = qobject_cast(activeNode().data()); if (!shapeLayer) { return; } KoFileDialog dialog(m_d->view->mainWindow(), KoFileDialog::SaveFile, "savenodeasimage"); dialog.setCaption(i18nc("@title:window", "Export to SVG")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(QStringList() << "image/svg+xml", "image/svg+xml"); QString filename = dialog.filename(); if (filename.isEmpty()) return; QUrl url = QUrl::fromLocalFile(filename); if (url.isEmpty()) return; const QSizeF sizeInPx = m_d->view->image()->bounds().size(); const QSizeF sizeInPt(sizeInPx.width() / m_d->view->image()->xRes(), sizeInPx.height() / m_d->view->image()->yRes()); QList shapes = shapeLayer->shapes(); std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); SvgWriter writer(shapes); if (!writer.save(filename, sizeInPt, true)) { QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita"), i18n("Could not save to svg: %1").arg(filename)); } } 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); while (srcIt.nextPixel() && dstIt.nextPixel()) { quint8 *srcPtr = srcIt.rawData(); quint8 *alpha8Ptr = dstIt.rawData(); *alpha8Ptr = srcCS->opacityU8(srcPtr); srcCS->setOpacity(srcPtr, OPACITY_OPAQUE_U8, 1); } 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); while (srcIt.nextPixel() && dstIt.nextPixel()) { quint8 *alpha8Ptr = srcIt.rawData(); quint8 *dstPtr = dstIt.rawData(); dstCS->setOpacity(dstPtr, *alpha8Ptr, 1); } 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::toggleLock() { KisNodeList nodes = this->selectedNodes(); KisNodeSP active = activeNode(); if (nodes.isEmpty() || !active) return; bool isLocked = active->userLocked(); for (auto &node : nodes) { node->setUserLocked(!isLocked); } } void KisNodeManager::toggleVisibility() { KisNodeList nodes = this->selectedNodes(); KisNodeSP active = activeNode(); if (nodes.isEmpty() || !active) return; bool isVisible = active->visible(); for (auto &node : nodes) { node->setVisible(!isVisible); node->setDirty(); } } void KisNodeManager::toggleAlphaLock() { KisNodeList nodes = this->selectedNodes(); KisNodeSP active = activeNode(); if (nodes.isEmpty() || !active) return; auto layer = qobject_cast(active.data()); if (!layer) { return; } bool isAlphaLocked = layer->alphaLocked(); for (auto &node : nodes) { auto layer = qobject_cast(node.data()); if (layer) { layer->setAlphaLocked(!isAlphaLocked); } } } void KisNodeManager::toggleInheritAlpha() { KisNodeList nodes = this->selectedNodes(); KisNodeSP active = activeNode(); if (nodes.isEmpty() || !active) return; auto layer = qobject_cast(active.data()); if (!layer) { return; } bool isAlphaDisabled = layer->alphaChannelDisabled(); for (auto &node : nodes) { auto layer = qobject_cast(node.data()); if (layer) { layer->disableAlphaChannel(!isAlphaDisabled); node->setDirty(); } } } void KisNodeManager::cutLayersToClipboard() { KisNodeList nodes = this->selectedNodes(); if (nodes.isEmpty()) return; KisClipboard::instance()->setLayers(nodes, m_d->view->image(), false); KUndo2MagicString actionName = kundo2_i18n("Cut Nodes"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->removeNode(nodes); } void KisNodeManager::copyLayersToClipboard() { KisNodeList nodes = this->selectedNodes(); KisClipboard::instance()->setLayers(nodes, m_d->view->image(), true); } void KisNodeManager::pasteLayersFromClipboard() { const QMimeData *data = KisClipboard::instance()->layersMimeData(); if (!data) return; KisNodeSP activeNode = this->activeNode(); KisShapeController *shapeController = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(shapeController); KisDummiesFacadeBase *dummiesFacade = dynamic_cast(m_d->imageView->document()->shapeController()); Q_ASSERT(dummiesFacade); const bool copyNode = false; KisImageSP image = m_d->view->image(); KisNodeDummy *parentDummy = dummiesFacade->dummyForNode(activeNode); KisNodeDummy *aboveThisDummy = parentDummy ? parentDummy->lastChild() : 0; KisMimeData::insertMimeLayers(data, image, shapeController, parentDummy, aboveThisDummy, copyNode, nodeInsertionAdapter()); } void KisNodeManager::createQuickGroupImpl(KisNodeJugglerCompressed *juggler, const QString &overrideGroupName, KisNodeSP *newGroup, KisNodeSP *newLastChild) { KisNodeSP active = activeNode(); if (!active) return; KisImageSP image = m_d->view->image(); QString groupName = !overrideGroupName.isEmpty() ? overrideGroupName : image->nextLayerName(); KisGroupLayerSP group = new KisGroupLayer(image.data(), groupName, OPACITY_OPAQUE_U8); KisNodeList nodes1; nodes1 << group; KisNodeList nodes2; nodes2 = KisLayerUtils::sortMergableNodes(image->root(), selectedNodes()); KisLayerUtils::filterMergableNodes(nodes2); if (KisLayerUtils::checkIsChildOf(active, nodes2)) { active = nodes2.first(); } KisNodeSP parent = active->parent(); KisNodeSP aboveThis = active; juggler->addNode(nodes1, parent, aboveThis); juggler->moveNode(nodes2, group, 0); *newGroup = group; *newLastChild = nodes2.last(); } void KisNodeManager::createQuickGroup() { KUndo2MagicString actionName = kundo2_i18n("Quick Group"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); KisNodeSP parent; KisNodeSP above; createQuickGroupImpl(juggler, "", &parent, &above); } void KisNodeManager::createQuickClippingGroup() { KUndo2MagicString actionName = kundo2_i18n("Quick Clipping Group"); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); KisNodeSP parent; KisNodeSP above; KisImageSP image = m_d->view->image(); createQuickGroupImpl(juggler, image->nextLayerName(i18nc("default name for a clipping group layer", "Clipping Group")), &parent, &above); KisPaintLayerSP maskLayer = new KisPaintLayer(image.data(), i18nc("default name for quick clip group mask layer", "Mask Layer"), OPACITY_OPAQUE_U8, image->colorSpace()); maskLayer->disableAlphaChannel(true); juggler->addNode(KisNodeList() << maskLayer, parent, above); } void KisNodeManager::quickUngroup() { KisNodeSP active = activeNode(); if (!active) return; KisNodeSP parent = active->parent(); KisNodeSP aboveThis = active; KUndo2MagicString actionName = kundo2_i18n("Quick Ungroup"); if (parent && dynamic_cast(active.data())) { KisNodeList nodes = active->childNodes(QStringList(), KoProperties()); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->moveNode(nodes, parent, active); juggler->removeNode(KisNodeList() << active); } else if (parent && parent->parent()) { KisNodeSP grandParent = parent->parent(); KisNodeList allChildNodes = parent->childNodes(QStringList(), KoProperties()); KisNodeList allSelectedNodes = selectedNodes(); const bool removeParent = KritaUtils::compareListsUnordered(allChildNodes, allSelectedNodes); KisNodeJugglerCompressed *juggler = m_d->lazyGetJuggler(actionName); juggler->moveNode(allSelectedNodes, grandParent, parent); if (removeParent) { juggler->removeNode(KisNodeList() << parent); } } } void KisNodeManager::selectLayersImpl(const KoProperties &props, const KoProperties &invertedProps) { KisImageSP image = m_d->view->image(); KisNodeList nodes = KisLayerUtils::findNodesWithProps(image->root(), props, true); KisNodeList selectedNodes = this->selectedNodes(); if (KritaUtils::compareListsUnordered(nodes, selectedNodes)) { nodes = KisLayerUtils::findNodesWithProps(image->root(), invertedProps, true); } if (!nodes.isEmpty()) { slotImageRequestNodeReselection(nodes.last(), nodes); } } void KisNodeManager::selectAllNodes() { KoProperties props; selectLayersImpl(props, props); } void KisNodeManager::selectVisibleNodes() { KoProperties props; props.setProperty("visible", true); KoProperties invertedProps; invertedProps.setProperty("visible", false); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectLockedNodes() { KoProperties props; props.setProperty("locked", true); KoProperties invertedProps; invertedProps.setProperty("locked", false); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectInvisibleNodes() { KoProperties props; props.setProperty("visible", false); KoProperties invertedProps; invertedProps.setProperty("visible", true); selectLayersImpl(props, invertedProps); } void KisNodeManager::selectUnlockedNodes() { KoProperties props; props.setProperty("locked", false); KoProperties invertedProps; invertedProps.setProperty("locked", true); selectLayersImpl(props, invertedProps); } diff --git a/libs/ui/kis_selection_manager.cc b/libs/ui/kis_selection_manager.cc index 1f04c27376..22ad36152c 100644 --- a/libs/ui/kis_selection_manager.cc +++ b/libs/ui/kis_selection_manager.cc @@ -1,609 +1,608 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2007 Sven Langkamp * * The outline algorithm uses the limn algorithm of fontutils by * Karl Berry and Kathryn Hargreaves * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_selection_manager.h" #include #include #include #include #include #include #include #include #include #include #include "KoCanvasController.h" #include "KoChannelInfo.h" #include "KoIntegerMaths.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_adjustment_layer.h" #include "kis_node_manager.h" #include "canvas/kis_canvas2.h" #include "kis_config.h" #include "kis_convolution_painter.h" #include "kis_convolution_kernel.h" #include "kis_debug.h" #include "KisDocument.h" #include "kis_fill_painter.h" #include "kis_group_layer.h" #include "kis_layer.h" #include "kis_statusbar.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_painter.h" #include "kis_transaction.h" #include "kis_selection.h" #include "kis_types.h" #include "kis_canvas_resource_provider.h" #include "kis_undo_adapter.h" #include "kis_pixel_selection.h" #include "flake/kis_shape_selection.h" #include "commands/kis_selection_commands.h" #include "kis_selection_mask.h" #include "flake/kis_shape_layer.h" #include "kis_selection_decoration.h" #include "canvas/kis_canvas_decoration.h" #include "kis_node_commands_adapter.h" #include "kis_iterator_ng.h" #include "kis_clipboard.h" #include "KisViewManager.h" #include "kis_selection_filters.h" #include "kis_figure_painting_tool_helper.h" #include "KisView.h" #include "dialogs/kis_dlg_stroke_selection_properties.h" #include "actions/kis_selection_action_factories.h" #include "actions/KisPasteActionFactory.h" #include "kis_action.h" #include "kis_action_manager.h" #include "operations/kis_operation_configuration.h" //new -#include "kis_recorded_path_paint_action.h" #include "kis_node_query_path.h" #include "kis_tool_shape.h" KisSelectionManager::KisSelectionManager(KisViewManager * view) : m_view(view), m_doc(0), m_imageView(0), m_adapter(new KisNodeCommandsAdapter(view)), m_copy(0), m_copyMerged(0), m_cut(0), m_paste(0), m_pasteNew(0), m_cutToNewLayer(0), m_selectAll(0), m_deselect(0), m_clear(0), m_reselect(0), m_invert(0), m_copyToNewLayer(0), m_fillForegroundColor(0), m_fillBackgroundColor(0), m_fillPattern(0), m_imageResizeToSelection(0), m_selectionDecoration(0) { m_clipboard = KisClipboard::instance(); } KisSelectionManager::~KisSelectionManager() { } void KisSelectionManager::setup(KisActionManager* actionManager) { m_cut = actionManager->createStandardAction(KStandardAction::Cut, this, SLOT(cut())); m_copy = actionManager->createStandardAction(KStandardAction::Copy, this, SLOT(copy())); m_paste = actionManager->createStandardAction(KStandardAction::Paste, this, SLOT(paste())); KisAction *action = actionManager->createAction("copy_sharp"); connect(action, SIGNAL(triggered()), this, SLOT(copySharp())); action = actionManager->createAction("cut_sharp"); connect(action, SIGNAL(triggered()), this, SLOT(cutSharp())); m_pasteNew = actionManager->createAction("paste_new"); connect(m_pasteNew, SIGNAL(triggered()), this, SLOT(pasteNew())); m_pasteAt = actionManager->createAction("paste_at"); connect(m_pasteAt, SIGNAL(triggered()), this, SLOT(pasteAt())); m_copyMerged = actionManager->createAction("copy_merged"); connect(m_copyMerged, SIGNAL(triggered()), this, SLOT(copyMerged())); m_selectAll = actionManager->createAction("select_all"); connect(m_selectAll, SIGNAL(triggered()), this, SLOT(selectAll())); m_deselect = actionManager->createAction("deselect"); connect(m_deselect, SIGNAL(triggered()), this, SLOT(deselect())); m_clear = actionManager->createAction("clear"); connect(m_clear, SIGNAL(triggered()), SLOT(clear())); m_reselect = actionManager->createAction("reselect"); connect(m_reselect, SIGNAL(triggered()), this, SLOT(reselect())); m_invert = actionManager->createAction("invert_selection"); m_invert->setOperationID("invertselection"); actionManager->registerOperation(new KisInvertSelectionOperation); m_copyToNewLayer = actionManager->createAction("copy_selection_to_new_layer"); connect(m_copyToNewLayer, SIGNAL(triggered()), this, SLOT(copySelectionToNewLayer())); m_cutToNewLayer = actionManager->createAction("cut_selection_to_new_layer"); connect(m_cutToNewLayer, SIGNAL(triggered()), this, SLOT(cutToNewLayer())); m_fillForegroundColor = actionManager->createAction("fill_selection_foreground_color"); connect(m_fillForegroundColor, SIGNAL(triggered()), this, SLOT(fillForegroundColor())); m_fillBackgroundColor = actionManager->createAction("fill_selection_background_color"); connect(m_fillBackgroundColor, SIGNAL(triggered()), this, SLOT(fillBackgroundColor())); m_fillPattern = actionManager->createAction("fill_selection_pattern"); connect(m_fillPattern, SIGNAL(triggered()), this, SLOT(fillPattern())); m_fillForegroundColorOpacity = actionManager->createAction("fill_selection_foreground_color_opacity"); connect(m_fillForegroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillForegroundColorOpacity())); m_fillBackgroundColorOpacity = actionManager->createAction("fill_selection_background_color_opacity"); connect(m_fillBackgroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillBackgroundColorOpacity())); m_fillPatternOpacity = actionManager->createAction("fill_selection_pattern_opacity"); connect(m_fillPatternOpacity, SIGNAL(triggered()), this, SLOT(fillPatternOpacity())); m_strokeShapes = actionManager->createAction("stroke_shapes"); connect(m_strokeShapes, SIGNAL(triggered()), this, SLOT(paintSelectedShapes())); m_toggleDisplaySelection = actionManager->createAction("toggle_display_selection"); connect(m_toggleDisplaySelection, SIGNAL(triggered()), this, SLOT(toggleDisplaySelection())); m_toggleDisplaySelection->setChecked(true); m_imageResizeToSelection = actionManager->createAction("resizeimagetoselection"); connect(m_imageResizeToSelection, SIGNAL(triggered()), this, SLOT(imageResizeToSelection())); action = actionManager->createAction("convert_to_vector_selection"); connect(action, SIGNAL(triggered()), SLOT(convertToVectorSelection())); action = actionManager->createAction("convert_shapes_to_vector_selection"); connect(action, SIGNAL(triggered()), SLOT(convertShapesToVectorSelection())); action = actionManager->createAction("convert_selection_to_shape"); connect(action, SIGNAL(triggered()), SLOT(convertToShape())); m_toggleSelectionOverlayMode = actionManager->createAction("toggle-selection-overlay-mode"); connect(m_toggleSelectionOverlayMode, SIGNAL(triggered()), SLOT(slotToggleSelectionDecoration())); m_strokeSelected = actionManager->createAction("stroke_selection"); connect(m_strokeSelected, SIGNAL(triggered()), SLOT(slotStrokeSelection())); QClipboard *cb = QApplication::clipboard(); connect(cb, SIGNAL(dataChanged()), SLOT(clipboardDataChanged())); } void KisSelectionManager::setView(QPointerimageView) { if (m_imageView && m_imageView->canvasBase()) { disconnect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), this, SLOT(clipboardDataChanged())); KoSelection *selection = m_imageView->canvasBase()->globalShapeManager()->selection(); selection->disconnect(this, SLOT(shapeSelectionChanged())); KisSelectionDecoration *decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data()); if (decoration) { disconnect(SIGNAL(currentSelectionChanged()), decoration); } m_imageView->image()->undoAdapter()->disconnect(this); m_selectionDecoration = 0; } m_imageView = imageView; if (m_imageView) { connect(m_imageView->canvasBase()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged())); KisSelectionDecoration* decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data()); if (!decoration) { decoration = new KisSelectionDecoration(m_imageView); decoration->setVisible(true); m_imageView->canvasBase()->addDecoration(decoration); } m_selectionDecoration = decoration; connect(this, SIGNAL(currentSelectionChanged()), decoration, SLOT(selectionChanged())); connect(m_imageView->image()->undoAdapter(), SIGNAL(selectionChanged()), SLOT(selectionChanged())); connect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), SLOT(clipboardDataChanged())); } } void KisSelectionManager::clipboardDataChanged() { m_view->updateGUI(); } bool KisSelectionManager::havePixelsSelected() { KisSelectionSP activeSelection = m_view->selection(); return activeSelection && !activeSelection->selectedRect().isEmpty(); } bool KisSelectionManager::havePixelsInClipboard() { return m_clipboard->hasClip(); } bool KisSelectionManager::haveShapesSelected() { if (m_view && m_view->canvasBase()) { return m_view->canvasBase()->selectedShapesProxy()->selection()->count() > 0; } return false; } bool KisSelectionManager::haveShapesInClipboard() { KoSvgPaste paste; return paste.hasShapes(); } bool KisSelectionManager::havePixelSelectionWithPixels() { KisSelectionSP selection = m_view->selection(); if (selection && selection->hasPixelSelection()) { return !selection->pixelSelection()->selectedRect().isEmpty(); } return false; } void KisSelectionManager::updateGUI() { Q_ASSERT(m_view); Q_ASSERT(m_clipboard); if (!m_view || !m_clipboard) return; bool havePixelsSelected = this->havePixelsSelected(); bool havePixelsInClipboard = this->havePixelsInClipboard(); bool haveShapesSelected = this->haveShapesSelected(); bool haveShapesInClipboard = this->haveShapesInClipboard(); bool haveDevice = m_view->activeDevice(); KisLayerSP activeLayer = m_view->activeLayer(); KisImageWSP image = activeLayer ? activeLayer->image() : 0; bool canReselect = image && image->canReselectGlobalSelection(); bool canDeselect = image && image->globalSelection(); m_clear->setEnabled(haveDevice || havePixelsSelected || haveShapesSelected); m_cut->setEnabled(havePixelsSelected || haveShapesSelected); m_copy->setEnabled(havePixelsSelected || haveShapesSelected); m_paste->setEnabled(havePixelsInClipboard || haveShapesInClipboard); m_pasteAt->setEnabled(havePixelsInClipboard || haveShapesInClipboard); // FIXME: how about pasting shapes? m_pasteNew->setEnabled(havePixelsInClipboard); m_selectAll->setEnabled(true); m_deselect->setEnabled(canDeselect); m_reselect->setEnabled(canReselect); // m_load->setEnabled(true); // m_save->setEnabled(havePixelsSelected); updateStatusBar(); emit signalUpdateGUI(); } void KisSelectionManager::updateStatusBar() { if (m_view && m_view->statusBar()) { m_view->statusBar()->setSelection(m_view->image()); } } void KisSelectionManager::selectionChanged() { m_view->updateGUI(); emit currentSelectionChanged(); } void KisSelectionManager::cut() { KisCutCopyActionFactory factory; factory.run(true, false, m_view); } void KisSelectionManager::copy() { KisCutCopyActionFactory factory; factory.run(false, false, m_view); } void KisSelectionManager::cutSharp() { KisCutCopyActionFactory factory; factory.run(true, true, m_view); } void KisSelectionManager::copySharp() { KisCutCopyActionFactory factory; factory.run(false, true, m_view); } void KisSelectionManager::copyMerged() { KisCopyMergedActionFactory factory; factory.run(m_view); } void KisSelectionManager::paste() { KisPasteActionFactory factory; factory.run(false, m_view); } void KisSelectionManager::pasteAt() { KisPasteActionFactory factory; factory.run(true, m_view); } void KisSelectionManager::pasteNew() { KisPasteNewActionFactory factory; factory.run(m_view); } void KisSelectionManager::selectAll() { KisSelectAllActionFactory factory; factory.run(m_view); } void KisSelectionManager::deselect() { KisDeselectActionFactory factory; factory.run(m_view); } void KisSelectionManager::invert() { if(m_invert) m_invert->trigger(); } void KisSelectionManager::reselect() { KisReselectActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertToVectorSelection() { KisSelectionToVectorActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertShapesToVectorSelection() { KisShapesToVectorSelectionActionFactory factory; factory.run(m_view); } void KisSelectionManager::convertToShape() { KisSelectionToShapeActionFactory factory; factory.run(m_view); } void KisSelectionManager::clear() { KisClearActionFactory factory; factory.run(m_view); } void KisSelectionManager::fillForegroundColor() { KisFillActionFactory factory; factory.run("fg", m_view); } void KisSelectionManager::fillBackgroundColor() { KisFillActionFactory factory; factory.run("bg", m_view); } void KisSelectionManager::fillPattern() { KisFillActionFactory factory; factory.run("pattern", m_view); } void KisSelectionManager::fillForegroundColorOpacity() { KisFillActionFactory factory; factory.run("fg_opacity", m_view); } void KisSelectionManager::fillBackgroundColorOpacity() { KisFillActionFactory factory; factory.run("bg_opacity", m_view); } void KisSelectionManager::fillPatternOpacity() { KisFillActionFactory factory; factory.run("pattern_opacity", m_view); } void KisSelectionManager::copySelectionToNewLayer() { copy(); paste(); } void KisSelectionManager::cutToNewLayer() { cut(); paste(); } void KisSelectionManager::toggleDisplaySelection() { KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration); m_selectionDecoration->toggleVisibility(); m_toggleDisplaySelection->blockSignals(true); m_toggleDisplaySelection->setChecked(m_selectionDecoration->visible()); m_toggleDisplaySelection->blockSignals(false); emit displaySelectionChanged(); } bool KisSelectionManager::displaySelection() { return m_toggleDisplaySelection->isChecked(); } void KisSelectionManager::shapeSelectionChanged() { KoShapeManager* shapeManager = m_view->canvasBase()->globalShapeManager(); KoSelection * selection = shapeManager->selection(); QList selectedShapes = selection->selectedShapes(); KoShapeStrokeSP border(new KoShapeStroke(0, Qt::lightGray)); Q_FOREACH (KoShape* shape, shapeManager->shapes()) { if (dynamic_cast(shape->parent())) { if (selectedShapes.contains(shape)) shape->setStroke(border); else shape->setStroke(KoShapeStrokeSP()); } } m_view->updateGUI(); } void KisSelectionManager::imageResizeToSelection() { KisImageResizeToSelectionActionFactory factory; factory.run(m_view); } void KisSelectionManager::paintSelectedShapes() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = m_view->activeLayer(); if (!layer) return; QList shapes = m_view->canvasBase()->shapeManager()->selection()->selectedShapes(); KisPaintLayerSP paintLayer = new KisPaintLayer(image, i18n("Stroked Shapes"), OPACITY_OPAQUE_U8); KUndo2MagicString actionName = kundo2_i18n("Stroke Shapes"); m_adapter->beginMacro(actionName); m_adapter->addNode(paintLayer.data(), layer->parent().data(), layer.data()); KisFigurePaintingToolHelper helper(actionName, image, paintLayer.data(), m_view->resourceProvider()->resourceManager(), KisPainter::StrokeStyleBrush, KisPainter::FillStyleNone); Q_FOREACH (KoShape* shape, shapes) { QTransform matrix = shape->absoluteTransformation(0) * QTransform::fromScale(image->xRes(), image->yRes()); QPainterPath mapedOutline = matrix.map(shape->outline()); helper.paintPainterPath(mapedOutline); } m_adapter->endMacro(); } void KisSelectionManager::slotToggleSelectionDecoration() { KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration); KisSelectionDecoration::Mode mode = m_selectionDecoration->mode() ? KisSelectionDecoration::Ants : KisSelectionDecoration::Mask; m_selectionDecoration->setMode(mode); emit displaySelectionChanged(); } bool KisSelectionManager::showSelectionAsMask() const { if (m_selectionDecoration) { return m_selectionDecoration->mode() == KisSelectionDecoration::Mask; } return false; } void KisSelectionManager::slotStrokeSelection() { KisImageWSP image = m_view->image(); if (!image ) { return; } KisNodeSP currentNode = m_view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); bool isVectorLayer = false; if (currentNode->inherits("KisShapeLayer")) { isVectorLayer = true; } QPointer dlg = new KisDlgStrokeSelection(image, m_view, isVectorLayer); if (dlg->exec() == QDialog::Accepted) { StrokeSelectionOptions params = dlg->getParams(); if (params.brushSelected){ KisStrokeBrushSelectionActionFactory factory; factory.run(m_view, params); } else { KisStrokeSelectionActionFactory factory; factory.run(m_view, params); } } delete dlg; } diff --git a/libs/ui/recorder/kis_node_query_path_editor.cc b/libs/ui/recorder/kis_node_query_path_editor.cc deleted file mode 100644 index 36db465c7a..0000000000 --- a/libs/ui/recorder/kis_node_query_path_editor.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_node_query_path_editor.h" - -#include "ui_wdgnodequerypatheditor.h" -#include -#include -#include - -struct KisNodeQueryPathEditor::Private -{ - Ui_WdgNodeQueryPathEditor form; -}; - -KisNodeQueryPathEditor::KisNodeQueryPathEditor(QWidget* parent) : QWidget(parent), d(new Private) -{ - d->form.setupUi(this); - - connect(d->form.radioButtonCurrentLayer, SIGNAL(clicked(bool)), SLOT(currentLayerEnabled(bool))); - connect(d->form.radioButtonCustomPath, SIGNAL(clicked(bool)), SLOT(customPathEnabled(bool))); - - d->form.kpushbutton->setIcon(KisIconUtils::loadIcon("system-help")); - connect(d->form.kpushbutton, SIGNAL(clicked()), this, SLOT(slotPopupQuickHelp())); - currentLayerEnabled(true); - - connect(d->form.klineeditPath, SIGNAL(textChanged(QString)), SIGNAL(nodeQueryPathChanged())); -} - -KisNodeQueryPathEditor::~KisNodeQueryPathEditor() -{ - delete d; -} - -void KisNodeQueryPathEditor::setNodeQueryPath(const KisNodeQueryPath& path) -{ - if(path.toString() == ".") - { - d->form.radioButtonCurrentLayer->setChecked(true); - currentLayerEnabled(true); - } else { - d->form.radioButtonCustomPath->setChecked(true); - customPathEnabled(true); - d->form.klineeditPath->setText(path.toString()); - } -} - -KisNodeQueryPath KisNodeQueryPathEditor::nodeQueryPath() const -{ - return KisNodeQueryPath::fromString(d->form.klineeditPath->text()); -} - -void KisNodeQueryPathEditor::currentLayerEnabled(bool v) -{ - if(!v) return; - d->form.klineeditPath->setEnabled(false); - d->form.kpushbutton->setEnabled(false); - d->form.klineeditPath->setText("."); -} - -void KisNodeQueryPathEditor::customPathEnabled(bool v) -{ - if(!v) return; - d->form.klineeditPath->setEnabled(true); - d->form.kpushbutton->setEnabled(true); -} - -void KisNodeQueryPathEditor::slotPopupQuickHelp() -{ - QWhatsThis::showText(QCursor::pos(), i18n( - "/ represents the root of the image, or a separator
\n" - "a number represents a layer
\n" - ". represents the current layer
\n" - ".. represents the parent layer
\n\n" - "Examples:
\n" - "/0 represents the bottom layer of the image
\n" - "../1 represents the second layer from the bottom of the parent of the current layer
\n" - "./0 represents the first child of the current layer" ) ); -} - diff --git a/libs/ui/recorder/kis_node_query_path_editor.h b/libs/ui/recorder/kis_node_query_path_editor.h deleted file mode 100644 index cfea6ea7b5..0000000000 --- a/libs/ui/recorder/kis_node_query_path_editor.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_NODE_QUERY_PATH_EDITOR_H_ -#define _KIS_NODE_QUERY_PATH_EDITOR_H_ - -#include - -class KisNodeQueryPath; -/** - * This class is used to edit @ref KisNodeQueryPath - */ -class KisNodeQueryPathEditor : public QWidget -{ - Q_OBJECT -public: - KisNodeQueryPathEditor(QWidget* parent); - ~KisNodeQueryPathEditor() override; - void setNodeQueryPath(const KisNodeQueryPath& path); - /** - * Generate a node query path based on the state of the widgets - */ - KisNodeQueryPath nodeQueryPath() const; -Q_SIGNALS: - void nodeQueryPathChanged(); -private Q_SLOTS: - void currentLayerEnabled(bool v); - void customPathEnabled(bool v); - void slotPopupQuickHelp(); -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_action_creator.cc b/libs/ui/recorder/kis_recorded_action_creator.cc deleted file mode 100644 index 20157d4fbc..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_creator.h" - -KisRecordedActionCreator::KisRecordedActionCreator(QWidget* parent, Qt::WindowFlags f) - : QWidget(parent, f) - , d(0) -{ -} - -KisRecordedActionCreator::~KisRecordedActionCreator() -{ - // delete d; -} - diff --git a/libs/ui/recorder/kis_recorded_action_creator.h b/libs/ui/recorder/kis_recorded_action_creator.h deleted file mode 100644 index bf3677f2e8..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef KIS_RECORDED_ACTION_CREATOR -#define KIS_RECORDED_ACTION_CREATOR -#include - -class KisRecordedAction; - -class KisRecordedActionCreator : public QWidget { -public: - explicit KisRecordedActionCreator(QWidget* parent = 0, Qt::WindowFlags f = 0); - ~KisRecordedActionCreator() override; - /** - * This function is called when the dialog is closed and the action has to be created - * from the parameters in the widget. - */ - virtual KisRecordedAction* createAction() const = 0; -private: - struct Private; - Private * const d; -}; - - -#endif diff --git a/libs/ui/recorder/kis_recorded_action_creator_factory.cc b/libs/ui/recorder/kis_recorded_action_creator_factory.cc deleted file mode 100644 index afd9f8f966..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator_factory.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2009,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_creator_factory.h" - -#include - -struct KisRecordedActionCreatorFactory::Private { - QString id; - QString name; -}; - -KisRecordedActionCreatorFactory::KisRecordedActionCreatorFactory(const QString& _id, const QString& _name) : d(new Private) -{ - d->id = _id; - d->name = _name; -} - -KisRecordedActionCreatorFactory::~KisRecordedActionCreatorFactory() -{ - delete d; -} - -QString KisRecordedActionCreatorFactory::id() const -{ - return d->id; -} - -QString KisRecordedActionCreatorFactory::name() const -{ - return d->name; -} - -KisRecordedActionCreator* KisRecordedActionCreatorFactory::createCreator(QWidget* /*parent*/) const -{ - Q_ASSERT(requireCreator() == false); - return 0; -} - -KisRecordedAction* KisRecordedActionCreatorFactory::createAction() const -{ - Q_ASSERT(requireCreator() == true); - return 0; -} diff --git a/libs/ui/recorder/kis_recorded_action_creator_factory.h b/libs/ui/recorder/kis_recorded_action_creator_factory.h deleted file mode 100644 index cd2d17c683..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator_factory.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2009,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_CREATOR_FACTORY_H_ -#define _KIS_RECORDED_ACTION_CREATOR_FACTORY_H_ - -#include - -class KisRecordedAction; -class KisRecordedActionCreator; -class QString; -class QWidget; - -/** - * This class allows to create widgets that are used to create new actions. - */ -class KRITAUI_EXPORT KisRecordedActionCreatorFactory -{ -public: - KisRecordedActionCreatorFactory(const QString& _id, const QString& _name); - virtual ~KisRecordedActionCreatorFactory(); - QString id() const; - QString name() const; - /** - * @return true if the creation of this action require the use of a creator widget - */ - virtual bool requireCreator() const = 0; - /** - * Create an creator for the action. - */ - virtual KisRecordedActionCreator* createCreator(QWidget* parent) const; - /** - * Create an action. If the action require a creator, it should return 0. - */ - virtual KisRecordedAction* createAction() const; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_action_creator_factory_registry.cc b/libs/ui/recorder/kis_recorded_action_creator_factory_registry.cc deleted file mode 100644 index ab0e0f8762..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator_factory_registry.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2009,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_creator_factory_registry.h" - -#include - -#include -#include -#include -#include - -#include -#include "kis_recorded_action_creator_factory.h" -#include "kis_recorded_filter_action_creator.h" - -Q_GLOBAL_STATIC(KisRecordedActionCreatorFactoryRegistry, s_instance) - -struct KisRecordedActionCreatorFactoryRegistry::Private { - KoGenericRegistry factories; -}; - -KisRecordedActionCreatorFactoryRegistry::KisRecordedActionCreatorFactoryRegistry() - : d(new Private) -{ - add(new KisRecordedFilterActionCreatorFactory); -} - -KisRecordedActionCreatorFactoryRegistry::~KisRecordedActionCreatorFactoryRegistry() -{ - delete d; -} - -KisRecordedActionCreatorFactoryRegistry* KisRecordedActionCreatorFactoryRegistry::instance() -{ - return s_instance; -} - -void KisRecordedActionCreatorFactoryRegistry::add(KisRecordedActionCreatorFactory* factory) -{ - d->factories.add(factory); -} - -KisRecordedActionCreatorFactory* KisRecordedActionCreatorFactoryRegistry::get(const QString& _id) const -{ - return d->factories.get(_id); -} - -QList KisRecordedActionCreatorFactoryRegistry::creators() const -{ - QList cs; - Q_FOREACH (const QString &id, d->factories.keys()) - { - cs.push_back(KoID(id, d->factories.get(id)->name())); - } - return cs; -} diff --git a/libs/ui/recorder/kis_recorded_action_creator_factory_registry.h b/libs/ui/recorder/kis_recorded_action_creator_factory_registry.h deleted file mode 100644 index 5e1e4c48b2..0000000000 --- a/libs/ui/recorder/kis_recorded_action_creator_factory_registry.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2009,2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_CREATOR_FACTORY_REGISTRY_H_ -#define _KIS_RECORDED_ACTION_CREATOR_FACTORY_REGISTRY_H_ - -#include -#include - -class KisRecordedActionCreatorFactory; - -/** - * This class allow to create a creator for a specific recorded action. - * - */ -class KRITAUI_EXPORT KisRecordedActionCreatorFactoryRegistry -{ -public: - KisRecordedActionCreatorFactoryRegistry(); - ~KisRecordedActionCreatorFactoryRegistry(); - static KisRecordedActionCreatorFactoryRegistry* instance(); - /** - * Add a factory of action creator. - */ - void add(KisRecordedActionCreatorFactory* factory); - /** - * @return an creator for the given action, or a null pointer if there is - * no factory for that action. - */ - KisRecordedActionCreatorFactory* get(const QString& _id) const; - /** - * @return the list of creators - */ - QList creators() const; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_action_editor_factory.cc b/libs/ui/recorder/kis_recorded_action_editor_factory.cc deleted file mode 100644 index dc46c9a735..0000000000 --- a/libs/ui/recorder/kis_recorded_action_editor_factory.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_editor_factory.h" - -struct KisRecordedActionEditorFactory::Private { - -}; - -KisRecordedActionEditorFactory::KisRecordedActionEditorFactory() : d(new Private) -{ -} - -KisRecordedActionEditorFactory::~KisRecordedActionEditorFactory() -{ - delete d; -} diff --git a/libs/ui/recorder/kis_recorded_action_editor_factory.h b/libs/ui/recorder/kis_recorded_action_editor_factory.h deleted file mode 100644 index 1c906569a6..0000000000 --- a/libs/ui/recorder/kis_recorded_action_editor_factory.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_EDITOR_FACTORY_H_ -#define _KIS_RECORDED_ACTION_EDITOR_FACTORY_H_ - -#include - -class QWidget; -class KisRecordedAction; - -/** - * This class allow to create widget that can edit a @ref KisRecordedAction - */ -class KRITAUI_EXPORT KisRecordedActionEditorFactory -{ -public: - KisRecordedActionEditorFactory(); - virtual ~KisRecordedActionEditorFactory(); - /** - * Create an editor for the action. - * The widget is expected to have a 'actionChanged' signal that is emitted - * when the editor has changed one of the parameter of the action. - */ - virtual QWidget* createEditor(QWidget* parent, KisRecordedAction* action) const = 0; - /** - * @return true if this factory can create an editor for the given action. - */ - virtual bool canEdit(const KisRecordedAction* action) const = 0; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_action_editor_factory_registry.cc b/libs/ui/recorder/kis_recorded_action_editor_factory_registry.cc deleted file mode 100644 index 14e6d2f409..0000000000 --- a/libs/ui/recorder/kis_recorded_action_editor_factory_registry.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_editor_factory_registry.h" - -#include -#include -#include -#include - -#include -#include "kis_recorded_action_editor_factory.h" -#include "kis_recorded_filter_action_editor.h" -#include "kis_recorded_paint_action_editor.h" - -Q_GLOBAL_STATIC(KisRecordedActionEditorFactoryRegistry, s_instance) - -struct KisRecordedActionEditorFactoryRegistry::Private { - QList< KisRecordedActionEditorFactory* > factories; -}; - -KisRecordedActionEditorFactoryRegistry::KisRecordedActionEditorFactoryRegistry() - : d(new Private) -{ - add(new KisRecordedFilterActionEditorFactory); - add(new KisRecordedPaintActionEditorFactory); -} - -KisRecordedActionEditorFactoryRegistry::~KisRecordedActionEditorFactoryRegistry() -{ - dbgRegistry << "Deleting KisRecordedActionEditorFactoryRegistry"; - qDeleteAll(d->factories); - delete d; -} - -KisRecordedActionEditorFactoryRegistry* KisRecordedActionEditorFactoryRegistry::instance() -{ - return s_instance; -} - -void KisRecordedActionEditorFactoryRegistry::add(KisRecordedActionEditorFactory* factory) -{ - if (d->factories.contains(factory)) return; - d->factories.push_front(factory); -} - -QWidget* KisRecordedActionEditorFactoryRegistry::createEditor(QWidget* parent, KisRecordedAction* action) const -{ - Q_FOREACH (KisRecordedActionEditorFactory* factory, d->factories) { - if (factory->canEdit(action)) { - QWidget* editor = factory->createEditor(parent, action); - Q_ASSERT(editor); - Q_ASSERT(editor->metaObject()->indexOfSignal("actionEdited()") != -1); - return editor; - } - } - return 0; -} - -bool KisRecordedActionEditorFactoryRegistry::hasEditor(KisRecordedAction* action) const -{ - Q_FOREACH (KisRecordedActionEditorFactory* factory, d->factories) { - if (factory->canEdit(action)) { - return true; - } - } - return false; -} diff --git a/libs/ui/recorder/kis_recorded_action_editor_factory_registry.h b/libs/ui/recorder/kis_recorded_action_editor_factory_registry.h deleted file mode 100644 index a5279d1fdf..0000000000 --- a/libs/ui/recorder/kis_recorded_action_editor_factory_registry.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_EDITOR_FACTORY_REGISTRY_H_ -#define _KIS_RECORDED_ACTION_EDITOR_FACTORY_REGISTRY_H_ - -#include - -class QWidget; -class KisRecordedAction; -class KisRecordedActionEditorFactory; - -/** - * This class allow to create an editor for a specific recorded action. - * - * If two editors can edit the same type of action, then the editor that - * was added last is used in priority. - */ -class KRITAUI_EXPORT KisRecordedActionEditorFactoryRegistry -{ -public: - KisRecordedActionEditorFactoryRegistry(); - ~KisRecordedActionEditorFactoryRegistry(); - static KisRecordedActionEditorFactoryRegistry* instance(); - /** - * Add a factory of action editor. - */ - void add(KisRecordedActionEditorFactory* factory); - /** - * @return an editor for the given action, or a null pointer if there is - * no factory for that action. - */ - QWidget* createEditor(QWidget* parent, KisRecordedAction* action) const; - /** - * @return true if there is an editor for this action. - */ - bool hasEditor(KisRecordedAction* action) const; -private: - struct Private; - Private* const d; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_filter_action_creator.cpp b/libs/ui/recorder/kis_recorded_filter_action_creator.cpp deleted file mode 100644 index fcdf6d4ef5..0000000000 --- a/libs/ui/recorder/kis_recorded_filter_action_creator.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_filter_action_creator.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -KisRecordedFilterActionCreator::KisRecordedFilterActionCreator(QWidget* parent , Qt::WindowFlags f) - : KisRecordedActionCreator(parent, f) -{ - m_filterModel = new KisFiltersModel(true, 0); - m_filterTree = new QTreeView(this); - m_filterTree->setModel(m_filterModel); - m_filterTree->header()->setVisible(false); - QGridLayout* layout = new QGridLayout(); - setLayout(layout); - layout->addWidget(m_filterTree, 0, 0, 1, 1); -} - -KisRecordedFilterActionCreator::~KisRecordedFilterActionCreator() -{ - delete m_filterTree; - delete m_filterModel; -} - -KisRecordedAction* KisRecordedFilterActionCreator::createAction() const -{ - const KisFilter* filter = m_filterModel->indexToFilter(m_filterTree->currentIndex()); - if(!filter) return 0; - return new KisRecordedFilterAction(filter->name(), KisNodeQueryPath::fromString(""), filter, filter->defaultConfiguration()); -} - - -KisRecordedFilterActionCreatorFactory::KisRecordedFilterActionCreatorFactory() - : KisRecordedActionCreatorFactory("filter", i18nc("recorded filter action", "Apply Filter")) -{ -} - -KisRecordedFilterActionCreatorFactory::~KisRecordedFilterActionCreatorFactory() -{ -} - -bool KisRecordedFilterActionCreatorFactory::requireCreator() const -{ - return true; -} - -KisRecordedActionCreator* KisRecordedFilterActionCreatorFactory::createCreator(QWidget* parent) const -{ - return new KisRecordedFilterActionCreator(parent); -} diff --git a/libs/ui/recorder/kis_recorded_filter_action_creator.h b/libs/ui/recorder/kis_recorded_filter_action_creator.h deleted file mode 100644 index d329ea238c..0000000000 --- a/libs/ui/recorder/kis_recorded_filter_action_creator.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2011 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_FILTER_ACTION_CREATOR_FACTORY_H_ -#define _KIS_RECORDED_FILTER_ACTION_CREATOR_FACTORY_H_ - -#include "kis_recorded_action_creator.h" -#include "kis_recorded_action_creator_factory.h" - -class KisFiltersModel; -class QTreeView; - -class KisRecordedFilterActionCreator : public KisRecordedActionCreator { -public: - explicit KisRecordedFilterActionCreator(QWidget* parent = 0, Qt::WindowFlags f = 0); - ~KisRecordedFilterActionCreator() override; - KisRecordedAction* createAction() const override; -private: - KisFiltersModel* m_filterModel; - QTreeView* m_filterTree; -}; - -/** - * This class allows to create widgets that are used to create new actions. - */ -class KisRecordedFilterActionCreatorFactory : public KisRecordedActionCreatorFactory -{ -public: - KisRecordedFilterActionCreatorFactory(); - ~KisRecordedFilterActionCreatorFactory() override; - bool requireCreator() const override; - KisRecordedActionCreator* createCreator(QWidget* parent) const override; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_filter_action_editor.cc b/libs/ui/recorder/kis_recorded_filter_action_editor.cc deleted file mode 100644 index 82a39ae679..0000000000 --- a/libs/ui/recorder/kis_recorded_filter_action_editor.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#include -#include "kis_recorded_filter_action_editor.h" -#include -#include -#include -#include -#include -#include -#include -#include "kis_node_query_path_editor.h" -#include -#include - -KisRecordedFilterActionEditor::KisRecordedFilterActionEditor(QWidget* parent, KisRecordedAction* action) - : QWidget(parent) - , m_action(dynamic_cast(action)) - , m_gridLayout(new QGridLayout(this)) -{ - Q_ASSERT(m_action); - - // Create the node query path editor - m_nodeQueryPathEditor = new KisNodeQueryPathEditor(this); - m_nodeQueryPathEditor->setNodeQueryPath(m_action->nodeQueryPath()); - connect(m_nodeQueryPathEditor, SIGNAL(nodeQueryPathChanged()), SLOT(nodeQueryPathChanged())); - m_gridLayout->addWidget(m_nodeQueryPathEditor, 1, 0); - - // Create the filter editor - m_configWidget = m_action->filter()->createConfigurationWidget(this, new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8())); - if (m_configWidget) { - m_gridLayout->addWidget(m_configWidget); - - // FIXME: pass the view object to the config widget - //m_configWidget->setView(view); - - m_configWidget->setConfiguration(m_action->filterConfiguration()); - connect(m_configWidget, SIGNAL(sigConfigurationItemChanged()), SLOT(configurationUpdated())); - } else { - m_gridLayout->addWidget(new QLabel(i18n("No configuration option."), this)); - } -} - -KisRecordedFilterActionEditor::~KisRecordedFilterActionEditor() -{ -} - -void KisRecordedFilterActionEditor::configurationUpdated() -{ - KisFilterConfigurationSP config = dynamic_cast(m_configWidget->configuration().data()); - if (config) { - m_action->setFilterConfiguration(config); - emit(actionEdited()); - } -} - -void KisRecordedFilterActionEditor::nodeQueryPathChanged() -{ - m_action->setNodeQueryPath(m_nodeQueryPathEditor->nodeQueryPath()); - emit(actionEdited()); -} - -KisRecordedFilterActionEditorFactory::KisRecordedFilterActionEditorFactory() -{ -} - -KisRecordedFilterActionEditorFactory::~KisRecordedFilterActionEditorFactory() -{ -} - -QWidget* KisRecordedFilterActionEditorFactory::createEditor(QWidget* parent, KisRecordedAction* action) const -{ - return new KisRecordedFilterActionEditor(parent, action); -} - -bool KisRecordedFilterActionEditorFactory::canEdit(const KisRecordedAction* action) const -{ - return action->id() == "FilterAction"; -} - diff --git a/libs/ui/recorder/kis_recorded_filter_action_editor.h b/libs/ui/recorder/kis_recorded_filter_action_editor.h deleted file mode 100644 index 3f034bacae..0000000000 --- a/libs/ui/recorder/kis_recorded_filter_action_editor.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_FILTER_ACTION_EDITOR_H_ -#define _KIS_RECORDED_FILTER_ACTION_EDITOR_H_ - -#include -#include "kis_recorded_action_editor_factory.h" - -class KisNodeQueryPathEditor; -class KisRecordedFilterAction; -class QGridLayout; -class KisConfigWidget; - -class KisRecordedFilterActionEditor : public QWidget -{ - Q_OBJECT -public: - KisRecordedFilterActionEditor(QWidget* parent, KisRecordedAction* action); - ~KisRecordedFilterActionEditor() override; -private Q_SLOTS: - void configurationUpdated(); - void nodeQueryPathChanged(); -Q_SIGNALS: - void actionEdited(); -private: - KisRecordedFilterAction* m_action; - QGridLayout* m_gridLayout; - KisConfigWidget* m_configWidget; - KisNodeQueryPathEditor* m_nodeQueryPathEditor; -}; - -class KisRecordedFilterActionEditorFactory : public KisRecordedActionEditorFactory -{ -public: - KisRecordedFilterActionEditorFactory(); - ~KisRecordedFilterActionEditorFactory() override; - QWidget* createEditor(QWidget* parent, KisRecordedAction* action) const override; - bool canEdit(const KisRecordedAction* action) const override; -}; - -#endif diff --git a/libs/ui/recorder/kis_recorded_paint_action_editor.cc b/libs/ui/recorder/kis_recorded_paint_action_editor.cc deleted file mode 100644 index d18e2b59e6..0000000000 --- a/libs/ui/recorder/kis_recorded_paint_action_editor.cc +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_paint_action_editor.h" - -#include -#include - -#include - -#include "recorder/kis_recorded_paint_action.h" -#include -#include -#include - -#include "ui_wdgpaintactioneditor.h" -#include -#include -#include "kis_node_query_path_editor.h" -#include - -KisRecordedPaintActionEditor::KisRecordedPaintActionEditor(QWidget* parent, KisRecordedAction* action) : QWidget(parent), - m_action(dynamic_cast(action)), - m_actionEditor(new Ui_WdgPaintActionEditor), - m_configWidget(0) -{ - Q_ASSERT(m_action); - m_actionEditor->setupUi(this); - - // Setup paint color editor - m_actionEditor->paintColor->setColor(m_action->paintColor()); - connect(m_actionEditor->paintColor, SIGNAL(changed(KoColor)), - this, SLOT(configurationUpdated())); - - // Setup background color editor - m_actionEditor->backgroundColor->setColor(m_action->backgroundColor()); - connect(m_actionEditor->backgroundColor, SIGNAL(changed(KoColor)), - this, SLOT(configurationUpdated())); - - // Setup opacity - m_actionEditor->opacity->setValue(m_action->opacity() * 100.0); - connect(m_actionEditor->opacity, SIGNAL(valueChanged(int)), SLOT(configurationUpdated())); - - // Setup paint ops - - QList keys = KisPaintOpRegistry::instance()->listKeys(); - Q_FOREACH (const KoID& paintopId, keys) { - QIcon pm = KisPaintOpRegistry::instance()->icon(paintopId); - - m_actionEditor->paintOps->addItem(pm, paintopId.name()); - m_paintops.append(paintopId.id()); - } - connect(m_actionEditor->paintOps, SIGNAL(activated(int)), SLOT(paintOpChanged(int))); - - // Setup configuration widget for paint op settings - m_gridLayout = new QGridLayout(m_actionEditor->frmOptionWidgetContainer); - setPaintOpPreset(); - m_actionEditor->paintOps->setCurrentIndex(m_paintops.indexOf(m_action->paintOpPreset()->paintOp().id())); - m_paintOpsToPreset[m_action->paintOpPreset()->paintOp().id()] = m_action->paintOpPreset(); - connect(m_actionEditor->wdgPresetChooser, SIGNAL(resourceSelected(KoResource*)), SLOT(resourceSelected(KoResource*))); - - // Setup the query path editor - m_actionEditor->nodeQueryPathEditor->setNodeQueryPath(m_action->nodeQueryPath()); - connect(m_actionEditor->nodeQueryPathEditor, SIGNAL(nodeQueryPathChanged()), SLOT(nodeQueryPathChanged())); - -} - -KisRecordedPaintActionEditor::~KisRecordedPaintActionEditor() -{ - delete m_actionEditor; -} - -void KisRecordedPaintActionEditor::configurationUpdated() -{ - m_configWidget->writeConfigurationSafe(const_cast(m_action->paintOpPreset()->settings().data())); - - m_action->setPaintColor(m_actionEditor->paintColor->color()); - m_action->setBackgroundColor(m_actionEditor->backgroundColor->color()); - m_action->setOpacity(m_actionEditor->opacity->value() / qreal(100.0)); - - emit(actionEdited()); -} - -void KisRecordedPaintActionEditor::paintOpChanged(int index) -{ - QString id = m_paintops[index]; - KisPaintOpPresetSP preset = m_paintOpsToPreset[id]; - if (!preset) { - preset = KisPaintOpRegistry::instance()->defaultPreset(KoID(id, "")); - m_paintOpsToPreset[id] = preset; - } - m_action->setPaintOpPreset(preset); - setPaintOpPreset(); -} - -void KisRecordedPaintActionEditor::resourceSelected(KoResource* resource) -{ - KisPaintOpPresetSP preset = static_cast(resource); - - m_paintOpsToPreset[preset->paintOp().id()] = preset; - m_action->setPaintOpPreset(preset); - setPaintOpPreset(); -} - -void KisRecordedPaintActionEditor::nodeQueryPathChanged() -{ - m_action->setNodeQueryPath(m_actionEditor->nodeQueryPathEditor->nodeQueryPath()); - emit(actionEdited()); -} - - -void KisRecordedPaintActionEditor::setPaintOpPreset() -{ - delete m_configWidget; - m_configWidget = KisPaintOpRegistry::instance()->get(m_action->paintOpPreset()->paintOp().id())->createConfigWidget(m_actionEditor->frmOptionWidgetContainer); - if (m_configWidget) { - m_gridLayout->addWidget(m_configWidget); - //TODO use default configuration instead? - //m_configWidget->setConfiguration(m_action->paintOpPreset()->settings()); - connect(m_configWidget, SIGNAL(sigConfigurationUpdated()), SLOT(configurationUpdated())); - } else { - m_gridLayout->addWidget(new QLabel(i18n("No configuration option."), this)); - } -} - -KisRecordedPaintActionEditorFactory::KisRecordedPaintActionEditorFactory() -{ -} - -KisRecordedPaintActionEditorFactory::~KisRecordedPaintActionEditorFactory() -{ -} - -QWidget* KisRecordedPaintActionEditorFactory::createEditor(QWidget* parent, KisRecordedAction* action) const -{ - return new KisRecordedPaintActionEditor(parent, action); -} - -bool KisRecordedPaintActionEditorFactory::canEdit(const KisRecordedAction* action) const -{ - return dynamic_cast(action); -} - diff --git a/libs/ui/recorder/kis_recorded_paint_action_editor.h b/libs/ui/recorder/kis_recorded_paint_action_editor.h deleted file mode 100644 index 5eeaaf79a4..0000000000 --- a/libs/ui/recorder/kis_recorded_paint_action_editor.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2010 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_PAINT_ACTION_EDITOR_H_ -#define _KIS_RECORDED_PAINT_ACTION_EDITOR_H_ - -#include -#include "kis_recorded_action_editor_factory.h" -#include "kis_types.h" - -class QGridLayout; -class KoColorPopupAction; -class KisPaintOpConfigWidget; -class KisRecordedPaintAction; -class Ui_WdgPaintActionEditor; -class KoResource; - -/** - * This is the editor for all \ref KisRecordedPaintAction - */ -class KisRecordedPaintActionEditor : public QWidget -{ - Q_OBJECT -public: - KisRecordedPaintActionEditor(QWidget* parent, KisRecordedAction* action); - ~KisRecordedPaintActionEditor() override; -private Q_SLOTS: - void configurationUpdated(); - void paintOpChanged(int index); - void resourceSelected(KoResource* resource); - void nodeQueryPathChanged(); -Q_SIGNALS: - void actionEdited(); -private: - void setPaintOpPreset(); - KisRecordedPaintAction* m_action; - Ui_WdgPaintActionEditor* m_actionEditor; - KisPaintOpConfigWidget* m_configWidget; - QGridLayout* m_gridLayout; - QList m_paintops; - QMap m_paintOpsToPreset; -}; - -class KisRecordedPaintActionEditorFactory : public KisRecordedActionEditorFactory -{ -public: - KisRecordedPaintActionEditorFactory(); - ~KisRecordedPaintActionEditorFactory() override; - QWidget* createEditor(QWidget* parent, KisRecordedAction* action) const override; - bool canEdit(const KisRecordedAction* action) const override; -}; - -#endif diff --git a/libs/ui/tests/CMakeLists.txt b/libs/ui/tests/CMakeLists.txt index 148486fa22..df77a02ec9 100644 --- a/libs/ui/tests/CMakeLists.txt +++ b/libs/ui/tests/CMakeLists.txt @@ -1,185 +1,184 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) #add_subdirectory(scratchpad) include_directories(${CMAKE_SOURCE_DIR}/libs/image/metadata ${CMAKE_SOURCE_DIR}/sdk/tests ) include(ECMAddTests) macro_add_unittest_definitions() ecm_add_tests( kis_image_view_converter_test.cpp kis_shape_selection_test.cpp - kis_recorded_action_editor_test.cpp kis_doc2_test.cpp kis_coordinates_converter_test.cpp kis_grid_config_test.cpp kis_stabilized_events_sampler_test.cpp kis_derived_resources_test.cpp kis_brush_hud_properties_config_test.cpp kis_shape_commands_test.cpp kis_shape_layer_test.cpp kis_stop_gradient_editor_test.cpp NAME_PREFIX "krita-ui-" LINK_LIBRARIES kritaui Qt5::Test ) ecm_add_tests( kis_file_layer_test.cpp kis_multinode_property_test.cpp NAME_PREFIX "krita-ui-" LINK_LIBRARIES kritaui kritaimage Qt5::Test ) ecm_add_test( KisFrameSerializerTest.cpp TEST_NAME krita-ui-KisFrameSerializerTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( KisFrameCacheStoreTest.cpp TEST_NAME krita-ui-KisFrameCacheStoreTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_selection_decoration_test.cpp ../../../sdk/tests/stroke_testing_utils.cpp TEST_NAME krita-ui-KisSelectionDecorationTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_node_dummies_graph_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-ui-KisNodeDummiesGraphTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_node_shapes_graph_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-ui-KisNodeShapesGraphTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_model_index_converter_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-ui-KisModelIndexConverterTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_categorized_list_model_test.cpp modeltest.cpp TEST_NAME krita-ui-KisCategorizedListModelTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) ecm_add_test( kis_node_juggler_compressed_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-image-BaseNodeTest LINK_LIBRARIES kritaimage kritaui Qt5::Test) ecm_add_test( kis_animation_exporter_test.cpp TEST_NAME kritaui-animation_exporter_test LINK_LIBRARIES kritaui kritaimage Qt5::Test) set(kis_node_view_test_SRCS kis_node_view_test.cpp ../../../sdk/tests/testutil.cpp) qt5_add_resources(kis_node_view_test_SRCS ${krita_QRCS}) ecm_add_test(${kis_node_view_test_SRCS} TEST_NAME krita-image-kis_node_view_test LINK_LIBRARIES kritaimage kritaui Qt5::Test) ##### Tests that currently fail and should be fixed ##### include(KritaAddBrokenUnitTest) krita_add_broken_unit_test( kis_node_model_test.cpp modeltest.cpp TEST_NAME krita-ui-kis_node_model_test LINK_LIBRARIES kritaui Qt5::Test) krita_add_broken_unit_test( kis_shape_controller_test.cpp kis_dummies_facade_base_test.cpp TEST_NAME krita-ui-kis_shape_controller_test LINK_LIBRARIES kritaimage kritaui Qt5::Test) krita_add_broken_unit_test( kis_prescaled_projection_test.cpp TEST_NAME krita-ui-kis_prescaled_projection_test LINK_LIBRARIES kritaui Qt5::Test) krita_add_broken_unit_test( kis_exiv2_test.cpp TEST_NAME krita-ui-KisExiv2Test LINK_LIBRARIES kritaimage kritaui Qt5::Test) krita_add_broken_unit_test( kis_clipboard_test.cpp TEST_NAME krita-ui-KisClipboardTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( freehand_stroke_test.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME krita-ui-FreehandStrokeTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( FreehandStrokeBenchmark.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME krita-ui-FreehandStrokeBenchmark LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( fill_processing_visitor_test.cpp ${CMAKE_SOURCE_DIR}/sdk/tests/stroke_testing_utils.cpp TEST_NAME krita-ui-FillProcessingVisitorTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( filter_stroke_test.cpp ../../../sdk/tests/stroke_testing_utils.cpp TEST_NAME krita-ui-FilterStrokeTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_selection_manager_test.cpp TEST_NAME krita-ui-KisSelectionManagerTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) #set_tests_properties(krita-ui-KisSelectionManagerTest PROPERTIES TIMEOUT 300) krita_add_broken_unit_test( kis_node_manager_test.cpp TEST_NAME krita-ui-KisNodeManagerTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_dummies_facade_test.cpp kis_dummies_facade_base_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-ui-KisDummiesFacadeTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_zoom_and_pan_test.cpp ../../../sdk/tests/testutil.cpp TEST_NAME krita-ui-KisZoomAndPanTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) #set_tests_properties(krita-ui-KisZoomAndPanTest PROPERTIES TIMEOUT 300) krita_add_broken_unit_test( kis_action_manager_test.cpp TEST_NAME krita-ui-KisActionManagerTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_categories_mapper_test.cpp testing_categories_mapper.cpp TEST_NAME krita-ui-KisCategoriesMapperTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_asl_layer_style_serializer_test.cpp TEST_NAME krita-ui-KisAslLayerStyleSerializerTest LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_animation_importer_test.cpp TEST_NAME kritaui-animation_importer_test LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( kis_animation_frame_cache_test.cpp TEST_NAME kritaui-animation_frame_cache_test LINK_LIBRARIES kritaui kritaimage Qt5::Test) krita_add_broken_unit_test( ResourceBundleTest.cpp TEST_NAME krita-resourcemanager-ResourceBundleTest LINK_LIBRARIES kritaui kritalibbrush kritalibpaintop Qt5::Test) # FIXME this test doesn't compile #ecm_add_test( # kis_input_manager_test.cpp ../../../sdk/tests/testutil.cpp # TEST_NAME krita-ui-KisInputManagerTest # LINK_LIBRARIES kritaui kritaimage Qt5::Test) diff --git a/libs/ui/tests/kis_recorded_action_editor_test.cpp b/libs/ui/tests/kis_recorded_action_editor_test.cpp deleted file mode 100644 index 3d00ce8d40..0000000000 --- a/libs/ui/tests/kis_recorded_action_editor_test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recorded_action_editor_test.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -void KisRecordedActionEditorTest::testFilterEditorCreation() -{ - KisRecordedActionEditorFactoryRegistry* reg = KisRecordedActionEditorFactoryRegistry::instance(); - const KisFilter* blurFilter = KisFilterRegistry::instance()->get("blur"); - KisRecordedFilterAction* blurFilterAction = new KisRecordedFilterAction( - "hello", KisNodeQueryPath::fromString(""), blurFilter, blurFilter->defaultConfiguration()); - QVERIFY(reg->hasEditor(blurFilterAction)); - QVERIFY(reg->createEditor(0, blurFilterAction)); - const KisFilter* invertFilter = KisFilterRegistry::instance()->get("invert"); - KisRecordedFilterAction* invertFilterAction = new KisRecordedFilterAction( - "hello", KisNodeQueryPath::fromString(""), invertFilter, invertFilter->defaultConfiguration()); - QVERIFY(reg->hasEditor(invertFilterAction)); - QVERIFY(reg->createEditor(0, invertFilterAction)); -} - - -QTEST_MAIN(KisRecordedActionEditorTest) - diff --git a/libs/ui/tests/kis_recorded_action_editor_test.h b/libs/ui/tests/kis_recorded_action_editor_test.h deleted file mode 100644 index 74b605a0ee..0000000000 --- a/libs/ui/tests/kis_recorded_action_editor_test.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2009 Cyrille Berger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_RECORDED_ACTION_EDITOR_TEST_H_ -#define _KIS_RECORDED_ACTION_EDITOR_TEST_H_ - -#include - -class KisRecordedActionEditorTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - void testFilterEditorCreation(); -}; - -#endif diff --git a/libs/ui/tool/kis_recording_adapter.cpp b/libs/ui/tool/kis_recording_adapter.cpp deleted file mode 100644 index 41e67fa9fc..0000000000 --- a/libs/ui/tool/kis_recording_adapter.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2011 Dmitry Kazakov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "kis_recording_adapter.h" - -#include "kis_image.h" -#include "kis_node.h" -#include - -#include "recorder/kis_action_recorder.h" -#include "recorder/kis_recorded_path_paint_action.h" -#include "recorder/kis_node_query_path.h" - - -KisRecordingAdapter::KisRecordingAdapter() - : m_pathPaintAction(0) -{ -} - -KisRecordingAdapter::~KisRecordingAdapter() -{ -} - -void KisRecordingAdapter::startStroke(KisImageWSP image, KisResourcesSnapshotSP resources, - const KisDistanceInitInfo &startDistInfo) -{ - Q_ASSERT(!m_pathPaintAction); - Q_ASSERT(!m_image); - - m_image = image; - m_pathPaintAction = new KisRecordedPathPaintAction( - KisNodeQueryPath::absolutePath(resources->currentNode()), 0, startDistInfo); - - resources->setupPaintAction(m_pathPaintAction); -} - -void KisRecordingAdapter::endStroke() -{ - Q_ASSERT(m_pathPaintAction); - Q_ASSERT(m_image); - - m_image->actionRecorder()->addAction(*m_pathPaintAction); - - delete m_pathPaintAction; - m_pathPaintAction = 0; - m_image = 0; -} - - -void KisRecordingAdapter::addPoint(const KisPaintInformation &pi) -{ - KIS_SAFE_ASSERT_RECOVER_RETURN(m_pathPaintAction); - m_pathPaintAction->addPoint(pi); -} - -void KisRecordingAdapter::addLine(const KisPaintInformation &pi1, - const KisPaintInformation &pi2) -{ - KIS_SAFE_ASSERT_RECOVER_RETURN(m_pathPaintAction); - m_pathPaintAction->addLine(pi1, pi2); -} - - -void KisRecordingAdapter::addCurve(const KisPaintInformation &pi1, - const QPointF &control1, - const QPointF &control2, - const KisPaintInformation &pi2) -{ - KIS_SAFE_ASSERT_RECOVER_RETURN(m_pathPaintAction); - m_pathPaintAction->addCurve(pi1, control1, control2, pi2); -} - diff --git a/libs/ui/tool/kis_recording_adapter.h b/libs/ui/tool/kis_recording_adapter.h deleted file mode 100644 index 76b8752465..0000000000 --- a/libs/ui/tool/kis_recording_adapter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011 Dmitry Kazakov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __KIS_RECORDING_ADAPTER_H -#define __KIS_RECORDING_ADAPTER_H - -#include "kis_types.h" -#include "kis_resources_snapshot.h" - -class KisRecordedPathPaintAction; -class KisPaintInformation; -class KisDistanceInitInfo; - - -class KisRecordingAdapter -{ -public: - KisRecordingAdapter(); - ~KisRecordingAdapter(); - - void startStroke(KisImageWSP image, KisResourcesSnapshotSP resources, - const KisDistanceInitInfo &startDist); - void endStroke(); - - void addPoint(const KisPaintInformation &pi); - void addLine(const KisPaintInformation &pi1, - const KisPaintInformation &pi2); - - void addCurve(const KisPaintInformation &pi1, - const QPointF &control1, - const QPointF &control2, - const KisPaintInformation &pi2); - -private: - KisImageWSP m_image; - KisRecordedPathPaintAction *m_pathPaintAction; -}; - -#endif /* __KIS_RECORDING_ADAPTER_H */ diff --git a/libs/ui/tool/kis_resources_snapshot.cpp b/libs/ui/tool/kis_resources_snapshot.cpp index 733ef420a0..99384963f9 100644 --- a/libs/ui/tool/kis_resources_snapshot.cpp +++ b/libs/ui/tool/kis_resources_snapshot.cpp @@ -1,429 +1,410 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_resources_snapshot.h" #include #include #include #include #include #include #include #include #include "kis_canvas_resource_provider.h" #include "filter/kis_filter_configuration.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" -#include "recorder/kis_recorded_paint_action.h" #include "kis_selection.h" #include "kis_selection_mask.h" #include "kis_algebra_2d.h" struct KisResourcesSnapshot::Private { Private() : currentPattern(0) , currentGradient(0) , currentGenerator(0) , compositeOp(0) { } KisImageSP image; KisDefaultBoundsBaseSP bounds; KoColor currentFgColor; KoColor currentBgColor; KoPattern *currentPattern = 0; KoAbstractGradient *currentGradient; KisPaintOpPresetSP currentPaintOpPreset; KisNodeSP currentNode; qreal currentExposure; KisFilterConfigurationSP currentGenerator; QPointF axesCenter; bool mirrorMaskHorizontal = false; bool mirrorMaskVertical = false; quint8 opacity = OPACITY_OPAQUE_U8; QString compositeOpId = COMPOSITE_OVER; const KoCompositeOp *compositeOp; KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; KisPainter::FillStyle fillStyle = KisPainter::FillStyleForegroundColor; bool globalAlphaLock = false; qreal effectiveZoom = 1.0; bool presetAllowsLod = false; KisSelectionSP selectionOverride; }; KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceManager *resourceManager, KisDefaultBoundsBaseSP bounds) : m_d(new Private()) { m_d->image = image; if (!bounds) { bounds = new KisDefaultBounds(m_d->image); } m_d->bounds = bounds; m_d->currentFgColor = resourceManager->resource(KoCanvasResourceManager::ForegroundColor).value(); m_d->currentBgColor = resourceManager->resource(KoCanvasResourceManager::BackgroundColor).value(); m_d->currentPattern = resourceManager->resource(KisCanvasResourceProvider::CurrentPattern).value(); m_d->currentGradient = resourceManager->resource(KisCanvasResourceProvider::CurrentGradient).value(); /** * We should deep-copy the preset, so that long-runnign actions * will have correct brush parameters. Theoretically this cloniong * can be expensive, but according to measurements, it takes * something like 0.1 ms for an average preset. */ m_d->currentPaintOpPreset = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value()->clone(); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ m_d->currentExposure = resourceManager->resource(KisCanvasResourceProvider::HdrExposure).toDouble(); m_d->currentGenerator = resourceManager->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); QPointF relativeAxesCenter(0.5, 0.5); if (m_d->image) { relativeAxesCenter = m_d->image->mirrorAxesCenter(); } m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds()); m_d->mirrorMaskHorizontal = resourceManager->resource(KisCanvasResourceProvider::MirrorHorizontal).toBool(); m_d->mirrorMaskVertical = resourceManager->resource(KisCanvasResourceProvider::MirrorVertical).toBool(); qreal normOpacity = resourceManager->resource(KisCanvasResourceProvider::Opacity).toDouble(); m_d->opacity = quint8(normOpacity * OPACITY_OPAQUE_U8); m_d->compositeOpId = resourceManager->resource(KisCanvasResourceProvider::CurrentEffectiveCompositeOp).toString(); setCurrentNode(currentNode); /** * Fill and Stroke styles are not a part of the resource manager * so the tools should set them manually * TODO: port stroke and fill styles to be a part * of the resource manager */ m_d->strokeStyle = KisPainter::StrokeStyleBrush; m_d->fillStyle = KisPainter::FillStyleNone; m_d->globalAlphaLock = resourceManager->resource(KisCanvasResourceProvider::GlobalAlphaLock).toBool(); m_d->effectiveZoom = resourceManager->resource(KisCanvasResourceProvider::EffectiveZoom).toDouble(); m_d->presetAllowsLod = resourceManager->resource(KisCanvasResourceProvider::EffectiveLodAvailablility).toBool(); } KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds) : m_d(new Private()) { m_d->image = image; if (!bounds) { bounds = new KisDefaultBounds(m_d->image); } m_d->bounds = bounds; #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ QPointF relativeAxesCenter(0.5, 0.5); if (m_d->image) { relativeAxesCenter = m_d->image->mirrorAxesCenter(); } m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds()); m_d->opacity = OPACITY_OPAQUE_U8; setCurrentNode(currentNode); /** * Fill and Stroke styles are not a part of the resource manager * so the tools should set them manually * TODO: port stroke and fill styles to be a part * of the resource manager */ m_d->strokeStyle = KisPainter::StrokeStyleBrush; m_d->fillStyle = KisPainter::FillStyleNone; } KisResourcesSnapshot::~KisResourcesSnapshot() { delete m_d; } void KisResourcesSnapshot::setupPainter(KisPainter* painter) { painter->setPaintColor(m_d->currentFgColor); painter->setBackgroundColor(m_d->currentBgColor); painter->setGenerator(m_d->currentGenerator); painter->setPattern(m_d->currentPattern); painter->setGradient(m_d->currentGradient); QBitArray lockflags = channelLockFlags(); if (lockflags.size() > 0) { painter->setChannelFlags(lockflags); } painter->setOpacity(m_d->opacity); painter->setCompositeOp(m_d->compositeOp); painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical); painter->setStrokeStyle(m_d->strokeStyle); painter->setFillStyle(m_d->fillStyle); /** * The paintOp should be initialized the last, because it may * ask the painter for some options while initialization */ painter->setPaintOpPreset(m_d->currentPaintOpPreset, m_d->currentNode, m_d->image); } void KisResourcesSnapshot::setupMaskingBrushPainter(KisPainter *painter) { KIS_SAFE_ASSERT_RECOVER_RETURN(painter->device()); KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->currentPaintOpPreset->hasMaskingPreset()); painter->setPaintColor(KoColor(Qt::white, painter->device()->colorSpace())); painter->setBackgroundColor(KoColor(Qt::black, painter->device()->colorSpace())); painter->setOpacity(OPACITY_OPAQUE_U8); painter->setChannelFlags(QBitArray()); // masked brush always paints in indirect mode painter->setCompositeOp(COMPOSITE_ALPHA_DARKEN); painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical); /** * The paintOp should be initialized the last, because it may * ask the painter for some options while initialization */ painter->setPaintOpPreset(m_d->currentPaintOpPreset->createMaskingPreset(), m_d->currentNode, m_d->image); } -void KisResourcesSnapshot::setupPaintAction(KisRecordedPaintAction *action) -{ - action->setPaintOpPreset(m_d->currentPaintOpPreset); - action->setPaintIncremental(!needsIndirectPainting()); - - action->setPaintColor(m_d->currentFgColor); - action->setBackgroundColor(m_d->currentBgColor); - action->setGenerator(m_d->currentGenerator); - action->setGradient(m_d->currentGradient); - action->setPattern(m_d->currentPattern); - - action->setOpacity(m_d->opacity / qreal(OPACITY_OPAQUE_U8)); - action->setCompositeOp(m_d->compositeOp->id()); - - action->setStrokeStyle(m_d->strokeStyle); - action->setFillStyle(m_d->fillStyle); -} - KisPostExecutionUndoAdapter* KisResourcesSnapshot::postExecutionUndoAdapter() const { return m_d->image ? m_d->image->postExecutionUndoAdapter() : 0; } void KisResourcesSnapshot::setCurrentNode(KisNodeSP node) { m_d->currentNode = node; KisPaintDeviceSP device; if(m_d->currentNode && (device = m_d->currentNode->paintDevice())) { m_d->compositeOp = device->colorSpace()->compositeOp(m_d->compositeOpId); if(!m_d->compositeOp) { m_d->compositeOp = device->colorSpace()->compositeOp(COMPOSITE_OVER); } } } void KisResourcesSnapshot::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { m_d->strokeStyle = strokeStyle; } void KisResourcesSnapshot::setFillStyle(KisPainter::FillStyle fillStyle) { m_d->fillStyle = fillStyle; } KisNodeSP KisResourcesSnapshot::currentNode() const { return m_d->currentNode; } KisImageSP KisResourcesSnapshot::image() const { return m_d->image; } bool KisResourcesSnapshot::needsIndirectPainting() const { return !m_d->currentPaintOpPreset->settings()->paintIncremental(); } QString KisResourcesSnapshot::indirectPaintingCompositeOp() const { return m_d->currentPaintOpPreset->settings()->indirectPaintingCompositeOp(); } bool KisResourcesSnapshot::needsMaskingBrushRendering() const { return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->hasMaskingPreset(); } KisSelectionSP KisResourcesSnapshot::activeSelection() const { /** * It is possible to have/use the snapshot without the image. Such * usecase is present for example in the scratchpad. */ if (m_d->selectionOverride) { return m_d->selectionOverride; } KisSelectionSP selection = m_d->image ? m_d->image->globalSelection() : 0; KisLayerSP layer = qobject_cast(m_d->currentNode.data()); KisSelectionMaskSP mask; if((layer = qobject_cast(m_d->currentNode.data()))) { selection = layer->selection(); } else if ((mask = dynamic_cast(m_d->currentNode.data())) && mask->selection() == selection) { selection = 0; } return selection; } bool KisResourcesSnapshot::needsAirbrushing() const { return m_d->currentPaintOpPreset->settings()->isAirbrushing(); } qreal KisResourcesSnapshot::airbrushingInterval() const { return m_d->currentPaintOpPreset->settings()->airbrushInterval(); } bool KisResourcesSnapshot::needsSpacingUpdates() const { return m_d->currentPaintOpPreset->settings()->useSpacingUpdates(); } void KisResourcesSnapshot::setOpacity(qreal opacity) { m_d->opacity = opacity * OPACITY_OPAQUE_U8; } quint8 KisResourcesSnapshot::opacity() const { return m_d->opacity; } const KoCompositeOp* KisResourcesSnapshot::compositeOp() const { return m_d->compositeOp; } QString KisResourcesSnapshot::compositeOpId() const { return m_d->compositeOpId; } KoPattern* KisResourcesSnapshot::currentPattern() const { return m_d->currentPattern; } KoColor KisResourcesSnapshot::currentFgColor() const { return m_d->currentFgColor; } KoColor KisResourcesSnapshot::currentBgColor() const { return m_d->currentBgColor; } KisPaintOpPresetSP KisResourcesSnapshot::currentPaintOpPreset() const { return m_d->currentPaintOpPreset; } QBitArray KisResourcesSnapshot::channelLockFlags() const { QBitArray channelFlags; KisPaintLayer *paintLayer; if ((paintLayer = dynamic_cast(m_d->currentNode.data()))) { channelFlags = paintLayer->channelLockFlags(); if (m_d->globalAlphaLock) { if (channelFlags.isEmpty()) { channelFlags = paintLayer->colorSpace()->channelFlags(true, true); } channelFlags &= paintLayer->colorSpace()->channelFlags(true, false); } } return channelFlags; } qreal KisResourcesSnapshot::effectiveZoom() const { return m_d->effectiveZoom; } bool KisResourcesSnapshot::presetAllowsLod() const { return m_d->presetAllowsLod; } bool KisResourcesSnapshot::presetNeedsAsynchronousUpdates() const { return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->settings()->needsAsynchronousUpdates(); } void KisResourcesSnapshot::setFGColorOverride(const KoColor &color) { m_d->currentFgColor = color; } void KisResourcesSnapshot::setBGColorOverride(const KoColor &color) { m_d->currentBgColor = color; } void KisResourcesSnapshot::setSelectionOverride(KisSelectionSP selection) { m_d->selectionOverride = selection; } void KisResourcesSnapshot::setBrush(const KisPaintOpPresetSP &brush) { m_d->currentPaintOpPreset = brush; } diff --git a/libs/ui/tool/kis_resources_snapshot.h b/libs/ui/tool/kis_resources_snapshot.h index 16e280c169..658936ba89 100644 --- a/libs/ui/tool/kis_resources_snapshot.h +++ b/libs/ui/tool/kis_resources_snapshot.h @@ -1,111 +1,106 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_RESOURCES_SNAPSHOT_H #define __KIS_RESOURCES_SNAPSHOT_H #include "kis_shared.h" #include "kis_shared_ptr.h" #include "kis_types.h" #include "kritaui_export.h" #include "kis_painter.h" #include "kis_default_bounds.h" class KoCanvasResourceManager; class KoCompositeOp; class KisPainter; class KisPostExecutionUndoAdapter; -class KisRecordedPaintAction; class KoPattern; /** * @brief The KisResourcesSnapshot class takes a snapshot of the various resources - * like colors and settings used at the begin of a stroke or a recording so subsequent + * like colors and settings used at the begin of a stroke so subsequent * changes don't impact the running stroke. The main reason for the snapshot is that the * user can *change* the options while the stroke is being executed in the background. */ class KRITAUI_EXPORT KisResourcesSnapshot : public KisShared { public: KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceManager *resourceManager, KisDefaultBoundsBaseSP bounds = 0); KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds = 0); ~KisResourcesSnapshot(); void setupPainter(KisPainter *painter); void setupMaskingBrushPainter(KisPainter *painter); - // XXX: This was marked as KDE_DEPRECATED, but no althernative was - // given in the apidox. - void setupPaintAction(KisRecordedPaintAction *action); - KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const; void setCurrentNode(KisNodeSP node); void setStrokeStyle(KisPainter::StrokeStyle strokeStyle); void setFillStyle(KisPainter::FillStyle fillStyle); KisNodeSP currentNode() const; KisImageSP image() const; bool needsIndirectPainting() const; QString indirectPaintingCompositeOp() const; bool needsMaskingBrushRendering() const; /** * \return currently active selection. Note that it will return * null if current node *is* the current selection. This * is done to avoid recursive selection application when * painting on selectgion masks. */ KisSelectionSP activeSelection() const; bool needsAirbrushing() const; qreal airbrushingInterval() const; bool needsSpacingUpdates() const; void setOpacity(qreal opacity); quint8 opacity() const; const KoCompositeOp* compositeOp() const; QString compositeOpId() const; KoPattern* currentPattern() const; KoColor currentFgColor() const; KoColor currentBgColor() const; KisPaintOpPresetSP currentPaintOpPreset() const; /// @return the channel lock flags of the current node with the global override applied QBitArray channelLockFlags() const; qreal effectiveZoom() const; bool presetAllowsLod() const; bool presetNeedsAsynchronousUpdates() const; void setFGColorOverride(const KoColor &color); void setBGColorOverride(const KoColor &color); void setSelectionOverride(KisSelectionSP selection); void setBrush(const KisPaintOpPresetSP &brush); private: struct Private; Private * const m_d; }; typedef KisSharedPtr KisResourcesSnapshotSP; #endif /* __KIS_RESOURCES_SNAPSHOT_H */ diff --git a/libs/ui/tool/kis_tool.cc b/libs/ui/tool/kis_tool.cc index 3331b2edb7..f9ee6ee555 100644 --- a/libs/ui/tool/kis_tool.cc +++ b/libs/ui/tool/kis_tool.cc @@ -1,710 +1,703 @@ /* * Copyright (c) 2006, 2010 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl_canvas2.h" #include "kis_canvas_resource_provider.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "filter/kis_filter_configuration.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" -#include #include #include "kis_resources_snapshot.h" #include #include "kis_action_registry.h" #include "kis_tool_utils.h" struct Q_DECL_HIDDEN KisTool::Private { QCursor cursor; // the cursor that should be shown on tool activation. // From the canvas resources KoPattern* currentPattern{0}; KoAbstractGradient* currentGradient{0}; KoColor currentFgColor; KoColor currentBgColor; float currentExposure{1.0}; KisFilterConfigurationSP currentGenerator; QWidget* optionWidget{0}; ToolMode m_mode{HOVER_MODE}; bool m_isActive{false}; }; KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor) : KoToolBase(canvas) , d(new Private) { d->cursor = cursor; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle())); connect(this, SIGNAL(isActiveChanged()), SLOT(resetCursorStyle())); KActionCollection *collection = this->canvas()->canvasController()->actionCollection(); if (!collection->action("toggle_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("toggle_fg_bg", collection); collection->addAction("toggle_fg_bg", toggleFgBg); } if (!collection->action("reset_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("reset_fg_bg", collection); collection->addAction("reset_fg_bg", toggleFgBg); } addAction("toggle_fg_bg", dynamic_cast(collection->action("toggle_fg_bg"))); addAction("reset_fg_bg", dynamic_cast(collection->action("reset_fg_bg"))); } KisTool::~KisTool() { delete d; } void KisTool::activate(ToolActivation activation, const QSet &shapes) { KoToolBase::activate(activation, shapes); resetCursorStyle(); if (!canvas()) return; if (!canvas()->resourceManager()) return; d->currentFgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); d->currentBgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::BackgroundColor).value(); if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentPattern)) { d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGradient)) { d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); } KisPaintOpPresetSP preset = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && preset->settings()) { preset->settings()->activate(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::HdrExposure)) { d->currentExposure = static_cast(canvas()->resourceManager()->resource(KisCanvasResourceProvider::HdrExposure).toDouble()); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration)) { d->currentGenerator = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); } connect(action("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection); connect(action("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection); d->m_isActive = true; emit isActiveChanged(); } void KisTool::deactivate() { bool result = true; result &= disconnect(action("toggle_fg_bg"), 0, this, 0); result &= disconnect(action("reset_fg_bg"), 0, this, 0); if (!result) { warnKrita << "WARNING: KisTool::deactivate() failed to disconnect" << "some signal connections. Your actions might be executed twice!"; } d->m_isActive = false; emit isActiveChanged(); KoToolBase::deactivate(); } void KisTool::canvasResourceChanged(int key, const QVariant & v) { QString formattedBrushName; if (key == KisCanvasResourceProvider::CurrentPaintOpPreset) { formattedBrushName = v.value()->name().replace("_", " "); } switch (key) { case(KoCanvasResourceManager::ForegroundColor): d->currentFgColor = v.value(); break; case(KoCanvasResourceManager::BackgroundColor): d->currentBgColor = v.value(); break; case(KisCanvasResourceProvider::CurrentPattern): d->currentPattern = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentGradient): d->currentGradient = static_cast(v.value()); break; case(KisCanvasResourceProvider::HdrExposure): d->currentExposure = static_cast(v.toDouble()); break; case(KisCanvasResourceProvider::CurrentGeneratorConfiguration): d->currentGenerator = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentPaintOpPreset): emit statusTextChanged(formattedBrushName); break; case(KisCanvasResourceProvider::CurrentKritaNode): resetCursorStyle(); break; default: break; // Do nothing }; } void KisTool::updateSettingsViews() { } QPointF KisTool::widgetCenterInWidgetPixels() { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); const KisCoordinatesConverter *converter = kritaCanvas->coordinatesConverter(); return converter->flakeToWidget(converter->flakeCenterPoint()); } QPointF KisTool::convertDocumentToWidget(const QPointF& pt) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); return kritaCanvas->coordinatesConverter()->documentToWidget(pt); } QPointF KisTool::convertToPixelCoord(KoPointerEvent *e) { if (!image()) return e->point; return image()->documentToPixel(e->point); } QPointF KisTool::convertToPixelCoord(const QPointF& pt) { if (!image()) return pt; return image()->documentToPixel(pt); } QPointF KisTool::convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!image()) return e->point; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); return image()->documentToPixel(pos); } QPointF KisTool::convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset) { if (!image()) return pt; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return image()->documentToPixel(pos); } QPoint KisTool::convertToImagePixelCoordFloored(KoPointerEvent *e) { if (!image()) return e->point.toPoint(); return image()->documentToImagePixelFloored(e->point); } QPointF KisTool::viewToPixel(const QPointF &viewCoord) const { if (!image()) return viewCoord; return image()->documentToPixel(canvas()->viewConverter()->viewToDocument(viewCoord)); } QRectF KisTool::convertToPt(const QRectF &rect) { if (!image()) return rect; QRectF r; //We add 1 in the following to the extreme coords because a pixel always has size r.setCoords(int(rect.left()) / image()->xRes(), int(rect.top()) / image()->yRes(), int(rect.right()) / image()->xRes(), int( rect.bottom()) / image()->yRes()); return r; } QPointF KisTool::pixelToView(const QPoint &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QPointF KisTool::pixelToView(const QPointF &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QRectF KisTool::pixelToView(const QRectF &pixelRect) const { if (!image()) return pixelRect; QPointF topLeft = pixelToView(pixelRect.topLeft()); QPointF bottomRight = pixelToView(pixelRect.bottomRight()); return QRectF(topLeft, bottomRight); } QPainterPath KisTool::pixelToView(const QPainterPath &pixelPolygon) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPolygon); } QPolygonF KisTool::pixelToView(const QPolygonF &pixelPath) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPath); } void KisTool::updateCanvasPixelRect(const QRectF &pixelRect) { canvas()->updateCanvas(convertToPt(pixelRect)); } void KisTool::updateCanvasViewRect(const QRectF &viewRect) { canvas()->updateCanvas(canvas()->viewConverter()->viewToDocument(viewRect)); } KisImageWSP KisTool::image() const { // For now, krita tools only work in krita, not for a krita shape. Krita shapes are for 2.1 KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (kisCanvas) { return kisCanvas->currentImage(); } return 0; } QCursor KisTool::cursor() const { return d->cursor; } void KisTool::notifyModified() const { if (image()) { image()->setModified(); } } KoPattern * KisTool::currentPattern() { return d->currentPattern; } KoAbstractGradient * KisTool::currentGradient() { return d->currentGradient; } KisPaintOpPresetSP KisTool::currentPaintOpPreset() { return canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); } KisNodeSP KisTool::currentNode() const { KisNodeSP node = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); return node; } KisNodeList KisTool::selectedNodes() const { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->nodeManager()->selectedNodes(); } KoColor KisTool::currentFgColor() { return d->currentFgColor; } KoColor KisTool::currentBgColor() { return d->currentBgColor; } KisImageWSP KisTool::currentImage() { return image(); } KisFilterConfigurationSP KisTool::currentGenerator() { return d->currentGenerator; } void KisTool::setMode(ToolMode mode) { d->m_mode = mode; } KisTool::ToolMode KisTool::mode() const { return d->m_mode; } void KisTool::setCursor(const QCursor &cursor) { d->cursor = cursor; } KisTool::AlternateAction KisTool::actionToAlternateAction(ToolAction action) { KIS_ASSERT_RECOVER_RETURN_VALUE(action != Primary, Secondary); return (AlternateAction)action; } void KisTool::activatePrimaryAction() { resetCursorStyle(); } void KisTool::deactivatePrimaryAction() { resetCursorStyle(); } void KisTool::beginPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::beginPrimaryDoubleClickAction(KoPointerEvent *event) { beginPrimaryAction(event); } void KisTool::continuePrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } bool KisTool::primaryActionSupportsHiResEvents() const { return false; } void KisTool::activateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::deactivateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action) { beginAlternateAction(event, action); } void KisTool::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::mouseDoubleClickEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseTripleClickEvent(KoPointerEvent *event) { mouseDoubleClickEvent(event); } void KisTool::mousePressEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseMoveEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::deleteSelection() { KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); if (!blockUntilOperationsFinished()) { return; } if (!KisToolUtils::clearImage(image(), resources->currentNode(), resources->activeSelection())) { KoToolBase::deleteSelection(); } } -void KisTool::setupPaintAction(KisRecordedPaintAction* action) -{ - action->setPaintColor(currentFgColor()); - action->setBackgroundColor(currentBgColor()); -} - QWidget* KisTool::createOptionWidget() { d->optionWidget = new QLabel(i18n("No options")); d->optionWidget->setObjectName("SpecialSpacer"); return d->optionWidget; } #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #define PROGRAM_VERTEX_ATTRIBUTE 0 void KisTool::paintToolOutline(QPainter* painter, const QPainterPath &path) { KisOpenGLCanvas2 *canvasWidget = dynamic_cast(canvas()->canvasWidget()); if (canvasWidget) { painter->beginNativePainting(); canvasWidget->paintToolOutline(path); painter->endNativePainting(); } else { painter->save(); painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter->setPen(QColor(128, 255, 128)); painter->drawPath(path); painter->restore(); } } void KisTool::resetCursorStyle() { useCursor(d->cursor); } bool KisTool::overrideCursorIfNotEditable() { // override cursor for canvas iff this tool is active // and we can't paint on the active layer if (isActive()) { KisNodeSP node = currentNode(); if (node && !node->isEditable()) { canvas()->setCursor(Qt::ForbiddenCursor); return true; } } return false; } bool KisTool::blockUntilOperationsFinished() { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->blockUntilOperationsFinished(image()); } void KisTool::blockUntilOperationsFinishedForced() { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); viewManager->blockUntilOperationsFinishedForced(image()); } bool KisTool::isActive() const { return d->m_isActive; } void KisTool::slotToggleFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); KoColor newFg = resourceManager->backgroundColor(); KoColor newBg = resourceManager->foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ resourceManager->setBackgroundColor(newBg); resourceManager->setForegroundColor(newFg); } void KisTool::slotResetFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); // see a comment in slotToggleFgBg() resourceManager->setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); resourceManager->setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } bool KisTool::nodeEditable() { KisNodeSP node = currentNode(); if (!node) { return false; } bool blockedNoIndirectPainting = false; const bool presetUsesIndirectPainting = !currentPaintOpPreset()->settings()->paintIncremental(); if (!presetUsesIndirectPainting) { const KisIndirectPaintingSupport *indirectPaintingLayer = dynamic_cast(node.data()); if (indirectPaintingLayer) { blockedNoIndirectPainting = !indirectPaintingLayer->supportsNonIndirectPainting(); } } bool nodeEditable = node->isEditable() && !blockedNoIndirectPainting; if (!nodeEditable) { KisCanvas2 * kiscanvas = static_cast(canvas()); QString message; if (!node->visible() && node->userLocked()) { message = i18n("Layer is locked and invisible."); } else if (node->userLocked()) { message = i18n("Layer is locked."); } else if(!node->visible()) { message = i18n("Layer is invisible."); } else if (blockedNoIndirectPainting) { message = i18n("Layer can be painted in Wash Mode only."); } else { message = i18n("Group not editable."); } kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked")); } return nodeEditable; } bool KisTool::selectionEditable() { KisCanvas2 * kisCanvas = static_cast(canvas()); KisViewManager * view = kisCanvas->viewManager(); bool editable = view->selectionEditable(); if (!editable) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()->showFloatingMessage(i18n("Local selection is locked."), KisIconUtils::loadIcon("object-locked")); } return editable; } void KisTool::listenToModifiers(bool listen) { Q_UNUSED(listen); } bool KisTool::listeningToModifiers() { return false; } diff --git a/libs/ui/tool/kis_tool.h b/libs/ui/tool/kis_tool.h index 21d532cee4..dcf5368519 100644 --- a/libs/ui/tool/kis_tool.h +++ b/libs/ui/tool/kis_tool.h @@ -1,324 +1,321 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TOOL_H_ #define KIS_TOOL_H_ #include #include #include #include #include #include #include #ifdef __GNUC__ #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come to" << __func__ << "while being mode" << _mode << "!" #else #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come while being mode" << _mode << "!" #endif #define CHECK_MODE_SANITY_OR_RETURN(_mode) if (mode() != _mode) { WARN_WRONG_MODE(mode()); return; } class KoCanvasBase; class KoPattern; class KoAbstractGradient; class KisFilterConfiguration; class QPainter; class QPainterPath; class QPolygonF; -class KisRecordedPaintAction; /// Definitions of the toolgroups of Krita static const QString TOOL_TYPE_SHAPE = "0 Krita/Shape"; // Geometric shapes like ellipses and lines static const QString TOOL_TYPE_TRANSFORM = "2 Krita/Transform"; // Tools that transform the layer; static const QString TOOL_TYPE_FILL = "3 Krita/Fill"; // Tools that fill parts of the canvas static const QString TOOL_TYPE_VIEW = "4 Krita/View"; // Tools that affect the canvas: pan, zoom, etc. static const QString TOOL_TYPE_SELECTION = "5 Krita/Select"; // Tools that select pixels //activation id for Krita tools, Krita tools are always active and handle locked and invisible layers by themself static const QString KRITA_TOOL_ACTIVATION_ID = "flake/always"; class KRITAUI_EXPORT KisTool : public KoToolBase { Q_OBJECT Q_PROPERTY(bool isActive READ isActive NOTIFY isActiveChanged) public: enum { FLAG_USES_CUSTOM_PRESET=0x01, FLAG_USES_CUSTOM_COMPOSITEOP=0x02, FLAG_USES_CUSTOM_SIZE=0x04 }; KisTool(KoCanvasBase * canvas, const QCursor & cursor); ~KisTool() override; virtual int flags() const { return 0; } void deleteSelection() override; // KoToolBase Implementation. public: /** * Called by KisToolProxy when the primary action of the tool is * going to be started now, that is when all the modifiers are * pressed and the only thing left is just to press the mouse * button. On coming of this callback the tool is supposed to * prepare the cursor and/or the outline to show the user shat is * going to happen next */ virtual void activatePrimaryAction(); /** * Called by KisToolProxy when the primary is no longer possible * to be started now, e.g. when its modifiers and released. The * tool is supposed revert all the preparetions it has doen in * activatePrimaryAction(). */ virtual void deactivatePrimaryAction(); /** * Called by KisToolProxy when a primary action for the tool is * started. The \p event stores the original event that * started the stroke. The \p event is _accepted_ by default. If * the tool decides to ignore this particular action (e.g. when * the node is not editable), it should call event->ignore(). Then * no further continuePrimaryAction() or endPrimaryAction() will * be called until the next user action. */ virtual void beginPrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is in progress * of pointer movement. If the tool has ignored the event in * beginPrimaryAction(), this method will not be called. */ virtual void continuePrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is being * finished, that is while mouseRelease or tabletRelease event. * If the tool has ignored the event in beginPrimaryAction(), this * method will not be called. */ virtual void endPrimaryAction(KoPointerEvent *event); /** * The same as beginPrimaryAction(), but called when the stroke is * started by a double-click * * \see beginPrimaryAction() */ virtual void beginPrimaryDoubleClickAction(KoPointerEvent *event); /** * Returns true if the tool can handle (and wants to handle) a * very tight flow of input events from the tablet */ virtual bool primaryActionSupportsHiResEvents() const; enum ToolAction { Primary, AlternateChangeSize, AlternatePickFgNode, AlternatePickBgNode, AlternatePickFgImage, AlternatePickBgImage, AlternateSecondary, AlternateThird, AlternateFourth, AlternateFifth, Alternate_NONE = 10000 }; // Technically users are allowed to configure this, but nobody ever would do that. // So these can basically be thought of as aliases to ctrl+click, etc. enum AlternateAction { ChangeSize = AlternateChangeSize, // Default: Shift+Left click PickFgNode = AlternatePickFgNode, // Default: Ctrl+Alt+Left click PickBgNode = AlternatePickBgNode, // Default: Ctrl+Alt+Right click PickFgImage = AlternatePickFgImage, // Default: Ctrl+Left click PickBgImage = AlternatePickBgImage, // Default: Ctrl+Right click Secondary = AlternateSecondary, Third = AlternateThird, Fourth = AlternateFourth, Fifth = AlternateFifth, NONE = 10000 }; static AlternateAction actionToAlternateAction(ToolAction action); virtual void activateAlternateAction(AlternateAction action); virtual void deactivateAlternateAction(AlternateAction action); virtual void beginAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void continueAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void endAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action); void mousePressEvent(KoPointerEvent *event) override; void mouseDoubleClickEvent(KoPointerEvent *event) override; void mouseTripleClickEvent(KoPointerEvent *event) override; void mouseReleaseEvent(KoPointerEvent *event) override; void mouseMoveEvent(KoPointerEvent *event) override; bool isActive() const; public Q_SLOTS: void activate(ToolActivation activation, const QSet &shapes) override; void deactivate() override; void canvasResourceChanged(int key, const QVariant & res) override; // Implement this slot in case there are any widgets or properties which need // to be updated after certain operations, to reflect the inner state correctly. // At the moment this is used for smoothing options in the freehand brush, but // this will likely be expanded. virtual void updateSettingsViews(); Q_SIGNALS: void isActiveChanged(); protected: // conversion methods are also needed by the paint information builder friend class KisToolPaintingInformationBuilder; /// Convert from native (postscript points) to image pixel /// coordinates. QPointF convertToPixelCoord(KoPointerEvent *e); QPointF convertToPixelCoord(const QPointF& pt); QPointF convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset = QPointF(), bool useModifiers = true); QPointF convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset = QPointF()); protected: QPointF widgetCenterInWidgetPixels(); QPointF convertDocumentToWidget(const QPointF& pt); /// Convert from native (postscript points) to integer image pixel /// coordinates. This rounds down (not truncate) the pixel coordinates and /// should be used in preference to QPointF::toPoint(), which rounds, /// to ensure the cursor acts on the pixel it is visually over. QPoint convertToImagePixelCoordFloored(KoPointerEvent *e); QRectF convertToPt(const QRectF &rect); QPointF viewToPixel(const QPointF &viewCoord) const; /// Convert an integer pixel coordinate into a view coordinate. /// The view coordinate is at the centre of the pixel. QPointF pixelToView(const QPoint &pixelCoord) const; /// Convert a floating point pixel coordinate into a view coordinate. QPointF pixelToView(const QPointF &pixelCoord) const; /// Convert a pixel rectangle into a view rectangle. QRectF pixelToView(const QRectF &pixelRect) const; /// Convert a pixel path into a view path QPainterPath pixelToView(const QPainterPath &pixelPath) const; /// Convert a pixel polygon into a view path QPolygonF pixelToView(const QPolygonF &pixelPolygon) const; /// Update the canvas for the given rectangle in image pixel coordinates. void updateCanvasPixelRect(const QRectF &pixelRect); /// Update the canvas for the given rectangle in view coordinates. void updateCanvasViewRect(const QRectF &viewRect); QWidget* createOptionWidget() override; /** * To determine whether this tool will change its behavior when * modifier keys are pressed */ virtual bool listeningToModifiers(); /** * Request that this tool no longer listen to modifier keys * (Responding to the request is optional) */ virtual void listenToModifiers(bool listen); protected: KisImageWSP image() const; QCursor cursor() const; /// Call this to set the document modified void notifyModified() const; KisImageWSP currentImage(); KoPattern* currentPattern(); KoAbstractGradient *currentGradient(); KisNodeSP currentNode() const; KisNodeList selectedNodes() const; KoColor currentFgColor(); KoColor currentBgColor(); KisPaintOpPresetSP currentPaintOpPreset(); KisFilterConfigurationSP currentGenerator(); - virtual void setupPaintAction(KisRecordedPaintAction* action); - /// paint the path which is in view coordinates, default paint mode is XOR_MODE, BW_MODE is also possible /// never apply transformations to the painter, they would be useless, if drawing in OpenGL mode. The coordinates in the path should be in view coordinates. void paintToolOutline(QPainter * painter, const QPainterPath &path); /// Checks checks if the current node is editable bool nodeEditable(); /// Checks checks if the selection is editable, only applies to local selection as global selection is always editable bool selectionEditable(); /// Override the cursor appropriately if current node is not editable bool overrideCursorIfNotEditable(); bool blockUntilOperationsFinished(); void blockUntilOperationsFinishedForced(); protected: enum ToolMode { HOVER_MODE, PAINT_MODE, SECONDARY_PAINT_MODE, MIRROR_AXIS_SETUP_MODE, GESTURE_MODE, PAN_MODE, OTHER // not used now }; virtual void setMode(ToolMode mode); virtual ToolMode mode() const; void setCursor(const QCursor &cursor); protected Q_SLOTS: /** * Called whenever the configuration settings change. */ virtual void resetCursorStyle(); private Q_SLOTS: void slotToggleFgBg(); void slotResetFgBg(); private: struct Private; Private* const d; }; #endif // KIS_TOOL_H_ diff --git a/libs/ui/tool/kis_tool_freehand.cc b/libs/ui/tool/kis_tool_freehand.cc index f419cc11d0..3df3db0957 100644 --- a/libs/ui/tool/kis_tool_freehand.cc +++ b/libs/ui/tool/kis_tool_freehand.cc @@ -1,467 +1,458 @@ /* * kis_tool_freehand.cc - part of Krita * * Copyright (c) 2003-2007 Boudewijn Rempt * Copyright (c) 2004 Bart Coppens * Copyright (c) 2007,2008,2010 Cyrille Berger * Copyright (c) 2009 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_freehand.h" #include #include #include #include #include #include #include #include #include #include //pop up palette #include // Krita/image #include #include #include #include #include #include // Krita/ui #include "kis_abstract_perspective_grid.h" #include "kis_config.h" #include "canvas/kis_canvas2.h" #include "kis_cursor.h" #include #include #include "kis_painting_information_builder.h" #include "kis_tool_freehand_helper.h" -#include "kis_recording_adapter.h" #include "strokes/freehand_stroke.h" using namespace std::placeholders; // For _1 placeholder KisToolFreehand::KisToolFreehand(KoCanvasBase * canvas, const QCursor & cursor, const KUndo2MagicString &transactionText) : KisToolPaint(canvas, cursor), m_paintopBasedPickingInAction(false), m_brushResizeCompressor(200, std::bind(&KisToolFreehand::slotDoResizeBrush, this, _1)) { m_assistant = false; m_magnetism = 1.0; m_only_one_assistant = true; setSupportOutline(true); setMaskSyntheticEvents(KisConfig().disableTouchOnCanvas()); // Disallow mouse events from finger presses unless enabled m_infoBuilder = new KisToolFreehandPaintingInformationBuilder(this); - m_recordingAdapter = new KisRecordingAdapter(); - m_helper = new KisToolFreehandHelper(m_infoBuilder, transactionText, m_recordingAdapter); + m_helper = new KisToolFreehandHelper(m_infoBuilder, transactionText); - connect(m_helper, SIGNAL(requestExplicitUpdateOutline()), - SLOT(explicitUpdateOutline())); + connect(m_helper, SIGNAL(requestExplicitUpdateOutline()), SLOT(explicitUpdateOutline())); } KisToolFreehand::~KisToolFreehand() { delete m_helper; - delete m_recordingAdapter; delete m_infoBuilder; } void KisToolFreehand::mouseMoveEvent(KoPointerEvent *event) { KisToolPaint::mouseMoveEvent(event); m_helper->cursorMoved(convertToPixelCoord(event)); } KisSmoothingOptionsSP KisToolFreehand::smoothingOptions() const { return m_helper->smoothingOptions(); } void KisToolFreehand::resetCursorStyle() { KisConfig cfg; switch (cfg.newCursorStyle()) { case CURSOR_STYLE_NO_CURSOR: useCursor(KisCursor::blankCursor()); break; case CURSOR_STYLE_POINTER: useCursor(KisCursor::arrowCursor()); break; case CURSOR_STYLE_SMALL_ROUND: useCursor(KisCursor::roundCursor()); break; case CURSOR_STYLE_CROSSHAIR: useCursor(KisCursor::crossCursor()); break; case CURSOR_STYLE_TRIANGLE_RIGHTHANDED: useCursor(KisCursor::triangleRightHandedCursor()); break; case CURSOR_STYLE_TRIANGLE_LEFTHANDED: useCursor(KisCursor::triangleLeftHandedCursor()); break; case CURSOR_STYLE_BLACK_PIXEL: useCursor(KisCursor::pixelBlackCursor()); break; case CURSOR_STYLE_WHITE_PIXEL: useCursor(KisCursor::pixelWhiteCursor()); break; case CURSOR_STYLE_TOOLICON: default: KisToolPaint::resetCursorStyle(); break; } } KisPaintingInformationBuilder* KisToolFreehand::paintingInformationBuilder() const { return m_infoBuilder; } -KisRecordingAdapter* KisToolFreehand::recordingAdapter() const -{ - return m_recordingAdapter; -} - void KisToolFreehand::resetHelper(KisToolFreehandHelper *helper) { delete m_helper; m_helper = helper; } int KisToolFreehand::flags() const { return KisTool::FLAG_USES_CUSTOM_COMPOSITEOP|KisTool::FLAG_USES_CUSTOM_PRESET |KisTool::FLAG_USES_CUSTOM_SIZE; } void KisToolFreehand::activate(ToolActivation activation, const QSet &shapes) { KisToolPaint::activate(activation, shapes); } void KisToolFreehand::deactivate() { if (mode() == PAINT_MODE) { endStroke(); setMode(KisTool::HOVER_MODE); } KisToolPaint::deactivate(); } void KisToolFreehand::initStroke(KoPointerEvent *event) { m_helper->initPaint(event, convertToPixelCoord(event), canvas()->resourceManager(), image(), currentNode(), image().data()); } void KisToolFreehand::doStroke(KoPointerEvent *event) { //set canvas information here?// KisCanvas2 *canvas2 = dynamic_cast(canvas()); if (canvas2) { m_helper->setCanvasHorizontalMirrorState(canvas2->xAxisMirrored()); m_helper->setCanvasRotation(canvas2->rotationAngle()); } m_helper->paintEvent(event); } void KisToolFreehand::endStroke() { m_helper->endPaint(); } bool KisToolFreehand::primaryActionSupportsHiResEvents() const { return true; } void KisToolFreehand::beginPrimaryAction(KoPointerEvent *event) { // FIXME: workaround for the Duplicate Op tryPickByPaintOp(event, PickFgImage); requestUpdateOutline(event->point, event); NodePaintAbility paintability = nodePaintAbility(); // XXX: move this to KisTool and make it work properly for clone layers: for clone layers, the shape paint tools don't work either if (!nodeEditable() || paintability != PAINT) { if (paintability == KisToolPaint::VECTOR || paintability == KisToolPaint::CLONE){ KisCanvas2 * kiscanvas = static_cast(canvas()); QString message = i18n("The brush tool cannot paint on this layer. Please select a paint layer or mask."); kiscanvas->viewManager()->showFloatingMessage(message, koIcon("object-locked")); } event->ignore(); return; } setMode(KisTool::PAINT_MODE); KisCanvas2 *canvas2 = dynamic_cast(canvas()); if (canvas2) { canvas2->viewManager()->disableControls(); } initStroke(event); } void KisToolFreehand::continuePrimaryAction(KoPointerEvent *event) { CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); requestUpdateOutline(event->point, event); /** * Actual painting */ doStroke(event); } void KisToolFreehand::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); endStroke(); if (m_assistant && static_cast(canvas())->paintingAssistantsDecoration()) { static_cast(canvas())->paintingAssistantsDecoration()->endStroke(); } notifyModified(); KisCanvas2 *canvas2 = dynamic_cast(canvas()); if (canvas2) { canvas2->viewManager()->enableControls(); } setMode(KisTool::HOVER_MODE); } bool KisToolFreehand::tryPickByPaintOp(KoPointerEvent *event, AlternateAction action) { if (action != PickFgNode && action != PickFgImage) return false; /** * FIXME: we need some better way to implement modifiers * for a paintop level. This method is used in DuplicateOp only! */ QPointF pos = adjustPosition(event->point, event->point); qreal perspective = 1.0; Q_FOREACH (const QPointer grid, static_cast(canvas())->viewManager()->resourceProvider()->perspectiveGrids()) { if (grid && grid->contains(pos)) { perspective = grid->distance(pos); break; } } if (!currentPaintOpPreset()) { return false; } bool paintOpIgnoredEvent = currentPaintOpPreset()->settings()-> mousePressEvent(KisPaintInformation(convertToPixelCoord(event->point), m_infoBuilder->pressureToCurve(event->pressure()), event->xTilt(), event->yTilt(), event->rotation(), event->tangentialPressure(), perspective, 0, 0), event->modifiers(), currentNode()); return !paintOpIgnoredEvent; } void KisToolFreehand::activateAlternateAction(AlternateAction action) { if (action != ChangeSize) { KisToolPaint::activateAlternateAction(action); return; } useCursor(KisCursor::blankCursor()); setOutlineEnabled(true); } void KisToolFreehand::deactivateAlternateAction(AlternateAction action) { if (action != ChangeSize) { KisToolPaint::deactivateAlternateAction(action); return; } resetCursorStyle(); setOutlineEnabled(false); } void KisToolFreehand::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { if (tryPickByPaintOp(event, action)) { m_paintopBasedPickingInAction = true; return; } if (action != ChangeSize) { KisToolPaint::beginAlternateAction(event, action); return; } setMode(GESTURE_MODE); m_initialGestureDocPoint = event->point; m_initialGestureGlobalPoint = QCursor::pos(); m_lastDocumentPoint = event->point; m_lastPaintOpSize = currentPaintOpPreset()->settings()->paintOpSize(); } void KisToolFreehand::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { if (tryPickByPaintOp(event, action) || m_paintopBasedPickingInAction) return; if (action != ChangeSize) { KisToolPaint::continueAlternateAction(event, action); return; } QPointF lastWidgetPosition = convertDocumentToWidget(m_lastDocumentPoint); QPointF actualWidgetPosition = convertDocumentToWidget(event->point); QPointF offset = actualWidgetPosition - lastWidgetPosition; KisCanvas2 *canvas2 = dynamic_cast(canvas()); QRect screenRect = QApplication::desktop()->screenGeometry(); qreal scaleX = 0; qreal scaleY = 0; canvas2->coordinatesConverter()->imageScale(&scaleX, &scaleY); const qreal maxBrushSize = KisConfig().readEntry("maximumBrushSize", 1000); const qreal effectiveMaxDragSize = 0.5 * screenRect.width(); const qreal effectiveMaxBrushSize = qMin(maxBrushSize, effectiveMaxDragSize / scaleX); const qreal scaleCoeff = effectiveMaxBrushSize / effectiveMaxDragSize; const qreal sizeDiff = scaleCoeff * offset.x() ; if (qAbs(sizeDiff) > 0.01) { KisPaintOpSettingsSP settings = currentPaintOpPreset()->settings(); const qreal newSize = qBound(0.01, m_lastPaintOpSize + sizeDiff, maxBrushSize); settings->setPaintOpSize(newSize); requestUpdateOutline(m_initialGestureDocPoint, 0); //m_brushResizeCompressor.start(newSize); m_lastDocumentPoint = event->point; m_lastPaintOpSize = newSize; } } void KisToolFreehand::endAlternateAction(KoPointerEvent *event, AlternateAction action) { if (tryPickByPaintOp(event, action) || m_paintopBasedPickingInAction) { m_paintopBasedPickingInAction = false; return; } if (action != ChangeSize) { KisToolPaint::endAlternateAction(event, action); return; } QCursor::setPos(m_initialGestureGlobalPoint); requestUpdateOutline(m_initialGestureDocPoint, 0); setMode(HOVER_MODE); } bool KisToolFreehand::wantsAutoScroll() const { return false; } void KisToolFreehand::setAssistant(bool assistant) { m_assistant = assistant; } void KisToolFreehand::setOnlyOneAssistantSnap(bool assistant) { m_only_one_assistant = assistant; } void KisToolFreehand::slotDoResizeBrush(qreal newSize) { KisPaintOpSettingsSP settings = currentPaintOpPreset()->settings(); settings->setPaintOpSize(newSize); requestUpdateOutline(m_initialGestureDocPoint, 0); } QPointF KisToolFreehand::adjustPosition(const QPointF& point, const QPointF& strokeBegin) { if (m_assistant && static_cast(canvas())->paintingAssistantsDecoration()) { static_cast(canvas())->paintingAssistantsDecoration()->setOnlyOneAssistantSnap(m_only_one_assistant); QPointF ap = static_cast(canvas())->paintingAssistantsDecoration()->adjustPosition(point, strokeBegin); return (1.0 - m_magnetism) * point + m_magnetism * ap; } return point; } qreal KisToolFreehand::calculatePerspective(const QPointF &documentPoint) { qreal perspective = 1.0; Q_FOREACH (const QPointer grid, static_cast(canvas())->viewManager()->resourceProvider()->perspectiveGrids()) { if (grid && grid->contains(documentPoint)) { perspective = grid->distance(documentPoint); break; } } return perspective; } void KisToolFreehand::explicitUpdateOutline() { requestUpdateOutline(m_outlineDocPoint, 0); } QPainterPath KisToolFreehand::getOutlinePath(const QPointF &documentPos, const KoPointerEvent *event, KisPaintOpSettings::OutlineMode outlineMode) { QPointF imagePos = convertToPixelCoord(documentPos); if (currentPaintOpPreset()) return m_helper->paintOpOutline(imagePos, event, currentPaintOpPreset()->settings(), outlineMode); else return QPainterPath(); } diff --git a/libs/ui/tool/kis_tool_freehand.h b/libs/ui/tool/kis_tool_freehand.h index 28db6de7cd..bc090e75ee 100644 --- a/libs/ui/tool/kis_tool_freehand.h +++ b/libs/ui/tool/kis_tool_freehand.h @@ -1,136 +1,131 @@ /* * Copyright (c) 2003-2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TOOL_FREEHAND_H_ #define KIS_TOOL_FREEHAND_H_ #include #include #include #include "kis_types.h" #include "kis_tool_paint.h" #include "kis_smoothing_options.h" #include "kis_signal_compressor_with_param.h" #include "kritaui_export.h" class KoPointerEvent; class KoCanvasBase; - - class KisPaintingInformationBuilder; class KisToolFreehandHelper; -class KisRecordingAdapter; class KRITAUI_EXPORT KisToolFreehand : public KisToolPaint { Q_OBJECT public: KisToolFreehand(KoCanvasBase * canvas, const QCursor & cursor, const KUndo2MagicString &transactionText); ~KisToolFreehand() override; int flags() const override; void mouseMoveEvent(KoPointerEvent *event) override; public Q_SLOTS: void activate(ToolActivation toolActivation, const QSet &shapes) override; void deactivate() override; protected: bool tryPickByPaintOp(KoPointerEvent *event, AlternateAction action); bool primaryActionSupportsHiResEvents() const override; void beginPrimaryAction(KoPointerEvent *event) override; void continuePrimaryAction(KoPointerEvent *event) override; void endPrimaryAction(KoPointerEvent *event) override; void activateAlternateAction(AlternateAction action) override; void deactivateAlternateAction(AlternateAction action) override; void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override; void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override; void endAlternateAction(KoPointerEvent *event, AlternateAction action) override; bool wantsAutoScroll() const override; virtual void initStroke(KoPointerEvent *event); virtual void doStroke(KoPointerEvent *event); virtual void endStroke(); QPainterPath getOutlinePath(const QPointF &documentPos, const KoPointerEvent *event, KisPaintOpSettings::OutlineMode outlineMode) override; KisPaintingInformationBuilder* paintingInformationBuilder() const; - KisRecordingAdapter* recordingAdapter() const; void resetHelper(KisToolFreehandHelper *helper); protected Q_SLOTS: void explicitUpdateOutline(); void resetCursorStyle() override; void setAssistant(bool assistant); void setOnlyOneAssistantSnap(bool assistant); void slotDoResizeBrush(qreal newSize); private: friend class KisToolFreehandPaintingInformationBuilder; /** * Adjusts a coordinates according to a KisPaintingAssitant, * if available. */ QPointF adjustPosition(const QPointF& point, const QPointF& strokeBegin); /** * Calculates a coefficient for KisPaintInformation * according to perspective grid values */ qreal calculatePerspective(const QPointF &documentPoint); protected: friend class KisViewManager; friend class KisView; KisSmoothingOptionsSP smoothingOptions() const; bool m_assistant; double m_magnetism; bool m_only_one_assistant; private: KisPaintingInformationBuilder *m_infoBuilder; KisToolFreehandHelper *m_helper; - KisRecordingAdapter *m_recordingAdapter; QPointF m_initialGestureDocPoint; QPointF m_lastDocumentPoint; qreal m_lastPaintOpSize; QPoint m_initialGestureGlobalPoint; bool m_paintopBasedPickingInAction; KisSignalCompressorWithParam m_brushResizeCompressor; }; #endif // KIS_TOOL_FREEHAND_H_ diff --git a/libs/ui/tool/kis_tool_freehand_helper.cpp b/libs/ui/tool/kis_tool_freehand_helper.cpp index f060c6cf91..f0c4b994bb 100644 --- a/libs/ui/tool/kis_tool_freehand_helper.cpp +++ b/libs/ui/tool/kis_tool_freehand_helper.cpp @@ -1,1028 +1,1003 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_freehand_helper.h" #include #include #include #include #include #include "kis_algebra_2d.h" #include "kis_distance_information.h" #include "kis_painting_information_builder.h" -#include "kis_recording_adapter.h" #include "kis_image.h" #include "kis_painter.h" #include #include #include "kis_update_time_monitor.h" #include "kis_stabilized_events_sampler.h" #include "KisStabilizerDelayedPaintHelper.h" #include "kis_config.h" #include "kis_random_source.h" #include "KisPerStrokeRandomSource.h" #include "strokes/freehand_stroke.h" #include "strokes/KisFreehandStrokeInfo.h" #include //#define DEBUG_BEZIER_CURVES // Factor by which to scale the airbrush timer's interval, relative to the actual airbrushing rate. // Setting this less than 1 makes the timer-generated pseudo-events happen faster than the desired // airbrush rate, which can improve responsiveness. const qreal AIRBRUSH_INTERVAL_FACTOR = 0.5; // The amount of time, in milliseconds, to allow between updates of the spacing information. Only // used when spacing updates between dabs are enabled. const qreal SPACING_UPDATE_INTERVAL = 50.0; // The amount of time, in milliseconds, to allow between updates of the timing information. Only // used when airbrushing. const qreal TIMING_UPDATE_INTERVAL = 50.0; struct KisToolFreehandHelper::Private { KisPaintingInformationBuilder *infoBuilder; - KisRecordingAdapter *recordingAdapter; KisStrokesFacade *strokesFacade; KUndo2MagicString transactionText; bool haveTangent; QPointF previousTangent; bool hasPaintAtLeastOnce; QTime strokeTime; QTimer strokeTimeoutTimer; QVector strokeInfos; KisResourcesSnapshotSP resources; KisStrokeId strokeId; KisPaintInformation previousPaintInformation; KisPaintInformation olderPaintInformation; KisSmoothingOptionsSP smoothingOptions; // fake random sources for hovering outline *only* KisRandomSourceSP fakeDabRandomSource; KisPerStrokeRandomSourceSP fakeStrokeRandomSource; // Timer used to generate paint updates periodically even without input events. This is only // used for paintops that depend on timely updates even when the cursor is not moving, e.g. for // airbrushing effects. QTimer airbrushingTimer; QList history; QList distanceHistory; // Keeps track of past cursor positions. This is used to determine the drawing angle when // drawing the brush outline or starting a stroke. KisPaintOpUtils::PositionHistory lastCursorPos; // Stabilizer data bool usingStabilizer; QQueue stabilizerDeque; QTimer stabilizerPollTimer; KisStabilizedEventsSampler stabilizedSampler; KisStabilizerDelayedPaintHelper stabilizerDelayedPaintHelper; QTimer asynchronousUpdatesThresholdTimer; int canvasRotation; bool canvasMirroredH; qreal effectiveSmoothnessDistance() const; }; KisToolFreehandHelper::KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder, const KUndo2MagicString &transactionText, - KisRecordingAdapter *recordingAdapter, KisSmoothingOptions *smoothingOptions) : m_d(new Private()) { m_d->infoBuilder = infoBuilder; - m_d->recordingAdapter = recordingAdapter; m_d->transactionText = transactionText; m_d->smoothingOptions = KisSmoothingOptionsSP( smoothingOptions ? smoothingOptions : new KisSmoothingOptions()); m_d->canvasRotation = 0; m_d->fakeDabRandomSource = new KisRandomSource(); m_d->fakeStrokeRandomSource = new KisPerStrokeRandomSource(); m_d->strokeTimeoutTimer.setSingleShot(true); connect(&m_d->strokeTimeoutTimer, SIGNAL(timeout()), SLOT(finishStroke())); connect(&m_d->airbrushingTimer, SIGNAL(timeout()), SLOT(doAirbrushing())); connect(&m_d->asynchronousUpdatesThresholdTimer, SIGNAL(timeout()), SLOT(doAsynchronousUpdate())); connect(&m_d->stabilizerPollTimer, SIGNAL(timeout()), SLOT(stabilizerPollAndPaint())); connect(m_d->smoothingOptions.data(), SIGNAL(sigSmoothingTypeChanged()), SLOT(slotSmoothingTypeChanged())); m_d->stabilizerDelayedPaintHelper.setPaintLineCallback( [this](const KisPaintInformation &pi1, const KisPaintInformation &pi2) { paintLine(pi1, pi2); }); m_d->stabilizerDelayedPaintHelper.setUpdateOutlineCallback( [this]() { emit requestExplicitUpdateOutline(); }); } KisToolFreehandHelper::~KisToolFreehandHelper() { delete m_d; } void KisToolFreehandHelper::setSmoothness(KisSmoothingOptionsSP smoothingOptions) { m_d->smoothingOptions = smoothingOptions; } KisSmoothingOptionsSP KisToolFreehandHelper::smoothingOptions() const { return m_d->smoothingOptions; } QPainterPath KisToolFreehandHelper::paintOpOutline(const QPointF &savedCursorPos, const KoPointerEvent *event, const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const { KisPaintOpSettingsSP settings = globalSettings; KisPaintInformation info = m_d->infoBuilder->hover(savedCursorPos, event); QPointF prevPoint = m_d->lastCursorPos.pushThroughHistory(savedCursorPos); qreal startAngle = KisAlgebra2D::directionBetweenPoints(prevPoint, savedCursorPos, 0); info.setCanvasRotation(m_d->canvasRotation); info.setCanvasHorizontalMirrorState( m_d->canvasMirroredH ); KisDistanceInformation distanceInfo(prevPoint, startAngle); if (!m_d->strokeInfos.isEmpty()) { settings = m_d->resources->currentPaintOpPreset()->settings(); if (m_d->stabilizerDelayedPaintHelper.running() && m_d->stabilizerDelayedPaintHelper.hasLastPaintInformation()) { info = m_d->stabilizerDelayedPaintHelper.lastPaintInformation(); } else { info = m_d->previousPaintInformation; } /** * When LoD mode is active it may happen that the helper has * already started a stroke, but it painted noting, because * all the work is being calculated by the scaled-down LodN * stroke. So at first we try to fetch the data from the lodN * stroke ("buddy") and then check if there is at least * something has been painted with this distance information * object. */ KisDistanceInformation *buddyDistance = m_d->strokeInfos.first()->buddyDragDistance(); if (buddyDistance) { /** * Tiny hack alert: here we fetch the distance information * directly from the LodN stroke. Ideally, we should * upscale its data, but here we just override it with our * local copy of the coordinates. */ distanceInfo = *buddyDistance; distanceInfo.overrideLastValues(prevPoint, startAngle); } else if (m_d->strokeInfos.first()->dragDistance->isStarted()) { distanceInfo = *m_d->strokeInfos.first()->dragDistance; } } KisPaintInformation::DistanceInformationRegistrar registrar = info.registerDistanceInformation(&distanceInfo); info.setRandomSource(m_d->fakeDabRandomSource); info.setPerStrokeRandomSource(m_d->fakeStrokeRandomSource); QPainterPath outline = settings->brushOutline(info, mode); if (m_d->resources && m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER && m_d->smoothingOptions->useDelayDistance()) { const qreal R = m_d->smoothingOptions->delayDistance() / m_d->resources->effectiveZoom(); outline.addEllipse(info.pos(), R, R); } return outline; } void KisToolFreehandHelper::cursorMoved(const QPointF &cursorPos) { m_d->lastCursorPos.pushThroughHistory(cursorPos); } void KisToolFreehandHelper::initPaint(KoPointerEvent *event, const QPointF &pixelCoords, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode, KisDefaultBoundsBaseSP bounds) { QPointF prevPoint = m_d->lastCursorPos.pushThroughHistory(pixelCoords); m_d->strokeTime.start(); KisPaintInformation pi = m_d->infoBuilder->startStroke(event, elapsedStrokeTime(), resourceManager); qreal startAngle = KisAlgebra2D::directionBetweenPoints(prevPoint, pixelCoords, 0.0); initPaintImpl(startAngle, pi, resourceManager, image, currentNode, strokesFacade, overrideNode, bounds); } bool KisToolFreehandHelper::isRunning() const { return m_d->strokeId; } void KisToolFreehandHelper::initPaintImpl(qreal startAngle, const KisPaintInformation &pi, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode, KisDefaultBoundsBaseSP bounds) { m_d->strokesFacade = strokesFacade; m_d->haveTangent = false; m_d->previousTangent = QPointF(); m_d->hasPaintAtLeastOnce = false; m_d->previousPaintInformation = pi; m_d->resources = new KisResourcesSnapshot(image, currentNode, resourceManager, bounds); if(overrideNode) { m_d->resources->setCurrentNode(overrideNode); } const bool airbrushing = m_d->resources->needsAirbrushing(); const bool useSpacingUpdates = m_d->resources->needsSpacingUpdates(); KisDistanceInitInfo startDistInfo(m_d->previousPaintInformation.pos(), startAngle, useSpacingUpdates ? SPACING_UPDATE_INTERVAL : LONG_TIME, airbrushing ? TIMING_UPDATE_INTERVAL : LONG_TIME, 0); KisDistanceInformation startDist = startDistInfo.makeDistInfo(); createPainters(m_d->strokeInfos, startDist); - if(m_d->recordingAdapter) { - m_d->recordingAdapter->startStroke(image, m_d->resources, startDistInfo); - } - KisStrokeStrategy *stroke = new FreehandStrokeStrategy(m_d->resources, m_d->strokeInfos, m_d->transactionText); m_d->strokeId = m_d->strokesFacade->startStroke(stroke); m_d->history.clear(); m_d->distanceHistory.clear(); if (airbrushing) { m_d->airbrushingTimer.setInterval(computeAirbrushTimerInterval()); m_d->airbrushingTimer.start(); } else if (m_d->resources->presetNeedsAsynchronousUpdates()) { m_d->asynchronousUpdatesThresholdTimer.setInterval(80 /* msec */); m_d->asynchronousUpdatesThresholdTimer.start(); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { stabilizerStart(m_d->previousPaintInformation); } // If airbrushing, paint an initial dab immediately. This is a workaround for an issue where // some paintops (Dyna, Particle, Sketch) might never initialize their spacing/timing // information until paintAt is called. if (airbrushing) { paintAt(pi); } } void KisToolFreehandHelper::paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2) { if (tangent1.isNull() || tangent2.isNull()) return; const qreal maxSanePoint = 1e6; QPointF controlTarget1; QPointF controlTarget2; // Shows the direction in which control points go QPointF controlDirection1 = pi1.pos() + tangent1; QPointF controlDirection2 = pi2.pos() - tangent2; // Lines in the direction of the control points QLineF line1(pi1.pos(), controlDirection1); QLineF line2(pi2.pos(), controlDirection2); // Lines to check whether the control points lay on the opposite // side of the line QLineF line3(controlDirection1, controlDirection2); QLineF line4(pi1.pos(), pi2.pos()); QPointF intersection; if (line3.intersect(line4, &intersection) == QLineF::BoundedIntersection) { qreal controlLength = line4.length() / 2; line1.setLength(controlLength); line2.setLength(controlLength); controlTarget1 = line1.p2(); controlTarget2 = line2.p2(); } else { QLineF::IntersectType type = line1.intersect(line2, &intersection); if (type == QLineF::NoIntersection || intersection.manhattanLength() > maxSanePoint) { intersection = 0.5 * (pi1.pos() + pi2.pos()); // dbgKrita << "WARINING: there is no intersection point " // << "in the basic smoothing algoriths"; } controlTarget1 = intersection; controlTarget2 = intersection; } // shows how near to the controlTarget the value raises qreal coeff = 0.8; qreal velocity1 = QLineF(QPointF(), tangent1).length(); qreal velocity2 = QLineF(QPointF(), tangent2).length(); if (velocity1 == 0.0 || velocity2 == 0.0) { velocity1 = 1e-6; velocity2 = 1e-6; warnKrita << "WARNING: Basic Smoothing: Velocity is Zero! Please report a bug:" << ppVar(velocity1) << ppVar(velocity2); } qreal similarity = qMin(velocity1/velocity2, velocity2/velocity1); // the controls should not differ more than 50% similarity = qMax(similarity, qreal(0.5)); // when the controls are symmetric, their size should be smaller // to avoid corner-like curves coeff *= 1 - qMax(qreal(0.0), similarity - qreal(0.8)); Q_ASSERT(coeff > 0); QPointF control1; QPointF control2; if (velocity1 > velocity2) { control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1; coeff *= similarity; control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2; } else { control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2; coeff *= similarity; control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1; } paintBezierCurve(pi1, control1, control2, pi2); } qreal KisToolFreehandHelper::Private::effectiveSmoothnessDistance() const { const qreal effectiveSmoothnessDistance = !smoothingOptions->useScalableDistance() ? smoothingOptions->smoothnessDistance() : smoothingOptions->smoothnessDistance() / resources->effectiveZoom(); return effectiveSmoothnessDistance; } void KisToolFreehandHelper::paintEvent(KoPointerEvent *event) { KisPaintInformation info = m_d->infoBuilder->continueStroke(event, elapsedStrokeTime()); info.setCanvasRotation( m_d->canvasRotation ); info.setCanvasHorizontalMirrorState( m_d->canvasMirroredH ); KisUpdateTimeMonitor::instance()->reportMouseMove(info.pos()); paint(info); } void KisToolFreehandHelper::paint(KisPaintInformation &info) { /** * Smooth the coordinates out using the history and the * distance. This is a heavily modified version of an algo used in * Gimp and described in https://bugs.kde.org/show_bug.cgi?id=281267 and * http://www24.atwiki.jp/sigetch_2007/pages/17.html. The main * differences are: * * 1) It uses 'distance' instead of 'velocity', since time * measurements are too unstable in realworld environment * * 2) There is no 'Quality' parameter, since the number of samples * is calculated automatically * * 3) 'Tail Aggressiveness' is used for controlling the end of the * stroke * * 4) The formila is a little bit different: 'Distance' parameter * stands for $3 \Sigma$ */ if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::WEIGHTED_SMOOTHING && m_d->smoothingOptions->smoothnessDistance() > 0.0) { { // initialize current distance QPointF prevPos; if (!m_d->history.isEmpty()) { const KisPaintInformation &prevPi = m_d->history.last(); prevPos = prevPi.pos(); } else { prevPos = m_d->previousPaintInformation.pos(); } qreal currentDistance = QVector2D(info.pos() - prevPos).length(); m_d->distanceHistory.append(currentDistance); } m_d->history.append(info); qreal x = 0.0; qreal y = 0.0; if (m_d->history.size() > 3) { const qreal sigma = m_d->effectiveSmoothnessDistance() / 3.0; // '3.0' for (3 * sigma) range qreal gaussianWeight = 1 / (sqrt(2 * M_PI) * sigma); qreal gaussianWeight2 = sigma * sigma; qreal distanceSum = 0.0; qreal scaleSum = 0.0; qreal pressure = 0.0; qreal baseRate = 0.0; Q_ASSERT(m_d->history.size() == m_d->distanceHistory.size()); for (int i = m_d->history.size() - 1; i >= 0; i--) { qreal rate = 0.0; const KisPaintInformation nextInfo = m_d->history.at(i); double distance = m_d->distanceHistory.at(i); Q_ASSERT(distance >= 0.0); qreal pressureGrad = 0.0; if (i < m_d->history.size() - 1) { pressureGrad = nextInfo.pressure() - m_d->history.at(i + 1).pressure(); const qreal tailAgressiveness = 40.0 * m_d->smoothingOptions->tailAggressiveness(); if (pressureGrad > 0.0 ) { pressureGrad *= tailAgressiveness * (1.0 - nextInfo.pressure()); distance += pressureGrad * 3.0 * sigma; // (3 * sigma) --- holds > 90% of the region } } if (gaussianWeight2 != 0.0) { distanceSum += distance; rate = gaussianWeight * exp(-distanceSum * distanceSum / (2 * gaussianWeight2)); } if (m_d->history.size() - i == 1) { baseRate = rate; } else if (baseRate / rate > 100) { break; } scaleSum += rate; x += rate * nextInfo.pos().x(); y += rate * nextInfo.pos().y(); if (m_d->smoothingOptions->smoothPressure()) { pressure += rate * nextInfo.pressure(); } } if (scaleSum != 0.0) { x /= scaleSum; y /= scaleSum; if (m_d->smoothingOptions->smoothPressure()) { pressure /= scaleSum; } } if ((x != 0.0 && y != 0.0) || (x == info.pos().x() && y == info.pos().y())) { info.setPos(QPointF(x, y)); if (m_d->smoothingOptions->smoothPressure()) { info.setPressure(pressure); } m_d->history.last() = info; } } } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::SIMPLE_SMOOTHING || m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::WEIGHTED_SMOOTHING) { // Now paint between the coordinates, using the bezier curve interpolation if (!m_d->haveTangent) { m_d->haveTangent = true; m_d->previousTangent = (info.pos() - m_d->previousPaintInformation.pos()) / qMax(qreal(1.0), info.currentTime() - m_d->previousPaintInformation.currentTime()); } else { QPointF newTangent = (info.pos() - m_d->olderPaintInformation.pos()) / qMax(qreal(1.0), info.currentTime() - m_d->olderPaintInformation.currentTime()); if (newTangent.isNull() || m_d->previousTangent.isNull()) { paintLine(m_d->previousPaintInformation, info); } else { paintBezierSegment(m_d->olderPaintInformation, m_d->previousPaintInformation, m_d->previousTangent, newTangent); } m_d->previousTangent = newTangent; } m_d->olderPaintInformation = m_d->previousPaintInformation; // Enable stroke timeout only when not airbrushing. if (!m_d->airbrushingTimer.isActive()) { m_d->strokeTimeoutTimer.start(100); } } else if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::NO_SMOOTHING){ paintLine(m_d->previousPaintInformation, info); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { m_d->stabilizedSampler.addEvent(info); if (m_d->stabilizerDelayedPaintHelper.running()) { // Paint here so we don't have to rely on the timer // This is just a tricky source for a relatively stable 7ms "timer" m_d->stabilizerDelayedPaintHelper.paintSome(); } } else { m_d->previousPaintInformation = info; } if(m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.start(); } } void KisToolFreehandHelper::endPaint() { if (!m_d->hasPaintAtLeastOnce) { paintAt(m_d->previousPaintInformation); } else if (m_d->smoothingOptions->smoothingType() != KisSmoothingOptions::NO_SMOOTHING) { finishStroke(); } m_d->strokeTimeoutTimer.stop(); if(m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.stop(); } if (m_d->asynchronousUpdatesThresholdTimer.isActive()) { m_d->asynchronousUpdatesThresholdTimer.stop(); } if (m_d->smoothingOptions->smoothingType() == KisSmoothingOptions::STABILIZER) { stabilizerEnd(); } /** * There might be some timer events still pending, so * we should cancel them. Use this flag for the purpose. * Please note that we are not in MT here, so no mutex * is needed */ m_d->strokeInfos.clear(); // last update to complete rendering if there is still something pending doAsynchronousUpdate(true); m_d->strokesFacade->endStroke(m_d->strokeId); m_d->strokeId.clear(); - - if(m_d->recordingAdapter) { - m_d->recordingAdapter->endStroke(); - } } void KisToolFreehandHelper::cancelPaint() { if (!m_d->strokeId) return; m_d->strokeTimeoutTimer.stop(); if (m_d->airbrushingTimer.isActive()) { m_d->airbrushingTimer.stop(); } if (m_d->asynchronousUpdatesThresholdTimer.isActive()) { m_d->asynchronousUpdatesThresholdTimer.stop(); } if (m_d->stabilizerPollTimer.isActive()) { m_d->stabilizerPollTimer.stop(); } if (m_d->stabilizerDelayedPaintHelper.running()) { m_d->stabilizerDelayedPaintHelper.cancel(); } // see a comment in endPaint() m_d->strokeInfos.clear(); m_d->strokesFacade->cancelStroke(m_d->strokeId); m_d->strokeId.clear(); - if(m_d->recordingAdapter) { - //FIXME: not implemented - //m_d->recordingAdapter->cancelStroke(); - } } int KisToolFreehandHelper::elapsedStrokeTime() const { return m_d->strokeTime.elapsed(); } void KisToolFreehandHelper::stabilizerStart(KisPaintInformation firstPaintInfo) { m_d->usingStabilizer = true; // FIXME: Ugly hack, this is no a "distance" in any way int sampleSize = qRound(m_d->effectiveSmoothnessDistance()); sampleSize = qMax(3, sampleSize); // Fill the deque with the current value repeated until filling the sample m_d->stabilizerDeque.clear(); for (int i = sampleSize; i > 0; i--) { m_d->stabilizerDeque.enqueue(firstPaintInfo); } // Poll and draw regularly KisConfig cfg; int stabilizerSampleSize = cfg.stabilizerSampleSize(); m_d->stabilizerPollTimer.setInterval(stabilizerSampleSize); m_d->stabilizerPollTimer.start(); bool delayedPaintEnabled = cfg.stabilizerDelayedPaint(); if (delayedPaintEnabled) { m_d->stabilizerDelayedPaintHelper.start(firstPaintInfo); } m_d->stabilizedSampler.clear(); m_d->stabilizedSampler.addEvent(firstPaintInfo); } KisPaintInformation KisToolFreehandHelper::getStabilizedPaintInfo(const QQueue &queue, const KisPaintInformation &lastPaintInfo) { KisPaintInformation result(lastPaintInfo.pos(), lastPaintInfo.pressure(), lastPaintInfo.xTilt(), lastPaintInfo.yTilt(), lastPaintInfo.rotation(), lastPaintInfo.tangentialPressure(), lastPaintInfo.perspective(), elapsedStrokeTime(), lastPaintInfo.drawingSpeed()); if (queue.size() > 1) { QQueue::const_iterator it = queue.constBegin(); QQueue::const_iterator end = queue.constEnd(); /** * The first point is going to be overridden by lastPaintInfo, skip it. */ it++; int i = 2; if (m_d->smoothingOptions->stabilizeSensors()) { while (it != end) { qreal k = qreal(i - 1) / i; // coeff for uniform averaging result.KisPaintInformation::mixOtherWithoutTime(k, *it); it++; i++; } } else{ while (it != end) { qreal k = qreal(i - 1) / i; // coeff for uniform averaging result.KisPaintInformation::mixOtherOnlyPosition(k, *it); it++; i++; } } } return result; } void KisToolFreehandHelper::stabilizerPollAndPaint() { KisStabilizedEventsSampler::iterator it; KisStabilizedEventsSampler::iterator end; std::tie(it, end) = m_d->stabilizedSampler.range(); QVector delayedPaintTodoItems; for (; it != end; ++it) { KisPaintInformation sampledInfo = *it; bool canPaint = true; if (m_d->smoothingOptions->useDelayDistance()) { const qreal R = m_d->smoothingOptions->delayDistance() / m_d->resources->effectiveZoom(); QPointF diff = sampledInfo.pos() - m_d->previousPaintInformation.pos(); qreal dx = sqrt(pow2(diff.x()) + pow2(diff.y())); if (!(dx > R)) { if (m_d->resources->needsAirbrushing()) { sampledInfo.setPos(m_d->previousPaintInformation.pos()); } else { canPaint = false; } } } if (canPaint) { KisPaintInformation newInfo = getStabilizedPaintInfo(m_d->stabilizerDeque, sampledInfo); if (m_d->stabilizerDelayedPaintHelper.running()) { delayedPaintTodoItems.append(newInfo); } else { paintLine(m_d->previousPaintInformation, newInfo); } m_d->previousPaintInformation = newInfo; // Push the new entry through the queue m_d->stabilizerDeque.dequeue(); m_d->stabilizerDeque.enqueue(sampledInfo); } else if (m_d->stabilizerDeque.head().pos() != m_d->previousPaintInformation.pos()) { QQueue::iterator it = m_d->stabilizerDeque.begin(); QQueue::iterator end = m_d->stabilizerDeque.end(); while (it != end) { *it = m_d->previousPaintInformation; ++it; } } } m_d->stabilizedSampler.clear(); if (m_d->stabilizerDelayedPaintHelper.running()) { m_d->stabilizerDelayedPaintHelper.update(delayedPaintTodoItems); } else { emit requestExplicitUpdateOutline(); } } void KisToolFreehandHelper::stabilizerEnd() { // Stop the timer m_d->stabilizerPollTimer.stop(); // Finish the line if (m_d->smoothingOptions->finishStabilizedCurve()) { // Process all the existing events first stabilizerPollAndPaint(); // Draw the finish line with pending events and a time override m_d->stabilizedSampler.addFinishingEvent(m_d->stabilizerDeque.size()); stabilizerPollAndPaint(); } if (m_d->stabilizerDelayedPaintHelper.running()) { m_d->stabilizerDelayedPaintHelper.end(); } m_d->usingStabilizer = false; } void KisToolFreehandHelper::slotSmoothingTypeChanged() { if (!isRunning()) { return; } KisSmoothingOptions::SmoothingType currentSmoothingType = m_d->smoothingOptions->smoothingType(); if (m_d->usingStabilizer && (currentSmoothingType != KisSmoothingOptions::STABILIZER)) { stabilizerEnd(); } else if (!m_d->usingStabilizer && (currentSmoothingType == KisSmoothingOptions::STABILIZER)) { stabilizerStart(m_d->previousPaintInformation); } } void KisToolFreehandHelper::finishStroke() { if (m_d->haveTangent) { m_d->haveTangent = false; QPointF newTangent = (m_d->previousPaintInformation.pos() - m_d->olderPaintInformation.pos()) / (m_d->previousPaintInformation.currentTime() - m_d->olderPaintInformation.currentTime()); paintBezierSegment(m_d->olderPaintInformation, m_d->previousPaintInformation, m_d->previousTangent, newTangent); } } void KisToolFreehandHelper::doAirbrushing() { // Check that the stroke hasn't ended. if (!m_d->strokeInfos.isEmpty()) { // Add a new painting update at a point identical to the previous one, except for the time // and speed information. const KisPaintInformation &prevPaint = m_d->previousPaintInformation; KisPaintInformation nextPaint(prevPaint.pos(), prevPaint.pressure(), prevPaint.xTilt(), prevPaint.yTilt(), prevPaint.rotation(), prevPaint.tangentialPressure(), prevPaint.perspective(), elapsedStrokeTime(), 0.0); paint(nextPaint); } } void KisToolFreehandHelper::doAsynchronousUpdate(bool forceUpdate) { m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::UpdateData(forceUpdate)); } int KisToolFreehandHelper::computeAirbrushTimerInterval() const { qreal realInterval = m_d->resources->airbrushingInterval() * AIRBRUSH_INTERVAL_FACTOR; return qMax(1, qFloor(realInterval)); } void KisToolFreehandHelper::paintAt(int strokeInfoId, const KisPaintInformation &pi) { m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(strokeInfoId, pi)); - if(m_d->recordingAdapter) { - m_d->recordingAdapter->addPoint(pi); - } } void KisToolFreehandHelper::paintLine(int strokeInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2) { m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(strokeInfoId, pi1, pi2)); - if(m_d->recordingAdapter) { - m_d->recordingAdapter->addLine(pi1, pi2); - } } void KisToolFreehandHelper::paintBezierCurve(int strokeInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) { #ifdef DEBUG_BEZIER_CURVES KisPaintInformation tpi1; KisPaintInformation tpi2; tpi1 = pi1; tpi2 = pi2; tpi1.setPressure(0.3); tpi2.setPressure(0.3); paintLine(tpi1, tpi2); tpi1.setPressure(0.6); tpi2.setPressure(0.3); tpi1.setPos(pi1.pos()); tpi2.setPos(control1); paintLine(tpi1, tpi2); tpi1.setPos(pi2.pos()); tpi2.setPos(control2); paintLine(tpi1, tpi2); #endif m_d->hasPaintAtLeastOnce = true; m_d->strokesFacade->addJob(m_d->strokeId, new FreehandStrokeStrategy::Data(strokeInfoId, pi1, control1, control2, pi2)); - if(m_d->recordingAdapter) { - m_d->recordingAdapter->addCurve(pi1, control1, control2, pi2); - } } void KisToolFreehandHelper::createPainters(QVector &strokeInfos, const KisDistanceInformation &startDist) { strokeInfos << new KisFreehandStrokeInfo(startDist); } void KisToolFreehandHelper::paintAt(const KisPaintInformation &pi) { paintAt(0, pi); } void KisToolFreehandHelper::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) { paintLine(0, pi1, pi2); } void KisToolFreehandHelper::paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) { paintBezierCurve(0, pi1, control1, control2, pi2); } int KisToolFreehandHelper::canvasRotation() { return m_d->canvasRotation; } void KisToolFreehandHelper::setCanvasRotation(int rotation) { m_d->canvasRotation = rotation; } bool KisToolFreehandHelper::canvasMirroredH() { return m_d->canvasMirroredH; } void KisToolFreehandHelper::setCanvasHorizontalMirrorState(bool mirrored) { m_d->canvasMirroredH = mirrored; } diff --git a/libs/ui/tool/kis_tool_freehand_helper.h b/libs/ui/tool/kis_tool_freehand_helper.h index 75840a2ee1..d313eca245 100644 --- a/libs/ui/tool/kis_tool_freehand_helper.h +++ b/libs/ui/tool/kis_tool_freehand_helper.h @@ -1,161 +1,159 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TOOL_FREEHAND_HELPER_H #define __KIS_TOOL_FREEHAND_HELPER_H #include #include #include "kis_types.h" #include "kritaui_export.h" #include #include "kis_default_bounds.h" #include #include "kis_smoothing_options.h" #include "kundo2magicstring.h" class KoPointerEvent; class KoCanvasResourceManager; class KisPaintingInformationBuilder; -class KisRecordingAdapter; class KisStrokesFacade; class KisPostExecutionUndoAdapter; class KisPaintOp; class KisFreehandStrokeInfo; class KRITAUI_EXPORT KisToolFreehandHelper : public QObject { Q_OBJECT public: KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder, const KUndo2MagicString &transactionText = KUndo2MagicString(), - KisRecordingAdapter *recordingAdapter = 0, KisSmoothingOptions *smoothingOptions = 0); ~KisToolFreehandHelper() override; void setSmoothness(KisSmoothingOptionsSP smoothingOptions); KisSmoothingOptionsSP smoothingOptions() const; bool isRunning() const; void cursorMoved(const QPointF &cursorPos); /** * @param pixelCoords - The position of the KoPointerEvent, in pixel coordinates. */ void initPaint(KoPointerEvent *event, const QPointF &pixelCoords, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP currentNode, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); void paintEvent(KoPointerEvent *event); void endPaint(); QPainterPath paintOpOutline(const QPointF &savedCursorPos, const KoPointerEvent *event, const KisPaintOpSettingsSP globalSettings, KisPaintOpSettings::OutlineMode mode) const; int canvasRotation(); void setCanvasRotation(int rotation = 0); bool canvasMirroredH(); void setCanvasHorizontalMirrorState (bool mirrored = false); Q_SIGNALS: /** * The signal is emitted when the outline should be updated * explicitly by the tool. Used by Stabilizer option, because it * paints on internal timer events instead of the on every paint() * event */ void requestExplicitUpdateOutline(); protected: void cancelPaint(); int elapsedStrokeTime() const; void initPaintImpl(qreal startAngle, const KisPaintInformation &pi, KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade, KisNodeSP overrideNode = 0, KisDefaultBoundsBaseSP bounds = 0); protected: virtual void createPainters(QVector &strokeInfos, const KisDistanceInformation &startDist); // lo-level methods for painting primitives void paintAt(int strokeInfoId, const KisPaintInformation &pi); void paintLine(int strokeInfoId, const KisPaintInformation &pi1, const KisPaintInformation &pi2); void paintBezierCurve(int strokeInfoId, const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); // hi-level methods for painting primitives virtual void paintAt(const KisPaintInformation &pi); virtual void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); virtual void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); private: void paint(KisPaintInformation &info); void paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2, QPointF tangent1, QPointF tangent2); void stabilizerStart(KisPaintInformation firstPaintInfo); void stabilizerEnd(); KisPaintInformation getStabilizedPaintInfo(const QQueue &queue, const KisPaintInformation &lastPaintInfo); int computeAirbrushTimerInterval() const; private Q_SLOTS: void finishStroke(); void doAirbrushing(); void doAsynchronousUpdate(bool forceUpdate = false); void stabilizerPollAndPaint(); void slotSmoothingTypeChanged(); private: struct Private; Private * const m_d; }; #endif /* __KIS_TOOL_FREEHAND_HELPER_H */ diff --git a/libs/ui/tool/kis_tool_multihand_helper.cpp b/libs/ui/tool/kis_tool_multihand_helper.cpp index 705c377e31..fe430d0edc 100644 --- a/libs/ui/tool/kis_tool_multihand_helper.cpp +++ b/libs/ui/tool/kis_tool_multihand_helper.cpp @@ -1,147 +1,146 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_multihand_helper.h" #include #include "kis_painter.h" #include struct KisToolMultihandHelper::Private { QVector transformations; }; KisToolMultihandHelper::KisToolMultihandHelper(KisPaintingInformationBuilder *infoBuilder, - const KUndo2MagicString &transactionText, - KisRecordingAdapter *recordingAdapter) - : KisToolFreehandHelper(infoBuilder, transactionText, recordingAdapter) + const KUndo2MagicString &transactionText) + : KisToolFreehandHelper(infoBuilder, transactionText) , d(new Private) { } KisToolMultihandHelper::~KisToolMultihandHelper() { delete d; } void KisToolMultihandHelper::setupTransformations(const QVector &transformations) { d->transformations = transformations; } void KisToolMultihandHelper::createPainters(QVector &strokeInfos, const KisDistanceInformation &startDist) { for (int i = 0; i < d->transformations.size(); i++) { strokeInfos << new KisFreehandStrokeInfo(startDist); } } void KisToolMultihandHelper::paintAt(const KisPaintInformation &pi) { for (int i = 0; i < d->transformations.size(); i++) { const QTransform &transform = d->transformations[i]; KisPaintInformation __pi = pi; QLineF rotateme(QPointF (0.0,0.0), QPointF (10.0,10.0)); rotateme.setAngle(__pi.canvasRotation()); QLineF rotated = transform.map(rotateme); - + __pi.setPos(transform.map(__pi.pos())); __pi.setCanvasRotation(rotated.angle()); if (__pi.canvasMirroredH()) { __pi.setCanvasRotation(180-__pi.canvasRotation()); __pi.setCanvasRotation(__pi.canvasRotation()+180); } paintAt(i, __pi); } } void KisToolMultihandHelper::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) { for (int i = 0; i < d->transformations.size(); i++) { const QTransform &transform = d->transformations[i]; KisPaintInformation __pi1 = pi1; KisPaintInformation __pi2 = pi2; __pi1.setPos(transform.map(__pi1.pos())); __pi2.setPos(transform.map(__pi2.pos())); - + QLineF rotateme(QPointF (0.0,0.0), QPointF (10.0,10.0)); rotateme.setAngle(__pi1.canvasRotation()); QLineF rotated = transform.map(rotateme); __pi1.setCanvasRotation(rotated.angle()); rotateme.setAngle(__pi2.canvasRotation()); rotated = transform.map(rotateme); __pi2.setCanvasRotation(rotated.angle()); //check mirroring if (__pi2.canvasMirroredH()) { __pi1.setCanvasRotation(180-__pi1.canvasRotation()); - __pi1.setCanvasRotation(__pi1.canvasRotation()+180); + __pi1.setCanvasRotation(__pi1.canvasRotation()+180); __pi2.setCanvasRotation(180-__pi2.canvasRotation()); __pi2.setCanvasRotation(__pi2.canvasRotation()+180); } - + paintLine(i, __pi1, __pi2); } } void KisToolMultihandHelper::paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) { for (int i = 0; i < d->transformations.size(); i++) { const QTransform &transform = d->transformations[i]; KisPaintInformation __pi1 = pi1; KisPaintInformation __pi2 = pi2; __pi1.setPos(transform.map(__pi1.pos())); __pi2.setPos(transform.map(__pi2.pos())); - + QLineF rotateme(QPointF (0.0,0.0), QPointF (10.0,10.0)); rotateme.setAngle(__pi1.canvasRotation()); QLineF rotated = transform.map(rotateme); __pi1.setCanvasRotation(rotated.angle()); - + rotateme.setAngle(__pi2.canvasRotation()); rotated = transform.map(rotateme); __pi2.setCanvasRotation(rotated.angle()); - + if (__pi2.canvasMirroredH()) { __pi1.setCanvasRotation(180-__pi1.canvasRotation()); - __pi1.setCanvasRotation(__pi1.canvasRotation()+180); + __pi1.setCanvasRotation(__pi1.canvasRotation()+180); __pi2.setCanvasRotation(180-__pi2.canvasRotation()); __pi2.setCanvasRotation(__pi2.canvasRotation()+180); } - + QPointF __control1 = transform.map(control1); QPointF __control2 = transform.map(control2); paintBezierCurve(i, __pi1, __control1, __control2, __pi2); } } diff --git a/libs/ui/tool/kis_tool_multihand_helper.h b/libs/ui/tool/kis_tool_multihand_helper.h index 5530ce58a2..38a31b6e1c 100644 --- a/libs/ui/tool/kis_tool_multihand_helper.h +++ b/libs/ui/tool/kis_tool_multihand_helper.h @@ -1,60 +1,59 @@ /* * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TOOL_MULTIHAND_HELPER_H #define __KIS_TOOL_MULTIHAND_HELPER_H #include "kis_tool_freehand_helper.h" class KRITAUI_EXPORT KisToolMultihandHelper : public KisToolFreehandHelper { Q_OBJECT public: KisToolMultihandHelper(KisPaintingInformationBuilder *infoBuilder, - const KUndo2MagicString &transactionText, - KisRecordingAdapter *recordingAdapter = 0); + const KUndo2MagicString &transactionText); ~KisToolMultihandHelper() override; void setupTransformations(const QVector &transformations); protected: void createPainters(QVector &strokeInfos, const KisDistanceInformation &startDist) override; void paintAt(const KisPaintInformation &pi) override; void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) override; void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2) override; using KisToolFreehandHelper::paintAt; using KisToolFreehandHelper::paintLine; using KisToolFreehandHelper::paintBezierCurve; private: struct Private; Private * const d; }; #endif /* __KIS_TOOL_MULTIHAND_HELPER_H */ diff --git a/libs/ui/tool/kis_tool_paint.cc b/libs/ui/tool/kis_tool_paint.cc index 7b32baba97..83fe524bad 100644 --- a/libs/ui/tool/kis_tool_paint.cc +++ b/libs/ui/tool/kis_tool_paint.cc @@ -1,815 +1,804 @@ /* * Copyright (c) 2003-2009 Boudewijn Rempt * Copyright (c) 2015 Moritz Molch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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_paint.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_display_color_converter.h" #include #include #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_slider_spin_box.h" #include "kis_canvas_resource_provider.h" -#include #include "kis_tool_utils.h" #include #include #include #include #include "strokes/kis_color_picker_stroke_strategy.h" #include KisToolPaint::KisToolPaint(KoCanvasBase *canvas, const QCursor &cursor) : KisTool(canvas, cursor), m_showColorPreview(false), m_colorPreviewShowComparePlate(false), m_colorPickerDelayTimer(), m_isOutlineEnabled(true) { m_specialHoverModifier = false; m_optionsWidgetLayout = 0; m_opacity = OPACITY_OPAQUE_U8; m_supportOutline = false; { int maxSize = KisConfig().readEntry("maximumBrushSize", 1000); int brushSize = 1; do { m_standardBrushSizes.push_back(brushSize); int increment = qMax(1, int(std::ceil(qreal(brushSize) / 15))); brushSize += increment; } while (brushSize < maxSize); m_standardBrushSizes.push_back(maxSize); } KisCanvas2 *kiscanvas = dynamic_cast(canvas); KisActionManager *actionManager = kiscanvas->viewManager()->actionManager(); // XXX: Perhaps a better place for these? if (!actionManager->actionByName("increase_brush_size")) { KisAction *increaseBrushSize = new KisAction(i18n("Increase Brush Size")); increaseBrushSize->setShortcut(Qt::Key_BracketRight); actionManager->addAction("increase_brush_size", increaseBrushSize); } if (!actionManager->actionByName("decrease_brush_size")) { KisAction *decreaseBrushSize = new KisAction(i18n("Decrease Brush Size")); decreaseBrushSize->setShortcut(Qt::Key_BracketLeft); actionManager->addAction("decrease_brush_size", decreaseBrushSize); } addAction("increase_brush_size", dynamic_cast(actionManager->actionByName("increase_brush_size"))); addAction("decrease_brush_size", dynamic_cast(actionManager->actionByName("decrease_brush_size"))); connect(this, SIGNAL(sigPaintingFinished()), kiscanvas->viewManager()->resourceProvider(), SLOT(slotPainting())); m_colorPickerDelayTimer.setSingleShot(true); connect(&m_colorPickerDelayTimer, SIGNAL(timeout()), this, SLOT(activatePickColorDelayed())); using namespace std::placeholders; // For _1 placeholder std::function callback = std::bind(&KisToolPaint::addPickerJob, this, _1); m_colorPickingCompressor.reset( new PickingCompressor(100, callback, KisSignalCompressor::FIRST_ACTIVE)); } KisToolPaint::~KisToolPaint() { } int KisToolPaint::flags() const { return KisTool::FLAG_USES_CUSTOM_COMPOSITEOP; } void KisToolPaint::canvasResourceChanged(int key, const QVariant& v) { KisTool::canvasResourceChanged(key, v); switch(key) { case(KisCanvasResourceProvider::Opacity): setOpacity(v.toDouble()); break; default: //nothing break; } connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle()), Qt::UniqueConnection); } void KisToolPaint::activate(ToolActivation toolActivation, const QSet &shapes) { if (currentPaintOpPreset()) { QString formattedBrushName = currentPaintOpPreset()->name().replace("_", " "); emit statusTextChanged(formattedBrushName); } KisTool::activate(toolActivation, shapes); if (flags() & KisTool::FLAG_USES_CUSTOM_SIZE) { connect(action("increase_brush_size"), SIGNAL(triggered()), SLOT(increaseBrushSize()), Qt::UniqueConnection); connect(action("decrease_brush_size"), SIGNAL(triggered()), SLOT(decreaseBrushSize()), Qt::UniqueConnection); } KisCanvasResourceProvider *provider = qobject_cast(canvas())->viewManager()->resourceProvider(); m_oldOpacity = provider->opacity(); provider->setOpacity(m_localOpacity); } void KisToolPaint::deactivate() { if (flags() & KisTool::FLAG_USES_CUSTOM_SIZE) { disconnect(action("increase_brush_size"), 0, this, 0); disconnect(action("decrease_brush_size"), 0, this, 0); } KisCanvasResourceProvider *provider = qobject_cast(canvas())->viewManager()->resourceProvider(); m_localOpacity = provider->opacity(); provider->setOpacity(m_oldOpacity); KisTool::deactivate(); } QPainterPath KisToolPaint::tryFixBrushOutline(const QPainterPath &originalOutline) { KisConfig cfg; if (cfg.newOutlineStyle() == OUTLINE_NONE) return originalOutline; const qreal minThresholdSize = cfg.outlineSizeMinimum(); /** * If the brush outline is bigger than the canvas itself (which * would make it invisible for a user in most of the cases) just * add a cross in the center of it */ QSize widgetSize = canvas()->canvasWidget()->size(); const int maxThresholdSum = widgetSize.width() + widgetSize.height(); QPainterPath outline = originalOutline; QRectF boundingRect = outline.boundingRect(); const qreal sum = boundingRect.width() + boundingRect.height(); QPointF center = boundingRect.center(); if (sum > maxThresholdSum) { const int hairOffset = 7; outline.moveTo(center.x(), center.y() - hairOffset); outline.lineTo(center.x(), center.y() + hairOffset); outline.moveTo(center.x() - hairOffset, center.y()); outline.lineTo(center.x() + hairOffset, center.y()); } else if (sum < minThresholdSize && !outline.isEmpty()) { outline = QPainterPath(); outline.addEllipse(center, 0.5 * minThresholdSize, 0.5 * minThresholdSize); } return outline; } void KisToolPaint::paint(QPainter &gc, const KoViewConverter &converter) { Q_UNUSED(converter); QPainterPath path = tryFixBrushOutline(pixelToView(m_currentOutline)); paintToolOutline(&gc, path); if (m_showColorPreview) { QRectF viewRect = converter.documentToView(m_oldColorPreviewRect); gc.fillRect(viewRect, m_colorPreviewCurrentColor); if (m_colorPreviewShowComparePlate) { QRectF baseColorRect = viewRect.translated(viewRect.width(), 0); gc.fillRect(baseColorRect, m_colorPreviewBaseColor); } } } void KisToolPaint::setMode(ToolMode mode) { if(this->mode() == KisTool::PAINT_MODE && mode != KisTool::PAINT_MODE) { // Let's add history information about recently used colors emit sigPaintingFinished(); } KisTool::setMode(mode); } void KisToolPaint::activatePickColor(AlternateAction action) { m_showColorPreview = true; requestUpdateOutline(m_outlineDocPoint, 0); int resource = colorPreviewResourceId(action); KoColor color = canvas()->resourceManager()->koColorResource(resource); KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas); m_colorPreviewCurrentColor = kisCanvas->displayColorConverter()->toQColor(color); if (!m_colorPreviewBaseColor.isValid()) { m_colorPreviewBaseColor = m_colorPreviewCurrentColor; } } void KisToolPaint::deactivatePickColor(AlternateAction action) { Q_UNUSED(action); m_showColorPreview = false; m_oldColorPreviewRect = QRect(); m_oldColorPreviewUpdateRect = QRect(); m_colorPreviewCurrentColor = QColor(); } void KisToolPaint::pickColorWasOverridden() { m_colorPreviewShowComparePlate = false; m_colorPreviewBaseColor = QColor(); } void KisToolPaint::activateAlternateAction(AlternateAction action) { switch (action) { case PickFgNode: /* Falls through */ case PickBgNode: /* Falls through */ case PickFgImage: /* Falls through */ case PickBgImage: delayedAction = action; m_colorPickerDelayTimer.start(100); /* Falls through */ default: pickColorWasOverridden(); KisTool::activateAlternateAction(action); }; } void KisToolPaint::activatePickColorDelayed() { switch (delayedAction) { case PickFgNode: useCursor(KisCursor::pickerLayerForegroundCursor()); activatePickColor(delayedAction); break; case PickBgNode: useCursor(KisCursor::pickerLayerBackgroundCursor()); activatePickColor(delayedAction); break; case PickFgImage: useCursor(KisCursor::pickerImageForegroundCursor()); activatePickColor(delayedAction); break; case PickBgImage: useCursor(KisCursor::pickerImageBackgroundCursor()); activatePickColor(delayedAction); break; default: break; }; repaintDecorations(); } bool KisToolPaint::isPickingAction(AlternateAction action) { return action == PickFgNode || action == PickBgNode || action == PickFgImage || action == PickBgImage; } void KisToolPaint::deactivateAlternateAction(AlternateAction action) { if (!isPickingAction(action)) { KisTool::deactivateAlternateAction(action); return; } delayedAction = KisTool::NONE; m_colorPickerDelayTimer.stop(); resetCursorStyle(); deactivatePickColor(action); } void KisToolPaint::addPickerJob(const PickingJob &pickingJob) { /** * The actual picking is delayed by a compressor, so we can get this * event when the stroke is already closed */ if (!m_pickerStrokeId) return; KIS_ASSERT_RECOVER_RETURN(isPickingAction(pickingJob.action)); const QPoint imagePoint = image()->documentToImagePixelFloored(pickingJob.documentPixel); const bool fromCurrentNode = pickingJob.action == PickFgNode || pickingJob.action == PickBgNode; m_pickingResource = colorPreviewResourceId(pickingJob.action); if (!fromCurrentNode) { auto *kisCanvas = dynamic_cast(canvas()); KIS_SAFE_ASSERT_RECOVER_RETURN(kisCanvas); KisSharedPtr referencesLayer = kisCanvas->imageView()->document()->referenceImagesLayer(); if (referencesLayer) { QColor color = referencesLayer->getPixel(imagePoint); if (color.isValid() && color.alpha() != 0) { slotColorPickingFinished(KoColor(color, image()->colorSpace())); return; } } } KisPaintDeviceSP device = fromCurrentNode ? currentNode()->colorPickSourceDevice() : image()->projection(); // Used for color picker blending. KoColor currentColor = canvas()->resourceManager()->foregroundColor(); if( pickingJob.action == PickBgNode || pickingJob.action == PickBgImage ){ currentColor = canvas()->resourceManager()->backgroundColor(); } image()->addJob(m_pickerStrokeId, new KisColorPickerStrokeStrategy::Data(device, imagePoint, currentColor)); } void KisToolPaint::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { if (isPickingAction(action)) { KIS_ASSERT_RECOVER_RETURN(!m_pickerStrokeId); setMode(SECONDARY_PAINT_MODE); KisColorPickerStrokeStrategy *strategy = new KisColorPickerStrokeStrategy(); connect(strategy, &KisColorPickerStrokeStrategy::sigColorUpdated, this, &KisToolPaint::slotColorPickingFinished); m_pickerStrokeId = image()->startStroke(strategy); m_colorPickingCompressor->start(PickingJob(event->point, action)); requestUpdateOutline(event->point, event); } else { KisTool::beginAlternateAction(event, action); } } void KisToolPaint::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { if (isPickingAction(action)) { KIS_ASSERT_RECOVER_RETURN(m_pickerStrokeId); m_colorPickingCompressor->start(PickingJob(event->point, action)); requestUpdateOutline(event->point, event); } else { KisTool::continueAlternateAction(event, action); } } void KisToolPaint::endAlternateAction(KoPointerEvent *event, AlternateAction action) { if (isPickingAction(action)) { KIS_ASSERT_RECOVER_RETURN(m_pickerStrokeId); image()->endStroke(m_pickerStrokeId); m_pickerStrokeId.clear(); requestUpdateOutline(event->point, event); setMode(HOVER_MODE); } else { KisTool::endAlternateAction(event, action); } } int KisToolPaint::colorPreviewResourceId(AlternateAction action) { bool toForegroundColor = action == PickFgNode || action == PickFgImage; int resource = toForegroundColor ? KoCanvasResourceManager::ForegroundColor : KoCanvasResourceManager::BackgroundColor; return resource; } void KisToolPaint::slotColorPickingFinished(const KoColor &color) { canvas()->resourceManager()->setResource(m_pickingResource, color); if (!m_showColorPreview) return; KisCanvas2 * kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas); QColor previewColor = kisCanvas->displayColorConverter()->toQColor(color); m_colorPreviewShowComparePlate = true; m_colorPreviewCurrentColor = previewColor; requestUpdateOutline(m_outlineDocPoint, 0); } void KisToolPaint::mousePressEvent(KoPointerEvent *event) { KisTool::mousePressEvent(event); if (mode() == KisTool::HOVER_MODE) { requestUpdateOutline(event->point, event); } } void KisToolPaint::mouseMoveEvent(KoPointerEvent *event) { KisTool::mouseMoveEvent(event); if (mode() == KisTool::HOVER_MODE) { requestUpdateOutline(event->point, event); } } void KisToolPaint::mouseReleaseEvent(KoPointerEvent *event) { KisTool::mouseReleaseEvent(event); if (mode() == KisTool::HOVER_MODE) { requestUpdateOutline(event->point, event); } } QWidget * KisToolPaint::createOptionWidget() { QWidget *optionWidget = new QWidget(); optionWidget->setObjectName(toolId()); QVBoxLayout *verticalLayout = new QVBoxLayout(optionWidget); verticalLayout->setObjectName("KisToolPaint::OptionWidget::VerticalLayout"); verticalLayout->setContentsMargins(0,0,0,0); verticalLayout->setSpacing(5); // See https://bugs.kde.org/show_bug.cgi?id=316896 QWidget *specialSpacer = new QWidget(optionWidget); specialSpacer->setObjectName("SpecialSpacer"); specialSpacer->setFixedSize(0, 0); verticalLayout->addWidget(specialSpacer); verticalLayout->addWidget(specialSpacer); m_optionsWidgetLayout = new QGridLayout(); m_optionsWidgetLayout->setColumnStretch(1, 1); verticalLayout->addLayout(m_optionsWidgetLayout); m_optionsWidgetLayout->setContentsMargins(0,0,0,0); m_optionsWidgetLayout->setSpacing(5); if (!quickHelp().isEmpty()) { QPushButton *push = new QPushButton(KisIconUtils::loadIcon("help-contents"), QString(), optionWidget); connect(push, SIGNAL(clicked()), this, SLOT(slotPopupQuickHelp())); QHBoxLayout *hLayout = new QHBoxLayout(optionWidget); hLayout->addWidget(push); hLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); verticalLayout->addLayout(hLayout); } return optionWidget; } QWidget* findLabelWidget(QGridLayout *layout, QWidget *control) { QWidget *result = 0; int index = layout->indexOf(control); int row, col, rowSpan, colSpan; layout->getItemPosition(index, &row, &col, &rowSpan, &colSpan); if (col > 0) { QLayoutItem *item = layout->itemAtPosition(row, col - 1); if (item) { result = item->widget(); } } else { QLayoutItem *item = layout->itemAtPosition(row, col + 1); if (item) { result = item->widget(); } } return result; } void KisToolPaint::showControl(QWidget *control, bool value) { control->setVisible(value); QWidget *label = findLabelWidget(m_optionsWidgetLayout, control); if (label) { label->setVisible(value); } } void KisToolPaint::enableControl(QWidget *control, bool value) { control->setEnabled(value); QWidget *label = findLabelWidget(m_optionsWidgetLayout, control); if (label) { label->setEnabled(value); } } void KisToolPaint::addOptionWidgetLayout(QLayout *layout) { Q_ASSERT(m_optionsWidgetLayout != 0); int rowCount = m_optionsWidgetLayout->rowCount(); m_optionsWidgetLayout->addLayout(layout, rowCount, 0, 1, 2); } void KisToolPaint::addOptionWidgetOption(QWidget *control, QWidget *label) { Q_ASSERT(m_optionsWidgetLayout != 0); if (label) { m_optionsWidgetLayout->addWidget(label, m_optionsWidgetLayout->rowCount(), 0); m_optionsWidgetLayout->addWidget(control, m_optionsWidgetLayout->rowCount() - 1, 1); } else { m_optionsWidgetLayout->addWidget(control, m_optionsWidgetLayout->rowCount(), 0, 1, 2); } } void KisToolPaint::setOpacity(qreal opacity) { m_opacity = quint8(opacity * OPACITY_OPAQUE_U8); } const KoCompositeOp* KisToolPaint::compositeOp() { if (currentNode()) { KisPaintDeviceSP device = currentNode()->paintDevice(); if (device) { QString op = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentCompositeOp).toString(); return device->colorSpace()->compositeOp(op); } } return 0; } void KisToolPaint::slotPopupQuickHelp() { QWhatsThis::showText(QCursor::pos(), quickHelp()); } -void KisToolPaint::setupPaintAction(KisRecordedPaintAction* action) -{ - KisTool::setupPaintAction(action); - action->setOpacity(m_opacity / qreal(255.0)); - const KoCompositeOp *op = compositeOp(); - if (op) { - action->setCompositeOp(op->id()); - } -} - KisToolPaint::NodePaintAbility KisToolPaint::nodePaintAbility() { KisNodeSP node = currentNode(); if (!node) { return NONE; } if (node->inherits("KisShapeLayer")) { return VECTOR; } if (node->inherits("KisCloneLayer")) { return CLONE; } if (node->paintDevice()) { return PAINT; } return NONE; } void KisToolPaint::activatePrimaryAction() { pickColorWasOverridden(); setOutlineEnabled(true); KisTool::activatePrimaryAction(); } void KisToolPaint::deactivatePrimaryAction() { setOutlineEnabled(false); KisTool::deactivatePrimaryAction(); } bool KisToolPaint::isOutlineEnabled() const { return m_isOutlineEnabled; } void KisToolPaint::setOutlineEnabled(bool value) { m_isOutlineEnabled = value; requestUpdateOutline(m_outlineDocPoint, 0); } void KisToolPaint::increaseBrushSize() { qreal paintopSize = currentPaintOpPreset()->settings()->paintOpSize(); std::vector::iterator result = std::upper_bound(m_standardBrushSizes.begin(), m_standardBrushSizes.end(), qRound(paintopSize)); int newValue = result != m_standardBrushSizes.end() ? *result : m_standardBrushSizes.back(); currentPaintOpPreset()->settings()->setPaintOpSize(newValue); requestUpdateOutline(m_outlineDocPoint, 0); } void KisToolPaint::decreaseBrushSize() { qreal paintopSize = currentPaintOpPreset()->settings()->paintOpSize(); std::vector::reverse_iterator result = std::upper_bound(m_standardBrushSizes.rbegin(), m_standardBrushSizes.rend(), (int)paintopSize, std::greater()); int newValue = result != m_standardBrushSizes.rend() ? *result : m_standardBrushSizes.front(); currentPaintOpPreset()->settings()->setPaintOpSize(newValue); requestUpdateOutline(m_outlineDocPoint, 0); } QRectF KisToolPaint::colorPreviewDocRect(const QPointF &outlineDocPoint) { if (!m_showColorPreview) return QRect(); KisConfig cfg; const QRectF colorPreviewViewRect = cfg.colorPreviewRect(); const QRectF colorPreviewDocumentRect = canvas()->viewConverter()->viewToDocument(colorPreviewViewRect); return colorPreviewDocumentRect.translated(outlineDocPoint); } void KisToolPaint::requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event) { if (!m_supportOutline) return; KisConfig cfg; KisPaintOpSettings::OutlineMode outlineMode; if (isOutlineEnabled() && (mode() == KisTool::GESTURE_MODE || ((cfg.newOutlineStyle() == OUTLINE_FULL || cfg.newOutlineStyle() == OUTLINE_CIRCLE || cfg.newOutlineStyle() == OUTLINE_TILT) && ((mode() == HOVER_MODE) || (mode() == PAINT_MODE && cfg.showOutlineWhilePainting()))))) { // lisp forever! outlineMode.isVisible = true; if (cfg.newOutlineStyle() == OUTLINE_CIRCLE) { outlineMode.forceCircle = true; } else if(cfg.newOutlineStyle() == OUTLINE_TILT) { outlineMode.forceCircle = true; outlineMode.showTiltDecoration = true; } else { // noop } } outlineMode.forceFullSize = cfg.forceAlwaysFullSizedOutline(); m_outlineDocPoint = outlineDocPoint; m_currentOutline = getOutlinePath(m_outlineDocPoint, event, outlineMode); QRectF outlinePixelRect = m_currentOutline.boundingRect(); QRectF outlineDocRect = currentImage()->pixelToDocument(outlinePixelRect); // This adjusted call is needed as we paint with a 3 pixel wide brush and the pen is outside the bounds of the path // Pen uses view coordinates so we have to zoom the document value to match 2 pixel in view coordiates // See BUG 275829 qreal zoomX; qreal zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); qreal xoffset = 2.0/zoomX; qreal yoffset = 2.0/zoomY; if (!outlineDocRect.isEmpty()) { outlineDocRect.adjust(-xoffset,-yoffset,xoffset,yoffset); } QRectF colorPreviewDocRect = this->colorPreviewDocRect(m_outlineDocPoint); QRectF colorPreviewDocUpdateRect; if (!colorPreviewDocRect.isEmpty()) { colorPreviewDocUpdateRect.adjust(-xoffset,-yoffset,xoffset,yoffset); } // DIRTY HACK ALERT: we should fetch the assistant's dirty rect when requesting // the update, instead of just dumbly update the entire canvas! KisCanvas2 * kiscanvas = dynamic_cast(canvas()); KisPaintingAssistantsDecorationSP decoration = kiscanvas->paintingAssistantsDecoration(); if (decoration && decoration->visible()) { kiscanvas->updateCanvas(); } else { // TODO: only this branch should be present! if (!m_oldColorPreviewUpdateRect.isEmpty()) { canvas()->updateCanvas(m_oldColorPreviewUpdateRect); } if (!m_oldOutlineRect.isEmpty()) { canvas()->updateCanvas(m_oldOutlineRect); } if (!outlineDocRect.isEmpty()) { canvas()->updateCanvas(outlineDocRect); } if (!colorPreviewDocUpdateRect.isEmpty()) { canvas()->updateCanvas(colorPreviewDocUpdateRect); } } m_oldOutlineRect = outlineDocRect; m_oldColorPreviewRect = colorPreviewDocRect; m_oldColorPreviewUpdateRect = colorPreviewDocUpdateRect; } QPainterPath KisToolPaint::getOutlinePath(const QPointF &documentPos, const KoPointerEvent *event, KisPaintOpSettings::OutlineMode outlineMode) { Q_UNUSED(event); QPointF imagePos = currentImage()->documentToPixel(documentPos); QPainterPath path = currentPaintOpPreset()->settings()-> brushOutline(KisPaintInformation(imagePos), outlineMode); return path; } diff --git a/libs/ui/tool/kis_tool_paint.h b/libs/ui/tool/kis_tool_paint.h index 93d1153d13..129d766655 100644 --- a/libs/ui/tool/kis_tool_paint.h +++ b/libs/ui/tool/kis_tool_paint.h @@ -1,212 +1,210 @@ /* * Copyright (c) 2003 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TOOL_PAINT_H_ #define KIS_TOOL_PAINT_H_ #include "kis_tool.h" #include #include #include #include #include #include #include #include #include #include "kis_signal_compressor_with_param.h" #include #include class QGridLayout; class KoCompositeOp; class KoCanvasBase; class KRITAUI_EXPORT KisToolPaint : public KisTool { Q_OBJECT public: KisToolPaint(KoCanvasBase *canvas, const QCursor &cursor); ~KisToolPaint() override; int flags() const override; void mousePressEvent(KoPointerEvent *event) override; void mouseReleaseEvent(KoPointerEvent *event) override; void mouseMoveEvent(KoPointerEvent *event) override; protected: void setMode(ToolMode mode) override; void canvasResourceChanged(int key, const QVariant &v) override; void paint(QPainter &gc, const KoViewConverter &converter) override; void activatePrimaryAction() override; void deactivatePrimaryAction() override; void activateAlternateAction(AlternateAction action) override; void deactivateAlternateAction(AlternateAction action) override; void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override; void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override; void endAlternateAction(KoPointerEvent *event, AlternateAction action) override; virtual void requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event); /** If the paint tool support outline like brushes, set to true. * If not (e.g. gradient tool), set to false. Default is false. */ void setSupportOutline(bool supportOutline) { m_supportOutline = supportOutline; } virtual QPainterPath getOutlinePath(const QPointF &documentPos, const KoPointerEvent *event, KisPaintOpSettings::OutlineMode outlineMode); protected: bool isOutlineEnabled() const; void setOutlineEnabled(bool enabled); bool pickColor(const QPointF &documentPixel, AlternateAction action); /// Add the tool-specific layout to the default option widget layout. void addOptionWidgetLayout(QLayout *layout); /// Add a widget and a label to the current option widget layout. virtual void addOptionWidgetOption(QWidget *control, QWidget *label = 0); void showControl(QWidget *control, bool value); void enableControl(QWidget *control, bool value); QWidget * createOptionWidget() override; /** * Quick help is a short help text about the way the tool functions. */ virtual QString quickHelp() const { return QString(); } - void setupPaintAction(KisRecordedPaintAction* action) override; - enum NodePaintAbility { NONE, PAINT, VECTOR, CLONE }; /// Checks if and how the tool can paint on the current node NodePaintAbility nodePaintAbility(); const KoCompositeOp* compositeOp(); public Q_SLOTS: void activate(ToolActivation toolActivation, const QSet &shapes) override; void deactivate() override; private Q_SLOTS: void slotPopupQuickHelp(); void increaseBrushSize(); void decreaseBrushSize(); void activatePickColorDelayed(); void slotColorPickingFinished(const KoColor &color); protected: quint8 m_opacity; bool m_paintOutline; QPointF m_outlineDocPoint; QPainterPath m_currentOutline; QRectF m_oldOutlineRect; bool m_showColorPreview; QRectF m_oldColorPreviewRect; QRectF m_oldColorPreviewUpdateRect; QColor m_colorPreviewCurrentColor; bool m_colorPreviewShowComparePlate; QColor m_colorPreviewBaseColor; private: QPainterPath tryFixBrushOutline(const QPainterPath &originalOutline); void setOpacity(qreal opacity); void activatePickColor(AlternateAction action); void deactivatePickColor(AlternateAction action); void pickColorWasOverridden(); int colorPreviewResourceId(AlternateAction action); QRectF colorPreviewDocRect(const QPointF &outlineDocPoint); bool isPickingAction(AlternateAction action); struct PickingJob { PickingJob() {} PickingJob(QPointF _documentPixel, AlternateAction _action) : documentPixel(_documentPixel), action(_action) {} QPointF documentPixel; AlternateAction action; }; void addPickerJob(const PickingJob &pickingJob); private: bool m_specialHoverModifier; QGridLayout *m_optionsWidgetLayout; bool m_supportOutline; /** * Used as a switch for pickColor */ // used to skip some of the tablet events and don't update the colour that often QTimer m_colorPickerDelayTimer; AlternateAction delayedAction; bool m_isOutlineEnabled; std::vector m_standardBrushSizes; KisStrokeId m_pickerStrokeId; int m_pickingResource; typedef KisSignalCompressorWithParam PickingCompressor; QScopedPointer m_colorPickingCompressor; qreal m_localOpacity {1.0}; qreal m_oldOpacity {1.0}; Q_SIGNALS: void sigPaintingFinished(); }; #endif // KIS_TOOL_PAINT_H_ diff --git a/libs/ui/tool/kis_tool_shape.cc b/libs/ui/tool/kis_tool_shape.cc index 9f46b39d2e..270a060e78 100644 --- a/libs/ui/tool/kis_tool_shape.cc +++ b/libs/ui/tool/kis_tool_shape.cc @@ -1,287 +1,234 @@ /* * Copyright (c) 2005 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_shape.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include #include "kis_figure_painting_tool_helper.h" -#include -#include +#include #include #include #include KisToolShape::KisToolShape(KoCanvasBase * canvas, const QCursor & cursor) : KisToolPaint(canvas, cursor) { m_shapeOptionsWidget = 0; } KisToolShape::~KisToolShape() { // in case the widget hasn't been shown if (m_shapeOptionsWidget && !m_shapeOptionsWidget->parent()) { delete m_shapeOptionsWidget; } } void KisToolShape::activate(ToolActivation toolActivation, const QSet &shapes) { KisToolPaint::activate(toolActivation, shapes); m_configGroup = KSharedConfig::openConfig()->group(toolId()); } int KisToolShape::flags() const { return KisTool::FLAG_USES_CUSTOM_COMPOSITEOP|KisTool::FLAG_USES_CUSTOM_PRESET |KisTool::FLAG_USES_CUSTOM_SIZE; } QWidget * KisToolShape::createOptionWidget() { m_shapeOptionsWidget = new WdgGeometryOptions(0); m_shapeOptionsWidget->cmbOutline->setCurrentIndex(KisPainter::StrokeStyleBrush); //connect two combo box event. Inherited classes can call the slots to make appropriate changes connect(m_shapeOptionsWidget->cmbOutline, SIGNAL(currentIndexChanged(int)), this, SLOT(outlineSettingChanged(int))); connect(m_shapeOptionsWidget->cmbFill, SIGNAL(currentIndexChanged(int)), this, SLOT(fillSettingChanged(int))); m_shapeOptionsWidget->cmbOutline->setCurrentIndex(m_configGroup.readEntry("outlineType", 0)); m_shapeOptionsWidget->cmbFill->setCurrentIndex(m_configGroup.readEntry("fillType", 0)); //if both settings are empty, force the outline to brush so the tool will work when first activated if ( m_shapeOptionsWidget->cmbFill->currentIndex() == 0 && m_shapeOptionsWidget->cmbOutline->currentIndex() == 0) { m_shapeOptionsWidget->cmbOutline->setCurrentIndex(1); // brush } return m_shapeOptionsWidget; } void KisToolShape::outlineSettingChanged(int value) { m_configGroup.writeEntry("outlineType", value); } void KisToolShape::fillSettingChanged(int value) { m_configGroup.writeEntry("fillType", value); } KisPainter::FillStyle KisToolShape::fillStyle(void) { if (m_shapeOptionsWidget) { return static_cast(m_shapeOptionsWidget->cmbFill->currentIndex()); } else { return KisPainter::FillStyleNone; } } KisPainter::StrokeStyle KisToolShape::strokeStyle(void) { if (m_shapeOptionsWidget) { return static_cast(m_shapeOptionsWidget->cmbOutline->currentIndex()); } else { return KisPainter::StrokeStyleNone; } } qreal KisToolShape::currentStrokeWidth() const { const qreal sizeInPx = canvas()->resourceManager()->resource(KisCanvasResourceProvider::Size).toReal(); return canvas()->unit().fromUserValue(sizeInPx); } -void KisToolShape::setupPaintAction(KisRecordedPaintAction* action) -{ - KisToolPaint::setupPaintAction(action); - action->setFillStyle(fillStyle()); - action->setStrokeStyle(strokeStyle()); - action->setGenerator(currentGenerator()); - action->setPattern(currentPattern()); - action->setGradient(currentGradient()); -} - void KisToolShape::addShape(KoShape* shape) { KoImageCollection* imageCollection = canvas()->shapeController()->resourceManager()->imageCollection(); switch(fillStyle()) { case KisPainter::FillStyleForegroundColor: shape->setBackground(QSharedPointer(new KoColorBackground(currentFgColor().toQColor()))); break; case KisPainter::FillStyleBackgroundColor: shape->setBackground(QSharedPointer(new KoColorBackground(currentBgColor().toQColor()))); break; case KisPainter::FillStylePattern: if (imageCollection) { QSharedPointer fill(new KoPatternBackground(imageCollection)); if (currentPattern()) { fill->setPattern(currentPattern()->pattern()); shape->setBackground(fill); } } else { shape->setBackground(QSharedPointer(0)); } break; case KisPainter::FillStyleGradient: { QLinearGradient *gradient = new QLinearGradient(QPointF(0, 0), QPointF(1, 1)); gradient->setCoordinateMode(QGradient::ObjectBoundingMode); gradient->setStops(currentGradient()->toQGradient()->stops()); QSharedPointer gradientFill(new KoGradientBackground(gradient)); shape->setBackground(gradientFill); } break; case KisPainter::FillStyleNone: default: shape->setBackground(QSharedPointer(0)); break; } switch (strokeStyle()) { case KisPainter::StrokeStyleNone: shape->setStroke(KoShapeStrokeModelSP()); break; case KisPainter::StrokeStyleBrush: { KoShapeStrokeSP stroke(new KoShapeStroke()); stroke->setLineWidth(currentStrokeWidth()); stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor()); shape->setStroke(stroke); break; } } KUndo2Command *parentCommand = new KUndo2Command(); KoSelection *selection = canvas()->selectedShapesProxy()->selection(); const QList oldSelectedShapes = selection->selectedShapes(); // reset selection on the newly added shape :) // TODO: think about moving this into controller->addShape? new KoKeepShapesSelectedCommand(oldSelectedShapes, {shape}, canvas()->selectedShapesProxy(), false, parentCommand); KUndo2Command *cmd = canvas()->shapeController()->addShape(shape, 0, parentCommand); parentCommand->setText(cmd->text()); new KoKeepShapesSelectedCommand(oldSelectedShapes, {shape}, canvas()->selectedShapesProxy(), true, parentCommand); canvas()->addCommand(parentCommand); } void KisToolShape::addPathShape(KoPathShape* pathShape, const KUndo2MagicString& name) { KisNodeSP node = currentNode(); if (!node || !blockUntilOperationsFinished()) { return; } - // Get painting options - KisPaintOpPresetSP preset = currentPaintOpPreset(); // Compute the outline KisImageSP image = this->image(); QTransform matrix; matrix.scale(image->xRes(), image->yRes()); matrix.translate(pathShape->position().x(), pathShape->position().y()); QPainterPath mapedOutline = matrix.map(pathShape->outline()); - // Recorde the paint action - KisRecordedPathPaintAction bezierCurvePaintAction( - KisNodeQueryPath::absolutePath(node), - preset, - KisDistanceInitInfo()); - bezierCurvePaintAction.setPaintColor(currentFgColor()); - QPointF lastPoint, nextPoint; - int elementCount = mapedOutline.elementCount(); - for (int i = 0; i < elementCount; i++) { - QPainterPath::Element element = mapedOutline.elementAt(i); - switch (element.type) { - case QPainterPath::MoveToElement: - if (i != 0) { - qFatal("Unhandled"); // XXX: I am not sure the tool can produce such element, deal with it when it can - } - lastPoint = QPointF(element.x, element.y); - break; - case QPainterPath::LineToElement: - nextPoint = QPointF(element.x, element.y); - bezierCurvePaintAction.addLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint)); - lastPoint = nextPoint; - break; - case QPainterPath::CurveToElement: - nextPoint = QPointF(mapedOutline.elementAt(i + 2).x, mapedOutline.elementAt(i + 2).y); - bezierCurvePaintAction.addCurve(KisPaintInformation(lastPoint), - QPointF(mapedOutline.elementAt(i).x, - mapedOutline.elementAt(i).y), - QPointF(mapedOutline.elementAt(i + 1).x, - mapedOutline.elementAt(i + 1).y), - KisPaintInformation(nextPoint)); - lastPoint = nextPoint; - break; - default: - continue; - } - } - image->actionRecorder()->addAction(bezierCurvePaintAction); - if (node->hasEditablePaintDevice()) { KisFigurePaintingToolHelper helper(name, image, node, canvas()->resourceManager(), strokeStyle(), fillStyle()); helper.paintPainterPath(mapedOutline); } else if (node->inherits("KisShapeLayer")) { pathShape->normalize(); addShape(pathShape); } notifyModified(); } diff --git a/libs/ui/tool/kis_tool_shape.h b/libs/ui/tool/kis_tool_shape.h index fcd913d999..71aa222204 100644 --- a/libs/ui/tool/kis_tool_shape.h +++ b/libs/ui/tool/kis_tool_shape.h @@ -1,86 +1,84 @@ /* * Copyright (c) 2005 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TOOL_SHAPE_H_ #define KIS_TOOL_SHAPE_H_ #include #include #include #include "kis_tool_paint.h" #include "kis_painter.h" #include "ui_wdggeometryoptions.h" class KoCanvasBase; class KoPathShape; class WdgGeometryOptions : public QWidget, public Ui::WdgGeometryOptions { Q_OBJECT public: WdgGeometryOptions(QWidget *parent) : QWidget(parent) { setupUi(this); } }; /** * Base for tools specialized in drawing shapes */ class KRITAUI_EXPORT KisToolShape : public KisToolPaint { Q_OBJECT public: KisToolShape(KoCanvasBase * canvas, const QCursor & cursor); ~KisToolShape() override; int flags() const override; WdgGeometryOptions *m_shapeOptionsWidget; public Q_SLOTS: void activate(ToolActivation toolActivation, const QSet &shapes) override; virtual void outlineSettingChanged(int value); virtual void fillSettingChanged(int value); protected: QWidget* createOptionWidget() override; virtual KisPainter::FillStyle fillStyle(); KisPainter::StrokeStyle strokeStyle(); qreal currentStrokeWidth() const; - void setupPaintAction(KisRecordedPaintAction* action) override; - void addShape(KoShape* shape); void addPathShape(KoPathShape* pathShape, const KUndo2MagicString& name); KConfigGroup m_configGroup; }; #endif // KIS_TOOL_SHAPE_H_ diff --git a/plugins/extensions/CMakeLists.txt b/plugins/extensions/CMakeLists.txt index b5ed7be859..9ace76c315 100644 --- a/plugins/extensions/CMakeLists.txt +++ b/plugins/extensions/CMakeLists.txt @@ -1,21 +1,20 @@ -add_subdirectory( bigbrother ) add_subdirectory( imagesplit ) add_subdirectory( clonesarray ) add_subdirectory( colorrange ) add_subdirectory( colorspaceconversion ) add_subdirectory( histogram ) add_subdirectory( imagesize ) add_subdirectory( metadataeditor ) add_subdirectory( modify_selection ) add_subdirectory( offsetimage ) add_subdirectory( rotateimage ) add_subdirectory( separate_channels ) add_subdirectory( shearimage ) add_subdirectory( layergroupswitcher ) add_subdirectory( resourcemanager ) add_subdirectory( layersplit ) add_subdirectory( animationrenderer ) add_subdirectory( waveletdecompose ) add_subdirectory( pykrita ) add_subdirectory( qmic ) add_subdirectory( buginfo ) diff --git a/plugins/extensions/bigbrother/CMakeLists.txt b/plugins/extensions/bigbrother/CMakeLists.txt deleted file mode 100644 index 6510562d10..0000000000 --- a/plugins/extensions/bigbrother/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(kritabigbrother_SOURCES - bigbrother.cc - actionseditor/kis_actions_editor.cpp - actionseditor/kis_actions_editor_dialog.cpp - actionseditor/kis_macro_model.cpp ) - -ki18n_wrap_ui(kritabigbrother_SOURCES - actionseditor/wdgactionseditor.ui ) - -add_library(kritabigbrother MODULE ${kritabigbrother_SOURCES}) -target_link_libraries(kritabigbrother kritaui) -install(TARGETS kritabigbrother DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) -install( FILES bigbrother.xmlgui DESTINATION ${DATA_INSTALL_DIR}/kritaplugins) diff --git a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.cpp b/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.cpp deleted file mode 100644 index ee37a7df7a..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "kis_actions_editor.h" - -#include "ui_wdgactionseditor.h" - -#include "kis_macro_model.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -KisActionsEditor::KisActionsEditor(QWidget* parent) : QWidget(parent), m_currentEditor(0), m_form(new Ui::ActionsEditor), m_macro(0), m_model(0), m_widgetLayout(0) - -{ - m_form->setupUi(this); - - // Setup buttons - m_form->bnAdd->setIcon(KisIconUtils::loadIcon("list-add")); - QSignalMapper* mapper = new QSignalMapper(this); - connect(mapper, SIGNAL(mapped(QString)), SLOT(slotCreateAction(QString))); - QMenu* addMenu = new QMenu; - Q_FOREACH (const KoID& id, KisRecordedActionCreatorFactoryRegistry::instance()->creators()) - { - QAction* action = addMenu->addAction(id.name(), mapper, SLOT(map())); - mapper->setMapping(action, id.id()); - } - m_form->bnAdd->setMenu(addMenu); - - - m_form->bnDelete->setIcon(KisIconUtils::loadIcon("edit-delete")); - connect(m_form->bnDelete, SIGNAL(released()), SLOT(slotBtnDelete())); - - m_form->bnRaise->setIcon(KisIconUtils::loadIcon("arrow-up")); - connect(m_form->bnRaise, SIGNAL(released()), SLOT(slotBtnRaise())); - - m_form->bnLower->setIcon(KisIconUtils::loadIcon("arrow-down")); - connect(m_form->bnLower, SIGNAL(released()), SLOT(slotBtnLower())); - - m_form->bnDuplicate->setIcon(KisIconUtils::loadIcon("edit-copy")); - connect(m_form->bnDuplicate, SIGNAL(released()), SLOT(slotBtnDuplicate())); - - // Setup actions list - connect(m_form->actionsList, SIGNAL(clicked(const QModelIndex&)), SLOT(slotActionActivated(const QModelIndex&))); - connect(m_form->actionsList, SIGNAL(activated(QModelIndex)), SLOT(slotActionActivated(const QModelIndex&))); - - // Editor - m_widgetLayout = new QGridLayout(m_form->editorWidget); - setCurrentAction(0); -} - -KisActionsEditor::~KisActionsEditor() -{ - delete m_form; -} - -void KisActionsEditor::setMacro(KisMacro* _macro) -{ - m_macro = _macro; - KisMacroModel* oldModel = m_model; - m_model = new KisMacroModel(m_macro); - m_form->actionsList->setModel(m_model); - delete oldModel; -} - -void KisActionsEditor::slotCreateAction(const QString& _id) -{ - KisRecordedActionCreatorFactory* f = KisRecordedActionCreatorFactoryRegistry::instance()->get(_id); - Q_ASSERT(f); - if(!f) return; - KisRecordedAction* action = 0; - if(f->requireCreator()) - { - KoDialog d; - d.setButtons(KoDialog::Ok | KoDialog::Cancel); - KisRecordedActionCreator* creator = f->createCreator(&d); - d.setMainWidget(creator); - if(d.exec() == KoDialog::Accepted) - { - action = creator->createAction(); - if(!action) { - QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Failed to create an action.")); - return; - } - } - else { - return; - } - } - else { - action = f->createAction(); - } - Q_ASSERT(action); - - m_model->addAction(m_form->actionsList->currentIndex(), *action); - delete action; -} - -void KisActionsEditor::slotActionActivated(const QModelIndex& item) -{ - if (item.isValid() && m_macro) { - setCurrentAction(m_macro->actions()[item.row()]); - } else { - setCurrentAction(0); - } -} - -void KisActionsEditor::setCurrentAction(KisRecordedAction* _action) -{ - // First change, the editor - delete m_currentEditor; - m_currentEditor = 0; - if (_action) { - m_currentEditor = KisRecordedActionEditorFactoryRegistry::instance()->createEditor(this, _action); - } else { - m_currentEditor = new QLabel(i18n("No action is selected."), this); - } - if (!m_currentEditor) { - m_currentEditor = new QLabel(i18n("No editor for current action."), this); - } - m_widgetLayout->addWidget(m_currentEditor, 0 , 0); - - // Then disable/enalbed button - m_form->bnDuplicate->setEnabled(_action); - m_form->bnRaise->setEnabled(_action); - m_form->bnLower->setEnabled(_action); - m_form->bnDelete->setEnabled(_action); - if (_action) { - int pos = m_macro->actions().indexOf(_action); - if (pos == 0) { - m_form->bnRaise->setEnabled(false); - } - if (pos == m_macro->actions().count() - 1) { - m_form->bnLower->setEnabled(false); - } - } -} - -void KisActionsEditor::slotBtnDelete() -{ - QModelIndex idx = m_form->actionsList->currentIndex(); - Q_ASSERT(idx.isValid()); - m_model->removeRows(idx.row(), 1); - setCurrentAction(0); -} - -void KisActionsEditor::slotBtnDuplicate() -{ - QModelIndex idx = m_form->actionsList->currentIndex(); - Q_ASSERT(idx.isValid()); - m_model->duplicateAction(idx); -} - -void KisActionsEditor::slotBtnRaise() -{ - QModelIndex idx = m_form->actionsList->currentIndex(); - Q_ASSERT(idx.isValid()); - m_model->raise(idx); - m_form->actionsList->setCurrentIndex(m_model->index(idx.row() - 1)); - slotActionActivated(m_form->actionsList->currentIndex()); -} - -void KisActionsEditor::slotBtnLower() -{ - QModelIndex idx = m_form->actionsList->currentIndex(); - Q_ASSERT(idx.isValid()); - m_model->lower(idx); - m_form->actionsList->setCurrentIndex(m_model->index(idx.row() + 1)); - slotActionActivated(m_form->actionsList->currentIndex()); -} - diff --git a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.h b/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.h deleted file mode 100644 index 8ad167b9be..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor.h +++ /dev/null @@ -1,61 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_ACTIONS_EDITOR_H_ -#define _KIS_ACTIONS_EDITOR_H_ - -#include - -class KisMacro; -class KisMacroModel; -class KisRecordedAction; - -class QModelIndex; -class QGridLayout; - -namespace Ui -{ -class ActionsEditor; -} - -class KisActionsEditor : public QWidget -{ - Q_OBJECT -public: - KisActionsEditor(QWidget* parent); - ~KisActionsEditor() override; - void setMacro(KisMacro*); -private Q_SLOTS: - void slotCreateAction(const QString& _id); - void slotActionActivated(const QModelIndex&); - void slotBtnDelete(); - void slotBtnDuplicate(); - void slotBtnRaise(); - void slotBtnLower(); -private: - void setCurrentAction(KisRecordedAction* _action); -private: - QWidget* m_currentEditor; - Ui::ActionsEditor* m_form; - KisMacro* m_macro; - KisMacroModel* m_model; - QGridLayout* m_widgetLayout; -}; - -#endif diff --git a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.cpp b/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.cpp deleted file mode 100644 index 561b6fa237..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "kis_actions_editor_dialog.h" -#include "kis_actions_editor.h" - -#include - -KisActionsEditorDialog::KisActionsEditorDialog(QWidget* parent) : KoDialog(parent), - m_actionsEditor(new KisActionsEditor(this)) -{ - setMainWidget(m_actionsEditor); - setButtons(Cancel | Ok); - setButtonText(Ok, i18n("Save macro")); - setButtonText(Cancel, i18n("Discard changes")); -} - -KisActionsEditorDialog::~KisActionsEditorDialog() -{ -} - -KisActionsEditor* KisActionsEditorDialog::actionsEditor() -{ - return m_actionsEditor; -} diff --git a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.h b/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.h deleted file mode 100644 index 8ca9a824c2..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_actions_editor_dialog.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_ACTIONS_EDITOR_DIALOG_H_ -#define _KIS_ACTIONS_EDITOR_DIALOG_H_ - -#include - -class KisActionsEditor; - -class KisActionsEditorDialog : public KoDialog -{ -public: - KisActionsEditorDialog(QWidget* parent); - ~KisActionsEditorDialog() override; - KisActionsEditor* actionsEditor(); -private: - KisActionsEditor* m_actionsEditor; -}; - -#endif diff --git a/plugins/extensions/bigbrother/actionseditor/kis_macro_model.cpp b/plugins/extensions/bigbrother/actionseditor/kis_macro_model.cpp deleted file mode 100644 index 01f55bf677..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_macro_model.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "kis_macro_model.h" -#include -#include - -KisMacroModel::KisMacroModel(KisMacro* _macro) : m_macro(_macro) -{ -} - -KisMacroModel::~KisMacroModel() -{ -} - -int KisMacroModel::rowCount(const QModelIndex & parent) const -{ - Q_UNUSED(parent); - return m_macro->actions().count(); -} - -QVariant KisMacroModel::data(const QModelIndex & index, int role) const -{ - if (index.isValid()) { - if (role == Qt::DisplayRole || role == Qt::EditRole) { - return m_macro->actions()[index.row()]->name(); - } - } - return QVariant(); -} - -bool KisMacroModel::setData(const QModelIndex & index, const QVariant & value, int role) -{ - if (index.isValid()) { - if (role == Qt::EditRole) { - m_macro->actions()[index.row()]->setName(value.toString()); - return true; - } - } - return false; -} - -Qt::ItemFlags KisMacroModel::flags(const QModelIndex & index) const -{ - Q_UNUSED(index); - return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable; -} - -bool KisMacroModel::removeRows(int row, int count, const QModelIndex & parent) -{ - beginRemoveRows(parent, row, row + count); - - QList actions; - for (int i = row; i < row + count; ++i) { - actions.push_back(m_macro->actions()[i]); - } - m_macro->removeActions(actions); - - endRemoveRows(); - return true; -} - -void KisMacroModel::addAction(const QModelIndex& _after, const KisRecordedAction& _action) -{ - if(m_macro->actions().isEmpty()) - { - beginInsertRows(QModelIndex(), 0, 0); - m_macro->addAction(_action); - endInsertRows(); - } else { - int row = _after.row(); - beginInsertRows(QModelIndex(), row, row); - m_macro->addAction(_action, m_macro->actions().at(row)); - endInsertRows(); - } -} - -void KisMacroModel::duplicateAction(const QModelIndex& index) -{ - if (index.isValid()) { - KisRecordedAction* action = m_macro->actions()[index.row()]; - beginInsertRows(QModelIndex(), index.row(), index.row()); - m_macro->addAction(*action, action); - endInsertRows(); - } -} - -void KisMacroModel::raise(const QModelIndex& index) -{ - if (index.isValid()) { - KisRecordedAction* action = m_macro->actions()[index.row()]; - KisRecordedAction* before = m_macro->actions()[index.row() - 1]; - m_macro->moveAction(action, before); - emit(dataChanged(createIndex(index.row() - 1, 0), index)); - } -} - -void KisMacroModel::lower(const QModelIndex& index) -{ - if (index.isValid()) { - KisRecordedAction* before = m_macro->actions()[index.row()]; - KisRecordedAction* action = m_macro->actions()[index.row() + 1]; - m_macro->moveAction(action, before); - emit(dataChanged(index, createIndex(index.row() + 1, 0))); - } -} diff --git a/plugins/extensions/bigbrother/actionseditor/kis_macro_model.h b/plugins/extensions/bigbrother/actionseditor/kis_macro_model.h deleted file mode 100644 index 8cd9189f8c..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/kis_macro_model.h +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of the KDE project - * Copyright (c) 2009 Cyrille Berger - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _KIS_MACRO_MODEL_H_ -#define _KIS_MACRO_MODEL_H_ - -#include - -class KisRecordedAction; -class KisMacro; - -class KisMacroModel : public QAbstractListModel -{ -public: - KisMacroModel(KisMacro*); - ~KisMacroModel() override; - int rowCount(const QModelIndex & parent = QModelIndex()) const override; - QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags(const QModelIndex & index) const override; - bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) override; - bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()) override; - void addAction(const QModelIndex& _after, const KisRecordedAction& _action); - void duplicateAction(const QModelIndex& index); - void raise(const QModelIndex& index); - void lower(const QModelIndex& index); -private: - KisMacro* m_macro; -}; - - -#endif diff --git a/plugins/extensions/bigbrother/actionseditor/wdgactionseditor.ui b/plugins/extensions/bigbrother/actionseditor/wdgactionseditor.ui deleted file mode 100644 index f59e050634..0000000000 --- a/plugins/extensions/bigbrother/actionseditor/wdgactionseditor.ui +++ /dev/null @@ -1,197 +0,0 @@ - - - ActionsEditor - - - - 0 - 0 - 682 - 403 - - - - - - - Qt::Horizontal - - - - - - - Actions: - - - - - - - - - - - - - 0 - 0 - - - - - 32 - 22 - - - - - 22 - 22 - - - - Create a new action - - - - - - QToolButton::MenuButtonPopup - - - true - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - Duplicate action - - - Duplicate action - - - Duplicate the currently selected action - - - - - - true - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - Move an action up - - - - - - true - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - Move an action down - - - - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - Delete the current action - - - - - - true - - - - - - - - - - - - - - - diff --git a/plugins/extensions/bigbrother/bigbrother.cc b/plugins/extensions/bigbrother/bigbrother.cc deleted file mode 100644 index aeaac1beac..0000000000 --- a/plugins/extensions/bigbrother/bigbrother.cc +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger (cberger@cberger.net) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "bigbrother.h" -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "actionseditor/kis_actions_editor.h" -#include "actionseditor/kis_actions_editor_dialog.h" - -#include -#include - - -K_PLUGIN_FACTORY_WITH_JSON(BigBrotherPluginFactory, "kritabigbrother.json", registerPlugin();) - -class RecordedActionSaveContext : public KisRecordedActionSaveContext { - public: - void saveGradient(const KoAbstractGradient* ) override {} - void savePattern(const KoPattern* ) override {} -}; - -class RecordedActionLoadContext : public KisRecordedActionLoadContext { - public: - KoAbstractGradient* gradient(const QString& name) const override - { - return KoResourceServerProvider::instance()->gradientServer()->resourceByName(name); - } - KoPattern* pattern(const QString& name) const override - { - return KoResourceServerProvider::instance()->patternServer()->resourceByName(name); - } -}; - -BigBrotherPlugin::BigBrotherPlugin(QObject *parent, const QVariantList &) - : KisActionPlugin(parent) - , m_recorder(0) -{ - if (parent->inherits("KisViewManager")) { - // Open and play action - KisAction* action = createAction("Macro_Open_Play"); - connect(action, SIGNAL(triggered()), this, SLOT(slotOpenPlay())); - - // Open and edit action - action = createAction("Macro_Open_Edit"); - connect(action, SIGNAL(triggered()), this, SLOT(slotOpenEdit())); - - // Start recording action - m_startRecordingMacroAction = createAction("Recording_Start_Recording_Macro"); - connect(m_startRecordingMacroAction, SIGNAL(triggered()), this, SLOT(slotStartRecordingMacro())); - - // Save recorded action - m_stopRecordingMacroAction = createAction("Recording_Stop_Recording_Macro"); - connect(m_stopRecordingMacroAction, SIGNAL(triggered()), this, SLOT(slotStopRecordingMacro())); - m_stopRecordingMacroAction->setEnabled(false); - } -} - -BigBrotherPlugin::~BigBrotherPlugin() -{ - delete m_recorder; -} - -void BigBrotherPlugin::slotOpenPlay() -{ - KisMacro* m = openMacro(); - dbgKrita << m; - if (!m) return; - dbgPlugins << "Play the macro"; - KoUpdaterPtr updater = viewManager()->createUnthreadedUpdater(i18n("Playing back macro")); - KisMacroPlayer player(m, KisPlayInfo(viewManager()->image(), viewManager()->activeNode()), updater); - player.start(); - while(player.isRunning()) - { - QApplication::processEvents(); - } - dbgPlugins << "Finished"; - delete m; -} - - -void BigBrotherPlugin::slotOpenEdit() -{ - KisMacro *macro = openMacro(); - if (!macro) return; - KisActionsEditorDialog aed(viewManager()->mainWindow()); - - aed.actionsEditor()->setMacro(macro); - - if (aed.exec() == QDialog::Accepted) { - saveMacro(macro); - } - - delete macro; -} - -void BigBrotherPlugin::slotStartRecordingMacro() -{ - dbgPlugins << "Start recording macro"; - if (m_recorder) return; - // Alternate actions - m_startRecordingMacroAction->setEnabled(false); - m_stopRecordingMacroAction->setEnabled(true); - - // Create recorder - m_recorder = new KisMacro(); - connect(viewManager()->image()->actionRecorder(), SIGNAL(addedAction(const KisRecordedAction&)), - m_recorder, SLOT(addAction(const KisRecordedAction&))); -} - -void BigBrotherPlugin::slotStopRecordingMacro() -{ - dbgPlugins << "Stop recording macro"; - if (!m_recorder) return; - // Alternate actions - m_startRecordingMacroAction->setEnabled(true); - m_stopRecordingMacroAction->setEnabled(false); - // Save the macro - saveMacro(m_recorder); - // Delete recorder - delete m_recorder; - m_recorder = 0; -} - -KisMacro* BigBrotherPlugin::openMacro() -{ - QStringList mimeFilter; - mimeFilter << "*.krarec|Recorded actions (*.krarec)"; - - KoFileDialog dialog(viewManager()->mainWindow(), KoFileDialog::OpenFile, "OpenDocument"); - dialog.setCaption(i18n("Open Macro")); - dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); - dialog.setMimeTypeFilters(QStringList() << "application/x-krita-recorded-macro"); - QString filename = dialog.filename(); - RecordedActionLoadContext loadContext; - - if (!filename.isNull()) { - QDomDocument doc; - QFile f(filename); - if (f.exists()) { - dbgPlugins << f.open(QIODevice::ReadOnly); - QString err; - int line, col; - if (!doc.setContent(&f, &err, &line, &col)) { - // TODO error message - dbgPlugins << err << " line = " << line << " col = " << col; - f.close(); - return 0; - } - f.close(); - QDomElement docElem = doc.documentElement(); - if (!docElem.isNull() && docElem.tagName() == "RecordedActions") { - dbgPlugins << "Load the macro"; - KisMacro* m = new KisMacro(); - m->fromXML(docElem, &loadContext); - return m; - } else { - // TODO error message - } - } else { - dbgPlugins << "Unexistant file : " << filename; - } - } - return 0; -} - -void BigBrotherPlugin::saveMacro(const KisMacro* macro) -{ - KoFileDialog dialog(viewManager()->mainWindow(), KoFileDialog::SaveFile, "bigbrother"); - dialog.setCaption(i18n("Save Macro")); - dialog.setMimeTypeFilters(QStringList() << "application/x-krita-recorded-macro"); - - QString filename = dialog.filename(); - - if (!filename.isNull()) { - QDomDocument doc; - QDomElement e = doc.createElement("RecordedActions"); - RecordedActionSaveContext context; - macro->toXML(doc, e, &context); - - doc.appendChild(e); - QFile f(filename); - f.open(QIODevice::WriteOnly); - QTextStream stream(&f); - stream.setCodec("UTF-8"); - doc.save(stream, 2); - f.close(); - } -} - -#include "bigbrother.moc" diff --git a/plugins/extensions/bigbrother/bigbrother.h b/plugins/extensions/bigbrother/bigbrother.h deleted file mode 100644 index c53b4c2fb4..0000000000 --- a/plugins/extensions/bigbrother/bigbrother.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2007 Cyrille Berger (cberger@cberger.net) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _BIGBROTHER_H_ -#define _BIGBROTHER_H_ - -#include -#include - -class KisAction; -class KisMacro; -class KisViewManager; - -class BigBrotherPlugin : public KisActionPlugin -{ - Q_OBJECT -public: - BigBrotherPlugin(QObject *parent, const QVariantList &); - ~BigBrotherPlugin() override; - -private Q_SLOTS: - - void slotOpenPlay(); - void slotOpenEdit(); - void slotStartRecordingMacro(); - void slotStopRecordingMacro(); - -private: - void saveMacro(const KisMacro* macro); - KisMacro *openMacro(); -private: - KisMacro *m_recorder; - KisAction *m_startRecordingMacroAction; - KisAction *m_stopRecordingMacroAction; - -}; - -#endif // bigbrotherPlugin_H diff --git a/plugins/extensions/bigbrother/bigbrother.xmlgui b/plugins/extensions/bigbrother/bigbrother.xmlgui deleted file mode 100644 index 8ed27965c3..0000000000 --- a/plugins/extensions/bigbrother/bigbrother.xmlgui +++ /dev/null @@ -1,15 +0,0 @@ - - - - &Tools - Recording - - - - Macros - - - - - - diff --git a/plugins/extensions/bigbrother/kritabigbrother.json b/plugins/extensions/bigbrother/kritabigbrother.json deleted file mode 100644 index 1ac545995c..0000000000 --- a/plugins/extensions/bigbrother/kritabigbrother.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - - "Id": "bigbrother", - "Type": "Service", - "X-KDE-Library": "kritabigbrother", - "X-KDE-ServiceTypes": [ - "Krita/ViewPlugin" - ], - "X-Krita-Version": "28" -} diff --git a/plugins/tools/basictools/kis_tool_ellipse.cc b/plugins/tools/basictools/kis_tool_ellipse.cc index f06a8d4bbe..926b61fce7 100644 --- a/plugins/tools/basictools/kis_tool_ellipse.cc +++ b/plugins/tools/basictools/kis_tool_ellipse.cc @@ -1,85 +1,74 @@ /* * kis_tool_ellipse.cc - part of Krayon * * Copyright (c) 2000 John Califf * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2009 Lukáš Tvrdý * Copyright (c) 2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_ellipse.h" #include #include #include #include "kis_figure_painting_tool_helper.h" #include -#include -#include -#include - - KisToolEllipse::KisToolEllipse(KoCanvasBase * canvas) : KisToolEllipseBase(canvas, KisToolEllipseBase::PAINT, KisCursor::load("tool_ellipse_cursor.png", 6, 6)) { setObjectName("tool_ellipse"); setSupportOutline(true); } KisToolEllipse::~KisToolEllipse() { } void KisToolEllipse::resetCursorStyle() { KisToolEllipseBase::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolEllipse::finishRect(const QRectF& rect) { if (rect.isEmpty() || !blockUntilOperationsFinished()) return; - if (image()) { - KisRecordedShapePaintAction linePaintAction(KisNodeQueryPath::absolutePath(currentNode()), currentPaintOpPreset(), KisRecordedShapePaintAction::Ellipse, rect); - setupPaintAction(&linePaintAction); - image()->actionRecorder()->addAction(linePaintAction); - } - if (!currentNode()->inherits("KisShapeLayer")) { KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Ellipse"), image(), currentNode(), canvas()->resourceManager(), strokeStyle(), fillStyle()); helper.paintEllipse(rect); } else { QRectF r = convertToPt(rect); KoShape* shape = KisShapeToolHelper::createEllipseShape(r); KoShapeStrokeSP border(new KoShapeStroke(currentStrokeWidth(), currentFgColor().toQColor())); shape->setStroke(border); addShape(shape); } notifyModified(); } diff --git a/plugins/tools/basictools/kis_tool_fill.cc b/plugins/tools/basictools/kis_tool_fill.cc index 4f5a155b90..35d23d27aa 100644 --- a/plugins/tools/basictools/kis_tool_fill.cc +++ b/plugins/tools/basictools/kis_tool_fill.cc @@ -1,314 +1,294 @@ /* * kis_tool_fill.cc - part of Krayon * * Copyright (c) 2000 John Califf * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Bart Coppens * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_fill.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include -#include #include "kis_resources_snapshot.h" #include #include KisToolFill::KisToolFill(KoCanvasBase * canvas) : KisToolPaint(canvas, KisCursor::load("tool_fill_cursor.png", 6, 6)) { setObjectName("tool_fill"); m_feather = 0; m_sizemod = 0; m_threshold = 80; m_usePattern = false; m_unmerged = false; m_fillOnlySelection = false; } KisToolFill::~KisToolFill() { } void KisToolFill::resetCursorStyle() { KisToolPaint::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolFill::activate(ToolActivation toolActivation, const QSet &shapes) { KisToolPaint::activate(toolActivation, shapes); m_configGroup = KSharedConfig::openConfig()->group(toolId()); } void KisToolFill::beginPrimaryAction(KoPointerEvent *event) { // cannot use fill tool on non-painting layers. // this logic triggers with multiple layer types like vector layer, clone layer, file layer, group layer if ( currentNode().isNull() || currentNode()->inherits("KisShapeLayer") || nodePaintAbility()!=NodePaintAbility::PAINT ) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()-> showFloatingMessage( i18n("You cannot use this tool with the selected layer type"), QIcon(), 2000, KisFloatingMessage::Medium, Qt::AlignCenter); event->ignore(); return; } if (!nodeEditable()) { event->ignore(); return; } setMode(KisTool::PAINT_MODE); m_startPos = convertToImagePixelCoordFloored(event); } void KisToolFill::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); setMode(KisTool::HOVER_MODE); if (!currentNode() || (!image()->wrapAroundModePermitted() && !image()->bounds().contains(m_startPos))) { return; } - // TODO: remove this block after recording refactoring - if (image()) { - KisNodeSP projectionNode; - if(m_unmerged) { - projectionNode = currentNode(); - } else { - projectionNode = image()->root(); - } - KisRecordedFillPaintAction paintAction(KisNodeQueryPath::absolutePath(currentNode()), m_startPos, KisNodeQueryPath::absolutePath(projectionNode)); - setupPaintAction(&paintAction); - paintAction.setPattern(currentPattern()); - if(m_usePattern) { - paintAction.setFillStyle(KisPainter::FillStylePattern); - } - image()->actionRecorder()->addAction(paintAction); - } - bool useFastMode = m_useFastMode->isChecked(); KisProcessingApplicator applicator(currentImage(), currentNode(), KisProcessingApplicator::SUPPORTS_WRAPAROUND_MODE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Flood Fill")); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); KisProcessingVisitorSP visitor = new FillProcessingVisitor(m_startPos, resources->activeSelection(), resources, useFastMode, m_usePattern, m_fillOnlySelection, m_feather, m_sizemod, m_threshold, m_unmerged, false); applicator.applyVisitor(visitor, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.end(); } QWidget* KisToolFill::createOptionWidget() { QWidget *widget = KisToolPaint::createOptionWidget(); widget->setObjectName(toolId() + " option widget"); QLabel *lbl_fastMode = new QLabel(i18n("Fast mode: "), widget); m_useFastMode = new QCheckBox(QString(), widget); m_useFastMode->setToolTip( i18n("Fills area faster, but does not take composition " "mode into account. Selections and other extended " "features will also be disabled.")); QLabel *lbl_threshold = new QLabel(i18n("Threshold: "), widget); m_slThreshold = new KisSliderSpinBox(widget); m_slThreshold->setObjectName("int_widget"); m_slThreshold->setRange(1, 100); m_slThreshold->setPageStep(3); QLabel *lbl_sizemod = new QLabel(i18n("Grow selection: "), widget); m_sizemodWidget = new KisSliderSpinBox(widget); m_sizemodWidget->setObjectName("sizemod"); m_sizemodWidget->setRange(-40, 40); m_sizemodWidget->setSingleStep(1); m_sizemodWidget->setSuffix(i18n(" px")); QLabel *lbl_feather = new QLabel(i18n("Feathering radius: "), widget); m_featherWidget = new KisSliderSpinBox(widget); m_featherWidget->setObjectName("feather"); m_featherWidget->setRange(0, 40); m_featherWidget->setSingleStep(1); m_featherWidget->setSuffix(i18n(" px")); QLabel *lbl_usePattern = new QLabel(i18n("Use pattern:"), widget); m_checkUsePattern = new QCheckBox(QString(), widget); m_checkUsePattern->setToolTip(i18n("When checked do not use the foreground color, but the pattern selected to fill with")); QLabel *lbl_sampleMerged = new QLabel(i18n("Limit to current layer:"), widget); m_checkSampleMerged = new QCheckBox(QString(), widget); QLabel *lbl_fillSelection = new QLabel(i18n("Fill entire selection:"), widget); m_checkFillSelection = new QCheckBox(QString(), widget); m_checkFillSelection->setToolTip(i18n("When checked do not look at the current layer colors, but just fill all of the selected area")); connect (m_useFastMode , SIGNAL(toggled(bool)) , this, SLOT(slotSetUseFastMode(bool))); connect (m_slThreshold , SIGNAL(valueChanged(int)), this, SLOT(slotSetThreshold(int))); connect (m_sizemodWidget , SIGNAL(valueChanged(int)), this, SLOT(slotSetSizemod(int))); connect (m_featherWidget , SIGNAL(valueChanged(int)), this, SLOT(slotSetFeather(int))); connect (m_checkUsePattern , SIGNAL(toggled(bool)) , this, SLOT(slotSetUsePattern(bool))); connect (m_checkSampleMerged , SIGNAL(toggled(bool)) , this, SLOT(slotSetSampleMerged(bool))); connect (m_checkFillSelection, SIGNAL(toggled(bool)) , this, SLOT(slotSetFillSelection(bool))); addOptionWidgetOption(m_useFastMode, lbl_fastMode); addOptionWidgetOption(m_slThreshold, lbl_threshold); addOptionWidgetOption(m_sizemodWidget , lbl_sizemod); addOptionWidgetOption(m_featherWidget , lbl_feather); addOptionWidgetOption(m_checkFillSelection, lbl_fillSelection); addOptionWidgetOption(m_checkSampleMerged, lbl_sampleMerged); addOptionWidgetOption(m_checkUsePattern, lbl_usePattern); updateGUI(); widget->setFixedHeight(widget->sizeHint().height()); // load configuration options m_useFastMode->setChecked(m_configGroup.readEntry("useFastMode", false)); m_slThreshold->setValue(m_configGroup.readEntry("thresholdAmount", 80)); m_sizemodWidget->setValue(m_configGroup.readEntry("growSelection", 0)); m_featherWidget->setValue(m_configGroup.readEntry("featherAmount", 0)); m_checkUsePattern->setChecked(m_configGroup.readEntry("usePattern", false)); m_checkSampleMerged->setChecked(m_configGroup.readEntry("sampleMerged", false)); m_checkFillSelection->setChecked(m_configGroup.readEntry("fillSelection", false)); return widget; } void KisToolFill::updateGUI() { bool useAdvancedMode = !m_useFastMode->isChecked(); bool selectionOnly = m_checkFillSelection->isChecked(); m_useFastMode->setEnabled(!selectionOnly); m_slThreshold->setEnabled(!selectionOnly); m_sizemodWidget->setEnabled(!selectionOnly && useAdvancedMode); m_featherWidget->setEnabled(!selectionOnly && useAdvancedMode); m_checkSampleMerged->setEnabled(!selectionOnly && useAdvancedMode); m_checkUsePattern->setEnabled(useAdvancedMode); } void KisToolFill::slotSetUseFastMode(bool value) { updateGUI(); m_configGroup.writeEntry("useFastMode", value); } void KisToolFill::slotSetThreshold(int threshold) { m_threshold = threshold; m_configGroup.writeEntry("thresholdAmount", threshold); } void KisToolFill::slotSetUsePattern(bool state) { m_usePattern = state; m_configGroup.writeEntry("usePattern", state); } void KisToolFill::slotSetSampleMerged(bool state) { m_unmerged = state; m_configGroup.writeEntry("sampleMerged", state); } void KisToolFill::slotSetFillSelection(bool state) { m_fillOnlySelection = state; m_configGroup.writeEntry("fillSelection", state); updateGUI(); } void KisToolFill::slotSetSizemod(int sizemod) { m_sizemod = sizemod; m_configGroup.writeEntry("growSelection", sizemod); } void KisToolFill::slotSetFeather(int feather) { m_feather = feather; m_configGroup.writeEntry("featherAmount", feather); } diff --git a/plugins/tools/basictools/kis_tool_line.cc b/plugins/tools/basictools/kis_tool_line.cc index 358efd9451..91d87d23e6 100644 --- a/plugins/tools/basictools/kis_tool_line.cc +++ b/plugins/tools/basictools/kis_tool_line.cc @@ -1,369 +1,362 @@ /* * kis_tool_line.cc - part of Krayon * * Copyright (c) 2000 John Califf * Copyright (c) 2002 Patrick Julien * Copyright (c) 2003 Boudewijn Rempt * Copyright (c) 2009 Lukáš Tvrdý * Copyright (c) 2007,2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_line.h" #include #include #include #include #include #include #include #include #include #include #include "kis_figure_painting_tool_helper.h" #include "kis_canvas2.h" - -#include -#include -#include - #include "kis_painting_information_builder.h" #include "kis_tool_line_helper.h" -#define ENABLE_RECORDING - const KisCoordinatesConverter* getCoordinatesConverter(KoCanvasBase * canvas) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas); return kritaCanvas->coordinatesConverter(); } KisToolLine::KisToolLine(KoCanvasBase * canvas) : KisToolShape(canvas, KisCursor::load("tool_line_cursor.png", 6, 6)), m_showGuideline(true), m_strokeIsRunning(false), m_infoBuilder(new KisConverterPaintingInformationBuilder(getCoordinatesConverter(canvas))), m_helper(new KisToolLineHelper(m_infoBuilder.data(), kundo2_i18n("Draw Line"))), m_strokeUpdateCompressor(500, KisSignalCompressor::POSTPONE), m_longStrokeUpdateCompressor(1000, KisSignalCompressor::FIRST_INACTIVE) { setObjectName("tool_line"); setSupportOutline(true); connect(&m_strokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); connect(&m_longStrokeUpdateCompressor, SIGNAL(timeout()), SLOT(updateStroke())); } KisToolLine::~KisToolLine() { } void KisToolLine::resetCursorStyle() { KisToolPaint::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolLine::activate(ToolActivation activation, const QSet &shapes) { KisToolPaint::activate(activation, shapes); configGroup = KSharedConfig::openConfig()->group(toolId()); } void KisToolLine::deactivate() { KisToolPaint::deactivate(); cancelStroke(); } QWidget* KisToolLine::createOptionWidget() { QWidget* widget = KisToolPaint::createOptionWidget(); m_chkUseSensors = new QCheckBox(i18n("Use sensors")); addOptionWidgetOption(m_chkUseSensors); m_chkShowPreview = new QCheckBox(i18n("Show Preview")); addOptionWidgetOption(m_chkShowPreview); m_chkShowGuideline = new QCheckBox(i18n("Show Guideline")); addOptionWidgetOption(m_chkShowGuideline); // hook up connections for value changing connect(m_chkUseSensors, SIGNAL(clicked(bool)), this, SLOT(setUseSensors(bool)) ); connect(m_chkShowPreview, SIGNAL(clicked(bool)), this, SLOT(setShowPreview(bool)) ); connect(m_chkShowGuideline, SIGNAL(clicked(bool)), this, SLOT(setShowGuideline(bool)) ); // read values in from configuration m_chkUseSensors->setChecked(configGroup.readEntry("useSensors", true)); m_chkShowPreview->setChecked(configGroup.readEntry("showPreview", true)); m_chkShowGuideline->setChecked(configGroup.readEntry("showGuideline", true)); return widget; } void KisToolLine::setUseSensors(bool value) { configGroup.writeEntry("useSensors", value); } void KisToolLine::setShowGuideline(bool value) { m_showGuideline = value; configGroup.writeEntry("showGuideline", value); } void KisToolLine::setShowPreview(bool value) { configGroup.writeEntry("showPreview", value); } void KisToolLine::requestStrokeCancellation() { cancelStroke(); } void KisToolLine::requestStrokeEnd() { // Terminate any in-progress strokes if (nodePaintAbility() == PAINT && m_helper->isRunning()) { endStroke(); } } void KisToolLine::updatePreviewTimer(bool showGuideline) { // If the user disables the guideline, we will want to try to draw some // preview lines even if they're slow, so set the timer to FIRST_ACTIVE. if (showGuideline) { m_strokeUpdateCompressor.setMode(KisSignalCompressor::POSTPONE); } else { m_strokeUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE); } } void KisToolLine::paint(QPainter& gc, const KoViewConverter &converter) { Q_UNUSED(converter); if(mode() == KisTool::PAINT_MODE) { paintLine(gc,QRect()); } KisToolPaint::paint(gc,converter); } void KisToolLine::beginPrimaryAction(KoPointerEvent *event) { NodePaintAbility nodeAbility = nodePaintAbility(); if (nodeAbility == NONE || !nodeEditable()) { event->ignore(); return; } setMode(KisTool::PAINT_MODE); // Always show guideline on vector layers m_showGuideline = m_chkShowGuideline->isChecked() || nodeAbility != PAINT; updatePreviewTimer(m_showGuideline); m_helper->setEnabled(nodeAbility == PAINT); m_helper->setUseSensors(m_chkUseSensors->isChecked()); m_helper->start(event, canvas()->resourceManager()); m_startPoint = convertToPixelCoordAndSnap(event); m_endPoint = m_startPoint; m_lastUpdatedPoint = m_startPoint; m_strokeIsRunning = true; } void KisToolLine::updateStroke() { if (!m_strokeIsRunning) return; m_helper->repaintLine(canvas()->resourceManager(), image(), currentNode(), image().data()); } void KisToolLine::continuePrimaryAction(KoPointerEvent *event) { CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); if (!m_strokeIsRunning) return; // First ensure the old guideline is deleted updateGuideline(); QPointF pos = convertToPixelCoordAndSnap(event); if (event->modifiers() == Qt::AltModifier) { QPointF trans = pos - m_endPoint; m_helper->translatePoints(trans); m_startPoint += trans; m_endPoint += trans; } else if (event->modifiers() == Qt::ShiftModifier) { pos = straightLine(pos); m_helper->addPoint(event, pos); } else { m_helper->addPoint(event, pos); } m_endPoint = pos; // Draw preview if requested if (m_chkShowPreview->isChecked()) { // If the cursor has moved a significant amount, immediately clear the // current preview and redraw. Otherwise, do slow redraws periodically. - auto updateDistance = (pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength(); + auto updateDistance = (pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength(); if (updateDistance > 10) { m_helper->clearPaint(); m_longStrokeUpdateCompressor.stop(); m_strokeUpdateCompressor.start(); m_lastUpdatedPoint = pos; } else if (updateDistance > 1) { m_longStrokeUpdateCompressor.start(); } } updateGuideline(); KisToolPaint::requestUpdateOutline(event->point, event); } void KisToolLine::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); setMode(KisTool::HOVER_MODE); updateGuideline(); endStroke(); } void KisToolLine::endStroke() { NodePaintAbility nodeAbility = nodePaintAbility(); if (!m_strokeIsRunning || m_startPoint == m_endPoint || nodeAbility == NONE) { return; } if (nodeAbility == PAINT) { updateStroke(); m_helper->end(); } else { KoPathShape* path = new KoPathShape(); path->setShapeId(KoPathShapeId); QTransform resolutionMatrix; resolutionMatrix.scale(1 / currentImage()->xRes(), 1 / currentImage()->yRes()); path->moveTo(resolutionMatrix.map(m_startPoint)); path->lineTo(resolutionMatrix.map(m_endPoint)); path->normalize(); KoShapeStrokeSP border(new KoShapeStroke(currentStrokeWidth(), currentFgColor().toQColor())); path->setStroke(border); KUndo2Command * cmd = canvas()->shapeController()->addShape(path, 0); canvas()->addCommand(cmd); } m_strokeIsRunning = false; m_endPoint = m_startPoint; } void KisToolLine::cancelStroke() { if (!m_strokeIsRunning) return; if (m_startPoint == m_endPoint) return; /** * The actual stroke is run by the timer so it is a legal * situation when m_strokeIsRunning is true, but the actual redraw * stroke is not running. */ if (m_helper->isRunning()) { m_helper->cancel(); } m_strokeIsRunning = false; m_endPoint = m_startPoint; } QPointF KisToolLine::straightLine(QPointF point) { const QPointF lineVector = point - m_startPoint; qreal lineAngle = std::atan2(lineVector.y(), lineVector.x()); if (lineAngle < 0) { lineAngle += 2 * M_PI; } const qreal ANGLE_BETWEEN_CONSTRAINED_LINES = (2 * M_PI) / 24; const quint32 constrainedLineIndex = static_cast((lineAngle / ANGLE_BETWEEN_CONSTRAINED_LINES) + 0.5); const qreal constrainedLineAngle = constrainedLineIndex * ANGLE_BETWEEN_CONSTRAINED_LINES; const qreal lineLength = std::sqrt((lineVector.x() * lineVector.x()) + (lineVector.y() * lineVector.y())); const QPointF constrainedLineVector(lineLength * std::cos(constrainedLineAngle), lineLength * std::sin(constrainedLineAngle)); const QPointF result = m_startPoint + constrainedLineVector; return result; } void KisToolLine::updateGuideline() { if (canvas()) { QRectF bound(m_startPoint, m_endPoint); canvas()->updateCanvas(convertToPt(bound.normalized().adjusted(-3, -3, 3, 3))); } } void KisToolLine::paintLine(QPainter& gc, const QRect&) { QPointF viewStartPos = pixelToView(m_startPoint); QPointF viewStartEnd = pixelToView(m_endPoint); if (m_showGuideline && canvas()) { QPainterPath path; path.moveTo(viewStartPos); path.lineTo(viewStartEnd); paintToolOutline(&gc, path); } } QString KisToolLine::quickHelp() const { return i18n("Alt+Drag will move the origin of the currently displayed line around, Shift+Drag will force you to draw straight lines"); } diff --git a/plugins/tools/basictools/kis_tool_line_helper.cpp b/plugins/tools/basictools/kis_tool_line_helper.cpp index 195a8595ae..230b358999 100644 --- a/plugins/tools/basictools/kis_tool_line_helper.cpp +++ b/plugins/tools/basictools/kis_tool_line_helper.cpp @@ -1,186 +1,184 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_line_helper.h" #include "kis_algebra_2d.h" #include "kis_painting_information_builder.h" #include "kis_image.h" struct KisToolLineHelper::Private { Private(KisPaintingInformationBuilder *_infoBuilder) : infoBuilder(_infoBuilder), useSensors(true), enabled(true) { } QVector linePoints; KisPaintingInformationBuilder *infoBuilder; bool useSensors; bool enabled; }; KisToolLineHelper::KisToolLineHelper(KisPaintingInformationBuilder *infoBuilder, - const KUndo2MagicString &transactionText, - KisRecordingAdapter *recordingAdapter) + const KUndo2MagicString &transactionText) : KisToolFreehandHelper(infoBuilder, transactionText, - recordingAdapter, new KisSmoothingOptions(false)), m_d(new Private(infoBuilder)) { } KisToolLineHelper::~KisToolLineHelper() { delete m_d; } void KisToolLineHelper::setEnabled(bool value) { m_d->enabled = value; } void KisToolLineHelper::setUseSensors(bool value) { m_d->useSensors = value; } void KisToolLineHelper::repaintLine(KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade) { if (!m_d->enabled) return; cancelPaint(); if (m_d->linePoints.isEmpty()) return; qreal startAngle = 0.0; if (m_d->linePoints.length() > 1) { startAngle = KisAlgebra2D::directionBetweenPoints(m_d->linePoints[0].pos(), m_d->linePoints[1].pos(), 0.0); } QVector::const_iterator it = m_d->linePoints.constBegin(); QVector::const_iterator end = m_d->linePoints.constEnd(); initPaintImpl(startAngle, *it, resourceManager, image, node, strokesFacade); ++it; while (it != end) { paintLine(*(it - 1), *it); ++it; } } void KisToolLineHelper::start(KoPointerEvent *event, KoCanvasResourceManager *resourceManager) { if (!m_d->enabled) return; // Ignore the elapsed stroke time, so that the line tool will behave as if the whole stroke is // drawn at once. This should prevent any possible spurious dabs caused by airbrushing features. KisPaintInformation pi = m_d->infoBuilder->startStroke(event, 0, resourceManager); if (!m_d->useSensors) { pi = KisPaintInformation(pi.pos()); } m_d->linePoints.append(pi); } void KisToolLineHelper::addPoint(KoPointerEvent *event, const QPointF &overridePos) { if (!m_d->enabled) return; // Ignore the elapsed stroke time, so that the line tool will behave as if the whole stroke is // drawn at once. This should prevent any possible spurious dabs caused by airbrushing features. KisPaintInformation pi = m_d->infoBuilder->continueStroke(event, 0); if (!m_d->useSensors) { pi = KisPaintInformation(pi.pos()); } if (!overridePos.isNull()) { pi.setPos(overridePos); } if (m_d->linePoints.size() > 1) { const QPointF startPos = m_d->linePoints.first().pos(); const QPointF endPos = pi.pos(); const qreal maxDistance = kisDistance(startPos, endPos); const QPointF unit = (endPos - startPos) / maxDistance; QVector::iterator it = m_d->linePoints.begin(); ++it; while (it != m_d->linePoints.end()) { qreal dist = kisDistance(startPos, it->pos()); if (dist < maxDistance) { QPointF pos = startPos + unit * dist; it->setPos(pos); ++it; } else { it = m_d->linePoints.erase(it); } } } m_d->linePoints.append(pi); } void KisToolLineHelper::translatePoints(const QPointF &offset) { if (!m_d->enabled) return; QVector::iterator it = m_d->linePoints.begin(); while (it != m_d->linePoints.end()) { it->setPos(it->pos() + offset); ++it; } } void KisToolLineHelper::end() { if (!m_d->enabled) return; KIS_ASSERT_RECOVER_RETURN(isRunning()); endPaint(); m_d->linePoints.clear(); } void KisToolLineHelper::cancel() { if (!m_d->enabled) return; KIS_ASSERT_RECOVER_RETURN(isRunning()); cancelPaint(); m_d->linePoints.clear(); } void KisToolLineHelper::clearPaint() { if (!m_d->enabled) return; cancelPaint(); } diff --git a/plugins/tools/basictools/kis_tool_line_helper.h b/plugins/tools/basictools/kis_tool_line_helper.h index 4fbb62913d..a8f15e1516 100644 --- a/plugins/tools/basictools/kis_tool_line_helper.h +++ b/plugins/tools/basictools/kis_tool_line_helper.h @@ -1,56 +1,55 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TOOL_LINE_HELPER_H #define __KIS_TOOL_LINE_HELPER_H #include "kis_tool_freehand_helper.h" class KisToolLineHelper : private KisToolFreehandHelper { public: KisToolLineHelper(KisPaintingInformationBuilder *infoBuilder, - const KUndo2MagicString &transactionText, - KisRecordingAdapter *recordingAdapter = 0); + const KUndo2MagicString &transactionText); ~KisToolLineHelper() override; void setEnabled(bool value); void setUseSensors(bool value); void repaintLine(KoCanvasResourceManager *resourceManager, KisImageWSP image, KisNodeSP node, KisStrokesFacade *strokesFacade); void start(KoPointerEvent *event, KoCanvasResourceManager *resourceManager); void addPoint(KoPointerEvent *event, const QPointF &overridePos = QPointF()); void translatePoints(const QPointF &offset); void end(); void cancel(); void clearPaint(); using KisToolFreehandHelper::isRunning; private: struct Private; Private * const m_d; }; #endif /* __KIS_TOOL_LINE_HELPER_H */ diff --git a/plugins/tools/basictools/kis_tool_multihand.cpp b/plugins/tools/basictools/kis_tool_multihand.cpp index 8da94a46f3..bfc025155f 100644 --- a/plugins/tools/basictools/kis_tool_multihand.cpp +++ b/plugins/tools/basictools/kis_tool_multihand.cpp @@ -1,422 +1,421 @@ /* * Copyright (c) 2011 Lukáš Tvrdý * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_multihand.h" #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_cursor.h" #include "kis_tool_multihand_helper.h" static const int MAXIMUM_BRUSHES = 50; #include #ifdef Q_OS_WIN // quoting DRAND48(3) man-page: // These functions are declared obsolete by SVID 3, // which states that rand(3) should be used instead. #define drand48() (static_cast(qrand()) / static_cast(RAND_MAX)) #endif KisToolMultihand::KisToolMultihand(KoCanvasBase *canvas) : KisToolBrush(canvas), m_transformMode(SYMMETRY), m_angle(0), m_handsCount(6), m_mirrorVertically(false), m_mirrorHorizontally(false), m_showAxes(false), m_translateRadius(100), m_setupAxesFlag(false) , customUI(0) { m_helper = new KisToolMultihandHelper(paintingInformationBuilder(), - kundo2_i18n("Multibrush Stroke"), - recordingAdapter()); + kundo2_i18n("Multibrush Stroke")); resetHelper(m_helper); if (image()) { m_axesPoint = QPointF(0.5 * image()->width(), 0.5 * image()->height()); } } KisToolMultihand::~KisToolMultihand() { } void KisToolMultihand::beginPrimaryAction(KoPointerEvent *event) { if(m_setupAxesFlag) { setMode(KisTool::OTHER); m_axesPoint = convertToPixelCoord(event->point); requestUpdateOutline(event->point, 0); updateCanvas(); } else { initTransformations(); KisToolFreehand::beginPrimaryAction(event); } } void KisToolMultihand::continuePrimaryAction(KoPointerEvent *event) { if(mode() == KisTool::OTHER) { m_axesPoint = convertToPixelCoord(event->point); requestUpdateOutline(event->point, 0); updateCanvas(); } else { KisToolFreehand::continuePrimaryAction(event); } } void KisToolMultihand::endPrimaryAction(KoPointerEvent *event) { if(mode() == KisTool::OTHER) { setMode(KisTool::HOVER_MODE); requestUpdateOutline(event->point, 0); finishAxesSetup(); } else { KisToolFreehand::endPrimaryAction(event); } } void KisToolMultihand::paint(QPainter& gc, const KoViewConverter &converter) { if(m_setupAxesFlag) { int diagonal = (currentImage()->height() + currentImage()->width()); QPainterPath path; path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle), m_axesPoint.y()-diagonal*sin(m_angle)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle), m_axesPoint.y()+diagonal*sin(m_angle)); path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()-diagonal*sin(m_angle+M_PI_2)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()+diagonal*sin(m_angle+M_PI_2)); paintToolOutline(&gc, pixelToView(path)); } else { KisToolFreehand::paint(gc, converter); if(m_showAxes){ int diagonal = (currentImage()->height() + currentImage()->width()); QPainterPath path; path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle), m_axesPoint.y()-diagonal*sin(m_angle)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle), m_axesPoint.y()+diagonal*sin(m_angle)); path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()-diagonal*sin(m_angle+M_PI_2)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()+diagonal*sin(m_angle+M_PI_2)); paintToolOutline(&gc, pixelToView(path)); } } } void KisToolMultihand::initTransformations() { QVector transformations; QTransform m; if(m_transformMode == SYMMETRY) { qreal angle = 0; qreal angleStep = (2 * M_PI) / m_handsCount; for(int i = 0; i < m_handsCount; i++) { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep; } } else if(m_transformMode == MIRROR) { transformations << m; if (m_mirrorHorizontally) { m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(-1,1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } if (m_mirrorVertically) { m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(1,-1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } if (m_mirrorVertically && m_mirrorHorizontally){ m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(-1,-1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } } else if(m_transformMode == SNOWFLAKE) { qreal angle = 0; qreal angleStep = (2 * M_PI) / m_handsCount/4; for(int i = 0; i < m_handsCount*4; i++) { if ((i%2)==1) { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(m_angle-angleStep); m.rotateRadians(angle); m.scale(-1,1); m.rotateRadians(-m_angle+angleStep); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep*2; } else { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(m_angle-angleStep); m.rotateRadians(angle); m.rotateRadians(-m_angle+angleStep); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep*2; } } } else /* if(m_transformationNode == TRANSLATE) */ { /** * TODO: currently, the seed is the same for all the * strokes */ for (int i = 0; i < m_handsCount; i++){ qreal angle = drand48() * M_PI * 2; qreal length = drand48(); // convert the Polar coordinates to Cartesian coordinates qreal nx = (m_translateRadius * cos(angle) * length); qreal ny = (m_translateRadius * sin(angle) * length); m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.translate(nx,ny); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } } m_helper->setupTransformations(transformations); } QWidget* KisToolMultihand::createOptionWidget() { QWidget *widget = KisToolBrush::createOptionWidget(); customUI = new KisToolMultiHandConfigWidget(); // brush smoothing option. customUI->layout()->addWidget(widget); customUI->smoothingOptionsLayout->addWidget(widget); // setup common parameters that all of the modes will see connect(customUI->showAxesCheckbox, SIGNAL(toggled(bool)), this, SLOT(slotSetAxesVisible(bool))); customUI->showAxesCheckbox->setChecked((bool)m_configGroup.readEntry("showAxes", false)); connect(image(), SIGNAL(sigSizeChanged(const QPointF &, const QPointF &)), this, SLOT(resetAxes(const QPointF &, const QPointF &))); customUI->moveOriginButton->setCheckable(true); connect(customUI->moveOriginButton, SIGNAL(clicked(bool)),this, SLOT(activateAxesPointModeSetup())); connect(customUI->resetOriginButton, SIGNAL(released()), this, SLOT(resetAxes())); customUI->multihandTypeCombobox->addItem(i18n("Symmetry"),int(SYMMETRY)); // axis mode customUI->multihandTypeCombobox->addItem(i18n("Mirror"),int(MIRROR)); customUI->multihandTypeCombobox->addItem(i18n("Translate"),int(TRANSLATE)); customUI->multihandTypeCombobox->addItem(i18n("Snowflake"),int(SNOWFLAKE)); connect(customUI->multihandTypeCombobox,SIGNAL(currentIndexChanged(int)),this, SLOT(slotSetTransformMode(int))); customUI->multihandTypeCombobox->setCurrentIndex(m_configGroup.readEntry("transformMode", 0)); slotSetTransformMode(customUI->multihandTypeCombobox->currentIndex()); customUI->axisRotationSpinbox->setSuffix(QChar(Qt::Key_degree)); // origin rotation customUI->axisRotationSpinbox->setSingleStep(0.5); customUI->axisRotationSpinbox->setRange(0.0, 90.0, 1); customUI->axisRotationSpinbox->setValue(m_configGroup.readEntry("axesAngle", 0.0)); connect( customUI->axisRotationSpinbox, SIGNAL(valueChanged(qreal)),this, SLOT(slotSetAxesAngle(qreal))); // symmetry mode options customUI->brushCountSpinBox->setRange(1, MAXIMUM_BRUSHES); connect(customUI->brushCountSpinBox, SIGNAL(valueChanged(int)),this, SLOT(slotSetHandsCount(int))); customUI->brushCountSpinBox->setValue(m_configGroup.readEntry("handsCount", 4)); // mirror mode specific options connect(customUI->horizontalCheckbox, SIGNAL(toggled(bool)), this, SLOT(slotSetMirrorHorizontally(bool))); customUI->horizontalCheckbox->setChecked((bool)m_configGroup.readEntry("mirrorHorizontally", false)); connect(customUI->verticalCheckbox, SIGNAL(toggled(bool)), this, SLOT(slotSetMirrorVertically(bool))); customUI->verticalCheckbox->setChecked((bool)m_configGroup.readEntry("mirrorVertically", false)); // translate mode options customUI->translationRadiusSpinbox->setRange(0, 200); customUI->translationRadiusSpinbox->setSuffix(i18n(" px")); customUI->translationRadiusSpinbox->setValue(m_configGroup.readEntry("translateRadius", 0)); connect(customUI->translationRadiusSpinbox,SIGNAL(valueChanged(int)),this,SLOT(slotSetTranslateRadius(int))); // snowflake re-uses the existing options, so there is no special parameters for that... return static_cast(customUI); // keeping it in the native class until the end allows us to access the UI components } void KisToolMultihand::activateAxesPointModeSetup() { if (customUI->moveOriginButton->isChecked()){ m_setupAxesFlag = true; useCursor(KisCursor::crossCursor()); updateCanvas(); } else { finishAxesSetup(); } } void KisToolMultihand::resetAxes() { m_axesPoint = QPointF(0.5 * image()->width(), 0.5 * image()->height()); finishAxesSetup(); } void KisToolMultihand::finishAxesSetup() { m_setupAxesFlag = false; customUI->moveOriginButton->setChecked(false); resetCursorStyle(); updateCanvas(); } void KisToolMultihand::updateCanvas() { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); Q_ASSERT(kisCanvas); kisCanvas->updateCanvas(); } void KisToolMultihand::slotSetHandsCount(int count) { m_handsCount = count; m_configGroup.writeEntry("handsCount", count); } void KisToolMultihand::slotSetAxesAngle(qreal angle) { //negative so axes rotates counter clockwise m_angle = -angle*M_PI/180; updateCanvas(); m_configGroup.writeEntry("axesAngle", angle); } void KisToolMultihand::slotSetTransformMode(int index) { m_transformMode = enumTransforModes(customUI->multihandTypeCombobox->itemData(index).toInt()); m_configGroup.writeEntry("transformMode", index); // hide all of the UI elements by default customUI->horizontalCheckbox->setVisible(false); customUI->verticalCheckbox->setVisible(false); customUI->translationRadiusSpinbox->setVisible(false); customUI->radiusLabel->setVisible(false); customUI->brushCountSpinBox->setVisible(false); customUI->brushesLabel->setVisible(false); // turn on what we need if (index == int(MIRROR)) { customUI->horizontalCheckbox->setVisible(true); customUI->verticalCheckbox->setVisible(true); } if (index == int(TRANSLATE)) { customUI->translationRadiusSpinbox->setVisible(true); customUI->radiusLabel->setVisible(true); } if (index == int(SYMMETRY) || index == int(SNOWFLAKE) || index == int(TRANSLATE) ) { customUI->brushCountSpinBox->setVisible(true); customUI->brushesLabel->setVisible(true); } } void KisToolMultihand::slotSetAxesVisible(bool vis) { m_showAxes = vis; updateCanvas(); m_configGroup.writeEntry("showAxes", vis); } void KisToolMultihand::slotSetMirrorVertically(bool mirror) { m_mirrorVertically = mirror; m_configGroup.writeEntry("mirrorVertically", mirror); } void KisToolMultihand::slotSetMirrorHorizontally(bool mirror) { m_mirrorHorizontally = mirror; m_configGroup.writeEntry("mirrorHorizontally", mirror); } void KisToolMultihand::slotSetTranslateRadius(int radius) { m_translateRadius = radius; m_configGroup.writeEntry("translateRadius", radius); } diff --git a/plugins/tools/basictools/kis_tool_rectangle.cc b/plugins/tools/basictools/kis_tool_rectangle.cc index 52be92cb97..72d8e5c1bc 100644 --- a/plugins/tools/basictools/kis_tool_rectangle.cc +++ b/plugins/tools/basictools/kis_tool_rectangle.cc @@ -1,93 +1,83 @@ /* * kis_tool_rectangle.cc - part of Krita * * Copyright (c) 2000 John Califf * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2009 Lukáš Tvrdý * Copyright (c) 2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_rectangle.h" #include #include #include "KoCanvasBase.h" #include "kis_shape_tool_helper.h" #include "kis_figure_painting_tool_helper.h" -#include -#include -#include - #include #include KisToolRectangle::KisToolRectangle(KoCanvasBase * canvas) : KisToolRectangleBase(canvas, KisToolRectangleBase::PAINT, KisCursor::load("tool_rectangle_cursor.png", 6, 6)) { setSupportOutline(true); setObjectName("tool_rectangle"); } KisToolRectangle::~KisToolRectangle() { } void KisToolRectangle::resetCursorStyle() { KisToolRectangleBase::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolRectangle::finishRect(const QRectF &rect) { if (rect.isNull() || !blockUntilOperationsFinished()) return; - if (image()) { - KisRecordedShapePaintAction linePaintAction(KisNodeQueryPath::absolutePath(currentNode()), currentPaintOpPreset(), KisRecordedShapePaintAction::Rectangle, rect); - setupPaintAction(&linePaintAction); - image()->actionRecorder()->addAction(linePaintAction); - } - if (!currentNode()->inherits("KisShapeLayer")) { KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Rectangle"), image(), currentNode(), canvas()->resourceManager(), strokeStyle(), fillStyle()); helper.paintRect(rect); } else { QRectF r = convertToPt(rect); KoShape* shape = KisShapeToolHelper::createRectangleShape(r); KoShapeStrokeSP border; if (strokeStyle() == KisPainter::StrokeStyleBrush) { border = toQShared(new KoShapeStroke(currentStrokeWidth(), currentFgColor().toQColor())); } shape->setStroke(border); addShape(shape); } notifyModified(); } diff --git a/plugins/tools/tool_polygon/kis_tool_polygon.cc b/plugins/tools/tool_polygon/kis_tool_polygon.cc index 3ba7af25bc..cbd7fe17af 100644 --- a/plugins/tools/tool_polygon/kis_tool_polygon.cc +++ b/plugins/tools/tool_polygon/kis_tool_polygon.cc @@ -1,93 +1,78 @@ /* * kis_tool_polygon.cc -- part of Krita * * Copyright (c) 2004 Michael Thaler * Copyright (c) 2009 Lukáš Tvrdý * Copyright (c) 2010 Cyrille Berger * Copyright (C) 2010 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_polygon.h" #include #include #include #include #include #include "kis_figure_painting_tool_helper.h" -#include -#include -#include - - - KisToolPolygon::KisToolPolygon(KoCanvasBase *canvas) : KisToolPolylineBase(canvas, KisToolPolylineBase::PAINT, KisCursor::load("tool_polygon_cursor.png", 6, 6)) { setObjectName("tool_polygon"); setSupportOutline(true); } KisToolPolygon::~KisToolPolygon() { } void KisToolPolygon::resetCursorStyle() { KisToolPolylineBase::resetCursorStyle(); overrideCursorIfNotEditable(); } void KisToolPolygon::finishPolyline(const QVector& points) { if (!blockUntilOperationsFinished()) return; - if (image()) { - KisRecordedPathPaintAction linePaintAction(KisNodeQueryPath::absolutePath(currentNode()), - currentPaintOpPreset(), - KisDistanceInitInfo()); - setupPaintAction(&linePaintAction); - linePaintAction.addPolyLine(points.toList()); - linePaintAction.addLine(KisPaintInformation(points.last()), KisPaintInformation(points.first())); - image()->actionRecorder()->addAction(linePaintAction); - } if (!currentNode()->inherits("KisShapeLayer")) { KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polygon"), image(), currentNode(), canvas()->resourceManager(), strokeStyle(), fillStyle()); helper.paintPolygon(points); } else { KoPathShape* path = new KoPathShape(); path->setShapeId(KoPathShapeId); QTransform resolutionMatrix; resolutionMatrix.scale(1 / currentImage()->xRes(), 1 / currentImage()->yRes()); path->moveTo(resolutionMatrix.map(points[0])); for (int i = 1; i < points.count(); i++) path->lineTo(resolutionMatrix.map(points[i])); path->close(); path->normalize(); addShape(path); } } diff --git a/plugins/tools/tool_polyline/kis_tool_polyline.cc b/plugins/tools/tool_polyline/kis_tool_polyline.cc index 5ceb634338..6148d448e6 100644 --- a/plugins/tools/tool_polyline/kis_tool_polyline.cc +++ b/plugins/tools/tool_polyline/kis_tool_polyline.cc @@ -1,96 +1,82 @@ /* * Copyright (c) 2004 Michael Thaler * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2009 Lukáš Tvrdý * Copyright (c) 2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_polyline.h" #include #include #include #include #include #include "kis_figure_painting_tool_helper.h" -#include -#include -#include - - - KisToolPolyline::KisToolPolyline(KoCanvasBase * canvas) : KisToolPolylineBase(canvas, KisToolPolylineBase::PAINT, KisCursor::load("tool_polyline_cursor.png", 6, 6)) { setObjectName("tool_polyline"); setSupportOutline(true); } KisToolPolyline::~KisToolPolyline() { } void KisToolPolyline::resetCursorStyle() { KisToolPolylineBase::resetCursorStyle(); overrideCursorIfNotEditable(); } QWidget* KisToolPolyline::createOptionWidget() { return KisToolPolylineBase::createOptionWidget(); } void KisToolPolyline::finishPolyline(const QVector& points) { if (!blockUntilOperationsFinished()) return; - if (image()) { - KisRecordedPathPaintAction linePaintAction(KisNodeQueryPath::absolutePath(currentNode()), - currentPaintOpPreset(), - KisDistanceInitInfo()); - setupPaintAction(&linePaintAction); - linePaintAction.addPolyLine(points.toList()); - image()->actionRecorder()->addAction(linePaintAction); - } if (!currentNode()->inherits("KisShapeLayer")) { KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), image(), currentNode(), canvas()->resourceManager(), strokeStyle(), fillStyle()); helper.paintPolyline(points); } else { KoPathShape* path = new KoPathShape(); path->setShapeId(KoPathShapeId); QTransform resolutionMatrix; resolutionMatrix.scale(1 / currentImage()->xRes(), 1 / currentImage()->yRes()); path->moveTo(resolutionMatrix.map(points[0])); for (int i = 1; i < points.count(); i++) path->lineTo(resolutionMatrix.map(points[i])); path->normalize(); addShape(path); } notifyModified(); } diff --git a/plugins/tools/tool_transform2/kis_tool_transform.cc b/plugins/tools/tool_transform2/kis_tool_transform.cc index a07fdd5bf5..5bbaec35b6 100644 --- a/plugins/tools/tool_transform2/kis_tool_transform.cc +++ b/plugins/tools/tool_transform2/kis_tool_transform.cc @@ -1,1273 +1,1278 @@ /* * kis_tool_transform.cc -- part of Krita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 C. Boemann * Copyright (c) 2010 Marc Pegon * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool_transform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kis_progress_widget.h" #include "kis_transform_utils.h" #include "kis_warp_transform_strategy.h" #include "kis_cage_transform_strategy.h" #include "kis_liquify_transform_strategy.h" #include "kis_free_transform_strategy.h" #include "kis_perspective_transform_strategy.h" #include "kis_transform_mask.h" #include "kis_transform_mask_adapter.h" +#include "krita_container_utils.h" #include "kis_layer_utils.h" #include #include "strokes/transform_stroke_strategy.h" KisToolTransform::KisToolTransform(KoCanvasBase * canvas) : KisTool(canvas, KisCursor::rotateCursor()) , m_workRecursively(true) , m_changesTracker(&m_transaction) , m_warpStrategy( new KisWarpTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction)) , m_cageStrategy( new KisCageTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction)) , m_liquifyStrategy( new KisLiquifyTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction, canvas->resourceManager())) , m_freeStrategy( new KisFreeTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), dynamic_cast(canvas)->snapGuide(), m_currentArgs, m_transaction)) , m_perspectiveStrategy( new KisPerspectiveTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), dynamic_cast(canvas)->snapGuide(), m_currentArgs, m_transaction)) { m_canvas = dynamic_cast(canvas); Q_ASSERT(m_canvas); setObjectName("tool_transform"); useCursor(KisCursor::selectCursor()); m_optionsWidget = 0; warpAction = new KisAction(i18n("Warp")); liquifyAction = new KisAction(i18n("Liquify")); cageAction = new KisAction(i18n("Cage")); freeTransformAction = new KisAction(i18n("Free")); perspectiveAction = new KisAction(i18n("Perspective")); // extra actions for free transform that are in the tool options mirrorHorizontalAction = new KisAction(i18n("Mirror Horizontal")); mirrorVericalAction = new KisAction(i18n("Mirror Vertical")); rotateNinteyCWAction = new KisAction(i18n("Rotate 90 degrees Clockwise")); rotateNinteyCCWAction = new KisAction(i18n("Rotate 90 degrees CounterClockwise")); applyTransformation = new KisAction(i18n("Apply")); resetTransformation = new KisAction(i18n("Reset")); m_contextMenu.reset(new QMenu()); connect(m_warpStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_cageStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_liquifyStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_liquifyStrategy.data(), SIGNAL(requestCursorOutlineUpdate(const QPointF&)), SLOT(cursorOutlineUpdateRequested(const QPointF&))); connect(m_liquifyStrategy.data(), SIGNAL(requestUpdateOptionWidget()), SLOT(updateOptionWidget())); connect(m_freeStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_freeStrategy.data(), SIGNAL(requestResetRotationCenterButtons()), SLOT(resetRotationCenterButtonsRequested())); connect(m_freeStrategy.data(), SIGNAL(requestShowImageTooBig(bool)), SLOT(imageTooBigRequested(bool))); connect(m_perspectiveStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_perspectiveStrategy.data(), SIGNAL(requestShowImageTooBig(bool)), SLOT(imageTooBigRequested(bool))); connect(&m_changesTracker, SIGNAL(sigConfigChanged()), this, SLOT(slotTrackerChangedConfig())); } KisToolTransform::~KisToolTransform() { cancelStroke(); } void KisToolTransform::outlineChanged() { emit freeTransformChanged(); m_canvas->updateCanvas(); } void KisToolTransform::canvasUpdateRequested() { m_canvas->updateCanvas(); } void KisToolTransform::resetCursorStyle() { setFunctionalCursor(); } void KisToolTransform::resetRotationCenterButtonsRequested() { if (!m_optionsWidget) return; m_optionsWidget->resetRotationCenterButtons(); } void KisToolTransform::imageTooBigRequested(bool value) { if (!m_optionsWidget) return; m_optionsWidget->setTooBigLabelVisible(value); } KisTransformStrategyBase* KisToolTransform::currentStrategy() const { if (m_currentArgs.mode() == ToolTransformArgs::FREE_TRANSFORM) { return m_freeStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::WARP) { return m_warpStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::CAGE) { return m_cageStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::LIQUIFY) { return m_liquifyStrategy.data(); } else /* if (m_currentArgs.mode() == ToolTransformArgs::PERSPECTIVE_4POINT) */ { return m_perspectiveStrategy.data(); } } void KisToolTransform::paint(QPainter& gc, const KoViewConverter &converter) { Q_UNUSED(converter); if (!m_strokeData.strokeId()) return; QRectF newRefRect = KisTransformUtils::imageToFlake(m_canvas->coordinatesConverter(), QRectF(0.0,0.0,1.0,1.0)); if (m_refRect != newRefRect) { m_refRect = newRefRect; currentStrategy()->externalConfigChanged(); } gc.save(); if (m_optionsWidget && m_optionsWidget->showDecorations()) { gc.setOpacity(0.3); gc.fillPath(m_selectionPath, Qt::black); } gc.restore(); currentStrategy()->paint(gc); if (!m_cursorOutline.isEmpty()) { QPainterPath mappedOutline = KisTransformUtils::imageToFlakeTransform( m_canvas->coordinatesConverter()).map(m_cursorOutline); paintToolOutline(&gc, mappedOutline); } } void KisToolTransform::setFunctionalCursor() { if (overrideCursorIfNotEditable()) { return; } if (!m_strokeData.strokeId()) { useCursor(KisCursor::pointingHandCursor()); } else { useCursor(currentStrategy()->getCurrentCursor()); } } void KisToolTransform::cursorOutlineUpdateRequested(const QPointF &imagePos) { QRect canvasUpdateRect; if (!m_cursorOutline.isEmpty()) { canvasUpdateRect = m_canvas->coordinatesConverter()-> imageToDocument(m_cursorOutline.boundingRect()).toAlignedRect(); } m_cursorOutline = currentStrategy()-> getCursorOutline().translated(imagePos); if (!m_cursorOutline.isEmpty()) { canvasUpdateRect |= m_canvas->coordinatesConverter()-> imageToDocument(m_cursorOutline.boundingRect()).toAlignedRect(); } if (!canvasUpdateRect.isEmpty()) { // grow rect a bit to follow interpolation fuzziness canvasUpdateRect = kisGrowRect(canvasUpdateRect, 2); m_canvas->updateCanvas(canvasUpdateRect); } } void KisToolTransform::beginActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (!nodeEditable()) { event->ignore(); return; } if (!m_strokeData.strokeId()) { startStroke(m_currentArgs.mode(), false); } else { bool result = false; if (usePrimaryAction) { result = currentStrategy()->beginPrimaryAction(event); } else { result = currentStrategy()->beginAlternateAction(event, action); } if (result) { setMode(KisTool::PAINT_MODE); } } m_actuallyMoveWhileSelected = false; outlineChanged(); } void KisToolTransform::continueActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (mode() != KisTool::PAINT_MODE) return; m_actuallyMoveWhileSelected = true; if (usePrimaryAction) { currentStrategy()->continuePrimaryAction(event); } else { currentStrategy()->continueAlternateAction(event, action); } updateOptionWidget(); outlineChanged(); } void KisToolTransform::endActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (mode() != KisTool::PAINT_MODE) return; setMode(KisTool::HOVER_MODE); if (m_actuallyMoveWhileSelected || currentStrategy()->acceptsClicks()) { bool result = false; if (usePrimaryAction) { result = currentStrategy()->endPrimaryAction(event); } else { result = currentStrategy()->endAlternateAction(event, action); } if (result) { commitChanges(); } outlineChanged(); } updateOptionWidget(); updateApplyResetAvailability(); } QMenu* KisToolTransform::popupActionsMenu() { if (m_contextMenu) { m_contextMenu->clear(); // add a quick switch to different transform types m_contextMenu->addAction(freeTransformAction); m_contextMenu->addAction(perspectiveAction); m_contextMenu->addAction(warpAction); m_contextMenu->addAction(cageAction); m_contextMenu->addAction(liquifyAction); // extra options if free transform is selected if (transformMode() == FreeTransformMode) { m_contextMenu->addSeparator(); m_contextMenu->addAction(mirrorHorizontalAction); m_contextMenu->addAction(mirrorVericalAction); m_contextMenu->addAction(rotateNinteyCWAction); m_contextMenu->addAction(rotateNinteyCCWAction); } m_contextMenu->addSeparator(); m_contextMenu->addAction(applyTransformation); m_contextMenu->addAction(resetTransformation); } return m_contextMenu.data(); } void KisToolTransform::beginPrimaryAction(KoPointerEvent *event) { beginActionImpl(event, true, KisTool::NONE); } void KisToolTransform::continuePrimaryAction(KoPointerEvent *event) { continueActionImpl(event, true, KisTool::NONE); } void KisToolTransform::endPrimaryAction(KoPointerEvent *event) { endActionImpl(event, true, KisTool::NONE); } void KisToolTransform::activatePrimaryAction() { currentStrategy()->activatePrimaryAction(); setFunctionalCursor(); } void KisToolTransform::deactivatePrimaryAction() { currentStrategy()->deactivatePrimaryAction(); } void KisToolTransform::activateAlternateAction(AlternateAction action) { currentStrategy()->activateAlternateAction(action); setFunctionalCursor(); } void KisToolTransform::deactivateAlternateAction(AlternateAction action) { currentStrategy()->deactivateAlternateAction(action); } void KisToolTransform::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { beginActionImpl(event, false, action); } void KisToolTransform::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { continueActionImpl(event, false, action); } void KisToolTransform::endAlternateAction(KoPointerEvent *event, AlternateAction action) { endActionImpl(event, false, action); } void KisToolTransform::mousePressEvent(KoPointerEvent *event) { KisTool::mousePressEvent(event); } void KisToolTransform::mouseMoveEvent(KoPointerEvent *event) { QPointF mousePos = m_canvas->coordinatesConverter()->documentToImage(event->point); cursorOutlineUpdateRequested(mousePos); if (this->mode() != KisTool::PAINT_MODE) { currentStrategy()->hoverActionCommon(event); setFunctionalCursor(); KisTool::mouseMoveEvent(event); return; } } void KisToolTransform::mouseReleaseEvent(KoPointerEvent *event) { KisTool::mouseReleaseEvent(event); } void KisToolTransform::applyTransform() { slotApplyTransform(); } KisToolTransform::TransformToolMode KisToolTransform::transformMode() const { TransformToolMode mode = FreeTransformMode; switch (m_currentArgs.mode()) { case ToolTransformArgs::FREE_TRANSFORM: mode = FreeTransformMode; break; case ToolTransformArgs::WARP: mode = WarpTransformMode; break; case ToolTransformArgs::CAGE: mode = CageTransformMode; break; case ToolTransformArgs::LIQUIFY: mode = LiquifyTransformMode; break; case ToolTransformArgs::PERSPECTIVE_4POINT: mode = PerspectiveTransformMode; break; default: KIS_ASSERT_RECOVER_NOOP(0 && "unexpected transform mode"); } return mode; } double KisToolTransform::translateX() const { return m_currentArgs.transformedCenter().x(); } double KisToolTransform::translateY() const { return m_currentArgs.transformedCenter().y(); } double KisToolTransform::rotateX() const { return m_currentArgs.aX(); } double KisToolTransform::rotateY() const { return m_currentArgs.aY(); } double KisToolTransform::rotateZ() const { return m_currentArgs.aZ(); } double KisToolTransform::scaleX() const { return m_currentArgs.scaleX(); } double KisToolTransform::scaleY() const { return m_currentArgs.scaleY(); } double KisToolTransform::shearX() const { return m_currentArgs.shearX(); } double KisToolTransform::shearY() const { return m_currentArgs.shearY(); } KisToolTransform::WarpType KisToolTransform::warpType() const { switch(m_currentArgs.warpType()) { case KisWarpTransformWorker::AFFINE_TRANSFORM: return AffineWarpType; case KisWarpTransformWorker::RIGID_TRANSFORM: return RigidWarpType; case KisWarpTransformWorker::SIMILITUDE_TRANSFORM: return SimilitudeWarpType; default: return RigidWarpType; } } double KisToolTransform::warpFlexibility() const { return m_currentArgs.alpha(); } int KisToolTransform::warpPointDensity() const { return m_currentArgs.numPoints(); } void KisToolTransform::setTransformMode(KisToolTransform::TransformToolMode newMode) { ToolTransformArgs::TransformMode mode = ToolTransformArgs::FREE_TRANSFORM; switch (newMode) { case FreeTransformMode: mode = ToolTransformArgs::FREE_TRANSFORM; break; case WarpTransformMode: mode = ToolTransformArgs::WARP; break; case CageTransformMode: mode = ToolTransformArgs::CAGE; break; case LiquifyTransformMode: mode = ToolTransformArgs::LIQUIFY; break; case PerspectiveTransformMode: mode = ToolTransformArgs::PERSPECTIVE_4POINT; break; default: KIS_ASSERT_RECOVER_NOOP(0 && "unexpected transform mode"); } if( mode != m_currentArgs.mode() ) { if( newMode == FreeTransformMode ) { m_optionsWidget->slotSetFreeTransformModeButtonClicked( true ); } else if( newMode == WarpTransformMode ) { m_optionsWidget->slotSetWarpModeButtonClicked( true ); } else if( newMode == CageTransformMode ) { m_optionsWidget->slotSetCageModeButtonClicked( true ); } else if( newMode == LiquifyTransformMode ) { m_optionsWidget->slotSetLiquifyModeButtonClicked( true ); } else if( newMode == PerspectiveTransformMode ) { m_optionsWidget->slotSetPerspectiveModeButtonClicked( true ); } emit transformModeChanged(); } } void KisToolTransform::setRotateX( double rotation ) { m_currentArgs.setAX( normalizeAngle(rotation) ); } void KisToolTransform::setRotateY( double rotation ) { m_currentArgs.setAY( normalizeAngle(rotation) ); } void KisToolTransform::setRotateZ( double rotation ) { m_currentArgs.setAZ( normalizeAngle(rotation) ); } void KisToolTransform::setWarpType( KisToolTransform::WarpType type ) { switch( type ) { case RigidWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::RIGID_TRANSFORM); break; case AffineWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::AFFINE_TRANSFORM); break; case SimilitudeWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::SIMILITUDE_TRANSFORM); break; default: break; } } void KisToolTransform::setWarpFlexibility( double flexibility ) { m_currentArgs.setAlpha( flexibility ); } void KisToolTransform::setWarpPointDensity( int density ) { m_optionsWidget->slotSetWarpDensity(density); } bool KisToolTransform::tryInitTransformModeFromNode(KisNodeSP node) { bool result = false; if (KisTransformMaskSP mask = dynamic_cast(node.data())) { KisTransformMaskParamsInterfaceSP savedParams = mask->transformParams(); KisTransformMaskAdapter *adapter = dynamic_cast(savedParams.data()); if (adapter) { m_currentArgs = adapter->transformArgs(); initGuiAfterTransformMode(); result = true; } } return result; } bool KisToolTransform::tryFetchArgsFromCommandAndUndo(ToolTransformArgs *args, ToolTransformArgs::TransformMode mode, KisNodeSP currentNode) { bool result = false; const KUndo2Command *lastCommand = image()->undoAdapter()->presentCommand(); KisNodeSP oldRootNode; + KisNodeList oldTransformedNodes; if (lastCommand && - TransformStrokeStrategy::fetchArgsFromCommand(lastCommand, args, &oldRootNode) && + TransformStrokeStrategy::fetchArgsFromCommand(lastCommand, args, &oldRootNode, &oldTransformedNodes) && args->mode() == mode && oldRootNode == currentNode) { - args->saveContinuedState(); + KisNodeList perspectiveTransformedNodes = fetchNodesList(mode, currentNode, m_workRecursively); - image()->undoAdapter()->undoLastCommand(); + if (KritaUtils::compareListsUnordered(oldTransformedNodes, perspectiveTransformedNodes)) { + args->saveContinuedState(); + image()->undoAdapter()->undoLastCommand(); - // FIXME: can we make it async? - image()->waitForDone(); - forceRepaintDelayedLayers(oldRootNode); + // FIXME: can we make it async? + image()->waitForDone(); + forceRepaintDelayedLayers(oldRootNode); - result = true; + result = true; + } } return result; } void KisToolTransform::initTransformMode(ToolTransformArgs::TransformMode mode) { // NOTE: we are requesting an old value of m_currentArgs variable // here, which is global, don't forget about this on higher // levels. QString filterId = m_currentArgs.filterId(); m_currentArgs = ToolTransformArgs(); m_currentArgs.setOriginalCenter(m_transaction.originalCenterGeometric()); m_currentArgs.setTransformedCenter(m_transaction.originalCenterGeometric()); if (mode == ToolTransformArgs::FREE_TRANSFORM) { m_currentArgs.setMode(ToolTransformArgs::FREE_TRANSFORM); } else if (mode == ToolTransformArgs::WARP) { m_currentArgs.setMode(ToolTransformArgs::WARP); m_optionsWidget->setDefaultWarpPoints(); m_currentArgs.setEditingTransformPoints(false); } else if (mode == ToolTransformArgs::CAGE) { m_currentArgs.setMode(ToolTransformArgs::CAGE); m_currentArgs.setEditingTransformPoints(true); } else if (mode == ToolTransformArgs::LIQUIFY) { m_currentArgs.setMode(ToolTransformArgs::LIQUIFY); const QRect srcRect = m_transaction.originalRect().toAlignedRect(); if (!srcRect.isEmpty()) { m_currentArgs.initLiquifyTransformMode(m_transaction.originalRect().toAlignedRect()); } } else if (mode == ToolTransformArgs::PERSPECTIVE_4POINT) { m_currentArgs.setMode(ToolTransformArgs::PERSPECTIVE_4POINT); } initGuiAfterTransformMode(); } void KisToolTransform::initGuiAfterTransformMode() { currentStrategy()->externalConfigChanged(); outlineChanged(); updateOptionWidget(); updateApplyResetAvailability(); } void KisToolTransform::updateSelectionPath() { m_selectionPath = QPainterPath(); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); QPainterPath selectionOutline; KisSelectionSP selection = resources->activeSelection(); if (selection && selection->outlineCacheValid()) { selectionOutline = selection->outlineCache(); } else { selectionOutline.addRect(m_selectedPortionCache->exactBounds()); } const KisCoordinatesConverter *converter = m_canvas->coordinatesConverter(); QTransform i2f = converter->imageToDocumentTransform() * converter->documentToFlakeTransform(); m_selectionPath = i2f.map(selectionOutline); } void KisToolTransform::initThumbnailImage(KisPaintDeviceSP previewDevice) { QImage origImg; m_selectedPortionCache = previewDevice; QTransform thumbToImageTransform; const int maxSize = 2000; QRect srcRect(m_transaction.originalRect().toAlignedRect()); int x, y, w, h; srcRect.getRect(&x, &y, &w, &h); if (w > maxSize || h > maxSize) { qreal scale = qreal(maxSize) / (w > h ? w : h); QTransform scaleTransform = QTransform::fromScale(scale, scale); QRect thumbRect = scaleTransform.mapRect(m_transaction.originalRect()).toAlignedRect(); origImg = m_selectedPortionCache-> createThumbnail(thumbRect.width(), thumbRect.height(), srcRect, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); thumbToImageTransform = scaleTransform.inverted(); } else { origImg = m_selectedPortionCache->convertToQImage(0, x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); thumbToImageTransform = QTransform(); } // init both strokes since the thumbnail is initialized only once // during the stroke m_freeStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_perspectiveStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_warpStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_cageStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_liquifyStrategy->setThumbnailImage(origImg, thumbToImageTransform); } void KisToolTransform::activate(ToolActivation toolActivation, const QSet &shapes) { KisTool::activate(toolActivation, shapes); if (currentNode()) { m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); } startStroke(ToolTransformArgs::FREE_TRANSFORM, false); } void KisToolTransform::deactivate() { endStroke(); m_canvas->updateCanvas(); KisTool::deactivate(); } void KisToolTransform::requestUndoDuringStroke() { if (!m_strokeData.strokeId()) return; m_changesTracker.requestUndo(); } void KisToolTransform::requestStrokeEnd() { endStroke(); } void KisToolTransform::requestStrokeCancellation() { if (m_currentArgs.isIdentity()) { cancelStroke(); } else { slotResetTransform(); } } void KisToolTransform::startStroke(ToolTransformArgs::TransformMode mode, bool forceReset) { Q_ASSERT(!m_strokeData.strokeId()); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); KisNodeSP currentNode = resources->currentNode(); if (!currentNode || !currentNode->isEditable()) { return; } /** * FIXME: The transform tool is not completely asynchronous, it * needs the content of the layer for creation of the stroke * strategy. It means that we cannot start a new stroke until the * previous one is finished. Ideally, we should create the * m_selectedPortionCache and m_selectionPath somewhere in the * stroke and pass it to the tool somehow. But currently, we will * just disable starting a new stroke asynchronously */ if (image()->tryBarrierLock()) { image()->unlock(); } else { return; } /** * We must ensure that the currently selected subtree * has finished all its updates. */ forceRepaintDelayedLayers(currentNode); ToolTransformArgs fetchedArgs; bool fetchedFromCommand = false; if (!forceReset) { fetchedFromCommand = tryFetchArgsFromCommandAndUndo(&fetchedArgs, mode, currentNode); } if (m_optionsWidget) { m_workRecursively = m_optionsWidget->workRecursively() || !currentNode->paintDevice(); } QList nodesList = fetchNodesList(mode, currentNode, m_workRecursively); if (nodesList.isEmpty()) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Selected layer cannot be transformed with active transformation mode "), koIcon("object-locked"), 4000, KisFloatingMessage::High); // force-reset transform mode to default initTransformMode(mode); return; } - TransformStrokeStrategy *strategy = new TransformStrokeStrategy(currentNode, resources->activeSelection(), image().data()); + TransformStrokeStrategy *strategy = new TransformStrokeStrategy(currentNode, nodesList, resources->activeSelection(), image().data()); KisPaintDeviceSP previewDevice = strategy->previewDevice(); KisSelectionSP selection = strategy->realSelection(); QRect srcRect = selection ? selection->selectedExactRect() : previewDevice->exactBounds(); if (!selection && resources->activeSelection()) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Selections are not used when editing transform masks "), QIcon(), 4000, KisFloatingMessage::Low); } if (srcRect.isEmpty()) { delete strategy; KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Cannot transform empty layer "), QIcon(), 1000, KisFloatingMessage::Medium); // force-reset transform mode to default initTransformMode(mode); return; } m_transaction = TransformTransactionProperties(srcRect, &m_currentArgs, currentNode, nodesList); initThumbnailImage(previewDevice); updateSelectionPath(); if (!forceReset && fetchedFromCommand) { m_currentArgs = fetchedArgs; initGuiAfterTransformMode(); } else if (forceReset || !tryInitTransformModeFromNode(currentNode)) { initTransformMode(mode); } m_strokeData = StrokeData(image()->startStroke(strategy)); bool haveInvisibleNodes = clearDevices(nodesList); if (haveInvisibleNodes) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Invisible sublayers will also be transformed. Lock layers if you do not want them to be transformed "), QIcon(), 4000, KisFloatingMessage::Low); } Q_ASSERT(m_changesTracker.isEmpty()); commitChanges(); } void KisToolTransform::endStroke() { if (!m_strokeData.strokeId()) return; if (!m_currentArgs.isIdentity()) { transformClearedDevices(); image()->addJob(m_strokeData.strokeId(), new TransformStrokeStrategy::TransformData( TransformStrokeStrategy::TransformData::SELECTION, m_currentArgs, m_transaction.rootNode())); // root node is used for progress only image()->endStroke(m_strokeData.strokeId()); } else { image()->cancelStroke(m_strokeData.strokeId()); } m_strokeData.clear(); m_changesTracker.reset(); m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); outlineChanged(); } void KisToolTransform::cancelStroke() { if (!m_strokeData.strokeId()) return; if (m_currentArgs.continuedTransform()) { m_currentArgs.restoreContinuedState(); endStroke(); } else { image()->cancelStroke(m_strokeData.strokeId()); m_strokeData.clear(); m_changesTracker.reset(); m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); outlineChanged(); } } void KisToolTransform::commitChanges() { if (!m_strokeData.strokeId()) return; m_changesTracker.commitConfig(m_currentArgs); } void KisToolTransform::slotTrackerChangedConfig() { slotUiChangedConfig(); updateOptionWidget(); } QList KisToolTransform::fetchNodesList(ToolTransformArgs::TransformMode mode, KisNodeSP root, bool recursive) { QList result; auto fetchFunc = [&result, mode, root] (KisNodeSP node) { - if (node->isEditable() && + if (node->isEditable(node == root) && (!node->inherits("KisShapeLayer") || mode == ToolTransformArgs::FREE_TRANSFORM) && !node->inherits("KisFileLayer") && (!node->inherits("KisTransformMask") || node == root)) { result << node; } }; if (recursive) { KisLayerUtils::recursiveApplyNodes(root, fetchFunc); } else { fetchFunc(root); } return result; } bool KisToolTransform::clearDevices(const QList &nodes) { bool haveInvisibleNodes = false; Q_FOREACH (KisNodeSP node, nodes) { haveInvisibleNodes |= !node->visible(false); image()->addJob(m_strokeData.strokeId(), new TransformStrokeStrategy::ClearSelectionData(node)); /** * It might happen that the editablity state of the node would * change during the stroke, so we need to save the set of * applicable nodes right in the beginning of the processing */ m_strokeData.addClearedNode(node); } return haveInvisibleNodes; } void KisToolTransform::transformClearedDevices() { Q_FOREACH (KisNodeSP node, m_strokeData.clearedNodes()) { KIS_ASSERT_RECOVER_RETURN(node); image()->addJob(m_strokeData.strokeId(), new TransformStrokeStrategy::TransformData( TransformStrokeStrategy::TransformData::PAINT_DEVICE, m_currentArgs, node)); } } QWidget* KisToolTransform::createOptionWidget() { m_optionsWidget = new KisToolTransformConfigWidget(&m_transaction, m_canvas, m_workRecursively, 0); Q_CHECK_PTR(m_optionsWidget); m_optionsWidget->setObjectName(toolId() + " option widget"); // See https://bugs.kde.org/show_bug.cgi?id=316896 QWidget *specialSpacer = new QWidget(m_optionsWidget); specialSpacer->setObjectName("SpecialSpacer"); specialSpacer->setFixedSize(0, 0); m_optionsWidget->layout()->addWidget(specialSpacer); connect(m_optionsWidget, SIGNAL(sigConfigChanged()), this, SLOT(slotUiChangedConfig())); connect(m_optionsWidget, SIGNAL(sigApplyTransform()), this, SLOT(slotApplyTransform())); connect(m_optionsWidget, SIGNAL(sigResetTransform()), this, SLOT(slotResetTransform())); connect(m_optionsWidget, SIGNAL(sigRestartTransform()), this, SLOT(slotRestartTransform())); connect(m_optionsWidget, SIGNAL(sigEditingFinished()), this, SLOT(slotEditingFinished())); connect(mirrorHorizontalAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotFlipX())); connect(mirrorVericalAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotFlipY())); connect(rotateNinteyCWAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotRotateCW())); connect(rotateNinteyCCWAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotRotateCCW())); connect(warpAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToWarpType())); connect(perspectiveAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToPerspectiveType())); connect(freeTransformAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToFreeTransformType())); connect(liquifyAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToLiquifyType())); connect(cageAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToCageType())); connect(applyTransformation, SIGNAL(triggered(bool)), this, SLOT(slotApplyTransform())); connect(resetTransformation, SIGNAL(triggered(bool)), this, SLOT(slotResetTransform())); updateOptionWidget(); return m_optionsWidget; } void KisToolTransform::updateOptionWidget() { if (!m_optionsWidget) return; if (!currentNode()) { m_optionsWidget->setEnabled(false); return; } else { m_optionsWidget->setEnabled(true); m_optionsWidget->updateConfig(m_currentArgs); } } void KisToolTransform::updateApplyResetAvailability() { if (m_optionsWidget) { m_optionsWidget->setApplyResetDisabled(m_currentArgs.isIdentity()); } } void KisToolTransform::slotUiChangedConfig() { if (mode() == KisTool::PAINT_MODE) return; currentStrategy()->externalConfigChanged(); if (m_currentArgs.mode() == ToolTransformArgs::LIQUIFY) { m_currentArgs.saveLiquifyTransformMode(); } outlineChanged(); updateApplyResetAvailability(); } void KisToolTransform::slotApplyTransform() { QApplication::setOverrideCursor(KisCursor::waitCursor()); endStroke(); QApplication::restoreOverrideCursor(); } void KisToolTransform::slotResetTransform() { if (m_currentArgs.continuedTransform()) { ToolTransformArgs::TransformMode savedMode = m_currentArgs.mode(); /** * Our reset transform button can be used for two purposes: * * 1) Reset current transform to the initial one, which was * loaded from the previous user action. * * 2) Reset transform frame to infinity when the frame is unchanged */ const bool transformDiffers = !m_currentArgs.continuedTransform()->isSameMode(m_currentArgs); if (transformDiffers && m_currentArgs.continuedTransform()->mode() == savedMode) { m_currentArgs.restoreContinuedState(); initGuiAfterTransformMode(); slotEditingFinished(); } else { KisNodeSP root = m_transaction.rootNode() ? m_transaction.rootNode() : image()->root(); cancelStroke(); image()->waitForDone(); forceRepaintDelayedLayers(root); startStroke(savedMode, true); KIS_ASSERT_RECOVER_NOOP(!m_currentArgs.continuedTransform()); } } else { initTransformMode(m_currentArgs.mode()); slotEditingFinished(); } } void KisToolTransform::slotRestartTransform() { if (!m_strokeData.strokeId()) return; KisNodeSP root = m_transaction.rootNode(); KIS_ASSERT_RECOVER_RETURN(root); // the stroke is guaranteed to be started by an 'if' above ToolTransformArgs savedArgs(m_currentArgs); cancelStroke(); image()->waitForDone(); forceRepaintDelayedLayers(root); startStroke(savedArgs.mode(), true); } void KisToolTransform::forceRepaintDelayedLayers(KisNodeSP root) { KIS_SAFE_ASSERT_RECOVER_RETURN(root); KisLayerUtils::forceAllDelayedNodesUpdate(root); image()->waitForDone(); } void KisToolTransform::slotEditingFinished() { commitChanges(); } void KisToolTransform::slotUpdateToWarpType() { setTransformMode(KisToolTransform::TransformToolMode::WarpTransformMode); } void KisToolTransform::slotUpdateToPerspectiveType() { setTransformMode(KisToolTransform::TransformToolMode::PerspectiveTransformMode); } void KisToolTransform::slotUpdateToFreeTransformType() { setTransformMode(KisToolTransform::TransformToolMode::FreeTransformMode); } void KisToolTransform::slotUpdateToLiquifyType() { setTransformMode(KisToolTransform::TransformToolMode::LiquifyTransformMode); } void KisToolTransform::slotUpdateToCageType() { setTransformMode(KisToolTransform::TransformToolMode::CageTransformMode); } void KisToolTransform::setShearY(double shear) { m_optionsWidget->slotSetShearY(shear); } void KisToolTransform::setShearX(double shear) { m_optionsWidget->slotSetShearX(shear); } void KisToolTransform::setScaleY(double scale) { m_optionsWidget->slotSetScaleY(scale); } void KisToolTransform::setScaleX(double scale) { m_optionsWidget->slotSetScaleX(scale); } void KisToolTransform::setTranslateY(double translation) { m_optionsWidget->slotSetTranslateY(translation); } void KisToolTransform::setTranslateX(double translation) { m_optionsWidget->slotSetTranslateX(translation); } diff --git a/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.cpp b/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.cpp index 5cbb0ec44f..8bab4d564d 100644 --- a/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.cpp +++ b/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.cpp @@ -1,315 +1,320 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "transform_stroke_strategy.h" #include #include "kundo2commandextradata.h" #include "kis_node_progress_proxy.h" #include #include #include #include #include #include #include #include "kis_transform_mask_adapter.h" #include "kis_transform_utils.h" #include "kis_abstract_projection_plane.h" #include "kis_recalculate_transform_mask_job.h" #include "kis_projection_leaf.h" #include "kis_modify_transform_mask_command.h" TransformStrokeStrategy::TransformStrokeStrategy(KisNodeSP rootNode, + KisNodeList processedNodes, KisSelectionSP selection, KisStrokeUndoFacade *undoFacade) : KisStrokeStrategyUndoCommandBased(kundo2_i18n("Transform"), false, undoFacade), m_selection(selection) { if (rootNode->childCount() || !rootNode->paintDevice()) { KisPaintDeviceSP device; if (KisTransformMask* tmask = dynamic_cast(rootNode.data())) { device = tmask->buildPreviewDevice(); /** * When working with transform mask, selections are not * taken into account. */ m_selection = 0; } else { rootNode->projectionLeaf()->explicitlyRegeneratePassThroughProjection(); device = rootNode->projection(); } m_previewDevice = createDeviceCache(device); } else { m_previewDevice = createDeviceCache(rootNode->paintDevice()); putDeviceCache(rootNode->paintDevice(), m_previewDevice); } - Q_ASSERT(m_previewDevice); + KIS_SAFE_ASSERT_RECOVER_NOOP(m_previewDevice); m_savedRootNode = rootNode; + m_savedProcessedNodes = processedNodes; } TransformStrokeStrategy::~TransformStrokeStrategy() { } KisPaintDeviceSP TransformStrokeStrategy::previewDevice() const { return m_previewDevice; } KisSelectionSP TransformStrokeStrategy::realSelection() const { return m_selection; } KisPaintDeviceSP TransformStrokeStrategy::createDeviceCache(KisPaintDeviceSP dev) { KisPaintDeviceSP cache; if (m_selection) { QRect srcRect = m_selection->selectedExactRect(); cache = dev->createCompositionSourceDevice(); KisPainter gc(cache); gc.setSelection(m_selection); gc.bitBlt(srcRect.topLeft(), dev, srcRect); } else { cache = dev->createCompositionSourceDevice(dev); } return cache; } bool TransformStrokeStrategy::haveDeviceInCache(KisPaintDeviceSP src) { QMutexLocker l(&m_devicesCacheMutex); return m_devicesCacheHash.contains(src.data()); } void TransformStrokeStrategy::putDeviceCache(KisPaintDeviceSP src, KisPaintDeviceSP cache) { QMutexLocker l(&m_devicesCacheMutex); m_devicesCacheHash.insert(src.data(), cache); } KisPaintDeviceSP TransformStrokeStrategy::getDeviceCache(KisPaintDeviceSP src) { QMutexLocker l(&m_devicesCacheMutex); KisPaintDeviceSP cache = m_devicesCacheHash.value(src.data()); if (!cache) { warnKrita << "WARNING: Transform Stroke: the device is absent in cache!"; } return cache; } bool TransformStrokeStrategy::checkBelongsToSelection(KisPaintDeviceSP device) const { return m_selection && (device == m_selection->pixelSelection().data() || device == m_selection->projection().data()); } void TransformStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) { TransformData *td = dynamic_cast(data); ClearSelectionData *csd = dynamic_cast(data); if(td) { m_savedTransformArgs = td->config; if (td->destination == TransformData::PAINT_DEVICE) { QRect oldExtent = td->node->extent(); KisPaintDeviceSP device = td->node->paintDevice(); if (device && !checkBelongsToSelection(device)) { KisPaintDeviceSP cachedPortion = getDeviceCache(device); Q_ASSERT(cachedPortion); KisTransaction transaction(device); KisProcessingVisitor::ProgressHelper helper(td->node); transformAndMergeDevice(td->config, cachedPortion, device, &helper); runAndSaveCommand(KUndo2CommandSP(transaction.endAndTake()), KisStrokeJobData::CONCURRENT, KisStrokeJobData::NORMAL); td->node->setDirty(oldExtent | td->node->extent()); } else if (KisExternalLayer *extLayer = dynamic_cast(td->node.data())) { if (td->config.mode() == ToolTransformArgs::FREE_TRANSFORM || (td->config.mode() == ToolTransformArgs::PERSPECTIVE_4POINT && extLayer->supportsPerspectiveTransform())) { QVector3D transformedCenter; KisTransformWorker w = KisTransformUtils::createTransformWorker(td->config, 0, 0, &transformedCenter); QTransform t = w.transform(); runAndSaveCommand(KUndo2CommandSP(extLayer->transform(t)), KisStrokeJobData::CONCURRENT, KisStrokeJobData::NORMAL); } } else if (KisTransformMask *transformMask = dynamic_cast(td->node.data())) { runAndSaveCommand(KUndo2CommandSP( new KisModifyTransformMaskCommand(transformMask, KisTransformMaskParamsInterfaceSP( new KisTransformMaskAdapter(td->config)))), KisStrokeJobData::CONCURRENT, KisStrokeJobData::NORMAL); } } else if (m_selection) { /** * We use usual transaction here, because we cannot calsulate * transformation for perspective and warp workers. */ KisTransaction transaction(m_selection->pixelSelection()); KisProcessingVisitor::ProgressHelper helper(td->node); KisTransformUtils::transformDevice(td->config, m_selection->pixelSelection(), &helper); runAndSaveCommand(KUndo2CommandSP(transaction.endAndTake()), KisStrokeJobData::CONCURRENT, KisStrokeJobData::NORMAL); } } else if (csd) { KisPaintDeviceSP device = csd->node->paintDevice(); if (device && !checkBelongsToSelection(device)) { if (!haveDeviceInCache(device)) { putDeviceCache(device, createDeviceCache(device)); } clearSelection(device); } else if (KisTransformMask *transformMask = dynamic_cast(csd->node.data())) { runAndSaveCommand(KUndo2CommandSP( new KisModifyTransformMaskCommand(transformMask, KisTransformMaskParamsInterfaceSP( new KisDumbTransformMaskParams(true)))), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); } } else { KisStrokeStrategyUndoCommandBased::doStrokeCallback(data); } } void TransformStrokeStrategy::clearSelection(KisPaintDeviceSP device) { KisTransaction transaction(device); if (m_selection) { device->clearSelection(m_selection); } else { QRect oldExtent = device->extent(); device->clear(); device->setDirty(oldExtent); } runAndSaveCommand(KUndo2CommandSP(transaction.endAndTake()), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); } void TransformStrokeStrategy::transformAndMergeDevice(const ToolTransformArgs &config, KisPaintDeviceSP src, KisPaintDeviceSP dst, KisProcessingVisitor::ProgressHelper *helper) { KoUpdaterPtr mergeUpdater = src != dst ? helper->updater() : 0; KisTransformUtils::transformDevice(config, src, helper); if (src != dst) { QRect mergeRect = src->extent(); KisPainter painter(dst); painter.setProgress(mergeUpdater); painter.bitBlt(mergeRect.topLeft(), src, mergeRect); painter.end(); } } struct TransformExtraData : public KUndo2CommandExtraData { ToolTransformArgs savedTransformArgs; KisNodeSP rootNode; + KisNodeList transformedNodes; }; void TransformStrokeStrategy::postProcessToplevelCommand(KUndo2Command *command) { TransformExtraData *data = new TransformExtraData(); data->savedTransformArgs = m_savedTransformArgs; data->rootNode = m_savedRootNode; + data->transformedNodes = m_savedProcessedNodes; command->setExtraData(data); } -bool TransformStrokeStrategy::fetchArgsFromCommand(const KUndo2Command *command, ToolTransformArgs *args, KisNodeSP *rootNode) +bool TransformStrokeStrategy::fetchArgsFromCommand(const KUndo2Command *command, ToolTransformArgs *args, KisNodeSP *rootNode, KisNodeList *transformedNodes) { const TransformExtraData *data = dynamic_cast(command->extraData()); if (data) { *args = data->savedTransformArgs; *rootNode = data->rootNode; + *transformedNodes = data->transformedNodes; } return bool(data); } void TransformStrokeStrategy::initStrokeCallback() { KisStrokeStrategyUndoCommandBased::initStrokeCallback(); if (m_selection) { m_selection->setVisible(false); } } void TransformStrokeStrategy::finishStrokeCallback() { if (m_selection) { m_selection->setVisible(true); } KisStrokeStrategyUndoCommandBased::finishStrokeCallback(); } void TransformStrokeStrategy::cancelStrokeCallback() { KisStrokeStrategyUndoCommandBased::cancelStrokeCallback(); if (m_selection) { m_selection->setVisible(true); } } diff --git a/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.h b/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.h index 689fdc87d3..97b1c1c78a 100644 --- a/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.h +++ b/plugins/tools/tool_transform2/strokes/transform_stroke_strategy.h @@ -1,126 +1,127 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __TRANSFORM_STROKE_STRATEGY_H #define __TRANSFORM_STROKE_STRATEGY_H #include #include #include #include #include "tool_transform_args.h" #include #include class KisPostExecutionUndoAdapter; class TransformStrokeStrategy : public KisStrokeStrategyUndoCommandBased { public: class TransformData : public KisStrokeJobData { public: enum Destination { PAINT_DEVICE, SELECTION, }; public: TransformData(Destination _destination, const ToolTransformArgs &_config, KisNodeSP _node) : KisStrokeJobData(CONCURRENT, NORMAL), destination(_destination), config(_config), node(_node) { } Destination destination; ToolTransformArgs config; KisNodeSP node; }; class ClearSelectionData : public KisStrokeJobData { public: ClearSelectionData(KisNodeSP _node) : KisStrokeJobData(SEQUENTIAL, NORMAL), node(_node) { } KisNodeSP node; }; public: - TransformStrokeStrategy(KisNodeSP rootNode, + TransformStrokeStrategy(KisNodeSP rootNode, KisNodeList processedNodes, KisSelectionSP selection, KisStrokeUndoFacade *undoFacade); ~TransformStrokeStrategy() override; KisPaintDeviceSP previewDevice() const; KisSelectionSP realSelection() const; void initStrokeCallback() override; void finishStrokeCallback() override; void cancelStrokeCallback() override; void doStrokeCallback(KisStrokeJobData *data) override; - static bool fetchArgsFromCommand(const KUndo2Command *command, ToolTransformArgs *args, KisNodeSP *rootNode); + static bool fetchArgsFromCommand(const KUndo2Command *command, ToolTransformArgs *args, KisNodeSP *rootNode, KisNodeList *transformedNodes); protected: void postProcessToplevelCommand(KUndo2Command *command) override; private: KoUpdaterPtr fetchUpdater(KisNodeSP node); void transformAndMergeDevice(const ToolTransformArgs &config, KisPaintDeviceSP src, KisPaintDeviceSP dst, KisProcessingVisitor::ProgressHelper *helper); void transformDevice(const ToolTransformArgs &config, KisPaintDeviceSP device, KisProcessingVisitor::ProgressHelper *helper); void clearSelection(KisPaintDeviceSP device); //void transformDevice(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisProcessingVisitor::ProgressHelper *helper); bool checkBelongsToSelection(KisPaintDeviceSP device) const; KisPaintDeviceSP createDeviceCache(KisPaintDeviceSP src); bool haveDeviceInCache(KisPaintDeviceSP src); void putDeviceCache(KisPaintDeviceSP src, KisPaintDeviceSP cache); KisPaintDeviceSP getDeviceCache(KisPaintDeviceSP src); private: KisSelectionSP m_selection; QMutex m_devicesCacheMutex; QHash m_devicesCacheHash; KisPaintDeviceSP m_previewDevice; KisTransformMaskSP writeToTransformMask; ToolTransformArgs m_savedTransformArgs; KisNodeSP m_savedRootNode; + KisNodeList m_savedProcessedNodes; }; #endif /* __TRANSFORM_STROKE_STRATEGY_H */