From 3dcab8b9bd319fbc9d3fd1eb15938965ede3f920 Mon Sep 17 00:00:00 2001 From: Charlie Jiang Date: Thu, 9 May 2019 16:26:08 -0400 Subject: [PATCH 1/9] Merge remote-tracking branch 'origind-dev/master' Add align to video function --- CMakeLists.txt | 541 +++++++++++++++++++++++++ src/bitmaps/button/button_align_16.png | Bin 0 -> 353 bytes src/bitmaps/button/button_align_24.png | Bin 0 -> 571 bytes src/bitmaps/button/button_align_32.png | Bin 0 -> 690 bytes src/bitmaps/button/button_align_48.png | Bin 0 -> 1161 bytes src/bitmaps/button/button_align_64.png | Bin 0 -> 547 bytes src/bitmaps/manifest.respack | 5 + src/colour_button.h | 6 + src/command/time.cpp | 13 + src/dialog_align.cpp | 378 +++++++++++++++++ src/dialogs.h | 1 + src/hotkey.cpp | 10 + src/image_position_picker.cpp | 127 ++++++ src/image_position_picker.h | 37 ++ src/libresrc/default_config.json | 4 + src/libresrc/default_hotkey.json | 3 + src/libresrc/default_toolbar.json | 1 + src/meson.build | 2 + 18 files changed, 1128 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 src/bitmaps/button/button_align_16.png create mode 100644 src/bitmaps/button/button_align_24.png create mode 100644 src/bitmaps/button/button_align_32.png create mode 100644 src/bitmaps/button/button_align_48.png create mode 100644 src/bitmaps/button/button_align_64.png create mode 100644 src/dialog_align.cpp create mode 100644 src/image_position_picker.cpp create mode 100644 src/image_position_picker.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..4647a9147d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,541 @@ +cmake_minimum_required(VERSION 3.14) +cmake_policy(SET CMP0074 NEW) + +project(Aegisub) + +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +include_directories("build") +include_directories("libaegisub/include") +include_directories("vendor/luajit/include") + +add_library(libaegisub STATIC + libaegisub/common/parser.cpp + libaegisub/ass/dialogue_parser.cpp + libaegisub/ass/time.cpp + libaegisub/ass/uuencode.cpp + libaegisub/audio/provider.cpp + libaegisub/audio/provider_convert.cpp + libaegisub/audio/provider_dummy.cpp + libaegisub/audio/provider_hd.cpp + libaegisub/audio/provider_lock.cpp + libaegisub/audio/provider_pcm.cpp + libaegisub/audio/provider_ram.cpp + libaegisub/common/cajun/elements.cpp + libaegisub/common/cajun/reader.cpp + libaegisub/common/cajun/writer.cpp + libaegisub/lua/modules/lfs.cpp + libaegisub/lua/modules/re.cpp + libaegisub/lua/modules/unicode.cpp + libaegisub/lua/modules/lpeg.c + libaegisub/lua/modules.cpp + libaegisub/lua/script_reader.cpp + libaegisub/lua/utils.cpp + libaegisub/common/calltip_provider.cpp + libaegisub/common/character_count.cpp + libaegisub/common/charset.cpp + libaegisub/common/charset_6937.cpp + libaegisub/common/charset_conv.cpp + libaegisub/common/color.cpp + libaegisub/common/file_mapping.cpp + libaegisub/common/format.cpp + libaegisub/common/fs.cpp + libaegisub/common/hotkey.cpp + libaegisub/common/io.cpp + libaegisub/common/json.cpp + libaegisub/common/kana_table.cpp + libaegisub/common/karaoke_matcher.cpp + libaegisub/common/keyframe.cpp + libaegisub/common/line_iterator.cpp + libaegisub/common/log.cpp + libaegisub/common/mru.cpp + libaegisub/common/option.cpp + libaegisub/common/option_value.cpp + libaegisub/common/path.cpp + libaegisub/common/thesaurus.cpp + libaegisub/common/util.cpp + libaegisub/common/vfr.cpp + libaegisub/common/ycbcr_conv.cpp + libaegisub/common/dispatch.cpp +) +if (UNIX) + target_sources(libaegisub PRIVATE + libaegisub/unix/access.cpp + libaegisub/unix/fs.cpp + libaegisub/unix/log.cpp + libaegisub/unix/path.cpp + libaegisub/unix/util.cpp + ) +elseif(WIN32) + target_sources(libaegisub PRIVATE + libaegisub/windows/access.cpp + libaegisub/windows/charset_conv_win.cpp + libaegisub/windows/fs.cpp + libaegisub/windows/lagi_pre.cpp + libaegisub/windows/log_win.cpp + libaegisub/windows/path_win.cpp + libaegisub/windows/util_win.cpp + ) +endif(UNIX) +SET_TARGET_PROPERTIES(libaegisub PROPERTIES PREFIX "") + +add_library(luabins STATIC + vendor/luabins/src/fwrite.c + vendor/luabins/src/load.c + vendor/luabins/src/luabins.c + vendor/luabins/src/luainternals.c + vendor/luabins/src/save.c + vendor/luabins/src/savebuffer.c + vendor/luabins/src/write.c +) + +add_executable(luajit-minilua vendor/luajit/src/host/minilua.c) +if (NOT MSVC) +target_link_libraries(luajit-minilua m) +endif(NOT MSVC) +add_custom_command(TARGET luajit-minilua POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen + COMMAND luajit-minilua ../dynasm/dynasm.lua -D P64 -D JIT -D FFI -D FPU -D HFABI -D VER= -o gen/buildvm_arch.h vm_x86.dasc + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src +) +add_custom_command(TARGET luajit-minilua POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_win.json ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json + COMMAND luajit-minilua ../../tools/respack.lua manifest.respack default_config.cpp default_config.h + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/libresrc + BYPRODUCTS ${PROJECT_SOURCE_DIR}/src/libresrc/default_config.cpp ${PROJECT_SOURCE_DIR}/src/libresrc/default_config.h +) +add_custom_command(TARGET luajit-minilua POST_BUILD + COMMAND luajit-minilua ../../tools/respack.lua manifest.respack ../libresrc/bitmap.cpp ../libresrc/bitmap.h + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bitmaps + BYPRODUCTS ${PROJECT_SOURCE_DIR}/src/libresrc/bitmap.cpp ${PROJECT_SOURCE_DIR}/src/libresrc/bitmap.h +) + +add_executable(luajit-buildvm + vendor/luajit/src/host/buildvm.c + vendor/luajit/src/host/buildvm_asm.c + vendor/luajit/src/host/buildvm_peobj.c + vendor/luajit/src/host/buildvm_lib.c + vendor/luajit/src/host/buildvm_fold.c +) +target_include_directories(luajit-buildvm PRIVATE vendor/luajit/src vendor/luajit/src/gen) +add_dependencies(luajit-buildvm luajit-minilua) +if(UNIX) + add_custom_command(TARGET luajit-buildvm POST_BUILD + COMMAND luajit-buildvm -m elfasm -o lj_vm.s + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src + BYPRODUCTS ${PROJECT_SOURCE_DIR}/vendor/luajit/src/lj_vm.s + ) + set_property(SOURCE vendor/luajit/src/lj_vm.s PROPERTY LANGUAGE C) +elseif(MSVC) + add_custom_command(TARGET luajit-buildvm POST_BUILD + COMMAND luajit-buildvm -m peobj -o lj_vm.obj + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src + BYPRODUCTS ${PROJECT_SOURCE_DIR}/vendor/luajit/src/lj_vm.obj + ) +endif(UNIX) +add_custom_command(TARGET luajit-buildvm POST_BUILD + COMMAND luajit-buildvm -m ffdef -o gen/lj_ffdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c + COMMAND luajit-buildvm -m bcdef -o gen/lj_bcdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c + COMMAND luajit-buildvm -m folddef -o gen/lj_folddef.h lj_opt_fold.c + COMMAND luajit-buildvm -m recdef -o gen/lj_recdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c + COMMAND luajit-buildvm -m libdef -o gen/lj_libdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c + COMMAND luajit-buildvm -m vmdef -o jit/vmdef.lua lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src +) + + +add_library(luajit STATIC + vendor/luajit/src/lj_gc.c + vendor/luajit/src/lj_err.c + vendor/luajit/src/lj_char.c + vendor/luajit/src/lj_bc.c + vendor/luajit/src/lj_obj.c + vendor/luajit/src/lj_str.c + vendor/luajit/src/lj_tab.c + vendor/luajit/src/lj_func.c + vendor/luajit/src/lj_udata.c + vendor/luajit/src/lj_meta.c + vendor/luajit/src/lj_debug.c + vendor/luajit/src/lj_state.c + vendor/luajit/src/lj_dispatch.c + vendor/luajit/src/lj_vmevent.c + vendor/luajit/src/lj_vmmath.c + vendor/luajit/src/lj_strscan.c + vendor/luajit/src/lj_api.c + vendor/luajit/src/lj_lex.c + vendor/luajit/src/lj_parse.c + vendor/luajit/src/lj_bcread.c + vendor/luajit/src/lj_bcwrite.c + vendor/luajit/src/lj_load.c + vendor/luajit/src/lj_ir.c + vendor/luajit/src/lj_opt_mem.c + vendor/luajit/src/lj_opt_fold.c + vendor/luajit/src/lj_opt_narrow.c + vendor/luajit/src/lj_opt_dce.c + vendor/luajit/src/lj_opt_loop.c + vendor/luajit/src/lj_opt_split.c + vendor/luajit/src/lj_opt_sink.c + vendor/luajit/src/lj_mcode.c + vendor/luajit/src/lj_snap.c + vendor/luajit/src/lj_record.c + vendor/luajit/src/lj_crecord.c + vendor/luajit/src/lj_ffrecord.c + vendor/luajit/src/lj_asm.c + vendor/luajit/src/lj_trace.c + vendor/luajit/src/lj_gdbjit.c + vendor/luajit/src/lj_ctype.c + vendor/luajit/src/lj_cdata.c + vendor/luajit/src/lj_cconv.c + vendor/luajit/src/lj_ccall.c + vendor/luajit/src/lj_ccallback.c + vendor/luajit/src/lj_carith.c + vendor/luajit/src/lj_clib.c + vendor/luajit/src/lj_cparse.c + vendor/luajit/src/lj_lib.c + vendor/luajit/src/lj_alloc.c + vendor/luajit/src/lib_aux.c + vendor/luajit/src/lib_base.c + vendor/luajit/src/lib_math.c + vendor/luajit/src/lib_bit.c + vendor/luajit/src/lib_string.c + vendor/luajit/src/lib_table.c + vendor/luajit/src/lib_io.c + vendor/luajit/src/lib_os.c + vendor/luajit/src/lib_package.c + vendor/luajit/src/lib_debug.c + vendor/luajit/src/lib_jit.c + vendor/luajit/src/lib_ffi.c + vendor/luajit/src/lib_init.c +) +if(MSVC) + target_sources(luajit PRIVATE vendor/luajit/src/lj_vm.obj) +else(MSVC) + target_sources(luajit PRIVATE vendor/luajit/src/lj_vm.s) + set_property(SOURCE vendor/luajit/src/lj_vm.s PROPERTY LANGUAGE C) + target_link_libraries(luajit dl) +endif(MSVC) +target_include_directories(luajit PRIVATE vendor/luajit/src/gen) +add_dependencies(luajit luajit-buildvm) +target_compile_definitions(luajit PRIVATE LUAJIT_ENABLE_LUA52COMPAT) + +add_library(resrc STATIC + src/libresrc/bitmap.cpp + src/libresrc/default_config.cpp + src/libresrc/libresrc.cpp +) +add_dependencies(resrc luajit-minilua) + +add_library(csri STATIC + vendor/csri/lib/list.c + vendor/csri/lib/wrap.c + vendor/csri/subhelp/logging.c +) +target_include_directories(csri PRIVATE "vendor/csri/include") +IF (WIN32) + target_include_directories(csri PRIVATE "vendor/csri/lib/win32") + target_sources(csri PRIVATE vendor/csri/lib/win32/enumerate.c) +ELSE() + target_include_directories(csri PRIVATE "vendor/csri/lib/posix") + target_sources(csri PRIVATE vendor/csri/lib/posix/enumerate.c) +ENDIF() + +add_executable(Aegisub WIN32 + src/command/app.cpp + src/command/audio.cpp + src/command/automation.cpp + src/command/command.cpp + src/command/edit.cpp + src/command/grid.cpp + src/command/help.cpp + src/command/keyframe.cpp + src/command/recent.cpp + src/command/subtitle.cpp + src/command/time.cpp + src/command/timecode.cpp + src/command/tool.cpp + src/command/video.cpp + src/command/vis_tool.cpp + src/dialog_about.cpp + src/dialog_align.cpp + src/dialog_attachments.cpp + src/dialog_automation.cpp + src/dialog_autosave.cpp + src/dialog_colorpicker.cpp + src/dialog_detached_video.cpp + src/dialog_dummy_video.cpp + src/dialog_export.cpp + src/dialog_export_ebu3264.cpp + src/dialog_fonts_collector.cpp + src/dialog_jumpto.cpp + src/dialog_kara_timing_copy.cpp + src/dialog_log.cpp + src/dialog_paste_over.cpp + src/dialog_progress.cpp + src/dialog_properties.cpp + src/dialog_resample.cpp + src/dialog_search_replace.cpp + src/dialog_selected_choices.cpp + src/dialog_selection.cpp + src/dialog_shift_times.cpp + src/dialog_spellchecker.cpp + src/dialog_style_editor.cpp + src/dialog_style_manager.cpp + src/dialog_styling_assistant.cpp + src/dialog_text_import.cpp + src/dialog_timing_processor.cpp + src/dialog_translation.cpp + src/dialog_version_check.cpp + src/dialog_video_details.cpp + src/dialog_video_properties.cpp + src/subtitle_format.cpp + src/subtitle_format_ass.cpp + src/subtitle_format_ebu3264.cpp + src/subtitle_format_encore.cpp + src/subtitle_format_microdvd.cpp + src/subtitle_format_mkv.cpp + src/subtitle_format_srt.cpp + src/subtitle_format_ssa.cpp + src/subtitle_format_transtation.cpp + src/subtitle_format_ttxt.cpp + src/subtitle_format_txt.cpp + src/visual_tool.cpp + src/visual_tool_clip.cpp + src/visual_tool_cross.cpp + src/visual_tool_drag.cpp + src/visual_tool_rotatexy.cpp + src/visual_tool_rotatez.cpp + src/visual_tool_scale.cpp + src/visual_tool_vector_clip.cpp + src/MatroskaParser.c + src/aegisublocale.cpp + src/ass_attachment.cpp + src/ass_dialogue.cpp + src/ass_entry.cpp + src/ass_export_filter.cpp + src/ass_exporter.cpp + src/ass_file.cpp + src/ass_karaoke.cpp + src/ass_override.cpp + src/ass_parser.cpp + src/ass_style.cpp + src/ass_style_storage.cpp + src/async_video_provider.cpp + src/audio_box.cpp + src/audio_colorscheme.cpp + src/audio_controller.cpp + src/audio_display.cpp + src/audio_karaoke.cpp + src/audio_marker.cpp + src/audio_player.cpp + src/audio_provider_factory.cpp + src/audio_renderer.cpp + src/audio_renderer_spectrum.cpp + src/audio_renderer_waveform.cpp + src/audio_timing_dialogue.cpp + src/audio_timing_karaoke.cpp + src/auto4_base.cpp + src/auto4_lua.cpp + src/auto4_lua_assfile.cpp + src/auto4_lua_dialog.cpp + src/auto4_lua_progresssink.cpp + src/base_grid.cpp + src/charset_detect.cpp + src/colorspace.cpp + src/colour_button.cpp + src/compat.cpp + src/context.cpp + src/export_fixstyle.cpp + src/export_framerate.cpp + src/fft.cpp + src/font_file_lister.cpp + src/frame_main.cpp + src/gl_text.cpp + src/gl_wrap.cpp + src/grid_column.cpp + src/help_button.cpp + src/hotkey.cpp + src/hotkey_data_view_model.cpp + src/image_position_picker.cpp + src/initial_line_state.cpp + src/main.cpp + src/menu.cpp + src/mkv_wrap.cpp + src/pen.cpp + src/persist_location.cpp + src/preferences.cpp + src/preferences_base.cpp + src/project.cpp + src/resolution_resampler.cpp + src/search_replace_engine.cpp + src/selection_controller.cpp + src/spellchecker.cpp + src/spline.cpp + src/spline_curve.cpp + src/string_codec.cpp + src/subs_controller.cpp + src/subs_edit_box.cpp + src/subs_edit_ctrl.cpp + src/subs_preview.cpp + src/subtitles_provider.cpp + src/subtitles_provider_libass.cpp + src/text_file_reader.cpp + src/text_file_writer.cpp + src/text_selection_controller.cpp + src/thesaurus.cpp + src/timeedit_ctrl.cpp + src/toggle_bitmap.cpp + src/toolbar.cpp + src/tooltip_manager.cpp + src/utils.cpp + src/validators.cpp + src/vector2d.cpp + src/version.cpp + src/video_box.cpp + src/video_controller.cpp + src/video_display.cpp + src/video_frame.cpp + src/video_out_gl.cpp + src/video_provider_cache.cpp + src/video_provider_dummy.cpp + src/video_provider_manager.cpp + src/video_provider_yuv4mpeg.cpp + src/video_slider.cpp + src/visual_feature.cpp +) +target_link_libraries(Aegisub ${CMAKE_DL_LIBS} libaegisub luabins luajit resrc csri) + +if (MSVC) + set_target_properties(libaegisub PROPERTIES COMPILE_FLAGS "/Yu${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h" COMPILE_FLAGS "/FI${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h") +else(MSVC) + target_compile_options(libaegisub PRIVATE -include "${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h") +endif(MSVC) + +set_property( + SOURCE libaegisub/unix/path.cpp + PROPERTY COMPILE_DEFINITIONS + P_DATA="${CMAKE_INSTALL_PREFIX}/share/aegisub/" +) + +if (MSVC) + add_definitions("-DNOMINMAX -MP -DINITGUID") + set_target_properties(Aegisub PROPERTIES COMPILE_FLAGS "/Yu${PROJECT_SOURCE_DIR}/src/agi_pre.h" COMPILE_FLAGS "/FI${PROJECT_SOURCE_DIR}/src/agi_pre.h") + target_link_libraries (Aegisub Usp10) + #target_sources(Aegisub PRIVATE src/res/res.rc src/res/strings.rc src/crash_writer_minidump.cpp) + target_sources(Aegisub PRIVATE src/res/res.rc src/res/strings.rc src/crash_writer.cpp src/dpi_aware.manifest) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Aegisub) +else(MSVC) + target_sources(Aegisub PRIVATE src/crash_writer.cpp) + target_compile_options(Aegisub PRIVATE -include "${PROJECT_SOURCE_DIR}/src/agi_pre.h") +endif(MSVC) + +if (WIN32) + target_sources(Aegisub PRIVATE src/font_file_lister_gdi.cpp) +else (WIN32) + find_package(Fontconfig REQUIRED) + target_link_libraries (Aegisub ${Fontconfig_LIBRARIES}) + target_sources(Aegisub PRIVATE src/font_file_lister_fontconfig.cpp) + set_property(SOURCE src/font_file_lister_fontconfig.cpp PROPERTY INCLUDE_DIRECTORIES "${Fontconfig_INCLUDE_DIRS}") +endif (WIN32) + +find_package(ass REQUIRED) +include_directories(${ass_INCLUDE_DIRS}) +target_link_libraries (Aegisub ${ass_LIBRARIES}) + +find_package(Boost REQUIRED chrono filesystem locale regex system thread) +include_directories(${Boost_INCLUDE_DIRS}) +target_link_directories(Aegisub PRIVATE ${Boost_LIBRARY_DIRS}) +target_link_libraries(Aegisub ${Boost_LIBRARIES}) + +find_package(OpenGL REQUIRED) +include_directories(${OPENGL_INCLUDE_DIR}) +target_link_libraries (Aegisub ${OPENGL_LIBRARIES}) + +find_package(Hunspell REQUIRED) +include_directories(${HUNSPELL_INCLUDE_DIR}) +target_link_libraries (Aegisub ${HUNSPELL_LIBRARIES}) +add_definitions("-DWITH_HUNSPELL") +target_sources(Aegisub PRIVATE src/spellchecker_hunspell.cpp) + +find_package(Iconv REQUIRED) +include_directories(${Iconv_INCLUDE_DIRS}) +target_link_libraries (Aegisub ${Iconv_LIBRARIES}) +add_definitions("-DHAVE_ICONV") +if (NOT Iconv_IS_BUILT_IN) +set_property( + SOURCE libaegisub/common/charset_conv.cpp + PROPERTY COMPILE_DEFINITIONS AGI_ICONV_CONST +) +endif (NOT Iconv_IS_BUILT_IN) + +find_package(ICU REQUIRED uc dt in) +include_directories(${ICU_INCLUDE_DIRS}) +target_link_libraries (Aegisub ${ICU_LIBRARIES}) + +find_package(wxWidgets REQUIRED adv base core gl stc xml) +include(${wxWidgets_USE_FILE}) +target_link_libraries(Aegisub ${wxWidgets_LIBRARIES}) + +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIRS}) +target_link_libraries (Aegisub ${ZLIB_LIBRARIES}) + +find_package(ALSA) +if (ALSA_FOUND) + include_directories(${ALSA_INCLUDE_DIRS}) + target_link_libraries (Aegisub ${ALSA_LIBRARIES}) + add_definitions("-DWITH_ALSA") + target_sources(Aegisub PRIVATE src/audio_player_alsa.cpp) +endif(ALSA_FOUND) + +# target_compile_definitions(Aegisub PRIVATE "WITH_AVISYNTH") +# target_sources(Aegisub PRIVATE src/audio_provider_avs.cpp src/avisynth_wrap.cpp src/video_provider_avs.cpp) + +target_compile_definitions(Aegisub PRIVATE "WITH_CSRI") +target_sources(Aegisub PRIVATE src/subtitles_provider_csri.cpp) +set_property(SOURCE src/subtitles_provider_csri.cpp PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/vendor/csri/include") + +if(MSVC) + target_link_libraries (Aegisub dsound) + add_definitions("-DWITH_DIRECTSOUND") + target_sources(Aegisub PRIVATE src/audio_player_dsound.cpp src/audio_player_dsound2.cpp) +endif(MSVC) + +find_package(FFMS2) +if (FFMS2_FOUND) + include_directories(${FFMS2_INCLUDE_DIRS}) + target_link_libraries (Aegisub ${FFMS2_LIBRARIES}) + add_definitions("-DWITH_FFMS2") + target_sources(Aegisub PRIVATE src/audio_provider_ffmpegsource.cpp src/ffmpegsource_common.cpp src/video_provider_ffmpegsource.cpp) +endif(FFMS2_FOUND) + +find_package(FFTW) +if (FFTW_FOUND) + include_directories(${FFTW_INCLUDES}) + target_link_libraries (Aegisub ${FFTW_LIBRARIES}) + add_definitions("-DWITH_FFTW3") +endif(FFTW_FOUND) + +#ifdef WITH_LIBPULSE +#add_definitions("-DWITH_LIBPULSE") +#target_sources(Aegisub PRIVATE src/audio_player_pulse.cpp) + +find_package(OpenAL) +if (OPENAL_FOUND) + include_directories(${OPENAL_INCLUDE_DIR}) + target_link_libraries (Aegisub ${OPENAL_LIBRARY}) + add_definitions("-DWITH_OPENAL") + target_sources(Aegisub PRIVATE src/audio_player_openal.cpp) +endif(OPENAL_FOUND) + +#ifdef WITH_OSS +#ifdef WITH_PORTAUDIO +#ifdef WITH_STARTUPLOG + +find_package(uchardet) +if (uchardet_FOUND) + include_directories(${uchardet_INCLUDE_DIRS}) + target_link_libraries (Aegisub ${uchardet_LIBRARIES}) + add_definitions("-DWITH_UCHARDET") +endif(uchardet_FOUND) + +#ifdef WITH_UPDATE_CHECKER diff --git a/src/bitmaps/button/button_align_16.png b/src/bitmaps/button/button_align_16.png new file mode 100644 index 0000000000000000000000000000000000000000..07ce86c1b127a1cb5711bebf1b67ccb99b70623d GIT binary patch literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Ec@}jv*HQ$$$R;w`bOD;PevaWeYoeTf2S7 z&Ykb;+KUt!7AA(JswnepIeV+>^|!T;kN4OA{`U66%IE-50R|pbjvwEDzn$|m`hLtk zRuK{L$&DwP7_CECB@|3@W{0s&xwAFZaDq+I%PZ0gE;KK8_?FyZ!lPiq(73%%BA|6k zZbeV43Ul*?)34nd?i9aYxJjU4(Zj<}-#UnXyt=s|M?qOxS$ch&z5I=aPYDH&9_mjx zVLO30{eEL=Vgu_UCXQcPm+B1-YX1I@pEt4a`90Cw`FHl!l(7fQnJlZs&m7R}@Zssf xZ^0b$Ru4^P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0nkZAK~y+TWBmXB zKLa%Y6O^VHj2c83kYLdD-Ag>&-Q#MfLiwlwJ^FVoo4o((D|S|9Ap8HnzyDaon(J~Q zQYU5>TW0hz7)AX*yA&dV0)Pe~gLor$s00*k3&>?PjfQa1 z0J=dHLE1po2~BH(>|#ezUZdbozwWCF$rza!^MO)3gM?!$L?s%)2<+P%ymIG3*)X69 zG64d3cis976-5O^6}5kU|M>O$KQl8UJ39wd2m_3k*@OTC0{}7T!*frBZ>RtO002ov JPDHLkV1fYY?n3|o literal 0 HcmV?d00001 diff --git a/src/bitmaps/button/button_align_32.png b/src/bitmaps/button/button_align_32.png new file mode 100644 index 0000000000000000000000000000000000000000..958f4b34eb382f97943c26277c79d85bcf642221 GIT binary patch literal 690 zcmV;j0!{siP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0!K+iK~zXfWBmXB zKLafR6O^VI7`1>P7`1>PAU_{m+B$d1k^4-4zIkM~J1DS2MKJ-;0`kDT1U-le6}#U< zg|GqaL8QWn1*pc%hf0HifPerR11rEDM7oTOSD;J;un8&iHsty7>o1Va#>stl&E$1w z9s}8S(M8^FE@g3^U{&Y3CRl{!Pj`>sGmumY@+EWWS91I#!QxAfYz3zxubi4fIS62Q1t z&jxcD-hKHFVSIZ13Bte*pcY{O4^F582;lN7F4lsw-MbC~6)efLf^Zx5e}rhk3h?BE zgAn}?kg@pb|NpNTp*#kl4Vw#WA#D5>;3+EXcCON%? zfw1udd}Yyw`DdUkhF8;%f++j)?Vj8qM%mU)ii~)J9uA;B!2sK9ETAf2;4xVI^NA%} z@B9NYD2jtaJ>C$_C_pa0eYiLs$Xf==*qB8W!`dehRoDS`3%>5HW?-=X1LdIrUooh; zP@s_mmB0aTR5*XXFfj8#*{I;?x~ZGbykKKt6cpsw(e`n5Q-@060HZBCf?(7F0)T-5 Y0C1xRlIB)rD*ylh07*qoM6N<$g5zf=@Bjb+ literal 0 HcmV?d00001 diff --git a/src/bitmaps/button/button_align_48.png b/src/bitmaps/button/button_align_48.png new file mode 100644 index 0000000000000000000000000000000000000000..9d28cffad34b14a970c6f66148f86730efd2ce38 GIT binary patch literal 1161 zcmV;41a|w0P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1RhC5K~z{r?U;K^ zQ&$|vPfK4`sP+QoQ64@L5g97Vj0*;$GDwWkKNMfVY|b%_pvGlWnHq7~{-DMfW}I78 zW;9!tiLV$nQ9(tGbR*yc4WNP&)bNx}Ob_MBNo;}?uUUPNE^xt=3ayd zb5talLc;ax5HJzagmGX=fKk*9@o?gT9c8HGZJissyF}m6d~Kw zJ9d~W!ZPoAJv;DS*1Yvq4u}ytU%K32BGlj40hSa%*ne|+Z4{&;WXxQCzGCkfEw~8H zxQ#o$o;r-T6D-wlXX0)_lJB^fyt^5~5|C2V_LVU5dlc<2n+&EG{iKu4PQFWU1>xSS zmPnDcRTiG>#qB53L%}Bun`q&C1X&QN?%%&khvDC1%)Ro&McS$?^MrTR+ zK^XT`&rPAV0?b&q{}pX=H!VmL%o5_t&Q=yp^zE`i36gd;5V(xIBs17v)TX$2JvBqd zRUF?W5NmtX^4NiWciG?oVJw=DY!u4jnSQJjS_!8<8%?97_5YH?d`)sNm+aN8Kc*O9 z^moZ@g%s@Wx}5*%B5ObO?gg``Z8b9!VCeTrFFfO>X&(AP`Tx6&RYN`37tfk~sSP|Y zI+gGNsP^YV%cUN#rQm%)qg6_-PCr1HD6aMu*?x~-$v@r3_}L!tDC6?#{4T53qe;S0ltFz*w@HvV39jtoo&e#{c|04npRSi^{L{wVztLqIk!S?b}OAzAxEYkTu$O zyC9T%Nb~|0hgCyu6^R4SpIKW@Ly*vMBZtII`BpovohvbrCBn8kK1CYrqP|(2N{*U2 zCDwPU7UOOkoQss=3Gns)q?ba5G$ib@+S0{a&Ux>MfK+~y2nu*eO^0)-^Ot;kp`Bj0 zQjzfH`r6?R(Fq;^#c_5&yw%#L;a@g99#2?Us8$mZm&grvv&nx8vycU`kOi@j1+f@n bf)IKGkv!)D1ej0e00000NkvXXu0mjfC*2^6 literal 0 HcmV?d00001 diff --git a/src/bitmaps/button/button_align_64.png b/src/bitmaps/button/button_align_64.png new file mode 100644 index 0000000000000000000000000000000000000000..0d6039c0f20196b86105833560a4b72b2d7b5cb4 GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGH$#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!h8>hl?nh|9`X&#%!?c$n)|uyNCYXKOc> zDyFTtd*;C1KU)txdmj<1xr^}}H}mn8bH!&Jvw67DA*V*GY?5f2zvu-`ms>T{Q_U21 zTh8KDxe%&Q8T2oEE{~Z{LwLgDE8V?J0S&%inM>}#D^y%x-#_qSDF!-3_{V+XBk1uUs|cX54Lyl*3O z&HwkO&OB8R=sT14@AUFrXUg3=OxEQUt}L*Z=Hpw_Vvy&YmiI`DH~344!9zhsT^2dX zJvSOO8}B?3Fw(u6vyVsqq5AqqzW>!(&sh|+y0g81be_vVSMCsR;4l88zV#BRK?$~K eVLq+)KjREVtEGO6wweGVmci52&t;ucLK6V2*xU;M literal 0 HcmV?d00001 diff --git a/src/bitmaps/manifest.respack b/src/bitmaps/manifest.respack index 2dc110d3ae..55c731bd9d 100644 --- a/src/bitmaps/manifest.respack +++ b/src/bitmaps/manifest.respack @@ -51,6 +51,11 @@ button/bugtracker_button_24.png button/bugtracker_button_32.png button/bugtracker_button_48.png button/bugtracker_button_64.png +button/button_align_16.png +button/button_align_24.png +button/button_align_32.png +button/button_align_48.png +button/button_align_64.png button/button_audio_commit_16.png button/button_audio_commit_24.png button/button_audio_commit_32.png diff --git a/src/colour_button.h b/src/colour_button.h index b2e0f9335e..6234dc9fc6 100644 --- a/src/colour_button.h +++ b/src/colour_button.h @@ -43,6 +43,12 @@ class ColourButton: public wxButton { /// Get the currently selected color agi::Color GetColor() { return colour; } + + void SetColor(agi::Color color) + { + colour = color; + UpdateBitmap(); + } }; struct ColorValidator final : public wxValidator { diff --git a/src/command/time.cpp b/src/command/time.cpp index d703ebdc0d..eec19c2d4e 100644 --- a/src/command/time.cpp +++ b/src/command/time.cpp @@ -235,6 +235,18 @@ struct time_snap_scene final : public validate_video_loaded { } }; +struct time_align_subtitle_to_point final : public validate_video_loaded { + CMD_NAME("time/align") + CMD_ICON(button_align) + STR_MENU("Align subtitle to video") + STR_DISP("Align subtitle to video") + STR_HELP("Align subtitle to video by key points.") + void operator()(agi::Context* c) override { + c->videoController->Stop(); + ShowAlignToVideoDialog(c); + } +}; + struct time_add_lead_both final : public Command { CMD_NAME("time/lead/both") STR_MENU("Add lead in and out") @@ -393,6 +405,7 @@ namespace cmd { reg(agi::make_unique()); reg(agi::make_unique()); reg(agi::make_unique()); + reg(agi::make_unique()); reg(agi::make_unique()); reg(agi::make_unique()); } diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp new file mode 100644 index 0000000000..004408bfa3 --- /dev/null +++ b/src/dialog_align.cpp @@ -0,0 +1,378 @@ +// Copyright (c) 2019, Charlie Jiang +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Aegisub Project http://www.aegisub.org/ + +#include "ass_dialogue.h" +#include "ass_file.h" +#include "compat.h" +#include "dialog_manager.h" +#include "format.h" +#include "include/aegisub/context.h" +#include "video_frame.h" +#include "libresrc/libresrc.h" +#include "options.h" +#include "project.h" +#include "selection_controller.h" +#include "video_controller.h" +#include "async_video_provider.h" +#include "colour_button.h" +#include "image_position_picker.h" + +#include + +#include +#include + +#include +#include +#include +#if BOOST_VERSION >= 106900 +#include +#else +#include +#endif + +namespace { + class DialogAlignToVideo final : public wxDialog { + agi::Context* context; + AsyncVideoProvider* provider; + + wxImage preview_image; + VideoFrame current_frame; + int current_n_frame; + + ImagePositionPicker* preview_frame; + ColourButton* selected_color; + wxTextCtrl* selected_x; + wxTextCtrl* selected_y; + wxTextCtrl* selected_tolerance; + + void update_from_textbox(); + void update_from_textbox(wxCommandEvent&); + + bool check_exists(int pos, int x, int y, int* lrud, double* orig, unsigned char tolerance); + void process(wxCommandEvent&); + public: + DialogAlignToVideo(agi::Context* context); + ~DialogAlignToVideo(); + }; + + DialogAlignToVideo::DialogAlignToVideo(agi::Context* context) + : wxDialog(context->parent, -1, _("Align subtitle to video by key point"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxRESIZE_BORDER) + , context(context), provider(context->project->VideoProvider()) + { + auto add_with_label = [&](wxSizer * sizer, wxString const& label, wxWindow * ctrl) { + sizer->Add(new wxStaticText(this, -1, label), 0, wxLEFT | wxRIGHT | wxCENTER, 3); + sizer->Add(ctrl, 1, wxLEFT); + }; + + auto tolerance = OPT_GET("Tool/Align to Video/Tolerance")->GetInt(); + auto maximized = OPT_GET("Tool/Align to Video/Maximized")->GetBool(); + + current_n_frame = context->videoController->GetFrameN(); + current_frame = *context->project->VideoProvider()->GetFrame(current_n_frame, 0, true); + preview_image = GetImage(current_frame); + + preview_frame = new ImagePositionPicker(this, preview_image, [&](int x, int y, unsigned char r, unsigned char g, unsigned char b) -> void { + selected_x->ChangeValue(wxString::Format(wxT("%i"), x)); + selected_y->ChangeValue(wxString::Format(wxT("%i"), y)); + + selected_color->SetColor(agi::Color(r, g, b)); + }); + selected_color = new ColourButton(this, wxSize(55, 16), true, agi::Color("FFFFFF")); + selected_color->SetToolTip(_("The key color to be followed.")); + selected_x = new wxTextCtrl(this, -1, "0"); + selected_x->SetToolTip(_("The x coord of the key point.")); + selected_y = new wxTextCtrl(this, -1, "0"); + selected_y->SetToolTip(_("The y coord of the key point.")); + selected_tolerance = new wxTextCtrl(this, -1, wxString::Format(wxT("%i"), int(tolerance))); + selected_tolerance->SetToolTip(_("Max tolerance of the color.")); + + selected_x->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this); + selected_y->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this); + update_from_textbox(); + + wxFlexGridSizer* right_sizer = new wxFlexGridSizer(4, 2, 5, 5); + add_with_label(right_sizer, _("X"), selected_x); + add_with_label(right_sizer, _("Y"), selected_y); + add_with_label(right_sizer, _("Color"), selected_color); + add_with_label(right_sizer, _("Tolerance"), selected_tolerance); + right_sizer->AddGrowableCol(1, 1); + + wxSizer* main_sizer = new wxBoxSizer(wxHORIZONTAL); + + main_sizer->Add(preview_frame, 1, (wxALL & ~wxRIGHT) | wxEXPAND, 5); + main_sizer->Add(right_sizer, 0, wxALIGN_LEFT, 5); + + wxSizer* dialog_sizer = new wxBoxSizer(wxVERTICAL); + dialog_sizer->Add(main_sizer, wxSizerFlags(1).Border(wxALL & ~wxBOTTOM).Expand()); + dialog_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Right().Border()); + SetSizerAndFit(dialog_sizer); + SetSize(1024, 700); + CenterOnParent(); + + Bind(wxEVT_BUTTON, &DialogAlignToVideo::process, this, wxID_OK); + SetIcon(GETICON(button_align_16)); + if (maximized) + wxDialog::Maximize(true); + } + + DialogAlignToVideo::~DialogAlignToVideo() + { + long lt; + if (!selected_tolerance->GetValue().ToLong(<)) + return; + if (lt < 0 || lt > 255) + return; + + OPT_SET("Tool/Align to Video/Tolerance")->SetInt(lt); + } + + void rgb2lab(unsigned char r, unsigned char g, unsigned char b, double* lab) + { + double R = static_cast(r) / 255.0; + double G = static_cast(g) / 255.0; + double B = static_cast(b) / 255.0; + double X = 0.412453 * R + 0.357580 * G + 0.180423 * B; + double Y = 0.212671 * R + 0.715160 * G + 0.072169 * B; + double Z = 0.019334 * R + 0.119193 * G + 0.950227 * B; + double xr = X / 0.950456, yr = Y / 1.000, zr = Z / 1.088854; + + if (yr > 0.008856) { + lab[0] = 116.0 * pow(yr, 1.0 / 3.0) - 16.0; + } + else { + lab[0] = 903.3 * yr; + } + + double fxr, fyr, fzr; + if (xr > 0.008856) + fxr = pow(xr, 1.0 / 3.0); + else + fxr = 7.787 * xr + 16.0 / 116.0; + + if (yr > 0.008856) + fyr = pow(yr, 1.0 / 3.0); + else + fyr = 7.787 * yr + 16.0 / 116.0; + + if (zr > 0.008856) + fzr = pow(zr, 1.0 / 3.0); + else + fzr = 7.787 * zr + 16.0 / 116.0; + + lab[1] = 500.0 * (fxr - fyr); + lab[2] = 200.0 * (fyr - fzr); + } + + template + bool check_point(boost::gil::pixel & pixel, double orig[3], unsigned char tolerance) + { + double lab[3]; + // in pixel: B,G,R + rgb2lab(pixel[2], pixel[1], pixel[0], lab); + auto diff = sqrt(pow(lab[0] - orig[0], 2) + pow(lab[1] - orig[1], 2) + pow(lab[2] - orig[2], 2)); + return diff < tolerance; + } + + template + bool calculate_point(boost::gil::image_view view, int x, int y, double orig[3], unsigned char tolerance, int* ret) + { + auto origin = *view.at(x, y); + if (!check_point(origin, orig, tolerance)) + return false; + auto w = view.width(); + auto h = view.height(); + int l = x, r = x, u = y, d = y; + for (int i = x + 1; i < w; i++) + { + auto p = *view.at(i, y); + if (!check_point(p, orig, tolerance)) + { + r = i; + break; + } + } + + for (int i = x - 1; i >= 0; i--) + { + auto p = *view.at(i, y); + if (!check_point(p, orig, tolerance)) + { + l = i; + break; + } + } + + for (int i = y + 1; i < h; i++) + { + auto p = *view.at(x, i); + if (!check_point(p, orig, tolerance)) + { + d = i; + break; + } + } + + for (int i = y - 1; i >= 0; i--) + { + auto p = *view.at(x, i); + if (!check_point(p, orig, tolerance)) + { + u = i; + break; + } + } + ret[0] = l; + ret[1] = r; + ret[2] = u; + ret[3] = d; + return true; + } + + void DialogAlignToVideo::process(wxCommandEvent & evt) + { + auto n_frames = provider->GetFrameCount(); + auto w = provider->GetWidth(); + auto h = provider->GetHeight(); + + long lx, ly, lt; + if (!selected_x->GetValue().ToLong(&lx) || !selected_y->GetValue().ToLong(&ly) || !selected_tolerance->GetValue().ToLong(<)) + { + wxMessageBox(_("Bad x or y position or tolerance value!")); + evt.Skip(); + return; + } + if (lx < 0 || ly < 0 || lx >= w || ly >= h) + { + wxMessageBox(wxString::Format(_("Bad x or y position! Require: 0 <= x < %i, 0 <= y < %i"), w, h)); + evt.Skip(); + return; + } + if (lt < 0 || lt > 255) + { + wxMessageBox(_("Bad tolerance value! Require: 0 <= torlerance <= 255")); + evt.Skip(); + return; + } + int x = int(lx), y = int(ly); + unsigned char tolerance = unsigned char(lt); + + auto color = selected_color->GetColor(); + auto r = color.r; + auto b = color.b; + auto g = color.g; + double lab[3]; + rgb2lab(r, g, b, lab); + + int pos = current_n_frame; + auto frame = provider->GetFrame(pos, -1, true); + auto view = interleaved_view(frame->width, frame->height, reinterpret_cast(frame->data.data()), frame->pitch); + if (frame->flipped) + y = frame->height - y; + int lrud[4]; + calculate_point(view, x, y, lab, tolerance, lrud); + + // find forward +#define CHECK_EXISTS_POS check_exists(pos, x, y, lrud, lab, tolerance) + while (pos >= 0) + { + if (CHECK_EXISTS_POS) + pos -= 2; + else break; + } + pos++; + pos = std::max(0, pos); + auto left = CHECK_EXISTS_POS ? pos : pos + 1; + + pos = current_n_frame; + while (pos < n_frames) + { + if (CHECK_EXISTS_POS) + pos += 2; + else break; + } + pos--; + pos = std::min(pos, n_frames - 1); + auto right = CHECK_EXISTS_POS ? pos : pos - 1; + + auto timecode = context->project->Timecodes(); + auto line = context->selectionController->GetActiveLine(); + line->Start = timecode.TimeAtFrame(left); + line->End = timecode.TimeAtFrame(right + 1); // exclusive + context->ass->Commit(_("Align to video by key point"), AssFile::COMMIT_DIAG_TIME); + Close(); + } + + + + bool DialogAlignToVideo::check_exists(int pos, int x, int y, int* lrud, double* orig, unsigned char tolerance) + { + auto frame = provider->GetFrame(pos, -1, true); + auto view = interleaved_view(frame->width, frame->height, reinterpret_cast(frame->data.data()), frame->pitch); + if (frame->flipped) + y = frame->height - y; + int actual[4]; + if (!calculate_point(view, x, y, orig, tolerance, actual)) return false; + int dl = abs(actual[0] - lrud[0]); + int dr = abs(actual[1] - lrud[1]); + int du = abs(actual[2] - lrud[2]); + int dd = abs(actual[3] - lrud[3]); + + return dl <= 5 && dr <= 5 && du <= 5 && dd <= 5; + } + + void DialogAlignToVideo::update_from_textbox() + { + long lx, ly; + int w = preview_image.GetWidth(), h = preview_image.GetHeight(); + if (!selected_x->GetValue().ToLong(&lx) || !selected_y->GetValue().ToLong(&ly)) + return; + + if (lx < 0 || ly < 0 || lx >= w || ly >= h) + return; + int x = int(lx); + int y = int(ly); + auto r = preview_image.GetRed(x, y); + auto g = preview_image.GetGreen(x, y); + auto b = preview_image.GetBlue(x, y); + selected_color->SetColor(agi::Color(r, g, b)); + } + + void DialogAlignToVideo::update_from_textbox(wxCommandEvent & evt) + { + update_from_textbox(); + } + +} + + +void ShowAlignToVideoDialog(agi::Context * c) +{ + c->dialog->Show(c); +} diff --git a/src/dialogs.h b/src/dialogs.h index 2e03d09e9e..d781c66148 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -74,3 +74,4 @@ void ShowSpellcheckerDialog(agi::Context *c); void ShowStyleManagerDialog(agi::Context *c); void ShowTimingProcessorDialog(agi::Context *c); void ShowVideoDetailsDialog(agi::Context *c); +void ShowAlignToVideoDialog(agi::Context* c); diff --git a/src/hotkey.cpp b/src/hotkey.cpp index 2ec8f50e42..deb624628e 100644 --- a/src/hotkey.cpp +++ b/src/hotkey.cpp @@ -29,6 +29,11 @@ #include namespace { + const char* added_hotkeys_cj[][3] = { + {"time/align", "Video", "KP_TAB"}, + {nullptr} + }; + const char *added_hotkeys_7035[][3] = { {"audio/play/line", "Audio", "R"}, {nullptr} @@ -81,6 +86,11 @@ void init() { auto migrations = OPT_GET("App/Hotkey Migrations")->GetListString(); + if (boost::find(migrations, "cj") == end(migrations)) { + migrate_hotkeys(added_hotkeys_cj); + migrations.emplace_back("cj"); + } + if (boost::find(migrations, "7035") == end(migrations)) { migrate_hotkeys(added_hotkeys_7035); migrations.emplace_back("7035"); diff --git a/src/image_position_picker.cpp b/src/image_position_picker.cpp new file mode 100644 index 0000000000..2bc9c6f898 --- /dev/null +++ b/src/image_position_picker.cpp @@ -0,0 +1,127 @@ +#include "image_position_picker.h" +BEGIN_EVENT_TABLE(ImagePositionPicker, wxPanel) + // some useful events + /* + EVT_MOTION(ImagePositionPicker::mouseMoved) + EVT_LEFT_DOWN(ImagePositionPicker::mouseDown) + EVT_LEFT_UP(ImagePositionPicker::mouseReleased) + EVT_RIGHT_DOWN(ImagePositionPicker::rightClick) + EVT_LEAVE_WINDOW(ImagePositionPicker::mouseLeftWindow) + EVT_KEY_DOWN(ImagePositionPicker::keyPressed) + EVT_KEY_UP(ImagePositionPicker::keyReleased) + EVT_MOUSEWHEEL(ImagePositionPicker::mouseWheelMoved) + */ + + // catch paint events + EVT_PAINT(ImagePositionPicker::paintEvent) + //Size event + EVT_SIZE(ImagePositionPicker::OnSize) + EVT_MOUSE_EVENTS(ImagePositionPicker::OnMouseEvent) +END_EVENT_TABLE() + + +// some useful events +/* + void ImagePositionPicker::mouseMoved(wxMouseEvent& event) {} + void ImagePositionPicker::mouseDown(wxMouseEvent& event) {} + void ImagePositionPicker::mouseWheelMoved(wxMouseEvent& event) {} + void ImagePositionPicker::mouseReleased(wxMouseEvent& event) {} + void ImagePositionPicker::rightClick(wxMouseEvent& event) {} + void ImagePositionPicker::mouseLeftWindow(wxMouseEvent& event) {} + void ImagePositionPicker::keyPressed(wxKeyEvent& event) {} + void ImagePositionPicker::keyReleased(wxKeyEvent& event) {} + */ + +ImagePositionPicker::ImagePositionPicker(wxWindow* parent, wxImage i, updator upd) : wxPanel(parent) +{ + image = i; + prevW = -1; + prevH = -1; + w = image.GetWidth(); + h = image.GetHeight(); + update = upd; +} + +/* + * Called by the system of by wxWidgets when the panel needs + * to be redrawn. You can also trigger this call by + * calling Refresh()/Update(). + */ + +void ImagePositionPicker::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Alternatively, you can use a clientDC to paint on the panel + * at any time. Using this generally does not free you from + * catching paint events, since it is possible that e.g. the window + * manager throws away your drawing when the window comes to the + * background, and expects you will redraw it when the window comes + * back (by sending a paint event). + */ +void ImagePositionPicker::paintNow() +{ + // depending on your system you may need to look at double-buffered dcs + wxClientDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void ImagePositionPicker::render(wxDC& dc) +{ + int neww, newh; + dc.GetSize(&neww, &newh); + + if (neww != prevW || newh != prevH) + { + // keep the image proportionate + int ww, hh; + if (double(neww) / w >= double(newh) / h) // too long + { + ww = newh * w / h; + hh = newh; + } + else + { + ww = neww; + hh = neww * h / w; + } + resized = wxBitmap(image.Scale(ww, hh /*, wxIMAGE_QUALITY_HIGH*/)); + prevW = ww; + prevH = hh; + dc.DrawBitmap(resized, 0, 0, false); + } + else { + dc.DrawBitmap(resized, 0, 0, false); + } +} + +/* + * Here we call refresh to tell the panel to draw itself again. + * So when the user resizes the image panel the image should be resized too. + */ +void ImagePositionPicker::OnSize(wxSizeEvent& event) { + Refresh(); + //skip the event. + event.Skip(); +} + +void ImagePositionPicker::OnMouseEvent(wxMouseEvent& evt) +{ + wxPoint pos = evt.GetPosition(); + if (evt.Dragging() || evt.LeftDown() || evt.LeftUp()) + { + int x = pos.x * w / prevW; + int y = pos.y * h / prevH; + if (x >= 0 && x < w && y >= 0 && y < h) + update(x, y, image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y)); + } +} diff --git a/src/image_position_picker.h b/src/image_position_picker.h new file mode 100644 index 0000000000..1f808db39e --- /dev/null +++ b/src/image_position_picker.h @@ -0,0 +1,37 @@ +#include +#include +#include "gl_wrap.h" + +typedef std::function updator; + +class ImagePositionPicker : public wxPanel +{ + wxImage image; + wxBitmap resized; + int prevW, prevH, w, h; + + updator update; + +public: + ImagePositionPicker(wxWindow* parent, wxImage i, updator upd); + + void paintEvent(wxPaintEvent & evt); + void paintNow(); + void OnSize(wxSizeEvent& event); + void OnMouseEvent(wxMouseEvent& evt); + void render(wxDC& dc); + + // some useful events + /* + void mouseMoved(wxMouseEvent& event); + void mouseDown(wxMouseEvent& event); + void mouseWheelMoved(wxMouseEvent& event); + void mouseReleased(wxMouseEvent& event); + void rightClick(wxMouseEvent& event); + void mouseLeftWindow(wxMouseEvent& event); + void keyPressed(wxKeyEvent& event); + void keyReleased(wxKeyEvent& event); + */ + + DECLARE_EVENT_TABLE() +}; diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index 318f8d3eef..c86ef36097 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -575,6 +575,10 @@ }, "Visual" : { "Autohide": false + }, + "Align to Video" : { + "Tolerance" : 20, + "Maximized" : true } }, diff --git a/src/libresrc/default_hotkey.json b/src/libresrc/default_hotkey.json index b9460979e8..d4b0af376a 100644 --- a/src/libresrc/default_hotkey.json +++ b/src/libresrc/default_hotkey.json @@ -286,6 +286,9 @@ ], "video/frame/prev/large" : [ "Alt-Left" + ], + "time/align" : [ + "KP_TAB" ] }, "Translation Assistant" : { diff --git a/src/libresrc/default_toolbar.json b/src/libresrc/default_toolbar.json index 07afb90b03..7b85ee600b 100644 --- a/src/libresrc/default_toolbar.json +++ b/src/libresrc/default_toolbar.json @@ -42,6 +42,7 @@ "subtitle/select/visible", "time/snap/scene", "time/frame/current", + "time/align", "", "tool/style/manager", "subtitle/properties", diff --git a/src/meson.build b/src/meson.build index 72587d366c..495c3f4183 100644 --- a/src/meson.build +++ b/src/meson.build @@ -56,6 +56,7 @@ aegisub_src = files( 'context.cpp', 'crash_writer.cpp', 'dialog_about.cpp', + 'dialog_align.cpp', 'dialog_attachments.cpp', 'dialog_automation.cpp', 'dialog_autosave.cpp', @@ -97,6 +98,7 @@ aegisub_src = files( 'help_button.cpp', 'hotkey.cpp', 'hotkey_data_view_model.cpp', + 'image_position_picker.cpp', 'initial_line_state.cpp', 'main.cpp', 'menu.cpp', From c71e140c410f3dda15e6a0a23afac699f87f2ba2 Mon Sep 17 00:00:00 2001 From: wangqr Date: Thu, 9 May 2019 16:48:15 -0400 Subject: [PATCH 2/9] Fix errors in AlignToVideo * Call TimeAtFrame with correct parameter * Fix syntax error --- src/dialog_align.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp index 004408bfa3..5243d21978 100644 --- a/src/dialog_align.cpp +++ b/src/dialog_align.cpp @@ -281,7 +281,7 @@ namespace { return; } int x = int(lx), y = int(ly); - unsigned char tolerance = unsigned char(lt); + unsigned char tolerance = (unsigned char)(lt); auto color = selected_color->GetColor(); auto r = color.r; @@ -323,8 +323,8 @@ namespace { auto timecode = context->project->Timecodes(); auto line = context->selectionController->GetActiveLine(); - line->Start = timecode.TimeAtFrame(left); - line->End = timecode.TimeAtFrame(right + 1); // exclusive + line->Start = timecode.TimeAtFrame(left, agi::vfr::Time::START); + line->End = timecode.TimeAtFrame(right, agi::vfr::Time::END); // exclusive context->ass->Commit(_("Align to video by key point"), AssFile::COMMIT_DIAG_TIME); Close(); } From 68166c758106acc654670a0fff716de808a66f40 Mon Sep 17 00:00:00 2001 From: wangqr Date: Mon, 9 Mar 2020 21:02:33 -0400 Subject: [PATCH 3/9] Fix missing config option for Align on macOS --- src/libresrc/osx/default_config.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json index 59f2ed05f5..56e9ec4e64 100644 --- a/src/libresrc/osx/default_config.json +++ b/src/libresrc/osx/default_config.json @@ -575,6 +575,10 @@ }, "Visual" : { "Autohide": false + }, + "Align to Video" : { + "Tolerance" : 20, + "Maximized" : true } }, From 42248eabade6a6dc97cf5f9cd3a86451b99ad739 Mon Sep 17 00:00:00 2001 From: wangqr Date: Sat, 24 Aug 2019 02:10:03 -0400 Subject: [PATCH 4/9] Remove the trailing period in help text of time/align Fix wangqr/Aegisub#7 --- src/command/time.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/time.cpp b/src/command/time.cpp index eec19c2d4e..c44216db23 100644 --- a/src/command/time.cpp +++ b/src/command/time.cpp @@ -240,7 +240,7 @@ struct time_align_subtitle_to_point final : public validate_video_loaded { CMD_ICON(button_align) STR_MENU("Align subtitle to video") STR_DISP("Align subtitle to video") - STR_HELP("Align subtitle to video by key points.") + STR_HELP("Align subtitle to video by key points") void operator()(agi::Context* c) override { c->videoController->Stop(); ShowAlignToVideoDialog(c); From b5e7bbc5ad898ee833636ff9e1d4a0e7bd6b595a Mon Sep 17 00:00:00 2001 From: wangqr Date: Wed, 25 Dec 2019 18:38:42 -0500 Subject: [PATCH 5/9] Submit "align to video" on double click Fix wangqr/Aegisub#34 --- src/dialog_align.cpp | 8 +++----- src/image_position_picker.cpp | 5 +++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp index 5243d21978..2de54b2c01 100644 --- a/src/dialog_align.cpp +++ b/src/dialog_align.cpp @@ -76,7 +76,7 @@ namespace { void update_from_textbox(wxCommandEvent&); bool check_exists(int pos, int x, int y, int* lrud, double* orig, unsigned char tolerance); - void process(wxCommandEvent&); + void process(wxEvent&); public: DialogAlignToVideo(agi::Context* context); ~DialogAlignToVideo(); @@ -137,6 +137,7 @@ namespace { CenterOnParent(); Bind(wxEVT_BUTTON, &DialogAlignToVideo::process, this, wxID_OK); + Bind(wxEVT_LEFT_DCLICK, &DialogAlignToVideo::process, this, preview_frame->GetId()); SetIcon(GETICON(button_align_16)); if (maximized) wxDialog::Maximize(true); @@ -255,7 +256,7 @@ namespace { return true; } - void DialogAlignToVideo::process(wxCommandEvent & evt) + void DialogAlignToVideo::process(wxEvent &) { auto n_frames = provider->GetFrameCount(); auto w = provider->GetWidth(); @@ -265,19 +266,16 @@ namespace { if (!selected_x->GetValue().ToLong(&lx) || !selected_y->GetValue().ToLong(&ly) || !selected_tolerance->GetValue().ToLong(<)) { wxMessageBox(_("Bad x or y position or tolerance value!")); - evt.Skip(); return; } if (lx < 0 || ly < 0 || lx >= w || ly >= h) { wxMessageBox(wxString::Format(_("Bad x or y position! Require: 0 <= x < %i, 0 <= y < %i"), w, h)); - evt.Skip(); return; } if (lt < 0 || lt > 255) { wxMessageBox(_("Bad tolerance value! Require: 0 <= torlerance <= 255")); - evt.Skip(); return; } int x = int(lx), y = int(ly); diff --git a/src/image_position_picker.cpp b/src/image_position_picker.cpp index 2bc9c6f898..5912b4fc32 100644 --- a/src/image_position_picker.cpp +++ b/src/image_position_picker.cpp @@ -124,4 +124,9 @@ void ImagePositionPicker::OnMouseEvent(wxMouseEvent& evt) if (x >= 0 && x < w && y >= 0 && y < h) update(x, y, image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y)); } + else if (evt.LeftDClick()) { + // Propagate the double click event to submit + evt.ResumePropagation(wxEVENT_PROPAGATE_MAX); + evt.Skip(); + } } From e098342f54a21e2cc87fef0c2ff5aaedc1512923 Mon Sep 17 00:00:00 2001 From: Oneric Date: Thu, 16 Jul 2020 23:04:26 +0200 Subject: [PATCH 6/9] dialog_align: Remove point at the end of the tooltips No other tooltips end with points, even if they're a sentence.These ones aren't even sentences. Also updates all *.po files accordingly, with an hacked in POT-Creation-Date due to issues with make_pot.sh. --- src/dialog_align.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp index 2de54b2c01..2c40eedbf5 100644 --- a/src/dialog_align.cpp +++ b/src/dialog_align.cpp @@ -105,13 +105,13 @@ namespace { selected_color->SetColor(agi::Color(r, g, b)); }); selected_color = new ColourButton(this, wxSize(55, 16), true, agi::Color("FFFFFF")); - selected_color->SetToolTip(_("The key color to be followed.")); + selected_color->SetToolTip(_("The key color to be followed")); selected_x = new wxTextCtrl(this, -1, "0"); - selected_x->SetToolTip(_("The x coord of the key point.")); + selected_x->SetToolTip(_("The x coord of the key point")); selected_y = new wxTextCtrl(this, -1, "0"); - selected_y->SetToolTip(_("The y coord of the key point.")); + selected_y->SetToolTip(_("The y coord of the key point")); selected_tolerance = new wxTextCtrl(this, -1, wxString::Format(wxT("%i"), int(tolerance))); - selected_tolerance->SetToolTip(_("Max tolerance of the color.")); + selected_tolerance->SetToolTip(_("Max tolerance of the color")); selected_x->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this); selected_y->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this); From 7a729532b44d163892a1b241fbc5c747f620380b Mon Sep 17 00:00:00 2001 From: Oneric Date: Fri, 17 Jul 2020 17:09:05 +0200 Subject: [PATCH 7/9] AlignToVideo: Improve rgb->lab precision --- src/dialog_align.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp index 2c40eedbf5..dafc599728 100644 --- a/src/dialog_align.cpp +++ b/src/dialog_align.cpp @@ -156,12 +156,9 @@ namespace { void rgb2lab(unsigned char r, unsigned char g, unsigned char b, double* lab) { - double R = static_cast(r) / 255.0; - double G = static_cast(g) / 255.0; - double B = static_cast(b) / 255.0; - double X = 0.412453 * R + 0.357580 * G + 0.180423 * B; - double Y = 0.212671 * R + 0.715160 * G + 0.072169 * B; - double Z = 0.019334 * R + 0.119193 * G + 0.950227 * B; + double X = (0.412453 * r + 0.357580 * g + 0.180423 * b) / 255.0; + double Y = (0.212671 * r + 0.715160 * g + 0.072169 * b) / 255.0; + double Z = (0.019334 * r + 0.119193 * g + 0.950227 * b) / 255.0; double xr = X / 0.950456, yr = Y / 1.000, zr = Z / 1.088854; if (yr > 0.008856) { From 61c6303a1439f000527af381c6b8f5f8163da5b8 Mon Sep 17 00:00:00 2001 From: Oneric Date: Thu, 16 Jul 2020 23:21:25 +0200 Subject: [PATCH 8/9] AlignToVideo: Handle tolerance = 0 correctly Checking if the diff is '>' instead of '>=' will always fail if tolerance=0, even if the colours are identical. This will cause the line to get a startime greter than its end time, which is not desireable. Rounding errors and limits of floating type precision might still affect the comparison. An additional sanity check before calculation is added to ensure the selected position and colour match within tolerance. This allows us to refactor the search code to never check the starting frame and guanrantees valid timings with start @@ -290,28 +290,30 @@ namespace { auto view = interleaved_view(frame->width, frame->height, reinterpret_cast(frame->data.data()), frame->pitch); if (frame->flipped) y = frame->height - y; + + // Ensure selected color and position match + if(!check_point(*view.at(x,y), lab, tolerance)) + { + wxMessageBox(_("Selected position and color are not within tolerance!")); + return; + } + int lrud[4]; calculate_point(view, x, y, lab, tolerance, lrud); // find forward #define CHECK_EXISTS_POS check_exists(pos, x, y, lrud, lab, tolerance) - while (pos >= 0) - { - if (CHECK_EXISTS_POS) - pos -= 2; - else break; - } + do { + pos -= 2; + } while (pos >= 0 && !CHECK_EXISTS_POS) pos++; pos = std::max(0, pos); auto left = CHECK_EXISTS_POS ? pos : pos + 1; pos = current_n_frame; - while (pos < n_frames) - { - if (CHECK_EXISTS_POS) - pos += 2; - else break; - } + do { + pos += 2; + } while (pos < n_frames && !CHECK_EXISTS_POS) pos--; pos = std::min(pos, n_frames - 1); auto right = CHECK_EXISTS_POS ? pos : pos - 1; From c232ef6bb6458036ec325fc1dd14ccd65deffb12 Mon Sep 17 00:00:00 2001 From: wangqr Date: Fri, 17 Jul 2020 12:47:06 -0400 Subject: [PATCH 9/9] Fix syntax error in e2ea84541f806310c1c7b37cb6e38569cf845488 --- src/dialog_align.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialog_align.cpp b/src/dialog_align.cpp index d6d755352f..93e5066363 100644 --- a/src/dialog_align.cpp +++ b/src/dialog_align.cpp @@ -305,7 +305,7 @@ namespace { #define CHECK_EXISTS_POS check_exists(pos, x, y, lrud, lab, tolerance) do { pos -= 2; - } while (pos >= 0 && !CHECK_EXISTS_POS) + } while (pos >= 0 && CHECK_EXISTS_POS); pos++; pos = std::max(0, pos); auto left = CHECK_EXISTS_POS ? pos : pos + 1; @@ -313,7 +313,7 @@ namespace { pos = current_n_frame; do { pos += 2; - } while (pos < n_frames && !CHECK_EXISTS_POS) + } while (pos < n_frames && CHECK_EXISTS_POS); pos--; pos = std::min(pos, n_frames - 1); auto right = CHECK_EXISTS_POS ? pos : pos - 1;