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 + +--- + 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();