From 7c92e6bbd65da85f584a4bce932160e6fb5594f9 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Sun, 31 Jul 2022 21:31:34 +0200 Subject: [PATCH 01/16] Folding: Dont error on missing _foldinfo --- src/auto4_lua_assfile.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/auto4_lua_assfile.cpp b/src/auto4_lua_assfile.cpp index f98e0a35d..c3e3902e6 100644 --- a/src/auto4_lua_assfile.cpp +++ b/src/auto4_lua_assfile.cpp @@ -102,13 +102,19 @@ namespace { } template - void get_userdata_field(lua_State *L, const char *name, const char *line_class, T *target) + bool get_userdata_field(lua_State *L, const char *name, const char *line_class, T *target, bool required) { lua_getfield(L, -1, name); - if (!lua_isuserdata(L, -1)) + if (!lua_isuserdata(L, -1)) { + if (!required) { + lua_pop(L, 1); + return false; + } throw bad_field("userdata", name, line_class); + } *target = *static_cast(lua_touserdata(L, -1)); lua_pop(L, 1); + return true; } using namespace Automation4; @@ -316,7 +322,9 @@ namespace Automation4 { dia->Margin[2] = get_int_field(L, "margin_t", "dialogue"); dia->Effect = get_string_field(L, "effect", "dialogue"); dia->Text = get_string_field(L, "text", "dialogue"); - get_userdata_field(L, "_foldinfo", "dialogue", &dia->Fold); + if (!get_userdata_field(L, "_foldinfo", "dialogue", &dia->Fold, false)) { + dia->Fold = FoldInfo(); + } std::vector new_ids; From c0fa794e453002d7b9169d263ef9fa28df3e7c9a Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 1 Aug 2022 19:13:54 +0200 Subject: [PATCH 02/16] Lua: Functions to set text selection and cursor Putting this logic for delaying changes in the TextSelectionController isn't the cleanest, but all attempts at saving this state somewhere in the Lua API instead turned out even worse. Also, the logic for inverted selections probably does belong in there. --- src/auto4_lua.cpp | 42 +++++++++++++++++++++++++++++++ src/text_selection_controller.cpp | 15 +++++++++++ src/text_selection_controller.h | 17 +++++++++++++ 3 files changed, 74 insertions(+) diff --git a/src/auto4_lua.cpp b/src/auto4_lua.cpp index 6c131902e..bba6e6aeb 100644 --- a/src/auto4_lua.cpp +++ b/src/auto4_lua.cpp @@ -51,6 +51,7 @@ #include "selection_controller.h" #include "subs_controller.h" #include "video_controller.h" +#include "text_selection_controller.h" #include "utils.h" #include @@ -285,6 +286,39 @@ namespace { return 0; } + int lua_get_text_cursor(lua_State *L) + { + push_value(L, get_context(L)->textSelectionController->GetStagedInsertionPoint() + 1); + return 1; + } + + int lua_set_text_cursor(lua_State *L) + { + int point = lua_tointeger(L, -1) - 1; + lua_pop(L, 1); + get_context(L)->textSelectionController->StageSetInsertionPoint(point); + return 0; + } + + int lua_get_text_selection(lua_State *L) + { + const agi::Context *c = get_context(L); + int start = c->textSelectionController->GetStagedSelectionStart() + 1; + int end = c->textSelectionController->GetStagedSelectionEnd() + 1; + push_value(L, start <= end ? start : end); + push_value(L, start <= end ? end : start); + return 2; + } + + int lua_set_text_selection(lua_State *L) + { + int start = lua_tointeger(L, -2) - 1; + int end = lua_tointeger(L, -1) - 1; + lua_pop(L, 2); + get_context(L)->textSelectionController->StageSetSelection(start, end); + return 0; + } + int project_properties(lua_State *L) { const agi::Context *c = get_context(L); @@ -489,6 +523,12 @@ namespace { set_field(L, "project_properties"); set_field(L, "get_audio_selection"); set_field(L, "set_status_text"); + lua_createtable(L, 0, 4); + set_field(L, "get_cursor"); + set_field(L, "set_cursor"); + set_field(L, "get_selection"); + set_field(L, "set_selection"); + lua_setfield(L, -2, "gui"); // store aegisub table to globals lua_settable(L, LUA_GLOBALSINDEX); @@ -786,6 +826,7 @@ namespace { void LuaCommand::operator()(agi::Context *c) { + c->textSelectionController->DropStagedChanges(); LuaStackcheck stackcheck(L); set_context(L, c); stackcheck.check_stack(0); @@ -883,6 +924,7 @@ namespace { new_active = *new_sel.begin(); c->selectionController->SetSelectionAndActive(std::move(new_sel), new_active); } + c->textSelectionController->CommitStagedChanges(); stackcheck.check_stack(0); } diff --git a/src/text_selection_controller.cpp b/src/text_selection_controller.cpp index deefa6573..7290370c0 100644 --- a/src/text_selection_controller.cpp +++ b/src/text_selection_controller.cpp @@ -73,3 +73,18 @@ void TextSelectionController::SetSelection(int start, int end) { changing = false; AnnounceSelectionChanged(); } + + +void TextSelectionController::CommitStagedChanges() { + if (has_staged_selection) { + if (staged_selection_start <= staged_selection_end) { + SetSelection(staged_selection_start, staged_selection_end); + } else { + // commit some crimes to get this to work in all cases + SetInsertionPoint(staged_selection_end == 0 ? staged_selection_start : 0); + SetSelection(staged_selection_start, staged_selection_start); + SetInsertionPoint(staged_selection_end); + } + has_staged_selection = false; + } +} \ No newline at end of file diff --git a/src/text_selection_controller.h b/src/text_selection_controller.h index be6949ef4..634ec4a9a 100644 --- a/src/text_selection_controller.h +++ b/src/text_selection_controller.h @@ -25,6 +25,10 @@ class TextSelectionController { int insertion_point = 0; bool changing = false; + int staged_selection_start = 0; + int staged_selection_end = 0; + bool has_staged_selection = false; + wxStyledTextCtrl *ctrl = nullptr; void UpdateUI(wxStyledTextEvent &evt); @@ -35,10 +39,23 @@ public: void SetSelection(int start, int end); void SetInsertionPoint(int point); + // This set of functions allows staging changes to the selection or insertion points, which can then be applied later. + // This is useful when one is still waiting on other changes to be applied, but already listening for changes to the + // selection in the eventually visible text. + // They also provide a wrapper for setting a selection whose insertion point is on the left side. + void StageSetSelection(int start, int end) { staged_selection_start = start; staged_selection_end = end; has_staged_selection = true; }; + void StageSetInsertionPoint(int point) { StageSetSelection(point, point); }; + void CommitStagedChanges(); + void DropStagedChanges() { has_staged_selection = false; }; + int GetSelectionStart() const { return selection_start; } int GetSelectionEnd() const { return selection_end; } int GetInsertionPoint() const { return insertion_point; } + int GetStagedSelectionStart() const { return has_staged_selection ? staged_selection_start : selection_start; } + int GetStagedSelectionEnd() const { return has_staged_selection ? staged_selection_end : selection_end; } + int GetStagedInsertionPoint() const { return has_staged_selection ? staged_selection_end : insertion_point; } + void SetControl(wxStyledTextCtrl *ctrl); ~TextSelectionController(); From fd1a92d6270517d97cf7947a8ab76b3c8a7b598e Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 1 Aug 2022 19:57:53 +0200 Subject: [PATCH 03/16] Folding: Fix default hotkeys --- src/libresrc/default_hotkey.json | 2 +- src/libresrc/osx/default_hotkey.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libresrc/default_hotkey.json b/src/libresrc/default_hotkey.json index 34e0ef486..1b428c775 100644 --- a/src/libresrc/default_hotkey.json +++ b/src/libresrc/default_hotkey.json @@ -263,7 +263,7 @@ "subtitle/select/all" : [ "Ctrl-A" ], - "grid/toggle" : [ + "grid/fold/toggle" : [ "Enter" ], "video/frame/next" : [ diff --git a/src/libresrc/osx/default_hotkey.json b/src/libresrc/osx/default_hotkey.json index 136f5bc48..64d16bd85 100644 --- a/src/libresrc/osx/default_hotkey.json +++ b/src/libresrc/osx/default_hotkey.json @@ -273,7 +273,7 @@ "subtitle/select/all" : [ "Ctrl-A" ], - "grid/toggle" : [ + "grid/fold/toggle" : [ "Enter" ], "video/frame/next" : [ From feab1a5663c040c59c3c14eae7921ecf062e996c Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 1 Aug 2022 20:48:07 +0200 Subject: [PATCH 04/16] Add documentation for text selection api --- automation/v4-docs/gui.txt | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 automation/v4-docs/gui.txt diff --git a/automation/v4-docs/gui.txt b/automation/v4-docs/gui.txt new file mode 100644 index 000000000..1ec617805 --- /dev/null +++ b/automation/v4-docs/gui.txt @@ -0,0 +1,57 @@ +Automation 4 Gui Functions + +This document describes the available Automation 4 functions for +controlling the editor's graphical interface. These all reside in the +table aegisub.gui . + +--- + +Getting and setting the selection and cursor in the text edit box + +This set of functions controls the selection in the text edit box. +All indices are counted starting from 1, following Lua conventions. +The setter functions are applied after all subtitle changes have been +applied. Only the latest update is applied. +The getter functions return the state after the latest update by +the setter functions, or the original state if there were none. + + +function aegisub.gui.get_cursor() + +Returns: 1 number + 1. The position of the cursor in the text edit field. + +--- + +function aegisub.get_selection() + +Returns: 2 values, all numbers. + 1. Starting position of the selection. + 2. Ending position of the selection, always larger or equal + than the stating position. + +--- + +function aegisub.gui.set_cursor(position) + +@position (number) + The new position of the cursor. + +Returns: 0 values + +--- + +function aegisub.gui.set_selection(start, end) + +@start (number) + The new start of the selection. + +@end (number) + The new end of the selection, i.e. where the cursor will be. + Can be smaller than the start, in which case the cursor will + be on the left side of the selection. + +Returns: 0 values + +--- + From fa33b07c7f4534aa130dafa5ec46c1b08625c676 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 11 Jul 2022 18:51:33 +0200 Subject: [PATCH 05/16] Add option toggling behaviour of Ctrl+Zoom --- src/libresrc/default_config.json | 3 ++- src/libresrc/osx/default_config.json | 3 ++- src/preferences.cpp | 2 ++ src/video_display.cpp | 8 +++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index e177379b2..6b7766218 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -612,6 +612,7 @@ "Show Keyframes" : true }, "Subtitle Sync" : true, - "Video Pan": false + "Video Pan": false, + "Default to Video Zoom": false } } diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json index c6408ec67..f30b5176d 100644 --- a/src/libresrc/osx/default_config.json +++ b/src/libresrc/osx/default_config.json @@ -612,6 +612,7 @@ "Show Keyframes" : true }, "Subtitle Sync" : true, - "Video Pan": false + "Video Pan": false, + "Default to Video Zoom": false } } diff --git a/src/preferences.cpp b/src/preferences.cpp index 1eb906c3a..813598900 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -435,6 +435,8 @@ void Advanced_Video(wxTreebook *book, Preferences *parent) { p->OptionChoice(expert, _("Subtitles provider"), sp_choice, "Subtitle/Provider"); p->OptionAdd(expert, _("Video Panning"), "Video/Video Pan"); + p->OptionAdd(expert, _("Default to Video Zoom"), "Video/Default to Video Zoom") + ->SetToolTip("Reverses the behavior of Ctrl while scrolling the video display. If not set, scrolling will default to UI zoom and Ctrl+scrolling will zoom the video. If set, this will be reversed."); #ifdef WITH_AVISYNTH diff --git a/src/video_display.cpp b/src/video_display.cpp index ebee959be..319a51c72 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -409,11 +409,13 @@ void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { bool videoPan = OPT_GET("Video/Video Pan")->GetBool(); if (int wheel = event.GetWheelRotation()) { - if (ForwardMouseWheelEvent(this, event)) - if (event.ControlDown() || !videoPan) + if (ForwardMouseWheelEvent(this, event)) { + if (!videoPan || (event.ControlDown() == OPT_GET("Video/Default to Video Zoom")->GetBool())) { SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); - else + } else { SetVideoZoom(wheel / event.GetWheelDelta()); + } + } } } From c07a648270693c8554805cafc28c6bf315b500ea Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 1 Aug 2022 21:21:24 +0200 Subject: [PATCH 06/16] Add options to commit or reverse video zoom --- src/libresrc/default_config.json | 2 ++ src/libresrc/osx/default_config.json | 2 ++ src/preferences.cpp | 3 +++ src/video_display.cpp | 5 ++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json index 6b7766218..47ac07696 100644 --- a/src/libresrc/default_config.json +++ b/src/libresrc/default_config.json @@ -584,6 +584,8 @@ }, "Video" : { + "Disable Scroll Zoom" : false, + "Reverse Zoom" : false, "Default Zoom" : 7, "Detached" : { "Enabled" : false, diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json index f30b5176d..c416e5c2f 100644 --- a/src/libresrc/osx/default_config.json +++ b/src/libresrc/osx/default_config.json @@ -584,6 +584,8 @@ }, "Video" : { + "Disable Scroll Zoom" : false, + "Reverse Zoom" : false, "Default Zoom" : 7, "Detached" : { "Enabled" : false, diff --git a/src/preferences.cpp b/src/preferences.cpp index 813598900..cc45cd394 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -174,6 +174,9 @@ void Video(wxTreebook *book, Preferences *parent) { p->CellSkip(general); p->OptionAdd(general, _("Automatically open audio when opening video"), "Video/Open Audio"); p->CellSkip(general); + p->OptionAdd(general, _("Disable zooming with scroll bar"), "Video/Disable Scroll Zoom") + ->SetToolTip("Makes the scroll bar not zoom the video. Useful when using a track pad that often scrolls accidentally."); + p->OptionAdd(general, _("Reverse zoom direction"), "Video/Reverse Zoom"); const wxString czoom_arr[24] = { "12.5%", "25%", "37.5%", "50%", "62.5%", "75%", "87.5%", "100%", "112.5%", "125%", "137.5%", "150%", "162.5%", "175%", "187.5%", "200%", "212.5%", "225%", "237.5%", "250%", "262.5%", "275%", "287.5%", "300%" }; wxArrayString choice_zoom(24, czoom_arr); diff --git a/src/video_display.cpp b/src/video_display.cpp index 319a51c72..3ceb12083 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -409,7 +409,10 @@ void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { bool videoPan = OPT_GET("Video/Video Pan")->GetBool(); if (int wheel = event.GetWheelRotation()) { - if (ForwardMouseWheelEvent(this, event)) { + if (ForwardMouseWheelEvent(this, event) && !OPT_GET("Video/Disable Scroll Zoom")->GetBool()) { + if (OPT_GET("Video/Reverse Zoom")->GetBool()) { + wheel = -wheel; + } if (!videoPan || (event.ControlDown() == OPT_GET("Video/Default to Video Zoom")->GetBool())) { SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); } else { From 3dcab8b9bd319fbc9d3fd1eb15938965ede3f920 Mon Sep 17 00:00:00 2001 From: Charlie Jiang Date: Thu, 9 May 2019 16:26:08 -0400 Subject: [PATCH 07/16] 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 000000000..4647a9147 --- /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 2dc110d3a..55c731bd9 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 b2e0f9335..6234dc9fc 100644 --- a/src/colour_button.h +++ b/src/colour_button.h @@ -43,6 +43,12 @@ public: /// 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 d703ebdc0..eec19c2d4 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 000000000..004408bfa --- /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 2e03d09e9..d781c6614 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 2ec8f50e4..deb624628 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 000000000..2bc9c6f89 --- /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 000000000..1f808db39 --- /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 318f8d3ee..c86ef3609 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 b9460979e..d4b0af376 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 07afb90b0..7b85ee600 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 72587d366..495c3f418 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 08/16] 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 004408bfa..5243d2197 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 09/16] 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 59f2ed05f..56e9ec4e6 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 10/16] 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 eec19c2d4..c44216db2 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 11/16] 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 5243d2197..2de54b2c0 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 2bc9c6f89..5912b4fc3 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 12/16] 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 2de54b2c0..2c40eedbf 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 13/16] 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 2c40eedbf..dafc59972 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 14/16] 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 15/16] 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 d6d755352..93e506636 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; From 8dbf6a4fb73ff761d4024087e2012f0b306e75c1 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 1 Aug 2022 22:15:22 +0200 Subject: [PATCH 16/16] README: lua_api, wangqr_time_video, and the zlib linker bug --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 618fe9867..478ee14b8 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,15 @@ The `cibuilds` branch makes some CI builds of snapshots of `feature` at relevant ### Branch/Feature list - [`folding`](https://github.com/arch1t3cht/Aegisub/tree/folding): Add the ability to visually group and collapse lines in the subtitle grid +- [`lua_api`](https://github.com/arch1t3cht/Aegisub/tree/lua_api): Add new functions to the Lua automation API, like controlling the selection or cursor in the text edit box - [`vector_clip_actions`](https://github.com/arch1t3cht/Aegisub/tree/vector_clip_actions): Make the different modes of the vector clip tool (lines, bezier curves, adding points, etc) bindable to hotkeys - [`color_picker_fix2`](https://github.com/arch1t3cht/Aegisub/tree/color_picker_fix2): Add an option (under "Interface") to restrict the color picker to the window, which fixes the color picker on Linux in a lot of cases. - [`avisynth`](https://github.com/arch1t3cht/Aegisub/tree/avisynth): Reenable Avisynth support on Windows (Still occasionally crashes) - [`bugfixes`](https://github.com/arch1t3cht/Aegisub/tree/bugfixes): Various fixes, mostly relevant for compilation - [`misc_dc`](https://github.com/arch1t3cht/Aegisub/tree/misc_dc): Miscellaneous changes taken from AegisubDC -- [`video_panning_feature`](https://github.com/arch1t3cht/Aegisub/tree/video_panning_feature): Merge [moex3's video zoom and panning](https://github.com/TypesettingTools/Aegisub/pull/150), with an OSX fix and an option to toggle the behavior of Ctrl+Zoom +- [`video_panning_feature`](https://github.com/arch1t3cht/Aegisub/tree/video_panning_feature): Merge [moex3's video zoom and panning](https://github.com/TypesettingTools/Aegisub/pull/150), with an OSX fix and more options to control zoom behavior - [`spectrum-frequency-mapping`](https://github.com/arch1t3cht/Aegisub/tree/spectrum-frequency-mapping): Merge EleonoreMizo's [spectrum display improvements](https://github.com/TypesettingTools/Aegisub/pull/94), and also make Shift+Scroll vertically zoom the audio display +- [`wangqr_time_video`](https://github.com/arch1t3cht/Aegisub/tree/wangqr_time_video): Merge wangqr's feature adding a tool for timing subtitles to changes in the video ### Troubleshooting #### Building fails with a "CMake sandbox violation" @@ -43,6 +45,9 @@ The changes to `default_config.json` or similar files weren't detected by meson #### The video is desynced / Frames don't appear at the right time This is probably due to the ffms2 seeking bug ([#394](https://github.com/FFMS/ffms2/issues/394)). On Windows, this shouldn't happen anymore. On Linux, you need to install the latest git version of ffms2 - for example the [`ffms2-git`](https://aur.archlinux.org/packages/ffms2-git) AUR package on Arch linux, or just compile it yourself. +#### On Windows: Aegisub crashes whenever I open a video +If you're compiling yourself, try adding `--force-fallback-for=zlib` to the meson options. + # Aegisub